@@ -0,0 +1,38 @@
|
||||
export function createWebcamTools({ camera, capture, normalizer } = {}) {
|
||||
const guard = () => {
|
||||
if (!camera) throw new Error('webcam is unavailable');
|
||||
camera.assertActive();
|
||||
};
|
||||
return [{
|
||||
name: 'webcam',
|
||||
permission: 'read',
|
||||
description: 'Capture one frame from the user webcam after Settings → Camera → Allow now. The still is attached for this turn. Do not paste the file path into speech.',
|
||||
parameters: { type: 'object', properties: {} },
|
||||
execute: async () => {
|
||||
try {
|
||||
guard();
|
||||
if (!capture?.capture) throw new Error('webcam helper is unavailable');
|
||||
const raw = `/tmp/jarvis-webcam/frame-${Date.now()}.png`;
|
||||
const grabbed = await capture.capture(raw, { device: camera.device });
|
||||
if (grabbed?.via) camera.setBackend(grabbed.via);
|
||||
// QVAC MtmdLlm / llama.cpp decode JPEG and PNG, not WebP.
|
||||
const still = `/tmp/jarvis-webcam/still-${Date.now()}.jpg`;
|
||||
const frame = normalizer?.normalize
|
||||
? await normalizer.normalize(grabbed.path || raw, still)
|
||||
: { path: grabbed.path || raw, mime: 'image/png' };
|
||||
const mime = frame.mime || 'image/jpeg';
|
||||
return {
|
||||
ok: true,
|
||||
via: grabbed.via || camera.backend,
|
||||
mime,
|
||||
width: frame.width,
|
||||
height: frame.height,
|
||||
note: 'The webcam still is attached for this turn. Describe what you see. Do not speak the file path.',
|
||||
images: [{ path: frame.path, mime }],
|
||||
};
|
||||
} catch (error) {
|
||||
return { error: error.message, next_action: 'Press Allow now in Settings, Camera' };
|
||||
}
|
||||
},
|
||||
}];
|
||||
}
|
||||
Reference in New Issue
Block a user