transl8-srt 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -39,8 +39,20 @@ interface TranslateOptions {
39
39
  batchSize?: number;
40
40
  /** Context overlap: N sentences from the prev batch prepended (default 4) */
41
41
  contextOverlap?: number;
42
- /** OpenAI model override. Defaults to gpt-4o for non-Latin scripts, gpt-4o-mini otherwise */
43
- model?: "gpt-4o" | "gpt-4o-mini";
42
+ /**
43
+ * Model for translation batches.
44
+ * OpenAI users: defaults to "gpt-4o" for complex scripts, "gpt-4o-mini" otherwise.
45
+ * Custom client users (DeepSeek, Groq, etc.): set this to your provider's model name,
46
+ * e.g. "deepseek-chat". Auto-selection only works for OpenAI model names.
47
+ */
48
+ model?: "gpt-4o" | "gpt-4o-mini" | (string & {});
49
+ /**
50
+ * Fallback model used when auto-selection would normally pick gpt-4o-mini
51
+ * but you're on a custom provider. Only needed if you want different models
52
+ * for different language complexity tiers on a non-OpenAI backend.
53
+ * Most custom client users should just set `model` and leave this unset.
54
+ */
55
+ modelFallback?: string;
44
56
  /** Max concurrent batch requests (default 8) */
45
57
  concurrency?: number;
46
58
  /** Enable AI primer call — for general/unknown content only */
@@ -89,7 +101,12 @@ declare class SubtitleTranslationError extends Error {
89
101
  declare function translate(
90
102
  /** Raw SRT or VTT file content */
91
103
  fileContent: string, opts: TranslateOptions,
92
- /** Pass your own OpenAI client (allows custom baseURL, auth, etc.) */
104
+ /**
105
+ * Pass your own OpenAI-compatible client.
106
+ * For DeepSeek: new OpenAI({ baseURL: "https://api.deepseek.com", apiKey: "..." })
107
+ * For Groq: new OpenAI({ baseURL: "https://api.groq.com/openai/v1", apiKey: "..." })
108
+ * Remember to also set opts.model to your provider's model name.
109
+ */
93
110
  client?: OpenAI): Promise<TranslationResult>;
94
111
  declare function translateFile(inputPath: string, outputPath: string, opts: TranslateOptions, client?: OpenAI): Promise<TranslationResult>;
95
112
 
package/dist/index.d.ts CHANGED
@@ -39,8 +39,20 @@ interface TranslateOptions {
39
39
  batchSize?: number;
40
40
  /** Context overlap: N sentences from the prev batch prepended (default 4) */
41
41
  contextOverlap?: number;
42
- /** OpenAI model override. Defaults to gpt-4o for non-Latin scripts, gpt-4o-mini otherwise */
43
- model?: "gpt-4o" | "gpt-4o-mini";
42
+ /**
43
+ * Model for translation batches.
44
+ * OpenAI users: defaults to "gpt-4o" for complex scripts, "gpt-4o-mini" otherwise.
45
+ * Custom client users (DeepSeek, Groq, etc.): set this to your provider's model name,
46
+ * e.g. "deepseek-chat". Auto-selection only works for OpenAI model names.
47
+ */
48
+ model?: "gpt-4o" | "gpt-4o-mini" | (string & {});
49
+ /**
50
+ * Fallback model used when auto-selection would normally pick gpt-4o-mini
51
+ * but you're on a custom provider. Only needed if you want different models
52
+ * for different language complexity tiers on a non-OpenAI backend.
53
+ * Most custom client users should just set `model` and leave this unset.
54
+ */
55
+ modelFallback?: string;
44
56
  /** Max concurrent batch requests (default 8) */
45
57
  concurrency?: number;
46
58
  /** Enable AI primer call — for general/unknown content only */
@@ -89,7 +101,12 @@ declare class SubtitleTranslationError extends Error {
89
101
  declare function translate(
90
102
  /** Raw SRT or VTT file content */
91
103
  fileContent: string, opts: TranslateOptions,
92
- /** Pass your own OpenAI client (allows custom baseURL, auth, etc.) */
104
+ /**
105
+ * Pass your own OpenAI-compatible client.
106
+ * For DeepSeek: new OpenAI({ baseURL: "https://api.deepseek.com", apiKey: "..." })
107
+ * For Groq: new OpenAI({ baseURL: "https://api.groq.com/openai/v1", apiKey: "..." })
108
+ * Remember to also set opts.model to your provider's model name.
109
+ */
93
110
  client?: OpenAI): Promise<TranslationResult>;
94
111
  declare function translateFile(inputPath: string, outputPath: string, opts: TranslateOptions, client?: OpenAI): Promise<TranslationResult>;
95
112
 
package/dist/index.js CHANGED
@@ -7126,11 +7126,27 @@ Do not explain metaphors or idioms \u2014 translate them faithfully.`,
7126
7126
  Preserve the speaker's natural register and sentence rhythm.
7127
7127
  Do not add formality that isn't in the source.`
7128
7128
  };
7129
- var NON_LATIN_SCRIPTS = /* @__PURE__ */ new Set(["ar", "am", "zh", "ja", "ko", "hi", "ru", "uk", "el"]);
7130
- function pickModel(targetLang, override) {
7131
- if (override) return override;
7132
- const needsFullModel = NON_LATIN_SCRIPTS.has(targetLang) || ["yo", "ig", "ha", "sw", "zu"].includes(targetLang);
7133
- return needsFullModel ? "gpt-4o" : "gpt-4o-mini";
7129
+ var NEEDS_FULL_MODEL = /* @__PURE__ */ new Set([
7130
+ "ar",
7131
+ "am",
7132
+ "zh",
7133
+ "ja",
7134
+ "ko",
7135
+ "hi",
7136
+ "ru",
7137
+ "uk",
7138
+ "el",
7139
+ "yo",
7140
+ "ig",
7141
+ "ha",
7142
+ "sw",
7143
+ "zu"
7144
+ ]);
7145
+ function pickModel(opts) {
7146
+ if (opts.model) return opts.model;
7147
+ const needsFull = NEEDS_FULL_MODEL.has(opts.targetLang);
7148
+ if (needsFull) return "gpt-4o";
7149
+ return opts.modelFallback ?? "gpt-4o-mini";
7134
7150
  }
7135
7151
  function buildGlossaryBlock(meta) {
7136
7152
  const lines = [];
@@ -7145,7 +7161,7 @@ function buildGlossaryBlock(meta) {
7145
7161
  }
7146
7162
  if (meta.glossary) {
7147
7163
  for (const [src, tgt] of Object.entries(meta.glossary)) {
7148
- lines.push(`"${src}" \u2192 "${tgt}"`);
7164
+ lines.push(`"${src}" -> "${tgt}"`);
7149
7165
  }
7150
7166
  }
7151
7167
  return lines.length ? `GLOSSARY (must follow exactly):
@@ -7161,7 +7177,7 @@ function buildSystemPrompt(opts) {
7161
7177
  domainBlock,
7162
7178
  glossaryBlock,
7163
7179
  `RULES:
7164
- - Preserve ALL-CAPS emphasis, ellipses (...), dashes (\u2014), and line-ending punctuation exactly.
7180
+ - Preserve ALL-CAPS emphasis, ellipses (...), dashes, and line-ending punctuation exactly.
7165
7181
  - Never merge or split sentences \u2014 one input item = one output item.
7166
7182
  - Never add explanatory text, parentheticals, or translator notes.
7167
7183
  - Output ONLY valid JSON. No markdown, no code fences, no preamble.`,
@@ -7276,7 +7292,7 @@ async function executeTranslation(client, sentences, opts) {
7276
7292
  const batchSize = opts.batchSize ?? 25;
7277
7293
  const overlap = opts.contextOverlap ?? 4;
7278
7294
  const concurrency = opts.concurrency ?? 8;
7279
- const model = pickModel(opts.targetLang, opts.model);
7295
+ const model = pickModel(opts);
7280
7296
  const systemPrompt = buildSystemPrompt(opts);
7281
7297
  const payloads = buildBatches(sentences, batchSize, overlap);
7282
7298
  const tasks = payloads.map(
@@ -7389,12 +7405,13 @@ function emitVTT(cues) {
7389
7405
  // src/index.ts
7390
7406
  import { readFile, writeFile } from "fs/promises";
7391
7407
  import { extname } from "path";
7392
- var COST_PER_M_TOKENS = {
7408
+ var KNOWN_COSTS = {
7393
7409
  "gpt-4o": { input: 2.5, output: 10 },
7394
7410
  "gpt-4o-mini": { input: 0.15, output: 0.6 }
7395
7411
  };
7396
7412
  function estimateCost(model, inputTokens, outputTokens) {
7397
- const rates = COST_PER_M_TOKENS[model];
7413
+ const rates = KNOWN_COSTS[model];
7414
+ if (!rates) return 0;
7398
7415
  return inputTokens / 1e6 * rates.input + outputTokens / 1e6 * rates.output;
7399
7416
  }
7400
7417
  async function translate(fileContent, opts, client) {
@@ -7405,14 +7422,14 @@ async function translate(fileContent, opts, client) {
7405
7422
  const sentences = reconstructSentences(cues);
7406
7423
  const { translations, totalInputTokens, totalOutputTokens, totalBatches } = await executeTranslation(oi, sentences, opts);
7407
7424
  const translatedCues = reanchorCues(cues, sentences, translations);
7408
- const model = opts.model ?? (["yo", "ig", "ha", "sw", "zu", "ar", "am"].includes(opts.targetLang) ? "gpt-4o" : "gpt-4o-mini");
7425
+ const resolvedModel = pickModel(opts);
7409
7426
  const stats = {
7410
7427
  totalCues: cues.length,
7411
7428
  totalSentences: sentences.length,
7412
7429
  totalBatches,
7413
7430
  inputTokens: totalInputTokens,
7414
7431
  outputTokens: totalOutputTokens,
7415
- estimatedCostUsd: estimateCost(model, totalInputTokens, totalOutputTokens),
7432
+ estimatedCostUsd: estimateCost(resolvedModel, totalInputTokens, totalOutputTokens),
7416
7433
  durationMs: Date.now() - startTime
7417
7434
  };
7418
7435
  return {