update
This commit is contained in:
@@ -53,6 +53,16 @@ PROVIDERS = {
|
||||
"quick": "minimax/MiniMax-M2.7-highspeed",
|
||||
"env_key": "MINIMAX_API_KEY",
|
||||
},
|
||||
# Wie "minimax", aber Chat/Elemente (Rolle "fast") laufen auf M3 OHNE Thinking.
|
||||
# M2.x kann Thinking nicht abschalten — nur M3 respektiert thinking:disabled.
|
||||
# guide/quick bleiben identisch zur Thinking-Variante.
|
||||
"minimax-direkt": {
|
||||
"cli": "opencode",
|
||||
"guide": "minimax/MiniMax-M3",
|
||||
"fast": "minimax-direkt/MiniMax-M3",
|
||||
"quick": "minimax/MiniMax-M2.7-highspeed",
|
||||
"env_key": "MINIMAX_API_KEY",
|
||||
},
|
||||
"lokal": {
|
||||
"cli": "opencode",
|
||||
"guide": "ollama/qwen3.6:27b",
|
||||
|
||||
@@ -42,6 +42,8 @@ CREATE TABLE IF NOT EXISTS elements (
|
||||
description TEXT NOT NULL DEFAULT '',
|
||||
examples TEXT NOT NULL DEFAULT '[]',
|
||||
hints TEXT NOT NULL DEFAULT '[]',
|
||||
aufgabe TEXT NOT NULL DEFAULT '',
|
||||
loesung TEXT NOT NULL DEFAULT '',
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
)
|
||||
@@ -68,6 +70,11 @@ async def init_db():
|
||||
await db.execute("ALTER TABLE guides ADD COLUMN step INTEGER")
|
||||
except aiosqlite.OperationalError:
|
||||
pass
|
||||
for col in ("aufgabe", "loesung"): # Migration für Elemente ohne Aufgabe/Lösung
|
||||
try:
|
||||
await db.execute(f"ALTER TABLE elements ADD COLUMN {col} TEXT NOT NULL DEFAULT ''")
|
||||
except aiosqlite.OperationalError:
|
||||
pass
|
||||
await db.execute(
|
||||
"UPDATE guides SET status = 'error', progress = NULL, error_msg = 'Server-Neustart' "
|
||||
"WHERE status IN ('queued', 'generating')"
|
||||
@@ -166,8 +173,8 @@ def _element_row(row, cursor) -> dict:
|
||||
async def create_element(element: dict) -> dict:
|
||||
db = await get_db()
|
||||
await db.execute(
|
||||
"""INSERT INTO elements (id, topic, title, description, examples, hints, created_at, updated_at)
|
||||
VALUES (:id, :topic, :title, :description, :examples, :hints, :created_at, :updated_at)""",
|
||||
"""INSERT INTO elements (id, topic, title, description, examples, hints, aufgabe, loesung, created_at, updated_at)
|
||||
VALUES (:id, :topic, :title, :description, :examples, :hints, :aufgabe, :loesung, :created_at, :updated_at)""",
|
||||
{**element, "examples": json.dumps(element["examples"], ensure_ascii=False),
|
||||
"hints": json.dumps(element["hints"], ensure_ascii=False)},
|
||||
)
|
||||
|
||||
@@ -1396,6 +1396,8 @@ def _element_fields(data: dict) -> dict | None:
|
||||
"description": str(data.get("description", "")).strip(),
|
||||
"examples": listen["examples"],
|
||||
"hints": listen["hints"],
|
||||
"aufgabe": str(data.get("aufgabe", "")).strip(),
|
||||
"loesung": str(data.get("loesung", "")).strip(),
|
||||
}
|
||||
|
||||
|
||||
@@ -1418,7 +1420,7 @@ def _topic_context(topic: str, limit: int = 12000) -> str:
|
||||
|
||||
async def generate_element(topic: str, hint: str, provider: str = DEFAULT_PROVIDER) -> dict:
|
||||
"""Erstellt Element-Felder per KI. Fallback: nur Titel aus dem Stichwort."""
|
||||
fallback = {"title": hint.strip() or "Neues Element", "description": "", "examples": [], "hints": []}
|
||||
fallback = {"title": hint.strip() or "Neues Element", "description": "", "examples": [], "hints": [], "aufgabe": "", "loesung": ""}
|
||||
try:
|
||||
prompt = _prompt(
|
||||
"Element-Create",
|
||||
@@ -1454,7 +1456,7 @@ def _parse_suggestions(stdout: str) -> list[dict] | None:
|
||||
text = str(s.get("text", "")).strip()
|
||||
target = s.get("target")
|
||||
content = str(s.get("content", "")).strip()
|
||||
if text and content and target in ("description", "examples", "hints"):
|
||||
if text and content and target in ("description", "examples", "hints", "aufgabe", "loesung"):
|
||||
if target == "examples":
|
||||
content = _fence(content)
|
||||
suggestions.append({"text": text, "target": target, "content": content})
|
||||
@@ -1465,7 +1467,7 @@ async def check_element(element: dict, provider: str = DEFAULT_PROVIDER) -> list
|
||||
"""Zweischrittige Prüfung auf fehlende Infos: Recherche → Verifizieren. None bei Fehler."""
|
||||
try:
|
||||
element_json = json.dumps(
|
||||
{k: element[k] for k in ("title", "description", "examples", "hints")},
|
||||
{k: element[k] for k in ("title", "description", "examples", "hints", "aufgabe", "loesung")},
|
||||
ensure_ascii=False, indent=1,
|
||||
)
|
||||
context = _topic_context(element["topic"])
|
||||
@@ -1502,7 +1504,7 @@ async def check_element(element: dict, provider: str = DEFAULT_PROVIDER) -> list
|
||||
|
||||
def _element_json(element: dict) -> str:
|
||||
return json.dumps(
|
||||
{k: element[k] for k in ("title", "description", "examples", "hints")},
|
||||
{k: element[k] for k in ("title", "description", "examples", "hints", "aufgabe", "loesung")},
|
||||
ensure_ascii=False, indent=1,
|
||||
)
|
||||
|
||||
@@ -1518,7 +1520,7 @@ def _validate_change(c, element: dict) -> dict | None:
|
||||
content = str(c.get("content", "")).strip()
|
||||
if not text or action not in ("entfernen", "anpassen", "hinzufuegen"):
|
||||
return None
|
||||
if target not in ("title", "description", "examples", "hints"):
|
||||
if target not in ("title", "description", "examples", "hints", "aufgabe", "loesung"):
|
||||
return None
|
||||
if action in ("anpassen", "hinzufuegen") and not content:
|
||||
return None
|
||||
|
||||
@@ -8,7 +8,7 @@ FormatType = Literal[
|
||||
"FullGuide",
|
||||
]
|
||||
|
||||
ProviderType = Literal["claude", "minimax", "lokal"]
|
||||
ProviderType = Literal["claude", "minimax", "minimax-direkt", "lokal"]
|
||||
|
||||
|
||||
class GuideCreateRequest(BaseModel):
|
||||
@@ -86,6 +86,8 @@ class ElementResponse(BaseModel):
|
||||
description: str = ""
|
||||
examples: list[str] = []
|
||||
hints: list[str] = []
|
||||
aufgabe: str = ""
|
||||
loesung: str = ""
|
||||
created_at: str
|
||||
updated_at: str
|
||||
|
||||
@@ -101,6 +103,8 @@ class ElementUpdateRequest(BaseModel):
|
||||
description: str | None = None
|
||||
examples: list[str] | None = None
|
||||
hints: list[str] | None = None
|
||||
aufgabe: str | None = None
|
||||
loesung: str | None = None
|
||||
|
||||
|
||||
class ElementCheckRequest(BaseModel):
|
||||
@@ -109,7 +113,7 @@ class ElementCheckRequest(BaseModel):
|
||||
|
||||
class ElementSuggestion(BaseModel):
|
||||
text: str
|
||||
target: Literal["description", "examples", "hints"]
|
||||
target: Literal["description", "examples", "hints", "aufgabe", "loesung"]
|
||||
content: str
|
||||
|
||||
|
||||
@@ -120,7 +124,7 @@ class ElementCheckResponse(BaseModel):
|
||||
class ElementStyleChange(BaseModel):
|
||||
text: str
|
||||
action: Literal["entfernen", "anpassen", "hinzufuegen"]
|
||||
target: Literal["title", "description", "examples", "hints"]
|
||||
target: Literal["title", "description", "examples", "hints", "aufgabe", "loesung"]
|
||||
index: int | None = None
|
||||
content: str = ""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user