Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -49,20 +49,18 @@ def tts_proxy():
|
|
| 49 |
if not text:
|
| 50 |
return jsonify({"error": "No text provided"}), 400
|
| 51 |
try:
|
| 52 |
-
tts = gTTS(text=text, lang='en', tld='co.uk')
|
| 53 |
mp3_fp = io.BytesIO()
|
| 54 |
tts.write_to_fp(mp3_fp)
|
| 55 |
mp3_fp.seek(0)
|
| 56 |
return send_file(mp3_fp, mimetype='audio/mpeg', as_attachment=True, download_name='audio.mp3')
|
| 57 |
except Exception as e:
|
| 58 |
-
print(f"Erro no gTTS: {e}")
|
| 59 |
return jsonify({"error": f"Failed to generate audio via gTTS: {e}"}), 500
|
| 60 |
|
| 61 |
|
| 62 |
# --- ROTA 2: ANÁLISE DE TEXTO (FLASHCARDS, ETC.) ---
|
| 63 |
@app.route('/explain-proxy', methods=['POST'])
|
| 64 |
def explain_proxy():
|
| 65 |
-
# ... (código existente sem alterações) ...
|
| 66 |
data = request.get_json()
|
| 67 |
model_provider, model_name = data.get('model', 'gemini:gemini-1.5-flash-latest').split(':', 1)
|
| 68 |
word, context = data.get('word', '').strip(), data.get('context', '')
|
|
@@ -91,9 +89,9 @@ def explain_proxy():
|
|
| 91 |
# --- ROTA 3: ANÁLISE DE IMAGEM ---
|
| 92 |
@app.route('/analyze-image', methods=['POST'])
|
| 93 |
def analyze_image():
|
| 94 |
-
# ... (código existente sem alterações) ...
|
| 95 |
if not genai_client: return jsonify({"error": "GEMINI_API_KEY not configured."}), 503
|
| 96 |
-
data
|
|
|
|
| 97 |
if not base64_image: return jsonify({"error": "No image data."}), 400
|
| 98 |
try:
|
| 99 |
image = Image.open(io.BytesIO(base64.b64decode(base64_image.split(',')[1])))
|
|
@@ -108,7 +106,6 @@ def analyze_image():
|
|
| 108 |
# --- ROTA 4: CHAT COM IA ---
|
| 109 |
@app.route('/chat-with-ai', methods=['POST'])
|
| 110 |
def chat_with_ai():
|
| 111 |
-
# ... (código existente sem alterações) ...
|
| 112 |
if not groq_client: return jsonify({"error": "GROQ_API_KEY not configured."}), 503
|
| 113 |
data = request.get_json()
|
| 114 |
history, user_message = data.get('history', []), data.get('message', '')
|
|
@@ -121,49 +118,51 @@ def chat_with_ai():
|
|
| 121 |
except Exception as e:
|
| 122 |
return jsonify({"error": f"AI chat failed: {e}"}), 500
|
| 123 |
|
| 124 |
-
# --- ROTA 5: ANÁLISE DE PRONÚNCIA
|
| 125 |
@app.route('/pronunciation-feedback', methods=['POST'])
|
| 126 |
def pronunciation_feedback():
|
| 127 |
-
if not groq_client:
|
| 128 |
-
return jsonify({"error": "GROQ_API_KEY not configured for pronunciation analysis."}), 503
|
| 129 |
-
|
| 130 |
data = request.get_json()
|
| 131 |
-
target_text = data.get('target_text')
|
| 132 |
-
user_text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 133 |
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 137 |
try:
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
messages = [
|
| 143 |
-
{"role": "system", "content": system_instruction},
|
| 144 |
-
{"role": "user", "content": user_prompt}
|
| 145 |
-
]
|
| 146 |
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
temperature=0.5
|
| 151 |
-
)
|
| 152 |
-
|
| 153 |
-
feedback = response.choices[0].message.content.strip()
|
| 154 |
-
return jsonify({"feedback": feedback})
|
| 155 |
|
| 156 |
except Exception as e:
|
| 157 |
-
|
| 158 |
-
return jsonify({"error": f"Pronunciation analysis failed: {e}"}), 500
|
| 159 |
|
| 160 |
# --- FUNÇÃO AUXILIAR E ROTA RAIZ ---
|
| 161 |
def get_ai_text_response(provider, model_name, system_instruction, user_prompt, json_schema=None):
|
| 162 |
-
# ... (código existente sem alterações) ...
|
| 163 |
if provider == 'gemini':
|
| 164 |
-
|
|
|
|
| 165 |
config = {"response_mime_type": "application/json", "response_schema": json_schema} if json_schema else None
|
| 166 |
-
|
|
|
|
| 167 |
return json.loads(response.text) if json_schema else response.text
|
| 168 |
elif provider == 'groq':
|
| 169 |
messages = [{"role": "system", "content": system_instruction}, {"role": "user", "content": user_prompt}]
|
|
@@ -177,4 +176,5 @@ def root():
|
|
| 177 |
return send_file('index.html')
|
| 178 |
|
| 179 |
if __name__ == '__main__':
|
| 180 |
-
app.run(host='0.0.0.0', port=7860)
|
|
|
|
|
|
| 49 |
if not text:
|
| 50 |
return jsonify({"error": "No text provided"}), 400
|
| 51 |
try:
|
| 52 |
+
tts = gTTS(text=text, lang='en', tld='co.uk')
|
| 53 |
mp3_fp = io.BytesIO()
|
| 54 |
tts.write_to_fp(mp3_fp)
|
| 55 |
mp3_fp.seek(0)
|
| 56 |
return send_file(mp3_fp, mimetype='audio/mpeg', as_attachment=True, download_name='audio.mp3')
|
| 57 |
except Exception as e:
|
|
|
|
| 58 |
return jsonify({"error": f"Failed to generate audio via gTTS: {e}"}), 500
|
| 59 |
|
| 60 |
|
| 61 |
# --- ROTA 2: ANÁLISE DE TEXTO (FLASHCARDS, ETC.) ---
|
| 62 |
@app.route('/explain-proxy', methods=['POST'])
|
| 63 |
def explain_proxy():
|
|
|
|
| 64 |
data = request.get_json()
|
| 65 |
model_provider, model_name = data.get('model', 'gemini:gemini-1.5-flash-latest').split(':', 1)
|
| 66 |
word, context = data.get('word', '').strip(), data.get('context', '')
|
|
|
|
| 89 |
# --- ROTA 3: ANÁLISE DE IMAGEM ---
|
| 90 |
@app.route('/analyze-image', methods=['POST'])
|
| 91 |
def analyze_image():
|
|
|
|
| 92 |
if not genai_client: return jsonify({"error": "GEMINI_API_KEY not configured."}), 503
|
| 93 |
+
data = request.get_json()
|
| 94 |
+
base64_image = data.get('image')
|
| 95 |
if not base64_image: return jsonify({"error": "No image data."}), 400
|
| 96 |
try:
|
| 97 |
image = Image.open(io.BytesIO(base64.b64decode(base64_image.split(',')[1])))
|
|
|
|
| 106 |
# --- ROTA 4: CHAT COM IA ---
|
| 107 |
@app.route('/chat-with-ai', methods=['POST'])
|
| 108 |
def chat_with_ai():
|
|
|
|
| 109 |
if not groq_client: return jsonify({"error": "GROQ_API_KEY not configured."}), 503
|
| 110 |
data = request.get_json()
|
| 111 |
history, user_message = data.get('history', []), data.get('message', '')
|
|
|
|
| 118 |
except Exception as e:
|
| 119 |
return jsonify({"error": f"AI chat failed: {e}"}), 500
|
| 120 |
|
| 121 |
+
# --- ROTA 5: ANÁLISE DE PRONÚNCIA ---
|
| 122 |
@app.route('/pronunciation-feedback', methods=['POST'])
|
| 123 |
def pronunciation_feedback():
|
| 124 |
+
if not groq_client: return jsonify({"error": "GROQ_API_KEY not configured for pronunciation analysis."}), 503
|
|
|
|
|
|
|
| 125 |
data = request.get_json()
|
| 126 |
+
target_text, user_text = data.get('target_text'), data.get('user_text')
|
| 127 |
+
if not target_text or not user_text: return jsonify({"error": "Target and user text are required."}), 400
|
| 128 |
+
try:
|
| 129 |
+
system_instruction = "You are an expert American English pronunciation coach. The user tried to say a target sentence, and their speech was transcribed. Based on the likely pronunciation differences, provide brief, friendly, and actionable feedback in Portuguese. Focus on 1-2 key points. If it's very close, praise the user."
|
| 130 |
+
user_prompt = f"Target: \"{target_text}\"\nTranscription: \"{user_text}\"\n\nProvide pronunciation feedback."
|
| 131 |
+
messages = [{"role": "system", "content": system_instruction}, {"role": "user", "content": user_prompt}]
|
| 132 |
+
response = groq_client.chat.completions.create(model="llama-3.1-8b-instant", messages=messages, temperature=0.5)
|
| 133 |
+
return jsonify({"feedback": response.choices[0].message.content.strip()})
|
| 134 |
+
except Exception as e:
|
| 135 |
+
return jsonify({"error": f"Pronunciation analysis failed: {e}"}), 500
|
| 136 |
|
| 137 |
+
# --- ROTA 6: GERAÇÃO DE IMAGEM (NOVO) ---
|
| 138 |
+
@app.route('/generate-image', methods=['POST'])
|
| 139 |
+
def generate_image():
|
| 140 |
+
if not genai_client:
|
| 141 |
+
return jsonify({"error": "GEMINI_API_KEY not configured for image generation."}), 503
|
| 142 |
+
data = request.get_json()
|
| 143 |
+
prompt = data.get('prompt')
|
| 144 |
+
if not prompt:
|
| 145 |
+
return jsonify({"error": "Image prompt is required."}), 400
|
| 146 |
try:
|
| 147 |
+
# Usa o modelo "Nano Banana"
|
| 148 |
+
model = genai_client.GenerativeModel(model_name='gemini-1.5-flash-image-preview')
|
| 149 |
+
response = model.generate_content(prompt)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 150 |
|
| 151 |
+
# A API retorna a imagem em base64 diretamente nos 'parts'
|
| 152 |
+
base64_image_data = response.parts[0].inline_data.data
|
| 153 |
+
return jsonify({"image_base64": base64_image_data})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 154 |
|
| 155 |
except Exception as e:
|
| 156 |
+
return jsonify({"error": f"Image generation failed: {e}"}), 500
|
|
|
|
| 157 |
|
| 158 |
# --- FUNÇÃO AUXILIAR E ROTA RAIZ ---
|
| 159 |
def get_ai_text_response(provider, model_name, system_instruction, user_prompt, json_schema=None):
|
|
|
|
| 160 |
if provider == 'gemini':
|
| 161 |
+
full_model_name = f'models/{model_name}'
|
| 162 |
+
model = genai_client.GenerativeModel(full_model_name, system_instruction=system_instruction)
|
| 163 |
config = {"response_mime_type": "application/json", "response_schema": json_schema} if json_schema else None
|
| 164 |
+
generation_config = genai.types.GenerationConfig(**config) if config else None
|
| 165 |
+
response = model.generate_content(user_prompt, generation_config=generation_config)
|
| 166 |
return json.loads(response.text) if json_schema else response.text
|
| 167 |
elif provider == 'groq':
|
| 168 |
messages = [{"role": "system", "content": system_instruction}, {"role": "user", "content": user_prompt}]
|
|
|
|
| 176 |
return send_file('index.html')
|
| 177 |
|
| 178 |
if __name__ == '__main__':
|
| 179 |
+
app.run(host='0.0.0.0', port=7860)
|
| 180 |
+
|