Tài liệuChuyển thành văn bản trực tiếp
Chuyển thành văn bản trực tiếp
Gửi âm thanh từ micro hoặc tab đến transcript1 qua WebSocket và nhận các dòng phụ đề, kèm bản dịch theo thời gian thực nếu muốn, ngay khi mọi người đang nói.
Chuyển thành văn bản trực tiếp biến luồng âm thanh thành các dòng phụ đề ngay khi mọi người còn đang nói. Client gửi âm thanh PCM thô qua WebSocket, còn transcript1 trả về các dòng: lúc đầu là bản nhận dạng tạm, sau đó thành bản cuối. Thêm translate_to và mỗi dòng sẽ có kèm bản dịch. Khi phiên kết thúc, kết quả được lưu thành một transcription bình thường.
Không có gói riêng cho tính năng trực tiếp: nó dùng chung số dư phút với mọi tính năng khác. Xem Tính phí để biết thời gian kết nối được tính thế nào.
Khi nào nên dùng chế độ trực tiếp
| Dùng chế độ trực tiếp khi | Dùng chuyển thành văn bản thông thường khi |
|---|---|
| Âm thanh vẫn đang được tạo ra: cuộc gọi, buổi nói chuyện, buổi phát trực tiếp, video bạn đang xem. | Bạn có sẵn một đường dẫn hoặc một file đã hoàn chỉnh. |
| Bạn cần phụ đề trong vòng một hai giây sau lời nói. | Bạn cần độ chính xác cao nhất và có thể chờ kết quả. |
| Bạn muốn có bản dịch theo thời gian thực bên cạnh từng dòng. | Bạn muốn dịch một transcript đã hoàn tất, hoặc dịch sang nhiều ngôn ngữ. |
Chế độ trực tiếp chỉ nhận âm thanh dạng PCM thô. Nó không nhận link video, file tải lên, WebM, Opus hay MP3. Hãy ghi âm thanh ở phía client và chuyển sang PCM trước. Mục Ghi âm thanh trong trình duyệt hướng dẫn cách làm.
Bắt đầu nhanh với SDK
Cài SDK 1.5.0 trở lên: npm i @transcript1/sdk@latest. t1.live.start tạo phiên, kết nối và hoàn tất khi phiên đã bắt đầu, nên bạn có thể gửi âm thanh ngay.
import { createReadStream } from 'node:fs';
import { setTimeout as sleep } from 'node:timers/promises';
import { Transcript1 } from '@transcript1/sdk';
const t1 = new Transcript1(); // reads TRANSCRIPT1_API_KEY
const live = await t1.live.start({ language: 'en', translateTo: 'es', sampleRate: 16000 });
live.on('line', line => {
const mark = line.final ? 'final ' : 'partial';
console.log(mark, line.text, '→', line.translation?.text ?? '');
});
live.on('warning', warning => console.warn(warning.code));
// speech.pcm: 16 kHz, mono, signed 16-bit little-endian, no header
for await (const chunk of createReadStream('./speech.pcm', { highWaterMark: 3200 })) {
live.send(chunk);
await sleep(100); // 3,200 bytes are 100 ms of audio: send at real-time speed
}
const result = await live.end();
console.log(result.reason, result.transcriptionId, result.minutesCharged);Các dòng được cập nhật tại chỗ. Khi một dòng có cùng id đến, hãy thay dòng bạn đang giữ, hoặc đọc tất cả từ live.lines. end() kết thúc phiên, chờ các dòng cuối và lưu transcript. Xem SDK Node.js để biết đủ phương thức và sự kiện.
Bắt đầu nhanh với WebSocket thuần
Không dùng SDK thì có hai bước: tạo phiên qua HTTPS, rồi mở WebSocket bằng token dùng một lần được trả về.
Tạo phiên
curl -X POST https://api.transcript1.com/v1/live/sessions \
-H "Authorization: Bearer $TRANSCRIPT1_API_KEY" \
-H "Content-Type: application/json" \
-d '{"language": "en", "translate_to": "es", "sample_rate": 16000}'API trả về 201:
{
"id": "lv_8fK2Lm0PqRsTuVwXyZaBcD",
"status": "waiting",
"transcription_id": "tr_3NcQvXy7BtHjKd5ErFgLmA",
"websocket_url": "wss://api.transcript1.com/v1/live/sessions/lv_8fK2Lm0PqRsTuVwXyZaBcD/stream",
"token": "Zk3x...",
"token_expires_at": "2026-11-02T12:01:00Z",
"rate": 1
}transcription_id là null khi save là false. Token chỉ dùng được một lần và hết hạn sau 60 giây, nên hãy kết nối ngay. rate là số phút số dư bị tính cho mỗi phút đã bắt đầu của phiên này; xem Tính phí.
Body của request nhận các trường sau. Tất cả đều không bắt buộc, và quyền cần có là transcriptions:write:
| Trường | Mặc định | Quy tắc |
|---|---|---|
language | auto | auto, hoặc mã hai chữ cái mà chế độ trực tiếp hỗ trợ. |
translate_to | không có | Mã hai chữ cái. Mỗi phiên chỉ có một ngôn ngữ đích. Xem Dịch trực tiếp. |
diarize | false | Gắn nhãn người nói. Một số cấu hình không gắn nhãn được, ví dụ khi dùng cùng language: "auto", và sẽ trả về 422. Hãy kiểm tra khả năng hỗ trợ. |
audio_format | pcm_s16le | Giá trị duy nhất. Trường này có để sau này thêm được định dạng khác. |
sample_rate | 16000 | Số nguyên từ 8000 đến 48000. Chỉ hỗ trợ mono. |
save | true | false sẽ không lưu gì sau khi phiên kết thúc. Xem Transcript đã lưu. |
Kết nối và truyền dữ liệu
Mở WebSocket với token ở vị trí subprotocol thứ hai. Cách này dùng được trong trình duyệt và trong Node 22+ mà không cần header tùy chỉnh. Hãy chờ session.started rồi mới gửi âm thanh: các frame nhị phân gửi sớm hơn sẽ bị bỏ, và bạn nhận cảnh báo audio_dropped.
import { createReadStream } from 'node:fs';
import { setTimeout as sleep } from 'node:timers/promises';
const session = await fetch('https://api.transcript1.com/v1/live/sessions', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.TRANSCRIPT1_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ language: 'en', translate_to: 'es', sample_rate: 16000 }),
}).then(response => response.json());
const ws = new WebSocket(session.websocket_url, ['t1-live', session.token]);
const lines = new Map();
ws.addEventListener('message', async message => {
const event = JSON.parse(message.data);
if (event.type === 'session.started') {
for await (const chunk of createReadStream('./speech.pcm', { highWaterMark: 3200 })) {
ws.send(chunk);
await sleep(100);
}
ws.send(JSON.stringify({ type: 'end' }));
} else if (event.type === 'line') {
lines.set(event.line.id, event.line); // the full current state: replace by id
console.log(event.line.final, event.line.text, event.line.translation?.text);
} else if (event.type === 'session.ended') {
console.log('ended:', event.reason, event.minutes_charged);
}
});
ws.addEventListener('close', event => console.log('closed', event.code));Node 20 không có WebSocket tích hợp sẵn: hãy dùng gói ws, có cùng dạng new WebSocket(url, protocols).
Với token hợp lệ, server chỉ trả lời bằng subprotocol t1-live. Token sai không bao giờ làm hỏng bước handshake: socket vẫn mở, bạn nhận sự kiện error, rồi socket đóng với mã 4xxx, nhờ đó trình duyệt hiển thị lý do thật thay vì mã 1006 chung chung. Xem Mã đóng.
Ghi âm thanh trong trình duyệt
Âm thanh cho chế độ trực tiếp phải là PCM mono 16-bit có dấu, little-endian, theo sample_rate của phiên. Trình duyệt cung cấp mẫu dạng số thực, vì vậy hãy chuyển đổi trong một AudioWorklet. Đoạn mã dưới đây ghi âm micro thành PCM 16 kHz theo từng khối 100 ms và gửi đi bằng entry SDK dành cho trình duyệt. getAccessToken trả về OAuth access token; đừng bao giờ đặt khóa API trong trình duyệt. Xem Bảo mật.
import { createLiveClient } from '@transcript1/sdk/live';
const workletSource = `
class Pcm16Processor extends AudioWorkletProcessor {
constructor() {
super();
this.buffer = new Int16Array(1600); // 100 ms at 16 kHz
this.filled = 0;
}
process(inputs) {
const channel = inputs[0][0];
if (!channel) return true;
for (let i = 0; i < channel.length; i++) {
const sample = Math.max(-1, Math.min(1, channel[i]));
this.buffer[this.filled++] = sample < 0 ? sample * 0x8000 : sample * 0x7fff;
if (this.filled === this.buffer.length) {
this.port.postMessage(this.buffer.slice());
this.filled = 0;
}
}
return true;
}
}
registerProcessor('pcm16', Pcm16Processor);
`;
const client = createLiveClient({ getAccessToken: () => myApp.getOAuthAccessToken() });
const stream = await navigator.mediaDevices.getUserMedia({ audio: { channelCount: 1 } });
const context = new AudioContext({ sampleRate: 16000 });
const moduleUrl = URL.createObjectURL(new Blob([workletSource], { type: 'text/javascript' }));
await context.audioWorklet.addModule(moduleUrl);
// the context's real rate: a browser that cannot do 16 kHz picks its own
const live = await client.start({ language: 'auto', sampleRate: context.sampleRate });
live.on('line', renderLine);
const microphone = context.createMediaStreamSource(stream);
const capture = new AudioWorkletNode(context, 'pcm16');
capture.port.onmessage = event => live.send(event.data); // an Int16Array
const mute = context.createGain();
mute.gain.value = 0;
microphone.connect(capture).connect(mute).connect(context.destination);
async function stop() {
stream.getTracks().forEach(track => track.stop());
await context.close();
return live.end();
}Worklet được viết cho 16 kHz. Nếu context chạy ở tần số khác, mỗi khối không còn là 100 ms, nhưng PCM vẫn đúng vì sampleRate khớp với context. Để ghi âm thanh của một tab hoặc video thay vì micro, hãy tạo MediaStream bằng getDisplayMedia hoặc từ captureStream() của một phần tử media, rồi nối vào theo cách tương tự.
Dịch trực tiếp
Thêm translate_to vào phiên và transcript1 sẽ dịch từng dòng ngay khi được nói.
- Mỗi phiên chỉ có một ngôn ngữ đích. Có thể thêm ngôn ngữ khác vào transcript đã lưu sau đó bằng endpoint dịch.
- Mỗi
linecó bản gốc (text,final) và một objecttranslation(language,text,final).translationlànullkhi không đặttranslate_to. - Bản gốc và bản dịch được chốt độc lập với nhau: một dòng có thể đã chốt bản gốc trong khi bản dịch vẫn đang thay đổi. Hãy hiển thị dòng là đã chốt khi cả hai đều đã chốt.
- Dòng vốn đã ở ngôn ngữ đích sẽ dùng chính văn bản của nó làm bản dịch, và được chốt khi dòng đóng lại.
- Một dòng đóng lại khi người nói ngắt quãng, đổi người nói, khoảng nghỉ giữa các từ dài hơn 0.9 giây, dòng đạt hai hàng phụ đề (84 ký tự) hoặc 15 giây, hoặc bạn gửi
finalize. Khi bật dịch, một dòng có thể đóng chậm hơn khoảng 3 giây trong lúc chờ bản dịch. Khi đó bản dịch có thể vẫn mở (final: false) và tiếp tục dài thêm sau khi bản gốc đã chốt. - Dịch miễn phí. Không tốn phút.
Những ngôn ngữ đích và cặp ngôn ngữ nào dùng được tùy vào nhà cung cấp nhận dạng giọng nói trực tiếp. Hãy đọc khả năng hỗ trợ thay vì viết cứng các quy tắc vào code. Ngôn ngữ đích không được hỗ trợ sẽ trả về 422 unsupported_translation. Ví dụ, nhà cung cấp có thể yêu cầu language cụ thể thay vì auto, hoặc chỉ cho phép các cặp có tiếng Anh.
Giao thức WebSocket
Kết nối
new WebSocket(websocket_url, ['t1-live', token]);Token đi kèm dưới dạng subprotocol của WebSocket. Nó không bao giờ xuất hiện trong URL hay log truy cập. Đừng gửi header Authorization: token chính là thông tin xác thực. Server gửi ping mỗi 30 giây; trình duyệt và gói ws tự động trả lời. Socket không gửi pong trong 60 giây sẽ bị ngắt.
Một kết nối hợp lệ vào phiên đã có socket sẽ thay thế socket cũ. Xem Tiếp tục và tiếp quản.
Thông điệp từ client
| Thông điệp | Ý nghĩa |
|---|---|
| Frame nhị phân | Âm thanh: PCM s16le mono theo sample_rate của phiên. Mỗi frame có độ dài chẵn và tối đa 256 KB. Khoảng 100 ms mỗi frame là kích thước phù hợp. |
{"type":"finalize"} | Đóng dòng hiện tại ngay, ví dụ khi video bị tạm dừng. |
{"type":"end"} | Kết thúc phiên và lưu lại. Server trả lời session.ended rồi đóng socket. |
| Bất cứ thứ gì khác | Sự kiện error không nghiêm trọng với mã invalid_message. |
Frame có độ dài lẻ hoặc quá lớn là vi phạm giao thức và làm socket đóng với mã 4008.
Hãy bắt đầu gửi âm thanh sau session.started. Client gửi âm thanh nhanh hơn thời gian thực sẽ bị tính theo thời lượng âm thanh thay vì thời gian kết nối (xem Tính phí), vì vậy hãy gửi theo đúng tốc độ âm thanh được tạo ra.
Sự kiện từ server
Mỗi sự kiện là một frame văn bản JSON có type.
| Sự kiện | Được gửi khi |
|---|---|
session.started | Kết nối được chấp nhận. Từ đây hãy gửi âm thanh. |
line | Một dòng phụ đề được tạo hoặc thay đổi. |
usage | Sau mỗi lần tính phí. |
warning | Có điều cần lưu ý nhưng phiên vẫn tiếp tục. |
error | Một sự cố không nghiêm trọng, hoặc lý do dẫn đến đóng ngay. |
reconnect | Server sắp khởi động lại. Hãy tiếp tục phiên. |
session.ended | Phiên đã kết thúc và được lưu. Sự kiện cuối cùng trước khi đóng bình thường. |
session.started cho biết đây có phải lần tiếp tục không và phiên đã xử lý bao nhiêu âm thanh:
{
"type": "session.started",
"session_id": "lv_8fK2Lm0PqRsTuVwXyZaBcD",
"transcription_id": "tr_3NcQvXy7BtHjKd5ErFgLmA",
"resumed": false,
"offset_ms": 0
}line mang toàn bộ trạng thái hiện tại của một dòng, vì vậy hãy thay dòng bạn đang giữ có cùng id. Xem Object dòng.
{
"type": "line",
"line": {
"id": 12,
"start_ms": 53120,
"end_ms": 56040,
"speaker": null,
"language": "en",
"text": "Welcome back to the stream",
"final": true,
"translation": { "language": "es", "text": "Bienvenidos de nuevo", "final": false }
}
}usage được gửi sau mỗi lần tính phí, kèm thời gian kết nối, thời lượng âm thanh, số phút số dư đã bị tính cho đến lúc đó và số phút còn lại:
{
"type": "usage",
"connected_ms": 61240,
"audio_ms": 60100,
"minutes_charged": 2,
"minutes_remaining": 898
}warning có một code:
code | Ý nghĩa |
|---|---|
balance_low | Lần tính phí tiếp theo sẽ thất bại. Phiên kết thúc với balance_exhausted khi đến hạn. Không được gửi khi tự động nạp đang bật. |
audio_dropped | Âm thanh đến trước khi phiên sẵn sàng, hoặc quá nhiều âm thanh đến trong lúc nhà cung cấp giọng nói đang kết nối. Âm thanh cũ nhất bị bỏ. |
idle_timeout_soon | Đã 4 phút không có âm thanh. Phiên kết thúc sau 5 phút không có âm thanh. Hãy gửi âm thanh để giữ phiên. |
{ "type": "warning", "code": "idle_timeout_soon" }error có code và message. Các mã sau có thể đến trên socket trực tiếp:
code | Nghiêm trọng | Ý nghĩa |
|---|---|---|
invalid_message | Không | Một frame văn bản không phải finalize hay end. |
invalid_token | Có | Token không hợp lệ, đã hết hạn hoặc đã được dùng. Socket đóng với mã 4001. |
not_found | Có | Phiên không tồn tại. Socket đóng với mã 4004. |
session_ended | Có | Phiên đã kết thúc. Socket đóng với mã 4004. |
{ "type": "error", "code": "invalid_message", "message": "Expected {\"type\":\"finalize\"} or {\"type\":\"end\"}" }reconnect đến trước khi server đóng socket với mã 1012, ví dụ khi đang triển khai bản mới. Hãy lấy token mới và tiếp tục phiên.
{ "type": "reconnect", "reason": "server_restart" }session.ended là sự kiện cuối cùng của mọi phiên. Các con số là tổng cuối cùng:
{
"type": "session.ended",
"reason": "client_ended",
"transcription_id": "tr_3NcQvXy7BtHjKd5ErFgLmA",
"minutes_charged": 3,
"connected_ms": 142500,
"audio_ms": 141900
}Object dòng
| Trường | Ý nghĩa |
|---|---|
id | Số bắt đầu từ 0 và tăng thêm một cho mỗi dòng. Đây là chỉ số segment trong transcript đã lưu. |
start_ms, end_ms | Thời điểm bắt đầu và kết thúc theo thời gian âm thanh của phiên. Thời gian này liên tục qua các lần kết nối lại. |
speaker | Nhãn người nói khi bật diarize, nếu không thì null. Nhãn giống như trong transcript thông thường. |
language | Ngôn ngữ được nhận diện hoặc được chỉ định của dòng, hoặc null khi chưa biết. |
text | Văn bản gốc cho đến lúc này. |
final | true khi văn bản gốc sẽ không đổi nữa. |
translation | null nếu không có translate_to, nếu không thì gồm language, text và final. |
Hãy hiển thị các dòng có final: false bằng kiểu nhạt hơn: văn bản của chúng vẫn có thể đổi. Văn bản của dòng có final: true không bao giờ đổi nữa, và dòng đã chốt không bao giờ bị xóa.
SDK dùng camelCase cho các trường của dòng: startMs, endMs.
Lý do kết thúc
session.ended và GET /v1/live/sessions/:id trả về end_reason:
| Lý do | Ý nghĩa |
|---|---|
client_ended | Bạn đã gửi end. |
balance_exhausted | Lần tính phí tiếp theo thất bại. Phiên kết thúc ở ranh giới phút và được lưu. |
idle_timeout | Không có âm thanh trong 5 phút. |
max_duration | Phiên đã kết nối 300 phút. Hãy bắt đầu phiên mới. |
disconnected | Client biến mất hơn 2 phút mà không tiếp tục phiên. |
upstream_error | Nhà cung cấp giọng nói gặp lỗi. |
internal_error | Có sự cố ở phía chúng tôi. |
not_connected | Phiên chưa từng được kết nối trong 5 phút. Phiên này không bao giờ bị tính phí và chỉ xem được qua GET. |
Mã đóng
| Mã | Ý nghĩa |
|---|---|
1000 | Đóng bình thường. Luôn đi sau session.ended. |
1011 | Lỗi server ngoài dự kiến. Server tự khôi phục phiên: hãy tiếp tục bằng token mới. |
1012 | Server khởi động lại. Đi sau reconnect: hãy tiếp tục bằng token mới. |
4001 | Token không hợp lệ, đã hết hạn hoặc đã được dùng. |
4004 | Không tìm thấy phiên hoặc phiên đã kết thúc. |
4008 | Vi phạm giao thức: frame nhị phân có độ dài lẻ hoặc quá lớn. |
4010 | Bị thay thế bởi một kết nối mới hơn vào cùng phiên. |
Trong lúc API khởi động lại, một request WebSocket mới có thể nhận HTTP 503. Hãy thử lại sau ít phút.
Tiếp tục và tiếp quản
Phiên vẫn tồn tại khi mạng đứt, khi API được triển khai lại và khi có sự cố. Sau khi mất kết nối, phiên chờ bạn trong 2 phút; quá thời gian đó phiên kết thúc với lý do disconnected và được lưu.
- Gọi
POST /v1/live/sessions/:id/token. Response gồmtoken,token_expires_atvàwebsocket_url, giống các trường khi bạn tạo phiên. Lệnh này thất bại với409 session_endedkhi phiên đã kết thúc. - Mở một WebSocket mới bằng token đó.
session.startedđến vớiresumed: true.offset_mslà lượng âm thanh phiên đã xử lý: hãy tiếp tục âm thanh từ điểm đó. Id của dòng được đánh số tiếp.
Các dòng đã chốt được giữ lại. Phần đang dở tại thời điểm mất kết nối sẽ mất, vì vậy nếu bạn có đệm âm thanh, hãy gửi lại vài giây âm thanh từ offset_ms. Khoảng thời gian kết nối lại không bị tính phí.
Tiếp quản cũng là cùng lệnh gọi đó. Nếu server vẫn nghĩ một socket đang mở, kết nối hợp lệ mới sẽ thay thế nó, và socket cũ bị đóng với mã 4010 sau khi các dòng của nó được lưu. Giới hạn số phiên đồng thời không bao giờ chặn việc tiếp tục phiên.
SDK làm tất cả việc này giúp bạn: khi mất kết nối hoặc nhận sự kiện reconnect, SDK lấy token và kết nối lại với khoảng chờ tăng dần từ 0.5 đến 8 giây trong tối đa 2 phút, rồi gửi lại 10 giây âm thanh cuối cùng mà bạn đã gửi trong lúc gián đoạn.
Tính phí
Chuyển thành văn bản trực tiếp trừ vào cùng số dư phút với các transcription thông thường.
- Thời gian kết nối được tính phí, từ lúc socket được chấp nhận đến khi đóng. Im lặng và video bị tạm dừng cũng được tính. Khoảng thời gian giữa lúc mất kết nối và lúc tiếp tục thì không.
- Tính theo từng phút đã bắt đầu, tối thiểu 1. Phút đầu tiên bị tính khi kết nối đầu tiên được chấp nhận, và mỗi phút sau bị tính khi phút đó bắt đầu.
- Nhanh hơn thời gian thực thì tính theo thời lượng âm thanh. Nếu âm thanh bạn gửi dài hơn thời gian kết nối, hệ thống tính thời lượng âm thanh.
- Hệ số lấy từ API. Một phút đã bắt đầu tốn
ratephút số dư, làm tròn lên. Hệ số thường là 1 và có thể là số thập phân. Hãy đọc hệ số trực tiếp từrates.livetrongGET /v1/account, từratetrongGET /v1/live/capabilitiesvà từratecủa phiên bạn tạo. Hệ số của một phiên được cố định sau khi phiên được tạo. - Dịch miễn phí.
- Chưa từng kết nối thì không bị tính phí. Phiên không được kết nối trong 5 phút sẽ kết thúc với
not_connected. - Lỗi được hoàn phí. Nếu phiên kết thúc với
upstream_errorhoặcinternal_errortrước khi tạo ra dòng nào, mọi khoản đã tính đều được hoàn lại. Phiên rỗng do im lặng vẫn bị tính phí và được lưu rỗng. - Khi hết số dư và tự động nạp đang bật, transcript1 trừ tiền thẻ đã lưu trong lúc phiên vẫn tiếp tục phát trực tiếp, và phiên được tiếp tục. Nếu tự động nạp tắt hoặc bị tạm dừng, hoặc việc trừ tiền thất bại, phiên được chốt, lưu và kết thúc với
balance_exhaustedở ranh giới phút. Cảnh báobalance_lowđến trước, trừ khi tự động nạp đang bật.
Tạo phiên trả về 402 insufficient_minutes khi số dư dùng được thấp hơn một phút đã bắt đầu theo hệ số hiện tại. Nếu tự động nạp đang bật, transcript1 sẽ thử nạp trước. Xem Thanh toán và giới hạn.
Giới hạn
| Free | Monthly | Annual | |
|---|---|---|---|
| Phiên trực tiếp cùng lúc | 1 | 2 | 3 |
- Một phiên được tính khi ở trạng thái
waiting,connectedhoặcdisconnected(trong khoảng 2 phút chờ tiếp tục). Vượt giới hạn,POST /v1/live/sessionstrả về429 too_many_live_sessionskèmRetry-After: 30. - Phiên trực tiếp không tính vào giới hạn job đang chạy của bạn.
- Một phiên kéo dài tối đa 300 phút thời gian kết nối. Sau đó phiên kết thúc với
max_duration. - Phiên không có âm thanh trong 5 phút kết thúc với
idle_timeout; bạn nhậnidle_timeout_soonsau 4 phút. Luồng bị tạm dừng vẫn bị tính thời gian kết nối và được coi là nhàn rỗi, nên hãy kết thúc phiên nếu tạm dừng lâu. - transcript1 giới hạn tổng của tất cả phiên trực tiếp. Khi đã dùng hết,
POST /v1/live/sessionstrả về503 live_capacity, lỗi có thể thử lại. Hãy chờRetry-After(30 giây) rồi thử lại. Giới hạn này chỉ được kiểm tra khi tạo phiên, không bao giờ kiểm tra giữa chừng. - Việc tạo phiên và lấy token được tính vào giới hạn request mỗi phút của bạn.
- Âm thanh chỉ là PCM thô:
pcm_s16le, mono, từ 8000 đến 48000 Hz.
Khả năng hỗ trợ
GET /v1/live/capabilities mô tả những gì chế độ trực tiếp đang hỗ trợ, để client không phải viết cứng quy tắc của nhà cung cấp. Quyền cần có là transcriptions:read.
{
"available": true,
"auto_language": true,
"languages": ["en", "es"],
"translation": {
"targets": ["es", "de"],
"pairs": "any",
"requires_language": false
},
"diarize": true,
"audio_formats": ["pcm_s16le"],
"sample_rate": { "min": 8000, "max": 48000 },
"max_session_minutes": 300,
"rate": 1
}Các danh sách ở đây đã được rút gọn. Hãy đọc đầy đủ từ API.
translation.pairslà"any"(từ mọi ngôn ngữ được nhận diện sang mọi ngôn ngữ đích), hoặc một danh sách object cófromvàto.translation.requires_languagelàtruekhi việc dịch cầnlanguagecụ thể thay vìauto.- Khi chế độ trực tiếp chưa được cấu hình, response là
available: falsechỉ kèmrate, và việc tạo phiên trả về503 live_unavailable.
Với SDK: await t1.live.capabilities().
Xem một phiên
GET /v1/live/sessions/:id trả về trạng thái của một phiên. Quyền cần có là transcriptions:read.
curl https://api.transcript1.com/v1/live/sessions/lv_8fK2Lm0PqRsTuVwXyZaBcD \
-H "Authorization: Bearer $TRANSCRIPT1_API_KEY"{
"id": "lv_8fK2Lm0PqRsTuVwXyZaBcD",
"status": "ended",
"end_reason": "client_ended",
"transcription_id": "tr_3NcQvXy7BtHjKd5ErFgLmA",
"options": {
"language": "en",
"translate_to": "es",
"diarize": false,
"audio_format": "pcm_s16le",
"sample_rate": 16000,
"save": true
},
"connected_ms": 142500,
"audio_ms": 141900,
"minutes_charged": 3,
"rate": 1,
"created_at": "2026-11-02T11:58:12Z",
"ended_at": "2026-11-02T12:00:35Z"
}status là waiting, connected, disconnected hoặc ended. end_reason là null cho đến khi phiên kết thúc. Với SDK: await t1.live.get(id).
Lỗi
Lỗi request dùng cấu trúc lỗi quen thuộc. Đây là các lỗi mà POST /v1/live/sessions và các endpoint liên quan trả về:
| Mã HTTP | code | Có thể thử lại | Khi nào |
|---|---|---|---|
| 422 | invalid_request | Không | Một trường bị thiếu hoặc không hợp lệ, ví dụ sample_rate ngoài khoảng 8000 đến 48000. |
| 422 | unsupported_language | Không | language không được chế độ trực tiếp hỗ trợ. |
| 422 | unsupported_translation | Không | Ngôn ngữ đích, hoặc cặp ngôn ngữ, không được hỗ trợ. |
| 402 | insufficient_minutes | Không | Số dư dùng được thấp hơn một phút đã bắt đầu theo hệ số hiện tại. |
| 403 | email_not_verified | Không | Hãy xác minh email trước. |
| 429 | too_many_live_sessions | Có | Số phiên trực tiếp cùng lúc của gói bạn đã dùng hết. Chờ theo Retry-After. |
| 503 | live_capacity | Có | Toàn bộ dung lượng trực tiếp đang được dùng. Chờ theo Retry-After (30 giây). |
| 503 | live_unavailable | Không | Chế độ trực tiếp hiện không khả dụng. |
| 409 | session_ended | Không | POST /v1/live/sessions/:id/token cho một phiên đã kết thúc. |
Sự cố trên socket đến dưới dạng sự kiện error và mã đóng.
Transcript đã lưu
Với save: true (mặc định), phiên được lưu thành một transcription thông thường khi kết thúc. Âm thanh không bao giờ được lưu.
transcription_idđược trả về khi bạn tạo phiên. Trạng thái của nó làlivetrong lúc phiên chạy vàcompletedsau khi phiên kết thúc. Phiên chưa từng kết nối để lại một transcription ở trạng tháicanceled.- Transcription có
source: { "platform": "live", "session_id": "lv_…" }. Không có link hay file. Bảng điều khiển liệt kê nó như một phiên trực tiếp. - Mỗi dòng trở thành một segment, có cùng chỉ số với
idcủa dòng. Đọc transcript dưới dạng JSON, văn bản, SRT hoặc VTT như mọi transcription khác: xem Tài liệu API. - Bản dịch trực tiếp được lưu cùng. Đọc nó bằng tham số
translation, như mô tả trong Dịch. - Có thể thêm ngôn ngữ dịch khác sau bằng
POST /v1/transcriptions/:id/translationskhi transcription đãcompleted. Xem Dịch.
Với save: false, không có gì được giữ lại sau khi phiên kết thúc: không có transcription và transcription_id là null. Bạn vẫn nhận mọi dòng qua socket và vẫn bị tính phí như bình thường.
Bảo mật
- Token bạn nhận khi tạo phiên chỉ dùng được một lần và hết hạn sau 60 giây. Nó được gửi dưới dạng subprotocol WebSocket, không nằm trong URL, nên không lọt vào log truy cập. Token bị lộ sẽ vô dụng sau khi đã dùng hoặc hết hạn.
- Chỉ dùng khóa API từ server do bạn kiểm soát. Đừng bao giờ đặt khóa API trong trang web hay tiện ích mở rộng.
- Trong trình duyệt hoặc tiện ích mở rộng, hãy cho người dùng đăng nhập bằng OAuth và truyền OAuth access token vào
getAccessTokencủacreateLiveClient. Token cần quyềntranscriptions:writeđể bắt đầu phiên. OAuth access token hết hạn sau 1 giờ, và mỗi lần tiếp tục phiên đều gọigetAccessTokenđể lấy token mới. - Server của bạn cũng có thể tạo phiên bằng khóa API rồi chỉ chuyển
websocket_urlvàtokencho trình duyệt. Khi đó client kết nối trực tiếp. Client không thể tiếp tục phiên nếu không có token mới từ bạn.
Cập nhật lần cuối 3 tháng 11, 2026