feat: brainstorm sessions, PDF document Q&A, embedding fixes, and UI improvements
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 7s
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 7s
- Add brainstorm feature with collaborative canvas, AI idea generation, live cursors, playback, and export - Add PDF upload/extraction/ingestion pipeline with pgvector document search (RAG) - Add document Q&A overlay with streaming chat and PDF preview - Add note attachments UI with status polling, grid layout, and auto-scroll - Add task extraction AI tool and agent executor improvements - Fix NoteEmbedding missing updatedAt column, re-index 66 notes with 1536-dim embeddings - Fix brainstorm 'Create Note' button: add success toast and redirect to created note - Fix memory echo notification infinite polling - Fix chat route to always include document_search tool - Add brainstorm i18n keys across all 14 locales - Add socket server for real-time brainstorm collaboration - Add hierarchical notebook selector and organize notebook dialog improvements - Add sidebar brainstorm section with session management - Update prisma schema with brainstorm tables, attachments, and document chunks
This commit is contained in:
@@ -48,7 +48,7 @@ export async function POST(req: Request) {
|
||||
|
||||
// 2. Parse request body
|
||||
const body = await req.json()
|
||||
const { messages: rawMessages, conversationId, notebookId, language, webSearch, noteContext, format } = body as {
|
||||
const { messages: rawMessages, conversationId, notebookId, language, webSearch, noteContext, format, noteId } = body as {
|
||||
messages: UIMessage[]
|
||||
conversationId?: string
|
||||
notebookId?: string
|
||||
@@ -56,6 +56,7 @@ export async function POST(req: Request) {
|
||||
webSearch?: boolean
|
||||
noteContext?: { title: string; content: string; tone: string; images?: string[] }
|
||||
format?: 'html' | 'markdown'
|
||||
noteId?: string
|
||||
}
|
||||
|
||||
const incomingMessages = toCoreMessages(rawMessages)
|
||||
@@ -107,17 +108,60 @@ export async function POST(req: Request) {
|
||||
|
||||
let searchResults: any[] = []
|
||||
try {
|
||||
searchResults = await semanticSearchService.search(currentMessage, {
|
||||
notebookId,
|
||||
limit: notebookId ? 10 : 5,
|
||||
threshold: notebookId ? 0.3 : 0.5,
|
||||
defaultTitle: untitledText,
|
||||
})
|
||||
const documentMention = currentMessage.match(
|
||||
/\b(pdf|document|fichier|pi[eè]ce jointe|attachment|file)\b/i
|
||||
)
|
||||
|
||||
if (documentMention) {
|
||||
const docResults = await semanticSearchService.searchWithDocuments(
|
||||
userId, currentMessage, {
|
||||
notebookId,
|
||||
limit: notebookId ? 10 : 5,
|
||||
threshold: notebookId ? 0.3 : 0.5,
|
||||
includeDocuments: true,
|
||||
defaultTitle: untitledText,
|
||||
}
|
||||
)
|
||||
searchResults = docResults
|
||||
} else {
|
||||
searchResults = await semanticSearchService.search(currentMessage, {
|
||||
notebookId,
|
||||
limit: notebookId ? 10 : 5,
|
||||
threshold: notebookId ? 0.3 : 0.5,
|
||||
defaultTitle: untitledText,
|
||||
})
|
||||
}
|
||||
} catch {}
|
||||
|
||||
searchNotes = searchResults
|
||||
.map((r) => `NOTE [${r.title || untitledText}]: ${r.content}`)
|
||||
.map((r) => {
|
||||
if ((r as any).source === 'document') {
|
||||
return `DOCUMENT [${(r as any).fileName} p.${(r as any).pageNumber}] (from note: ${r.title || untitledText}):\n${r.content}`
|
||||
}
|
||||
return `NOTE [${r.title || untitledText}]: ${r.content}`
|
||||
})
|
||||
.join('\n\n---\n\n')
|
||||
} else if (noteId) {
|
||||
try {
|
||||
const docResults = await semanticSearchService.searchWithDocuments(
|
||||
userId, currentMessage, {
|
||||
noteId,
|
||||
limit: 8,
|
||||
threshold: 0.3,
|
||||
includeDocuments: true,
|
||||
defaultTitle: untitledText,
|
||||
}
|
||||
)
|
||||
searchNotes = docResults
|
||||
.map((r) => {
|
||||
if ((r as any).source === 'document') {
|
||||
return `DOCUMENT [${(r as any).fileName} p.${(r as any).pageNumber}]:\n${r.content}`
|
||||
}
|
||||
return ''
|
||||
})
|
||||
.filter(Boolean)
|
||||
.join('\n\n---\n\n')
|
||||
} catch {}
|
||||
}
|
||||
|
||||
const contextNotes = [notebookContext, searchNotes].filter(Boolean).join('\n\n---\n\n')
|
||||
@@ -125,7 +169,7 @@ export async function POST(req: Request) {
|
||||
// 5. System prompt synthesis
|
||||
const promptLang: Record<string, { contextWithNotes: string; contextNoNotes: string; system: string }> = {
|
||||
en: {
|
||||
contextWithNotes: `## User's notes\n\n${contextNotes}\n\nWhen using info from the notes above, cite the source note title in parentheses, e.g.: "Deployment is done via Docker (💻 Development Guide)". Don't copy word for word — rephrase. If the notes don't cover the topic, say so and supplement with your general knowledge.`,
|
||||
contextWithNotes: `## User's notes & documents\n\n${contextNotes}\n\nWhen using info from the notes above, cite the source note title in parentheses, e.g.: "Deployment is done via Docker (💻 Development Guide)". For document passages, cite the filename and page number, e.g.: "The revenue was $5M (📄 report.pdf p.12)". Don't copy word for word — rephrase. If the notes don't cover the topic, say so and supplement with your general knowledge.`,
|
||||
contextNoNotes: "No relevant notes found for this question. Answer with your general knowledge.",
|
||||
system: `You are the AI assistant of Memento. The user asks you questions about their projects, technical docs, and notes. You must respond in a structured and helpful way.
|
||||
|
||||
@@ -159,11 +203,13 @@ Momento is an intelligent note-taking application. Key features include:
|
||||
- **Lab**: Experimental AI tools for data analysis and deeper insights.
|
||||
|
||||
## Available tools
|
||||
You have access to: note_search, note_read, web_search, web_scrape.
|
||||
Only use tools if you need more information. Never invent note IDs or URLs.`,
|
||||
You have access to: note_search, note_read, document_search, task_extract, web_search, web_scrape.
|
||||
Only use tools if you need more information. Never invent note IDs or URLs.
|
||||
- document_search: Searches attached PDF documents for the current note/notebook. Use when the user asks about documents or files.
|
||||
- task_extract: Extracts action items from notes and creates a synthesis note. Use when the user asks to extract tasks or TODOs.`,
|
||||
},
|
||||
fr: {
|
||||
contextWithNotes: `## Notes de l'utilisateur\n\n${contextNotes}\n\nQuand tu utilises une info venant des notes ci-dessus, cite le titre de la note source entre parenthèses, ex: "Le déploiement se fait via Docker (💻 Development Guide)". Ne recopie pas mot pour mot — reformule.`,
|
||||
contextWithNotes: `## Notes et documents de l'utilisateur\n\n${contextNotes}\n\nQuand tu utilises une info venant des notes ci-dessus, cite le titre de la note source entre parenthèses, ex: "Le déploiement se fait via Docker (💻 Development Guide)". Pour les documents PDF, cite le nom du fichier et la page, ex: "Le chiffre d'affaires est de 5M$ (📄 rapport.pdf p.12)". Ne recopie pas mot pour mot — reformule.`,
|
||||
contextNoNotes: "Aucune note pertinente trouvée pour cette question. Réponds avec tes connaissances générales.",
|
||||
system: `Tu es l'assistant IA de Memento. L'utilisateur te pose des questions sur ses projets, sa doc technique, ses notes. Tu dois répondre de façon structurée et utile.
|
||||
|
||||
@@ -191,7 +237,9 @@ Only use tools if you need more information. Never invent note IDs or URLs.`,
|
||||
Momento est une application de prise de notes intelligente. Ses fonctionnalités : Éditeur Markdown riche, Copilot IA, Organisation par Carnets, Recherche sémantique, Agents IA, Lab.
|
||||
|
||||
## Outils disponibles
|
||||
Tu as accès à : note_search, note_read, web_search, web_scrape.`,
|
||||
Tu as accès à : note_search, note_read, document_search, task_extract, web_search, web_scrape.
|
||||
- document_search : Recherche dans les documents PDF attachés à la note/au carnet.
|
||||
- task_extract : Extrait les tâches/action items des notes et crée une note de synthèse.`,
|
||||
},
|
||||
fa: {
|
||||
contextWithNotes: `## یادداشتهای کاربر\n\n${contextNotes}\n\nهنگام استفاده از اطلاعات یادداشتهای بالا، عنوان یادداشت منبع را در پرانتز ذکر کنید.`,
|
||||
@@ -276,7 +324,7 @@ Focus ONLY on this note unless asked otherwise.`
|
||||
// 6. Execute stream
|
||||
const sysConfig = await getSystemConfig()
|
||||
const chatTools = noteContext
|
||||
? toolRegistry.buildToolsForChat({ userId, config: sysConfig, webSearch, webOnly: true })
|
||||
? toolRegistry.buildToolsForChat({ userId, config: sysConfig, webSearch, notebookId: notebookId || undefined })
|
||||
: toolRegistry.buildToolsForChat({ userId, config: sysConfig, webSearch, notebookId: notebookId || undefined })
|
||||
|
||||
const provider = getChatProvider(sysConfig)
|
||||
|
||||
Reference in New Issue
Block a user