Spaces:
Sleeping
Sleeping
| import os | |
| import json | |
| from groq import Groq | |
| from openai import OpenAI | |
| # Load environment variables only if .env file exists (local development) | |
| try: | |
| from dotenv import load_dotenv | |
| load_dotenv() | |
| except ImportError: | |
| # dotenv not needed in production (Hugging Face Spaces) | |
| pass | |
| # Initialize Groq client | |
| # Security Note: API Key is loaded from environment variable GROQ_API_KEY | |
| # In Hugging Face Spaces, this will be loaded from Repository Secrets | |
| # client = Groq( | |
| # api_key=os.environ.get("GROQ_API_KEY"), | |
| # ) | |
| MODEL_NAME = "llama-3.3-70b-versatile" | |
| GLM_MODEL_NAME = "glm-4.7" | |
| GLM_BASE_URL = "https://api.z.ai/api/coding/paas/v4" | |
| SYSTEM_PROMPT = """ | |
| You are an expert English language tutor for Spanish speakers. Your task is to analyze user's English input and provide a "mirror" response that includes: | |
| 1. **Grammatical Error Correction (GEC)**: Correct any morphosyntactic, lexical, or spelling errors. | |
| 2. **Reverse Translation**: Translate the *corrected* English text back into Spanish to verify the semantic intention. | |
| 3. **Pedagogical Explanation**: Explain the grammatical rules violated in Spanish. | |
| Output valid JSON strictly following this schema: | |
| { | |
| "corrected_text": "Complete corrected English text", | |
| "spanish_translation": "Spanish translation of the corrected text", | |
| "errors": [ | |
| { | |
| "original": "Error word/phrase", | |
| "correction": "Correction", | |
| "explanation": "Brief explanation in Spanish", | |
| "type": "Grammar/Spelling/Style" | |
| } | |
| ], | |
| "general_feedback": "Short motivational message in Spanish" | |
| } | |
| If there are no errors, the "errors" list should be empty, and "corrected_text" should be the same as the input. | |
| Do not include any text outside of JSON object. | |
| """ | |
| def analyze_text_glm(input_text: str, api_key: str) -> dict: | |
| """ | |
| Analyzes the input English text using GLM-4.7 API and returns a structured response. | |
| Args: | |
| input_text (str): The English text to analyze. | |
| api_key (str): The GLM API key to use. | |
| Returns: | |
| dict: The structured analysis result. | |
| """ | |
| if not input_text.strip(): | |
| return { | |
| "corrected_text": "", | |
| "spanish_translation": "", | |
| "errors": [], | |
| "general_feedback": "Por favor, ingresa un texto para analizar.", | |
| } | |
| if not api_key: | |
| return { | |
| "corrected_text": input_text, | |
| "spanish_translation": "Error de configuraci贸n", | |
| "errors": [], | |
| "general_feedback": "No se proporcion贸 una API Key v谩lida.", | |
| } | |
| try: | |
| client = OpenAI(api_key=api_key, base_url=GLM_BASE_URL) | |
| response = client.chat.completions.create( | |
| model=GLM_MODEL_NAME, | |
| messages=[ | |
| {"role": "system", "content": SYSTEM_PROMPT}, | |
| {"role": "user", "content": input_text}, | |
| ], | |
| temperature=0, | |
| ) | |
| content = response.choices[0].message.content | |
| # Log raw response for debugging | |
| raw_response = content | |
| if not raw_response.strip(): | |
| return { | |
| "corrected_text": input_text, | |
| "spanish_translation": "Error al procesar", | |
| "errors": [], | |
| "general_feedback": f"Ocurri贸 un error: GLM devolvi贸 una respuesta vac铆a o con solo espacios. Longitud: {len(raw_response)} caracteres. Respuesta cruda: '{raw_response}'", | |
| } | |
| # Clean markdown code blocks from response | |
| cleaned_response = raw_response.strip() | |
| # Remove ```json and ``` if present | |
| if cleaned_response.startswith("```json"): | |
| cleaned_response = cleaned_response[7:] # Remove ```json | |
| if cleaned_response.startswith("```"): | |
| cleaned_response = cleaned_response[3:] # Remove ``` | |
| if cleaned_response.endswith("```"): | |
| cleaned_response = cleaned_response[:-3] # Remove trailing ``` | |
| # Remove any system messages or content after JSON | |
| # Find closing brace of the JSON object | |
| try: | |
| json_end = cleaned_response.rfind("}") + 1 | |
| if json_end > 0: | |
| cleaned_response = cleaned_response[:json_end] | |
| except: | |
| pass | |
| try: | |
| return json.loads(cleaned_response) | |
| except json.JSONDecodeError as json_error: | |
| # Return actual response content for debugging | |
| preview = ( | |
| cleaned_response[:500] | |
| if len(cleaned_response) > 500 | |
| else cleaned_response | |
| ) | |
| return { | |
| "corrected_text": input_text, | |
| "spanish_translation": "Error al procesar", | |
| "errors": [], | |
| "general_feedback": f"Error de JSON: {str(json_error)}. Respuesta cruda del modelo (primeros 500 caracteres): {preview}", | |
| } | |
| except Exception as e: | |
| return { | |
| "corrected_text": input_text, | |
| "spanish_translation": "Error al procesar", | |
| "errors": [], | |
| "general_feedback": f"Ocurri贸 un error al conectar con GLM: {str(e)}", | |
| } | |
| def analyze_text(input_text: str, api_key: str, provider: str = "groq") -> dict: | |
| """ | |
| Analyzes the input English text using the specified provider and returns a structured response. | |
| Args: | |
| input_text (str): The English text to analyze. | |
| api_key (str): The API key to use for the provider. | |
| provider (str): The provider to use - "groq" or "glm". Defaults to "groq". | |
| Returns: | |
| dict: The structured analysis result. | |
| """ | |
| if provider == "glm": | |
| return analyze_text_glm(input_text, api_key) | |
| # Default Groq provider logic | |
| if not input_text.strip(): | |
| return { | |
| "corrected_text": "", | |
| "spanish_translation": "", | |
| "errors": [], | |
| "general_feedback": "Por favor, ingresa un texto para analizar.", | |
| } | |
| if not api_key: | |
| return { | |
| "corrected_text": input_text, | |
| "spanish_translation": "Error de configuraci贸n", | |
| "errors": [], | |
| "general_feedback": "No se proporcion贸 una API Key v谩lida.", | |
| } | |
| try: | |
| client = Groq(api_key=api_key) | |
| completion = client.chat.completions.create( | |
| model=MODEL_NAME, | |
| messages=[ | |
| {"role": "system", "content": SYSTEM_PROMPT}, | |
| {"role": "user", "content": input_text}, | |
| ], | |
| temperature=0, | |
| response_format={"type": "json_object"}, | |
| ) | |
| response_content = completion.choices[0].message.content | |
| return json.loads(response_content) | |
| except Exception as e: | |
| # Fallback error handling | |
| return { | |
| "corrected_text": input_text, | |
| "spanish_translation": "Error al procesar", | |
| "errors": [], | |
| "general_feedback": f"Ocurri贸 un error al conectar con el asistente: {str(e)}", | |
| } | |
| if __name__ == "__main__": | |
| # Simple test | |
| test_text = "She dont like play football." | |
| print("Analyzing:", test_text) | |
| result = analyze_text(test_text) | |
| print(json.dumps(result, indent=2, ensure_ascii=False)) | |
| def validate_glm_api_key(api_key: str) -> bool: | |
| """ | |
| Validates the GLM API Key by making a simple request. | |
| """ | |
| if not api_key: | |
| return False | |
| try: | |
| client = OpenAI( | |
| model=GLM_MODEL_NAME, | |
| base_url=GLM_BASE_URL, | |
| api_key=api_key, | |
| temperature=0, | |
| max_tokens=1, | |
| ) | |
| client.chat.completions.create( | |
| model=GLM_MODEL_NAME, | |
| messages=[{"role": "user", "content": "test"}], | |
| temperature=0, | |
| ) | |
| return True | |
| except Exception: | |
| return False | |
| def validate_api_key(api_key: str) -> bool: | |
| """ | |
| Validates the Groq API Key by making a simple request (listing models). | |
| """ | |
| if not api_key: | |
| return False | |
| try: | |
| client = Groq(api_key=api_key) | |
| # Attempt to list models to verify the key | |
| client.models.list() | |
| return True | |
| except Exception: | |
| return False | |