feat: AI Dungeon Master engine + web frontend

- Engine: stato SQLite, state machine, 10 approved tools, parser azioni
- LLM: multi-provider (Ollama/OpenRouter/Local), system prompt DCC
- DM cycle: LLM decide tool → engine esegue → narrazione + meccanica
- Dati avventura: JSON machine-readable con 9 aree, mostri, enigmi, quest
- Web: FastAPI + WebSocket backend, SPA frontend dark fantasy
- Ref: architecture-patterns/neon-scratch-lounge (separazione reasoning/execution)
This commit is contained in:
truetype committed 2026-06-26 20:31:34 +02:00
1 parent ae73fe43d3
commit 90f823fdb9
17 files changed
+4082

No files matched your search

+35
View File
@@ -0,0 +1,35 @@
from __future__ import annotations
import os
from dataclasses import dataclass
from typing import Literal
ProviderKind = Literal["ollama", "openrouter", "local"]
@dataclass
class ProviderConfig:
kind: ProviderKind = "openrouter"
ollama_base_url: str = "http://192.168.0.50:11434"
ollama_model: str = "gemma2:9b"
openrouter_api_key: str = ""
openrouter_model: str = "openrouter/free"
openrouter_free_fallback: bool = True
local_base_url: str = "http://192.168.0.240/v1"
local_api_key: str = ""
local_model: str = "big-pickle"
timeout: int = 60
def load_from_env() -> ProviderConfig:
return ProviderConfig(
kind=os.getenv("DCC_LLM_PROVIDER", "openrouter"), # type: ignore
ollama_base_url=os.getenv("DCC_OLLAMA_URL", "http://192.168.0.50:11434"),
ollama_model=os.getenv("DCC_OLLAMA_MODEL", "gemma2:9b"),
openrouter_api_key=os.getenv("OPENROUTER_API_KEY", ""),
openrouter_model=os.getenv("DCC_OPENROUTER_MODEL", "openrouter/free"),
openrouter_free_fallback=os.getenv("DCC_OR_FREE_FALLBACK", "1") == "1",
local_base_url=os.getenv("DCC_LOCAL_URL", "http://192.168.0.240/v1"),
local_api_key=os.getenv("DCC_LOCAL_KEY", ""),
local_model=os.getenv("DCC_LOCAL_MODEL", "big-pickle"),
timeout=int(os.getenv("DCC_LLM_TIMEOUT", "60")),
)