Skip to content

Commit 72e1218

Browse files
committed
Increase translation batch size from 3 to 8
Send eight semantic segments per request so a typical viewport finishes in one round-trip. Raise the background cap and max tokens to match.
1 parent ae5aa76 commit 72e1218

7 files changed

Lines changed: 31 additions & 17 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,9 @@ Current as of August 10, 2026, DeepSeek lists the following prices per 1 million
134134

135135
DeepSeek says these prices may increase soon, so check the current pricing page before relying on this estimate. Its official [token usage guide](https://api-docs.deepseek.com/quick_start/token_usage/) estimates about 0.3 token per English character and about 0.6 token per Chinese character. Its [context caching guide](https://api-docs.deepseek.com/guides/kv_cache/) explains the automatic best-effort disk cache used for repeated prefixes.
136136

137-
A measured 20-minute English talk contained **2,935 spoken English words** and 15,433 transcript characters. With YouTube Digest's current grouping, it became 128 semantic segments and 43 requests of three segments each. Repeated prompts and JSON brought the rendered input to about 108,528 English characters, or **about 32,600 input tokens** using DeepSeek's 0.3 token per English character heuristic. The translated Chinese JSON output is estimated at about 3,500 to 4,500 tokens using the 0.6 token per Chinese character heuristic, plus JSON and ID overhead.
137+
A measured 20-minute English talk contained **2,935 spoken English words** and 15,433 transcript characters. With YouTube Digest's current grouping, it became 128 semantic segments and 16 requests of eight segments each. Repeated prompts and JSON bring the rendered input to about 50,100 English characters, or **about 15,000 input tokens** using DeepSeek's 0.3 token per English character heuristic. The translated Chinese JSON output is estimated at about 3,500 to 4,500 tokens using the 0.6 token per Chinese character heuristic, plus JSON and ID overhead.
138138

139-
If all input is billed as cache miss, input costs about $0.0046 and output costs about $0.0010 to $0.0013, for a total of about $0.0056 to $0.0059. When much of the repeated system prompt hits DeepSeek's automatic best-effort cache, a realistic lower end is about $0.002 to $0.003. A practical estimate for fully translating this talk is therefore **$0.002 to $0.006 USD, about ¥0.02 to ¥0.04**.
139+
If all input is billed as cache miss, input costs about $0.0021 and output costs about $0.0010 to $0.0013, for a total of about $0.0031 to $0.0034. When much of the repeated system prompt hits DeepSeek's automatic best-effort cache, a realistic lower end is about $0.001 to $0.002. A practical estimate for fully translating this talk is therefore **$0.001 to $0.004 USD, about ¥0.01 to ¥0.03**.
140140

141141
Translation is lazy and progressive. Cached segments are reused, and only rows you request by scrolling into them incur calls. Retries, provider behavior, and pricing changes can increase the final cost.
142142

README.zh-CN.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,9 @@ DeepSeek 的额度与 Supadata 分开计算。DeepSeek 可能有自己的免费
134134

135135
DeepSeek 说明这些价格可能很快上调,因此使用此估算前必须查看当前价格页面。官方 [token 用量指南](https://api-docs.deepseek.com/quick_start/token_usage/)估算每个英文字符约为 0.3 token,每个中文字符约为 0.6 token。[上下文缓存指南](https://api-docs.deepseek.com/guides/kv_cache/)说明了重复前缀使用的自动尽力而为磁盘缓存。
136136

137-
一个实测的 20 分钟英文演讲包含 **2,935 个英文口语词**和 15,433 个字幕字符。按 YouTube Digest 当前的分组方式,它会变成 128 个语义分段,以每次 3 段的方式发出 43 次请求。算上重复 prompt 和 JSON 后,渲染后的输入约为 108,528 个英文字符,按官方每个英文字符 0.3 token 的经验值,即**32,600 个输入 token**。按每个中文字符 0.6 token 的经验值,再加上 JSON 和 ID 开销,中文 JSON 输出估计为 3,500 到 4,500 token。
137+
一个实测的 20 分钟英文演讲包含 **2,935 个英文口语词**和 15,433 个字幕字符。按 YouTube Digest 当前的分组方式,它会变成 128 个语义分段,以每次 8 段的方式发出 16 次请求。算上重复 prompt 和 JSON 后,渲染后的输入约为 50,100 个英文字符,按官方每个英文字符 0.3 token 的经验值,即**15,000 个输入 token**。按每个中文字符 0.6 token 的经验值,再加上 JSON 和 ID 开销,中文 JSON 输出估计为 3,500 到 4,500 token。
138138

139-
如果所有输入都按缓存未命中计费,输入约 $0.0046,输出约 $0.0010 到 $0.0013,总计约 $0.0056 到 $0.0059。当大量重复的 system prompt 命中 DeepSeek 自动尽力而为缓存时,更现实的低值约为 $0.002 到 $0.003。完整翻译这段演讲的实用估算是 **$0.002 到 $0.006 USD,约 ¥0.02 到 ¥0.04**
139+
如果所有输入都按缓存未命中计费,输入约 $0.0021,输出约 $0.0010 到 $0.0013,总计约 $0.0031 到 $0.0034。当大量重复的 system prompt 命中 DeepSeek 自动尽力而为缓存时,更现实的低值约为 $0.001 到 $0.002。完整翻译这段演讲的实用估算是 **$0.001 到 $0.004 USD,约 ¥0.01 到 ¥0.03**
140140

141141
翻译是延迟按需和渐进式的。已缓存的分段会复用,只有滚动到并请求的字幕行才会发起调用。重试、服务商行为和价格变化都可能增加最终成本。
142142

background.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1448,8 +1448,8 @@ async function getTranslationBaseRules(targetLanguage) {
14481448

14491449
function validateTranscriptBatchRequest(content) {
14501450
const segments = content?.segments;
1451-
if (!Array.isArray(segments) || segments.length < 1 || segments.length > 4) {
1452-
throw new Error("Transcript translation requires 1 to 4 segments");
1451+
if (!Array.isArray(segments) || segments.length < 1 || segments.length > 8) {
1452+
throw new Error("Transcript translation requires 1 to 8 segments");
14531453
}
14541454

14551455
const seenIds = new Set();
@@ -1563,7 +1563,7 @@ async function handleTranslateContent(
15631563
const userContent = JSON.stringify({ segments: sourceSegments });
15641564
const translationOptions = {
15651565
temperature: 0.2,
1566-
maxTokens: 1536,
1566+
maxTokens: 4096,
15671567
responseFormat: { type: "json_object" },
15681568
};
15691569
let result = await callAiTranslation(

prompts/translation.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ TRANSLATION RULES (follow strictly):
2727

2828
## Transcript batch translation
2929

30-
Input is a JSON object with 1 to 4 complete semantic transcript segments. Each
30+
Input is a JSON object with 1 to 8 complete semantic transcript segments. Each
3131
segment has a stable `id` and source-language `text`.
3232

3333
```

sidepanel.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ let transcriptScrollObserver = null;
3939
// Stable keys include the video, source mode, language, and semantic segment ID.
4040
let transcriptParagraphCache = new Map();
4141
const TRANSLATION_MESSAGE_TIMEOUT_MS = 130_000;
42+
const TRANSLATION_BATCH_SIZE = 8;
4243

4344
/**
4445
* Prevent a stopped service worker or dead message channel from leaving the
@@ -1989,7 +1990,7 @@ function retryTranslationSegment(index, generation) {
19891990
}
19901991

19911992
/**
1992-
* Renders immediately, translates the first small batch, then observes the
1993+
* Renders immediately, translates the first visible batch, then observes the
19931994
* remaining rows. Batches are sequential so the provider is never flooded.
19941995
*/
19951996
async function translateTranscript() {
@@ -2011,7 +2012,7 @@ async function translateTranscript() {
20112012
if (processing || queue.length === 0 || generation !== translationGeneration)
20122013
return;
20132014
processing = true;
2014-
const indices = queue.splice(0, 3);
2015+
const indices = queue.splice(0, TRANSLATION_BATCH_SIZE);
20152016
indices.forEach((index) => queued.delete(index));
20162017
try {
20172018
await requestTranscriptTranslationBatch(
@@ -2061,7 +2062,7 @@ async function translateTranscript() {
20612062

20622063
rows.forEach((row, index) => {
20632064
if (!row.classList.contains("translated")) transcriptScrollObserver.observe(row);
2064-
if (index < 3) enqueue(index);
2065+
if (index < TRANSLATION_BATCH_SIZE) enqueue(index);
20652066
});
20662067
}
20672068

tests/release.test.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,15 +101,15 @@ test("release copy documents current scope without em dashes", () => {
101101
assert.match(readme, /api-docs\.deepseek\.com\/guides\/kv_cache/i);
102102
assert.match(readme, /\$0\.0028[\s\S]*\$0\.14[\s\S]*\$0\.28/);
103103
assert.match(readme, /2,935 spoken English words/i);
104-
assert.match(readme, /about 32,600 input tokens/i);
105-
assert.match(readme, /\$0\.002[^\n]*\$0\.006 USD/i);
104+
assert.match(readme, /about 15,000 input tokens/i);
105+
assert.match(readme, /\$0\.001[^\n]*\$0\.004 USD/i);
106106
assert.match(chineseReadme, /api-docs\.deepseek\.com\/quick_start\/pricing/i);
107107
assert.match(chineseReadme, /api-docs\.deepseek\.com\/quick_start\/token_usage/i);
108108
assert.match(chineseReadme, /api-docs\.deepseek\.com\/guides\/kv_cache/i);
109109
assert.match(chineseReadme, /\u00a50\.02[\s\S]*\u00a51[\s\S]*\u00a52/);
110110
assert.match(chineseReadme, /2,935 \u4e2a\u82f1\u6587\u53e3\u8bed\u8bcd/);
111-
assert.match(chineseReadme, /\u7ea6 32,600 \u4e2a\u8f93\u5165 token/);
112-
assert.match(chineseReadme, /\$0\.002[^\n]*\$0\.006 USD/);
111+
assert.match(chineseReadme, /\u7ea6 15,000 \u4e2a\u8f93\u5165 token/);
112+
assert.match(chineseReadme, /\$0\.001[^\n]*\$0\.004 USD/);
113113
assert.match(chineseReadme, /dash\.supadata\.ai\/auth\/sign-up/i);
114114
assert.match(chineseReadme, /platform\.deepseek\.com\/api_keys/i);
115115
assert.match(readme, /^### The Digest button is missing on a YouTube video$/m);

tests/translation.test.js

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ test("Transcript header exposes and wires Original, Chinese, and bilingual modes
173173
assert.match(html, /data-transcript-mode="bilingual"[\s\S]*?>\u53cc\u8bed</);
174174
assert.match(js, /handleTranscriptModeChange\(button\.dataset\.transcriptMode\)/);
175175
assert.match(js, /contentType: "transcriptBatch"/);
176+
assert.match(js, /TRANSLATION_BATCH_SIZE = 8/);
176177
assert.doesNotMatch(js, /English \+ Chinese/);
177178
assert.match(js, /Original \(\$\{language\}\)/);
178179
});
@@ -315,7 +316,19 @@ test("background rejects unsupported language fallthrough and malformed batches"
315316
assert.match(source, /targetLanguage !== "zh"/);
316317
assert.throws(
317318
() => validateTranscriptBatchRequest({ segments: [] }),
318-
/1 to 4 segments/,
319+
/1 to 8 segments/,
320+
);
321+
const eight = Array.from({ length: 8 }, (_, index) => ({
322+
id: `segment-${index}-0`,
323+
text: "Hello.",
324+
}));
325+
assert.equal(validateTranscriptBatchRequest({ segments: eight }).length, 8);
326+
assert.throws(
327+
() =>
328+
validateTranscriptBatchRequest({
329+
segments: [...eight, { id: "segment-8-0", text: "Too many." }],
330+
}),
331+
/1 to 8 segments/,
319332
);
320333
assert.throws(
321334
() =>
@@ -544,7 +557,7 @@ test("DeepSeek retries one empty transcript JSON response without response_forma
544557
assert.equal(requests.length, 2);
545558
assert.deepEqual(requests[0].response_format, { type: "json_object" });
546559
assert.equal(Object.hasOwn(requests[1], "response_format"), false);
547-
assert.equal(requests[0].max_tokens, 1536);
560+
assert.equal(requests[0].max_tokens, 4096);
548561
});
549562

550563
test("translation message watchdog rejects, clears its timer, and ignores late replies", async () => {

0 commit comments

Comments
 (0)