Skip to content

Commit d18c951

Browse files
committed
feat: implement async retries in model chain for summary and retouch functions
1 parent bd9e2e2 commit d18c951

2 files changed

Lines changed: 65 additions & 61 deletions

File tree

model_manager.py

Lines changed: 19 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -197,49 +197,33 @@ def try_model_chain(
197197
task_name: str = "task"
198198
) -> Optional[object]:
199199
"""
200-
Try models in chain order (primary → fallbacks).
200+
Try models in chain order (primary → fallbacks), one attempt per model.
201201
Returns first successful response, or None if all fail.
202+
Retries are handled by the async caller.
202203
"""
203204
models_to_try = model_chain.get("all", [])
204205
if not models_to_try:
205206
log("ERROR", f"No models available for {task_name}")
206207
return None
207208

208-
max_retries = getattr(config.Config, 'MODEL_RETRY_COUNT', 2)
209-
retry_delay = getattr(config.Config, 'MODEL_RETRY_DELAY_SECONDS', 2.0)
210-
211209
for model_name in models_to_try:
212-
attempt = 1
213-
while attempt <= max_retries:
214-
try:
215-
log("MODEL", f"Trying {model_name} for {task_name} (attempt {attempt}/{max_retries})...")
216-
kwargs = {"model": model_name, "contents": contents}
217-
if generation_config:
218-
kwargs["config"] = generation_config
219-
220-
response = gemini_client.models.generate_content(**kwargs)
221-
222-
if response and getattr(response, 'text', None):
223-
log("MODEL", f"Success with {model_name} for {task_name}")
224-
return response
225-
226-
log("MODEL", f"{model_name} returned empty response for {task_name}")
227-
break
228-
229-
except Exception as e:
230-
transient = is_transient_gemini_error(e)
231-
log("MODEL", f"{model_name} failed for {task_name} (attempt {attempt}/{max_retries}): {e}")
232-
if attempt >= max_retries or not transient:
233-
break
234-
235-
sleep_time = retry_delay * attempt
236-
log("MODEL", f"Transient error detected, retrying {model_name} after {sleep_time}s...")
237-
import time
238-
time.sleep(sleep_time)
239-
attempt += 1
240-
continue
241-
242-
log("MODEL", f"Moving to next model after {model_name} for {task_name}")
210+
try:
211+
log("MODEL", f"Trying {model_name} for {task_name}...")
212+
kwargs = {"model": model_name, "contents": contents}
213+
if generation_config:
214+
kwargs["config"] = generation_config
215+
216+
response = gemini_client.models.generate_content(**kwargs)
217+
218+
if response and getattr(response, 'text', None):
219+
log("MODEL", f"Success with {model_name} for {task_name}")
220+
return response
221+
222+
log("MODEL", f"{model_name} returned empty response for {task_name}")
223+
224+
except Exception as e:
225+
log("MODEL", f"{model_name} failed for {task_name}: {e}")
226+
continue
243227

244228
log("ERROR", f"All models failed for {task_name}")
245229
return None

utils.py

Lines changed: 46 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ def build_retouch_prompt() -> str:
117117

118118
async def summarize_text(transcript: str, gemini_client) -> str:
119119
"""Generates a journalist-friendly summary of the transcript.
120-
Uses model chain: primary (gemma) → fallbacks.
120+
Uses model chain: primary (gemma) → fallbacks with async retries.
121121
"""
122122
if not gemini_client:
123123
return "Summarization disabled: Gemini API key not configured or client failed to load."
@@ -129,25 +129,35 @@ async def summarize_text(transcript: str, gemini_client) -> str:
129129
from model_manager import try_model_chain
130130

131131
chain = get_model_chain("summary")
132-
config = types.GenerateContentConfig(temperature=0.3)
133-
134-
response = await asyncio.to_thread(
135-
try_model_chain,
136-
gemini_client,
137-
chain,
138-
[prompt, transcript],
139-
config,
140-
"summary"
141-
)
132+
gen_config = types.GenerateContentConfig(temperature=0.3)
133+
max_retries = config.Config.MODEL_RETRY_COUNT
134+
retry_delay = config.Config.MODEL_RETRY_DELAY_SECONDS
135+
136+
for attempt in range(max_retries):
137+
response = await asyncio.to_thread(
138+
try_model_chain,
139+
gemini_client,
140+
chain,
141+
[prompt, transcript],
142+
gen_config,
143+
"summary"
144+
)
145+
146+
if response and response.text:
147+
return response.text
148+
149+
# If all models failed and this wasn't the last attempt, retry
150+
if attempt < max_retries - 1:
151+
sleep_time = retry_delay * (attempt + 1)
152+
log("GEMINI", f"All models failed for summary, retrying after {sleep_time}s...")
153+
await asyncio.sleep(sleep_time)
142154

143-
if response and response.text:
144-
return response.text
145155
return "❌ Error generating summary: all models failed"
146156

147157

148158
async def retouch_transcript(transcript: str, gemini_client) -> str:
149159
"""Retouch/clean up transcript: fix typos, punctuation, add paragraph breaks.
150-
Uses model chain: primary (gemma) → fallbacks.
160+
Uses model chain: primary (gemma) → fallbacks with async retries.
151161
"""
152162
if not gemini_client:
153163
return transcript # Return original if no client
@@ -159,19 +169,29 @@ async def retouch_transcript(transcript: str, gemini_client) -> str:
159169
from model_manager import try_model_chain
160170

161171
chain = get_model_chain("retouch")
162-
config = types.GenerateContentConfig(temperature=0.3)
163-
164-
response = await asyncio.to_thread(
165-
try_model_chain,
166-
gemini_client,
167-
chain,
168-
contents,
169-
config,
170-
"retouch"
171-
)
172+
gen_config = types.GenerateContentConfig(temperature=0.3)
173+
max_retries = config.Config.MODEL_RETRY_COUNT
174+
retry_delay = config.Config.MODEL_RETRY_DELAY_SECONDS
175+
176+
for attempt in range(max_retries):
177+
response = await asyncio.to_thread(
178+
try_model_chain,
179+
gemini_client,
180+
chain,
181+
contents,
182+
gen_config,
183+
"retouch"
184+
)
185+
186+
if response and response.text:
187+
return response.text
188+
189+
# If all models failed and this wasn't the last attempt, retry
190+
if attempt < max_retries - 1:
191+
sleep_time = retry_delay * (attempt + 1)
192+
log("GEMINI", f"All models failed for retouch, retrying after {sleep_time}s...")
193+
await asyncio.sleep(sleep_time)
172194

173-
if response and response.text:
174-
return response.text
175195
return transcript # Return original on error
176196

177197

0 commit comments

Comments
 (0)