@llm-translate/cli 1.0.0-next.1 → 1.0.0-next.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.
@@ -0,0 +1,99 @@
1
+ name: Docker Publish
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - develop
7
+ - main
8
+ tags:
9
+ - "v*"
10
+ paths-ignore:
11
+ - "docs/**"
12
+ - "*.md"
13
+
14
+ env:
15
+ REGISTRY: ghcr.io
16
+ IMAGE_NAME: ${{ github.repository }}
17
+
18
+ permissions:
19
+ contents: read
20
+
21
+ jobs:
22
+ build-and-push:
23
+ name: Build and Push Docker Image
24
+ runs-on: ubuntu-latest
25
+ permissions:
26
+ contents: read
27
+ packages: write
28
+ attestations: write
29
+ id-token: write
30
+
31
+ steps:
32
+ - name: Checkout
33
+ uses: actions/checkout@v4
34
+
35
+ - name: Set up QEMU
36
+ uses: docker/setup-qemu-action@v3
37
+
38
+ - name: Set up Docker Buildx
39
+ uses: docker/setup-buildx-action@v3
40
+
41
+ - name: Login to GHCR
42
+ uses: docker/login-action@v3
43
+ with:
44
+ registry: ${{ env.REGISTRY }}
45
+ username: ${{ github.actor }}
46
+ password: ${{ secrets.GITHUB_TOKEN }}
47
+
48
+ - name: Extract version from package.json
49
+ id: pkg
50
+ run: |
51
+ VERSION=$(node -p "require('./package.json').version")
52
+ echo "version=$VERSION" >> $GITHUB_OUTPUT
53
+
54
+ - name: Generate Docker tags
55
+ id: tags
56
+ run: |
57
+ IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}"
58
+ IMAGE_LOWER=$(echo "$IMAGE" | tr '[:upper:]' '[:lower:]')
59
+ VERSION="${{ steps.pkg.outputs.version }}"
60
+
61
+ if [[ "${{ github.ref_type }}" == "tag" ]]; then
62
+ # Tag push (v*) - stable release
63
+ TAG_VERSION="${GITHUB_REF_NAME#v}"
64
+ TAGS="${IMAGE_LOWER}:${TAG_VERSION},${IMAGE_LOWER}:latest"
65
+ elif [[ "${{ github.ref_name }}" == "main" ]]; then
66
+ # Main branch push - stable release
67
+ TAGS="${IMAGE_LOWER}:${VERSION},${IMAGE_LOWER}:latest"
68
+ elif [[ "${{ github.ref_name }}" == "develop" ]]; then
69
+ # Develop branch push - alpha release
70
+ ALPHA_VERSION="${VERSION}-alpha.${{ github.run_number }}"
71
+ TAGS="${IMAGE_LOWER}:${ALPHA_VERSION},${IMAGE_LOWER}:alpha"
72
+ fi
73
+
74
+ echo "tags=$TAGS" >> $GITHUB_OUTPUT
75
+ echo "Generated tags: $TAGS"
76
+
77
+ - name: Build and push Docker image
78
+ id: push
79
+ uses: docker/build-push-action@v6
80
+ with:
81
+ context: .
82
+ platforms: linux/amd64,linux/arm64
83
+ push: true
84
+ tags: ${{ steps.tags.outputs.tags }}
85
+ cache-from: type=gha
86
+ cache-to: type=gha,mode=max
87
+ labels: |
88
+ org.opencontainers.image.title=llm-translate
89
+ org.opencontainers.image.description=CLI-based document translation tool powered by LLMs
90
+ org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
91
+ org.opencontainers.image.revision=${{ github.sha }}
92
+ org.opencontainers.image.version=${{ steps.pkg.outputs.version }}
93
+
94
+ - name: Generate artifact attestation
95
+ uses: actions/attest-build-provenance@v2
96
+ with:
97
+ subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
98
+ subject-digest: ${{ steps.push.outputs.digest }}
99
+ push-to-registry: true
package/Dockerfile CHANGED
@@ -52,4 +52,4 @@ HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
52
52
  CMD node -e "fetch('http://localhost:3000/health/live').then(r => r.ok ? process.exit(0) : process.exit(1)).catch(() => process.exit(1))"
53
53
 
54
54
  # Start server with JSON logging for container environments
55
- CMD ["node", "dist/cli/index.js", "serve", "--json"]
55
+ CMD ["node", "dist/cli/index.js", "serve", "--json", "--cors", "--no-auth", "--cache-dir", "./.translate-cache/server"]
package/dist/cli/index.js CHANGED
@@ -2973,20 +2973,28 @@ var init_engine = __esm({
2973
2973
  }
2974
2974
  this.provider = getProvider(this.config.provider.default, providerConfig);
2975
2975
  }
2976
- const cacheDisabled = options.noCache || !this.config.paths?.cache;
2977
- if (cacheDisabled) {
2978
- this.cache = createNullCacheManager();
2979
- if (this.verbose && options.noCache) {
2980
- logger.info("Cache disabled (--no-cache)");
2981
- }
2982
- } else {
2983
- this.cache = createCacheManager({
2984
- cacheDir: this.config.paths.cache,
2985
- verbose: this.verbose
2986
- });
2976
+ if (options.cacheManager) {
2977
+ this.cache = options.cacheManager;
2987
2978
  if (this.verbose) {
2988
2979
  const stats = this.cache.getStats();
2989
- logger.info(`Cache initialized: ${stats.entries} entries`);
2980
+ logger.info(`Using shared cache: ${stats.entries} entries`);
2981
+ }
2982
+ } else {
2983
+ const cacheDisabled = options.noCache || !this.config.paths?.cache;
2984
+ if (cacheDisabled) {
2985
+ this.cache = createNullCacheManager();
2986
+ if (this.verbose && options.noCache) {
2987
+ logger.info("Cache disabled (--no-cache)");
2988
+ }
2989
+ } else {
2990
+ this.cache = createCacheManager({
2991
+ cacheDir: this.config.paths.cache,
2992
+ verbose: this.verbose
2993
+ });
2994
+ if (this.verbose) {
2995
+ const stats = this.cache.getStats();
2996
+ logger.info(`Cache initialized: ${stats.entries} entries`);
2997
+ }
2990
2998
  }
2991
2999
  }
2992
3000
  }
@@ -4232,6 +4240,7 @@ translateRouter.post(
4232
4240
  try {
4233
4241
  const baseConfig = await loadConfig();
4234
4242
  const modeConfig = MODE_PRESETS2[body.mode ?? "balanced"];
4243
+ const cachePath = c.get("cachePath");
4235
4244
  const config2 = {
4236
4245
  ...baseConfig,
4237
4246
  languages: {
@@ -4248,12 +4257,16 @@ translateRouter.post(
4248
4257
  ...baseConfig.quality,
4249
4258
  threshold: body.qualityThreshold ?? modeConfig.qualityThreshold,
4250
4259
  maxIterations: body.maxIterations ?? modeConfig.maxIterations
4260
+ },
4261
+ paths: {
4262
+ ...baseConfig.paths,
4263
+ cache: cachePath
4251
4264
  }
4252
4265
  };
4253
4266
  const engine = createTranslationEngine({
4254
4267
  config: config2,
4255
4268
  verbose: false,
4256
- noCache: true
4269
+ noCache: !cachePath
4257
4270
  });
4258
4271
  if (body.glossary && body.glossary.length > 0) {
4259
4272
  convertInlineGlossary(body.glossary, body.sourceLang, body.targetLang);
@@ -4345,6 +4358,12 @@ function handleTranslationError(c, error, requestId) {
4345
4358
  // src/server/index.ts
4346
4359
  function createApp(options) {
4347
4360
  const app = new Hono();
4361
+ if (options.cachePath) {
4362
+ app.use("*", async (c, next) => {
4363
+ c.set("cachePath", options.cachePath);
4364
+ await next();
4365
+ });
4366
+ }
4348
4367
  app.use("*", createLoggerMiddleware({
4349
4368
  json: options.jsonLogging ?? false
4350
4369
  }));
@@ -4411,6 +4430,7 @@ llm-translate server started`);
4411
4430
  console.log(` - Translate: http://${options.host}:${options.port}/translate`);
4412
4431
  console.log(` - Auth: ${options.enableAuth ? "enabled" : "disabled"}`);
4413
4432
  console.log(` - CORS: ${options.enableCors ? "enabled" : "disabled"}`);
4433
+ console.log(` - Cache: ${options.cachePath ?? "disabled"}`);
4414
4434
  console.log("");
4415
4435
  const shutdown = (signal) => {
4416
4436
  console.log(`
@@ -4438,7 +4458,11 @@ var serveCommand = new Command("serve").description("Start the translation API s
4438
4458
  "-p, --port <number>",
4439
4459
  "Server port (env: TRANSLATE_PORT)",
4440
4460
  process.env["TRANSLATE_PORT"] ?? "3000"
4441
- ).option("-H, --host <string>", "Host to bind", "0.0.0.0").option("--no-auth", "Disable API key authentication").option("--cors", "Enable CORS for browser clients").option("--json", "Use JSON logging format (for containers)").action((options) => {
4461
+ ).option("-H, --host <string>", "Host to bind", "0.0.0.0").option("--no-auth", "Disable API key authentication").option("--cors", "Enable CORS for browser clients").option("--json", "Use JSON logging format (for containers)").option(
4462
+ "--cache-dir <path>",
4463
+ "Cache directory path (env: TRANSLATE_CACHE_DIR)",
4464
+ process.env["TRANSLATE_CACHE_DIR"]
4465
+ ).action((options) => {
4442
4466
  const port = parseInt(options.port ?? "3000", 10);
4443
4467
  const host = options.host ?? "0.0.0.0";
4444
4468
  if (isNaN(port) || port < 1 || port > 65535) {
@@ -4460,7 +4484,8 @@ var serveCommand = new Command("serve").description("Start the translation API s
4460
4484
  enableAuth,
4461
4485
  enableCors: options.cors ?? false,
4462
4486
  apiKey: process.env["TRANSLATE_API_KEY"],
4463
- jsonLogging: options.json ?? false
4487
+ jsonLogging: options.json ?? false,
4488
+ cachePath: options.cacheDir
4464
4489
  });
4465
4490
  });
4466
4491