写真つきの機能が、月末に高くつく
写真を送ると商品が探せる機能を作りました。便利ですが、月末の請求を見ると予想の何倍にもなっていました。
画像や音声は、文字より重く、費用もかさみます。しかも、この機能を使えない人や、守るべき人がいます。このレッスンでは、その両方を数えます。
このレッスンのゴール
メモ
入力の費用を計算し、気を付けるべき入力を見つけて、一日の報告を作れます。
キーワード
| ことば | いみ |
|---|---|
| 代替テキスト | 画像の内容を、文字で言い表したもの |
| 文字起こし | 音声を文字にしたもの |
| 保存期間 | 入力を、消さずに持ち続ける日数 |
| アクセス | 機能を使えること。見えない人や聞こえない人も含む |
| 予算 | 使ってよい費用の上限 |
学生が入力するセルは、このプレビューでは空白です。
画像、ページ、音声は大きさで値段が決まる
文字は、トークンの数で値段が決まりました。画像はタイルの数、ページは枚数、音声は長さで決まります。
ここでは、どの要求にも 2、画像は 15 とタイル 1 枚につき 8、ページは 1 枚につき 4、音声は 10 秒ごとに 3 という、架空の決まりを使います。単位はポイントです。
四つの入力の値段
| 入力 | 大きさ | 計算 | 値段 |
|---|---|---|---|
| 画像 | 6 タイル | 2 + 15 + 8 x 6 | 65 |
| ページ | 3 枚 | 2 + 4 x 3 | 14 |
| 音声 | 25 秒 | 2 + 3 x 3 | 11 |
| 画像 | 2 タイル | 2 + 15 + 8 x 2 | 33 |
学生が入力するセルは、このプレビューでは空白です。
この機能は、だれを置き去りにするか
画像だけの機能は、見えない人が使えません。音声だけの機能は、聞こえない人が使えません。代替テキストと文字起こしがあれば、その人たちも使えます。
顔や声は、個人を特定できる情報になりえます。必要のない入力は取らず、取るなら保存期間を短くします。
よくある間違い
注意
「とりあえず全部保存しておけば、あとで役に立つ」と考えがちです。保存が長いほど、漏れたときの被害が大きくなります。使い道が決まった日数だけ持ち、過ぎたら消します。
モデル用の補助を書く(1)
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const base = process.env.AI_URL || \"http://ai:4000\";' '// 応答に含まれるトークン数。なければ null。' 'function count(data, name) {' ' return data.usage && typeof data.usage[name] === \"number\" ? data.usage[name] : null;' '}' > model.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
モデル用の補助を書く(2)
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function ask(messages, sample, max) {' ' try {' ' const res = await fetch(base + \"/v1/chat/completions\", {' ' method: \"POST\",' ' headers: { \"content-type\": \"application/json\", authorization: \"Bearer lab\" },' ' body: JSON.stringify({ model: \"lab\", messages: messages, max_tokens: max || 100 }),' ' signal: AbortSignal.timeout(30000),' ' });' ' if (res.ok === false) throw new Error(\"status \" + res.status);' ' const d = await res.json();' ' return { text: d.choices[0].message.content, inTokens: count(d, \"prompt_tokens\"), outTokens: count(d, \"completion_tokens\"), recorded: false };' ' } catch (error) {' ' console.log(\"記録済みサンプル: モデルが答えませんでした (\" + error.message + \")。\");' ' return { text: sample, inTokens: null, outTokens: null, recorded: true };' ' }' '}' 'module.exports = { ask };' >> model.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
費用と印のスクリプトを書く(1)
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { ask } = require(\"./model\");' 'const items = [' ' { id: \"a1\", kind: \"image\", tiles: 6, face: true, voice: false, alt: false, keep: 90 },' ' { id: \"a2\", kind: \"page\", pages: 3, face: false, voice: false, alt: true, keep: 7 },' ' { id: \"a3\", kind: \"audio\", seconds: 25, face: false, voice: true, alt: false, keep: 30 },' ' { id: \"a4\", kind: \"image\", tiles: 2, face: false, voice: false, alt: true, keep: 7 },' '];' > cost6.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
費用と印のスクリプトを書く(2)
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function price(i) {' ' if (i.kind === \"image\") return 2 + 15 + 8 * i.tiles;' ' if (i.kind === \"page\") return 2 + 4 * i.pages;' ' if (i.kind === \"audio\") return 2 + 3 * Math.ceil(i.seconds / 10);' ' return 2;' '}' >> cost6.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
費用と印のスクリプトを書く(3)
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function flags(i) {' ' const out = [];' ' if (i.face) out.push(\"顔\");' ' if (i.voice) out.push(\"声\");' ' if (i.kind === \"image\" && i.alt === false) out.push(\"代替テキストなし\");' ' if (i.kind === \"audio\" && i.alt === false) out.push(\"文字起こしなし\");' ' if (i.keep > 30) out.push(\"保存が長すぎる\");' ' return out;' '}' >> cost6.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
費用と印のスクリプトを書く(4)
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' ' let total = 0;' ' items.forEach(function (i) {' ' total += price(i);' ' console.log(i.id + \": \" + price(i) + \" ポイント \" + JSON.stringify(flags(i)));' ' });' ' console.log(\"一日の合計: \" + total + \" ポイント、予算 100 に対して \" + (100 - total));' ' const q = \"画像に代替テキストを付ける理由を、短い一文で書いてください。\";' ' const r = await ask([{ role: \"user\", content: q }], \"画像を見られない人も、代替テキストを読み上げてもらえば、内容が分かるからです。\", 60);' ' console.log(\"返事: \" + r.text);' '}' 'main();' >> cost6.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
一日の入力の値段を出し、印を付ける
docker exec -w /home/node/project agent node cost6.jsここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
出力の例
| 行 | 示していること |
|---|---|
| a1: 65 ポイント ["顔","代替テキストなし","保存が長すぎる"] | 値段が高く、気を付ける理由が三つある |
| a2: 14 ポイント [] | 問題のない入力 |
| a3: 11 ポイント ["声","文字起こしなし"] | 保存が 30 日ちょうどなので、長すぎるとは言わない |
| 一日の合計: 123 ポイント、予算 100 に対して -23 | 予算を超えている |
| 返事: ... | モデルの一文。先に「記録済みサンプル」の行が出ることもある |
学生が入力するセルは、このプレビューでは空白です。