Nugh75 commited on
Commit
403260d
·
1 Parent(s): 24083bf

download conversazione e audio conversazione

Browse files
app/configs/prompts.py CHANGED
@@ -43,5 +43,15 @@ SYSTEM_PROMPTS = {
43
  Quando comunichi con lo studente, usa un linguaggio che stimoli la riflessione interiore. Non offrire soluzioni immediate, ma guida verso una comprensione più profonda delle emozioni e dei pensieri che emergono durante lo studio. Il tuo tono deve essere calmo e riflessivo, invitando lo studente a esplorare le proprie sensazioni con curiosità invece che con giudizio.
44
  Esempio: “Lo studio non è solo l'acquisizione di nozioni, ma un viaggio di scoperta di te stesso e del mondo che ti circonda. Ogni momento di difficoltà è un'opportunità per comprendere meglio come la tua mente lavora e apprende. Cosa ti sta insegnando questa esperienza su di te?”
45
  Esempio n°2: “Osserva questi pensieri con curiosità, come faresti con un fenomeno interessante che stai studiando. Cosa noti di particolare nel modo in cui la tua mente sta processando questa situazione?"
 
 
 
 
 
 
 
 
 
 
46
  Usa questo contesto per rispondere: {context}"""
47
  }
 
43
  Quando comunichi con lo studente, usa un linguaggio che stimoli la riflessione interiore. Non offrire soluzioni immediate, ma guida verso una comprensione più profonda delle emozioni e dei pensieri che emergono durante lo studio. Il tuo tono deve essere calmo e riflessivo, invitando lo studente a esplorare le proprie sensazioni con curiosità invece che con giudizio.
44
  Esempio: “Lo studio non è solo l'acquisizione di nozioni, ma un viaggio di scoperta di te stesso e del mondo che ti circonda. Ogni momento di difficoltà è un'opportunità per comprendere meglio come la tua mente lavora e apprende. Cosa ti sta insegnando questa esperienza su di te?”
45
  Esempio n°2: “Osserva questi pensieri con curiosità, come faresti con un fenomeno interessante che stai studiando. Cosa noti di particolare nel modo in cui la tua mente sta processando questa situazione?"
46
+ Usa questo contesto per rispondere: {context}""",
47
+ "Choch didattico": """Sei un amichevole e disponibile coach didattico che aiuta gli insegnanti a pianificare una lezione.
48
+ Inizia presentandoti e chiedendo all'insegnante quale argomento desidera insegnare e a quale livello di grado si rivolge la sua classe. Aspetta la risposta dell'insegnante e non procedere fino a quando l'insegnante non risponde.
49
+ Successivamente, chiedi all'insegnante se gli studenti hanno conoscenze pregresse sull'argomento o se si tratta di un argomento completamente nuovo. Se gli studenti hanno conoscenze pregresse sull'argomento, chiedi all'insegnante di spiegare brevemente cosa pensa che gli studenti sappiano a riguardo. Aspetta la risposta dell'insegnante e non rispondere al posto dell'insegnante.
50
+ Dopo di che, chiedi all'insegnante quale sia il loro obiettivo di apprendimento per la lezione; cioè cosa vorrebbero che gli studenti capissero o fossero in grado di fare dopo la lezione. Aspetta una risposta.
51
+ Sulla base di queste informazioni, crea un piano di lezione personalizzato che includa una varietà di tecniche di insegnamento e modalità, tra cui l'istruzione diretta, la verifica della comprensione (compresa la raccolta di prove di comprensione da un campione ampio di studenti), la discussione, un'attività coinvolgente in classe e un compito.
52
+ Spiega perché stai scegliendo ciascuno di questi. Chiedi all'insegnante se desidera apportare modifiche o se sono a conoscenza di eventuali concezioni errate sull'argomento che gli studenti potrebbero incontrare. Aspetta una risposta.
53
+ Se l'insegnante desidera apportare modifiche o elenca eventuali concezioni errate, collabora con l'insegnante per modificare la lezione e affrontare le concezioni errate.
54
+ Successivamente, chiedi all'insegnante se desidera ricevere consigli su come assicurarsi che l'obiettivo di apprendimento venga raggiunto. Aspetta una risposta.
55
+ Se l'insegnante è soddisfatto della lezione, informa l'insegnante che può tornare a questa istruzione e contattarti nuovamente per condividere come è andata la lezione.
56
  Usa questo contesto per rispondere: {context}"""
57
  }
app/llm_handling.py CHANGED
@@ -7,6 +7,9 @@ from openai import OpenAI
7
  from langchain_community.vectorstores import FAISS
8
  from langchain_community.embeddings import HuggingFaceEmbeddings
9
  import gradio as gr
 
 
 
10
 
11
  from app.config import OPENAI_API_KEY
12
  from app.functions.database_handling import BASE_DB_PATH # Aggiungi questo import
@@ -27,6 +30,84 @@ local_client = OpenAI(
27
  api_key="not-needed"
28
  )
29
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  def get_system_prompt(prompt_type="tutor"):
31
  """Seleziona il prompt di sistema appropriato"""
32
  return SYSTEM_PROMPTS.get(prompt_type, SYSTEM_PROMPTS["tutor"])
@@ -76,31 +157,45 @@ def answer_question(question, db_name, prompt_type="tutor", chat_history=None, l
76
  context = "\n".join([doc.page_content for doc in relevant_docs])
77
  prompt = SYSTEM_PROMPTS[prompt_type].format(context=context)
78
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  if llm_type == LLMType.OPENAI:
80
  response = openai_client.chat.completions.create(
81
- model="gpt-4-mini",
82
- messages=[
83
- {"role": "system", "content": prompt},
84
- {"role": "user", "content": question}
85
- ],
86
- temperature=0.7
87
  )
88
  answer = response.choices[0].message.content
89
 
90
  else: # LOCAL
91
  response = local_client.chat.completions.create(
92
  model="qwen2.5-coder-7b-instruct",
93
- messages=[
94
- {"role": "system", "content": prompt},
95
- {"role": "user", "content": question}
96
- ],
97
  temperature=0.7
98
  )
99
  answer = response.choices[0].message.content
100
-
 
 
 
 
101
  return [
102
- {"role": "user", "content": question},
103
- {"role": "assistant", "content": answer}
104
  ]
105
 
106
  except Exception as e:
 
7
  from langchain_community.vectorstores import FAISS
8
  from langchain_community.embeddings import HuggingFaceEmbeddings
9
  import gradio as gr
10
+ import asyncio
11
+ import edge_tts
12
+ from pathlib import Path
13
 
14
  from app.config import OPENAI_API_KEY
15
  from app.functions.database_handling import BASE_DB_PATH # Aggiungi questo import
 
30
  api_key="not-needed"
31
  )
32
 
33
+ # Voci italiane edge-tts
34
+ VOICE_USER = "it-IT-DiegoNeural" # Voce maschile utente
35
+ VOICE_ASSISTANT = "it-IT-ElsaNeural" # Voce femminile assistente
36
+
37
+ async def text_to_speech(text, voice_name, output_file):
38
+ """Genera audio usando edge-tts"""
39
+ communicate = edge_tts.Communicate(text, voice_name)
40
+ await communicate.save(output_file)
41
+
42
+ def generate_speech(text, is_user=True):
43
+ try:
44
+ # Crea directory per audio temporanei
45
+ audio_dir = Path("temp_audio")
46
+ audio_dir.mkdir(exist_ok=True)
47
+
48
+ # Seleziona voce e genera nome file
49
+ voice = VOICE_USER if is_user else VOICE_ASSISTANT
50
+ file_name = f"speech_{hash(text)}.mp3"
51
+ output_path = audio_dir / file_name
52
+
53
+ # Genera audio
54
+ asyncio.run(text_to_speech(text, voice, str(output_path)))
55
+ return str(output_path)
56
+
57
+ except Exception as e:
58
+ logging.error(f"Errore TTS: {e}")
59
+ return None
60
+
61
+ import re
62
+
63
+ def clean_markdown(text):
64
+ """Rimuove markdown dal testo"""
65
+ text = re.sub(r'```[\s\S]*?```', '', text) # blocchi codice
66
+ text = re.sub(r'`.*?`', '', text) # codice inline
67
+ text = re.sub(r'\[([^\]]+)\]\([^\)]+\)', r'\1', text) # link
68
+ text = re.sub(r'\*\*(.*?)\*\*', r'\1', text) # bold
69
+ text = re.sub(r'\*(.*?)\*', r'\1', text) # italic
70
+ return text.strip()
71
+
72
+ def generate_chat_audio(chat_history):
73
+ """Genera audio della conversazione con voci alternate"""
74
+ try:
75
+ audio_files = []
76
+ audio_dir = Path("temp_audio")
77
+ audio_dir.mkdir(exist_ok=True)
78
+
79
+ # Genera audio per ogni messaggio
80
+ for msg in chat_history:
81
+ content = clean_markdown(msg["content"])
82
+ if not content.strip():
83
+ continue
84
+
85
+ voice = VOICE_USER if msg["role"] == "user" else VOICE_ASSISTANT
86
+ file_name = f"chat_{msg['role']}_{hash(content)}.mp3"
87
+ output_path = audio_dir / file_name
88
+
89
+ # Genera audio senza prefissi
90
+ asyncio.run(text_to_speech(content, voice, str(output_path)))
91
+ audio_files.append(str(output_path))
92
+
93
+ # Combina tutti gli audio
94
+ if audio_files:
95
+ from pydub import AudioSegment
96
+ combined = AudioSegment.empty()
97
+ for audio_file in audio_files:
98
+ segment = AudioSegment.from_mp3(audio_file)
99
+ combined += segment
100
+
101
+ final_path = audio_dir / f"chat_complete_{hash(str(chat_history))}.mp3"
102
+ combined.export(str(final_path), format="mp3")
103
+ return str(final_path)
104
+
105
+ return None
106
+
107
+ except Exception as e:
108
+ logging.error(f"Errore generazione audio: {e}")
109
+ return None
110
+
111
  def get_system_prompt(prompt_type="tutor"):
112
  """Seleziona il prompt di sistema appropriato"""
113
  return SYSTEM_PROMPTS.get(prompt_type, SYSTEM_PROMPTS["tutor"])
 
157
  context = "\n".join([doc.page_content for doc in relevant_docs])
158
  prompt = SYSTEM_PROMPTS[prompt_type].format(context=context)
159
 
160
+ # Prepara la cronologia completa delle conversazioni
161
+ conversation_history = []
162
+ for msg in chat_history: # Rimuovo limite di 4 messaggi
163
+ conversation_history.append({
164
+ "role": msg["role"],
165
+ "content": msg["content"]
166
+ })
167
+
168
+ # Costruisci messaggio con contesto completo
169
+ messages = [
170
+ {"role": "system", "content": prompt},
171
+ *conversation_history, # Includi tutta la cronologia
172
+ {"role": "user", "content": question}
173
+ ]
174
+
175
  if llm_type == LLMType.OPENAI:
176
  response = openai_client.chat.completions.create(
177
+ model="gpt-4o-mini",
178
+ messages=messages,
179
+ temperature=0.7,
180
+ max_tokens=2048 # Aumenta token per gestire conversazioni lunghe
 
 
181
  )
182
  answer = response.choices[0].message.content
183
 
184
  else: # LOCAL
185
  response = local_client.chat.completions.create(
186
  model="qwen2.5-coder-7b-instruct",
187
+ messages=messages,
 
 
 
188
  temperature=0.7
189
  )
190
  answer = response.choices[0].message.content
191
+
192
+ # Genera audio per domanda e risposta
193
+ user_audio = generate_speech(question, is_user=True)
194
+ assistant_audio = generate_speech(answer, is_user=False)
195
+
196
  return [
197
+ {"role": "user", "content": question, "audio": user_audio},
198
+ {"role": "assistant", "content": answer, "audio": assistant_audio}
199
  ]
200
 
201
  except Exception as e:
temp_audio/speech_7579359131755957934.mp3 ADDED
Binary file (35.6 kB). View file
 
temp_audio/speech_8367152923735697791.mp3 ADDED
Binary file (17 kB). View file
 
ui/chatbot_tab.py CHANGED
@@ -1,11 +1,14 @@
1
  # ui/chatbot_tab.py
2
 
 
3
  import gradio as gr
4
  from app.functions.database_handling import list_databases
5
- from app.configs.prompts import SYSTEM_PROMPTS # Aggiunta importazionei
6
- from app.llm_handling import answer_question, LLMType # Aggiungi LLMType
7
  from utils.helpers import extract_text_from_files
8
 
 
 
9
  def create_chatbot_tab():
10
  """Crea il tab 'Chatbot' dell'interfaccia Gradio."""
11
 
@@ -31,13 +34,16 @@ def create_chatbot_tab():
31
  # Converti stringa in enum
32
  selected_llm = LLMType.LOCAL if llm_type == "local" else LLMType.OPENAI
33
 
34
- new_messages = answer_question(
 
35
  message,
36
  db_name,
37
  prompt_type,
 
38
  llm_type=selected_llm
39
  )
40
- chat_history.extend(new_messages)
 
41
 
42
  return "", chat_history
43
 
@@ -45,6 +51,98 @@ def create_chatbot_tab():
45
  """Pulisce la cronologia della chat."""
46
  return [], []
47
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  # Ottieni la lista aggiornata dei database
49
  databases = list_databases()
50
 
@@ -84,7 +182,7 @@ def create_chatbot_tab():
84
  with gr.Row():
85
  ask_button = gr.Button("Invia")
86
  clear_button = gr.Button("Pulisci Chat")
87
-
88
  # Upload file con dimensioni ridotte
89
  with gr.Row():
90
  file_input = gr.File(
@@ -99,6 +197,28 @@ def create_chatbot_tab():
99
  # Stato della chat
100
  chat_state = gr.State([])
101
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  # Eventi per i bottoni
103
  upload_button.click(
104
  fn=chat_upload_and_respond,
@@ -117,5 +237,13 @@ def create_chatbot_tab():
117
  outputs=[chatbot, chat_state]
118
  )
119
 
 
 
 
 
 
 
 
 
120
  # Ritorna il riferimento al dropdown corretto
121
  return {"db_selector": db_name_chat}
 
1
  # ui/chatbot_tab.py
2
 
3
+ import logging
4
  import gradio as gr
5
  from app.functions.database_handling import list_databases
6
+ from app.configs.prompts import SYSTEM_PROMPTS
7
+ from app.llm_handling import answer_question, LLMType, generate_chat_audio
8
  from utils.helpers import extract_text_from_files
9
 
10
+ logging.basicConfig(level=logging.INFO)
11
+
12
  def create_chatbot_tab():
13
  """Crea il tab 'Chatbot' dell'interfaccia Gradio."""
14
 
 
34
  # Converti stringa in enum
35
  selected_llm = LLMType.LOCAL if llm_type == "local" else LLMType.OPENAI
36
 
37
+ # Ottieni risposta con audio
38
+ messages = answer_question(
39
  message,
40
  db_name,
41
  prompt_type,
42
+ chat_history=chat_history, # Passa la cronologia
43
  llm_type=selected_llm
44
  )
45
+
46
+ chat_history.extend(messages)
47
 
48
  return "", chat_history
49
 
 
51
  """Pulisce la cronologia della chat."""
52
  return [], []
53
 
54
+ def format_conversation_for_download(chat_history):
55
+ """Formatta la cronologia della chat per il download."""
56
+ if not chat_history:
57
+ return "Nessuna conversazione da scaricare"
58
+
59
+ formatted_text = []
60
+ for msg in chat_history:
61
+ role = "User" if msg["role"] == "user" else "Assistant"
62
+ content = msg["content"]
63
+ formatted_text.append(f"{role}: {content}\n")
64
+
65
+ return "\n".join(formatted_text)
66
+
67
+ def download_conversation(chat_history):
68
+ """Prepara il file di testo per il download."""
69
+ conversation_text = format_conversation_for_download(chat_history)
70
+
71
+ # Crea un file temporaneo con la conversazione
72
+ import tempfile
73
+ import os
74
+ from pathlib import Path
75
+
76
+ temp_dir = tempfile.gettempdir()
77
+ temp_path = os.path.join(temp_dir, "conversazione.txt")
78
+
79
+ # Assicurati che il contenuto sia in UTF-8
80
+ with open(temp_path, "w", encoding="utf-8") as f:
81
+ f.write(conversation_text)
82
+
83
+ return str(Path(temp_path).absolute())
84
+
85
+ def download_audio(chat_history):
86
+ """Scarica l'ultimo messaggio audio dalla chat"""
87
+ try:
88
+ if not chat_history:
89
+ gr.Warning("Nessun messaggio nella chat")
90
+ return None
91
+
92
+ # Prendi l'ultimo messaggio assistant
93
+ for msg in reversed(chat_history):
94
+ if msg["role"] == "assistant" and "audio" in msg:
95
+ audio_path = msg["audio"]
96
+ if audio_path and os.path.exists(audio_path):
97
+ return audio_path
98
+
99
+ gr.Warning("Nessun audio disponibile per l'ultima risposta")
100
+ return None
101
+
102
+ except Exception as e:
103
+ gr.Error(f"Errore durante il download dell'audio: {str(e)}")
104
+ return None
105
+
106
+ def format_conversation_for_audio(chat_history):
107
+ """Formatta la conversazione per la sintesi vocale"""
108
+ audio_text = []
109
+ for msg in chat_history:
110
+ role = "Utente" if msg["role"] == "user" else "Assistente"
111
+ audio_text.append(f"{role} dice: {msg['content']}")
112
+ return "\n".join(audio_text)
113
+
114
+ def generate_conversation_audio(chat_history):
115
+ """Genera audio della conversazione completa"""
116
+ try:
117
+ if not chat_history:
118
+ gr.Warning("Nessun messaggio nella chat")
119
+ return None
120
+
121
+ conversation_text = format_conversation_for_audio(chat_history)
122
+ audio_path = generate_speech(conversation_text, is_user=False)
123
+
124
+ if audio_path and os.path.exists(audio_path):
125
+ return audio_path
126
+ else:
127
+ gr.Warning("Errore nella generazione dell'audio")
128
+ return None
129
+
130
+ except Exception as e:
131
+ gr.Error(f"Errore: {str(e)}")
132
+ return None
133
+
134
+ def convert_chat_to_audio(chat_history):
135
+ if not chat_history:
136
+ gr.Warning("Nessun messaggio da convertire")
137
+ return None
138
+
139
+ audio_path = generate_chat_audio(chat_history)
140
+ if audio_path:
141
+ return audio_path
142
+ else:
143
+ gr.Warning("Errore nella generazione dell'audio")
144
+ return None
145
+
146
  # Ottieni la lista aggiornata dei database
147
  databases = list_databases()
148
 
 
182
  with gr.Row():
183
  ask_button = gr.Button("Invia")
184
  clear_button = gr.Button("Pulisci Chat")
185
+
186
  # Upload file con dimensioni ridotte
187
  with gr.Row():
188
  file_input = gr.File(
 
197
  # Stato della chat
198
  chat_state = gr.State([])
199
 
200
+
201
+ # Download e Audio in due righe separate
202
+ with gr.Row():
203
+ with gr.Column(scale=1):
204
+ download_button = gr.Button("💾 Scarica Conversazione")
205
+ download_file = gr.File(
206
+ label="Download Conversazione",
207
+ visible=True,
208
+ interactive=False
209
+ )
210
+
211
+ with gr.Row():
212
+ with gr.Column(scale=1):
213
+ audio_button = gr.Button("🎤 Genera Audio Chat")
214
+ audio_output = gr.Audio(label="Audio", visible=True)
215
+
216
+ audio_button.click(
217
+ fn=convert_chat_to_audio,
218
+ inputs=[chatbot],
219
+ outputs=[audio_output]
220
+ )
221
+
222
  # Eventi per i bottoni
223
  upload_button.click(
224
  fn=chat_upload_and_respond,
 
237
  outputs=[chatbot, chat_state]
238
  )
239
 
240
+ # Aggiungi evento per il download
241
+ download_button.click(
242
+ fn=download_conversation,
243
+ inputs=[chatbot],
244
+ outputs=[download_file]
245
+ )
246
+
247
+
248
  # Ritorna il riferimento al dropdown corretto
249
  return {"db_selector": db_name_chat}