mramirez2001 commited on
Commit
b4d513c
·
verified ·
1 Parent(s): dea71a5

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +67 -71
app.py CHANGED
@@ -4,73 +4,65 @@ import gradio as gr
4
  import os
5
  from openai import OpenAI
6
  import json
 
7
 
8
  # --- 1. Configurar el Cliente de OpenAI ---
9
- # La clave de API se cargará de forma segura desde los "Secrets" de Hugging Face
10
  try:
11
  client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
12
  api_key_found = True
13
  except TypeError:
14
  api_key_found = False
15
 
16
- # --- 2. El Prompt: El Cerebro de la Operación ---
17
- # Este prompt le dice a GPT-4o cómo actuar y qué analizar.
18
  SYSTEM_PROMPT = """
19
- Eres un experto evaluador de inglés como segundo idioma (ESL) con un doctorado en fonética.
20
- Tu tarea es analizar un audio, la transcripción del usuario y la transcripción generada por Whisper.
21
- Debes calificar la pronunciación general en una escala de 0 a 100.
22
- Tu análisis debe ser profundo, considerando:
23
- 1. **Precisión (Accuracy):** Compara la transcripción del usuario con la de Whisper para detectar palabras omitidas o incorrectas.
24
- 2. **Fluidez (Fluency):** Analiza el ritmo, la cadencia y la presencia de pausas o muletillas (uh, um).
25
- 3. **Prosodia (Prosody):** Evalúa la entonación y el acento de la frase. ¿Suena natural o monótono?
26
 
27
- Devuelve tu análisis únicamente en un formato JSON estricto con la siguiente estructura:
 
 
 
 
 
28
  {
29
  "calificacion_general_100": integer,
30
- "nivel_mcerl_estimado": "string (ej. A2)",
31
- "analisis_fluidez": "string (un párrafo corto)",
32
- "analisis_precision": "string (un párrafo corto)",
33
- "palabras_a_mejorar": [
34
- {"palabra": "string", "error_detectado": "string (ej. pronunciado como '...')" }
 
 
 
 
35
  ]
36
  }
37
  """
38
 
39
- # --- 3. La Función Principal que se Conecta a Gradio ---
40
  def evaluate_pronunciation_openai(audio_input, user_transcript):
41
- """
42
- Toma un audio y un texto, los envía a la API de OpenAI y formatea la respuesta.
43
- """
44
  if not api_key_found:
45
- raise gr.Error("Clave de API de OpenAI no encontrada. Asegúrate de configurarla en los 'Secrets' de tu Space.")
46
 
47
  if audio_input is None or not user_transcript:
48
- return 0, "N/A", "N/A", "N/A", [("Por favor, proporciona un audio y una transcripción.", None)]
 
49
 
50
- sr, waveform = audio_input # Gradio nos da el audio
51
-
52
- # Guardar temporalmente el audio para enviarlo a la API
53
  temp_audio_path = "temp_audio.wav"
54
- import soundfile as sf
55
  sf.write(temp_audio_path, waveform, sr)
56
 
57
- # 1. Transcribir el audio con la API de Whisper de OpenAI
58
- print("Transcribiendo audio con Whisper API...")
59
  with open(temp_audio_path, "rb") as audio_file:
60
- ai_transcript = client.audio.transcriptions.create(
61
- model="whisper-1",
62
- file=audio_file
63
- ).text
64
 
65
- # 2. Construir el prompt final para el modelo de lenguaje
66
  user_prompt = f"""
67
- Evalúa el audio proporcionado.
68
- Transcripción del usuario: "{user_transcript}"
69
- Transcripción generada por la IA (Whisper): "{ai_transcript}"
70
  """
71
 
72
- # 3. Llamar a la API de Chat (GPT-4o) para la evaluación
73
- print("Enviando a GPT-4o para evaluación...")
74
  response = client.chat.completions.create(
75
  model="gpt-4o",
76
  response_format={"type": "json_object"},
@@ -80,58 +72,62 @@ def evaluate_pronunciation_openai(audio_input, user_transcript):
80
  ]
81
  )
82
 
83
- # 4. Procesar y formatear la respuesta JSON
84
  try:
85
  result = json.loads(response.choices[0].message.content)
86
- score = result.get("calificacion_general_100", 0)
87
- level = result.get("nivel_mcerl_estimado", "N/A")
88
- fluency = result.get("analisis_fluidez", "")
89
- accuracy = result.get("analisis_precision", "")
90
 
91
- highlighted_feedback = []
92
- # Crear retroalimentación visual a partir de la transcripción de la IA
93
- words_to_improve = {item['palabra'].upper() for item in result.get("palabras_a_mejorar", [])}
94
- for word in ai_transcript.split():
95
- if word.upper().strip(".,?!") in words_to_improve:
96
- highlighted_feedback.append((word, "Mejorar"))
97
- else:
98
- highlighted_feedback.append(word)
 
 
 
 
 
 
 
 
 
 
99
 
100
- return score, level, fluency, accuracy, highlighted_feedback
101
  except (json.JSONDecodeError, KeyError) as e:
102
- print(f"Error al parsear la respuesta de la API: {e}")
103
- return 0, "Error", "Error", "Error", [("La respuesta de la API no tuvo el formato esperado.", None)]
 
104
 
105
 
106
- # --- 5. Definir y Lanzar la Interfaz de Gradio (Versión Corregida) ---
107
  description = """
108
- Sube un audio y escribe la transcripción. La IA de OpenAI (Whisper + GPT-4o)
109
- analizará tu pronunciación, fluidez y prosodia para darte una calificación completa
110
- y una retroalimentación detallada.
111
  """
112
 
 
 
 
 
 
113
  demo = gr.Interface(
114
  fn=evaluate_pronunciation_openai,
115
  inputs=[
116
  gr.Audio(type="numpy", label="Sube tu Audio (.wav o .mp3)"),
117
- gr.Textbox(lines=5, label="Escribe la Transcripción Aquí")
118
  ],
119
  outputs=[
120
  gr.Number(label="Calificación General (0-100)"),
121
- gr.Textbox(label="Nivel MCERL Estimado"),
122
- gr.Textbox(label="Análisis de Fluidez"),
123
- gr.Textbox(label="Análisis de Precisión"),
124
- gr.HighlightedText(
125
- label="Retroalimentación por Palabra",
126
- color_map={"Mejorar": "yellow"}
127
- )
128
  ],
129
- title="🤖 Evaluador de Pronunciación con OpenAI API",
130
  description=description,
131
- # --- AJUSTE CLAVE ---
132
- # Asegúrate de que 'audio_ejemplo.mp3' es el nombre exacto
133
- # del archivo que subiste a tu Space.
134
- examples=[["mark_is_going_to_see_elephant.wav", "MARK IS GOING TO SEE ELEPHANT"]]
135
  )
136
 
137
  if __name__ == "__main__":
 
4
  import os
5
  from openai import OpenAI
6
  import json
7
+ import soundfile as sf
8
 
9
  # --- 1. Configurar el Cliente de OpenAI ---
 
10
  try:
11
  client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
12
  api_key_found = True
13
  except TypeError:
14
  api_key_found = False
15
 
16
+ # --- 2. El NUEVO Prompt: Más Técnico y Preciso ---
 
17
  SYSTEM_PROMPT = """
18
+ Eres un lingüista computacional y experto en fonética inglesa, especializado en la evaluación de acentos para hablantes de inglés como segundo idioma (ESL).
19
+ Tu tarea es realizar un análisis fonético detallado de un audio, comparando la pronunciación del hablante con un modelo de Inglés Americano General (General American English).
 
 
 
 
 
20
 
21
+ Debes basar tu análisis en estos tres pilares:
22
+ 1. **Precisión Fonética (Phonetic Accuracy):** Compara la transcripción de Whisper con la transcripción de referencia. Para cada palabra, analiza si los fonemas clave fueron producidos correctamente.
23
+ 2. **Prosodia (Prosody):** Evalúa el ritmo, la entonación y el acento de la frase. ¿La entonación sube y baja de forma natural? ¿Se acentúan las palabras correctas?
24
+ 3. **Vinculación (Linking/Liaison):** Observa si el hablante conecta las palabras de manera fluida (ej. "is a" suena como /ɪzə/).
25
+
26
+ Tu respuesta DEBE ser un objeto JSON válido, sin texto adicional antes o después. La estructura es la siguiente:
27
  {
28
  "calificacion_general_100": integer,
29
+ "calificacion_precision_fonetica_100": integer,
30
+ "analisis_general": "string (Un resumen de dos o tres líneas sobre los puntos fuertes y las áreas de mejora principales del hablante.)",
31
+ "feedback_fonetico_por_palabra": [
32
+ {
33
+ "palabra": "string",
34
+ "ipa_correcta": "string (La transcripción fonética correcta en IPA, ej. /ˈreɪn.boʊ/)",
35
+ "error_detectado": "string (Describe el error fonético, ej. 'La vocal /eɪ/ se pronunció como /e/ de forma monoptonga.')",
36
+ "sugerencia": "string (Un consejo práctico para corregirlo, ej. 'Asegúrate de deslizar la lengua de la posición de 'e' a la de 'i' para crear el diptongo.')"
37
+ }
38
  ]
39
  }
40
  """
41
 
42
+ # --- 3. La Función Principal (Actualizada para el nuevo JSON) ---
43
  def evaluate_pronunciation_openai(audio_input, user_transcript):
 
 
 
44
  if not api_key_found:
45
+ raise gr.Error("Clave de API de OpenAI no encontrada.")
46
 
47
  if audio_input is None or not user_transcript:
48
+ # Devuelve valores por defecto para todos los outputs
49
+ return 0, 0, "Por favor, proporciona un audio y una transcripción.", "### Retroalimentación Detallada\nEsperando análisis..."
50
 
51
+ sr, waveform = audio_input
 
 
52
  temp_audio_path = "temp_audio.wav"
 
53
  sf.write(temp_audio_path, waveform, sr)
54
 
55
+ print("Transcribiendo audio...")
 
56
  with open(temp_audio_path, "rb") as audio_file:
57
+ ai_transcript = client.audio.transcriptions.create(model="whisper-1", file=audio_file).text
 
 
 
58
 
 
59
  user_prompt = f"""
60
+ Realiza el análisis fonético del audio proporcionado.
61
+ Frase de referencia (lo que el usuario intentaba decir): "{user_transcript}"
62
+ Transcripción generada por Whisper (lo que realmente se dijo): "{ai_transcript}"
63
  """
64
 
65
+ print("Enviando a GPT-4o para evaluación fonética...")
 
66
  response = client.chat.completions.create(
67
  model="gpt-4o",
68
  response_format={"type": "json_object"},
 
72
  ]
73
  )
74
 
 
75
  try:
76
  result = json.loads(response.choices[0].message.content)
 
 
 
 
77
 
78
+ # Extraer datos del nuevo formato JSON
79
+ score_general = result.get("calificacion_general_100", 0)
80
+ score_phonetics = result.get("calificacion_precision_fonetica_100", 0)
81
+ analysis = result.get("analisis_general", "No se proporcionó análisis.")
82
+ feedback_list = result.get("feedback_fonetico_por_palabra", [])
83
+
84
+ # Formatear el feedback detallado como Markdown para una mejor visualización
85
+ markdown_feedback = "### Retroalimentación Fonética Detallada\n---\n"
86
+ if not feedback_list:
87
+ markdown_feedback += "¡Excelente pronunciación! No se detectaron errores específicos."
88
+ else:
89
+ for item in feedback_list:
90
+ markdown_feedback += f"**Palabra:** `{item.get('palabra', 'N/A')}`\n"
91
+ markdown_feedback += f"- **IPA Correcta:** `{item.get('ipa_correcta', 'N/A')}`\n"
92
+ markdown_feedback += f"- **Error Detectado:** {item.get('error_detectado', 'N/A')}\n"
93
+ markdown_feedback += f"- **Sugerencia:** {item.get('sugerencia', 'N/A')}\n\n"
94
+
95
+ return score_general, score_phonetics, analysis, markdown_feedback
96
 
 
97
  except (json.JSONDecodeError, KeyError) as e:
98
+ print(f"Error al procesar la respuesta de la API: {e}")
99
+ error_message = "La respuesta de la API no tuvo el formato JSON esperado. Inténtalo de nuevo."
100
+ return 0, 0, error_message, f"### Error\n---\n{error_message}"
101
 
102
 
103
+ # --- 4. Definir y Lanzar la Interfaz de Gradio (Actualizada) ---
104
  description = """
105
+ Usa la frase estándar para una evaluación completa o prueba con tus propias frases.
106
+ Sube tu audio y la transcripción. La IA analizará tu pronunciación fonema por fonema.
 
107
  """
108
 
109
+ # IMPORTANTE: Graba un audio diciendo la frase de ejemplo y guárdalo
110
+ # con este nombre en la misma carpeta que tu app.py
111
+ audio_ejemplo_path = "mark_is_going_to_see_elephant.wav"
112
+ frase_ejemplo_texto = "MARK IS GOING TO SEE ELEPHANT"
113
+
114
  demo = gr.Interface(
115
  fn=evaluate_pronunciation_openai,
116
  inputs=[
117
  gr.Audio(type="numpy", label="Sube tu Audio (.wav o .mp3)"),
118
+ gr.Textbox(lines=3, label="Escribe la Transcripción de Referencia", value=frase_ejemplo_texto)
119
  ],
120
  outputs=[
121
  gr.Number(label="Calificación General (0-100)"),
122
+ gr.Number(label="Precisión Fonética (0-100)"),
123
+ gr.Textbox(label="Análisis General"),
124
+ gr.Markdown(label="Feedback Detallado por Palabra") # CAMBIO: Markdown para mejor visualización
 
 
 
 
125
  ],
126
+ title="🤖 Evaluador Fonético de Pronunciación (v2)",
127
  description=description,
128
+ examples=[
129
+ [audio_ejemplo_path, frase_ejemplo_texto]
130
+ ]
 
131
  )
132
 
133
  if __name__ == "__main__":