143 lines
5.0 KiB
JavaScript
143 lines
5.0 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
import { buildVisionPayload, extractImageUrlsFromMessage } from './tkmind-proxy.mjs';
|
|
|
|
test('extractImageUrlsFromMessage reads metadata image urls', () => {
|
|
const urls = extractImageUrlsFromMessage({
|
|
metadata: {
|
|
imageUrls: ['/api/mindspace/v1/assets/asset-1/download?inline=1'],
|
|
},
|
|
content: [{ type: 'text', text: '根据图片生成页面' }],
|
|
});
|
|
|
|
assert.deepEqual(urls, ['/api/mindspace/v1/assets/asset-1/download?inline=1']);
|
|
});
|
|
|
|
test('extractImageUrlsFromMessage falls back to formatted image lines', () => {
|
|
const urls = extractImageUrlsFromMessage({
|
|
metadata: { userVisible: true, agentVisible: true },
|
|
content: [
|
|
{
|
|
type: 'text',
|
|
text:
|
|
'根据图片生成一个主题页面\n\n' +
|
|
'[图片1]: https://m.tkmind.cn/api/mindspace/v1/assets/asset-2/download?inline=1&v=123',
|
|
},
|
|
],
|
|
});
|
|
|
|
assert.deepEqual(urls, [
|
|
'https://m.tkmind.cn/api/mindspace/v1/assets/asset-2/download?inline=1&v=123',
|
|
]);
|
|
});
|
|
|
|
test('extractImageUrlsFromMessage deduplicates image urls', () => {
|
|
const url = '/api/mindspace/v1/assets/asset-3/download?inline=1';
|
|
const urls = extractImageUrlsFromMessage({
|
|
metadata: { imageUrls: [url] },
|
|
content: [{ type: 'text', text: `[图片1]: ${url}` }],
|
|
});
|
|
|
|
assert.deepEqual(urls, [url]);
|
|
});
|
|
|
|
test('extractImageUrlsFromMessage ignores content aliases when metadata is present', () => {
|
|
const urls = extractImageUrlsFromMessage({
|
|
metadata: {
|
|
imageUrls: ['/api/mindspace/v1/assets/asset-4/download?inline=1'],
|
|
},
|
|
content: [
|
|
{
|
|
type: 'text',
|
|
text:
|
|
'[图片1]: https://m.tkmind.cn/MindSpace/user/public/images/2026-07-10/asset-4.jpg',
|
|
},
|
|
],
|
|
});
|
|
|
|
assert.deepEqual(urls, ['/api/mindspace/v1/assets/asset-4/download?inline=1']);
|
|
});
|
|
|
|
test('buildVisionPayload marks one billable image analysis when vision succeeds', async () => {
|
|
const result = await buildVisionPayload({
|
|
userId: 'user-1',
|
|
publishLayout: { publicUrl: 'https://m.tkmind.cn/MindSpace/user-1' },
|
|
userMessage: {
|
|
content: [{ type: 'text', text: '根据图片生成页面\n\n[图片1]: /api/mindspace/v1/assets/asset-1/download?inline=1' }],
|
|
},
|
|
localFetchAsset: async () => ({
|
|
buffer: Buffer.from('fake-image'),
|
|
mimeType: 'image/png',
|
|
}),
|
|
llmProviderService: {
|
|
analyzeImagesWithVision: async () => '一位小女孩正在餐厅里开心地吃饭',
|
|
},
|
|
});
|
|
|
|
assert.equal(result?.billableImageCount, 1);
|
|
assert.match(result?.userMessage?.content?.[0]?.text ?? '', /Qwen VL 图片描述/);
|
|
assert.match(result?.userMessage?.content?.[0]?.text ?? '', /本轮图片主题/);
|
|
assert.equal(
|
|
result?.userMessage?.metadata?.displayText,
|
|
'根据图片生成页面\n\n[图片1]: /api/mindspace/v1/assets/asset-1/download?inline=1',
|
|
);
|
|
});
|
|
|
|
test('buildVisionPayload sends all current-turn images to Qwen in order', async () => {
|
|
const imageUrls = [
|
|
'https://m.tkmind.cn/MindSpace/user-1/public/wechat-mp/first.jpg',
|
|
'https://m.tkmind.cn/MindSpace/user-1/public/wechat-mp/second.jpg',
|
|
];
|
|
let analyzedImages = [];
|
|
const result = await buildVisionPayload({
|
|
userId: 'user-1',
|
|
publishLayout: { publicUrl: 'https://m.tkmind.cn/MindSpace/user-1' },
|
|
userMessage: {
|
|
content: [{ type: 'text', text: '请结合两张图片生成页面' }],
|
|
metadata: { imageUrls },
|
|
},
|
|
fetchImpl: async () =>
|
|
new Response(Buffer.from('fake-image'), {
|
|
status: 200,
|
|
headers: { 'Content-Type': 'image/jpeg' },
|
|
}),
|
|
llmProviderService: {
|
|
analyzeImagesWithVision: async (images) => {
|
|
analyzedImages = images;
|
|
return '第一张是宝塔,第二张是晚霞。';
|
|
},
|
|
},
|
|
});
|
|
|
|
assert.equal(analyzedImages.length, 2);
|
|
assert.deepEqual(analyzedImages.map((item) => item.rawUrl), imageUrls);
|
|
assert.deepEqual(result?.userMessage?.metadata?.imageUrls, [
|
|
'/MindSpace/user-1/public/wechat-mp/first.jpg',
|
|
'/MindSpace/user-1/public/wechat-mp/second.jpg',
|
|
]);
|
|
assert.match(result?.userMessage?.content?.[0]?.text ?? '', /本轮用户仅上传 2 张图片/);
|
|
assert.match(result?.userMessage?.content?.[0]?.text ?? '', /图片2/);
|
|
});
|
|
|
|
test('buildVisionPayload does not mark billable usage when vision analysis fails', async () => {
|
|
const result = await buildVisionPayload({
|
|
userId: 'user-1',
|
|
publishLayout: { publicUrl: 'https://m.tkmind.cn/MindSpace/user-1' },
|
|
userMessage: {
|
|
content: [{ type: 'text', text: '根据图片生成页面\n\n[图片1]: /api/mindspace/v1/assets/asset-1/download?inline=1' }],
|
|
},
|
|
localFetchAsset: async () => ({
|
|
buffer: Buffer.from('fake-image'),
|
|
mimeType: 'image/png',
|
|
}),
|
|
llmProviderService: {
|
|
analyzeImagesWithVision: async () => {
|
|
throw new Error('vision unavailable');
|
|
},
|
|
},
|
|
});
|
|
|
|
assert.equal(result?.billableImageCount, 0);
|
|
assert.doesNotMatch(result?.userMessage?.content?.[0]?.text ?? '', /Qwen VL 图片描述/);
|
|
});
|