ai-sub-translator 1.0.0

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/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ Copyright (c) <2025> <Alex>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,135 @@
1
+ # AI Subtitle Translator
2
+
3
+ <img src="./images/screenshot.png" alt="App screenshot" width="512" height="712">
4
+
5
+ An Electron-based desktop application for translating subtitles using AI technology. This application allows users to translate subtitle files efficiently using Google's Generative AI.
6
+
7
+ ## Features
8
+
9
+ - Well, it translates subtitles
10
+ - Progress bar
11
+ - Modern React-based user interface (he-he)
12
+ - Grab subtitles directly from video source
13
+ - Support for both x64 and ARM64 Windows architectures
14
+ - **Headless server mode** for servers (JSON-RPC API)
15
+
16
+ ## ToDo
17
+
18
+ - Support .mks, .ass formats
19
+ - Different AI models support
20
+ - Download / Upload subtitles to subtitle websites
21
+ - Proper UX/UI
22
+
23
+ ## Known bugs
24
+ - No proper progress for downloading ffmpeg
25
+ - State is not cleared when load new subtitles
26
+
27
+ ## Usage
28
+
29
+ 1. Grab latest release or build the app
30
+ 2. Obtain API key for Gemini AI [here](https://aistudio.google.com/app/apikey). **Free tier is enough**
31
+ 3. Launch the app
32
+ 4. Load source .srt file
33
+ 5. Enter your API key, language to translate, name the piece of content that you want to translate (eg. Last of us season 2 episode 1)
34
+ 6. Press Translate button. It should take couple of minutes (progress will be displayed)
35
+
36
+ ## Prerequisites
37
+
38
+ - Node.js (v14 or higher)
39
+ - npm (v6 or higher)
40
+
41
+
42
+ ## Installation
43
+
44
+ 1. Clone the repository:
45
+ ```bash
46
+ git clone https://github.com/seeingred/ai-sub-translator.git
47
+ cd ai-sub-translator
48
+ ```
49
+
50
+ 2. Install dependencies:
51
+ ```bash
52
+ npm install
53
+ ```
54
+
55
+
56
+ ## Headless Server Mode
57
+
58
+ The app can run as a headless server on Linux servers without GUI, exposing a JSON-RPC API for subtitle translation.
59
+
60
+ ### Quick Start
61
+ ```bash
62
+ # On Linux server (auto-detects no display)
63
+ ./ai-sub-translator
64
+
65
+ # Force headless mode on any platform
66
+ ./ai-sub-translator --headless
67
+
68
+ # Custom port
69
+ API_PORT=8080 ./ai-sub-translator --headless
70
+ ```
71
+
72
+ **For full server documentation, see [README-SERVER.md](./README-SERVER.md)**
73
+
74
+ ## Development
75
+
76
+ To start the application in development mode:
77
+
78
+ ```bash
79
+ npm start
80
+
81
+ # Test headless mode locally
82
+ npm start -- --headless
83
+ ```
84
+
85
+ ## Building
86
+
87
+ To create a production build:
88
+
89
+ ```bash
90
+ npm run make
91
+ ```
92
+
93
+ This will create distributable packages for your platform.
94
+
95
+ ### Building for specific architectures
96
+
97
+ For Windows, you can build for specific architectures:
98
+
99
+ ```bash
100
+ # Build for Windows x64
101
+ npm run make:win:x64
102
+
103
+ # Build for Windows ARM64
104
+ npm run make:win:arm64
105
+
106
+ # Build for both Windows architectures
107
+ npm run make:win:all
108
+ ```
109
+
110
+ ## Available Scripts
111
+
112
+ - `npm start` - Start the application in development mode
113
+ - `npm run make` - Create distributable packages for your current platform
114
+ - `npm run make:win:x64` - Build Windows x64 package
115
+ - `npm run make:win:arm64` - Build Windows ARM64 package
116
+ - `npm run make:win:all` - Build Windows packages for both architectures
117
+ - `npm run make:mac` - Build macOS package
118
+ - `npm run make:linux` - Build Linux package
119
+ - `npm run make:all` - Build packages for all platforms and architectures
120
+
121
+ ## Technologies Used
122
+
123
+ - Electron
124
+ - React
125
+ - TypeScript
126
+ - Webpack
127
+ - Google Generative AI API
128
+
129
+ ## License
130
+
131
+ This project is licensed under the MIT License - see the LICENSE file for details.
132
+
133
+ ## Author
134
+
135
+ Alex
@@ -0,0 +1,9 @@
1
+ export interface GeminiCallOptions {
2
+ text: string;
3
+ language: string;
4
+ context: string;
5
+ model: string;
6
+ apiKey: string;
7
+ }
8
+ export declare function callGemini(options: GeminiCallOptions): Promise<string>;
9
+ //# sourceMappingURL=gemini-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gemini-client.d.ts","sourceRoot":"","sources":["../lib/gemini-client.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CAwB5E"}
@@ -0,0 +1,24 @@
1
+ import { GoogleGenAI } from '@google/genai';
2
+ export async function callGemini(options) {
3
+ const { text, language, context, model, apiKey } = options;
4
+ const ai = new GoogleGenAI({ apiKey });
5
+ const prompt = `You are a professional subtitle translator. Translate the following SRT subtitle batch to ${language}.
6
+
7
+ CRITICAL RULES:
8
+ - Output ONLY the translated SRT subtitle text
9
+ - Preserve ALL subtitle numbers and timecodes EXACTLY as given
10
+ - Do NOT add any markdown formatting, backticks, or code blocks
11
+ - Do NOT add any explanations, notes, or comments
12
+ - Do NOT modify timecodes or subtitle numbering
13
+ - Maintain the exact SRT format structure
14
+
15
+ Context: ${context}
16
+
17
+ ${text}`;
18
+ const response = await ai.models.generateContent({
19
+ model,
20
+ contents: prompt,
21
+ });
22
+ return response.text || '';
23
+ }
24
+ //# sourceMappingURL=gemini-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gemini-client.js","sourceRoot":"","sources":["../lib/gemini-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAU5C,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,OAA0B;IACzD,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAC3D,MAAM,EAAE,GAAG,IAAI,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IAEvC,MAAM,MAAM,GAAG,6FAA6F,QAAQ;;;;;;;;;;WAU3G,OAAO;;EAEhB,IAAI,EAAE,CAAC;IAEP,MAAM,QAAQ,GAAG,MAAM,EAAE,CAAC,MAAM,CAAC,eAAe,CAAC;QAC/C,KAAK;QACL,QAAQ,EAAE,MAAM;KACjB,CAAC,CAAC;IAEH,OAAO,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC;AAC7B,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { translate } from './translator';
2
+ export { parseSrt, formatSrt } from './srt-parser';
3
+ export type { TranslateOptions, TranslateResult, SrtEntry } from './types';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACnD,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { translate } from './translator';
2
+ export { parseSrt, formatSrt } from './srt-parser';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { SrtEntry } from './types';
2
+ export declare function parseSrt(text: string): SrtEntry[];
3
+ export declare function formatSrt(entries: SrtEntry[]): string;
4
+ //# sourceMappingURL=srt-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"srt-parser.d.ts","sourceRoot":"","sources":["../lib/srt-parser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,EAAE,CA0BjD;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,QAAQ,EAAE,GAAG,MAAM,CAIrD"}
@@ -0,0 +1,30 @@
1
+ export function parseSrt(text) {
2
+ const entries = [];
3
+ const normalized = text.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
4
+ const blocks = normalized.split(/\n\n+/);
5
+ for (const block of blocks) {
6
+ const trimmed = block.trim();
7
+ if (!trimmed)
8
+ continue;
9
+ const lines = trimmed.split('\n');
10
+ if (lines.length < 2)
11
+ continue;
12
+ const indexLine = lines[0].trim();
13
+ const index = parseInt(indexLine, 10);
14
+ if (isNaN(index))
15
+ continue;
16
+ const timestampLine = lines[1].trim();
17
+ if (!timestampLine.includes('-->'))
18
+ continue;
19
+ const textLines = lines.slice(2);
20
+ const text = textLines.join('\n');
21
+ entries.push({ index, timestamp: timestampLine, text });
22
+ }
23
+ return entries;
24
+ }
25
+ export function formatSrt(entries) {
26
+ return entries
27
+ .map((entry) => `${entry.index}\n${entry.timestamp}\n${entry.text}`)
28
+ .join('\n\n') + '\n';
29
+ }
30
+ //# sourceMappingURL=srt-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"srt-parser.js","sourceRoot":"","sources":["../lib/srt-parser.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,MAAM,OAAO,GAAe,EAAE,CAAC;IAC/B,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACpE,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAEzC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;QAC7B,IAAI,CAAC,OAAO;YAAE,SAAS;QAEvB,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAClC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;YAAE,SAAS;QAE/B,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAClC,MAAM,KAAK,GAAG,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QACtC,IAAI,KAAK,CAAC,KAAK,CAAC;YAAE,SAAS;QAE3B,MAAM,aAAa,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACtC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,SAAS;QAE7C,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACjC,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAElC,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1D,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,OAAmB;IAC3C,OAAO,OAAO;SACX,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,KAAK,KAAK,KAAK,CAAC,SAAS,KAAK,KAAK,CAAC,IAAI,EAAE,CAAC;SACnE,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;AACzB,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { TranslateOptions, TranslateResult } from './types';
2
+ export declare function translate(options: TranslateOptions): Promise<TranslateResult>;
3
+ //# sourceMappingURL=translator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"translator.d.ts","sourceRoot":"","sources":["../lib/translator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAY,MAAM,SAAS,CAAC;AA0BtE,wBAAsB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CA+CnF"}
@@ -0,0 +1,46 @@
1
+ import { parseSrt, formatSrt } from './srt-parser';
2
+ import { callGemini } from './gemini-client';
3
+ const DEFAULT_MODEL = 'gemini-2.0-flash';
4
+ const DEFAULT_BATCH_SIZE = 50;
5
+ const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
6
+ async function translateBatch(entries, language, context, model, apiKey) {
7
+ const text = formatSrt(entries);
8
+ try {
9
+ return await callGemini({ text, language, context, model, apiKey });
10
+ }
11
+ catch (error) {
12
+ console.error('Translation error, retrying in 10 seconds...', error);
13
+ await wait(10000);
14
+ return translateBatch(entries, language, context, model, apiKey);
15
+ }
16
+ }
17
+ export async function translate(options) {
18
+ const { text, targetLanguage, apiKey, model = DEFAULT_MODEL, batchSize = DEFAULT_BATCH_SIZE, context = '', onProgress, signal, } = options;
19
+ const entries = parseSrt(text);
20
+ if (entries.length === 0) {
21
+ return { translatedText: '', totalBatches: 0, completedBatches: 0 };
22
+ }
23
+ const totalBatches = Math.ceil(entries.length / batchSize);
24
+ let completedBatches = 0;
25
+ let translatedText = '';
26
+ if (onProgress) {
27
+ onProgress(0);
28
+ }
29
+ for (let i = 0; i < entries.length; i += batchSize) {
30
+ if (signal?.aborted) {
31
+ throw new Error('Translation cancelled');
32
+ }
33
+ const batch = entries.slice(i, i + batchSize);
34
+ const batchResult = await translateBatch(batch, targetLanguage, context, model, apiKey);
35
+ translatedText += (translatedText ? '\n' : '') + batchResult;
36
+ completedBatches++;
37
+ if (onProgress) {
38
+ onProgress(Math.min(completedBatches / totalBatches, 1));
39
+ }
40
+ }
41
+ if (onProgress) {
42
+ onProgress(1);
43
+ }
44
+ return { translatedText, totalBatches, completedBatches };
45
+ }
46
+ //# sourceMappingURL=translator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"translator.js","sourceRoot":"","sources":["../lib/translator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ export interface SrtEntry {
2
+ index: number;
3
+ timestamp: string;
4
+ text: string;
5
+ }
6
+ export interface TranslateOptions {
7
+ text: string;
8
+ targetLanguage: string;
9
+ apiKey: string;
10
+ model?: string;
11
+ batchSize?: number;
12
+ context?: string;
13
+ onProgress?: (progress: number) => void;
14
+ signal?: AbortSignal;
15
+ }
16
+ export interface TranslateResult {
17
+ translatedText: string;
18
+ totalBatches: number;
19
+ completedBatches: number;
20
+ }
21
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../lib/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;CAC1B"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../lib/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,91 @@
1
+ {
2
+ "name": "ai-sub-translator",
3
+ "productName": "ai-sub-translator",
4
+ "version": "1.0.0",
5
+ "description": "AI-powered subtitle translator using Google Gemini. Translates SRT subtitles to any language.",
6
+ "main": ".webpack/main",
7
+ "exports": {
8
+ ".": {
9
+ "import": "./dist/index.js",
10
+ "types": "./dist/index.d.ts"
11
+ }
12
+ },
13
+ "types": "./dist/index.d.ts",
14
+ "type": "module",
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "scripts": {
19
+ "start": "electron-forge start",
20
+ "package": "electron-forge package",
21
+ "make": "electron-forge make",
22
+ "make:mac": "electron-forge make --platform darwin",
23
+ "make:win:x64": "electron-forge make --platform win32 --arch x64",
24
+ "make:win:arm64": "electron-forge make --platform win32 --arch arm64",
25
+ "make:win": "npm run make:win:x64 && npm run make:win:arm64",
26
+ "make:linux": "npm run make:linux:x64 && npm run make:linux:arm64",
27
+ "make:linux:x64": "electron-forge make --platform linux --arch x64",
28
+ "make:linux:arm64": "electron-forge make --platform linux --arch arm64",
29
+ "make:all": "npm run make:mac && npm run make:win && npm run make:linux",
30
+ "publish": "electron-forge publish",
31
+ "lint": "eslint --ext .ts,.tsx .",
32
+ "build:lib": "tsc -p tsconfig.lib.json",
33
+ "test:lib": "node --experimental-vm-modules node_modules/.bin/jest --config jest.config.js",
34
+ "prepublishOnly": "npm run build:lib"
35
+ },
36
+ "keywords": [
37
+ "subtitles",
38
+ "srt",
39
+ "translator",
40
+ "gemini",
41
+ "ai",
42
+ "translation"
43
+ ],
44
+ "author": {
45
+ "name": "aka",
46
+ "email": "aka@aka.aka"
47
+ },
48
+ "license": "MIT",
49
+ "devDependencies": {
50
+ "@aws-sdk/client-s3": "^3.787.0",
51
+ "@electron-forge/cli": "^7.8.0",
52
+ "@electron-forge/maker-deb": "^7.8.0",
53
+ "@electron-forge/maker-rpm": "^7.8.0",
54
+ "@electron-forge/maker-squirrel": "^7.8.0",
55
+ "@electron-forge/maker-zip": "^7.8.0",
56
+ "@electron-forge/plugin-auto-unpack-natives": "^7.8.0",
57
+ "@electron-forge/plugin-fuses": "^7.8.0",
58
+ "@electron-forge/plugin-webpack": "^7.8.0",
59
+ "@electron-forge/publisher-github": "^7.8.0",
60
+ "@electron/fuses": "^1.8.0",
61
+ "@types/jest": "^29.5.14",
62
+ "@types/react": "^19.1.2",
63
+ "@types/react-dom": "^19.1.2",
64
+ "@types/unzipper": "^0.10.11",
65
+ "@typescript-eslint/eslint-plugin": "^5.62.0",
66
+ "@typescript-eslint/parser": "^5.62.0",
67
+ "@vercel/webpack-asset-relocator-loader": "^1.7.3",
68
+ "css-loader": "^6.11.0",
69
+ "electron": "35.1.5",
70
+ "electron-squirrel-startup": "^1.0.1",
71
+ "eslint": "^8.57.1",
72
+ "eslint-plugin-import": "^2.31.0",
73
+ "fork-ts-checker-webpack-plugin": "^7.3.0",
74
+ "jayson": "^4.2.0",
75
+ "jest": "^29.7.0",
76
+ "node-loader": "^2.1.0",
77
+ "react": "^19.1.0",
78
+ "react-dom": "^19.1.0",
79
+ "style-loader": "^3.3.4",
80
+ "tar": "^7.4.3",
81
+ "ts-jest": "^29.4.6",
82
+ "ts-loader": "^9.5.2",
83
+ "ts-node": "^10.9.2",
84
+ "typescript": "^5.9.3",
85
+ "unzipper": "^0.12.3",
86
+ "xz-decompress": "^0.2.2"
87
+ },
88
+ "dependencies": {
89
+ "@google/genai": "^0.8.0"
90
+ }
91
+ }