Files
boc/projects/landvex/20-automation/llm_client.py
T
Bernt 6de2455917 v1.2.0: Add Global Markets footer, translated to 9 languages
- Added GLOBAL_MARKETS_TITLE to all translation files
- Updated footer with 12 markets (4 active + 8 upcoming)
- Translated market section to: zh-cn, zh-tw, ja, ko, th, vi, id, ms, hi
- Built and deployed to production
- CloudFront invalidation: I3RTMXVFDJXWLG3SYX208OP1CC
2026-07-08 19:56:03 +00:00

176 lines
5.2 KiB
Python

#!/usr/bin/env python3
"""
LLM Client för Landvex Produktionsagent
Använder Moonshot/Kimi API (OpenAI-kompatibelt)
"""
import os
import json
import time
from typing import Optional, Dict, Any, List
try:
from openai import OpenAI
except ImportError:
raise ImportError("openai paket krävs. Kör: pip install openai")
# Konfiguration
MOONSHOT_API_KEY = os.environ.get("MOONSHOT_API_KEY") or os.environ.get("KIMI_API_KEY")
MOONSHOT_BASE_URL = "https://api.moonshot.cn/v1"
DEFAULT_MODEL = "moonshot-v1-128k" # 128k context för långa artiklar
class LLMClient:
"""Klient för att kommunicera med Moonshot/Kimi LLM API."""
def __init__(self, api_key: Optional[str] = None, model: str = DEFAULT_MODEL):
self.api_key = api_key or MOONSHOT_API_KEY
if not self.api_key:
raise ValueError("MOONSHOT_API_KEY eller KIMI_API_KEY måste sättas")
self.model = model
self.client = OpenAI(
api_key=self.api_key,
base_url=MOONSHOT_BASE_URL
)
def generera_artikel(
self,
amne: str,
doman: str,
system_prompt: str,
webb_resultat: Optional[List[Dict]] = None,
max_tokens: int = 4000,
temperatur: float = 0.7
) -> Dict[str, Any]:
"""
Generera en komplett artikel om ett infrastrukturobjekt.
Args:
amne: Objektets namn (t.ex. "Avstängningsventil")
doman: Domänkod (t.ex. "VAT")
system_prompt: Systemprompt från fil
webb_resultat: Resultat från webbsökning (valfritt)
max_tokens: Max tokens i svaret
temperatur: Kreativitet (0.0-1.0)
Returns:
Dict med komplett artikeldata
"""
# Bygg användarprompt med webbdata om tillgängligt
webb_kontext = ""
if webb_resultat:
webb_kontext = "\n\n## Webbresearch:\n"
for i, result in enumerate(webb_resultat[:3], 1):
webb_kontext += f"\n### Källa {i}: {result.get('title', 'Okänd')}\n"
webb_kontext += f"URL: {result.get('url', 'N/A')}\n"
webb_kontext += f"Innehåll: {result.get('content', result.get('snippet', ''))[:500]}...\n"
user_prompt = f"""Generera en komplett artikel om följande infrastrukturobjekt:
Objekt: {amne}
Domän: {doman}
{webb_kontext}
Returnera SVARET SOM JSON i följande format:
{{
"slug": "url-vänlig-slug",
"namn": {{
"sv": "Svenskt namn",
"en": "Engelskt namn"
}},
"beskrivning": "Detaljerad beskrivning av objektet, dess funktion och användningsområden (minst 200 ord)",
"teknik": {{
"material": ["Material som används"],
"dimensioner": "Typiska dimensioner",
"standarder": ["Tillämpliga standarder"]
}},
"anvandningsomraden": ["Lista över användningsområden"],
"relaterade_objekt": ["Lista över relaterade infrastrukturobjekt"],
"bilder": [
{{
"beskrivning": "Beskrivning av vad bilden ska visa",
"alt_text": "Alt-text för tillgänglighet"
}}
],
"kallor": [
{{
"titel": "Källans titel",
"url": "https://example.com",
"typ": "webbsida|standard|dokument"
}}
]
}}
VIKTIGT: Returnera ENDAST JSON, ingen annan text."""
# Anropa LLM
response = self.client.chat.completions.create(
model=self.model,
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}
],
temperature=temperatur,
max_tokens=max_tokens,
response_format={"type": "json_object"}
)
# Parsa JSON-svar
try:
result = json.loads(response.choices[0].message.content)
return result
except json.JSONDecodeError as e:
raise ValueError(f"Kunde inte parsa LLM-svar som JSON: {e}")
def forbattra_artikel(
self,
befintlig_artikel: Dict[str, Any],
instruktioner: str,
max_tokens: int = 4000
) -> Dict[str, Any]:
"""
Förbättra en befintlig artikel baserat på instruktioner.
"""
user_prompt = f"""Förbättra följande artikel enligt instruktionerna:
## Instruktioner:
{instruktioner}
## Befintlig artikel:
{json.dumps(befintlig_artikel, ensure_ascii=False, indent=2)}
Returnera den förbättrade artikeln som JSON i samma format."""
response = self.client.chat.completions.create(
model=self.model,
messages=[
{"role": "user", "content": user_prompt}
],
temperature=0.5,
max_tokens=max_tokens,
response_format={"type": "json_object"}
)
return json.loads(response.choices[0].message.content)
def testa_llm():
"""Testa LLM-anslutning."""
client = LLMClient()
print("✓ LLM-klient skapad")
# Testa med enkelt anrop
response = client.client.chat.completions.create(
model=DEFAULT_MODEL,
messages=[{"role": "user", "content": "Svara med ett enkelt 'OK'"}],
max_tokens=10
)
print(f"✓ LLM svarade: {response.choices[0].message.content}")
return True
if __name__ == "__main__":
testa_llm()