feat(diarization-ui): add rename/delete for prompts/projects/documents and document move between projects

This commit is contained in:
2026-03-21 14:25:18 +01:00
parent 0f5a857b6e
commit f0d851a28a

80
app.py
View File

@@ -127,6 +127,12 @@ def get_projects():
return c.execute("SELECT id,name FROM projects ORDER BY name").fetchall() return c.execute("SELECT id,name FROM projects ORDER BY name").fetchall()
def get_project_name(project_id: int) -> str:
with db() as c:
r = c.execute("SELECT name FROM projects WHERE id=?", (project_id,)).fetchone()
return r[0] if r else ""
def get_prompts(): def get_prompts():
with db() as c: with db() as c:
return c.execute("SELECT id,name,prompt FROM prompts ORDER BY name").fetchall() return c.execute("SELECT id,name,prompt FROM prompts ORDER BY name").fetchall()
@@ -172,6 +178,29 @@ def add_project(name: str = Form(...)):
return HTMLResponse("<meta http-equiv='refresh' content='0; url=/prompts'>") return HTMLResponse("<meta http-equiv='refresh' content='0; url=/prompts'>")
@app.post("/projects/update", response_class=HTMLResponse)
def rename_project(id: int = Form(...), name: str = Form(...)):
with db() as c:
c.execute("UPDATE projects SET name=? WHERE id=?", (name.strip(), id))
return HTMLResponse("<meta http-equiv='refresh' content='0; url=/prompts'>")
@app.post("/projects/{project_id}/delete", response_class=HTMLResponse)
def delete_project(project_id: int):
with db() as c:
default = c.execute("SELECT id FROM projects WHERE name='Default'").fetchone()
if not default:
c.execute("INSERT INTO projects(name, created_at) VALUES (?,?)", ("Default", now_iso()))
default_id = c.execute("SELECT id FROM projects WHERE name='Default'").fetchone()[0]
else:
default_id = default[0]
if project_id == default_id:
return HTMLResponse("<meta http-equiv='refresh' content='0; url=/prompts'>")
c.execute("UPDATE documents SET project_id=? WHERE project_id=?", (default_id, project_id))
c.execute("DELETE FROM projects WHERE id=?", (project_id,))
return HTMLResponse("<meta http-equiv='refresh' content='0; url=/prompts'>")
@app.post("/upload", response_class=HTMLResponse) @app.post("/upload", response_class=HTMLResponse)
async def upload(project_id: int = Form(...), title: str = Form(""), file: UploadFile = File(...)): async def upload(project_id: int = Form(...), title: str = Form(""), file: UploadFile = File(...)):
data = await file.read() data = await file.read()
@@ -222,10 +251,17 @@ def library(project_id: Optional[int] = None):
p_opts = "<option value=''>Alle</option>" + "".join( p_opts = "<option value=''>Alle</option>" + "".join(
[f"<option value='{p['id']}' {'selected' if project_id==p['id'] else ''}>{p['name']}</option>" for p in projects] [f"<option value='{p['id']}' {'selected' if project_id==p['id'] else ''}>{p['name']}</option>" for p in projects]
) )
proj_opts = "".join([f"<option value='{p['id']}'>{p['name']}</option>" for p in projects])
items = "".join( items = "".join(
[ [
f"<div class='card'><b>#{d['id']}</b> [{d['kind']}] {d['title']}<br><small>{d['project']} · {d['created_at']}</small><br>" f"<div class='card'><b>#{d['id']}</b> [{d['kind']}] {d['title']}<br><small>{d['project']} · {d['created_at']}</small><br>"
f"<a href='/document/{d['id']}'>Ansehen</a> | <a href='/document/{d['id']}/download.md'>Download .md</a></div>" f"<a href='/document/{d['id']}'>Ansehen</a> | <a href='/document/{d['id']}/download.md'>Download .md</a>"
f"<form method='post' action='/document/{d['id']}/rename' class='row' style='margin-top:8px'>"
f"<input name='title' value='{d['title']}'><button>Umbenennen</button></form>"
f"<form method='post' action='/document/{d['id']}/move' class='row' style='margin-top:6px'>"
f"<select name='project_id'>{proj_opts}</select><button>Verschieben</button></form>"
f"<form method='post' action='/document/{d['id']}/delete' onsubmit=\"return confirm('Dokument löschen?')\" style='margin-top:6px'>"
f"<button>Löschen</button></form></div>"
for d in docs for d in docs
] ]
) )
@@ -275,6 +311,27 @@ def download_md(doc_id: int):
return PlainTextResponse(d["content_md"], headers={"Content-Disposition": f"attachment; filename=document_{doc_id}.md"}) return PlainTextResponse(d["content_md"], headers={"Content-Disposition": f"attachment; filename=document_{doc_id}.md"})
@app.post("/document/{doc_id}/rename", response_class=HTMLResponse)
def rename_document(doc_id: int, title: str = Form(...)):
with db() as c:
c.execute("UPDATE documents SET title=? WHERE id=?", (title.strip(), doc_id))
return HTMLResponse("<meta http-equiv='refresh' content='0; url=/library'>")
@app.post("/document/{doc_id}/move", response_class=HTMLResponse)
def move_document(doc_id: int, project_id: int = Form(...)):
with db() as c:
c.execute("UPDATE documents SET project_id=? WHERE id=?", (project_id, doc_id))
return HTMLResponse("<meta http-equiv='refresh' content='0; url=/library'>")
@app.post("/document/{doc_id}/delete", response_class=HTMLResponse)
def delete_document(doc_id: int):
with db() as c:
c.execute("DELETE FROM documents WHERE id=?", (doc_id,))
return HTMLResponse("<meta http-equiv='refresh' content='0; url=/library'>")
@app.get("/prompts", response_class=HTMLResponse) @app.get("/prompts", response_class=HTMLResponse)
def prompts_page(): def prompts_page():
with db() as c: with db() as c:
@@ -284,11 +341,20 @@ def prompts_page():
p_list = "".join( p_list = "".join(
[ [
f"<div class='card'><b>{p['name']}</b><pre>{(p['prompt'] or '').replace('<','&lt;')}</pre>" f"<div class='card'><b>{p['name']}</b><pre>{(p['prompt'] or '').replace('<','&lt;')}</pre>"
f"<form method='post' action='/prompts/update'><input type='hidden' name='id' value='{p['id']}'><input name='name' value='{p['name']}'><br><textarea name='prompt'>{p['prompt']}</textarea><br><button>Speichern</button></form></div>" f"<form method='post' action='/prompts/update'><input type='hidden' name='id' value='{p['id']}'><input name='name' value='{p['name']}'><br><textarea name='prompt'>{p['prompt']}</textarea><br><button>Speichern</button></form>"
f"<form method='post' action='/prompts/{p['id']}/delete' onsubmit=\"return confirm('Prompt löschen?')\" style='margin-top:6px'><button>Löschen</button></form>"
f"</div>"
for p in prompts for p in prompts
] ]
) )
project_opts = "".join([f"<option value='{p['name']}'>{p['name']}</option>" for p in projects]) project_opts = "".join([f"<option value='{p['name']}'>{p['name']}</option>" for p in projects])
project_list = "".join([
f"<div class='card'><b>{p['name']}</b>"
f"<form method='post' action='/projects/update' class='row' style='margin-top:6px'>"
f"<input type='hidden' name='id' value='{p['id']}'><input name='name' value='{p['name']}'><button>Umbenennen</button></form>"
f"<form method='post' action='/projects/{p['id']}/delete' onsubmit=\"return confirm('Projekt löschen? Dokumente werden auf Default verschoben.')\" style='margin-top:6px'><button>Löschen</button></form>"
f"</div>" for p in projects
])
body = f""" body = f"""
<h2>Prompt-Konfiguration</h2> <h2>Prompt-Konfiguration</h2>
@@ -308,6 +374,9 @@ def prompts_page():
<button type='submit'>Anlegen</button> <button type='submit'>Anlegen</button>
</form> </form>
</div> </div>
<h3>Projekte</h3>
{project_list}
<h3>Prompts</h3>
{p_list} {p_list}
""" """
return layout("Prompts", body) return layout("Prompts", body)
@@ -330,6 +399,13 @@ def prompt_update(id: int = Form(...), name: str = Form(...), prompt: str = Form
return HTMLResponse("<meta http-equiv='refresh' content='0; url=/prompts'>") return HTMLResponse("<meta http-equiv='refresh' content='0; url=/prompts'>")
@app.post("/prompts/{prompt_id}/delete", response_class=HTMLResponse)
def prompt_delete(prompt_id: int):
with db() as c:
c.execute("DELETE FROM prompts WHERE id=?", (prompt_id,))
return HTMLResponse("<meta http-equiv='refresh' content='0; url=/prompts'>")
@app.get("/run", response_class=HTMLResponse) @app.get("/run", response_class=HTMLResponse)
def run_page(): def run_page():
with db() as c: with db() as c: