Skip to content

Commit 26333cc

Browse files
committed
feat: add global usage & max option
1 parent 333ed5d commit 26333cc

File tree

6 files changed

+64
-29
lines changed

6 files changed

+64
-29
lines changed

packages/translate/src/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ program
3333
'-t, --target-language <language>',
3434
'Specify the target language code for translation (e.g., "zh-CN", "fr", "es")',
3535
)
36+
.option(
37+
'--max <number>',
38+
'Maximum number of files to process in one batch (per language) (default: unlimited)',
39+
)
3640
.action(
3741
async (options: {
3842
config?: string;
@@ -41,6 +45,7 @@ program
4145
docsPath?: string;
4246
listOnly?: boolean;
4347
targetLanguage?: string;
48+
max?: number;
4449
}) => {
4550
if (options.verbose) {
4651
logger.setVerbose(true);
@@ -54,6 +59,7 @@ program
5459
...config,
5560
...(options.pattern ? { pattern: options.pattern } : {}),
5661
...(options.docsPath ? { docsPath: options.docsPath } : {}),
62+
...(options.max ? { max: options.max } : {}),
5763
listOnly: options.listOnly,
5864
targetLanguage: options.targetLanguage,
5965
});

packages/translate/src/main.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import micromatch from 'micromatch';
44
import { executeInBatches } from './batch';
55
import { logger } from './logger';
66
import type { MainConfig } from './types';
7+
import { GlobalUsage } from './usage';
78
import {
89
findDocFiles,
910
getDocUpdateStatus,
@@ -19,6 +20,7 @@ export async function main({
1920
outputRoot = 'content',
2021
docsPath = ['**/*.mdx'],
2122
listOnly,
23+
max = Number.POSITIVE_INFINITY,
2224
targetLanguage,
2325
}: MainConfig): Promise<void> {
2426
// Filter languages based on targetLanguage if specified
@@ -76,6 +78,10 @@ export async function main({
7678
logger.info(`Using patterns: ${processedPatterns.join(', ')}`);
7779
}
7880

81+
if (max !== Number.POSITIVE_INFINITY) {
82+
logger.info(`Limiting to ${max} files per language to process`);
83+
}
84+
7985
// Process each language
8086
for (const [lang, langConfig] of Object.entries(filteredLangs)) {
8187
logger.divider();
@@ -135,7 +141,7 @@ export async function main({
135141
);
136142

137143
// Build tasks list and document status table
138-
const tasks = [];
144+
let tasks = [];
139145
const tableData = [];
140146

141147
for (const docPath of filteredPaths) {
@@ -174,6 +180,12 @@ export async function main({
174180
logger.info(
175181
`Found ${tasks.length}/${filteredPaths.length} documents to update`,
176182
);
183+
if (tasks.length > max) {
184+
logger.warn(
185+
`Limiting to ${max} files to process. You can increase this limit with the --max option.`,
186+
);
187+
tasks = tasks.slice(0, max);
188+
}
177189

178190
// Process tasks if not in list-only mode
179191
if (!listOnly) {
@@ -207,4 +219,7 @@ export async function main({
207219
}
208220

209221
logger.divider();
222+
logger.info(
223+
`Usage statistics for the completion request:\n${JSON.stringify(GlobalUsage, null, 2)}`,
224+
);
210225
}

packages/translate/src/openai.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
splitIntoChunks,
88
} from './chunk';
99
import { logger } from './logger';
10+
import { type Usage, addUsage } from './usage';
1011

1112
interface LangConfig {
1213
name: string;
@@ -95,6 +96,7 @@ HERE IS THE TEXT TO TRANSLATE:
9596
});
9697

9798
logger.debug(`response.usage:\n${JSON.stringify(response.usage, null, 2)}`);
99+
addUsage(response.usage as Usage);
98100
const message = response.choices?.[0]?.message;
99101

100102
if (!message?.content) {

packages/translate/src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export interface MainConfig {
2424
docsContext?: string;
2525
pattern?: string | string[];
2626
docsPath?: string | string[];
27+
max?: number;
2728
listOnly?: boolean;
2829
targetLanguage?: string;
2930
}

packages/translate/src/usage.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/**
2+
* Usage statistics for the completion request.
3+
*/
4+
export const GlobalUsage = {
5+
completion_tokens: 0, // Number of tokens in the generated completion.
6+
prompt_tokens: 0, // Number of tokens in the prompt. It equals prompt_cache_hit_tokens + prompt_cache_miss_tokens.
7+
total_tokens: 0, // Total number of tokens used in the request (prompt + completion).
8+
prompt_cache_hit_tokens: 0, // Number of tokens in the prompt that hits the context cache.
9+
prompt_cache_miss_tokens: 0, // Number of tokens in the prompt that misses the context cache.
10+
};
11+
12+
export type Usage = typeof GlobalUsage;
13+
14+
export function addUsage(usage: Usage): Usage {
15+
if (!usage) {
16+
return GlobalUsage;
17+
}
18+
if (usage.prompt_tokens) {
19+
GlobalUsage.prompt_tokens += usage.prompt_tokens;
20+
}
21+
if (usage.completion_tokens) {
22+
GlobalUsage.completion_tokens += usage.completion_tokens;
23+
}
24+
if (usage.total_tokens) {
25+
GlobalUsage.total_tokens += usage.total_tokens;
26+
}
27+
if (usage.prompt_cache_hit_tokens) {
28+
GlobalUsage.prompt_cache_hit_tokens += usage.prompt_cache_hit_tokens;
29+
}
30+
if (usage.prompt_cache_miss_tokens) {
31+
GlobalUsage.prompt_cache_miss_tokens += usage.prompt_cache_miss_tokens;
32+
}
33+
34+
return GlobalUsage;
35+
}

packages/translate/src/utils.ts

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -76,38 +76,14 @@ export async function getDocUpdateStatus({
7676
const chunks = needsChunking(sourceContent)
7777
? splitIntoChunks(sourceContent).length
7878
: 1;
79-
const sourceParsed = matter(sourceContent);
80-
81-
let sourceLastModifiedDate = getLastModifiedTimeFromGit(sourcePath);
82-
if (sourceParsed.data.ref) {
83-
try {
84-
await fs$.access(sourceParsed.data.ref);
85-
} catch (error) {
86-
logger.error(
87-
`Referenced file not found: ${sourceParsed.data.ref}, don't need updating, consider REMOVING it`,
88-
);
89-
return {
90-
shouldUpdate: false,
91-
reason: 'Referenced file not found',
92-
chunks,
93-
};
94-
}
95-
96-
const refLastModifiedDate = getLastModifiedTimeFromGit(
97-
sourceParsed.data.ref,
98-
);
99-
if (refLastModifiedDate > sourceLastModifiedDate) {
100-
sourceLastModifiedDate = refLastModifiedDate;
101-
}
102-
}
10379

10480
try {
10581
await fs$.access(targetPath);
10682
} catch (error) {
10783
logger.debug(`Target file not found: ${targetPath}, needs updating`);
10884
return { shouldUpdate: true, reason: 'Target not found.', chunks };
10985
}
110-
86+
const sourceLastModifiedDate = getLastModifiedTimeFromGit(sourcePath);
11187
// Read target file and parse frontmatter
11288
const targetContent = await fs$.readFile(targetPath, 'utf8');
11389
const targetParsed = matter(targetContent);
@@ -126,13 +102,13 @@ export async function getDocUpdateStatus({
126102
);
127103
return {
128104
shouldUpdate: true,
129-
reason: 'Source has been modified. ',
105+
reason: 'Source modified.',
130106
chunks,
131107
};
132108
}
133109
return {
134110
shouldUpdate: false,
135-
reason: 'Source has not been modified.',
111+
reason: 'Source not modified.',
136112
chunks,
137113
};
138114
}
@@ -143,7 +119,7 @@ export async function getDocUpdateStatus({
143119
);
144120
return {
145121
shouldUpdate: true,
146-
reason: 'Target no source-updated-at metadata, needs updating.',
122+
reason: 'Target has no source-updated-at metadata.',
147123
chunks,
148124
};
149125
}

0 commit comments

Comments
 (0)