update
This commit is contained in:
@@ -365,7 +365,7 @@ FORMAT-SPEZIFIKATION:
|
|||||||
REFERENZ-BEISPIEL:
|
REFERENZ-BEISPIEL:
|
||||||
{reference}
|
{reference}
|
||||||
|
|
||||||
Schlage 8 Bausteine vor. Antworte AUSSCHLIESSLICH mit einem JSON-Array. Jedes Element hat:
|
Schlage 40 Bausteine vor. Antworte AUSSCHLIESSLICH mit einem JSON-Array. Jedes Element hat:
|
||||||
- "title"
|
- "title"
|
||||||
- "description"
|
- "description"
|
||||||
- "purpose"
|
- "purpose"
|
||||||
@@ -375,9 +375,10 @@ Orientiere dich an der Spezifikation und Referenz. NUR das JSON-Array, kein weit
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def _build_baustein_detail_prompt(topic: str, title: str) -> str:
|
def _build_baustein_detail_prompt(topic: str, title: str, instructions: str = "") -> str:
|
||||||
spec = (TEMPLATES_DIR / "Format" / "Baustein.md").read_text(encoding="utf-8")
|
spec = (TEMPLATES_DIR / "Format" / "Baustein.md").read_text(encoding="utf-8")
|
||||||
reference = (TEMPLATES_DIR / "Referenz" / "Baustein.md").read_text(encoding="utf-8")
|
reference = (TEMPLATES_DIR / "Referenz" / "Baustein.md").read_text(encoding="utf-8")
|
||||||
|
extra = f"\n\nZUSÄTZLICHE INFOS VOM NUTZER:\n{instructions}\n" if instructions else ""
|
||||||
|
|
||||||
return f"""Generiere Details für den Baustein "{title}" im Kontext des Themas "{topic}".
|
return f"""Generiere Details für den Baustein "{title}" im Kontext des Themas "{topic}".
|
||||||
|
|
||||||
@@ -386,7 +387,7 @@ FORMAT-SPEZIFIKATION:
|
|||||||
|
|
||||||
REFERENZ-BEISPIEL:
|
REFERENZ-BEISPIEL:
|
||||||
{reference}
|
{reference}
|
||||||
|
{extra}
|
||||||
Antworte AUSSCHLIESSLICH mit einem JSON-Objekt mit den Feldern "description", "purpose", "examples".
|
Antworte AUSSCHLIESSLICH mit einem JSON-Objekt mit den Feldern "description", "purpose", "examples".
|
||||||
"examples" ist ein Array mit 1 Objekt {{"label": "...", "code": "..."}}.
|
"examples" ist ein Array mit 1 Objekt {{"label": "...", "code": "..."}}.
|
||||||
Orientiere dich an der Spezifikation und Referenz. Kein weiterer Text, nur das JSON.
|
Orientiere dich an der Spezifikation und Referenz. Kein weiterer Text, nur das JSON.
|
||||||
@@ -403,7 +404,7 @@ async def generate_suggestions(topic: str, html_paths: list[Path]) -> None:
|
|||||||
|
|
||||||
prompt = _build_suggestions_prompt(topic, html_paths, existing_titles)
|
prompt = _build_suggestions_prompt(topic, html_paths, existing_titles)
|
||||||
tools = "Read" if html_paths else None
|
tools = "Read" if html_paths else None
|
||||||
returncode, stdout, stderr = await _run_claude("suggestions-" + topic, prompt, 180, tools=tools, model=MODEL_BAUSTEIN_GEN)
|
returncode, stdout, stderr = await _run_claude("suggestions-" + topic, prompt, 1800, tools=tools, model=MODEL_BAUSTEIN_GEN)
|
||||||
|
|
||||||
if returncode != 0:
|
if returncode != 0:
|
||||||
return
|
return
|
||||||
@@ -414,7 +415,7 @@ async def generate_suggestions(topic: str, html_paths: list[Path]) -> None:
|
|||||||
|
|
||||||
now = datetime.now(timezone.utc).isoformat()
|
now = datetime.now(timezone.utc).isoformat()
|
||||||
suggestions = []
|
suggestions = []
|
||||||
for item in items[:8]:
|
for item in items[:40]:
|
||||||
suggestions.append({
|
suggestions.append({
|
||||||
"id": str(uuid.uuid4()),
|
"id": str(uuid.uuid4()),
|
||||||
"topic": topic,
|
"topic": topic,
|
||||||
@@ -433,9 +434,9 @@ async def generate_suggestions(topic: str, html_paths: list[Path]) -> None:
|
|||||||
_suggestions_generating.discard(topic)
|
_suggestions_generating.discard(topic)
|
||||||
|
|
||||||
|
|
||||||
async def generate_baustein_detail(baustein_id: str, topic: str, title: str) -> None:
|
async def generate_baustein_detail(baustein_id: str, topic: str, title: str, instructions: str = "") -> None:
|
||||||
try:
|
try:
|
||||||
prompt = _build_baustein_detail_prompt(topic, title)
|
prompt = _build_baustein_detail_prompt(topic, title, instructions)
|
||||||
returncode, stdout, stderr = await _run_claude("baustein-" + baustein_id, prompt, 60, tools=None, model=MODEL_BAUSTEIN_GEN)
|
returncode, stdout, stderr = await _run_claude("baustein-" + baustein_id, prompt, 60, tools=None, model=MODEL_BAUSTEIN_GEN)
|
||||||
|
|
||||||
if returncode != 0:
|
if returncode != 0:
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ class GuideResponse(BaseModel):
|
|||||||
class BausteinCreateRequest(BaseModel):
|
class BausteinCreateRequest(BaseModel):
|
||||||
topic: str = Field(min_length=1, max_length=100)
|
topic: str = Field(min_length=1, max_length=100)
|
||||||
title: str = Field(min_length=1, max_length=200)
|
title: str = Field(min_length=1, max_length=200)
|
||||||
|
instructions: str = Field(default="", max_length=2000)
|
||||||
|
|
||||||
|
|
||||||
class BausteinReworkRequest(BaseModel):
|
class BausteinReworkRequest(BaseModel):
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ async def add_baustein(req: BausteinCreateRequest):
|
|||||||
"updated_at": now,
|
"updated_at": now,
|
||||||
}
|
}
|
||||||
await db_create_baustein(baustein)
|
await db_create_baustein(baustein)
|
||||||
asyncio.create_task(generate_baustein_detail(baustein["id"], baustein["topic"], baustein["title"]))
|
asyncio.create_task(generate_baustein_detail(baustein["id"], baustein["topic"], baustein["title"], req.instructions.strip()))
|
||||||
return baustein
|
return baustein
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -49,11 +49,11 @@ export async function fetchBausteine(topic) {
|
|||||||
return res.json()
|
return res.json()
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createBaustein(topic, title) {
|
export async function createBaustein(topic, title, instructions = '') {
|
||||||
const res = await fetch(`${BASE}/bausteine`, {
|
const res = await fetch(`${BASE}/bausteine`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ topic, title }),
|
body: JSON.stringify({ topic, title, instructions }),
|
||||||
})
|
})
|
||||||
return res.json()
|
return res.json()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ const bausteine = ref([])
|
|||||||
const suggestions = ref([])
|
const suggestions = ref([])
|
||||||
const suggestionsLoading = ref(false)
|
const suggestionsLoading = ref(false)
|
||||||
const newTitle = ref('')
|
const newTitle = ref('')
|
||||||
|
const newInfo = ref('')
|
||||||
const reworkInputs = ref({})
|
const reworkInputs = ref({})
|
||||||
const reworkingIds = ref(new Set())
|
const reworkingIds = ref(new Set())
|
||||||
const reworkingSnapshots = new Map()
|
const reworkingSnapshots = new Map()
|
||||||
@@ -55,8 +56,10 @@ async function checkAndGenerate() {
|
|||||||
async function handleAdd() {
|
async function handleAdd() {
|
||||||
const title = newTitle.value.trim()
|
const title = newTitle.value.trim()
|
||||||
if (!title) return
|
if (!title) return
|
||||||
|
const info = newInfo.value.trim()
|
||||||
newTitle.value = ''
|
newTitle.value = ''
|
||||||
const created = await createBaustein(props.topic, title)
|
newInfo.value = ''
|
||||||
|
const created = await createBaustein(props.topic, title, info)
|
||||||
bausteine.value.push(created)
|
bausteine.value.push(created)
|
||||||
reworkingSnapshots.set(created.id, created.updated_at)
|
reworkingSnapshots.set(created.id, created.updated_at)
|
||||||
reworkingIds.value = new Set([...reworkingIds.value, created.id])
|
reworkingIds.value = new Set([...reworkingIds.value, created.id])
|
||||||
@@ -168,12 +171,18 @@ onUnmounted(stopPolling)
|
|||||||
<div class="bausteine-view">
|
<div class="bausteine-view">
|
||||||
<div class="bausteine-grid">
|
<div class="bausteine-grid">
|
||||||
<div class="card new-card">
|
<div class="card new-card">
|
||||||
|
<h3>Neuer Baustein</h3>
|
||||||
<input
|
<input
|
||||||
v-model="newTitle"
|
v-model="newTitle"
|
||||||
placeholder="Neuer Baustein…"
|
placeholder="Thema…"
|
||||||
@keyup.enter="handleAdd"
|
@keyup.enter="handleAdd"
|
||||||
/>
|
/>
|
||||||
<button @click="handleAdd" :disabled="!newTitle.trim()">+</button>
|
<textarea
|
||||||
|
v-model="newInfo"
|
||||||
|
placeholder="Zusätzliche Infos (optional)…"
|
||||||
|
rows="4"
|
||||||
|
></textarea>
|
||||||
|
<button class="new-btn" @click="handleAdd" :disabled="!newTitle.trim()">Generieren</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-for="b in bausteine" :key="b.id" class="card">
|
<div v-for="b in bausteine" :key="b.id" class="card">
|
||||||
@@ -272,41 +281,52 @@ onUnmounted(stopPolling)
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
|
max-height: 400px;
|
||||||
|
overflow-y: auto;
|
||||||
|
overscroll-behavior: contain;
|
||||||
}
|
}
|
||||||
|
|
||||||
.new-card {
|
.new-card {
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
background: #f8f9fb;
|
background: #f8f9fb;
|
||||||
border-style: dashed;
|
border-style: dashed;
|
||||||
}
|
}
|
||||||
|
|
||||||
.new-card input {
|
.new-card h3 {
|
||||||
flex: 1;
|
font-size: 0.95rem;
|
||||||
|
color: #1a1a1a;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.new-card input,
|
||||||
|
.new-card textarea {
|
||||||
|
width: 100%;
|
||||||
padding: 8px 10px;
|
padding: 8px 10px;
|
||||||
border: 1px solid #d8dde3;
|
border: 1px solid #d8dde3;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
font-size: 0.9rem;
|
font-size: 0.85rem;
|
||||||
|
font-family: inherit;
|
||||||
outline: none;
|
outline: none;
|
||||||
|
resize: vertical;
|
||||||
}
|
}
|
||||||
|
|
||||||
.new-card input:focus {
|
.new-card input:focus,
|
||||||
|
.new-card textarea:focus {
|
||||||
border-color: #6366f1;
|
border-color: #6366f1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.new-card button {
|
.new-btn {
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
border: none;
|
border: none;
|
||||||
background: #6366f1;
|
background: #6366f1;
|
||||||
color: white;
|
color: white;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
font-size: 1rem;
|
font-size: 0.85rem;
|
||||||
font-weight: 700;
|
font-weight: 600;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
margin-top: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.new-card button:disabled {
|
.new-btn:disabled {
|
||||||
opacity: 0.4;
|
opacity: 0.4;
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user