fix(rag): do not mark a document indexed when no chunk could be embedded
Some checks failed
ci / 정본·보안·린트·타입·테스트 (push) Successful in 51s
ci / 모바일 린트·타입·Jest (push) Successful in 37s
ci / Supabase Edge Functions + Cloudflare Worker (push) Successful in 26s
ci / .NET API 서버 테스트 (push) Successful in 14s
deploy-site / deploy (push) Failing after 15s
ci / 워크스페이스 빌드 검증 (push) Failing after 11m7s
Some checks failed
ci / 정본·보안·린트·타입·테스트 (push) Successful in 51s
ci / 모바일 린트·타입·Jest (push) Successful in 37s
ci / Supabase Edge Functions + Cloudflare Worker (push) Successful in 26s
ci / .NET API 서버 테스트 (push) Successful in 14s
deploy-site / deploy (push) Failing after 15s
ci / 워크스페이스 빌드 검증 (push) Failing after 11m7s
With the embedding server unavailable every chunk failed, yet the document was stored as indexed=true with 0 chunks, so the knowledge base listed it as searchable while queries could never match it. The red use-case test caught this; it had been written off as an environment failure. Now a run with zero embedded chunks leaves indexed=false and throws RAGEmbeddingFailed (surfaced by reindex, logged by addDocument). Tests that only hold on the Windows developer machine now declare it: the bundled SoX binary and PowerShell device discovery run on win32 only, and the sidecar venv test runs only when sidecar/.venv exists. The Linux Forgejo runner skips them instead of failing.
This commit is contained in:
parent
b8a09c0333
commit
0d92a4a853
3 changed files with 21 additions and 4 deletions
|
|
@ -292,13 +292,27 @@ ${context}`
|
||||||
await new Promise((r) => setTimeout(r, 10))
|
await new Promise((r) => setTimeout(r, 10))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._state = 'idle'
|
||||||
|
|
||||||
|
// 한 청크도 임베딩하지 못했으면(임베딩 서버 없음 등) 색인됐다고 표시하지 않는다.
|
||||||
|
// indexed=true + 0 chunks 로 두면 문서가 검색 가능한 것처럼 보이지만 질의에 걸리지 않는다.
|
||||||
|
if (successCount === 0) {
|
||||||
|
db.update(ragDocuments)
|
||||||
|
.set({ indexed: false, indexedAt: null })
|
||||||
|
.where(eq(ragDocuments.id, docId))
|
||||||
|
.run()
|
||||||
|
throw new D3ROError(
|
||||||
|
ErrorCode.RAGEmbeddingFailed,
|
||||||
|
`No chunk of ${fileName} could be embedded (${chunks.length} attempted)`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// 인덱싱 완료 표시
|
// 인덱싱 완료 표시
|
||||||
db.update(ragDocuments)
|
db.update(ragDocuments)
|
||||||
.set({ indexed: true, indexedAt: Date.now(), chunkCount: successCount })
|
.set({ indexed: true, indexedAt: Date.now(), chunkCount: successCount })
|
||||||
.where(eq(ragDocuments.id, docId))
|
.where(eq(ragDocuments.id, docId))
|
||||||
.run()
|
.run()
|
||||||
|
|
||||||
this._state = 'idle'
|
|
||||||
this._sendToRenderer(IPC_CHANNELS.RAG.INDEX_COMPLETE, { documentId: docId, fileName })
|
this._sendToRenderer(IPC_CHANNELS.RAG.INDEX_COMPLETE, { documentId: docId, fileName })
|
||||||
logger.info(`RAG indexing complete: ${fileName} (${successCount}/${chunks.length} chunks embedded)`)
|
logger.info(`RAG indexing complete: ${fileName} (${successCount}/${chunks.length} chunks embedded)`)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,8 @@ describe('Windows child process visibility', () => {
|
||||||
expectWindowsHideOnAllCalls(childProcess.exec)
|
expectWindowsHideOnAllCalls(childProcess.exec)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('hides Windows device discovery and active-window PowerShell calls', async () => {
|
// 장치 목록·활성 창 조회는 win32 분기에서만 PowerShell 을 부른다.
|
||||||
|
it.skipIf(process.platform !== 'win32')('hides Windows device discovery and active-window PowerShell calls', async () => {
|
||||||
const audioModule = await import('../../../src/main/services/AudioCaptureService')
|
const audioModule = await import('../../../src/main/services/AudioCaptureService')
|
||||||
const audioService = audioModule.getAudioCaptureService() as unknown as {
|
const audioService = audioModule.getAudioCaptureService() as unknown as {
|
||||||
_getDevicesWindows(): Promise<unknown>
|
_getDevicesWindows(): Promise<unknown>
|
||||||
|
|
|
||||||
|
|
@ -37,13 +37,15 @@ describe('paths (dev)', () => {
|
||||||
expect(getAppRoot()).toBe(desktopDir)
|
expect(getAppRoot()).toBe(desktopDir)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('prefers the bundled SoX binary over the system PATH', () => {
|
// resources/sox 에는 Windows용 sox.exe 만 커밋돼 있다(앱은 Windows 배포). 다른 OS에서는 PATH 의 sox 를 쓴다.
|
||||||
|
it.skipIf(process.platform !== 'win32')('prefers the bundled SoX binary over the system PATH', () => {
|
||||||
expect(getSoxPath()).toContain(path.join('resources', 'sox', 'sox'))
|
expect(getSoxPath()).toContain(path.join('resources', 'sox', 'sox'))
|
||||||
expect(existsSync(getSoxPath())).toBe(true)
|
expect(existsSync(getSoxPath())).toBe(true)
|
||||||
expect(getSoxPath()).not.toBe('sox')
|
expect(getSoxPath()).not.toBe('sox')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('uses the sidecar virtualenv python when it exists', () => {
|
// 로컬 개발 환경에만 있는 sidecar/.venv 가 있을 때의 동작이다. CI 에는 venv 가 없다.
|
||||||
|
it.skipIf(!existsSync(path.join(desktopDir, 'sidecar', '.venv')))('uses the sidecar virtualenv python when it exists', () => {
|
||||||
const launch = getSidecarCommand()
|
const launch = getSidecarCommand()
|
||||||
|
|
||||||
expect(launch.source).toBe('venv')
|
expect(launch.source).toBe('venv')
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue