|
require 'net/http' |
|
require 'uri' |
|
require 'json' |
|
require 'open3' |
|
require 'fileutils' |
|
|
|
# === 設定 === |
|
TMP_DIR = "tmp" |
|
OUTPUT_DIR = "output" |
|
AUDIO_FILE = File.join(TMP_DIR, "recording.mp3") |
|
TRANSCRIBED_FILE = File.join(TMP_DIR, "transcribed.txt") |
|
PROMPT_FILE = "prompt.txt" |
|
DEVICE = ":0" # macOS の内蔵マイク(avfoundation) |
|
OPENAI_API_KEY = ENV['OPENAI_API_KEY'] |
|
EDITOR = ENV['EDITOR'] || "vi" |
|
|
|
# === ディレクトリ準備 === |
|
FileUtils.mkdir_p(TMP_DIR) |
|
FileUtils.mkdir_p(OUTPUT_DIR) |
|
|
|
# === 録音開始 === |
|
puts "🎙️ 録音を開始します。Enterキーで終了します。" |
|
ffmpeg_cmd = ["ffmpeg", "-y", "-f", "avfoundation", "-i", DEVICE, "-acodec", "libmp3lame", AUDIO_FILE] |
|
stdin, stdout, stderr, wait_thr = Open3.popen3(*ffmpeg_cmd) |
|
|
|
puts "(話し始めてください。録音中です…)" |
|
STDIN.gets |
|
|
|
Process.kill("INT", wait_thr.pid) |
|
wait_thr.value |
|
puts "📁 録音完了:#{AUDIO_FILE}" |
|
|
|
# === Whisper API で文字起こし === |
|
puts "📝 Whisper API に送信中..." |
|
|
|
whisper_uri = URI("https://api.openai.com/v1/audio/transcriptions") |
|
whisper_req = Net::HTTP::Post.new(whisper_uri) |
|
whisper_req["Authorization"] = "Bearer #{OPENAI_API_KEY}" |
|
whisper_req.set_form( |
|
[['file', File.open(AUDIO_FILE)], ['model', 'whisper-1']], |
|
'multipart/form-data' |
|
) |
|
|
|
whisper_res = Net::HTTP.start(whisper_uri.hostname, whisper_uri.port, use_ssl: true) do |http| |
|
http.request(whisper_req) |
|
end |
|
|
|
transcribed_text = JSON.parse(whisper_res.body)["text"] |
|
File.write(TRANSCRIBED_FILE, transcribed_text) |
|
puts "📄 テキスト化結果を保存しました:#{TRANSCRIBED_FILE}" |
|
|
|
# === ChatGPT で整形 === |
|
puts "🎨 ChatGPT で整形中..." |
|
|
|
prompt_text = File.read(PROMPT_FILE) |
|
|
|
chat_uri = URI("https://api.openai.com/v1/chat/completions") |
|
chat_headers = { |
|
"Content-Type" => "application/json", |
|
"Authorization" => "Bearer #{OPENAI_API_KEY}" |
|
} |
|
chat_body = { |
|
model: "gpt-4", |
|
messages: [ |
|
{ role: "system", content: prompt_text }, |
|
{ role: "user", content: transcribed_text } |
|
], |
|
temperature: 0.2 |
|
} |
|
|
|
chat_req = Net::HTTP::Post.new(chat_uri.path, chat_headers) |
|
chat_req.body = chat_body.to_json |
|
|
|
chat_res = Net::HTTP.start(chat_uri.hostname, chat_uri.port, use_ssl: true) do |http| |
|
http.request(chat_req) |
|
end |
|
|
|
formatted_text = JSON.parse(chat_res.body)["choices"][0]["message"]["content"] |
|
puts "\n🧾 整形後のテキスト:\n\n#{formatted_text}" |
|
|
|
# === タイムスタンプ付きファイルに保存 === |
|
timestamp = Time.now.strftime("%Y-%m-%d-%H%M%S") |
|
output_path = File.join(OUTPUT_DIR, "#{timestamp}.txt") |
|
File.write(output_path, formatted_text) |
|
puts "\n💾 整形済みテキストを保存しました:#{output_path}" |
|
|
|
# === エディタで開く === |
|
puts "🖊️ エディタ(#{EDITOR})でファイルを開きます..." |
|
system(EDITOR, output_path) |