File size: 6,930 Bytes
b4ad204
 
 
1b967ef
b4ad204
 
 
 
1b967ef
b4ad204
1b967ef
b4ad204
 
 
1b967ef
b4ad204
1b967ef
 
b4ad204
 
 
 
1b967ef
 
b4ad204
 
 
 
 
 
1b967ef
b4ad204
 
 
12fbfda
b4ad204
 
 
 
 
 
 
1b967ef
12fbfda
b4ad204
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import os
import re  # Import the regular expression module
from typing import List

from fastapi import FastAPI, HTTPException, status
from pydantic import BaseModel
import requests
from fastapi.responses import HTMLResponse

app = FastAPI()

GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY")
if not GEMINI_API_KEY:
    raise ValueError("The GEMINI_API_KEY environment variable is not set.")

GEMINI_API_URL = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash-lite:generateContent?key=" + GEMINI_API_KEY


class TranslationRequest(BaseModel):
    text: str
    target_language: str
    source_language: str = None


class TranslationResponse(BaseModel):  # For /detect_language
    translated_text: str
    source_language: str
    target_language: str

# --- Helper Functions ---

def detect_language_and_options(text: str):
    """Detects the language and provides translation options."""
    prompt = f"""Please identify the language of the text provided and then offer translation options as numbered choices (1-5).  Use this format:  "The text is in [Language].  Choose a language to translate to: 1. [Option 1], 2. [Option 2], 3. [Option 3], 4. [Option 4], 5. [Option 5]"

    Input Text: {text}"""

    request_data = {
        "contents": [{
            "role": "user",
            "parts": [{"text": prompt}]
        }]
    }

    try:
        response = requests.post(GEMINI_API_URL, json=request_data)
        response.raise_for_status()
        response_json = response.json()

        try:
            response_text = response_json['candidates'][0]['content']['parts'][0]['text']
            source_language = response_text.split("The text is in ")[1].split(".")[0].strip()
            options_str = response_text.split("Choose a language to translate to:")[1].strip()
            options_list = [opt.split(". ")[1].strip() for opt in options_str.split(", ")]
            while len(options_list) < 5:
                options_list.append("Option Not Available")
            options_list = options_list[:5]
            options = {str(i + 1): lang for i, lang in enumerate(options_list)}
            return source_language, options
        except (KeyError, IndexError, AttributeError) as e:
            raise HTTPException(status_code=500, detail=f"Error parsing Gemini API response: {e}")
    except requests.exceptions.RequestException as e:
        raise HTTPException(status_code=500, detail=f"Error communicating with Gemini API: {e}")
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"An unexpected error occurred: {e}")


def translate_with_gemini(text: str, source_language: str, target_language: str) -> str:
    """Translates text, requesting HTML, and removes Markdown code blocks."""

    prompt = f"""Translate the following text from {source_language} to {target_language}. Return *only* the translated text.  Format the response as HTML. If any part of the translated text should be emphasized (like an example or key phrase), use `<strong>` tags around that part. Do not include ANY additional text like 'Here is the translation:' or similar.  Only the translated text, formatted as HTML.

    Text:
    {text}"""

    request_data = {
        "contents": [{
            "role": "user",
            "parts": [{"text": prompt}]
        }]
    }

    try:
        response = requests.post(GEMINI_API_URL, json=request_data)
        response.raise_for_status()
        response_json = response.json()

        try:
            translated_text = response_json['candidates'][0]['content']['parts'][0]['text']

            # Remove Markdown code blocks (```html ... ```)
            translated_text = re.sub(r"```html\n?([\s\S]*?)\n?```", r"\1", translated_text).strip()
            translated_text = re.sub(r"```([\s\S]*?)```", r"\1", translated_text).strip() # Remove plain ``` ... ```


            return translated_text
        except (KeyError, IndexError) as e:
            raise HTTPException(status_code=500, detail=f"Error parsing Gemini API response: {e}")
    except requests.exceptions.RequestException as e:
        raise HTTPException(status_code=500, detail=f"Error communicating with Gemini API: {e}")
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"An unexpected error occurred: {e}")


@app.post("/translate", response_class=HTMLResponse, status_code=status.HTTP_200_OK)
async def translate(request: TranslationRequest):
    """Translates text, returning HTML."""

    if not request.text:
        raise HTTPException(status_code=400, detail="Text to translate cannot be empty.")
    if not request.target_language:
        raise HTTPException(status_code=400, detail="Target language must be provided.")

    if request.source_language:
        source_language = request.source_language
    else:
        try:
            source_language, _ = detect_language_and_options(request.text)
        except HTTPException as e:
            raise e

    supported_languages = ["Afrikaans", "Arabic", "Armenian", "Azerbaijani", "Belarusian", "Bosnian", "Bulgarian",
                           "Catalan", "Chinese", "Croatian", "Czech", "Danish", "Dutch", "English", "Estonian",
                           "Finnish", "French", "Galician", "German", "Greek", "Hebrew", "Hindi", "Hungarian",
                           "Icelandic", "Indonesian", "Italian", "Japanese", "Kannada", "Kazakh", "Korean", "Latvian",
                           "Lithuanian", "Macedonian", "Malay", "Marathi", "Maori", "Nepali", "Norwegian", "Persian",
                           "Polish", "Portuguese", "Romanian", "Russian", "Serbian", "Slovak", "Slovenian", "Spanish",
                           "Swahili", "Swedish", "Tagalog", "Tamil", "Thai", "Turkish", "Ukrainian", "Urdu",
                           "Vietnamese", "Welsh"]

    if request.target_language not in supported_languages:
        raise HTTPException(status_code=400, detail=f"Target language '{request.target_language}' is not supported.")

    try:
        translated_html = translate_with_gemini(request.text, source_language, request.target_language)
        return translated_html
    except HTTPException as e:
        raise e
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"An unexpected error occurred: {e}")



@app.post("/detect_language", status_code=status.HTTP_200_OK)
async def detect_language(text: str = ""):
    """Detects the language of the input text and provides translation options."""
    if not text:
        raise HTTPException(status_code=400, detail="Text to detect cannot be empty.")
    try:
        source_language, options = detect_language_and_options(text)
        return {"source_language": source_language, "translation_options": options}
    except HTTPException as e:
        raise e
    except Exception as e:
         raise HTTPException(status_code=500,detail=f"An unexpected error occurred {e}")