fix(keep-notes): sidebar chevron, labels sync, batch org errors, perf guards
- Notebooks: chevron visible when expanded (remove overflow clip), functional expand state - Labels: sync/cleanup by notebookId, reconcile after note move - Settings: refresh notebooks after cleanup; label dialog routing - ConnectionsBadge lazy-load; reminder check persistence; i18n keys Made-with: Cursor
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { prisma } from '@/lib/prisma'
|
||||
import { getAIProvider } from '@/lib/ai/factory'
|
||||
import { getTagsProvider } from '@/lib/ai/factory'
|
||||
import { getSystemConfig } from '@/lib/config'
|
||||
|
||||
export interface NoteForOrganization {
|
||||
@@ -102,24 +102,12 @@ export class BatchOrganizationService {
|
||||
): Promise<OrganizationPlan> {
|
||||
const prompt = this.buildPrompt(notes, notebooks, language)
|
||||
|
||||
try {
|
||||
const config = await getSystemConfig()
|
||||
const provider = getAIProvider(config)
|
||||
const response = await provider.generateText(prompt)
|
||||
const config = await getSystemConfig()
|
||||
const provider = getTagsProvider(config)
|
||||
const response = await provider.generateText(prompt)
|
||||
|
||||
// Parse AI response
|
||||
const plan = this.parseAIResponse(response, notes, notebooks)
|
||||
|
||||
return plan
|
||||
} catch (error) {
|
||||
console.error('Failed to create organization plan:', error)
|
||||
// Return empty plan on error
|
||||
return {
|
||||
notebooks: [],
|
||||
totalNotes: notes.length,
|
||||
unorganizedNotes: notes.length,
|
||||
}
|
||||
}
|
||||
const plan = this.parseAIResponse(response, notes, notebooks)
|
||||
return plan
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -870,6 +858,10 @@ ${notesList}
|
||||
return instructions[language] || instructions['en'] || instructions['fr']
|
||||
}
|
||||
|
||||
private normalizeForMatch(str: string): string {
|
||||
return str.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '').trim()
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse AI response into OrganizationPlan
|
||||
*/
|
||||
@@ -879,7 +871,6 @@ ${notesList}
|
||||
notebooks: any[]
|
||||
): OrganizationPlan {
|
||||
try {
|
||||
// Try to parse JSON response
|
||||
const jsonMatch = response.match(/\{[\s\S]*\}/)
|
||||
if (!jsonMatch) {
|
||||
throw new Error('No JSON found in response')
|
||||
@@ -889,9 +880,10 @@ ${notesList}
|
||||
|
||||
const notebookOrganizations: NotebookOrganization[] = []
|
||||
|
||||
// Process each notebook in AI response
|
||||
for (const aiNotebook of aiData.carnets || []) {
|
||||
const notebook = notebooks.find(nb => nb.name === aiNotebook.nom)
|
||||
const aiName = this.normalizeForMatch(aiNotebook.nom || '')
|
||||
const notebook = notebooks.find(nb => this.normalizeForMatch(nb.name) === aiName)
|
||||
|| notebooks.find(nb => this.normalizeForMatch(nb.name).includes(aiName) || aiName.includes(this.normalizeForMatch(nb.name)))
|
||||
if (!notebook) continue
|
||||
|
||||
const noteAssignments = aiNotebook.notes
|
||||
@@ -933,12 +925,8 @@ ${notesList}
|
||||
unorganizedNotes: unorganizedCount,
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to parse AI response:', error)
|
||||
return {
|
||||
notebooks: [],
|
||||
totalNotes: notes.length,
|
||||
unorganizedNotes: notes.length,
|
||||
}
|
||||
console.error('Failed to parse AI response:', error, '\nRaw response:', response.substring(0, 500))
|
||||
throw new Error(`AI response parsing failed: ${error instanceof Error ? error.message : 'Invalid JSON'}`)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user