ローカルで動いた。それだけでは、架空のSaaSのままだ。
デモページに「デモ」と書いてあるだけでは、ただのモックアップだ。
本物のAPIサーバーを作って、誰でも使える状態にする。
それをやるまで、Quillは完成していない。
#2 実装編で、20行のスクリプトが動いた。 音声ファイルを渡すと、Whisper APIで文字起こしして、Claudeで議事録を生成して、Markdownファイルに保存する。 ローカルでは完璧に動く。
でも、気づいた。「ローカルで動く」と「誰でも使える」は、まったく別のことだと。 デモページに音声ファイルをアップロードできるフォームを置いても、それを受け取るサーバーがなければ何も起きない。
やることはシンプルだった。音声ファイルを受け取って、WhisperとClaudeを走らせて、結果を返すサーバーを作ればいい。サーバーといっても、外部から呼び出せる「窓口」が1つあれば十分だ。
Python製のFastAPI(軽量なWebサーバーを素早く作れる道具)で書いた。窓口は1つだけ。
{
"success": true,
"transcript": "本日の会議では...",
"minutes": "## 議事録\n\n### 決定事項\n..."
}
音声ファイルを受け取って、Whisper APIに渡して文字起こし、その結果をClaudeに渡して議事録を生成する。 パソコンの中で動かしていたものを、そのままインターネットに公開できる形に包み直しただけ。コードは50行もなかった。
どこで動かすかを決める。Render(レンダー)というクラウドサービスの無料プランを選んだ。GitHubにコードをアップしておけば、自動でサーバーが立ち上がって URL が発行される。自分でサーバーを管理しなくていい。
設定はシンプルだ。GitHubのリポジトリを指定して、「どのコマンドで起動するか」と「APIキー」を画面に入力するだけ。コード側に直接キーを書かなくていいので、GitHubに上げても安全だ。
Deployボタンを押すと2〜3分でURLが発行された。ブラウザで開いて動作を確認。設定込みで15分もかからなかった。
動いた。と思ったら、問題が起きた。
Render の無料プランは、15分間アクセスがないとサーバーが眠る。次のリクエストが来たときに起動するのだが、起動に50〜70秒かかる。 デモページで音声をアップロードしたユーザーが、1分近く待たされる。これではデモにならない。
解決策は単純だった。UptimeRobotで5分ごとにヘルスチェックを送る。 UptimeRobotの無料プランは5分間隔でURLをポーリングしてくれる。 サーバーへのリクエストが途切れないので、眠らない。設定は3分で終わった。
サーバーが常時動くようになった。残るはデモページからAPIを呼ぶことだ。
HTMLのフォームから `fetch()` でAPIを叩くように書いた。 音声ファイルを選んでアップロードボタンを押すと、`/transcribe` にPOSTして、レスポンスが返ってきたらページに議事録を表示する。
音声ファイルを選んだ。アップロードした。
インジケーターが回った。数秒後、画面に文字が現れた。
文字起こし。議事録。決定事項。次のアクション。
動いた。
架空のSaaSとして企画して、設計して、ローカルで動かして、サーバーに上げた。 デモページが本物のAPIサーバーと繋がって、本物の音声を処理している。 架空のプロダクトが、本物として動いている。
モックアップとデモの違いはここだと思う。
見た目が同じでも、意味が違う。後者の方が、話せることが多い。 「どう作ったか」「何が大変だったか」「どう解決したか」—— 本物を動かした人間だけが話せることが、そこにある。
今のQuillは、誰でもブラウザから音声ファイルを渡せる状態にある。 試した人が「ちゃんと動いた」と言える状態になっている。 それだけで、架空のSaaSが持てる説得力はずいぶん変わると思っている。
Quillは動いている。でも今のままだと、デモページからのリクエストに上限がない。 悪意のある使い方でなくても、リクエストが集中すればAPI費用が増え続ける。
次は1日あたりのリクエスト数に上限をつける。上限に達したらわかりやすいエラーメッセージを返す。それだけで、コスト面のリスクはほぼゼロになる。 デモが本物になったら、次は本物を守る番だ。
音声ファイルをアップロードすると、議事録が生成されます