mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-29 05:23:55 +08:00
update:由于现在的模型本身动作有限,使用起来体验不佳,暂时移除动作控制的代码
This commit is contained in:
@@ -305,43 +305,6 @@ export function getMcpTools() {
|
||||
return mcpTools.map(tool => ({ name: tool.name, description: tool.description, inputSchema: tool.inputSchema }));
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行Live2D动作
|
||||
* @param {string} toolName - 工具名称,如 'live2d.smile', 'live2d.wave', 'live2d.action'
|
||||
* @param {Object} toolArgs - 工具参数,对于 'live2d.action' 工具,应包含 'action' 字段
|
||||
* @returns {Object} 执行结果,包含 success, message, action, tool 等字段
|
||||
*/
|
||||
function executeLive2DAction(toolName, toolArgs) {
|
||||
try {
|
||||
const live2dManager = window.chatApp?.live2dManager;
|
||||
if (!live2dManager) {
|
||||
log('Live2D管理器未初始化', 'error');
|
||||
return { success: false, error: 'Live2D管理器未初始化' };
|
||||
}
|
||||
// 动作映射:工具名称到Live2D动作名称
|
||||
const actionMap = { 'live2d.smile': 'FlickUp', 'live2d.wave': 'Tap', 'live2d.happy': 'FlickUp', 'live2d.sad': 'FlickDown', 'live2d.tap': 'Tap', 'live2d.tapBody': 'Tap@Body', 'live2d.flick': 'Flick', 'live2d.flickBody': 'Flick@Body', 'live2d.flickUp': 'FlickUp', 'live2d.flickDown': 'FlickDown' };
|
||||
let motionName;
|
||||
if (toolName === 'live2d.action' && toolArgs?.action) {
|
||||
// 通用动作工具,使用指定的动作名称
|
||||
motionName = toolArgs.action;
|
||||
} else {
|
||||
// 使用映射表查找对应动作名称
|
||||
motionName = actionMap[toolName];
|
||||
}
|
||||
if (!motionName) {
|
||||
log(`未知的动作: ${toolName}`, 'error');
|
||||
return { success: false, error: `未知的动作: ${toolName}` };
|
||||
}
|
||||
// 触发Live2D动作
|
||||
live2dManager.motion(motionName);
|
||||
log(`Live2D动作已触发: ${motionName}`, 'success');
|
||||
return { success: true, message: `虚拟人已执行动作: ${motionName}`, action: motionName, tool: toolName };
|
||||
} catch (error) {
|
||||
log(`执行Live2D动作失败: ${error.message}`, 'error');
|
||||
return { success: false, error: `执行动作失败: ${error.message}` };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行工具调用
|
||||
*/
|
||||
@@ -351,10 +314,6 @@ export function executeMcpTool(toolName, toolArgs) {
|
||||
log(`未找到工具: ${toolName}`, 'error');
|
||||
return { success: false, error: `未知工具: ${toolName}` };
|
||||
}
|
||||
// 处理Live2D动作工具
|
||||
if (toolName.startsWith('live2d.')) {
|
||||
return executeLive2DAction(toolName, toolArgs);
|
||||
}
|
||||
// 如果有模拟返回结果,使用它
|
||||
if (tool.mockResponse) {
|
||||
// 替换模板变量
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
/**
|
||||
* MCP工具模块测试 - Browser compatible version
|
||||
* 测试Live2D动作工具执行功能
|
||||
*
|
||||
* This version works without Vitest - uses the simple test framework from test-runner.html
|
||||
*/
|
||||
|
||||
import { executeMcpTool, initMcpTools, setWebSocket } from './tools.js';
|
||||
|
||||
describe('Live2D Action Tools', () => {
|
||||
let mockLive2DManager, originalChatApp;
|
||||
|
||||
beforeEach(() => {
|
||||
// Reset mocks before each test
|
||||
vi.clearAllMocks();
|
||||
// Save original chatApp
|
||||
originalChatApp = window.chatApp;
|
||||
// Mock Live2D manager
|
||||
mockLive2DManager = { motion: vi.fn() };
|
||||
// Setup window.chatApp
|
||||
window.chatApp = { live2dManager: mockLive2DManager };
|
||||
// Mock localStorage
|
||||
localStorage.getItem = vi.fn(() => null);
|
||||
// Mock fetch for default-mcp-tools.json
|
||||
globalThis.fetch = vi.fn(() => Promise.resolve({ json: () => Promise.resolve([{ name: 'live2d.smile', description: 'Make the virtual human smile', inputSchema: { type: 'object', properties: {} } }, { name: 'live2d.wave', description: 'Make the virtual human wave', inputSchema: { type: 'object', properties: {} } }, { name: 'live2d.action', description: 'Trigger a specified action', inputSchema: { type: 'object', properties: { action: { type: 'string' } }, required: ['action'] } }]) }));
|
||||
// Mock DOM elements - ensure all required elements exist
|
||||
const mockContainer = { innerHTML: '', appendChild: vi.fn(), textContent: '' };
|
||||
document.getElementById = vi.fn((id) => {
|
||||
// Return mock elements for all IDs that tools.js might access
|
||||
if (id === 'mcpToolsContainer' || id === 'mcpPropertiesContainer') return mockContainer;
|
||||
if (id === 'mcpToolsCount') return { textContent: '' };
|
||||
// Return null for other elements (they're checked with if statements)
|
||||
return null;
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// Clean up
|
||||
window.chatApp = originalChatApp;
|
||||
});
|
||||
|
||||
/**
|
||||
* 测试 executeMcpTool - smile 动作
|
||||
*/
|
||||
test('should execute Live2D smile action', async () => {
|
||||
await initMcpTools();
|
||||
const result = executeMcpTool('live2d.smile', {});
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.action).toBe('FlickUp');
|
||||
expect(result.tool).toBe('live2d.smile');
|
||||
expect(mockLive2DManager.motion).toHaveBeenCalledWith('FlickUp');
|
||||
});
|
||||
|
||||
/**
|
||||
* 测试 executeMcpTool - wave 动作
|
||||
*/
|
||||
test('should execute Live2D wave action', async () => {
|
||||
await initMcpTools();
|
||||
const result = executeMcpTool('live2d.wave', {});
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.action).toBe('Tap');
|
||||
expect(result.tool).toBe('live2d.wave');
|
||||
expect(mockLive2DManager.motion).toHaveBeenCalledWith('Tap');
|
||||
});
|
||||
|
||||
/**
|
||||
* 测试 executeMcpTool - 通用动作工具
|
||||
*/
|
||||
test('should handle generic action tool', async () => {
|
||||
await initMcpTools();
|
||||
const result = executeMcpTool('live2d.action', { action: 'FlickDown' });
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.action).toBe('FlickDown');
|
||||
expect(result.tool).toBe('live2d.action');
|
||||
expect(mockLive2DManager.motion).toHaveBeenCalledWith('FlickDown');
|
||||
});
|
||||
|
||||
/**
|
||||
* 测试 executeMcpTool - Live2D管理器未初始化
|
||||
*/
|
||||
test('should handle missing Live2D manager gracefully', async () => {
|
||||
await initMcpTools();
|
||||
window.chatApp = null;
|
||||
const result = executeMcpTool('live2d.smile', {});
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.error).toContain('Live2D管理器未初始化');
|
||||
});
|
||||
|
||||
/**
|
||||
* 测试 executeMcpTool - 未知的工具
|
||||
*/
|
||||
test('should handle unknown tool gracefully', async () => {
|
||||
await initMcpTools();
|
||||
const result = executeMcpTool('unknown.tool', {});
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.error).toContain('未知工具');
|
||||
});
|
||||
});
|
||||
@@ -1,133 +0,0 @@
|
||||
/**
|
||||
* MCP工具模块测试
|
||||
* 测试Live2D动作工具执行功能
|
||||
*/
|
||||
|
||||
import { describe, test, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||
import { executeMcpTool, initMcpTools, setWebSocket } from './tools.js';
|
||||
|
||||
describe('Live2D Action Tools', () => {
|
||||
let mockLive2DManager;
|
||||
|
||||
beforeEach(() => {
|
||||
// Reset mocks before each test
|
||||
vi.clearAllMocks();
|
||||
// Mock Live2D manager
|
||||
mockLive2DManager = { motion: vi.fn() };
|
||||
// Setup window.chatApp
|
||||
global.window.chatApp = { live2dManager: mockLive2DManager };
|
||||
// Mock localStorage
|
||||
global.localStorage.getItem = vi.fn(() => null);
|
||||
// Mock fetch for default-mcp-tools.json
|
||||
global.fetch = vi.fn(() => Promise.resolve({ json: () => Promise.resolve([{ name: 'live2d.smile', description: 'Make the virtual human smile', inputSchema: { type: 'object', properties: {} } }, { name: 'live2d.wave', description: 'Make the virtual human wave', inputSchema: { type: 'object', properties: {} } }, { name: 'live2d.action', description: 'Trigger a specified action', inputSchema: { type: 'object', properties: { action: { type: 'string' } }, required: ['action'] } }]) }));
|
||||
// Mock DOM elements
|
||||
global.document.getElementById = vi.fn((id) => {
|
||||
if (id === 'mcpToolsContainer') {
|
||||
return { innerHTML: '', appendChild: vi.fn() };
|
||||
}
|
||||
if (id === 'mcpToolsCount') {
|
||||
return { textContent: '' };
|
||||
}
|
||||
return null;
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// Clean up
|
||||
global.window.chatApp = null;
|
||||
});
|
||||
|
||||
/**
|
||||
* 测试 executeMcpTool - smile 动作
|
||||
*/
|
||||
test('should execute Live2D smile action', async () => {
|
||||
await initMcpTools();
|
||||
const result = executeMcpTool('live2d.smile', {});
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.action).toBe('FlickUp');
|
||||
expect(result.tool).toBe('live2d.smile');
|
||||
expect(mockLive2DManager.motion).toHaveBeenCalledWith('FlickUp');
|
||||
});
|
||||
|
||||
/**
|
||||
* 测试 executeMcpTool - wave 动作
|
||||
*/
|
||||
test('should execute Live2D wave action', async () => {
|
||||
await initMcpTools();
|
||||
const result = executeMcpTool('live2d.wave', {});
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.action).toBe('Tap');
|
||||
expect(result.tool).toBe('live2d.wave');
|
||||
expect(mockLive2DManager.motion).toHaveBeenCalledWith('Tap');
|
||||
});
|
||||
|
||||
/**
|
||||
* 测试 executeMcpTool - 通用动作工具
|
||||
*/
|
||||
test('should handle generic action tool', async () => {
|
||||
await initMcpTools();
|
||||
const result = executeMcpTool('live2d.action', { action: 'FlickDown' });
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.action).toBe('FlickDown');
|
||||
expect(result.tool).toBe('live2d.action');
|
||||
expect(mockLive2DManager.motion).toHaveBeenCalledWith('FlickDown');
|
||||
});
|
||||
|
||||
/**
|
||||
* 测试 executeMcpTool - Live2D管理器未初始化
|
||||
*/
|
||||
test('should handle missing Live2D manager gracefully', async () => {
|
||||
await initMcpTools();
|
||||
global.window.chatApp = null;
|
||||
const result = executeMcpTool('live2d.smile', {});
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.error).toContain('Live2D管理器未初始化');
|
||||
});
|
||||
|
||||
/**
|
||||
* 测试 executeMcpTool - 未知的动作
|
||||
*/
|
||||
test('should handle unknown action gracefully', async () => {
|
||||
await initMcpTools();
|
||||
// Add an unknown live2d tool to the list
|
||||
const tools = await global.fetch().then(res => res.json());
|
||||
tools.push({ name: 'live2d.unknown', description: 'Unknown action', inputSchema: { type: 'object', properties: {} } });
|
||||
global.fetch = vi.fn(() => Promise.resolve({ json: () => Promise.resolve(tools) }));
|
||||
await initMcpTools();
|
||||
const result = executeMcpTool('live2d.unknown', {});
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.error).toContain('未知的动作');
|
||||
});
|
||||
|
||||
/**
|
||||
* 测试 executeMcpTool - 未知的工具
|
||||
*/
|
||||
test('should handle unknown tool gracefully', async () => {
|
||||
await initMcpTools();
|
||||
const result = executeMcpTool('unknown.tool', {});
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.error).toContain('未知工具');
|
||||
});
|
||||
|
||||
/**
|
||||
* 测试 executeMcpTool - 其他动作映射
|
||||
*/
|
||||
test('should handle other action mappings', async () => {
|
||||
await initMcpTools();
|
||||
const actionMappings = [{ tool: 'live2d.happy', expectedAction: 'FlickUp' }, { tool: 'live2d.sad', expectedAction: 'FlickDown' }, { tool: 'live2d.tap', expectedAction: 'Tap' }, { tool: 'live2d.tapBody', expectedAction: 'Tap@Body' }, { tool: 'live2d.flick', expectedAction: 'Flick' }, { tool: 'live2d.flickBody', expectedAction: 'Flick@Body' }, { tool: 'live2d.flickUp', expectedAction: 'FlickUp' }, { tool: 'live2d.flickDown', expectedAction: 'FlickDown' }];
|
||||
// Add these tools to the mock
|
||||
const tools = await global.fetch().then(res => res.json());
|
||||
actionMappings.forEach(mapping => {
|
||||
tools.push({ name: mapping.tool, description: `Test ${mapping.tool}`, inputSchema: { type: 'object', properties: {} } });
|
||||
});
|
||||
global.fetch = vi.fn(() => Promise.resolve({ json: () => Promise.resolve(tools) }));
|
||||
await initMcpTools();
|
||||
for (const mapping of actionMappings) {
|
||||
mockLive2DManager.motion.mockClear();
|
||||
const result = executeMcpTool(mapping.tool, {});
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.action).toBe(mapping.expectedAction);
|
||||
expect(mockLive2DManager.motion).toHaveBeenCalledWith(mapping.expectedAction);
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user