diff --git a/src/services/tools/executor.ts b/src/services/tools/executor.ts index fb20e40..54edcc4 100644 --- a/src/services/tools/executor.ts +++ b/src/services/tools/executor.ts @@ -33,6 +33,7 @@ import { type MetasoSearchInput, type MetasoSearchResponse, type MetasoImageResult, + type MetasoVideoResult, } from './metasoSearch'; import { metasoReader, @@ -58,6 +59,8 @@ export interface ToolExecutionResult { images?: string[]; /** 搜索到的图片数组(图片搜索时产生) */ searchImages?: MetasoImageResult[]; + /** 搜索到的视频数组(视频搜索时产生) */ + searchVideos?: MetasoVideoResult[]; /** 是否需要浏览器端 Pyodide 执行 */ requiresPyodide?: boolean; /** 代码内容(当 requiresPyodide 为 true 时) */ @@ -148,12 +151,12 @@ export async function executeTool( case 'mita_search': { const query = String(input.query || ''); - const scope = (input.scope as 'webpage' | 'image') || 'webpage'; + const scope = (input.scope as 'webpage' | 'image' | 'video') || 'webpage'; - // 图片搜索时请求更多图片用于验证筛选,网页搜索保持原有逻辑 + // 图片搜索时请求更多图片用于验证筛选,视频和网页搜索保持原有逻辑 const requestSize = scope === 'image' ? ImageValidationConfig.REQUEST_SIZE - : (input.size ? Number(input.size) : 10); + : (input.size ? Number(input.size) : (scope === 'video' ? 5 : 10)); const searchInput: MetasoSearchInput = { query, @@ -185,6 +188,8 @@ export async function executeTool( rawData: response, // 如果是图片搜索,返回验证后的图片数据 searchImages: scope === 'image' ? validatedImages : undefined, + // 如果是视频搜索,返回视频数据 + searchVideos: scope === 'video' ? response.videos : undefined, }; } diff --git a/src/services/tools/metasoSearch.ts b/src/services/tools/metasoSearch.ts index 4a21190..e79e7df 100644 --- a/src/services/tools/metasoSearch.ts +++ b/src/services/tools/metasoSearch.ts @@ -1,6 +1,6 @@ /** * 秘塔AI搜索工具服务 - * 使用秘塔AI API 实现智能搜索(支持网页搜索和图片搜索) + * 使用秘塔AI API 实现智能搜索(支持网页搜索、图片搜索和视频搜索) */ // ============ 图片验证相关常量 ============ @@ -9,6 +9,9 @@ const IMAGE_VALIDATION_CONCURRENCY = 5; // 并发验证数量 const IMAGE_REQUEST_SIZE = 15; // 图片搜索时请求的数量 const IMAGE_TARGET_COUNT = 10; // 返回给前端的图片数量(前端会显示5张+5张备用) +// ============ 视频搜索相关常量 ============ +const VIDEO_DEFAULT_SIZE = 5; // 视频搜索默认数量 + // 网页搜索结果 export interface MetasoSearchResult { title: string; @@ -31,23 +34,38 @@ export interface MetasoImageResult { sourceUrl?: string; } +// 视频搜索结果 +export interface MetasoVideoResult { + title: string; + link: string; + snippet: string; + score: string; + position: number; + authors: string[]; + date: string; + duration: string; + coverImage: string; +} + // 搜索响应 export interface MetasoSearchResponse { success: boolean; credits?: number; total?: number; - scope?: 'webpage' | 'image'; + scope?: 'webpage' | 'image' | 'video'; // 网页搜索结果 results?: MetasoSearchResult[]; // 图片搜索结果 images?: MetasoImageResult[]; + // 视频搜索结果 + videos?: MetasoVideoResult[]; error?: string; } // 搜索输入参数 export interface MetasoSearchInput { query: string; - scope?: 'webpage' | 'image'; + scope?: 'webpage' | 'image' | 'video'; size?: number; /** 页码,用于获取不同页的结果(从1开始) */ page?: number; @@ -71,7 +89,8 @@ export async function metasoSearch( } const scope = input.scope || 'webpage'; - const size = input.size || (scope === 'image' ? 5 : 10); // 图片默认5张 + // 根据 scope 设置默认 size + const size = input.size || (scope === 'image' ? 5 : scope === 'video' ? VIDEO_DEFAULT_SIZE : 10); try { const response = await fetch('https://metaso.cn/api/v1/search', { @@ -111,7 +130,36 @@ export async function metasoSearch( const data = await response.json(); // 根据 scope 解析不同的结果 - if (scope === 'image') { + if (scope === 'video') { + // 视频搜索结果 + return { + success: true, + credits: data.credits, + total: data.total, + scope: 'video', + videos: data.videos?.map((item: { + title: string; + link: string; + snippet: string; + score: string; + position: number; + authors?: string[]; + date?: string; + duration?: string; + coverImage?: string; + }) => ({ + title: item.title, + link: item.link, + snippet: item.snippet, + score: item.score, + position: item.position, + authors: item.authors || [], + date: item.date || '', + duration: item.duration || '0', + coverImage: item.coverImage || '', + })), + }; + } else if (scope === 'image') { // 图片搜索结果 return { success: true, @@ -179,6 +227,25 @@ export function formatMetasoSearchResults(response: MetasoSearchResponse): strin return `搜索失败: ${response.error}`; } + // 视频搜索结果 + if (response.scope === 'video' && response.videos) { + let result = `## 秘塔视频搜索结果 (共${response.total}个)\n\n`; + response.videos.forEach((item, index) => { + result += `${index + 1}. **${item.title}**\n`; + result += ` - 链接: ${item.link}\n`; + result += ` - 时长: ${item.duration}秒\n`; + if (item.authors && item.authors.length > 0) { + result += ` - 作者: ${item.authors.join(', ')}\n`; + } + if (item.date) { + result += ` - 发布日期: ${item.date}\n`; + } + result += ` - 摘要: ${item.snippet}\n`; + result += '\n'; + }); + return result; + } + // 图片搜索结果 if (response.scope === 'image' && response.images) { let result = `## 秘塔图片搜索结果 (共${response.total}张)\n\n`; @@ -339,6 +406,12 @@ export function formatMetasoSearchResultsShort( return `搜索失败: ${response.error}`; } + // 视频搜索结果 + if (response.scope === 'video' && response.videos) { + const videoCount = response.videos.length; + return `> 🎬 秘塔搜索「${query}」视频,找到 ${response.total || videoCount} 个相关视频`; + } + // 图片搜索结果 if (response.scope === 'image' && response.images) { const imageCount = response.images.length;