บันทึกการประชุม API LLM: บทถอดเสียงสู่สรุปใน Python
เพื่อรับบันทึกการประชุมจาก llm api คุณส่งไฟล์ถอดเสียงไปยังเอนด์พอยต์ chat completions พร้อมพรอมต์ระบบสั้นๆ แล้วอ่านคำตอบ ส่วนสำคัญที่กำหนดคุณภาพคือ พรอมต์ รูปแบบเอาต์พุตที่ตายตัว และวิธีการจัดการกับไฟล์ถอดเสียงที่ยาว
อัปเดต

ประเด็นสำคัญ
- การเรียก chat completion หนึ่งครั้งแปลงบทถอดเสียงเป็นบันทึก; โหมด JSON ให้รูปแบบฟิลด์ที่แน่นอน
- หน้าต่าง 100,000 โทเคนรองรับบทถอดเสียงการประชุมส่วนใหญ่โดยไม่ต้องแบ่งส่วน
- บอกโมเดลให้เขียน null สำหรับเจ้าของและวันที่ที่ขาดหายไป เพื่อให้โมเดลไม่สร้างข้อมูลขึ้นมาเอง
- คีย์เต็มรูปแบบอนุญาตให้ทำคำขอพร้อมกัน 8 คำขอ เพียงพอสำหรับการประมวลผลการประชุมหนึ่งวันแบบขนาน
ขั้นตอนการทำงานสี่ขั้นตอน
- บันทึกและถอดเสียง ใช้เครื่องมือแปลงเสียงเป็นข้อความใดก็ได้ API นี้รับเฉพาะข้อความและไม่รองรับไฟล์เสียง
- เตรียมข้อความ เพิ่มส่วนหัวที่มีชื่อกำหนดการประชุม วันที่ และรายชื่อผู้เข้าร่วม หากมีป้ายระบุผู้พูดจะช่วยได้มาก
- เรียกโมเดล ส่งบทถอดเสียงพร้อมระบบพรอมต์ที่กำหนดส่วนต่างๆ ที่คุณต้องการ
- จัดเก็บและแชร์ผลลัพธ์ บันทึก JSON, แสดงผลเป็น Markdown หรือ HTML, โพสต์ในที่ที่ทีมอ่าน
เอนด์พอยต์คือ POST /v1/chat/completions บน https://api.whisperapis.com/v1, ID โมเดลคือ uncensored และ SDK ของ OpenAI ใดๆ ก็ใช้ได้หลังจากเปลี่ยน Base URL และคีย์ หากคุณต้องตั้งค่าเครื่องมือแปลงเสียงเป็นข้อความก่อน เอกสาร เริ่มต้นอย่างรวดเร็ว จะครอบคลุมส่วนข้อความ และเซิร์ฟเวอร์ที่เข้ากันได้กับ Whisper ใดๆ ก็สามารถให้บทบันทึกได้
รับบันทึกที่มีโครงสร้างด้วยโหมด JSON
สรุปแบบอิสระเหมาะสำหรับการอ่าน แต่ขั้นตอนการทำงานต้องการฟิลด์ที่สามารถจัดเก็บและกรองได้ โหมด JSON เปิดใช้งานด้วย response_format ตั้งค่าเป็น {"type": "json_object"} ทำให้โมเดลส่งคืนออบเจกต์ JSON เดียว ระบุคีย์ในระบบพรอมต์ และระบุคำว่า JSON ที่นั่น เพราะพรอมต์คือสิ่งที่กำหนดรูปแบบ
import json
from openai import OpenAI
client = OpenAI(base_url="https://api.whisperapis.com/v1", api_key="YOUR_KEY")
SYSTEM = """You write meeting notes from raw transcripts.
Use only what the transcript says. If an owner or a date is not stated, write null.
Reply with a JSON object with the keys: summary (string), decisions (array of strings),
action_items (array of objects with task, owner, due), open_questions (array of strings)."""
transcript = open("standup.txt", encoding="utf-8").read()
resp = client.chat.completions.create(
model="uncensored",
messages=[
{"role": "system", "content": SYSTEM},
{"role": "user", "content": "Transcript:\n\n" + transcript},
],
response_format={"type": "json_object"},
temperature=0.2,
)
notes = json.loads(resp.choices[0].message.content)
for item in notes["action_items"]:
print(item["owner"], "->", item["task"], item["due"])บรรทัดสองบรรทัดในพรอมต์นี้ทำหน้าที่ส่วนใหญ่ "ใช้เฉพาะสิ่งที่อยู่ในบันทึกการสนทนา" ช่วยป้องกันไม่ให้โมเดลเพิ่มรายละเอียดที่สมเหตุสมผลแต่ไม่ถูกต้อง "หากไม่มีการระบุเจ้าของหรือวันที่ ให้เขียน null" ให้วิธีที่ถูกต้องตามกฎหมายในการบอกว่าโมเดลไม่ทราบข้อมูล ซึ่งดีกว่าการสร้างชื่อขึ้นมาเอง อุณหภูมิต่ำเช่น 0.2 ลดความแปรปรวนระหว่างการรัน ซึ่งคุณต้องการเมื่อไฟล์บันทึกการสนทนาเดียวกันอาจถูกประมวลผลสองครั้ง
ควรแยกวิเคราะห์อย่างระมัดระวังเสมอ ห่อหุ้ม json.loads ไว้ใน try block และเมื่อเกิดข้อผิดพลาดให้ลองใหม่หนึ่งครั้ง คำขอที่ล้มเหลวจะไม่ถูกคิดเงิน และการลองใหม่เพียงครั้งเดียวสามารถแก้ไขข้อผิดพลาดการจัดรูปแบบแบบครั้งเดียวส่วนใหญ่ได้
สตรีมผลลัพธ์ไปยังคนที่รอ
หากใครคลิกปุ่มและรอรับบันทึก ให้แสดงข้อความเมื่อมาถึง ตั้งค่า stream เป็น true และ API จะส่งเหตุการณ์ที่ส่งโดยเซิร์ฟเวอร์; การใช้งานถูกรวมไว้ที่ท้ายสตรีม
from openai import OpenAI
client = OpenAI(base_url="https://api.whisperapis.com/v1", api_key="YOUR_KEY")
transcript = open("standup.txt", encoding="utf-8").read()
stream = client.chat.completions.create(
model="uncensored",
messages=[
{"role": "system", "content": "Write concise meeting notes in Markdown with headings: Summary, Decisions, Actions."},
{"role": "user", "content": transcript},
],
stream=True,
temperature=0.3,
)
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)สตรีมมิงมีรายละเอียดการทำงานหนึ่งประการ: คำขอสตรีมจะครอบครองช่องความพร้อมใช้งานพร้อมกันจนกว่าสตรีมจะสิ้นสุด คีย์แบบเต็มอนุญาตให้ทำพร้อมกัน 8 รายการ คีย์ทดลองทำพร้อมกัน 2 รายการ หากแท็บเบราว์เซอร์ปิดและเซิร์ฟเวอร์ของคุณยังคงอ่านอยู่ ช่องนั้นจะยังคงใช้งานอยู่ ดังนั้นให้ยกเลิกคำขอ upstream เมื่อไคลเอนต์ตัดการเชื่อมต่อ
สำหรับงานแบทช์ที่ไม่มีคนดู ให้ข้ามสตรีมมิง คำขอธรรมดาง่ายกว่าและคุณได้รับคำตอบทั้งหมดในออบเจกต์เดียว
การประชุมที่ยาวนานและหน้าต่าง 100k
หน้าต่างบริบทมีขนาด 100,000 โทเคน โดยนับรวมพรอมต์และคำตอบรวมกัน การประชุมหนึ่งชั่วโมงมีคำประมาณ 9,000 คำ หรือประมาณ 12,000 โทเคน ดังนั้นเวิร์กช็อปตลอดทั้งวันจึงสามารถใส่ในคำขอเดียวได้ วิธีนี้กำจัดรูปแบบการออกแบบแบบ map-and-reduce ที่คุณต้องแบ่งไฟล์ถอดเสียง สรุปแต่ละส่วน แล้วสรุปผลสรุปเหล่านั้น ซึ่งแต่ละขั้นตอนของการออกแบบดังกล่าวจะสูญเสียรายละเอียด และการตัดสินใจที่เกิดขึ้นที่นาทีที่ 5 และแก้ไขที่นาทีที่ 50 อาจถูกรายงานผิดพลาดได้ง่าย
ยังคงตรวจสอบขนาดก่อนส่ง การตรวจสอบแบบหยาบคือจำนวนตัวหารด้วยสี่สำหรับข้อความภาษาอังกฤษ หากคุณอยู่ใกล้ขีดจำกัด มีสองตัวเลือกที่สะอาด:
- แบ่งที่จุดแตกตามธรรมชาติเช่น รายการวาระการประชุม สรุปแต่ละรายการและส่งบันทึกบางส่วนไปยังการเรียกครั้งสุดท้ายที่รวมพวกมัน
- ละเว้นเนื้อหาที่ไม่สำคัญเช่น ช่วงยาวของการพูดคุยเล็กๆ น้อยๆ ก่อนการประชุมเริ่มต้น
ขนาดสูงสุดของ body ของคำขอคือ 8 MB ซึ่งไม่ใช่ข้อจำกัดในทางปฏิบัติสำหรับข้อความ พรอมต์ไม่ถูกใช้ในการฝึก ซึ่งสำคัญหากการบันทึกเสียงมีแผนภายในหรือชื่อลูกค้า
รายละเอียดพรอมต์ที่เปลี่ยนผลลัพธ์
บอกว่าบันทึกสำหรับใคร
"บันทึกสำหรับวิศวกรที่พลาดการประชุม" ได้รายละเอียดต่างจาก "อัปเดตย่อหน้าเดียวสำหรับทีมผู้บริหาร" เขียนผู้อ่านเข้าไปในระบบพรอมต์
ให้รายชื่อผู้เข้าร่วมกับโมเดล
Speech-to-text มักทำให้ชื่อเพี้ยน บรรทัดเช่น "Attendees: Priya Nair (PM), Tom Ortiz (backend), Lena Fischer (design)" ช่วยให้โมเดลซ่อม transcript ที่บอกว่า "Tom Ortis" และแน่งานกับบุคคลที่ถูกต้อง
ขอการตัดสินใจและการกระทำแยกกัน
การตัดสินใจคือสิ่งที่กลุ่มตกลงกัน การกระทำคือสิ่งที่บุคคลหนึ่งจะทำ เมื่อทั้งสองอยู่ในรายการเดียว ผู้อ่านข้ามมัน คีย์แยกทำให้ความแตกต่างชัดเจน และโมเดลทำตามอย่างสม่ำเสมอ
เก็บข้อมูลสำคัญไว้
การประชุมจริงมักมีภาษาที่ตรงไปตรงมา การบ่นถึงบุคคลเฉพาะ ความกังวลทางกฎหมาย และการโต้แย้งอย่างรุนแรง โมเดลนี้ถูกปรับให้ตอบโดยไม่ปฏิเสธเนื้อหาสำหรับการใช้งานของผู้ใหญ่ตามกฎหมาย จึงสรุปสิ่งที่พูดไปแทนที่จะปฏิเสธ คุณยังคงเป็นเจ้าของผลลัพธ์ ดังนั้นจึงควรตรวจสอบบันทึกก่อนส่งให้ผู้ที่ไม่ได้เข้าร่วมการประชุม
การจัดการประชุมตลอดทั้งวัน
ทีมที่บันทึกการประชุมหกครั้งต่อวันสามารถประมวลผลแบบขนานได้ ด้วยคำขอพร้อมกัน 8 คำขอ สามารถส่งได้ครั้งละสูงสุดแปดรายการ; คอลเลกชันของ worker ขนาดเล็กพร้อม semaphore ก็เพียงพอแล้ว ขีดจำกัดอัตราต่อนาทีสำหรับคีย์เต็มคือ 300 คำขอ ซึ่งสายการผลิตการประชุมจะไม่แตะถึง
Node ทำงานในลักษณะเดียวกับ Python นี่คือเวอร์ชันที่ไม่มีการสตรีม:
import OpenAI from "openai";
import { readFileSync } from "node:fs";
const client = new OpenAI({
baseURL: "https://api.whisperapis.com/v1",
apiKey: process.env.API_KEY,
});
const transcript = readFileSync("standup.txt", "utf8");
const resp = await client.chat.completions.create({
model: "uncensored",
messages: [
{ role: "system", content: "Summarize the meeting in five bullets, then list action items with owners." },
{ role: "user", content: transcript },
],
temperature: 0.2,
});
console.log(resp.choices[0].message.content);หากคุณได้รับ HTTP 429 ให้อ่านรหัสข้อผิดพลาด concurrency หมายถึงมีคำขอมากเกินไปในครั้งเดียว ดังนั้นให้ลดขนาด pool ลง rate_limited หมายถึงมีคำขอมากเกินไปต่อนาที คำตอบ 429 พร้อม header Retry-After: 5 บ่งชี้ถึงการโอเวอร์โหลดชั่วคราว; รอห้าวินาทีแล้วลองอีกครั้ง
การตรวจสอบบันทึกก่อนที่คุณจะไว้วางใจ
บันทึกที่สร้างขึ้นอ่านดูมั่นใจแม้ว่าจะผิด ดังนั้นจึงควรสร้างการตรวจสอบที่ใช้ทรัพยากรน้อยไม่กี่รายการลงในสายการผลิตแทนที่จะพึ่งพามนุษย์ให้สังเกต
- ตรวจสอบคำพูดอ้างอิง ขอคำพูดอ้างอิงสั้นๆ พร้อมรายการการกระทำแต่ละรายการ แล้วค้นหาในบันทึกการสนทนาเพื่อหาคำพูดนั้น หากคำพูดอ้างอิงไม่ปรากฏ แสดงว่ารายการนั้นถูกสร้างขึ้นมา
- ตรวจสอบเจ้าของ เปรียบเทียบเจ้าของแต่ละรายการกับรายชื่อผู้เข้าร่วมของคุณและระบุชื่อที่ไม่ได้อยู่ในรายการ
- ตรวจสอบความว่าง การประชุมที่ไม่มีผลการตัดสินใจเป็นไปได้ แต่ผลลัพธ์ที่มีชุดข้อมูลว่างทั้งหมดในบทถอดเสียงที่ยาว 40 นาที มักหมายถึงข้อมูลนำเข้าถูกตัดหรือใช้ไฟล์ผิด
- ตรวจสอบความยาว บันทึกที่ยาวกว่าประมาณหนึ่งในห้าของบทถอดเสียงไม่ใช่บันทึก; ปรับพรอมต์หรือตั้งค่า
max_tokens
บันทึกส่วนหัวการตอบกลับ X-Request-Id ไว้ข้างผลลัพธ์ที่บันทึกไว้แต่ละรายการ เมื่อมีคนบอกว่ารายการที่ต้องดำเนินการผิด ตัวระบุนี้ช่วยให้คุณหาคำขอนั้นและเปรียบเทียบกับบทถอดเสียงได้ การเก็บบทถอดเสียงดั้งเดิมไว้ข้างๆ บันทึกมีต้นทุนต่ำและยุติข้อโต้แย้งส่วนใหญ่ได้รวดเร็ว
ต้นทุนและการทดสอบครั้งแรก
ราคาคือ $0.15 ต่อโทเคนอินพุตหนึ่งล้านโทเคน และ $0.50 ต่อโทเคนเอาต์พุตหนึ่งล้านโทเคน การประชุมหนึ่งชั่วโมงพร้อม transcript ยาว 12,000 โทเคน และชุด notes ยาว 800 โทเคน มีต้นทุนอินพุต $0.0018 และเอาต์พุต $0.0004 รวมเป็น $0.0022 ในอัตราดังกล่าว เงิน $1 ครอบคลุมการประชุมลักษณะนี้ประมาณ 454 ครั้ง ดูหน้า ราคา เพื่อเติมเงิน ซึ่งเริ่มที่ $20 และจ่ายได้ด้วยบัตรหรือคริปโต
เพื่อทดลองใช้งาน ให้สมัครและเปิดหน้า คีย์ API มีเครดิตทดลองใช้งาน $0.50 แบบคลิกเดียว ให้ได้ครั้งเดียวต่อคน ใช้ได้ 7 วัน ไม่ต้องใช้บัตร รันสคริปต์ Python ข้างต้นกับ transcript จริงหนึ่งรายการ อ่าน JSON แล้วปรับพรอมต์จนกว่า action item จะตรงกับสิ่งที่เกิดขึ้นในการประชุม จากนั้นทำซ้ำกับรายการที่เหลือ
คู่มือเพิ่มเติม
ถาม-ตอบ
ฉันส่งไฟล์เสียงบันทึกโดยตรงได้ไหม
ไม่ได้ API รับเฉพาะข้อความเท่านั้น ให้ถอดเสียงไฟล์เสียงด้วยเครื่องมือ speech-to-text ก่อน แล้วส่ง transcript
ฉันทำให้รูปแบบผลลัพธ์สอดคล้องกันได้อย่างไร
ใช้โหมด JSON พร้อมระบบพรอมต์ที่ระบุชื่อคีย์ทุกตัว และตั้งค่าอุณหภูมิให้ต่ำ จากนั้นแยกวิเคราะห์ผลลัพธ์ในบล็อก try และลองใหม่หนึ่งครั้งหากเกิดข้อผิดพลาด
บทถอดเสียงยาวแค่ไหนจึงจะพอดีกับคำขอเดียว
หน้าต่างบริบทรองรับโทเคน 100,000 โทเคนสำหรับพรอมต์รวมกับการตอบกลับ ซึ่งครอบคลุมเวิร์กช็อปตลอดทั้งวันในกรณีส่วนใหญ่
ข้อความถอดเสียงของฉันถูกนำไปใช้ฝึกโมเดลไหม
ไม่ พรอมต์ไม่ถูกนำไปใช้ในการฝึกโมเดล
การประชุมหนึ่งครั้งมีค่าใช้จ่ายเท่าใด
การประชุมที่ยาวหนึ่งชั่วโมงพร้อมบทถอดเสียง 12,000 โทเคนและบทสรุป 800 โทเคน มีค่าใช้จ่ายประมาณ $0.0022 เมื่ออัตราโทเคนอินพุตอยู่ที่ $0.15 และโทเคนเอาต์พุตอยู่ที่ $0.50 ต่อหนึ่งล้านโทเคน
คีย์ของคุณอยู่ห่างแค่ขั้นตอนเดียว
สร้างบัญชี คัดลอกคีย์ และเปลี่ยน base URL นั่นคือการตั้งค่าทั้งหมด