gnosticdev commited on
Commit
41484d1
·
verified ·
1 Parent(s): 11706ee

Update conver.py

Browse files
Files changed (1) hide show
  1. conver.py +56 -43
conver.py CHANGED
@@ -1,5 +1,5 @@
1
  from dataclasses import dataclass
2
- from typing import List, Tuple, Dict
3
  import os
4
  import re
5
  import httpx
@@ -7,19 +7,16 @@ import json
7
  from openai import OpenAI
8
  import edge_tts
9
  import tempfile
10
- import wave
11
  from pydub import AudioSegment
12
  import base64
13
  from pathlib import Path
14
 
15
-
16
  @dataclass
17
  class ConversationConfig:
18
  max_words: int = 3000
19
  prefix_url: str = "https://r.jina.ai/"
20
  model_name: str = "meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo"
21
 
22
-
23
  class URLToAudioConverter:
24
  def __init__(self, config: ConversationConfig, llm_api_key: str):
25
  self.config = config
@@ -43,41 +40,45 @@ class URLToAudioConverter:
43
  raise ValueError("Input text cannot be empty")
44
 
45
  try:
 
 
 
 
 
 
 
46
  chat_completion = self.llm_client.chat.completions.create(
47
- messages=[{"role": "user", "content": self._build_prompt(text)}],
48
  model=self.config.model_name,
 
49
  )
50
-
51
- pattern = r"\{(?:[^{}]|(?:\{[^{}]*\}))*\}"
52
- json_match = re.search(pattern, chat_completion.choices[0].message.content)
53
-
54
- if not json_match:
55
- raise ValueError("No valid JSON found in response")
56
-
57
- return json.loads(json_match.group())
 
 
 
 
 
 
 
 
 
58
  except Exception as e:
59
- raise RuntimeError(f"Failed to extract conversation: {e}")
60
-
61
- def _build_prompt(self, text: str) -> str:
62
- template = """
63
- {
64
- "conversation": [
65
- {"speaker": "", "text": ""},
66
- {"speaker": "", "text": ""}
67
- ]
68
- }
69
- """
70
- return (
71
- f"{text}\nConvert the provided text into a short informative and crisp "
72
- f"podcast conversation between two experts. The tone should be "
73
- f"professional and engaging. Please adhere to the following "
74
- f"format and return the conversation in JSON:\n{template}"
75
- )
76
 
77
  async def text_to_speech(self, conversation_json: Dict, voice_1: str, voice_2: str) -> Tuple[List[str], str]:
78
  output_dir = Path(self._create_output_directory())
79
  filenames = []
80
-
81
  try:
82
  for i, turn in enumerate(conversation_json["conversation"]):
83
  filename = output_dir / f"output_{i}.wav"
@@ -122,33 +123,32 @@ class URLToAudioConverter:
122
  raise ValueError("No input files provided")
123
 
124
  try:
125
- audio_segments = []
126
-
127
  for filename in filenames:
128
- audio_segment = AudioSegment.from_mp3(filename)
129
- audio_segments.append(audio_segment)
130
-
131
- combined = sum(audio_segments)
132
 
133
  combined.export(output_file, format="wav")
134
 
 
135
  for filename in filenames:
136
  os.remove(filename)
137
-
 
138
  except Exception as e:
139
  raise RuntimeError(f"Failed to combine audio files: {e}")
140
 
141
- async def url_to_audio(self, url: str, voice_1: str, voice_2: str) -> str:
142
  text = self.fetch_text(url)
143
 
144
  words = text.split()
145
  if len(words) > self.config.max_words:
146
- text = " ".join(words[: self.config.max_words])
147
 
148
  conversation_json = self.extract_conversation(text)
149
  conversation_text = "\n".join(
150
- f"{turn['speaker']}: {turn['text']}" for turn in conversation_json["conversation"]
151
- )
152
  self.llm_out = conversation_json
153
  audio_files, folder_name = await self.text_to_speech(
154
  conversation_json, voice_1, voice_2
@@ -156,4 +156,17 @@ class URLToAudioConverter:
156
 
157
  final_output = os.path.join(folder_name, "combined_output.wav")
158
  self.combine_audio_files(audio_files, final_output)
159
- return final_output,conversation_text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  from dataclasses import dataclass
2
+ from typing import List, Tuple, Dict, Optional
3
  import os
4
  import re
5
  import httpx
 
7
  from openai import OpenAI
8
  import edge_tts
9
  import tempfile
 
10
  from pydub import AudioSegment
11
  import base64
12
  from pathlib import Path
13
 
 
14
  @dataclass
15
  class ConversationConfig:
16
  max_words: int = 3000
17
  prefix_url: str = "https://r.jina.ai/"
18
  model_name: str = "meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo"
19
 
 
20
  class URLToAudioConverter:
21
  def __init__(self, config: ConversationConfig, llm_api_key: str):
22
  self.config = config
 
40
  raise ValueError("Input text cannot be empty")
41
 
42
  try:
43
+ # Prompt mejorado para obtener JSON consistente
44
+ prompt = (
45
+ f"{text}\nConvert the provided text into a short informative podcast conversation "
46
+ f"between two experts. Return ONLY a JSON object with the following structure:\n"
47
+ '{"conversation": [{"speaker": "Speaker1", "text": "..."}, {"speaker": "Speaker2", "text": "..."}]}'
48
+ )
49
+
50
  chat_completion = self.llm_client.chat.completions.create(
51
+ messages=[{"role": "user", "content": prompt}],
52
  model=self.config.model_name,
53
+ response_format={"type": "json_object"} # Fuerza formato JSON
54
  )
55
+
56
+ # Extracción robusta de JSON
57
+ response_content = chat_completion.choices[0].message.content
58
+ json_str = response_content.strip()
59
+
60
+ # Limpieza de texto alrededor del JSON
61
+ if not json_str.startswith('{'):
62
+ start = json_str.find('{')
63
+ if start != -1:
64
+ json_str = json_str[start:]
65
+
66
+ if not json_str.endswith('}'):
67
+ end = json_str.rfind('}')
68
+ if end != -1:
69
+ json_str = json_str[:end+1]
70
+
71
+ return json.loads(json_str)
72
  except Exception as e:
73
+ # Debug: Imprime la respuesta del modelo para diagnóstico
74
+ print(f"Error en extract_conversation: {str(e)}")
75
+ print(f"Respuesta del modelo: {response_content}")
76
+ raise RuntimeError(f"Failed to extract conversation: {str(e)}")
 
 
 
 
 
 
 
 
 
 
 
 
 
77
 
78
  async def text_to_speech(self, conversation_json: Dict, voice_1: str, voice_2: str) -> Tuple[List[str], str]:
79
  output_dir = Path(self._create_output_directory())
80
  filenames = []
81
+
82
  try:
83
  for i, turn in enumerate(conversation_json["conversation"]):
84
  filename = output_dir / f"output_{i}.wav"
 
123
  raise ValueError("No input files provided")
124
 
125
  try:
126
+ combined = AudioSegment.empty()
 
127
  for filename in filenames:
128
+ audio_segment = AudioSegment.from_wav(filename)
129
+ combined += audio_segment
 
 
130
 
131
  combined.export(output_file, format="wav")
132
 
133
+ # Limpieza de archivos temporales
134
  for filename in filenames:
135
  os.remove(filename)
136
+ os.rmdir(os.path.dirname(filenames[0]))
137
+
138
  except Exception as e:
139
  raise RuntimeError(f"Failed to combine audio files: {e}")
140
 
141
+ async def url_to_audio(self, url: str, voice_1: str, voice_2: str) -> Tuple[str, str]:
142
  text = self.fetch_text(url)
143
 
144
  words = text.split()
145
  if len(words) > self.config.max_words:
146
+ text = " ".join(words[:self.config.max_words])
147
 
148
  conversation_json = self.extract_conversation(text)
149
  conversation_text = "\n".join(
150
+ f"{turn['speaker']}: {turn['text']}" for turn in conversation_json["conversation"]
151
+ )
152
  self.llm_out = conversation_json
153
  audio_files, folder_name = await self.text_to_speech(
154
  conversation_json, voice_1, voice_2
 
156
 
157
  final_output = os.path.join(folder_name, "combined_output.wav")
158
  self.combine_audio_files(audio_files, final_output)
159
+ return final_output, conversation_text
160
+
161
+ async def text_to_audio(self, text: str, voice_1: str, voice_2: str) -> Tuple[str, str]:
162
+ """Nuevo método para procesar texto directo"""
163
+ conversation_json = self.extract_conversation(text)
164
+ conversation_text = "\n".join(
165
+ f"{turn['speaker']}: {turn['text']}" for turn in conversation_json["conversation"]
166
+ )
167
+ audio_files, folder_name = await self.text_to_speech(
168
+ conversation_json, voice_1, voice_2
169
+ )
170
+ final_output = os.path.join(folder_name, "combined_output.wav")
171
+ self.combine_audio_files(audio_files, final_output)
172
+ return final_output, conversation_text