1+ from __future__ import annotations
2+ from typing import Tuple
3+ import os
4+ # LLM client setup copied from notebook
5+ try :
6+ from ollama import Client
7+ except Exception : # if ollama isn't installed in some env, don't crash imports
8+ Client = None # type: ignore
9+ MODEL_NAME = os .getenv ("MODEL_NAME" , "Llama3.1:8b" )
10+ OLLAMA_URL = os .getenv ("OLLAMA_HOST" , "localhost:11434" )
11+ class _DummyClient :
12+ """Fallback so that importing this module doesn't explode in CI."""
13+ def chat (self , * args , ** kwargs ):
14+ class Message :
15+ def __init__ (self , content ):
16+ self .content = content
17+ class Response :
18+ def __init__ (self , content ):
19+ self .message = Message (content )
20+ return Response ("dummy response" )
21+ if Client :
22+ client = Client (host = OLLAMA_URL )
23+ else :
24+ client = _DummyClient ()
25+ def get_translation (post : str ) -> str :
26+ """
27+ Translate a non-English post into English using the local Ollama model.
28+ (Copied from notebook.)
29+ """
30+ context = (
31+ "You are a translation assistant. Translate the following text into natural English. "
32+ "Only output the translated text, with no explanations or commentary."
33+ )
34+ try :
35+ prompt = f"{ context } \n \n Text to translate:\n { post } "
36+ response = client .chat (
37+ model = MODEL_NAME ,
38+ messages = [{"role" : "user" , "content" : prompt }],
39+ )
40+ return response .message .content .strip ()
41+ except Exception as e :
42+ return f"[Error: { type (e ).__name__ } - { e } ]"
43+ def get_language (post : str ) -> str :
44+ """
45+ Detects the language of a given post using the LLM.
46+ Returns the name of the language in English (e.g. 'German', 'Spanish', 'Chinese', etc.)
47+ (Copied from notebook, with a small robustness tweak.)
48+ """
49+ prompt = (
50+ "Identify the language of the following text. "
51+ "Respond with only the language name in English (for example, 'German', 'Spanish', 'Chinese'). "
52+ "Do not answer in the language itself.\n \n "
53+ f"Text:\n { post } "
54+ )
55+ try :
56+ response = client .chat (
57+ model = MODEL_NAME ,
58+ messages = [{"role" : "user" , "content" : prompt }],
59+ )
60+ if isinstance (response , dict ):
61+ content = response .get ("message" , {}).get ("content" , "" )
62+ else :
63+ content = getattr (getattr (response , "message" , None ), "content" , "" )
64+ return str (content ).strip ()
65+ except Exception as e :
66+ return f"[Error: { type (e ).__name__ } - { e } ]"
67+ def query_llm_robust (post : str ) -> tuple [bool , str ]:
68+ """
69+ A robust version of query_llm that safely handles unexpected model responses or errors.
70+ Ensures output is always in the correct format (bool, str).
71+ (Exactly your notebook code.)
72+ """
73+ try :
74+ # Try language detection
75+ lang = get_language (post )
76+ # Validate language detection output
77+ if not isinstance (lang , str ) or len (lang .strip ()) == 0 :
78+ # Model gave empty or invalid response
79+ return False , "[Invalid language detection output]"
80+ # Determine if English
81+ is_english = lang .strip ().lower () in ["english" , "en" ]
82+ # If English, return original post
83+ if is_english :
84+ return True , post .strip ()
85+ # If not English, attempt translation
86+ translation = get_translation (post )
87+ # Validate translation output
88+ if not isinstance (translation , str ) or len (translation .strip ()) == 0 :
89+ return False , "[Invalid translation output]"
90+ return False , translation .strip ()
91+ except Exception as e :
92+ return False , f"[Error: { type (e ).__name__ } - { e } ]"
0 commit comments