Spaces:
Sleeping
Sleeping
Rename llm_utils.py to qa_openrouter.py
Browse files- llm_utils.py +0 -39
- qa_openrouter.py +60 -0
llm_utils.py
DELETED
|
@@ -1,39 +0,0 @@
|
|
| 1 |
-
import requests
|
| 2 |
-
import os
|
| 3 |
-
|
| 4 |
-
OPENROUTER_API = os.getenv("OPENROUTER_API_KEY")
|
| 5 |
-
GROQ_API = os.getenv("GROQ_API_KEY")
|
| 6 |
-
|
| 7 |
-
def call_llm(prompt, provider="openrouter"):
|
| 8 |
-
try:
|
| 9 |
-
if provider == "openrouter" and OPENROUTER_API:
|
| 10 |
-
resp = requests.post(
|
| 11 |
-
"https://openrouter.ai/api/v1/chat/completions",
|
| 12 |
-
headers={"Authorization": f"Bearer {OPENROUTER_API}"},
|
| 13 |
-
json={"model": "gpt-3.5-turbo", "messages": [{"role": "user", "content": prompt}]}
|
| 14 |
-
)
|
| 15 |
-
return resp.json()["choices"][0]["message"]["content"]
|
| 16 |
-
elif provider == "groq" and GROQ_API:
|
| 17 |
-
resp = requests.post(
|
| 18 |
-
"https://api.groq.com/openai/v1/chat/completions",
|
| 19 |
-
headers={"Authorization": f"Bearer {GROQ_API}"},
|
| 20 |
-
json={"model": "mixtral-8x7b", "messages": [{"role": "user", "content": prompt}]}
|
| 21 |
-
)
|
| 22 |
-
return resp.json()["choices"][0]["message"]["content"]
|
| 23 |
-
else:
|
| 24 |
-
raise Exception("No valid API keys provided.")
|
| 25 |
-
except Exception:
|
| 26 |
-
# failover
|
| 27 |
-
if provider == "openrouter":
|
| 28 |
-
return call_llm(prompt, "groq")
|
| 29 |
-
else:
|
| 30 |
-
return "⚠️ Could not connect to either API."
|
| 31 |
-
|
| 32 |
-
def generate_scraper_instruction(user_prompt):
|
| 33 |
-
system_prompt = f"Given the following user request, extract the main intent and suggest the most relevant website URL and keywords to scrape.\nUser: {user_prompt}"
|
| 34 |
-
content = call_llm(system_prompt)
|
| 35 |
-
return {"intent": user_prompt, "url": "https://news.ycombinator.com", "raw_instruction": content}
|
| 36 |
-
|
| 37 |
-
def answer_query(query, context):
|
| 38 |
-
qa_prompt = f"Answer the question based on this content:\n\n{context}\n\nQuestion: {query}"
|
| 39 |
-
return call_llm(qa_prompt)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
qa_openrouter.py
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# qa_openrouter.py
|
| 2 |
+
import os
|
| 3 |
+
import requests
|
| 4 |
+
import json
|
| 5 |
+
from typing import Optional
|
| 6 |
+
|
| 7 |
+
OPENROUTER_API = "https://openrouter.ai/api/v1/chat/completions"
|
| 8 |
+
|
| 9 |
+
def ask_openrouter(question: str, context_text: str, model: str = "openrouter/auto") -> str:
|
| 10 |
+
"""
|
| 11 |
+
Send a chat-style request to OpenRouter.
|
| 12 |
+
- question: user's natural language question
|
| 13 |
+
- context_text: scraped data concatenated (we truncate for safety)
|
| 14 |
+
- model: model id; default uses OpenRouter auto-router
|
| 15 |
+
"""
|
| 16 |
+
api_key = os.getenv("OPENROUTER_API_KEY")
|
| 17 |
+
if not api_key:
|
| 18 |
+
raise RuntimeError("OPENROUTER_API_KEY environment variable not set.")
|
| 19 |
+
|
| 20 |
+
# truncate context to avoid huge payloads (approx)
|
| 21 |
+
MAX_CHARS = 14000
|
| 22 |
+
ctx = context_text
|
| 23 |
+
if len(ctx) > MAX_CHARS:
|
| 24 |
+
ctx = ctx[:MAX_CHARS] + "\n\n[TRUNCATED]"
|
| 25 |
+
|
| 26 |
+
system_prompt = (
|
| 27 |
+
"You are a helpful assistant. Answer questions about the user's scraped web data. "
|
| 28 |
+
"If the answer requires referring to the data, cite brief snippets. Keep answers concise."
|
| 29 |
+
)
|
| 30 |
+
|
| 31 |
+
# Build messages
|
| 32 |
+
messages = [
|
| 33 |
+
{"role": "system", "content": system_prompt},
|
| 34 |
+
{"role": "user", "content": f"Here is the scraped content:\n\n{ctx}"},
|
| 35 |
+
{"role": "user", "content": f"Question: {question}"}
|
| 36 |
+
]
|
| 37 |
+
|
| 38 |
+
payload = {
|
| 39 |
+
"model": model,
|
| 40 |
+
"messages": messages,
|
| 41 |
+
"max_tokens": 800,
|
| 42 |
+
"temperature": 0.0
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
headers = {
|
| 46 |
+
"Authorization": f"Bearer {api_key}",
|
| 47 |
+
"Content-Type": "application/json"
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
resp = requests.post(OPENROUTER_API, headers=headers, json=payload, timeout=30)
|
| 51 |
+
if resp.status_code != 200:
|
| 52 |
+
raise RuntimeError(f"OpenRouter API error {resp.status_code}: {resp.text}")
|
| 53 |
+
data = resp.json()
|
| 54 |
+
# OpenRouter responses follow a Chat-completions-like schema: choices[0].message.content
|
| 55 |
+
try:
|
| 56 |
+
text = data["choices"][0]["message"]["content"]
|
| 57 |
+
except Exception:
|
| 58 |
+
# fallback to raw text
|
| 59 |
+
text = json.dumps(data, indent=2)
|
| 60 |
+
return text
|