File size: 10,926 Bytes
f3f9d46
 
 
c091b8a
59ef98a
f3f9d46
d40b72f
 
 
 
f3f9d46
d40b72f
 
f3f9d46
d40b72f
 
f3f9d46
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2c63f8e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59ef98a
 
 
 
 
 
2c63f8e
59ef98a
 
 
 
f3f9d46
2c63f8e
59ef98a
 
2c63f8e
 
 
 
 
 
 
 
59ef98a
2c63f8e
59ef98a
 
 
 
 
 
 
 
 
f3f9d46
59ef98a
2c63f8e
 
 
 
 
 
 
 
 
59ef98a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f3f9d46
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59ef98a
 
 
 
 
 
 
 
 
2c63f8e
 
 
 
 
 
 
 
 
 
 
59ef98a
 
 
 
f3f9d46
 
59ef98a
f3f9d46
 
d40b72f
 
 
f3f9d46
d40b72f
f3f9d46
 
 
59ef98a
f3f9d46
 
 
 
59ef98a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2c63f8e
59ef98a
 
 
 
 
 
 
 
2c63f8e
 
 
 
59ef98a
 
 
 
 
 
2c63f8e
59ef98a
 
 
f3f9d46
 
 
 
59ef98a
 
 
3d5331d
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
from flask import Flask, request, jsonify, render_template
import os
from flask_cors import CORS
from openai import OpenAI
from translate import Translator

# Load API key and base URL from environment variables
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY") or os.getenv("GEMINI_API_KEY")
if not OPENAI_API_KEY:
    raise ValueError("OpenAI API Key is missing. Set it in environment variables.")

OPENAI_API_BASE = os.getenv("OPENAI_API_BASE", "https://generativelanguage.googleapis.com/v1beta/openai/")  # Default is standard OpenAI
OPENAI_MODEL = os.getenv("OPENAI_MODEL", "gemini-2.5-flash")  # Default model

# Configure OpenAI client (supports custom base url for OpenAI-compatible APIs)
client = OpenAI(api_key=OPENAI_API_KEY, base_url=OPENAI_API_BASE)

# Set the static folder path to the "static" folder
STATIC_FOLDER = os.path.join(os.path.dirname(__file__), "static")

# Read the context file from the static folder
CONTEXT_FILE = os.path.join(STATIC_FOLDER, "context.txt")
try:
    with open(CONTEXT_FILE, "r", encoding="utf-8") as file:
        CONTEXT_DATA = file.read()
except FileNotFoundError:
    CONTEXT_DATA = "No context available."

SYSTEM_INSTRUCTION = """
You are Hal, an AI assistant created to help farmers.
Your goal is to analyze the crop data provided in the context file and assist farmers by answering their queries and solving their problems.

Response Rules:
1. Use the context file to answer farmer-related questions.
2. Do not share any personal information.
3. Provide only the information available in the context file.
4. If not found, generate helpful answers from agricultural knowledge.
5. Keep responses simple, clear, and useful.
"""

# Flask app
app = Flask(__name__, template_folder="templates", static_folder="static")
CORS(app)

# Language detection function
def detect_language(text):
    """
    Detect language of text using multiple methods
    """
    try:
        # Method 1: Try langdetect if available
        try:
            from langdetect import detect
            detected = detect(text)
            return detected
        except ImportError:
            pass
        except:
            pass
        
        # Method 2: Simple heuristic detection
        common_words = {
            'en': ['the', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for', 'of', 'with', 'by', 'is', 'are', 'was', 'were'],
            'es': ['el', 'la', 'de', 'que', 'y', 'en', 'un', 'es', 'se', 'no', 'te', 'lo', 'por', 'con', 'del', 'las'],
            'fr': ['le', 'de', 'et', 'à', 'un', 'il', 'être', 'en', 'avoir', 'que', 'pour', 'du', 'ce', 'son', 'une'],
            'de': ['der', 'die', 'und', 'in', 'den', 'von', 'zu', 'das', 'mit', 'sich', 'des', 'auf', 'für', 'ist'],
            'it': ['il', 'di', 'che', 'e', 'la', 'per', 'in', 'un', 'è', 'con', 'non', 'da', 'del', 'sono'],
            'pt': ['de', 'a', 'o', 'que', 'e', 'do', 'da', 'em', 'um', 'para', 'é', 'com', 'os', 'uma', 'ser'],
            'ru': ['в', 'и', 'не', 'на', 'я', 'быть', 'с', 'а', 'как', 'его', 'к', 'он', 'что', 'то'],
            'hi': ['है', 'का', 'के', 'में', 'और', 'को', 'से', 'पर', 'यह', 'वह', 'एक', 'जो'],
            'ar': ['في', 'من', 'إلى', 'على', 'هذا', 'هذه', 'التي', 'الذي', 'أن', 'كان', 'مع'],
            'zh': ['的', '是', '在', '了', '和', '有', '人', '我', '你', '他', '她', '它'],
        }
        
        text_lower = text.lower()
        scores = {}
        
        for lang, words in common_words.items():
            score = sum(1 for word in words if word in text_lower)
            if score > 0:
                scores[lang] = score / len(words)  # Normalize by word count
        
        if scores:
            return max(scores, key=scores.get)
        
        return 'en'  # Default to English if detection fails
        
    except Exception:
        return 'en'  # Default to English

# Translation function with proper language detection
def translate_text(text, target_lang, source_lang=None):
    """
    Translate text to desired language using Microsoft Translator
    
    Args:
        text (str): Text to translate
        target_lang (str): Target language code (e.g., 'es', 'fr', 'de', 'hi', 'zh')
        source_lang (str): Source language code (if None, will auto-detect)
    
    Returns:
        str: Translated text or original text if translation fails
    """
    try:
        # Skip translation if target language is English and source appears to be English
        if target_lang.lower() == 'en':
            return text
        
        # Detect source language if not provided
        if source_lang is None or source_lang == 'auto':
            source_lang = detect_language(text)
        
        # Skip translation if source and target are the same
        if source_lang.lower() == target_lang.lower():
            return text
            
        # Create translator instance with detected/specified source language
        translator = Translator(to_lang=target_lang, from_lang=source_lang)
        translated = translator.translate(text)
        
        # Return translated text if successful
        if translated and translated.strip():
            return translated
        else:
            return text  # Return original if translation is empty
            
    except Exception as e:
        print(f"Translation error: {str(e)}")
        # Try fallback translation with English as source
        try:
            fallback_translator = Translator(to_lang=target_lang, from_lang='en')
            fallback_result = fallback_translator.translate(text)
            if fallback_result and fallback_result.strip():
                return fallback_result
        except:
            pass
        return text  # Return original text if all translation attempts fail

# Language code mapping for common languages
LANGUAGE_CODES = {
    'english': 'en',
    'spanish': 'es',
    'french': 'fr',
    'german': 'de',
    'italian': 'it',
    'portuguese': 'pt',
    'russian': 'ru',
    'chinese': 'zh',
    'japanese': 'ja',
    'korean': 'ko',
    'arabic': 'ar',
    'hindi': 'hi',
    'dutch': 'nl',
    'swedish': 'sv',
    'norwegian': 'no',
    'danish': 'da',
    'finnish': 'fi',
    'polish': 'pl',
    'czech': 'cs',
    'hungarian': 'hu',
    'romanian': 'ro',
    'turkish': 'tr',
    'greek': 'el',
    'hebrew': 'he',
    'thai': 'th',
    'vietnamese': 'vi',
    'indonesian': 'id',
    'malay': 'ms'
}

@app.route("/", methods=["GET"])
def home():
    return render_template("index.html")

@app.route("/chat", methods=["POST"])
def chat():
    try:
        data = request.get_json()
        user_message = data.get("message")
        target_lang = data.get("lang", "en")

        if not user_message:
            return jsonify({"error": "Message is required"}), 400

        # Normalize language code (handle full language names)
        target_lang = target_lang.lower()
        if target_lang in LANGUAGE_CODES:
            target_lang = LANGUAGE_CODES[target_lang]

        # Translate user message to English for processing if it's not in English
        processed_message = user_message
        if target_lang != "en":
            try:
                # Detect source language of user message
                detected_source = detect_language(user_message)
                print(f"Detected user language: {detected_source}")
                
                # Translate to English only if source is not English
                if detected_source != 'en':
                    english_translator = Translator(to_lang='en', from_lang=detected_source)
                    processed_message = english_translator.translate(user_message)
                    if not processed_message or not processed_message.strip():
                        processed_message = user_message  # Fallback to original
                    print(f"Translated user message to English: {processed_message}")
            except Exception as e:
                print(f"User message translation error: {str(e)}")
                processed_message = user_message  # Use original message

        messages = [
            {"role": "system", "content": SYSTEM_INSTRUCTION},
            {"role": "user", "content": f"Context Data:\n{CONTEXT_DATA}\n\nUser Query: {processed_message}"}
        ]

        # Call OpenAI (or OpenAI-compatible) chat API
        response = client.chat.completions.create(
            model=OPENAI_MODEL,
            messages=messages,
            temperature=0.7
        )
        ai_response = response.choices[0].message.content.strip()

        # Translate AI response to target language if not English
        if target_lang.lower() != "en":
            ai_response = translate_text(ai_response, target_lang)

        return jsonify({"response": ai_response})
        
    except Exception as e:
        error_message = f"Error: {str(e)}"
        # Try to translate error message if target language is specified
        if 'target_lang' in locals() and target_lang.lower() != "en":
            try:
                error_message = translate_text(error_message, target_lang)
            except:
                pass  # Use original error message if translation fails
        
        return jsonify({"error": error_message}), 500

@app.route("/languages", methods=["GET"])
def get_languages():
    """Endpoint to get available language codes"""
    return jsonify({"languages": LANGUAGE_CODES})

@app.route("/translate", methods=["POST"])
def translate_endpoint():
    """Standalone translation endpoint"""
    try:
        data = request.get_json()
        text = data.get("text")
        target_lang = data.get("target_lang", "en")
        source_lang = data.get("source_lang")  # Remove default 'auto'
        
        if not text:
            return jsonify({"error": "Text is required"}), 400
            
        # Normalize language code
        target_lang = target_lang.lower()
        if target_lang in LANGUAGE_CODES:
            target_lang = LANGUAGE_CODES[target_lang]
        
        # Auto-detect source language if not provided
        if not source_lang or source_lang.lower() == 'auto':
            source_lang = detect_language(text)
            
        translated = translate_text(text, target_lang, source_lang)
        
        return jsonify({
            "original_text": text,
            "translated_text": translated,
            "detected_source_lang": source_lang,
            "target_lang": target_lang
        })
        
    except Exception as e:
        return jsonify({"error": str(e)}), 500

if __name__ == '__main__':
    print("Starting Flask app with translation support...")
    print("Available language codes:", list(LANGUAGE_CODES.keys()))
    print("Install dependencies: pip install translate")
    app.run(debug=True, host='0.0.0.0', port=7860, threaded=True)