51 lines
1.7 KiB
Python
51 lines
1.7 KiB
Python
|
|
import json
|
||
|
|
import logging
|
||
|
|
|
||
|
|
from openai import AsyncOpenAI
|
||
|
|
|
||
|
|
from app.config import settings
|
||
|
|
from app.models import Movie
|
||
|
|
from app.services.llm.base import SYSTEM_PROMPT, LLMProvider, build_user_message
|
||
|
|
|
||
|
|
logger = logging.getLogger("movie-night.llm.ollama")
|
||
|
|
|
||
|
|
|
||
|
|
class OllamaProvider(LLMProvider):
|
||
|
|
def __init__(self):
|
||
|
|
base_url = settings.llm_base_url or "http://localhost:11434/v1"
|
||
|
|
self.client = AsyncOpenAI(api_key="ollama", base_url=base_url)
|
||
|
|
self.model = settings.llm_model or "llama3"
|
||
|
|
|
||
|
|
async def get_recommendations(self, mood: str, candidates: list[Movie], max_results: int = 6) -> list[dict]:
|
||
|
|
system = SYSTEM_PROMPT.format(max_results=max_results)
|
||
|
|
user_msg = build_user_message(mood, candidates)
|
||
|
|
|
||
|
|
logger.info(f"Calling Ollama ({self.model}) with {len(candidates)} candidates")
|
||
|
|
|
||
|
|
response = await self.client.chat.completions.create(
|
||
|
|
model=self.model,
|
||
|
|
max_tokens=2048,
|
||
|
|
messages=[
|
||
|
|
{"role": "system", "content": system},
|
||
|
|
{"role": "user", "content": user_msg},
|
||
|
|
],
|
||
|
|
)
|
||
|
|
|
||
|
|
text = response.choices[0].message.content.strip()
|
||
|
|
|
||
|
|
try:
|
||
|
|
data = json.loads(text)
|
||
|
|
return data.get("recommendations", [])
|
||
|
|
except json.JSONDecodeError:
|
||
|
|
# Try to extract JSON from response
|
||
|
|
start = text.find("{")
|
||
|
|
end = text.rfind("}") + 1
|
||
|
|
if start >= 0 and end > start:
|
||
|
|
try:
|
||
|
|
data = json.loads(text[start:end])
|
||
|
|
return data.get("recommendations", [])
|
||
|
|
except json.JSONDecodeError:
|
||
|
|
pass
|
||
|
|
logger.error(f"Failed to parse Ollama response: {text[:200]}")
|
||
|
|
return []
|