feat(insights): fix DBSCAN, Persian embeddings crash, D3 physics layouts, and D3 node not found runtime error
Some checks failed
CI / Lint, Test & Build (push) Failing after 1m7s
CI / Deploy production (on server) (push) Has been skipped

This commit is contained in:
Antigravity
2026-05-24 18:57:33 +00:00
parent e2672cd2c2
commit e881004c77
63 changed files with 5729 additions and 563 deletions

View File

@@ -10,6 +10,9 @@ import { useLanguage } from '@/lib/i18n/LanguageProvider'
import type { BlockSuggestion } from '@/components/block-picker'
import { toast } from 'sonner'
import { useNoteEditorContext } from '@/components/note-editor/note-editor-context'
import { stripHtmlToPlainText } from '@/lib/text/plain-text'
import { detectTextDirection } from '@/lib/clip/rtl-content'
import { SEMANTIC_SIMILARITY_FLOOR_CLIP } from '@/lib/ai/semantic-proximity'
interface ConnectionData {
noteId: string
@@ -40,16 +43,16 @@ interface PreviewTarget {
excerpt: string
}
function stripHtml(html: string): string {
return html.replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim()
}
function excerpt(text: string, max = 150): string {
const plain = stripHtml(text)
const plain = stripHtmlToPlainText(text)
if (plain.length <= max) return plain
return `${plain.slice(0, max).trim()}`
}
function isRtlText(text: string): boolean {
return detectTextDirection(text) === 'rtl'
}
async function resolveBlockForEmbed(sourceNoteId: string, hint: string): Promise<{ block: BlockSuggestion; mode: 'live' | 'citation' } | null> {
const params = new URLSearchParams({ noteId: sourceNoteId, hint })
const res = await fetch(`/api/blocks/resolve?${params}`)
@@ -155,7 +158,7 @@ export function MemoryEchoSection({
useEffect(() => {
if (isLoading || connections.length === 0) return
const top = connections[0]
if (!top || top.similarity < 0.75) return
if (!top || top.similarity < SEMANTIC_SIMILARITY_FLOOR_CLIP) return
const key = `memory-echo-scroll-${noteId}`
if (sessionStorage.getItem(key)) return
sessionStorage.setItem(key, '1')
@@ -167,7 +170,7 @@ export function MemoryEchoSection({
const handleEmbed = useCallback(async (conn: ConnectionData) => {
setEmbeddingId(conn.noteId)
try {
const hint = excerpt(stripHtml(conn.content), 300)
const hint = (conn.content || '').trim().slice(0, 12000)
const resolved = await resolveBlockForEmbed(conn.noteId, hint)
const noteTitle = conn.title || t('memoryEcho.comparison.untitled')
@@ -200,7 +203,7 @@ export function MemoryEchoSection({
return
}
const citationText = stripHtml(
const citationText = stripHtmlToPlainText(
resolved?.block.content || conn.content || hint
).slice(0, 1200)
@@ -213,7 +216,9 @@ export function MemoryEchoSection({
if (editorCtx.state.isMarkdown) {
const quoted = citationText.split('\n').map(line => `> ${line}`).join('\n')
const mdCitation = `\n\n${quoted}\n\n— [${noteTitle}](/home?openNote=${conn.noteId})\n`
const mdCitation = isRtlText(citationText)
? `\n\n<div dir="rtl" lang="fa">\n\n${quoted}\n\n— [${noteTitle}](/home?openNote=${conn.noteId})\n\n</div>\n`
: `\n\n${quoted}\n\n— [${noteTitle}](/home?openNote=${conn.noteId})\n`
editorCtx.actions.setContent(editorCtx.state.content + mdCitation)
toast.success(t('memoryEcho.editorSection.citationSuccess'))
return
@@ -326,7 +331,14 @@ export function MemoryEchoSection({
</div>
)}
<blockquote className="border-l-2 border-indigo-500/20 pl-3 font-serif italic text-sm leading-relaxed text-foreground/85">
<blockquote
className={cn(
'border-indigo-500/20 pl-3 font-serif italic text-sm leading-relaxed text-foreground/85',
isRtlText(topConnection.content) ? 'border-r-2 border-l-0 pr-3 pl-0 text-right' : 'border-l-2',
)}
dir={isRtlText(topConnection.content) ? 'rtl' : undefined}
lang={isRtlText(topConnection.content) ? 'fa' : undefined}
>
« {excerpt(topConnection.content)} »
</blockquote>