amauricunha commited on
Commit
d2083e1
·
verified ·
1 Parent(s): 31d7049

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +40 -127
app.py CHANGED
@@ -2,20 +2,14 @@
2
  import os
3
  import io
4
  import json
5
- import uuid
6
- import tempfile
7
- import requests
8
 
9
  from flask import Flask, request, jsonify, send_file
10
  from gtts import gTTS
11
- # Importa Groq e Google GenAI
12
  from groq import Groq
13
- from google import genai
14
- from google.genai import types
15
 
16
  # --- CONFIGURAÇÃO INICIAL ---
17
-
18
- # Inicializa o Flask
19
  app = Flask(__name__)
20
 
21
  # --- CONFIGURAÇÃO DAS APIS LLM ---
@@ -24,10 +18,8 @@ groq_client = None
24
 
25
  # 1. Configuração Gemini
26
  try:
27
- # Use os Secrets do Hugging Face para armazenar suas chaves
28
  GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY")
29
  if GEMINI_API_KEY:
30
- # Apenas inicializa o cliente se a chave existir
31
  genai.configure(api_key=GEMINI_API_KEY)
32
  genai_client = genai
33
  else:
@@ -49,98 +41,56 @@ except Exception as e:
49
 
50
 
51
  # --- ROTA 1: TEXT-TO-SPEECH (TTS) - USANDO gTTS GRATUITO ---
52
-
53
  @app.route('/tts-proxy', methods=['POST'])
54
  def tts_proxy():
55
- """
56
- Gera áudio MP3 a partir de texto usando a biblioteca gTTS (gratuita)
57
- e retorna o áudio como um arquivo.
58
- """
59
  data = request.get_json()
60
  text = data.get('text', '')
61
-
62
  if not text:
63
  return jsonify({"error": "No text provided"}), 400
64
-
65
  try:
66
- # Cria um objeto gTTS (sem controle de velocidade)
67
- tts = gTTS(text=text, lang='en', tld='us') # TLD 'us' para sotaque Americano
68
-
69
- # Salva o áudio em um buffer de bytes na memória
70
  mp3_fp = io.BytesIO()
71
  tts.write_to_fp(mp3_fp)
72
  mp3_fp.seek(0)
73
-
74
- # Retorna o arquivo de áudio MP3
75
- return send_file(
76
- mp3_fp,
77
- mimetype='audio/mpeg',
78
- as_attachment=True,
79
- download_name='audio.mp3'
80
- )
81
-
82
  except Exception as e:
83
  print(f"Erro no gTTS: {e}")
84
  return jsonify({"error": f"Failed to generate audio via gTTS: {e}"}), 500
85
 
86
 
87
  # --- ROTA 2: TRADUÇÃO RÁPIDA E CONTEXTO (IA) - USANDO GEMINI OU GROQ ---
88
-
89
  def get_ai_response(provider, model_name, system_instruction, user_prompt, json_schema=None):
90
- """Função auxiliar para rotear a requisição LLM para o provedor selecionado."""
91
-
92
  if provider == 'gemini':
93
  if not genai_client:
94
  raise Exception("Gemini client not initialized. GEMINI_API_KEY is missing.")
95
-
96
  model = genai_client.GenerativeModel(model_name)
97
 
98
- # Configuração para resposta JSON estruturada
99
  generation_config = None
100
  if json_schema:
101
- generation_config = genai.GenerationConfig(
102
- response_mime_type="application/json",
103
- response_schema=json_schema
104
- )
105
 
106
- response = model.generate_content(
107
- user_prompt,
108
- generation_config=generation_config
109
- )
110
 
111
  if json_schema:
112
- if response.candidates and response.candidates[0].content and response.candidates[0].content.parts:
113
- json_text = response.candidates[0].content.parts[0].text.strip()
114
- return json.loads(json_text)
115
- else:
116
- raise Exception("Gemini returned empty or invalid JSON content.")
117
  else:
118
  return response.text.strip()
119
 
120
  elif provider == 'groq':
121
  if not groq_client:
122
  raise Exception("Groq client not initialized. GROQ_API_KEY is missing.")
123
-
124
- messages = [
125
- {"role": "system", "content": system_instruction},
126
- {"role": "user", "content": user_prompt}
127
- ]
128
-
129
  config_params = {}
130
  if json_schema:
131
  config_params['response_format'] = {"type": "json_object"}
132
-
133
- response = groq_client.chat.completions.create(
134
- model=model_name,
135
- messages=messages,
136
- **config_params
137
- )
138
  text_response = response.choices[0].message.content.strip()
139
-
140
- if json_schema:
141
- return json.loads(text_response)
142
- else:
143
- return text_response
144
 
145
  else:
146
  raise Exception(f"Unsupported provider: {provider}")
@@ -156,79 +106,42 @@ def explain_proxy():
156
  context_focus = data.get('context_focus', 'General/Social')
157
  custom_prompt = data.get('custom_prompt', None)
158
 
159
- if model_provider == 'gemini' and not genai_client:
160
- return jsonify({"error": "GEMINI_API_KEY not configured."}), 503
161
- if model_provider == 'groq' and not groq_client:
162
- return jsonify({"error": "GROQ_API_KEY not configured."}), 503
163
 
164
  system_instruction_base = f"You are a professional English tutor focused on the context '{context_focus}'. All responses must be accurate and relevant to language learning."
165
 
166
- if custom_prompt:
167
- try:
168
- text_response = get_ai_response(
169
- model_provider, model_name,
170
- system_instruction=system_instruction_base,
171
- user_prompt=custom_prompt,
172
- json_schema=None
173
- )
174
- return jsonify({
175
- "explanation": text_response,
176
- "translation": "Activity Generated."
177
- })
178
- except Exception as e:
179
- print(f"Erro na geração de atividade: {e}")
180
- return jsonify({"error": f"AI activity generation failed: {e}"}), 500
181
-
182
- if not word:
183
- return jsonify({"error": "No word or phrase selected."}), 400
184
-
185
- # Schema JSON aprimorado para o Flashcard Inteligente
186
- flashcard_schema = {
187
- "type": "object",
188
- "properties": {
189
- "term": {"type": "string", "description": "The selected English word or phrase."},
190
- "translation": {"type": "string", "description": "The accurate Portuguese translation to be used as a hint."},
191
- "context_sentence": {"type": "string", "description": "The original, complete English sentence from the context."},
192
- "gapped_sentence": {"type": "string", "description": "The context sentence with the term replaced by '______________'."},
193
- "definition": {"type": "string", "description": "A concise, clear English definition of the term."},
194
- },
195
- "required": ["term", "translation", "context_sentence", "gapped_sentence", "definition"]
196
- }
197
-
198
  try:
 
 
 
 
 
 
 
199
  if for_flashcard:
200
- # Prompt detalhado para gerar o flashcard
 
 
 
 
 
 
 
 
201
  system_instruction = system_instruction_base + " Your task is to generate a JSON object for an 'intelligent flashcard'."
202
- user_prompt = f"""
203
- Analyze the term '{word}' found in the following sentence: '{context}'.
204
- Based on this, generate a JSON object that follows the required schema.
205
- - 'term' should be the exact word/phrase '{word}'.
206
- - 'translation' must be its most accurate Portuguese translation in this context.
207
- - 'context_sentence' is the full original sentence.
208
- - 'gapped_sentence' is the original sentence, but replacing '{word}' with '______________'.
209
- - 'definition' is a clear, single-sentence definition in English.
210
- """
211
-
212
- card_data = get_ai_response(
213
- model_provider, model_name,
214
- system_instruction, user_prompt,
215
- json_schema=flashcard_schema
216
- )
217
  return jsonify(card_data)
218
 
219
- else: # Requisição para o Modal (Clique Duplo)
220
  system_instruction = system_instruction_base
221
- user_prompt = f"Analyze the term '{word}' in context: '{context}'. Provide a clear, one-sentence English explanation, followed by its Portuguese translation, separated by '---'."
222
-
223
- text_response = get_ai_response(
224
- model_provider, model_name,
225
- system_instruction, user_prompt,
226
- json_schema=None
227
- )
228
  parts = text_response.split('---', 1)
229
  explanation = parts[0].strip()
230
  translation = parts[1].strip() if len(parts) > 1 else 'Tradução não disponível.'
231
-
232
  return jsonify({"explanation": explanation, "translation": translation})
233
 
234
  except Exception as e:
@@ -236,10 +149,10 @@ def explain_proxy():
236
  return jsonify({"error": f"AI analysis failed: {e}"}), 500
237
 
238
  # --- ROTA DE INICIALIZAÇÃO E ARQUIVOS ESTÁTICOS ---
239
-
240
  @app.route('/')
241
  def root():
242
  return send_file('index.html')
243
 
244
  if __name__ == '__main__':
245
  app.run(host='0.0.0.0', port=7860)
 
 
2
  import os
3
  import io
4
  import json
 
 
 
5
 
6
  from flask import Flask, request, jsonify, send_file
7
  from gtts import gTTS
 
8
  from groq import Groq
9
+ # CORREÇÃO: A importação correta para a biblioteca do Google Generative AI
10
+ import google.generativeai as genai
11
 
12
  # --- CONFIGURAÇÃO INICIAL ---
 
 
13
  app = Flask(__name__)
14
 
15
  # --- CONFIGURAÇÃO DAS APIS LLM ---
 
18
 
19
  # 1. Configuração Gemini
20
  try:
 
21
  GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY")
22
  if GEMINI_API_KEY:
 
23
  genai.configure(api_key=GEMINI_API_KEY)
24
  genai_client = genai
25
  else:
 
41
 
42
 
43
  # --- ROTA 1: TEXT-TO-SPEECH (TTS) - USANDO gTTS GRATUITO ---
 
44
  @app.route('/tts-proxy', methods=['POST'])
45
  def tts_proxy():
 
 
 
 
46
  data = request.get_json()
47
  text = data.get('text', '')
 
48
  if not text:
49
  return jsonify({"error": "No text provided"}), 400
 
50
  try:
51
+ tts = gTTS(text=text, lang='en', tld='us')
 
 
 
52
  mp3_fp = io.BytesIO()
53
  tts.write_to_fp(mp3_fp)
54
  mp3_fp.seek(0)
55
+ return send_file(mp3_fp, mimetype='audio/mpeg', as_attachment=True, download_name='audio.mp3')
 
 
 
 
 
 
 
 
56
  except Exception as e:
57
  print(f"Erro no gTTS: {e}")
58
  return jsonify({"error": f"Failed to generate audio via gTTS: {e}"}), 500
59
 
60
 
61
  # --- ROTA 2: TRADUÇÃO RÁPIDA E CONTEXTO (IA) - USANDO GEMINI OU GROQ ---
 
62
  def get_ai_response(provider, model_name, system_instruction, user_prompt, json_schema=None):
 
 
63
  if provider == 'gemini':
64
  if not genai_client:
65
  raise Exception("Gemini client not initialized. GEMINI_API_KEY is missing.")
 
66
  model = genai_client.GenerativeModel(model_name)
67
 
68
+ # CORREÇÃO: A configuração de geração para JSON agora é um dicionário simples
69
  generation_config = None
70
  if json_schema:
71
+ generation_config = {
72
+ "response_mime_type": "application/json",
73
+ "response_schema": json_schema
74
+ }
75
 
76
+ response = model.generate_content(user_prompt, generation_config=generation_config)
 
 
 
77
 
78
  if json_schema:
79
+ json_text = response.candidates[0].content.parts[0].text.strip()
80
+ return json.loads(json_text)
 
 
 
81
  else:
82
  return response.text.strip()
83
 
84
  elif provider == 'groq':
85
  if not groq_client:
86
  raise Exception("Groq client not initialized. GROQ_API_KEY is missing.")
87
+ messages = [{"role": "system", "content": system_instruction}, {"role": "user", "content": user_prompt}]
 
 
 
 
 
88
  config_params = {}
89
  if json_schema:
90
  config_params['response_format'] = {"type": "json_object"}
91
+ response = groq_client.chat.completions.create(model=model_name, messages=messages, **config_params)
 
 
 
 
 
92
  text_response = response.choices[0].message.content.strip()
93
+ return json.loads(text_response) if json_schema else text_response
 
 
 
 
94
 
95
  else:
96
  raise Exception(f"Unsupported provider: {provider}")
 
106
  context_focus = data.get('context_focus', 'General/Social')
107
  custom_prompt = data.get('custom_prompt', None)
108
 
109
+ if (model_provider == 'gemini' and not genai_client) or \
110
+ (model_provider == 'groq' and not groq_client):
111
+ return jsonify({"error": f"{model_provider.upper()}_API_KEY not configured."}), 503
 
112
 
113
  system_instruction_base = f"You are a professional English tutor focused on the context '{context_focus}'. All responses must be accurate and relevant to language learning."
114
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
  try:
116
+ if custom_prompt:
117
+ text_response = get_ai_response(model_provider, model_name, system_instruction_base, custom_prompt)
118
+ return jsonify({"explanation": text_response, "translation": "Activity Generated."})
119
+
120
+ if not word:
121
+ return jsonify({"error": "No word or phrase selected."}), 400
122
+
123
  if for_flashcard:
124
+ flashcard_schema = {
125
+ "type": "object",
126
+ "properties": {
127
+ "term": {"type": "string"}, "translation": {"type": "string"},
128
+ "context_sentence": {"type": "string"}, "gapped_sentence": {"type": "string"},
129
+ "definition": {"type": "string"},
130
+ },
131
+ "required": ["term", "translation", "context_sentence", "gapped_sentence", "definition"]
132
+ }
133
  system_instruction = system_instruction_base + " Your task is to generate a JSON object for an 'intelligent flashcard'."
134
+ user_prompt = f"Analyze the term '{word}' in the sentence: '{context}'. Generate a JSON object following the schema. The 'gapped_sentence' must replace '{word}' with '______________'."
135
+ card_data = get_ai_response(model_provider, model_name, system_instruction, user_prompt, json_schema=flashcard_schema)
 
 
 
 
 
 
 
 
 
 
 
 
 
136
  return jsonify(card_data)
137
 
138
+ else:
139
  system_instruction = system_instruction_base
140
+ user_prompt = f"Analyze '{word}' in context: '{context}'. Provide a one-sentence English explanation, then '---', then the Portuguese translation."
141
+ text_response = get_ai_response(model_provider, model_name, system_instruction, user_prompt)
 
 
 
 
 
142
  parts = text_response.split('---', 1)
143
  explanation = parts[0].strip()
144
  translation = parts[1].strip() if len(parts) > 1 else 'Tradução não disponível.'
 
145
  return jsonify({"explanation": explanation, "translation": translation})
146
 
147
  except Exception as e:
 
149
  return jsonify({"error": f"AI analysis failed: {e}"}), 500
150
 
151
  # --- ROTA DE INICIALIZAÇÃO E ARQUIVOS ESTÁTICOS ---
 
152
  @app.route('/')
153
  def root():
154
  return send_file('index.html')
155
 
156
  if __name__ == '__main__':
157
  app.run(host='0.0.0.0', port=7860)
158
+