feat: configure canvas pages sent for note analysis
Canvas analysis previously sent every page. Add a Magic Notes setting for 1-8 canvas pages, defaulting to 1 for new and historical settings. Select the first N pages in current canvas order before capture and use the same text/image range for saved entries, drafts and canvas-source todos. Keep full 50-page saving/export, expose the same setting through config tools, and use the shared settings select with an inline help icon. Include pagination, persistence, production IPC and isolated Electron regressions, including text-only input and scaled page boundaries. Validation: focused feature tests and isolated Electron regressions passed; the final compact UI passed 14 tests. Typecheck and lint were reported passing by the coordinating agent. No full-suite pass is claimed because the completed full test command exposed no summary. No live model calls were made for this commit preparation. Release note: 魔法笔记新增“发送画布页数”设置,可选 1~8 页,默认 1 页,按当前画布顺序发送前 N 页的文字和图片;标题旁问号可查看说明,保存和导出完整画布不受影响。
This commit is contained in:
@@ -10,7 +10,7 @@ import { createServer } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
import { expect, it } from 'vitest'
|
||||
|
||||
it('analyzes saved, edited, created and todo canvases through production Electron IPC', async () => {
|
||||
it.each([true, false])('analyzes selected canvas pages through production Electron UI and IPC (vision=%s)', async (supportsImageInput) => {
|
||||
const directory = await mkdtemp(join(tmpdir(), 'goodbuddy-notes-analysis-'))
|
||||
const server = await createServer({ configFile: false, root: resolve('.'), cacheDir: join(directory, 'vite'),
|
||||
plugins: [react(), { name: 'notes-analysis', configureServer(server) {
|
||||
@@ -30,7 +30,7 @@ it('analyzes saved, edited, created and todo canvases through production Electro
|
||||
build.onLoad({ filter: /.*/, namespace: 'probe' }, ({ path }) => ({ contents: path === 'channels'
|
||||
? 'export const startEnvironmentChannels=()=>[]; export const isReadOnlyChannelMessage=()=>true;'
|
||||
: `export const createDefaultModelRuntime=()=>({ dispose:async()=>{}, releaseConversation:async()=>{}, async *run(request) {
|
||||
if (!request.images?.length) throw new Error('Expected real canvas captures');
|
||||
(globalThis.analysisRequests ??= []).push({ prompt: request.prompt, imageCount: request.images?.length ?? 0 });
|
||||
yield {requestId:request.requestId,type:'text',delta:'{"comments":[{"kind":"summary","content":"Canvas reviewed."}]}'};
|
||||
yield {requestId:request.requestId,type:'done'};
|
||||
}}); export const createModelProfileRuntime=createDefaultModelRuntime;` }))
|
||||
@@ -45,7 +45,7 @@ it('analyzes saved, edited, created and todo canvases through production Electro
|
||||
await server.listen()
|
||||
const bootstrap = join(directory, 'bootstrap.cjs')
|
||||
await writeFile(bootstrap, `import(${JSON.stringify(pathToFileURL(driver).href)}).catch(error => { console.error(error); require('electron').app.exit(1) })`)
|
||||
const env: NodeJS.ProcessEnv = { ...process.env, GB_NOTES_PROBE_DIRECTORY: directory, GB_NOTES_PROBE_URL: server.resolvedUrls!.local[0] + 'analysis.html' }
|
||||
const env: NodeJS.ProcessEnv = { ...process.env, GB_NOTES_PROBE_VISION: String(supportsImageInput), GB_NOTES_PROBE_DIRECTORY: directory, GB_NOTES_PROBE_URL: server.resolvedUrls!.local[0] + 'analysis.html' }
|
||||
delete env.ELECTRON_RUN_AS_NODE
|
||||
const child = spawn(createRequire(import.meta.url)('electron'), [bootstrap], { env, stdio: ['ignore', 'pipe', 'pipe'] })
|
||||
let output = ''
|
||||
@@ -56,7 +56,16 @@ it('analyzes saved, edited, created and todo canvases through production Electro
|
||||
expect(await new Promise((resolve, reject) => { child.once('exit', resolve); child.once('error', reject) }), output).toBe(0)
|
||||
} finally { clearTimeout(timeout) }
|
||||
const result = JSON.parse(await readFile(join(directory, 'result.json'), 'utf8'))
|
||||
expect(result).toEqual({ errors: [], manualRevision: 1, editedRevision: 3, createdAnalyzed: true, todoAnalyzed: 'canvas-images' })
|
||||
expect(result).toMatchObject({ errors: [], manualRevision: 1, editedRevision: 3, createdAnalyzed: true, todoAnalyzed: supportsImageInput ? 'canvas-images' : 'text-fallback' })
|
||||
expect(result.requests).toHaveLength(6)
|
||||
for (const request of result.requests.slice(0, 5)) {
|
||||
expect(request.imageCount).toBe(supportsImageInput ? 2 : 0)
|
||||
expect(request.prompt).toContain('Included second')
|
||||
expect(request.prompt).not.toContain('Excluded third')
|
||||
}
|
||||
expect(result.requests[5].prompt).toContain('Automatic start')
|
||||
expect(result.requests[5].prompt).not.toContain('Automatic excluded tail')
|
||||
expect(result.requests[5].imageCount).toBe(supportsImageInput ? 2 : 0)
|
||||
} finally {
|
||||
await server.close()
|
||||
await rm(directory, { recursive: true, force: true })
|
||||
|
||||
Reference in New Issue
Block a user