feat: add document OCR and offline model archives
This commit is contained in:
+104
-2
@@ -75,6 +75,15 @@ import type {
|
||||
EmbeddingIndexStatus,
|
||||
EmbeddingSettingsSnapshot
|
||||
} from '../shared/embedding-contracts'
|
||||
import type {
|
||||
DocumentOcrAssets,
|
||||
DocumentOcrFailure,
|
||||
DocumentOcrRequest,
|
||||
DocumentOcrResult,
|
||||
DocumentParsingDiagnostic,
|
||||
DocumentParsingSettings,
|
||||
DocumentParsingSnapshot
|
||||
} from '../shared/document-parsing-contracts'
|
||||
import type { AgentRuntimeSelection } from '../shared/runtime-selection-contracts'
|
||||
import type { WeixinBindingSnapshot } from '../shared/weixin-channel-contracts'
|
||||
import type { RemoteChannelActivity } from '../shared/remote-channel-contracts'
|
||||
@@ -345,9 +354,14 @@ const desktopApi: DesktopApi = {
|
||||
ipcChannels.speechModelsSelect,
|
||||
{ modelId }
|
||||
) as Promise<SpeechModelSnapshot>,
|
||||
importLocalDirectory: (modelId: string) =>
|
||||
importArchive: (modelId: string) =>
|
||||
ipcRenderer.invoke(
|
||||
ipcChannels.speechModelsImportLocal,
|
||||
ipcChannels.speechModelsImportArchive,
|
||||
{ modelId }
|
||||
) as Promise<SpeechModelSnapshot | undefined>,
|
||||
exportArchive: (modelId: string) =>
|
||||
ipcRenderer.invoke(
|
||||
ipcChannels.speechModelsExportArchive,
|
||||
{ modelId }
|
||||
) as Promise<SpeechModelSnapshot | undefined>,
|
||||
openRepository: async (modelId: string) => {
|
||||
@@ -403,6 +417,94 @@ const desktopApi: DesktopApi = {
|
||||
)
|
||||
}
|
||||
},
|
||||
documentParsing: {
|
||||
getSnapshot: () =>
|
||||
ipcRenderer.invoke(
|
||||
ipcChannels.documentParsingGet
|
||||
) as Promise<DocumentParsingSnapshot>,
|
||||
update: (input: DocumentParsingSettings) =>
|
||||
ipcRenderer.invoke(
|
||||
ipcChannels.documentParsingUpdate,
|
||||
input
|
||||
) as Promise<DocumentParsingSnapshot>,
|
||||
test: () =>
|
||||
ipcRenderer.invoke(
|
||||
ipcChannels.documentParsingTest
|
||||
) as Promise<DocumentParsingDiagnostic | undefined>,
|
||||
installOcrModel: (modelId: string) =>
|
||||
ipcRenderer.invoke(
|
||||
ipcChannels.documentOcrModelsInstall,
|
||||
{ modelId }
|
||||
) as Promise<DocumentParsingSnapshot>,
|
||||
cancelOcrModelOperation: (modelId: string) =>
|
||||
ipcRenderer.invoke(
|
||||
ipcChannels.documentOcrModelsCancel,
|
||||
{ modelId }
|
||||
) as Promise<boolean>,
|
||||
removeOcrModel: (modelId: string) =>
|
||||
ipcRenderer.invoke(
|
||||
ipcChannels.documentOcrModelsRemove,
|
||||
{ modelId }
|
||||
) as Promise<DocumentParsingSnapshot>,
|
||||
importOcrModelArchive: (modelId: string) =>
|
||||
ipcRenderer.invoke(
|
||||
ipcChannels.documentOcrModelsImportArchive,
|
||||
{ modelId }
|
||||
) as Promise<DocumentParsingSnapshot | undefined>,
|
||||
exportOcrModelArchive: (modelId: string) =>
|
||||
ipcRenderer.invoke(
|
||||
ipcChannels.documentOcrModelsExportArchive,
|
||||
{ modelId }
|
||||
) as Promise<DocumentParsingSnapshot | undefined>,
|
||||
openOcrModelRepository: async (modelId: string) => {
|
||||
await ipcRenderer.invoke(
|
||||
ipcChannels.documentOcrModelsOpenRepository,
|
||||
{ modelId }
|
||||
)
|
||||
},
|
||||
openOcrModelsDirectory: async () => {
|
||||
await ipcRenderer.invoke(
|
||||
ipcChannels.documentOcrModelsOpenDirectory
|
||||
)
|
||||
},
|
||||
getOcrAssets: (modelId: string) =>
|
||||
ipcRenderer.invoke(
|
||||
ipcChannels.documentParsingOcrAssets,
|
||||
{ modelId }
|
||||
) as Promise<DocumentOcrAssets>,
|
||||
respondOcr: async (
|
||||
response: DocumentOcrResult | DocumentOcrFailure
|
||||
) => {
|
||||
await ipcRenderer.invoke(
|
||||
ipcChannels.documentParsingOcrRespond,
|
||||
response
|
||||
)
|
||||
},
|
||||
onOcrRequest: (listener) => {
|
||||
const handler = (
|
||||
_event: Electron.IpcRendererEvent,
|
||||
request: DocumentOcrRequest
|
||||
): void => listener(request)
|
||||
ipcRenderer.on(ipcChannels.documentParsingOcrRequest, handler)
|
||||
return () =>
|
||||
ipcRenderer.removeListener(
|
||||
ipcChannels.documentParsingOcrRequest,
|
||||
handler
|
||||
)
|
||||
},
|
||||
onOcrCancel: (listener) => {
|
||||
const handler = (
|
||||
_event: Electron.IpcRendererEvent,
|
||||
requestId: string
|
||||
): void => listener(requestId)
|
||||
ipcRenderer.on(ipcChannels.documentParsingOcrCancel, handler)
|
||||
return () =>
|
||||
ipcRenderer.removeListener(
|
||||
ipcChannels.documentParsingOcrCancel,
|
||||
handler
|
||||
)
|
||||
}
|
||||
},
|
||||
projects: {
|
||||
list: (includeArchived = false) =>
|
||||
ipcRenderer.invoke(
|
||||
|
||||
@@ -36,4 +36,17 @@ describe('sandboxed preload', () => {
|
||||
/(?:setComputerCapability|BrowserProfile).{0,80}(?:executablePath|command|env|args)/su
|
||||
)
|
||||
})
|
||||
|
||||
it('exposes model ZIP dialogs without renderer-controlled paths', () => {
|
||||
const source = readFileSync(
|
||||
join(process.cwd(), 'src', 'preload', 'index.ts'),
|
||||
'utf8'
|
||||
)
|
||||
expect(source).toContain('importArchive: (modelId: string)')
|
||||
expect(source).toContain('exportArchive: (modelId: string)')
|
||||
expect(source).toContain('importOcrModelArchive: (modelId: string)')
|
||||
expect(source).toContain('exportOcrModelArchive: (modelId: string)')
|
||||
expect(source).not.toContain('importLocalDirectory:')
|
||||
expect(source).not.toContain('importOcrModel:')
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user