marks commited on
Commit
3d47604
·
1 Parent(s): 4033555
Files changed (1) hide show
  1. api_clients.py +44 -76
api_clients.py CHANGED
@@ -1,45 +1,14 @@
1
  from functools import lru_cache
2
- from typing import List, Tuple, Optional, Dict
3
  import aiohttp
4
  import elevenlabs
5
  import time
6
  from contextlib import asynccontextmanager
7
  from logger import setup_logger, log_execution_time, log_async_execution_time
8
- from models import OpenRouterModel, OpenRouterRequest, OpenRouterResponse, Message
9
 
10
  logger = setup_logger("api_clients")
11
 
12
- def preprocess_text(text: str) -> str:
13
- """
14
- Clean and format text by removing unwanted characters and formatting
15
-
16
- Args:
17
- text: Raw input text
18
-
19
- Returns:
20
- Cleaned text suitable for podcast generation
21
- """
22
- import re
23
-
24
- # Remove markdown-style formatting
25
- text = re.sub(r'\*\*(.+?)\*\*', r'\1', text) # Bold
26
- text = re.sub(r'\*(.+?)\*', r'\1', text) # Italic
27
- text = re.sub(r'__(.+?)__', r'\1', text) # Underline
28
- text = re.sub(r'~~(.+?)~~', r'\1', text) # Strikethrough
29
-
30
- # Remove action blocks and special formatting
31
- text = re.sub(r'\[.*?\]', '', text) # Remove [actions]
32
- text = re.sub(r'\{.*?\}', '', text) # Remove {actions}
33
- text = re.sub(r'<.*?>', '', text) # Remove <actions>
34
-
35
- # Remove podcast-specific formatting
36
- text = re.sub(r'\((?:pause|break|music|sfx|sound effect|jingle).*?\)', '', text, flags=re.IGNORECASE)
37
- text = re.sub(r'\((host|speaker|guest)\s*\d*\s*:?\)', '', text, flags=re.IGNORECASE)
38
- text = re.sub(r'#\s*\d+\s*[:.-]', '', text) # Remove segment numbers
39
-
40
- # Clean up whitespace
41
- return ' '.join(text.split())
42
-
43
  class OpenRouterClient:
44
  """Handles OpenRouter API interactions with comprehensive logging and error tracking"""
45
 
@@ -116,56 +85,52 @@ class OpenRouterClient:
116
  logger.error("Prompt too short or missing")
117
  raise ValueError("Please provide a more detailed prompt")
118
 
119
- # Clean input text
120
- cleaned_content = preprocess_text(content)
121
- cleaned_prompt = preprocess_text(prompt)
122
-
123
- system_prompt = """You are an expert podcast script writer. Your task is to create engaging,
124
- natural-sounding podcast scripts that flow conversationally while being informative and engaging.
125
-
126
- Follow these guidelines:
127
- 1. Write in a conversational, natural speaking style that sounds authentic
128
- 2. Break complex topics into digestible segments with clear transitions
129
- 3. Avoid technical jargon unless necessary, explaining complex terms when used
130
- 4. Use natural speech patterns:
131
- - Contractions (I'm, we're, let's)
132
- - Casual language
133
- - Rhetorical questions to engage listeners
134
- 5. Include brief pauses for emphasis and pacing (but don't mark them explicitly)
135
- 6. Incorporate storytelling elements to maintain engagement
136
- 7. End with a clear conclusion and call-to-action
137
- 8. Keep paragraphs short and focused for easier delivery
138
- 9. Use simple sentence structures that flow naturally when spoken
139
 
140
- Format the script for natural speech, avoiding any special characters or formatting."""
141
 
142
- user_prompt = f"""Create a podcast script based on the following topic and content:
143
 
144
- Topic: {cleaned_prompt}
 
145
 
146
- Content to cover: {cleaned_content}
147
-
148
- Focus on making it engaging and natural to listen to."""
149
 
150
  try:
151
- request = OpenRouterRequest(
152
- model=model_id,
153
- messages=[
154
- Message(role="system", content=system_prompt),
155
- Message(role="user", content=user_prompt)
156
- ]
157
- )
 
 
158
 
159
  async with self.get_session() as session:
160
  async with session.post(
161
  f"{self.base_url}/chat/completions",
162
- json=request.dict()
163
  ) as response:
164
- response.raise_for_status()
 
 
 
 
165
  data = await response.json()
166
- router_response = OpenRouterResponse(**data)
167
- logger.debug(f"Generated script length: {len(router_response.choices[0].message.content)} chars")
168
- return router_response.choices[0].message.content
169
 
170
  except Exception as e:
171
  logger.error(f"Script generation failed", exc_info=True)
@@ -186,14 +151,17 @@ class ElevenLabsClient:
186
  """
187
  try:
188
  voices = elevenlabs.voices()
189
- return [(voice.voice_id, f"{voice.name} ({voice.labels.get('accent', 'No accent')})" +
190
- (f" - {voice.description[:50]}..." if voice.description else ""))
191
- for voice in voices]
 
 
 
192
  except Exception as e:
193
  logger.error("Failed to fetch voices from ElevenLabs", exc_info=True)
194
  raise
195
 
196
- async def generate_audio(self, text: str, voice_id: str):
197
  """Generate audio synchronously"""
198
  logger.info(f"Starting audio generation with voice: {voice_id}")
199
  logger.debug(f"Input text length: {len(text)} chars")
@@ -203,7 +171,7 @@ class ElevenLabsClient:
203
 
204
  try:
205
  start_time = time.time()
206
- audio = await elevenlabs.generate(
207
  text=text,
208
  voice=voice_id,
209
  model="eleven_monolingual_v1"
 
1
  from functools import lru_cache
2
+ from typing import List, Tuple, Optional
3
  import aiohttp
4
  import elevenlabs
5
  import time
6
  from contextlib import asynccontextmanager
7
  from logger import setup_logger, log_execution_time, log_async_execution_time
8
+ from models import OpenRouterModel
9
 
10
  logger = setup_logger("api_clients")
11
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  class OpenRouterClient:
13
  """Handles OpenRouter API interactions with comprehensive logging and error tracking"""
14
 
 
85
  logger.error("Prompt too short or missing")
86
  raise ValueError("Please provide a more detailed prompt")
87
 
88
+ system_prompt = """DO NOT WRITE ASIDES OR ACTION DESCRIPTIONS, YOU WRITE DIALOG ONLY!!. You are an expert podcast script writer with these specific requirements:
89
+ 1. Start the content immediately - no introductions, timestamps, or meta-commentary
90
+ 2. Write in a natural, conversational tone suitable for speaking
91
+ 3. Structure the content with clear paragraphs and natural pauses
92
+ 4. Use informal language while maintaining professionalism
93
+ 5. Focus on narrative flow and engaging delivery
94
+ 6. Keep technical terms simple and explained
95
+ 7. Include vocal variety cues through punctuation
96
+ 8. Write as if speaking directly to the listener
97
+ 9. Use storytelling techniques to maintain interest
98
+ 10. Do not add muscial queues or sound effects
99
+ 11. Add host and show intros, outros, and transitions as needed
100
+ """
 
 
 
 
 
 
 
101
 
102
+ user_prompt = f"""Write a podcast script based on the following content. Make it engaging and easy to follow.
103
 
104
+ Context: {prompt if prompt else 'Create an informative and engaging podcast episode'}
105
 
106
+ Content:
107
+ {content}
108
 
109
+ Format the script in a clear, readable way with appropriate spacing. Do not add asides or action descriptions. Only add spoken dialog and host cues."""
 
 
110
 
111
  try:
112
+ request_data = {
113
+ "model": model_id,
114
+ "messages": [
115
+ {"role": "system", "content": system_prompt},
116
+ {"role": "user", "content": user_prompt}
117
+ ],
118
+ "temperature": 0.7,
119
+ "max_tokens": 2000
120
+ }
121
 
122
  async with self.get_session() as session:
123
  async with session.post(
124
  f"{self.base_url}/chat/completions",
125
+ json=request_data
126
  ) as response:
127
+ if response.status != 200:
128
+ error_text = await response.text()
129
+ logger.error(f"OpenRouter API error: {error_text}")
130
+ raise ValueError(f"API request failed: {error_text}")
131
+
132
  data = await response.json()
133
+ return data['choices'][0]['message']['content']
 
 
134
 
135
  except Exception as e:
136
  logger.error(f"Script generation failed", exc_info=True)
 
151
  """
152
  try:
153
  voices = elevenlabs.voices()
154
+ return [(
155
+
156
+ f"{voice.name} ({voice.labels.get('accent', 'No accent')})" +
157
+ (f" - {voice.description[:50]}..." if voice.description else ""),
158
+ voice.voice_id # Value (hidden from user)
159
+ ) for voice in voices]
160
  except Exception as e:
161
  logger.error("Failed to fetch voices from ElevenLabs", exc_info=True)
162
  raise
163
 
164
+ def generate_audio(self, text: str, voice_id: str):
165
  """Generate audio synchronously"""
166
  logger.info(f"Starting audio generation with voice: {voice_id}")
167
  logger.debug(f"Input text length: {len(text)} chars")
 
171
 
172
  try:
173
  start_time = time.time()
174
+ audio = elevenlabs.generate(
175
  text=text,
176
  voice=voice_id,
177
  model="eleven_monolingual_v1"