diff --git a/matrixbot/commands.py b/matrixbot/commands.py index 72b5c46..04817ab 100644 --- a/matrixbot/commands.py +++ b/matrixbot/commands.py @@ -1390,37 +1390,39 @@ async def _generate_hangman_word() -> dict | None: 'Format: {"word": "example", "hint": "short category or hint"}' ) user_msg = "Pick a common English word between 5 and 8 letters (lowercase letters only, no hyphens or spaces) and give a short hint." - try: - timeout = aiohttp.ClientTimeout(total=60) - async with aiohttp.ClientSession(timeout=timeout) as session: - async with session.post( - f"{OLLAMA_URL}/api/chat", - json={ - "model": ASK_MODEL, - "stream": False, - "messages": [ - {"role": "system", "content": system_msg}, - {"role": "user", "content": user_msg}, - ], - }, - ) as response: - data = await response.json() - text = data.get("message", {}).get("content", "").strip() - if "```" in text: - text = re.sub(r"```[a-z]*\n?", "", text).strip() - m = re.search(r"\{[^{}]+\}", text, re.DOTALL) - candidate = m.group(0) if m else text - try: - parsed = json.loads(candidate) - except json.JSONDecodeError: - logger.warning("hangman: JSON parse failed, raw: %.200s", text) - parsed = {} - word = parsed.get("word", "").lower().strip() - hint = parsed.get("hint", "").strip() - if word.isalpha() and 5 <= len(word) <= 8 and hint: - return {"word": word, "hint": hint} - except Exception as e: - logger.error(f"hangman word generation error: {e}", exc_info=True) + for attempt in range(2): + try: + timeout = aiohttp.ClientTimeout(total=60) + async with aiohttp.ClientSession(timeout=timeout) as session: + async with session.post( + f"{OLLAMA_URL}/api/chat", + json={ + "model": ASK_MODEL, + "stream": False, + "messages": [ + {"role": "system", "content": system_msg}, + {"role": "user", "content": user_msg}, + ], + }, + ) as response: + data = await response.json() + text = data.get("message", {}).get("content", "").strip() + if "```" in text: + text = re.sub(r"```[a-z]*\n?", "", text).strip() + m = re.search(r"\{[^{}]+\}", text, re.DOTALL) + candidate = m.group(0) if m else text + try: + parsed = json.loads(candidate) + except json.JSONDecodeError: + logger.warning("hangman: JSON parse failed (attempt %d), raw: %.200s", attempt + 1, text) + parsed = {} + word = parsed.get("word", "").lower().strip() + hint = parsed.get("hint", "").strip() + if word.isalpha() and 5 <= len(word) <= 8 and hint: + return {"word": word, "hint": hint} + logger.warning("hangman: validation failed (attempt %d): word=%r hint=%r", attempt + 1, word, hint) + except Exception as e: + logger.error(f"hangman word generation error (attempt {attempt + 1}): {e}", exc_info=True) return None