| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- #!/usr/bin/env python3
- import json
- import sqlite3
- import time
- import urllib.request
- DB = "data/zammad_analysis.sqlite3"
- URL = "http://127.0.0.1:11434/api/chat"
- MODEL = "qwen3:8b"
- TAXONOMY = """
- VERSANDSTATUS
- LIEFERVERZUG
- ADRESSÄNDERUNG
- REKLAMATION
- TRANSPORTSCHADEN
- FEHLLIEFERUNG
- RECHNUNG
- ZAHLUNG
- WIDERRUF
- RETOURE
- PFLANZENBERATUNG
- SORTENBERATUNG
- PFLEGEFRAGE
- BESTANDSANFRAGE
- VORBESTELLUNG
- B2B
- GROSSHANDEL
- DÜNGER_FEHLT
- SONSTIGES
- """
- SYSTEM = f"""
- Du analysierst Kundenservice-Tickets von Schmid Gartenpflanzen.
- Klassifiziere das tatsächliche Kundenanliegen.
- Bestehende Primärtaxonomie:
- {TAXONOMY}
- Wichtige Regeln:
- - PRODUKTQUALITÄT unter REKLAMATION oder PFLANZENBERATUNG.
- - SCHLECHTVERPACKT unter REKLAMATION bzw. TRANSPORTSCHADEN.
- - FALSCHESORTEGELIEFERT unter FEHLLIEFERUNG.
- - DÜNGER_FEHLT ist ein eigener Intent.
- - Mehrere Anliegen gleichzeitig müssen als Multi-Intent erfasst werden.
- - Keine neuen Primärintents erfinden.
- Antworte ausschließlich als JSON:
- {{
- "primary_intent": "...",
- "secondary_intents": [],
- "complaint_type": null,
- "actions": [],
- "summary": "...",
- "taxonomy_fit": "GOOD|PARTIAL|POOR",
- "taxonomy_candidate": null,
- "confidence": 0.0
- }}
- """
- def ask(case):
- prompt = f"""
- Ticket #{case['ticket_number']}
- Betreff:
- {case['title'] or ''}
- KUNDEN:
- {case['customer_text'] or ''}
- KUNDENSERVICE:
- {case['agent_text'] or ''}
- SONSTIGE FACHLICHE ANTWORTEN:
- {case['unknown_text'] or ''}
- """
- payload = {
- "model": MODEL,
- "messages": [
- {
- "role": "system",
- "content": SYSTEM,
- },
- {
- "role": "user",
- "content": prompt,
- },
- ],
- "stream": False,
- "format": "json",
- "options": {
- "temperature": 0,
- },
- }
- request = urllib.request.Request(
- URL,
- data=json.dumps(payload).encode(),
- headers={
- "Content-Type": "application/json",
- },
- )
- started = time.time()
- with urllib.request.urlopen(
- request,
- timeout=300,
- ) as response:
- result = json.loads(
- response.read()
- )
- elapsed = time.time() - started
- content = result["message"]["content"]
- parsed = json.loads(content)
- return elapsed, parsed
- db = sqlite3.connect(DB)
- db.row_factory = sqlite3.Row
- rows = db.execute("""
- SELECT
- ticket_id,
- ticket_number,
- title,
- customer_text,
- agent_text,
- unknown_text
- FROM cases
- WHERE classification_status = 'NEW'
- ORDER BY ticket_id
- LIMIT 10
- """).fetchall()
- print("=" * 72)
- print("OLLAMA API TEST")
- print("=" * 72)
- print(f"Tickets: {len(rows)}")
- print(f"Modell: {MODEL}")
- print()
- for row in rows:
- elapsed, result = ask(row)
- print(
- f"#{row['ticket_number']} "
- f"{elapsed:.1f}s "
- f"→ {result.get('primary_intent')} "
- f"secondary={result.get('secondary_intents')} "
- f"confidence={result.get('confidence')}"
- )
- print(
- f" {result.get('summary', '')[:250]}"
- )
- db.close()
|