diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index b350ecc..7f0e0df 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -300,130 +300,106 @@ export function apiSSEStream( } // --------------------------------------------------------------------------- -// Briefing +// Journal // --------------------------------------------------------------------------- -export interface BriefingLocation { - label: string; - address: string; - lat?: number; - lon?: number; +export interface JournalConfig { + prep_enabled: boolean; + prep_hour: number; + prep_minute: number; + day_rollover_hour: number; + morning_end_hour?: number; + midday_end_hour?: number; + [key: string]: unknown; } -export interface BriefingSlots { - compilation: boolean; - morning: boolean; - midday: boolean; - afternoon: boolean; -} - -export interface BriefingConfig { - enabled: boolean; - locations: { - home?: BriefingLocation; - work?: BriefingLocation; - }; - use_caldav_event_locations: boolean; - work_days: number[]; - slots: BriefingSlots; - notifications: boolean; - temp_unit: 'C' | 'F'; -} - -export interface BriefingFeed { +export interface JournalConversation { id: number; title: string; - url: string; - category: string | null; - last_fetched_at: string | null; -} - -export interface BriefingConversation { - id: number; - title: string; - briefing_date: string | null; + model: string; + conversation_type: string; + day_date: string | null; + rag_project_id: number | null; message_count: number; created_at: string; + updated_at: string; } -export interface BriefingMessage { +export interface JournalMessage { id: number; + conversation_id: number; role: 'user' | 'assistant' | 'system'; content: string; + status: string; + context_note_id: number | null; + tool_calls: unknown[] | null; + metadata: Record | null; created_at: string; - metadata?: Record | null; } -const DEFAULT_BRIEFING_CONFIG: BriefingConfig = { - enabled: false, - locations: {}, - use_caldav_event_locations: false, - work_days: [1, 2, 3, 4, 5], - slots: { compilation: true, morning: true, midday: false, afternoon: false }, - notifications: true, - temp_unit: 'C', -}; - -export async function getBriefingConfig(): Promise { - try { - const data = await apiGet('/api/briefing/config'); - return { ...DEFAULT_BRIEFING_CONFIG, ...data }; - } catch { - return { ...DEFAULT_BRIEFING_CONFIG }; - } +export interface JournalDayPayload { + day_date: string; + conversation: JournalConversation | null; + messages: JournalMessage[]; } -export async function saveBriefingConfig(config: BriefingConfig): Promise { - await apiPut('/api/briefing/config', config); +export interface JournalMoment { + id: number; + user_id: number; + conversation_id: number | null; + source_message_id: number | null; + day_date: string; + occurred_at: string; + recorded_at: string; + content: string; + raw_excerpt: string | null; + tags: string[]; + pinned: boolean; + people: { id: number; title: string }[]; + places: { id: number; title: string }[]; + task_ids: number[]; + note_ids: number[]; + score?: number; } -export async function getBriefingFeeds(): Promise { - const data = await apiGet('/api/briefing/feeds'); - return data; +export async function getJournalConfig(): Promise { + return apiGet('/api/journal/config'); } -export async function createBriefingFeed(url: string, category?: string): Promise { - const body: Record = { url }; - if (category?.trim()) body.category = category.trim(); - const data = await apiPost<{ id: number; url: string; title: string; category: string | null }>('/api/briefing/feeds', body); - return { ...data, last_fetched_at: null }; +export async function saveJournalConfig(config: JournalConfig): Promise { + await apiPut('/api/journal/config', config); } -export async function refreshBriefingFeeds(): Promise<{ feeds_refreshed: number; new_items: number }> { - return apiPost('/api/briefing/feeds/refresh', {}); +export async function getJournalToday(): Promise { + return apiGet('/api/journal/today'); } -export async function deleteBriefingFeed(id: number): Promise { - await apiDelete(`/api/briefing/feeds/${id}`); +export async function getJournalDay(isoDate: string): Promise { + return apiGet(`/api/journal/day/${isoDate}`); } -export async function getBriefingConversations(): Promise { - const data = await apiGet<{ conversations: BriefingConversation[] }>('/api/briefing/conversations'); - return data.conversations; +export async function getJournalDays(): Promise { + const data = await apiGet<{ days: string[] }>('/api/journal/days'); + return data.days; } -export async function getBriefingToday(): Promise<{ id: number; title: string; messages: BriefingMessage[] }> { - return apiGet('/api/briefing/conversations/today'); +export async function triggerJournalPrep(date?: string): Promise<{ ok: boolean; message_id: number }> { + return apiPost('/api/journal/trigger-prep', date ? { date } : {}); } -export async function getBriefingConvMessages(id: number): Promise { - const data = await apiGet<{ messages: BriefingMessage[] }>(`/api/briefing/conversations/${id}/messages`); - return data.messages; +export async function listJournalMoments(params: Record = {}): Promise { + const qs = new URLSearchParams(); + for (const [k, v] of Object.entries(params)) qs.set(k, String(v)); + const data = await apiGet<{ moments: JournalMoment[] }>(`/api/journal/moments?${qs}`); + return data.moments; } -export async function triggerBriefingSlot(slot: string): Promise { - await apiPost('/api/briefing/trigger', { slot }); +export async function updateJournalMoment(id: number, patch: Partial): Promise { + return apiPatch(`/api/journal/moments/${id}`, patch); } -export async function postRssReaction( - rssItemId: number, - reaction: 'up' | 'down' -): Promise<{ ok: boolean; action: string }> { - return apiPost('/api/briefing/rss-reactions', { rss_item_id: rssItemId, reaction }); -} - -export async function deleteRssReaction(rssItemId: number): Promise { - return apiDelete(`/api/briefing/rss-reactions/${rssItemId}`); +export async function deleteJournalMoment(id: number): Promise { + await apiDelete(`/api/journal/moments/${id}`); } export async function openArticleInChat( @@ -434,7 +410,7 @@ export async function openArticleInChat( export async function geocodeAddress(address: string): Promise<{ lat: number; lon: number; display_name: string } | null> { try { - const r = await apiPost<{ lat: number; lon: number; label: string }>('/api/briefing/weather/geocode', { query: address }); + const r = await apiPost<{ lat: number; lon: number; label: string }>('/api/geocode', { query: address }); return { lat: r.lat, lon: r.lon, display_name: r.label }; } catch { return null; diff --git a/frontend/src/components/AppHeader.vue b/frontend/src/components/AppHeader.vue index 07fad8a..839574c 100644 --- a/frontend/src/components/AppHeader.vue +++ b/frontend/src/components/AppHeader.vue @@ -76,6 +76,7 @@ router.afterEach(() => { @@ -123,6 +124,7 @@ router.afterEach(() => {
Knowledge Chat + Journal Calendar Projects Shared diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts index df6c340..f98ad5e 100644 --- a/frontend/src/router/index.ts +++ b/frontend/src/router/index.ts @@ -116,6 +116,11 @@ const router = createRouter({ name: "calendar", component: () => import("@/views/CalendarView.vue"), }, + { + path: "/journal", + name: "journal", + component: () => import("@/views/JournalView.vue"), + }, { path: "/settings", name: "settings", diff --git a/frontend/src/views/JournalView.vue b/frontend/src/views/JournalView.vue new file mode 100644 index 0000000..337fd17 --- /dev/null +++ b/frontend/src/views/JournalView.vue @@ -0,0 +1,504 @@ + + + + + diff --git a/frontend/src/views/NewsView.vue b/frontend/src/views/NewsView.vue deleted file mode 100644 index 5475a23..0000000 --- a/frontend/src/views/NewsView.vue +++ /dev/null @@ -1,406 +0,0 @@ - - - - -