dptran 2.4.0

A tool to run DeepL translations on command line written by Rust.
Documentation
# This is a dummy API server for translation services for testing purposes.
# To run this server:
# $ pip3 install -r requirements.txt
# $ uvicorn dummy_api_server.main:app --reload

from fastapi import FastAPI, Form, Request, Query
from fastapi.responses import JSONResponse
from pydantic import BaseModel
from enum import Enum
from typing import List, Optional
from dummy_api_server.glossaries_api import router as glossaries_router

app = FastAPI()
app.include_router(glossaries_router)

class TranslationResponseText(BaseModel):
    text: str

class TranslationResponse(BaseModel):
    translations: list[TranslationResponseText]

class TranslationDummyData(BaseModel):
    source_lang: str
    target_lang: str
    request: str
    reponse: str

class SplitSentences(str, Enum):
    False_ = "0"
    True_ = "1"
    NoNewLines = "nonewlines"

class Formality(str, Enum):
    Default = "default"
    More = "more"
    Less = "less"
    PreferMore = "prefer_more"
    PreferLess = "prefer_less"

class ModelType(str, Enum):
    QualityOptimized = "quality"
    PreferQualityOptimized = "prefer_quality_optimized"
    LatencyOptimized = "latency_optimized"

class TagHandling(str, Enum):
    Xml = "xml"
    Html = "html"

class TranslateRequest(BaseModel):
    text: List[str]
    target_lang: str
    source_lang: Optional[str] = None
    context: Optional[str] = None
    show_billed_characters: Optional[bool] = None
    split_sentences: Optional[SplitSentences] = None
    preserve_formatting: Optional[bool] = None
    formality: Optional[Formality] = None
    model_type: Optional[ModelType] = None
    glossary_id: Optional[str] = None
    tag_handling: Optional[TagHandling] = None
    outline_detection: Optional[bool] = None
    non_splitting_tags: Optional[List[str]] = None
    splitting_tags: Optional[List[str]] = None
    ignore_tags: Optional[List[str]] = None

dummy_data = [
    TranslationDummyData(
        source_lang="en",
        target_lang="ja",
        request="Hello",
        reponse="こんにちは"
    ),
    TranslationDummyData(
        source_lang="ja",
        target_lang="en",
        request="こんにちは",
        reponse="Hello"
    ),
    TranslationDummyData(
        source_lang="en",
        target_lang="ja",
        request="Hello, World!",
        reponse="ハロー、ワールド!"
    ),
    TranslationDummyData(
        source_lang="ja",
        target_lang="en",
        request="ハロー、ワールド!",
        reponse="Hello, World!"
    ),
    TranslationDummyData(
        source_lang="en",
        target_lang="fr",
        request="Hello",
        reponse="Bonjour"
    ),
    TranslationDummyData(
        source_lang="fr",
        target_lang="en",
        request="Bonjour",
        reponse="Hello"
    ),
    TranslationDummyData(
        source_lang="ja",
        target_lang="fr",
        request="こんにちは",
        reponse="Bonjour"
    ),
    TranslationDummyData(
        source_lang="fr",
        target_lang="ja",
        request="Bonjour",
        reponse="こんにちは"
    ),
]

character_count = 0

def translate_texts(source_lang: str, target_lang: str, text: str) -> str:
    source_lang = source_lang.lower() if source_lang else None
    target_lang = target_lang.lower()
    # if source_lang == target_lang, return the text as is
    if source_lang == target_lang:
        return JSONResponse(content={"translations": [
            {"detected_source_language": source_lang or target_lang, "text": t} for t in text
        ]})
    # Simulate translation by looking up dummy data
    results = []
    global character_count
    for text in text:
        character_count += len(text)
        for item in dummy_data:
            if ((item.source_lang == source_lang or source_lang == None) and
                    item.target_lang == target_lang and
                    item.request == text):
                results.append({
                    "detected_source_language": item.source_lang,
                    "text": item.reponse
                })
    if results:
        return JSONResponse(content={"translations": results})
    return JSONResponse(content={"translations": [
        {"detected_source_language": source_lang or target_lang, "text": text}
    ]})

def usage_response(character_count: int, character_limit: int, type: str) -> JSONResponse:
    if type == "free":
        return JSONResponse(
            content={
                "character_count": character_count,
                "character_limit": character_limit
            }
        )
    elif type == "pro":
        return JSONResponse(
            content={
                "character_count": character_count * 10,
                "character_limit": character_limit * 10
            }
        )
    return JSONResponse(
        content={
            "error": "Invalid type"
        }
    )

def languages_response(type: str) -> JSONResponse:
    if type == "source":
        return JSONResponse(
            content=[
                {
                    "language": "EN",
                    "name": "English",
                    "supports_formality": True
                },
                {
                    "language": "EN-US",
                    "name": "English",
                    "supports_formality": True
                },
                {
                    "language": "JA",
                    "name": "Japanese",
                    "supports_formality": False
                },
                {
                    "language": "FR",
                    "name": "French",
                    "supports_formality": True
                }
            ]
        )
    elif type == "target":
        return JSONResponse(
            content=[
                {
                    "language": "EN",
                    "name": "English",
                    "supports_formality": True
                },
                {
                    "language": "EN-US",
                    "name": "English",
                    "supports_formality": True
                },
                {
                    "language": "JA",
                    "name": "Japanese",
                    "supports_formality": False
                },
                {
                    "language": "FR",
                    "name": "French",
                    "supports_formality": True
                }
            ]
        )
    return JSONResponse(
        content={
            "error": "Invalid type"
        }
    )

@app.post("/free/v2/translate")
async def translate_for_free(request: Request, body: TranslateRequest):
    # Get the Authorization header
    auth_header = request.headers.get("Authorization", "")
    print(f"Authorization header: {auth_header}")

    # Check if the Authorization header is valid
    if not auth_header.startswith("DeepL-Auth-Key "):
        return JSONResponse(content={"error": "Invalid or missing Authorization header"}, status_code=401)

    api_key = auth_header.replace("DeepL-Auth-Key ", "")
    if not api_key:
        return JSONResponse(content={"error": "auth_key is required"}, status_code=400)

    # Log the request body for debugging
    print(f"Received JSON: {body.json()}")

    # Call the translation function
    return translate_texts(body.source_lang, body.target_lang, body.text)

@app.post("/pro/v2/translate")
async def translate_for_pro(request: Request, body: TranslateRequest):
    # Get the Authorization header
    auth_header = request.headers.get("Authorization", "")
    print(f"Authorization header: {auth_header}")

    # Check if the Authorization header is valid
    if not auth_header.startswith("DeepL-Auth-Key "):
        return JSONResponse(content={"error": "Invalid or missing Authorization header"}, status_code=401)

    api_key = auth_header.replace("DeepL-Auth-Key ", "")
    if not api_key:
        return JSONResponse(content={"error": "auth_key is required"}, status_code=400)

    # Log the request body for debugging
    print(f"Received JSON: {body.json()}")

    # Call the translation function
    return translate_texts(body.source_lang, body.target_lang, body.text)

@app.get("/free/v2/usage")
async def usage_for_free(request: Request):
    auth_header = request.headers.get("Authorization", "")
    print(f"Received request: auth_key={auth_header}")
    if not auth_header.startswith("DeepL-Auth-Key "):
        return JSONResponse(content={"error": "Invalid or missing Authorization header"}, status_code=401)
    global character_count
    return usage_response(
        character_count=character_count,
        character_limit=1000000,
        type="free"
    )

@app.get("/pro/v2/usage")
async def usage_for_pro(request: Request):
    auth_header = request.headers.get("Authorization", "")
    print(f"Received request: auth_key={auth_header}")
    if not auth_header.startswith("DeepL-Auth-Key "):
        return JSONResponse(content={"error": "Invalid or missing Authorization header"}, status_code=401)
    global character_count
    return usage_response(
        character_count=character_count,
        character_limit=1000000000000,
        type="pro"
    )

class LanguagesResponseElement(BaseModel):
    language: str
    name: str

@app.get("/free/v2/languages")
async def languages_for_free(request: Request, type: Optional[str] = Query(None)):
    auth_header = request.headers.get("Authorization", "")
    print(f"Received request: auth_key={auth_header}")
    print(f"Type parameter: {type}")
    if not auth_header.startswith("DeepL-Auth-Key "):
        return JSONResponse(content={"error": "Invalid or missing Authorization header"}, status_code=401)
    return languages_response(type)

@app.get("/pro/v2/languages")
async def languages_for_pro(request: Request, type: Optional[str] = Query(None)):
    auth_header = request.headers.get("Authorization", "")
    print(f"Received request: auth_key={auth_header}")
    print(f"Type parameter: {type}")
    if not auth_header.startswith("DeepL-Auth-Key "):
        return JSONResponse(content={"error": "Invalid or missing Authorization header"}, status_code=401)
    return languages_response(type)

@app.get("/")
async def get_root():
    return JSONResponse(content={"message": "200 OK"}, status_code=200)

@app.post("/")
async def post_root():
    return JSONResponse(content={"message": "200 OK"}, status_code=200)

@app.delete("/")
async def delete_root():
    return JSONResponse(content={"message": "200 OK"}, status_code=200)

@app.patch("/")
async def patch_root():
    return JSONResponse(content={"message": "200 OK"}, status_code=200)

if __name__ == "__main__":
    import uvicorn

    uvicorn.run(app, host="127.0.0.1", port=8000)