Admin: KI-Anfragen nach Quelle aufschlüsseln (cloud/local/luna)
- ki_daily_calls: PK auf (user_id, date, source) erweitert + Index; Migration baut Tabelle mit neuer Struktur neu auf, behält Altdaten als 'cloud' - ki.py: return_source=True-Parameter gibt (text, 'cloud'|'local') zurück - training.py: ki_source aus ki.complete() auslesen, in DB speichern - social.py: _ki_complete_tracked() zählt Luna-Anfragen mit source='luna'; alle Content-Endpoints (generate, evaluate, training-tip, breed-of-day, pflege-tipp) nutzen tracking-Variante - admin.py: Stats aufgeteilt in ki_cloud/ki_local/ki_luna je heute+Monat - admin.js: KI-Karte zeigt 9 Zeilen mit ☁️ Claude / 🖥️ LM Studio / 🌙 Luna - SW by-v359, APP_VER 344
This commit is contained in:
parent
74b6c03bb3
commit
8d5c7a19b1
6 changed files with 136 additions and 33 deletions
|
|
@ -466,9 +466,19 @@ _PFLEGE_TIPPS = [
|
|||
"fell_typ":"lang","saison":None,"tipp":"Von Beinen und Schwanz beginnen — dort filzt es zuerst."},
|
||||
{"id":"fell_buersten_lockig","titel":"Pflege bei Lockenfell (Pudel, Labradoodle)","kat":"Fell",
|
||||
"beschreibung":"Lockiges Fell verliert kaum Haare, verfilzt aber stark — spezielle Technik nötig.",
|
||||
"schritte":["Täglich durchkämmen mit Metallkamm","Verfilzungen mit Finger lösen, dann Kamm","Alle 6–8 Wochen Schertermin","Zwischen Augen und Pfoten regelmäßig trimmen"],
|
||||
"schritte":["Täglich durchkämmen mit Metallkamm","Verfilzungen mit Finger lösen, dann Kamm","Alle 6–8 Wochen Schertermin","Zwischen Augen und Pfoten regelmäßig kürzen"],
|
||||
"materialien":"Metallkamm, Pin-Bürste, Schere","haeufigkeit":"Täglich + 6–8 Wochen Schertermin",
|
||||
"fell_typ":"lockig","saison":None,"tipp":"Lockiges Fell = hypoallergen, aber Pflegeaufwand unterschätzt!"},
|
||||
"fell_typ":"lockig","saison":None,"fell_pflege_art":"schneiden","tipp":"Lockiges Fell = hypoallergen, aber Pflegeaufwand unterschätzt!"},
|
||||
{"id":"fell_scheren_technik","titel":"Fell schneiden: Technik & Scheren-Tipps","kat":"Fell",
|
||||
"beschreibung":"Für Rassen mit kontinuierlichem Fellwuchs (Pudel, Bichon, Spoodle) — Scheren statt Trimmen!",
|
||||
"schritte":["Fell nach dem Bad komplett trocknen und bürsten","Schere oder Clipper parallel zur Haarwuchsrichtung führen","Empfindliche Stellen (Gesicht, Pfoten) mit Effilierschere","Alle 6–8 Wochen zum Groomer oder selbst lernen","Nach dem Scheren: Fell bürsten und kontrollieren"],
|
||||
"materialien":"Effilierschere, Clipper, Metallkamm","haeufigkeit":"Alle 6–8 Wochen",
|
||||
"fell_typ":"lockig","saison":None,"fell_pflege_art":"schneiden","tipp":"Nie nasses Fell scheren — immer erst trocknen, sonst ungleichmäßiges Ergebnis."},
|
||||
{"id":"fell_trimmen_technik","titel":"Fell trimmen: Stripping beim Rauhaar-Terrier","kat":"Fell",
|
||||
"beschreibung":"Rauhaardrahtiges Fell (Westie, Schnauzer, Jack Russell) hat natürliche Wachstumsbegrenzung — Trimmen statt Scheren!",
|
||||
"schritte":["Daumen und Zeigefinger: abgestorbene Haare zupfen (Stripping)","Immer in Haarwuchsrichtung arbeiten","Unterwolle mit feinem Rake ausbürsten","Niemals scheren — zerstört Textur dauerhaft","Alle 3–4 Monate professionelles Hand-Stripping"],
|
||||
"materialien":"Stripper-Messer (Trimmmesser), Rake, Kreide für Grip","haeufigkeit":"Alle 3–4 Monate",
|
||||
"fell_typ":"alle","saison":None,"fell_pflege_art":"trimmen","tipp":"Geschorenes Drahthaarfell verliert seine typische Textur dauerhaft — immer trimmen!"},
|
||||
{"id":"fell_unterwolle", "titel":"Unterwolle ausbürsten (Fellwechsel)","kat":"Fell",
|
||||
"beschreibung":"Zweimal jährlich toter Unterwolle-Berg — richtig ausgebürstet statt überall verteilt.",
|
||||
"schritte":["Undercoat-Rake gegen Haarwuchsrichtung","Abschnittweise: Rücken, Flanken, Bauch","Furminator maximal 2x/Woche","Nach dem Bürsten: Hund ausschütteln lassen"],
|
||||
|
|
@ -949,6 +959,28 @@ async def _ki_complete(prompt: str) -> str:
|
|||
)
|
||||
|
||||
|
||||
async def _ki_complete_tracked(prompt: str, user_id: int) -> str:
|
||||
"""Wie _ki_complete, zählt die Anfrage in ki_daily_calls (source='luna')."""
|
||||
import datetime as _dt
|
||||
import ki as ki_module
|
||||
text = await ki_module.complete(
|
||||
prompt,
|
||||
system=_SYSTEM,
|
||||
max_tokens=1200,
|
||||
requires_premium=False,
|
||||
)
|
||||
today = str(_dt.date.today())
|
||||
try:
|
||||
with db() as conn:
|
||||
conn.execute("""
|
||||
INSERT INTO ki_daily_calls (user_id, date, count, source) VALUES (?, ?, 1, 'luna')
|
||||
ON CONFLICT(user_id, date, source) DO UPDATE SET count = count + 1
|
||||
""", (user_id, today))
|
||||
except Exception:
|
||||
pass
|
||||
return text
|
||||
|
||||
|
||||
def _parse_json(raw: str) -> dict:
|
||||
import re
|
||||
try:
|
||||
|
|
@ -1064,7 +1096,7 @@ async def generate_content(req: GenerateRequest, user=Depends(require_social_med
|
|||
)
|
||||
|
||||
try:
|
||||
raw = await _ki_complete(prompt)
|
||||
raw = await _ki_complete_tracked(prompt, user["id"])
|
||||
data = _parse_json(raw)
|
||||
except Exception as e:
|
||||
logger.error("Social-Media-Generierung fehlgeschlagen: %s", e)
|
||||
|
|
@ -1113,7 +1145,7 @@ async def evaluate_content(req: EvaluateRequest, user=Depends(require_social_med
|
|||
)
|
||||
|
||||
try:
|
||||
raw = await _ki_complete(prompt)
|
||||
raw = await _ki_complete_tracked(prompt, user["id"])
|
||||
data = _parse_json(raw)
|
||||
except Exception as e:
|
||||
raise HTTPException(500, f"KI-Fehler: {e}")
|
||||
|
|
@ -1197,13 +1229,21 @@ def _seed_pflege():
|
|||
conn.execute(
|
||||
"""INSERT OR IGNORE INTO pflege_tipps
|
||||
(tipp_id, titel, kategorie, beschreibung, schritte,
|
||||
materialien, haeufigkeit, fell_typ, saison, rassengruppe, tipp)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?)""",
|
||||
materialien, haeufigkeit, fell_typ, saison, rassengruppe, tipp,
|
||||
fell_pflege_art)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?)""",
|
||||
(p["id"], p["titel"], p["kat"],
|
||||
p.get("beschreibung"), json.dumps(p.get("schritte", []), ensure_ascii=False),
|
||||
p.get("materialien"), p.get("haeufigkeit"),
|
||||
p.get("fell_typ"), p.get("saison"), p.get("rassengruppe"), p.get("tipp")),
|
||||
p.get("fell_typ"), p.get("saison"), p.get("rassengruppe"), p.get("tipp"),
|
||||
p.get("fell_pflege_art")),
|
||||
)
|
||||
# UPDATE für bereits bestehende Tipps (idempotent)
|
||||
if p.get("fell_pflege_art"):
|
||||
conn.execute(
|
||||
"UPDATE pflege_tipps SET fell_pflege_art=? WHERE tipp_id=? AND (fell_pflege_art IS NULL OR fell_pflege_art != ?)",
|
||||
(p["fell_pflege_art"], p["id"], p["fell_pflege_art"]),
|
||||
)
|
||||
|
||||
try:
|
||||
_seed_exercises()
|
||||
|
|
@ -1251,7 +1291,7 @@ async def training_tip(user=Depends(require_social_media)):
|
|||
)
|
||||
|
||||
try:
|
||||
raw = await _ki_complete(prompt)
|
||||
raw = await _ki_complete_tracked(prompt, user["id"])
|
||||
data = _parse_json(raw)
|
||||
except Exception as e:
|
||||
raise HTTPException(500, f"KI-Fehler: {e}")
|
||||
|
|
@ -1407,7 +1447,7 @@ async def breed_of_day(user=Depends(require_social_media)):
|
|||
)
|
||||
|
||||
try:
|
||||
raw = await _ki_complete(prompt)
|
||||
raw = await _ki_complete_tracked(prompt, user["id"])
|
||||
data = _parse_json(raw)
|
||||
except Exception as e:
|
||||
raise HTTPException(500, f"KI-Fehler: {e}")
|
||||
|
|
@ -1546,7 +1586,7 @@ async def pflege_tipp(breed_id: Optional[int] = None, user=Depends(require_socia
|
|||
)
|
||||
|
||||
try:
|
||||
raw = await _ki_complete(prompt)
|
||||
raw = await _ki_complete_tracked(prompt, user["id"])
|
||||
data = _parse_json(raw)
|
||||
except Exception as e:
|
||||
raise HTTPException(500, f"KI-Fehler: {e}")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue