Add Dreamer section to settings — Dream Now button, mode selector, lucid task input, last dream status
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useStore } from '@/lib/store';
|
import { useStore } from '@/lib/store';
|
||||||
import { api, auth } from '@/lib/api';
|
import { api, auth } from '@/lib/api';
|
||||||
import type { Status } from '@/lib/api';
|
import type { Status, DreamerStatus } from '@/lib/api';
|
||||||
|
|
||||||
export default function SettingsPanel() {
|
export default function SettingsPanel() {
|
||||||
const { settingsOpen, setSettingsOpen, settings, setSettings } = useStore();
|
const { settingsOpen, setSettingsOpen, settings, setSettings } = useStore();
|
||||||
@@ -11,10 +11,16 @@ export default function SettingsPanel() {
|
|||||||
const [memory, setMemory] = useState('');
|
const [memory, setMemory] = useState('');
|
||||||
const [editingMemory, setEditingMemory] = useState(false);
|
const [editingMemory, setEditingMemory] = useState(false);
|
||||||
const [reindexing, setReindexing] = useState(false);
|
const [reindexing, setReindexing] = useState(false);
|
||||||
|
const [dreamerStatus, setDreamerStatus] = useState<DreamerStatus | null>(null);
|
||||||
|
const [dreamMode, setDreamMode] = useState('nrem');
|
||||||
|
const [dreamTask, setDreamTask] = useState('');
|
||||||
|
const [dreaming, setDreaming] = useState(false);
|
||||||
|
const [dreamStarted, setDreamStarted] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!settingsOpen) return;
|
if (!settingsOpen) return;
|
||||||
api.getStatus().then(setStatus).catch(console.error);
|
api.getStatus().then(setStatus).catch(console.error);
|
||||||
|
api.getDreamerStatus().then(setDreamerStatus).catch(console.error);
|
||||||
api.getMemory().then(d => setMemory(d.content)).catch(console.error);
|
api.getMemory().then(d => setMemory(d.content)).catch(console.error);
|
||||||
}, [settingsOpen]);
|
}, [settingsOpen]);
|
||||||
|
|
||||||
@@ -29,6 +35,18 @@ export default function SettingsPanel() {
|
|||||||
setEditingMemory(false);
|
setEditingMemory(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function triggerDream() {
|
||||||
|
setDreaming(true);
|
||||||
|
setDreamStarted(false);
|
||||||
|
const result = await api.runDreamer(dreamMode, dreamTask || undefined);
|
||||||
|
setDreaming(false);
|
||||||
|
if (result.started) {
|
||||||
|
setDreamStarted(true);
|
||||||
|
setTimeout(() => setDreamStarted(false), 4000);
|
||||||
|
setTimeout(() => api.getDreamerStatus().then(setDreamerStatus), 5000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function triggerReindex() {
|
async function triggerReindex() {
|
||||||
setReindexing(true);
|
setReindexing(true);
|
||||||
await api.reindex();
|
await api.reindex();
|
||||||
@@ -188,6 +206,43 @@ export default function SettingsPanel() {
|
|||||||
</Row>
|
</Row>
|
||||||
</Section>
|
</Section>
|
||||||
|
|
||||||
|
{/* Dreamer */}
|
||||||
|
<Section title="Dreamer">
|
||||||
|
<div className="grid grid-cols-2 gap-2 mb-3">
|
||||||
|
<StatCard number={dreamerStatus?.last_mode?.toUpperCase() || '—'} label="last mode" />
|
||||||
|
<StatCard number={dreamerStatus?.last_dream || '—'} label="last dream" />
|
||||||
|
</div>
|
||||||
|
<Row label="Mode">
|
||||||
|
<select
|
||||||
|
value={dreamMode}
|
||||||
|
onChange={e => setDreamMode(e.target.value)}
|
||||||
|
className="rounded-md px-2 py-1 text-sm"
|
||||||
|
style={{ background: 'var(--bg3)', border: '1px solid var(--border2)', color: 'var(--text)', fontFamily: 'var(--font-sans)' }}
|
||||||
|
>
|
||||||
|
<option value="nrem">NREM — consolidation</option>
|
||||||
|
<option value="early-rem">Early REM — personal</option>
|
||||||
|
<option value="late-rem">Late REM — associative</option>
|
||||||
|
<option value="lucid">Lucid — targeted</option>
|
||||||
|
</select>
|
||||||
|
</Row>
|
||||||
|
{dreamMode === 'lucid' && (
|
||||||
|
<div className="py-2" style={{ borderBottom: '1px solid var(--border)' }}>
|
||||||
|
<input
|
||||||
|
value={dreamTask}
|
||||||
|
onChange={e => setDreamTask(e.target.value)}
|
||||||
|
placeholder="What question should the dreamer pursue?"
|
||||||
|
className="w-full rounded-md px-3 py-2 text-xs"
|
||||||
|
style={{ background: 'var(--bg3)', border: '1px solid var(--border2)', color: 'var(--text)', fontFamily: 'var(--font-sans)' }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<Row label="Dream now" desc={dreamStarted ? 'Dream started — check Journal/Dreams/' : 'Run the dreamer immediately'}>
|
||||||
|
<SBtn primary onClick={triggerDream} disabled={dreaming || (dreamMode === 'lucid' && !dreamTask.trim())}>
|
||||||
|
{dreaming ? 'Starting...' : dreamStarted ? 'Started ✓' : 'Dream'}
|
||||||
|
</SBtn>
|
||||||
|
</Row>
|
||||||
|
</Section>
|
||||||
|
|
||||||
{/* System */}
|
{/* System */}
|
||||||
<Section title="System">
|
<Section title="System">
|
||||||
<StatusRow label="Aaron AI service" value={status?.aaron_ai || 'unknown'} ok={status?.aaron_ai === 'running'} />
|
<StatusRow label="Aaron AI service" value={status?.aaron_ai || 'unknown'} ok={status?.aaron_ai === 'running'} />
|
||||||
|
|||||||
+12
@@ -32,6 +32,12 @@ export const api = {
|
|||||||
request<{ saved: boolean }>('/memory', { method: 'POST', body: JSON.stringify({ content }) }),
|
request<{ saved: boolean }>('/memory', { method: 'POST', body: JSON.stringify({ content }) }),
|
||||||
getStatus: () => request<Status>('/status'),
|
getStatus: () => request<Status>('/status'),
|
||||||
reindex: () => request<{ started: boolean }>('/reindex', { method: 'POST' }),
|
reindex: () => request<{ started: boolean }>('/reindex', { method: 'POST' }),
|
||||||
|
getDreamerStatus: () => request<DreamerStatus>('/dreamer/status'),
|
||||||
|
runDreamer: (mode: string, task?: string) =>
|
||||||
|
request<{ started: boolean; mode: string }>('/dreamer/run', {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({ mode, task }),
|
||||||
|
}),
|
||||||
transcribe: async (audio: Blob): Promise<{ text: string }> => {
|
transcribe: async (audio: Blob): Promise<{ text: string }> => {
|
||||||
const form = new FormData();
|
const form = new FormData();
|
||||||
form.append('audio', audio, 'recording.webm');
|
form.append('audio', audio, 'recording.webm');
|
||||||
@@ -86,6 +92,12 @@ export interface ChatResponse {
|
|||||||
sources: string[];
|
sources: string[];
|
||||||
conversation_id: string;
|
conversation_id: string;
|
||||||
}
|
}
|
||||||
|
export interface DreamerStatus {
|
||||||
|
last_dream: string;
|
||||||
|
last_mode: string;
|
||||||
|
last_file: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface Status {
|
export interface Status {
|
||||||
aaron_ai: string;
|
aaron_ai: string;
|
||||||
watcher: string;
|
watcher: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user