diff --git a/apps/client/src/widgets/NoteDetail.tsx b/apps/client/src/widgets/NoteDetail.tsx index e961e49d6..8b8d27c02 100644 --- a/apps/client/src/widgets/NoteDetail.tsx +++ b/apps/client/src/widgets/NoteDetail.tsx @@ -37,7 +37,8 @@ const TYPE_MAPPINGS: Record Promise<{ default: TypeWidge "render": () => import("./type_widgets/Render"), "canvas": () => import("./type_widgets/Canvas"), "relationMap": () => import("./type_widgets/relation_map/RelationMap"), - "noteMap": () => import("./type_widgets/NoteMap") + "noteMap": () => import("./type_widgets/NoteMap"), + "aiChat": () => import("./type_widgets/AiChat") // TODO: finalize the record. }; diff --git a/apps/client/src/widgets/type_widgets/AiChat.tsx b/apps/client/src/widgets/type_widgets/AiChat.tsx new file mode 100644 index 000000000..49ab7267a --- /dev/null +++ b/apps/client/src/widgets/type_widgets/AiChat.tsx @@ -0,0 +1,38 @@ +import { useEffect, useRef, useState } from "preact/hooks"; +import { useEditorSpacedUpdate, useLegacyWidget } from "../react/hooks"; +import { type TypeWidgetProps } from "./type_widget"; +import LlmChatPanel from "../llm_chat"; + +export default function AiChat({ note, noteContext }: TypeWidgetProps) { + const dataRef = useRef(); + const spacedUpdate = useEditorSpacedUpdate({ + note, + getData: async () => dataRef.current, + onContentChange: (newContent) => dataRef.current = newContent + }); + const [ ChatWidget, llmChatPanel ] = useLegacyWidget(() => { + return new LlmChatPanel(); + }, { + noteContext, + containerClassName: "ai-chat-widget-container", + containerStyle: { + height: "100%" + } + }); + + useEffect(() => { + llmChatPanel.setDataCallbacks( + async (data) => { + dataRef.current = data; + spacedUpdate.scheduleUpdate(); + }, + async () => dataRef.current + ); + }, []); + + useEffect(() => { + llmChatPanel.setCurrentNoteId(note.noteId); + }, [ note ]); + + return ChatWidget; +} diff --git a/apps/client/src/widgets/type_widgets_old/ai_chat.ts b/apps/client/src/widgets/type_widgets_old/ai_chat.ts index 7f015d334..314ab824f 100644 --- a/apps/client/src/widgets/type_widgets_old/ai_chat.ts +++ b/apps/client/src/widgets/type_widgets_old/ai_chat.ts @@ -10,48 +10,6 @@ export default class AiChatTypeWidget extends TypeWidget { private isInitialized: boolean = false; private initPromise: Promise | null = null; - constructor() { - super(); - this.llmChatPanel = new LlmChatPanel(); - - // Connect the data callbacks - this.llmChatPanel.setDataCallbacks( - (data) => this.saveData(data), - () => this.getData() - ); - } - - static getType() { - return "aiChat"; - } - - doRender() { - this.$widget = $('
'); - this.$widget.append(this.llmChatPanel.render()); - - return this.$widget; - } - - // Override the refreshWithNote method to ensure we get note changes - async refreshWithNote(note: FNote | null | undefined) { - console.log("refreshWithNote called for note:", note?.noteId); - - // Always force a refresh when the note changes - if (this.note?.noteId !== note?.noteId) { - console.log(`Note ID changed from ${this.note?.noteId} to ${note?.noteId}, forcing reset`); - this.isInitialized = false; - this.initPromise = null; - - // Force refresh the chat panel with the new note - if (note) { - this.llmChatPanel.setCurrentNoteId(note.noteId); - } - } - - // Continue with regular doRefresh - await this.doRefresh(note); - } - async doRefresh(note: FNote | null | undefined) { try { console.log("doRefresh called for note:", note?.noteId); @@ -185,10 +143,10 @@ export default class AiChatTypeWidget extends TypeWidget { // If we have a noteId in the data, that's the AI Chat note we should save to // This happens when the chat panel is saving its conversation const targetNoteId = data.noteId; - + // If no noteId in data, use the current note (for new chats) const noteIdToUse = targetNoteId || this.note?.noteId; - + if (!noteIdToUse) { console.warn("Cannot save AI Chat data: no note ID available"); return;