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)