mirror of
https://github.com/JezzWTF/vibepod.git
synced 2026-06-13 03:58:07 +00:00
feat(phase-1): persistent generation library
- Save every completed generation to SQLite (generation_store.py) with WAV and waveform peaks written to data/generations/<id>/ - Deferred DB write until success — cancelled/errored generations never touch the DB and never appear in the library - Fixed cancel+regenerate IndexError: _reset_scheduler_caches() now directly zeros scheduler._step_index and running state in addition to clearing VibePod cache dicts; same explicit resets added in the fresh path of prepare_noise_scheduler as belt-and-suspenders - Added /library page with GenerationCard, WaveformPreview, waveform fetch, play/pause, download, delete, pagination, empty + error states - Added generation API routes (list, single, audio stream, waveform, delete) proxying to Python server - Added Library nav link to Header with active state - Persist script/speaker/CFG to localStorage so generate page state survives navigation - Updated build plan: Phase 0+1 ticked off, better-sqlite3 moved to Phase 2, architectural note on Python owning all persistence
This commit is contained in:
+32
-1
@@ -171,8 +171,39 @@ const initialState: AppState = {
|
||||
serverConfig: null,
|
||||
};
|
||||
|
||||
const STORAGE_KEY = "vibepod_form";
|
||||
|
||||
function loadSavedForm(): Partial<Pick<AppState, "script" | "speaker" | "cfgScale">> {
|
||||
if (typeof window === "undefined") return {};
|
||||
try {
|
||||
const raw = localStorage.getItem(STORAGE_KEY);
|
||||
if (!raw) return {};
|
||||
return JSON.parse(raw) as Partial<Pick<AppState, "script" | "speaker" | "cfgScale">>;
|
||||
} catch {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
export default function HomePage() {
|
||||
const [state, dispatch] = useReducer(reducer, initialState);
|
||||
const [state, dispatch] = useReducer(reducer, initialState, (base) => {
|
||||
const saved = loadSavedForm();
|
||||
return {
|
||||
...base,
|
||||
...(saved.script !== undefined && { script: saved.script }),
|
||||
...(saved.speaker !== undefined && { speaker: saved.speaker }),
|
||||
...(typeof saved.cfgScale === "number" && { cfgScale: saved.cfgScale }),
|
||||
};
|
||||
});
|
||||
|
||||
// Persist user-editable form fields across navigation.
|
||||
useEffect(() => {
|
||||
try {
|
||||
localStorage.setItem(
|
||||
STORAGE_KEY,
|
||||
JSON.stringify({ script: state.script, speaker: state.speaker, cfgScale: state.cfgScale })
|
||||
);
|
||||
} catch {}
|
||||
}, [state.script, state.speaker, state.cfgScale]);
|
||||
|
||||
const wordCount = state.script.trim() === "" ? 0 : state.script.trim().split(/\s+/).length;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user