-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathllm_gateway.py
More file actions
112 lines (99 loc) · 4.93 KB
/
Copy pathllm_gateway.py
File metadata and controls
112 lines (99 loc) · 4.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import json
from typing import Optional
from config import config
class LLMGateway:
"""Interface to communicate with Language Models."""
def __init__(self):
self.api_key = config.OPENAI_API_KEY
self.model_name = config.MODEL_NAME
self.temperature = config.TEMPERATURE
def generate_completion(self, system_prompt: str, user_prompt: str, json_mode: bool = False, model: Optional[str] = None, temperature: Optional[float] = None) -> str:
"""
Implementation of an LLM call supporting OpenRouter and Ollama.
"""
model = model or self.model_name
temp = temperature if temperature is not None else self.temperature
if config.DEBUG_MODE:
print(f"--- LLM REQUEST ({model}) ---")
print(f"System: {system_prompt[:100]}...")
print(f"User: {user_prompt[:100]}...")
print("-------------------------")
import urllib.request
import urllib.error
import time
max_retries = 3
for attempt in range(max_retries):
try:
from environment_probe import RateLimitTracker
# Approximate prompt tokens tracking
RateLimitTracker.log_call(estimated_prompt_tokens=len(system_prompt)//4 + len(user_prompt)//4)
if self.api_key.startswith("sk-"):
# OpenRouter / OpenAI API Integration
url = "https://openrouter.ai/api/v1/chat/completions"
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {self.api_key}"
}
data = {
"model": model,
"messages": [
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}
],
"temperature": temp
}
if json_mode:
data["response_format"] = {"type": "json_object"}
else:
# Local Ollama Integration
url = "http://localhost:11434/api/chat"
headers = {
"Content-Type": "application/json"
}
data = {
"model": model,
"messages": [
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}
],
"stream": False,
"options": {
"temperature": temp
}
}
if json_mode:
data["format"] = "json"
req = urllib.request.Request(url, data=json.dumps(data).encode("utf-8"), headers=headers)
with urllib.request.urlopen(req, timeout=config.LLM_TIMEOUT) as response:
res_body = response.read()
res_json = json.loads(res_body)
if self.api_key.startswith("sk-"):
content = res_json.get("choices", [{}])[0].get("message", {}).get("content", "")
else:
content = res_json.get("message", {}).get("content", "")
if json_mode:
content = content.replace("```json", "").replace("```", "").strip()
return content
except (urllib.error.HTTPError, urllib.error.URLError, ConnectionError) as e:
# If it's an HTTP 429 (Rate Limit) or Connection Error, retry.
is_retryable = False
if isinstance(e, urllib.error.HTTPError):
if e.code in (429, 502, 503, 504): is_retryable = True
else:
is_retryable = True # URLError/ConnectionError usually retryable
if is_retryable and attempt < max_retries - 1:
wait_time = (attempt + 1) * 2
print(f"API Error ({e}). Retrying in {wait_time}s... ({attempt+1}/{max_retries})")
time.sleep(wait_time)
continue
err_msg = str(e)
if isinstance(e, urllib.error.HTTPError):
err_msg = e.read().decode('utf-8', errors='ignore')
print(f"API Error ({err_msg}). Final attempt failed.")
raise e
except Exception as e:
print(f"Unexpected API Error ({e}).")
if attempt < max_retries - 1:
time.sleep(0.5)
continue
raise e