feat: Structured prompt editing for Pro model

Backend:
- Added prompt_structure JSON column to clips DB (migration in init_db)
- Updated GenerateRequest model with optional prompt_structure dict
- build_prompt() method combines structured fields into single prompt:
  'Generate a track with the following elements:\n\n**Style:** [style]\n...'
- create_clip() accepts and stores prompt_structure JSON
- get_clips()/get_clip() parse prompt_structure back to dict

Frontend:
- New StructuredPromptEditor component with 8 collapsible fields:
  Style, Timbre, Structure, Mood, Tempo, Instrumentation, Effects, Additional
  - Fields show filled/empty state with colored dots
  - Expand/collapse individual fields
  - 'Expand All' button
  - Counter: 'X of 8 fields filled'
- Generator component updated with Basic/Advanced mode toggle (Pro only)
  - Basic: single textarea (works for both models)
  - Advanced: StructuredPromptEditor (Pro only)
  - Mode resets to Basic when switching to Clip Preview
- DetailPanel shows structured prompt breakdown when present
  - Each filled field shown in its own labeled box
  - Style, Timbre, Structure, Mood, Tempo, Instrumentation, Effects, Additional
- Clip interface updated with prompt_structure field across all components

Architecture KB and Tasks KB updated.
This commit is contained in:
rin.kagamine committed 2026-05-29 22:28:52 -04:00
1 parent a79b2806dc
commit 70beb89ad9
8 files changed
+273 -25

No files matched your search

+7 -2
View File
@@ -77,13 +77,18 @@ async def _generate_and_save(clip_id: str, prompt: str, model: str, duration: in
@app.post("/api/generate", response_model=GenerateResponse)
async def generate(request: GenerateRequest, background_tasks: BackgroundTasks):
duration = request.get_effective_duration()
clip_id = await create_clip(request.prompt, request.model, duration)
# Build prompt from structured fields if present
final_prompt = request.build_prompt()
# Serialize structured prompt for DB storage
import json
prompt_structure_json = json.dumps(request.prompt_structure) if request.prompt_structure else None
clip_id = await create_clip(final_prompt, request.model, duration, prompt_structure_json)
# Kick off generation in background
background_tasks.add_task(
_generate_and_save,
clip_id,
request.prompt,
final_prompt,
request.model,
duration
)