CMMS fork: hand the board photos to the AI bridge
The board photos live in pcb-retrace's IndexedDB, not as CMMS
attachments, so the assistant had no way to see them and burned all its
tool-call rounds looking. cmms-bridge.js now downscales each project
photo (long edge ~1400px, JPEG q0.8 - a phone photo lands under ~300KB)
and sends them alongside the buffer in the cmms-ai-editor-buffer reply
as `images: [{id,name,mime,data_base64}]` (max 6). The CMMS
read_board_image tool surfaces one at a time.
This commit is contained in:
parent
04d29dc0ac
commit
40373493b5
1 changed files with 44 additions and 1 deletions
|
|
@ -160,6 +160,47 @@
|
||||||
return JSON.stringify(view);
|
return JSON.stringify(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The board photos live in pcb-retrace's IndexedDB (imported by the user or
|
||||||
|
// unpacked from the .pcbretrace.zip), NOT as CMMS attachments, so the
|
||||||
|
// assistant can't reach them with read_attachment_image. Downscale + JPEG
|
||||||
|
// each and hand them along with the buffer so a `read_board_image` tool can
|
||||||
|
// surface them. Long edge ~1400px, quality 0.8 - a phone photo lands well
|
||||||
|
// under 300KB.
|
||||||
|
async function encodeImage(blob, maxEdge) {
|
||||||
|
const bmp = await createImageBitmap(blob);
|
||||||
|
const s = Math.min(1, maxEdge / Math.max(bmp.width, bmp.height));
|
||||||
|
const w = Math.max(1, Math.round(bmp.width * s));
|
||||||
|
const h = Math.max(1, Math.round(bmp.height * s));
|
||||||
|
const c = document.createElement('canvas');
|
||||||
|
c.width = w; c.height = h;
|
||||||
|
c.getContext('2d').drawImage(bmp, 0, 0, w, h);
|
||||||
|
bmp.close();
|
||||||
|
const out = await new Promise(res => c.toBlob(res, 'image/jpeg', 0.8));
|
||||||
|
const b64 = await new Promise((res, rej) => {
|
||||||
|
const r = new FileReader();
|
||||||
|
r.onload = () => res(String(r.result).split(',', 2)[1] || '');
|
||||||
|
r.onerror = rej;
|
||||||
|
r.readAsDataURL(out);
|
||||||
|
});
|
||||||
|
return { w, h, b64 };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function buildProjectImages() {
|
||||||
|
if (!currentBomId || !bomImages.length) return [];
|
||||||
|
const out = [];
|
||||||
|
for (const img of bomImages.slice(0, 6)) {
|
||||||
|
try {
|
||||||
|
const enc = await encodeImage(img.blob, 1400);
|
||||||
|
if (enc.b64.length > 3 * 1024 * 1024) { trace('image too large after encode, skipping', img.id); continue; }
|
||||||
|
out.push({ id: img.id, name: img.name || (img.id + '.jpg'), mime: 'image/jpeg', data_base64: enc.b64 });
|
||||||
|
} catch (e) {
|
||||||
|
trace('image encode failed', img.id, e && e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trace('buildProjectImages:', out.length, 'of', bomImages.length, 'photos encoded');
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
async function applyProjectPatch(patchJson) {
|
async function applyProjectPatch(patchJson) {
|
||||||
const patch = JSON.parse(patchJson);
|
const patch = JSON.parse(patchJson);
|
||||||
if (!currentBomId) { status('Select or create a board first', true); return; }
|
if (!currentBomId) { status('Select or create a board first', true); return; }
|
||||||
|
|
@ -227,8 +268,10 @@
|
||||||
if (d.type === 'cmms-ai-editor-get-buffer') {
|
if (d.type === 'cmms-ai-editor-get-buffer') {
|
||||||
trace('get-buffer received');
|
trace('get-buffer received');
|
||||||
let buffer = null;
|
let buffer = null;
|
||||||
|
let images = [];
|
||||||
try { buffer = await buildProjectView(); } catch (e) { trace('buildProjectView threw:', e && e.message); }
|
try { buffer = await buildProjectView(); } catch (e) { trace('buildProjectView threw:', e && e.message); }
|
||||||
replyToChat(evt.source, { type: 'cmms-ai-editor-buffer', buffer: buffer });
|
try { images = await buildProjectImages(); } catch (e) { trace('buildProjectImages threw:', e && e.message); }
|
||||||
|
replyToChat(evt.source, { type: 'cmms-ai-editor-buffer', buffer: buffer, images: images });
|
||||||
} else if (d.type === 'cmms-ai-editor-apply' && d.editor === 'pcb' && typeof d.new_source === 'string') {
|
} else if (d.type === 'cmms-ai-editor-apply' && d.editor === 'pcb' && typeof d.new_source === 'string') {
|
||||||
trace('apply received');
|
trace('apply received');
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue