Spaces:
Running
Running
Upload 6 files
Browse files- Dockerfile +6 -27
- README.md +2 -16
- gradio_app.py +6 -56
- main.py +15 -85
- requirements.txt +4 -3
- space.yaml +8 -0
Dockerfile
CHANGED
|
@@ -1,35 +1,14 @@
|
|
| 1 |
-
|
| 2 |
-
FROM ubuntu:20.04
|
| 3 |
-
|
| 4 |
-
ENV DEBIAN_FRONTEND=noninteractive
|
| 5 |
-
|
| 6 |
-
RUN apt update && apt install -y \
|
| 7 |
-
python3 python3-pip unzip curl git build-essential cmake libboost-all-dev \
|
| 8 |
-
&& rm -rf /var/lib/apt/lists/*
|
| 9 |
-
|
| 10 |
-
RUN pip3 install --no-cache-dir fastapi uvicorn[standard] gradio requests langcodes
|
| 11 |
|
| 12 |
RUN useradd -m -u 1000 user
|
| 13 |
USER user
|
|
|
|
| 14 |
|
| 15 |
-
|
| 16 |
-
RUN mkdir -p /home/user/models && \
|
| 17 |
-
curl -L "https://github.com/xxnuo/MTranServer/releases/download/models/enzh.zip" -o /home/user/models/enzh.zip && \
|
| 18 |
-
curl -L "https://github.com/xxnuo/MTranServer/releases/download/models/zhen.zip" -o /home/user/models/zhen.zip && \
|
| 19 |
-
curl -L "https://github.com/xxnuo/MTranServer/releases/download/models/enja.zip" -o /home/user/models/enja.zip && \
|
| 20 |
-
unzip /home/user/models/enzh.zip -d /home/user/models/enzh && \
|
| 21 |
-
unzip /home/user/models/zhen.zip -d /home/user/models/zhen && \
|
| 22 |
-
unzip /home/user/models/enja.zip -d /home/user/models/enja && \
|
| 23 |
-
rm /home/user/models/*.zip
|
| 24 |
|
| 25 |
-
COPY --chown=user
|
| 26 |
-
COPY --chown=user gradio_app.py /home/user/gradio_app.py
|
| 27 |
|
| 28 |
-
|
| 29 |
|
| 30 |
-
EXPOSE 8989
|
| 31 |
EXPOSE 7860
|
| 32 |
-
|
| 33 |
-
CMD bash -c "\
|
| 34 |
-
python3 /home/user/main.py & \
|
| 35 |
-
python3 /home/user/gradio_app.py"
|
|
|
|
| 1 |
+
FROM python:3.9
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
|
| 3 |
RUN useradd -m -u 1000 user
|
| 4 |
USER user
|
| 5 |
+
ENV PATH="/home/user/.local/bin:$PATH"
|
| 6 |
|
| 7 |
+
WORKDIR /home/user/app
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
|
| 9 |
+
COPY --chown=user . .
|
|
|
|
| 10 |
|
| 11 |
+
RUN pip install --no-cache-dir -r requirements.txt
|
| 12 |
|
|
|
|
| 13 |
EXPOSE 7860
|
| 14 |
+
CMD ["python", "gradio_app.py"]
|
|
|
|
|
|
|
|
|
README.md
CHANGED
|
@@ -1,17 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
title: MTranServer Full UI
|
| 3 |
-
emoji: 🌍
|
| 4 |
-
colorFrom: green
|
| 5 |
-
colorTo: blue
|
| 6 |
-
sdk: docker
|
| 7 |
-
pinned: true
|
| 8 |
-
---
|
| 9 |
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
支持:
|
| 13 |
-
- 多语言模型选择
|
| 14 |
-
- 自动语言代码识别(zh-CN, en-US)
|
| 15 |
-
- 插件接口支持(kiss/imme/hcfy)
|
| 16 |
-
- 文件翻译(txt)
|
| 17 |
-
- Gradio 前端 UI
|
|
|
|
| 1 |
+
# MTranServer HF Python 版
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
|
| 3 |
+
这是一个基于 Hugging Face Transformers 的英文翻译服务器,支持 Gradio 界面。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
gradio_app.py
CHANGED
|
@@ -1,61 +1,11 @@
|
|
| 1 |
-
|
| 2 |
import gradio as gr
|
| 3 |
import requests
|
| 4 |
-
import os
|
| 5 |
-
|
| 6 |
-
API_URL = "http://localhost:8989/translate"
|
| 7 |
-
FILE_URL = "http://localhost:8989/translate/file"
|
| 8 |
-
API_TOKEN = os.environ.get("CORE_API_TOKEN", "")
|
| 9 |
-
|
| 10 |
-
LANGUAGE_PAIRS = {
|
| 11 |
-
"English → Chinese": ("en", "zh"),
|
| 12 |
-
"Chinese → English": ("zh", "en"),
|
| 13 |
-
"English → Japanese": ("en", "ja")
|
| 14 |
-
}
|
| 15 |
-
|
| 16 |
-
def translate_text(text, direction):
|
| 17 |
-
src, tgt = LANGUAGE_PAIRS[direction]
|
| 18 |
-
headers = {"Content-Type": "application/json"}
|
| 19 |
-
if API_TOKEN:
|
| 20 |
-
headers["Authorization"] = API_TOKEN
|
| 21 |
-
payload = {"from": src, "to": tgt, "text": text}
|
| 22 |
-
try:
|
| 23 |
-
r = requests.post(API_URL, json=payload, headers=headers, timeout=10)
|
| 24 |
-
r.raise_for_status()
|
| 25 |
-
return r.json().get("result", "")
|
| 26 |
-
except Exception as e:
|
| 27 |
-
return f"翻译失败:{str(e)}"
|
| 28 |
-
|
| 29 |
-
def translate_file(file, direction):
|
| 30 |
-
if file is None:
|
| 31 |
-
return "请上传文件"
|
| 32 |
-
src, tgt = LANGUAGE_PAIRS[direction]
|
| 33 |
-
headers = {}
|
| 34 |
-
if API_TOKEN:
|
| 35 |
-
headers["Authorization"] = API_TOKEN
|
| 36 |
-
with open(file.name, "rb") as f:
|
| 37 |
-
files = {"file": (file.name, f, "text/plain")}
|
| 38 |
-
r = requests.post(FILE_URL + f"?from_lang={src}&to_lang={tgt}", files=files, headers=headers)
|
| 39 |
-
try:
|
| 40 |
-
r.raise_for_status()
|
| 41 |
-
return r.json().get("result", "")
|
| 42 |
-
except Exception as e:
|
| 43 |
-
return f"文件翻译失败:{str(e)}"
|
| 44 |
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
text = gr.Textbox(label="输入文本", lines=5)
|
| 49 |
-
lang = gr.Radio(choices=list(LANGUAGE_PAIRS.keys()), label="语言方向", value="English → Chinese")
|
| 50 |
-
output = gr.Textbox(label="翻译结果")
|
| 51 |
-
btn = gr.Button("翻译")
|
| 52 |
-
btn.click(translate_text, inputs=[text, lang], outputs=output)
|
| 53 |
|
| 54 |
-
|
| 55 |
-
file = gr.File(label="上传 .txt 文件")
|
| 56 |
-
lang2 = gr.Radio(choices=list(LANGUAGE_PAIRS.keys()), label="语言方向", value="English → Chinese")
|
| 57 |
-
output2 = gr.Textbox(label="翻译结果")
|
| 58 |
-
btn2 = gr.Button("翻译文件")
|
| 59 |
-
btn2.click(translate_file, inputs=[file, lang2], outputs=output2)
|
| 60 |
|
| 61 |
-
|
|
|
|
|
|
|
|
|
| 1 |
import gradio as gr
|
| 2 |
import requests
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
|
| 4 |
+
def translate_text(text):
|
| 5 |
+
response = requests.post("http://localhost:7860/translate", json={"text": text})
|
| 6 |
+
return response.json().get("result", "Error")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
|
| 8 |
+
demo = gr.Interface(fn=translate_text, inputs="text", outputs="text", title="英文翻译(Hugging Face 模型)")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
|
| 10 |
+
if __name__ == "__main__":
|
| 11 |
+
demo.launch(server_name="0.0.0.0", server_port=7860)
|
main.py
CHANGED
|
@@ -1,90 +1,20 @@
|
|
| 1 |
-
|
| 2 |
-
from
|
| 3 |
-
import os
|
| 4 |
-
import subprocess
|
| 5 |
-
import uvicorn
|
| 6 |
-
import langcodes
|
| 7 |
|
| 8 |
app = FastAPI()
|
| 9 |
-
API_TOKEN = os.environ.get("CORE_API_TOKEN", "")
|
| 10 |
-
MODEL_ROOT = "/home/user/models"
|
| 11 |
-
SUPPORTED_LANGS = {
|
| 12 |
-
("en", "zh"): "enzh",
|
| 13 |
-
("zh", "en"): "zhen",
|
| 14 |
-
("en", "ja"): "enja"
|
| 15 |
-
}
|
| 16 |
-
|
| 17 |
-
def normalize_lang(code):
|
| 18 |
-
try:
|
| 19 |
-
return langcodes.standardize_tag(code).split("-")[0]
|
| 20 |
-
except:
|
| 21 |
-
return code.lower().split("-")[0]
|
| 22 |
-
|
| 23 |
-
def check_token(req: Request):
|
| 24 |
-
if API_TOKEN:
|
| 25 |
-
token = req.headers.get("Authorization", "")
|
| 26 |
-
if token != API_TOKEN:
|
| 27 |
-
raise HTTPException(status_code=401, detail="Unauthorized")
|
| 28 |
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
model_key = SUPPORTED_LANGS.get((src, tgt))
|
| 33 |
-
if not model_key:
|
| 34 |
-
raise HTTPException(status_code=400, detail=f"Unsupported language pair: {src} → {tgt}")
|
| 35 |
-
model_path = os.path.join(MODEL_ROOT, model_key)
|
| 36 |
-
result = subprocess.run(
|
| 37 |
-
["mtranclient", "--from", src, "--to", tgt, "--text", text, "--model-dir", model_path],
|
| 38 |
-
capture_output=True, text=True
|
| 39 |
-
)
|
| 40 |
-
if result.returncode != 0:
|
| 41 |
-
raise HTTPException(status_code=500, detail="Translation failed")
|
| 42 |
-
return result.stdout.strip()
|
| 43 |
|
| 44 |
@app.post("/translate")
|
| 45 |
-
async def
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
results = [translate_by_subprocess(t, data["from"], data["to"]) for t in texts]
|
| 56 |
-
return {"results": results}
|
| 57 |
-
|
| 58 |
-
@app.post("/translate/file")
|
| 59 |
-
async def translate_file(file: UploadFile = File(...), from_lang: str = "en", to_lang: str = "zh"):
|
| 60 |
-
contents = await file.read()
|
| 61 |
-
text = contents.decode("utf-8")
|
| 62 |
-
result = translate_by_subprocess(text, from_lang, to_lang)
|
| 63 |
-
return {"filename": file.filename, "result": result}
|
| 64 |
-
|
| 65 |
-
@app.get("/models")
|
| 66 |
-
def get_models():
|
| 67 |
-
return {"models": list(SUPPORTED_LANGS.values())}
|
| 68 |
-
|
| 69 |
-
@app.get("/health")
|
| 70 |
-
def health():
|
| 71 |
-
return {"status": "ok"}
|
| 72 |
-
|
| 73 |
-
@app.post("/kiss")
|
| 74 |
-
@app.post("/imme")
|
| 75 |
-
@app.post("/hcfy")
|
| 76 |
-
@app.post("/language/translate/v2")
|
| 77 |
-
async def plugin_translate(req: Request):
|
| 78 |
-
check_token(req)
|
| 79 |
-
data = await req.json()
|
| 80 |
-
src = data.get("source") or data.get("from") or "auto"
|
| 81 |
-
tgt = data.get("target") or data.get("to") or "zh"
|
| 82 |
-
text = data.get("q") or data.get("text")
|
| 83 |
-
return {
|
| 84 |
-
"data": {
|
| 85 |
-
"translations": [{"translatedText": translate_by_subprocess(text, src, tgt)}]
|
| 86 |
-
}
|
| 87 |
-
}
|
| 88 |
-
|
| 89 |
-
if __name__ == "__main__":
|
| 90 |
-
uvicorn.run(app, host="0.0.0.0", port=8989)
|
|
|
|
| 1 |
+
from fastapi import FastAPI, Request
|
| 2 |
+
from transformers import MarianMTModel, MarianTokenizer
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
|
| 4 |
app = FastAPI()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
|
| 6 |
+
model_name = "hf_model"
|
| 7 |
+
tokenizer = MarianTokenizer.from_pretrained(model_name)
|
| 8 |
+
model = MarianMTModel.from_pretrained(model_name)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
|
| 10 |
@app.post("/translate")
|
| 11 |
+
async def translate(request: Request):
|
| 12 |
+
data = await request.json()
|
| 13 |
+
src_text = data.get("text", "")
|
| 14 |
+
if not src_text:
|
| 15 |
+
return {"error": "Empty text"}
|
| 16 |
+
|
| 17 |
+
inputs = tokenizer([src_text], return_tensors="pt", padding=True, truncation=True)
|
| 18 |
+
translated = model.generate(**inputs)
|
| 19 |
+
output = tokenizer.batch_decode(translated, skip_special_tokens=True)
|
| 20 |
+
return {"result": output[0]}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
requirements.txt
CHANGED
|
@@ -1,5 +1,6 @@
|
|
| 1 |
fastapi
|
| 2 |
-
uvicorn
|
| 3 |
-
|
|
|
|
| 4 |
gradio
|
| 5 |
-
|
|
|
|
| 1 |
fastapi
|
| 2 |
+
uvicorn
|
| 3 |
+
transformers
|
| 4 |
+
torch
|
| 5 |
gradio
|
| 6 |
+
requests
|
space.yaml
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: MTranServer-HF
|
| 3 |
+
emoji: 🚀
|
| 4 |
+
colorFrom: indigo
|
| 5 |
+
colorTo: pink
|
| 6 |
+
sdk: docker
|
| 7 |
+
app_file: gradio_app.py
|
| 8 |
+
pinned: false
|