├── requirements.txt ├── conf ├── translate-service.service ├── nginx.conf └── httpd.conf ├── .github └── workflows │ └── docker-image.yml ├── README.md ├── Dockerfile ├── app.py └── langs.json /requirements.txt: -------------------------------------------------------------------------------- 1 | fastapi==0.68.0 2 | pydantic==1.8.2 3 | deep_translator==1.5.0 4 | uvicorn==0.15.0 5 | -------------------------------------------------------------------------------- /conf/translate-service.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=My FastAPI app 3 | After=network.target 4 | 5 | [Service] 6 | User=root 7 | Group=root 8 | WorkingDirectory=/path/to/myapp 9 | ExecStart=/usr/bin/env python3.8 -m uvicorn main:app --host 0.0.0.0 --port 8080 10 | Restart=always 11 | 12 | [Install] 13 | WantedBy=multi-user.target 14 | -------------------------------------------------------------------------------- /conf/nginx.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 8888; 3 | server_name translate.your-domain.com; 4 | 5 | location / { 6 | proxy_pass http://127.0.0.1:8080; 7 | proxy_set_header Host $host; 8 | proxy_set_header X-Real-IP $remote_addr; 9 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 10 | } 11 | } -------------------------------------------------------------------------------- /conf/httpd.conf: -------------------------------------------------------------------------------- 1 | 2 | ServerName translate.your-domain.com 3 | 4 | ProxyPass / http://127.0.0.1:8080/ 5 | ProxyPassReverse / http://127.0.0.1:8080/ 6 | 7 | ProxyPreserveHost On 8 | RequestHeader set X-Real-IP %{REMOTE_ADDR}s 9 | RequestHeader set X-Forwarded-For %{HTTP:X-Forwarded-For}s 10 | -------------------------------------------------------------------------------- /.github/workflows/docker-image.yml: -------------------------------------------------------------------------------- 1 | name: Docker Image CI 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | jobs: 10 | 11 | build: 12 | 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v3 17 | - name: Build the Docker image 18 | run: docker build . --file Dockerfile --tag my-image-name:$(date +%s) 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Notes 2 | - Install Python 3.8 or higher 3 | - Keep in mind that this service need to make requests to google so it needs intenet 4 | - Feel free to submit merge request 5 | - Enjoy 6 | 7 | # Installation 8 | git clone https://github.com/imanimen/translate-service.git 9 | cd translate-service 10 | pip install -r requirements.txt 11 | # Run 12 | python app.py 13 | # Endpoint 14 | http://127.0.0.1/translate 15 | # Method 16 | POST 17 | # Payload 18 | { 19 | "text": "your-sample-text", 20 | "source": "en", 21 | "target": "fa" 22 | } 23 | # Documentation 24 | http://127.0.0.1/docs 25 | 26 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Use an official Python runtime as a parent image 2 | FROM python:3.9-slim-buster 3 | 4 | # Set the working directory to /app 5 | WORKDIR /app 6 | 7 | # Copy the current directory contents into the container at /app 8 | COPY . /app 9 | 10 | # Install any needed packages specified in requirements.txt 11 | RUN apt-get update && \ 12 | apt-get install -y gcc libpq-dev && \ 13 | pip install --no-cache-dir -r requirements.txt && \ 14 | apt-get remove -y gcc libpq-dev && \ 15 | apt-get autoremove -y && \ 16 | apt-get clean && \ 17 | rm -rf /var/lib/apt/lists/* 18 | 19 | # Expose port 8080 for the FastAPI app 20 | EXPOSE 8080 21 | 22 | # Run the FastAPI app with uvicorn 23 | CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8080"] -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI 2 | from pydantic import BaseModel 3 | from typing import Optional 4 | import re 5 | from deep_translator import GoogleTranslator 6 | from fastapi.middleware.cors import CORSMiddleware 7 | 8 | app = FastAPI() 9 | 10 | origins = ["*"] 11 | 12 | app.add_middleware( 13 | CORSMiddleware, 14 | allow_origins=origins, 15 | allow_credentials=True, 16 | allow_methods=["*"], 17 | allow_headers=["*"], 18 | ) 19 | 20 | # Define the request payload schema 21 | class TranslationRequest(BaseModel): 22 | text: str 23 | source: Optional[str] = None 24 | target: str 25 | 26 | # Split the text into smaller groups up to 5000 characters without breaking lines so need to split on new lines 27 | def split_text(text, max_len=4500): 28 | # Split the text into lines 29 | lines = text.split("\n") 30 | # List of chunks 31 | chunks = [] 32 | # Chunk buffer 33 | chunk = "" 34 | 35 | # Loop through the lines 36 | for line in lines: 37 | # If the chunk is too long, add it to the list and reset the chunk 38 | if len(chunk + line) > max_len: 39 | chunks.append(chunk) 40 | chunk = "" 41 | # Add the line to the chunk 42 | chunk += line + "\n" 43 | 44 | # Add the last chunk to the list 45 | if chunk: 46 | chunks.append(chunk) 47 | 48 | # Return the list of chunks 49 | return chunks 50 | 51 | @app.post("/translate") 52 | def translate_text(request: TranslationRequest): 53 | # Get the input values from the request payload 54 | text = request.text 55 | source = request.source 56 | target = request.target 57 | 58 | # Translate the main text 59 | chunks = split_text(text) 60 | translated_text = '' 61 | for chunk in chunks: 62 | if source is None: 63 | source = 'auto' 64 | translated = GoogleTranslator(source=source, target=target).translate(text=chunk) 65 | translated_text += translated + "\n" 66 | 67 | # Remove extra new lines 68 | translated_text = re.sub(r'[\n]{3,}', '\n\n', translated_text.strip()) 69 | translated_text = translated_text.strip() 70 | 71 | # Return the translated text 72 | return { 'text': translated_text } 73 | 74 | if __name__ == "__main__": 75 | import uvicorn 76 | uvicorn.run(app, host="0.0.0.0", port=8080) 77 | -------------------------------------------------------------------------------- /langs.json: -------------------------------------------------------------------------------- 1 | { 2 | "afrikaans": "af", 3 | "albanian": "sq", 4 | "amharic": "am", 5 | "arabic": "ar", 6 | "armenian": "hy", 7 | "assamese": "as", 8 | "aymara": "ay", 9 | "azerbaijani": "az", 10 | "bambara": "bm", 11 | "basque": "eu", 12 | "belarusian": "be", 13 | "bengali": "bn", 14 | "bhojpuri": "bho", 15 | "bosnian": "bs", 16 | "bulgarian": "bg", 17 | "catalan": "ca", 18 | "cebuano": "ceb", 19 | "chichewa": "ny", 20 | "chinese (simplified)": "zh-CN", 21 | "chinese (traditional)": "zh-TW", 22 | "corsican": "co", 23 | "croatian": "hr", 24 | "czech": "cs", 25 | "danish": "da", 26 | "dhivehi": "dv", 27 | "dogri": "doi", 28 | "dutch": "nl", 29 | "english": "en", 30 | "esperanto": "eo", 31 | "estonian": "et", 32 | "ewe": "ee", 33 | "filipino": "tl", 34 | "finnish": "fi", 35 | "french": "fr", 36 | "frisian": "fy", 37 | "galician": "gl", 38 | "georgian": "ka", 39 | "german": "de", 40 | "greek": "el", 41 | "guarani": "gn", 42 | "gujarati": "gu", 43 | "haitian creole": "ht", 44 | "hausa": "ha", 45 | "hawaiian": "haw", 46 | "hebrew": "iw", 47 | "hindi": "hi", 48 | "hmong": "hmn", 49 | "hungarian": "hu", 50 | "icelandic": "is", 51 | "igbo": "ig", 52 | "ilocano": "ilo", 53 | "indonesian": "id", 54 | "irish": "ga", 55 | "italian": "it", 56 | "japanese": "ja", 57 | "javanese": "jw", 58 | "kannada": "kn", 59 | "kazakh": "kk", 60 | "khmer": "km", 61 | "kinyarwanda": "rw", 62 | "konkani": "gom", 63 | "korean": "ko", 64 | "krio": "kri", 65 | "kurdish (kurmanji)": "ku", 66 | "kurdish (sorani)": "ckb", 67 | "kyrgyz": "ky", 68 | "lao": "lo", 69 | "latin": "la", 70 | "latvian": "lv", 71 | "lingala": "ln", 72 | "lithuanian": "lt", 73 | "luganda": "lg", 74 | "luxembourgish": "lb", 75 | "macedonian": "mk", 76 | "maithili": "mai", 77 | "malagasy": "mg", 78 | "malay": "ms", 79 | "malayalam": "ml", 80 | "maltese": "mt", 81 | "maori": "mi", 82 | "marathi": "mr", 83 | "meiteilon (manipuri)": "mni-Mtei", 84 | "mizo": "lus", 85 | "mongolian": "mn", 86 | "myanmar": "my", 87 | "nepali": "ne", 88 | "norwegian": "no", 89 | "odia (oriya)": "or", 90 | "oromo": "om", 91 | "pashto": "ps", 92 | "persian": "fa", 93 | "polish": "pl", 94 | "portuguese": "pt", 95 | "punjabi": "pa", 96 | "quechua": "qu", 97 | "romanian": "ro", 98 | "russian": "ru", 99 | "samoan": "sm", 100 | "sanskrit": "sa", 101 | "scots gaelic": "gd", 102 | "sepedi": "nso", 103 | "serbian": "sr", 104 | "sesotho": "st", 105 | "shona": "sn", 106 | "sindhi": "sd", 107 | "sinhala": "si", 108 | "slovak": "sk", 109 | "slovenian": "sl", 110 | "somali": "so", 111 | "spanish": "es", 112 | "sundanese":"su", 113 | "swahili": "sw", 114 | "swedish": "sv", 115 | "tajik": "tg", 116 | "tamil": "ta", 117 | "tatar": "tt", 118 | "telugu": "te", 119 | "thai": "th", 120 | "tigrinya": "ti", 121 | "tsonga": "ts", 122 | "turkish": "tr", 123 | "turkmen": "tk", 124 | "twi": "ak", 125 | "ukrainian": "uk", 126 | "urdu": "ur", 127 | "uyghur": "ug", 128 | "uzbek": "uz", 129 | "vietnamese": "vi", 130 | "welsh": "cy", 131 | "xhosa": "xh", 132 | "yiddish": "yi", 133 | "yoruba": "yo", 134 | "zulu": "zu" 135 | } --------------------------------------------------------------------------------