Spaces:
Paused
Paused
| import { useState } from 'react' | |
| // Collapsible "view / edit the exact prompt before it runs" panel. | |
| // | |
| // `value` is the current prompt text (null = use the backend default). | |
| // `fetchPrompt` is an async () => string that assembles the default prompt | |
| // (some steps fetch live data to build it, so it may take a moment). | |
| // When the user edits the box, value diverges from the default — the run | |
| // button sends `value`; if the panel was never opened, value stays null and | |
| // the backend assembles the default itself. | |
| export default function PromptPanel({ fetchPrompt, value, setValue, disabled, label = 'prompt', open: openProp, setOpen: setOpenProp }) { | |
| const [openState, setOpenState] = useState(false) | |
| // Controlled when the parent passes open/setOpen (e.g. to auto-reveal prompts | |
| // after a bulk generate); otherwise self-managed. | |
| const controlled = openProp !== undefined | |
| const open = controlled ? openProp : openState | |
| const setOpen = controlled ? setOpenProp : setOpenState | |
| const [loading, setLoading] = useState(false) | |
| const [error, setError] = useState('') | |
| const [original, setOriginal] = useState(null) | |
| const load = async () => { | |
| setLoading(true) | |
| setError('') | |
| try { | |
| const p = await fetchPrompt() | |
| setValue(p) | |
| setOriginal(p) | |
| } catch (e) { | |
| setError(e.message) | |
| } finally { | |
| setLoading(false) | |
| } | |
| } | |
| const toggle = async () => { | |
| if (!open && value == null) await load() | |
| setOpen(!open) | |
| } | |
| const edited = value != null && original != null && value !== original | |
| return ( | |
| <div className="prompt-panel"> | |
| <button className="prompt-toggle" onClick={toggle} disabled={disabled}> | |
| {open ? '▾ Hide' : '▸ Show / edit'} the {label} prompt (advanced) | |
| {edited && <span className="edited-badge">● edited</span>} | |
| </button> | |
| {open && ( | |
| <div> | |
| <p className="prompt-hint"> | |
| This is the exact text sent to the model. Edit it to QC the output, then run. Your edits are used as-is. | |
| </p> | |
| {loading ? ( | |
| <p className="muted"><span className="spinner" />Assembling prompt…</p> | |
| ) : error ? ( | |
| <div className="error-box">{error}</div> | |
| ) : ( | |
| <textarea className="prompt-area" value={value || ''} onChange={(e) => setValue(e.target.value)} /> | |
| )} | |
| <button className="btn small secondary" onClick={load} disabled={loading}> | |
| ↺ Reset to default | |
| </button> | |
| </div> | |
| )} | |
| </div> | |
| ) | |
| } | |