arindae commited on
Commit
012abcf
·
1 Parent(s): 8a03b02

Current changes

Browse files
.gitignore CHANGED
@@ -1,2 +1,3 @@
1
  translator_app/.venv
2
- backend
 
 
1
  translator_app/.venv
2
+ translator_app
3
+ translator_app/db.sqlite3
Dockerfile CHANGED
@@ -33,4 +33,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends patchelf \
33
  COPY backend/ ./
34
  COPY --from=model /m/models ./models
35
  EXPOSE 7860
36
- CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
 
 
 
33
  COPY backend/ ./
34
  COPY --from=model /m/models ./models
35
  EXPOSE 7860
36
+ COPY entrypoint.sh .
37
+ RUN chmod +x entrypoint.sh
38
+ CMD ["./entrypoint.sh"]
backend/main.py CHANGED
@@ -7,6 +7,7 @@ import os
7
  import httpx
8
  from fastapi import FastAPI, Header, HTTPException
9
  from fastapi.middleware.cors import CORSMiddleware
 
10
  from pydantic import BaseModel, Field
11
 
12
  import providers
@@ -33,7 +34,9 @@ class TranslateRequest(BaseModel):
33
  text: str = Field(..., description="Text to translate.")
34
  source: str = Field(..., description="Source FLORES-200 code, e.g. 'eng_Latn'.")
35
  target: str = Field(..., description="Target FLORES-200 code, e.g. 'kor_Hang'.")
36
- engine: str | None = Field(None, description="Engine id; defaults to first available.")
 
 
37
 
38
 
39
  class TranslateResponse(BaseModel):
@@ -69,7 +72,10 @@ def translate_endpoint(
69
  ) -> TranslateResponse:
70
  if not req.text.strip():
71
  return TranslateResponse(
72
- translation="", source=req.source, target=req.target, engine=req.engine or ""
 
 
 
73
  )
74
  if len(req.text) > MAX_INPUT_CHARS:
75
  raise HTTPException(400, f"Input too long (max {MAX_INPUT_CHARS} chars).")
@@ -87,19 +93,33 @@ def translate_endpoint(
87
 
88
  if provider.kind == "api":
89
  if not (provider.is_available() or api_key):
90
- raise HTTPException(503, provider.setup_hint or "Add an API key in Settings.")
 
 
91
  elif not provider.is_available():
92
- raise HTTPException(503, provider.setup_hint or f"Engine '{engine_id}' is not available.")
 
 
93
 
94
  try:
95
  result = provider.translate(req.text, req.source, req.target, api_key=api_key)
96
  except ValueError as exc:
97
  raise HTTPException(400, str(exc)) from exc
98
  except httpx.HTTPStatusError as exc:
99
- raise HTTPException(502, f"Upstream API error: {exc.response.status_code}") from exc
 
 
100
  except Exception as exc: # noqa: BLE001 — surface engine errors to the client
101
  raise HTTPException(500, f"Translation failed: {exc}") from exc
102
 
103
  return TranslateResponse(
104
  translation=result, source=req.source, target=req.target, engine=engine_id
105
  )
 
 
 
 
 
 
 
 
 
7
  import httpx
8
  from fastapi import FastAPI, Header, HTTPException
9
  from fastapi.middleware.cors import CORSMiddleware
10
+ from scalar_fastapi import get_scalar_api_reference
11
  from pydantic import BaseModel, Field
12
 
13
  import providers
 
34
  text: str = Field(..., description="Text to translate.")
35
  source: str = Field(..., description="Source FLORES-200 code, e.g. 'eng_Latn'.")
36
  target: str = Field(..., description="Target FLORES-200 code, e.g. 'kor_Hang'.")
37
+ engine: str | None = Field(
38
+ None, description="Engine id; defaults to first available."
39
+ )
40
 
41
 
42
  class TranslateResponse(BaseModel):
 
72
  ) -> TranslateResponse:
73
  if not req.text.strip():
74
  return TranslateResponse(
75
+ translation="",
76
+ source=req.source,
77
+ target=req.target,
78
+ engine=req.engine or "",
79
  )
80
  if len(req.text) > MAX_INPUT_CHARS:
81
  raise HTTPException(400, f"Input too long (max {MAX_INPUT_CHARS} chars).")
 
93
 
94
  if provider.kind == "api":
95
  if not (provider.is_available() or api_key):
96
+ raise HTTPException(
97
+ 503, provider.setup_hint or "Add an API key in Settings."
98
+ )
99
  elif not provider.is_available():
100
+ raise HTTPException(
101
+ 503, provider.setup_hint or f"Engine '{engine_id}' is not available."
102
+ )
103
 
104
  try:
105
  result = provider.translate(req.text, req.source, req.target, api_key=api_key)
106
  except ValueError as exc:
107
  raise HTTPException(400, str(exc)) from exc
108
  except httpx.HTTPStatusError as exc:
109
+ raise HTTPException(
110
+ 502, f"Upstream API error: {exc.response.status_code}"
111
+ ) from exc
112
  except Exception as exc: # noqa: BLE001 — surface engine errors to the client
113
  raise HTTPException(500, f"Translation failed: {exc}") from exc
114
 
115
  return TranslateResponse(
116
  translation=result, source=req.source, target=req.target, engine=engine_id
117
  )
118
+
119
+
120
+ @app.get("/scalar", include_in_schema=False)
121
+ async def scalar_html():
122
+ return get_scalar_api_reference(
123
+ openapi_url=app.openapi_url,
124
+ title=app.title,
125
+ )
backend/providers/__init__.py CHANGED
@@ -7,6 +7,8 @@ report themselves available.
7
 
8
  from __future__ import annotations
9
 
 
 
10
  from providers.base import ProviderInfo, TranslationProvider
11
  from providers.gemini import GeminiProvider
12
  from providers.groq import GroqProvider, GroqQwenProvider
@@ -14,14 +16,15 @@ from providers.madlad import MADLADProvider
14
  from providers.nllb import NLLBProvider
15
  from providers.ollama import OllamaProvider
16
 
17
- # Order = display order in the UI. Local/private engines first.
18
  _PROVIDERS: list[TranslationProvider] = [
19
  NLLBProvider(),
20
  NLLBProvider(
21
  provider_id="nllb_1_3b",
22
  name="NLLB-200 (1.3B)",
23
- model_dir="models/nllb-200-distilled-1.3B-int8",
24
- hf_model="facebook/nllb-200-distilled-1.3B",
 
 
25
  ),
26
  MADLADProvider(),
27
  OllamaProvider(),
 
7
 
8
  from __future__ import annotations
9
 
10
+ import os
11
+
12
  from providers.base import ProviderInfo, TranslationProvider
13
  from providers.gemini import GeminiProvider
14
  from providers.groq import GroqProvider, GroqQwenProvider
 
16
  from providers.nllb import NLLBProvider
17
  from providers.ollama import OllamaProvider
18
 
 
19
  _PROVIDERS: list[TranslationProvider] = [
20
  NLLBProvider(),
21
  NLLBProvider(
22
  provider_id="nllb_1_3b",
23
  name="NLLB-200 (1.3B)",
24
+ model_dir=os.environ.get(
25
+ "CT2_MODEL_DIR_1_3B", "models/nllb-200-distilled-1.3B-int8"
26
+ ),
27
+ hf_model=os.environ.get("HF_MODEL_1_3B", "facebook/nllb-200-distilled-1.3B"),
28
  ),
29
  MADLADProvider(),
30
  OllamaProvider(),
backend/requirements.txt CHANGED
@@ -12,3 +12,4 @@ protobuf==5.29.2
12
 
13
  # ctranslate2 4.5 imports pkg_resources, removed in setuptools>=81
14
  setuptools<81
 
 
12
 
13
  # ctranslate2 4.5 imports pkg_resources, removed in setuptools>=81
14
  setuptools<81
15
+ scalar-fastapi
entrypoint.sh ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ echo "== Converting NLLB 600M =="
5
+ CT2_MODEL_DIR="/data/models/nllb-200-distilled-600M-int8" \
6
+ python convert_model.py
7
+
8
+ echo "== Converting NLLB 1.3B =="
9
+ HF_MODEL="facebook/nllb-200-distilled-1.3B" \
10
+ CT2_MODEL_DIR="/data/models/nllb-200-distilled-1.3B-int8" \
11
+ python convert_model.py
12
+
13
+ echo "== Converting MADLAD 3B =="
14
+ HF_MODEL="google/madlad400-3b-mt" \
15
+ CT2_MODEL_DIR="/data/models/madlad400-3b-mt-int8" \
16
+ python convert_model.py
17
+
18
+ echo "== Starting server =="
19
+ exec uvicorn main:app --host 0.0.0.0 --port 7860