import React, { useEffect, useState } from 'react'; import { Sparkles, X } from 'lucide-react'; import { toast } from 'react-hot-toast'; import { Dialog, Button, Textarea, Field, Badge } from '../ui'; import { apiPost } from '../api/client'; import './Misc.css'; /** * DirectionDialog — Phase 4.2 per-segment direction editor. * * The user types a natural-language note ("urgent and surprised"). We call * /tools/direction to preview the parsed taxonomy tokens + instruct prompt + * rate bias — useful for seeing what the LLM/heuristic actually took away. * * On Save, the parent receives the raw direction string and persists it on * the segment. The dub pipeline re-parses at send time so the saved text is * always the canonical input. */ export default function DirectionDialog({ open, seg, onSave, onClose }) { const [text, setText] = useState(''); const [preview, setPreview] = useState(null); const [parsing, setParsing] = useState(false); const [saving, setSaving] = useState(false); useEffect(() => { if (open) { setText(seg?.direction || ''); setPreview(null); } }, [open, seg?.id, seg?.direction]); const runPreview = async () => { if (!text.trim()) { setPreview(null); return; } setParsing(true); try { setPreview(await apiPost('/tools/direction', { text })); } catch (e) { toast.error(`Preview failed: ${e.message}`); } finally { setParsing(false); } }; const save = async () => { setSaving(true); try { await onSave?.(text.trim()); onClose?.(); } finally { setSaving(false); } }; if (!open) return null; return ( Direction for segment #{seg?.id?.slice?.(0, 6) || ''}} footer={ <> {seg?.direction && ( )} } >

Tell the pipeline how this line should feel. Plain English works — the system maps your words onto a stable taxonomy (energy / emotion / pace / intimacy / formality), then threads the taxonomy through Cinematic translation, TTS, and slot-fit.

Line: "{seg.text.slice(0, 80)}{seg.text.length > 80 ? '…' : ''}" : null }>