🏗️ 项目重构:模块化清理完成
This commit is contained in:
6
modules/testing-framework/pytest.ini
Normal file
6
modules/testing-framework/pytest.ini
Normal file
@@ -0,0 +1,6 @@
|
||||
[pytest]
|
||||
testpaths = tests
|
||||
python_files = test_*.py
|
||||
python_classes = Test*
|
||||
python_functions = test_*
|
||||
addopts = --cov=src --cov-report=html --cov-report=term-missing --asyncio-mode=auto
|
||||
@@ -0,0 +1,24 @@
|
||||
class TestCulturalAccuracy:
|
||||
"""文化准确性测试"""
|
||||
|
||||
def test_immortal_characteristics(self):
|
||||
"""验证八仙特征的准确性"""
|
||||
# immortals = get_immortal_configs()
|
||||
#
|
||||
# # 验证吕洞宾的技术分析特色
|
||||
# assert immortals['吕洞宾'].specialty == 'technical_analysis'
|
||||
# assert immortals['吕洞宾'].element == '乾'
|
||||
#
|
||||
# # 验证何仙姑的风险控制特色
|
||||
# assert immortals['何仙姑'].specialty == 'risk_metrics'
|
||||
# assert immortals['何仙姑'].element == '坤'
|
||||
pass
|
||||
|
||||
def test_debate_cultural_context(self):
|
||||
"""验证辩论的文化背景准确性"""
|
||||
# debate = create_test_debate('AAPL')
|
||||
#
|
||||
# # 确保辩论遵循稷下学宫的传统
|
||||
# assert 'jixia' in debate.context
|
||||
# assert len(debate.participants) == 8 # 八仙
|
||||
pass
|
||||
@@ -0,0 +1,3 @@
|
||||
class TestDebateDataQuality:
|
||||
"""辩论数据质量测试"""
|
||||
pass
|
||||
@@ -0,0 +1,14 @@
|
||||
class TestImmortalDataRouting:
|
||||
"""八仙数据路由测试"""
|
||||
|
||||
def test_lv_dongbin_technical_analysis(self):
|
||||
"""测试吕洞宾的技术分析数据获取"""
|
||||
pass
|
||||
|
||||
def test_he_xiangu_risk_metrics(self):
|
||||
"""测试何仙姑的风险指标数据"""
|
||||
pass
|
||||
|
||||
def test_immortal_data_consistency(self):
|
||||
"""测试八仙数据的一致性"""
|
||||
pass
|
||||
@@ -0,0 +1,3 @@
|
||||
class TestImmortalPreferences:
|
||||
"""八仙偏好测试"""
|
||||
pass
|
||||
@@ -0,0 +1,62 @@
|
||||
import pytest
|
||||
from unittest import mock
|
||||
from src.jixia.engines.openbb_stock_data import get_stock_data
|
||||
from types import SimpleNamespace
|
||||
|
||||
class TestOpenBBIntegration:
|
||||
"""OpenBB集成测试套件"""
|
||||
|
||||
def test_stock_data_retrieval(self):
|
||||
"""测试股票数据成功获取"""
|
||||
# 创建一个模拟的'openbb'模块
|
||||
mock_openbb_module = mock.MagicMock()
|
||||
# 在该模块上创建一个模拟的'obb'属性
|
||||
mock_obb_object = mock.MagicMock()
|
||||
mock_openbb_module.obb = mock_obb_object
|
||||
|
||||
# 配置模拟的obb对象的返回值
|
||||
mock_data = [
|
||||
SimpleNamespace(date='2023-01-01', open=100, high=110, low=90, close=105, volume=10000),
|
||||
SimpleNamespace(date='2023-01-02', open=105, high=115, low=102, close=112, volume=12000)
|
||||
]
|
||||
mock_obb_object.equity.price.historical.return_value = SimpleNamespace(results=mock_data)
|
||||
|
||||
# 使用patch.dict来模拟openbb模块的导入
|
||||
with mock.patch.dict('sys.modules', {'openbb': mock_openbb_module}):
|
||||
data = get_stock_data('AAPL')
|
||||
|
||||
# 断言
|
||||
assert data is not None
|
||||
assert len(data) == 2
|
||||
assert data[0].close == 105
|
||||
mock_obb_object.equity.price.historical.assert_called_once()
|
||||
|
||||
def test_stock_data_handles_api_error(self):
|
||||
"""测试当OpenBB API未返回有效数据时的情况"""
|
||||
mock_openbb_module = mock.MagicMock()
|
||||
mock_obb_object = mock.MagicMock()
|
||||
mock_openbb_module.obb = mock_obb_object
|
||||
|
||||
# 配置模拟的obb对象以返回没有结果的情况
|
||||
mock_obb_object.equity.price.historical.return_value = SimpleNamespace(results=None)
|
||||
|
||||
with mock.patch.dict('sys.modules', {'openbb': mock_openbb_module}):
|
||||
data = get_stock_data('FAIL')
|
||||
|
||||
# 断言
|
||||
assert data is None
|
||||
mock_obb_object.equity.price.historical.assert_called_once_with(
|
||||
symbol='FAIL',
|
||||
provider='yfinance',
|
||||
start_date=mock.ANY,
|
||||
end_date=mock.ANY
|
||||
)
|
||||
|
||||
def test_stock_data_handles_import_error(self):
|
||||
"""测试openbb库不可用时的降级行为"""
|
||||
# 模拟sys.modules中没有openbb
|
||||
with mock.patch.dict('sys.modules', {'openbb': None}):
|
||||
data = get_stock_data('NOBB')
|
||||
|
||||
# 断言
|
||||
assert data is None
|
||||
299
modules/testing-framework/tests/test-api-example.js
Normal file
299
modules/testing-framework/tests/test-api-example.js
Normal file
@@ -0,0 +1,299 @@
|
||||
// API 测试示例脚本
|
||||
// 演示如何使用 Hyperdrive API 进行 CRUD 操作
|
||||
|
||||
const API_BASE_URL = 'https://hyperdrive-neondb-test.<your-subdomain>.workers.dev';
|
||||
const API_KEY = 'your-api-key'; // 可选,如果设置了 API_SECRET
|
||||
|
||||
// 通用请求函数
|
||||
async function apiRequest(endpoint, options = {}) {
|
||||
const url = `${API_BASE_URL}${endpoint}`;
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
...(API_KEY && { 'X-API-Key': API_KEY }),
|
||||
...options.headers
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
...options,
|
||||
headers
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`API Error: ${data.message || response.statusText}`);
|
||||
}
|
||||
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error(`Request failed for ${endpoint}:`, error.message);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// API 测试函数
|
||||
class ApiTester {
|
||||
static async testHealthCheck() {
|
||||
console.log('\n🏥 Testing health check...');
|
||||
try {
|
||||
const result = await apiRequest('/health');
|
||||
console.log('✅ Health check passed:', result.data);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.log('❌ Health check failed:', error.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static async initializeDatabase() {
|
||||
console.log('\n🗄️ Initializing database...');
|
||||
try {
|
||||
const result = await apiRequest('/init', { method: 'POST' });
|
||||
console.log('✅ Database initialized:', result.message);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.log('❌ Database initialization failed:', error.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static async createUser(name, email) {
|
||||
console.log(`\n👤 Creating user: ${name} (${email})...`);
|
||||
try {
|
||||
const result = await apiRequest('/users', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ name, email })
|
||||
});
|
||||
console.log('✅ User created:', result.data);
|
||||
return result.data;
|
||||
} catch (error) {
|
||||
console.log('❌ User creation failed:', error.message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static async getUsers(page = 1, limit = 10, search = null) {
|
||||
console.log(`\n📋 Getting users (page ${page}, limit ${limit}${search ? `, search: ${search}` : ''})...`);
|
||||
try {
|
||||
let endpoint = `/users?page=${page}&limit=${limit}`;
|
||||
if (search) endpoint += `&search=${encodeURIComponent(search)}`;
|
||||
|
||||
const result = await apiRequest(endpoint);
|
||||
console.log('✅ Users retrieved:', {
|
||||
count: result.data.length,
|
||||
total: result.meta.total,
|
||||
users: result.data.map(u => `${u.name} (${u.email})`)
|
||||
});
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.log('❌ Failed to get users:', error.message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static async getUserById(id) {
|
||||
console.log(`\n🔍 Getting user by ID: ${id}...`);
|
||||
try {
|
||||
const result = await apiRequest(`/users/${id}`);
|
||||
console.log('✅ User found:', result.data);
|
||||
return result.data;
|
||||
} catch (error) {
|
||||
console.log('❌ Failed to get user:', error.message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static async updateUser(id, updates) {
|
||||
console.log(`\n✏️ Updating user ${id}:`, updates);
|
||||
try {
|
||||
const result = await apiRequest(`/users/${id}`, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(updates)
|
||||
});
|
||||
console.log('✅ User updated:', result.data);
|
||||
return result.data;
|
||||
} catch (error) {
|
||||
console.log('❌ Failed to update user:', error.message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static async deleteUser(id) {
|
||||
console.log(`\n🗑️ Deleting user ${id}...`);
|
||||
try {
|
||||
const result = await apiRequest(`/users/${id}`, { method: 'DELETE' });
|
||||
console.log('✅ User deleted:', result.message);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.log('❌ Failed to delete user:', error.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static async getApiDocs() {
|
||||
console.log('\n📚 Getting API documentation...');
|
||||
try {
|
||||
const result = await apiRequest('/docs');
|
||||
console.log('✅ API Documentation:');
|
||||
console.log('Endpoints:', result.data.endpoints);
|
||||
console.log('Authentication:', result.data.authentication);
|
||||
console.log('Examples:', result.data.examples);
|
||||
return result.data;
|
||||
} catch (error) {
|
||||
console.log('❌ Failed to get API docs:', error.message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 完整的测试流程
|
||||
async function runFullTest() {
|
||||
console.log('🚀 Starting Hyperdrive API Test Suite');
|
||||
console.log('=====================================');
|
||||
|
||||
// 1. 健康检查
|
||||
const healthOk = await ApiTester.testHealthCheck();
|
||||
if (!healthOk) {
|
||||
console.log('\n❌ Health check failed. Please check your deployment.');
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 获取 API 文档
|
||||
await ApiTester.getApiDocs();
|
||||
|
||||
// 3. 初始化数据库
|
||||
await ApiTester.initializeDatabase();
|
||||
|
||||
// 4. 创建测试用户
|
||||
const user1 = await ApiTester.createUser('张三', 'zhangsan@example.com');
|
||||
const user2 = await ApiTester.createUser('李四', 'lisi@example.com');
|
||||
const user3 = await ApiTester.createUser('王五', 'wangwu@example.com');
|
||||
|
||||
if (!user1 || !user2 || !user3) {
|
||||
console.log('\n❌ Failed to create test users.');
|
||||
return;
|
||||
}
|
||||
|
||||
// 5. 获取用户列表
|
||||
await ApiTester.getUsers();
|
||||
|
||||
// 6. 搜索用户
|
||||
await ApiTester.getUsers(1, 10, '张');
|
||||
|
||||
// 7. 获取单个用户
|
||||
await ApiTester.getUserById(user1.id);
|
||||
|
||||
// 8. 更新用户
|
||||
await ApiTester.updateUser(user1.id, {
|
||||
name: '张三丰',
|
||||
email: 'zhangsanfeng@example.com'
|
||||
});
|
||||
|
||||
// 9. 验证更新
|
||||
await ApiTester.getUserById(user1.id);
|
||||
|
||||
// 10. 分页测试
|
||||
await ApiTester.getUsers(1, 2); // 第一页,每页2条
|
||||
await ApiTester.getUsers(2, 2); // 第二页,每页2条
|
||||
|
||||
// 11. 删除用户
|
||||
await ApiTester.deleteUser(user3.id);
|
||||
|
||||
// 12. 验证删除
|
||||
await ApiTester.getUserById(user3.id); // 应该返回 404
|
||||
|
||||
// 13. 最终用户列表
|
||||
await ApiTester.getUsers();
|
||||
|
||||
console.log('\n🎉 API Test Suite Completed!');
|
||||
console.log('============================');
|
||||
}
|
||||
|
||||
// 性能测试
|
||||
async function performanceTest() {
|
||||
console.log('\n⚡ Performance Test');
|
||||
console.log('==================');
|
||||
|
||||
const startTime = Date.now();
|
||||
const promises = [];
|
||||
|
||||
// 并发创建10个用户
|
||||
for (let i = 0; i < 10; i++) {
|
||||
promises.push(
|
||||
ApiTester.createUser(`测试用户${i}`, `test${i}@example.com`)
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
const results = await Promise.all(promises);
|
||||
const endTime = Date.now();
|
||||
const duration = endTime - startTime;
|
||||
|
||||
console.log(`✅ Created ${results.filter(r => r).length} users in ${duration}ms`);
|
||||
console.log(`📊 Average: ${(duration / 10).toFixed(2)}ms per user`);
|
||||
|
||||
// 清理测试数据
|
||||
console.log('\n🧹 Cleaning up test data...');
|
||||
for (const user of results.filter(r => r)) {
|
||||
await ApiTester.deleteUser(user.id);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.log('❌ Performance test failed:', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// 错误处理测试
|
||||
async function errorHandlingTest() {
|
||||
console.log('\n🚨 Error Handling Test');
|
||||
console.log('======================');
|
||||
|
||||
// 测试无效数据
|
||||
console.log('\n Testing invalid user data...');
|
||||
await ApiTester.createUser('', 'invalid-email'); // 应该失败
|
||||
|
||||
// 测试不存在的用户
|
||||
console.log('\n Testing non-existent user...');
|
||||
await ApiTester.getUserById(99999); // 应该返回 404
|
||||
|
||||
// 测试无效的更新
|
||||
console.log('\n Testing invalid update...');
|
||||
await ApiTester.updateUser(99999, { name: 'Test' }); // 应该返回 404
|
||||
}
|
||||
|
||||
// 主函数
|
||||
async function main() {
|
||||
console.log('请确保已经部署了 Worker 并更新了 API_BASE_URL');
|
||||
console.log('如果设置了 API_SECRET,请更新 API_KEY 变量\n');
|
||||
|
||||
try {
|
||||
await runFullTest();
|
||||
await performanceTest();
|
||||
await errorHandlingTest();
|
||||
} catch (error) {
|
||||
console.error('\n💥 Test suite failed:', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果直接运行此脚本
|
||||
if (typeof window === 'undefined') {
|
||||
// Node.js 环境
|
||||
const fetch = require('node-fetch');
|
||||
global.fetch = fetch;
|
||||
main();
|
||||
} else {
|
||||
// 浏览器环境
|
||||
console.log('在浏览器控制台中运行: main()');
|
||||
}
|
||||
|
||||
// 导出函数供其他模块使用
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = {
|
||||
ApiTester,
|
||||
runFullTest,
|
||||
performanceTest,
|
||||
errorHandlingTest,
|
||||
main
|
||||
};
|
||||
}
|
||||
79
modules/testing-framework/tests/test-hyperdrive-remote.js
Normal file
79
modules/testing-framework/tests/test-hyperdrive-remote.js
Normal file
@@ -0,0 +1,79 @@
|
||||
// Test script to validate Hyperdrive configuration for remote deployment
|
||||
// This script helps test the configuration without local PostgreSQL
|
||||
|
||||
const { execSync } = require('child_process');
|
||||
const fs = require('fs');
|
||||
|
||||
console.log('🚀 Testing Hyperdrive Configuration for Remote Deployment');
|
||||
console.log('======================================================');
|
||||
|
||||
try {
|
||||
// Check wrangler configuration
|
||||
console.log('\n📋 Validating wrangler.toml...');
|
||||
|
||||
const wranglerContent = fs.readFileSync('wrangler.toml', 'utf8');
|
||||
console.log('✅ wrangler.toml loaded successfully');
|
||||
|
||||
// Validate configuration syntax
|
||||
try {
|
||||
execSync('wrangler config validate', { stdio: 'pipe' });
|
||||
console.log('✅ wrangler.toml syntax is valid');
|
||||
} catch (error) {
|
||||
console.log('⚠️ Configuration validation warning (this is normal for Hyperdrive)');
|
||||
}
|
||||
|
||||
// Check if we can authenticate with Cloudflare
|
||||
console.log('\n🔐 Checking Cloudflare authentication...');
|
||||
try {
|
||||
const whoami = execSync('wrangler whoami', { encoding: 'utf8' });
|
||||
console.log('✅ Authenticated with Cloudflare');
|
||||
console.log(` ${whoami.trim()}`);
|
||||
} catch (error) {
|
||||
console.log('❌ Not authenticated with Cloudflare');
|
||||
console.log(' Run: wrangler login');
|
||||
return;
|
||||
}
|
||||
|
||||
// List Hyperdrive configurations
|
||||
console.log('\n🔗 Checking Hyperdrive configurations...');
|
||||
try {
|
||||
const hyperdrives = execSync('wrangler hyperdrive list', { encoding: 'utf8' });
|
||||
console.log('✅ Hyperdrive configurations:');
|
||||
console.log(hyperdrives);
|
||||
} catch (error) {
|
||||
console.log('⚠️ Could not list Hyperdrive configurations');
|
||||
console.log(' Error:', error.message);
|
||||
}
|
||||
|
||||
// Check specific Hyperdrive
|
||||
console.log('\n🎯 Checking specific Hyperdrive ID...');
|
||||
try {
|
||||
const hyperdriveInfo = execSync('wrangler hyperdrive get ef43924d89064cddabfaccf06aadfab6', { encoding: 'utf8' });
|
||||
console.log('✅ Hyperdrive configuration found:');
|
||||
console.log(hyperdriveInfo);
|
||||
} catch (error) {
|
||||
console.log('❌ Could not find Hyperdrive configuration');
|
||||
console.log(' Error:', error.message);
|
||||
console.log(' Make sure the Hyperdrive ID is correct and exists in your account');
|
||||
}
|
||||
|
||||
console.log('\n📝 Configuration Summary:');
|
||||
console.log(' - Worker Name: hyperdrive-neondb-test');
|
||||
console.log(' - Hyperdrive ID: ef43924d89064cddabfaccf06aadfab6');
|
||||
console.log(' - Binding: HYPERDRIVE');
|
||||
console.log(' - Database Type: NeonDB (PostgreSQL)');
|
||||
|
||||
console.log('\n🚀 Deployment Commands:');
|
||||
console.log(' 1. Deploy to production: wrangler deploy');
|
||||
console.log(' 2. Test endpoints after deployment:');
|
||||
console.log(' - https://hyperdrive-neondb-test.<your-subdomain>.workers.dev/test-connection');
|
||||
console.log(' - https://hyperdrive-neondb-test.<your-subdomain>.workers.dev/test-query');
|
||||
|
||||
console.log('\n💡 Tips:');
|
||||
console.log(' - Hyperdrive provides connection pooling and caching for your database');
|
||||
console.log(' - It reduces latency and improves performance for database queries');
|
||||
console.log(' - The worker will automatically use the Hyperdrive connection in production');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Error during testing:', error.message);
|
||||
}
|
||||
93
modules/testing-framework/tests/test-hyperdrive.js
Normal file
93
modules/testing-framework/tests/test-hyperdrive.js
Normal file
@@ -0,0 +1,93 @@
|
||||
// Simple test script for Hyperdrive configuration
|
||||
// This script helps verify the wrangler.toml configuration
|
||||
|
||||
console.log('🚀 Hyperdrive NeonDB Test Configuration');
|
||||
console.log('=====================================');
|
||||
|
||||
// Check if wrangler.toml exists and has correct configuration
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
try {
|
||||
const wranglerPath = path.join(__dirname, 'wrangler.toml');
|
||||
|
||||
if (fs.existsSync(wranglerPath)) {
|
||||
console.log('✅ wrangler.toml found');
|
||||
|
||||
const content = fs.readFileSync(wranglerPath, 'utf8');
|
||||
|
||||
// Check for Hyperdrive configuration
|
||||
if (content.includes('hyperdrive')) {
|
||||
console.log('✅ Hyperdrive configuration found');
|
||||
} else {
|
||||
console.log('❌ Hyperdrive configuration missing');
|
||||
}
|
||||
|
||||
// Check for binding
|
||||
if (content.includes('binding = "HYPERDRIVE"')) {
|
||||
console.log('✅ HYPERDRIVE binding configured');
|
||||
} else {
|
||||
console.log('❌ HYPERDRIVE binding missing');
|
||||
}
|
||||
|
||||
// Check for Hyperdrive ID
|
||||
if (content.includes('ef43924d89064cddabfaccf06aadfab6')) {
|
||||
console.log('✅ Hyperdrive ID configured');
|
||||
} else {
|
||||
console.log('❌ Hyperdrive ID missing');
|
||||
}
|
||||
|
||||
// Check for nodejs_compat
|
||||
if (content.includes('nodejs_compat')) {
|
||||
console.log('✅ nodejs_compat flag enabled');
|
||||
} else {
|
||||
console.log('❌ nodejs_compat flag missing');
|
||||
}
|
||||
|
||||
} else {
|
||||
console.log('❌ wrangler.toml not found');
|
||||
}
|
||||
|
||||
// Check if src/index.ts exists
|
||||
const indexPath = path.join(__dirname, 'src', 'index.ts');
|
||||
if (fs.existsSync(indexPath)) {
|
||||
console.log('✅ src/index.ts found');
|
||||
} else {
|
||||
console.log('❌ src/index.ts missing');
|
||||
}
|
||||
|
||||
// Check if package.json exists
|
||||
const packagePath = path.join(__dirname, 'package.json');
|
||||
if (fs.existsSync(packagePath)) {
|
||||
console.log('✅ package.json found');
|
||||
|
||||
const packageContent = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
|
||||
|
||||
// Check for required dependencies
|
||||
if (packageContent.dependencies && packageContent.dependencies.pg) {
|
||||
console.log('✅ pg dependency configured');
|
||||
} else {
|
||||
console.log('❌ pg dependency missing');
|
||||
}
|
||||
|
||||
if (packageContent.devDependencies && packageContent.devDependencies['@cloudflare/workers-types']) {
|
||||
console.log('✅ Cloudflare Workers types configured');
|
||||
} else {
|
||||
console.log('❌ Cloudflare Workers types missing');
|
||||
}
|
||||
}
|
||||
|
||||
console.log('\n📋 Next Steps:');
|
||||
console.log('1. Run: wrangler dev --local (for local testing)');
|
||||
console.log('2. Run: wrangler dev (for remote testing with Hyperdrive)');
|
||||
console.log('3. Test endpoints:');
|
||||
console.log(' - http://localhost:8787/test-connection');
|
||||
console.log(' - http://localhost:8787/test-query');
|
||||
console.log('\n🔧 Hyperdrive Configuration:');
|
||||
console.log(' - Hyperdrive ID: ef43924d89064cddabfaccf06aadfab6');
|
||||
console.log(' - Binding: HYPERDRIVE');
|
||||
console.log(' - Database: NeonDB (PostgreSQL)');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Error checking configuration:', error.message);
|
||||
}
|
||||
67
modules/testing-framework/tests/test-shushu-api.sh
Executable file
67
modules/testing-framework/tests/test-shushu-api.sh
Executable file
@@ -0,0 +1,67 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 术数书 API 测试脚本
|
||||
# 使用 curl 命令测试 Hyperdrive + NeonDB 术数书查询系统
|
||||
|
||||
API_BASE="https://hyperdrive.seekkey.tech"
|
||||
|
||||
echo "🚀 术数书 Hyperdrive API 测试"
|
||||
echo "================================"
|
||||
|
||||
# 测试连接
|
||||
echo ""
|
||||
echo "🔗 测试数据库连接..."
|
||||
curl -s "$API_BASE/test-connection" | jq -r '.message // .error // "连接测试完成"'
|
||||
|
||||
# 查询表结构
|
||||
echo ""
|
||||
echo "📋 查询数据库表结构..."
|
||||
echo "发现的表:"
|
||||
curl -s "$API_BASE/query-tables" | jq -r '.tables[]? | "- \(.table_name) (\(.table_schema))"'
|
||||
|
||||
# 获取术数书统计
|
||||
echo ""
|
||||
echo "📊 术数书统计信息..."
|
||||
curl -s "$API_BASE/shushu-stats" | jq -r '.existing_tables[]? | "- \(.table_name): \(.record_count) 条记录"'
|
||||
|
||||
# 查询术数书内容
|
||||
echo ""
|
||||
echo "📚 查询术数书内容 (前3条)..."
|
||||
echo "书籍信息:"
|
||||
curl -s "$API_BASE/query-shushu?limit=3" | jq -r '.data[]? | "- ID: \(.id), 标题: \(.title), 作者: \(.author), 类别: \(.category)"'
|
||||
|
||||
# 搜索功能测试
|
||||
echo ""
|
||||
echo "🔍 搜索测试..."
|
||||
echo "搜索关键词: 易经"
|
||||
curl -s "$API_BASE/search-shushu?q=易经&limit=2" | jq -r '.total_matches // 0 | "找到 \(.) 条匹配记录"'
|
||||
|
||||
echo "搜索关键词: 八卦"
|
||||
curl -s "$API_BASE/search-shushu?q=八卦&limit=2" | jq -r '.total_matches // 0 | "找到 \(.) 条匹配记录"'
|
||||
|
||||
echo "搜索关键词: 面相"
|
||||
curl -s "$API_BASE/search-shushu?q=面相&limit=2" | jq -r '.total_matches // 0 | "找到 \(.) 条匹配记录"'
|
||||
|
||||
# 性能测试
|
||||
echo ""
|
||||
echo "⚡ 性能测试..."
|
||||
echo "测试查询响应时间:"
|
||||
time curl -s "$API_BASE/query-shushu?limit=1" > /dev/null
|
||||
|
||||
echo ""
|
||||
echo "✅ API 测试完成!"
|
||||
echo ""
|
||||
echo "📖 可用端点:"
|
||||
echo "- GET $API_BASE/ - 系统信息"
|
||||
echo "- GET $API_BASE/test-connection - 测试连接"
|
||||
echo "- GET $API_BASE/query-tables - 查询表结构"
|
||||
echo "- GET $API_BASE/query-shushu?limit=N - 查询术数书"
|
||||
echo "- GET $API_BASE/search-shushu?q=keyword&limit=N - 搜索术数书"
|
||||
echo "- GET $API_BASE/shushu-stats - 统计信息"
|
||||
echo ""
|
||||
echo "🎯 与 AutoRAG 对比优势:"
|
||||
echo "- ✅ 毫秒级响应 (Hyperdrive 边缘缓存)"
|
||||
echo "- ✅ 精确查询 (SQL vs 向量相似性)"
|
||||
echo "- ✅ 实时数据 (直连数据库)"
|
||||
echo "- ✅ 成本优化 (连接池 + 缓存)"
|
||||
echo "- ✅ 全球分布 (Cloudflare 边缘网络)"
|
||||
122
modules/testing-framework/tests/test_alpha_vantage_meta.py
Normal file
122
modules/testing-framework/tests/test_alpha_vantage_meta.py
Normal file
@@ -0,0 +1,122 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Alpha Vantage API 测试脚本 - Meta (META) 财报和分析师评级
|
||||
"""
|
||||
|
||||
import os
|
||||
import requests
|
||||
import json
|
||||
from datetime import datetime
|
||||
|
||||
def get_alpha_vantage_key():
|
||||
"""从环境变量获取 Alpha Vantage API Key"""
|
||||
api_key = os.getenv('ALPHA_VANTAGE_API_KEY')
|
||||
if not api_key:
|
||||
raise ValueError("未找到 ALPHA_VANTAGE_API_KEY 环境变量")
|
||||
return api_key
|
||||
|
||||
def get_company_overview(symbol, api_key):
|
||||
"""获取公司基本信息和财务概览"""
|
||||
url = f"https://www.alphavantage.co/query"
|
||||
params = {
|
||||
'function': 'OVERVIEW',
|
||||
'symbol': symbol,
|
||||
'apikey': api_key
|
||||
}
|
||||
|
||||
response = requests.get(url, params=params)
|
||||
return response.json()
|
||||
|
||||
def get_earnings_data(symbol, api_key):
|
||||
"""获取财报数据"""
|
||||
url = f"https://www.alphavantage.co/query"
|
||||
params = {
|
||||
'function': 'EARNINGS',
|
||||
'symbol': symbol,
|
||||
'apikey': api_key
|
||||
}
|
||||
|
||||
response = requests.get(url, params=params)
|
||||
return response.json()
|
||||
|
||||
def get_analyst_ratings(symbol, api_key):
|
||||
"""获取分析师评级(需要付费版本,这里尝试调用看是否有数据)"""
|
||||
url = f"https://www.alphavantage.co/query"
|
||||
params = {
|
||||
'function': 'ANALYST_RECOMMENDATIONS',
|
||||
'symbol': symbol,
|
||||
'apikey': api_key
|
||||
}
|
||||
|
||||
response = requests.get(url, params=params)
|
||||
return response.json()
|
||||
|
||||
def get_income_statement(symbol, api_key):
|
||||
"""获取损益表"""
|
||||
url = f"https://www.alphavantage.co/query"
|
||||
params = {
|
||||
'function': 'INCOME_STATEMENT',
|
||||
'symbol': symbol,
|
||||
'apikey': api_key
|
||||
}
|
||||
|
||||
response = requests.get(url, params=params)
|
||||
return response.json()
|
||||
|
||||
def format_financial_data(data, title):
|
||||
"""格式化财务数据输出"""
|
||||
print(f"\n{'='*60}")
|
||||
print(f"{title}")
|
||||
print(f"{'='*60}")
|
||||
|
||||
if isinstance(data, dict):
|
||||
if 'Error Message' in data:
|
||||
print(f"❌ 错误: {data['Error Message']}")
|
||||
elif 'Note' in data:
|
||||
print(f"⚠️ 注意: {data['Note']}")
|
||||
else:
|
||||
print(json.dumps(data, indent=2, ensure_ascii=False))
|
||||
else:
|
||||
print(data)
|
||||
|
||||
def main():
|
||||
"""主函数"""
|
||||
try:
|
||||
# 获取 API Key
|
||||
api_key = get_alpha_vantage_key()
|
||||
print(f"✅ 成功获取 Alpha Vantage API Key: {api_key[:8]}...")
|
||||
|
||||
symbol = "META" # Meta Platforms Inc.
|
||||
print(f"\n🔍 正在获取 {symbol} 的财务数据...")
|
||||
|
||||
# 1. 公司概览
|
||||
print("\n📊 获取公司概览...")
|
||||
overview = get_company_overview(symbol, api_key)
|
||||
format_financial_data(overview, f"{symbol} - 公司概览")
|
||||
|
||||
# 2. 财报数据
|
||||
print("\n📈 获取财报数据...")
|
||||
earnings = get_earnings_data(symbol, api_key)
|
||||
format_financial_data(earnings, f"{symbol} - 财报数据")
|
||||
|
||||
# 3. 分析师评级
|
||||
print("\n⭐ 获取分析师评级...")
|
||||
ratings = get_analyst_ratings(symbol, api_key)
|
||||
format_financial_data(ratings, f"{symbol} - 分析师评级")
|
||||
|
||||
# 4. 损益表
|
||||
print("\n💰 获取损益表...")
|
||||
income_statement = get_income_statement(symbol, api_key)
|
||||
format_financial_data(income_statement, f"{symbol} - 损益表")
|
||||
|
||||
print(f"\n✅ {symbol} 数据获取完成!")
|
||||
print(f"⏰ 完成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ 错误: {str(e)}")
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
if __name__ == "__main__":
|
||||
exit(main())
|
||||
205
modules/testing-framework/tests/test_cloudflare_gemini.py
Normal file
205
modules/testing-framework/tests/test_cloudflare_gemini.py
Normal file
@@ -0,0 +1,205 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
测试Cloudflare网关的Gemini API
|
||||
使用用户提供的新配置
|
||||
"""
|
||||
|
||||
import requests
|
||||
import json
|
||||
import logging
|
||||
|
||||
# 配置日志
|
||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def test_cloudflare_gemini():
|
||||
"""测试Cloudflare网关的Gemini API"""
|
||||
|
||||
# 用户提供的新配置
|
||||
API_KEY = "AIzaSyAQ2TXFAzmTKm4aFqgrjkhjgsp95bDsAyE"
|
||||
BASE_URL = "https://gateway.ai.cloudflare.com/v1/e167cb36a5b95cb3cc8daf77a3f7d0b3/default/google-ai-studio"
|
||||
MODEL = "models/gemini-2.5-pro"
|
||||
|
||||
logger.info(f"🧪 测试Cloudflare Gemini配置:")
|
||||
logger.info(f"📡 BASE_URL: {BASE_URL}")
|
||||
logger.info(f"🔑 API_KEY: {API_KEY[:10]}...")
|
||||
logger.info(f"🤖 MODEL: {MODEL}")
|
||||
|
||||
# 构建请求
|
||||
url = f"{BASE_URL}/v1beta/{MODEL}:generateContent"
|
||||
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"x-goog-api-key": API_KEY
|
||||
}
|
||||
|
||||
payload = {
|
||||
"contents": [
|
||||
{
|
||||
"parts": [
|
||||
{
|
||||
"text": "你好,请简单介绍一下你自己"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"generationConfig": {
|
||||
"maxOutputTokens": 1000,
|
||||
"temperature": 0.7
|
||||
}
|
||||
}
|
||||
|
||||
try:
|
||||
logger.info("🚀 发送请求到Cloudflare网关...")
|
||||
logger.info(f"📍 请求URL: {url}")
|
||||
|
||||
response = requests.post(
|
||||
url,
|
||||
json=payload,
|
||||
headers=headers,
|
||||
timeout=60
|
||||
)
|
||||
|
||||
logger.info(f"📊 状态码: {response.status_code}")
|
||||
|
||||
if response.status_code == 200:
|
||||
result = response.json()
|
||||
logger.info(f"✅ 请求成功!")
|
||||
logger.info(f"📋 完整响应: {json.dumps(result, ensure_ascii=False, indent=2)}")
|
||||
|
||||
# 提取内容
|
||||
if 'candidates' in result and len(result['candidates']) > 0:
|
||||
candidate = result['candidates'][0]
|
||||
if 'content' in candidate and 'parts' in candidate['content']:
|
||||
content = candidate['content']['parts'][0].get('text', '')
|
||||
logger.info(f"🗣️ Gemini回应: {content}")
|
||||
return True, content
|
||||
|
||||
return True, "响应格式异常"
|
||||
|
||||
else:
|
||||
logger.error(f"❌ 请求失败: {response.status_code}")
|
||||
logger.error(f"📋 错误响应: {response.text}")
|
||||
return False, response.text
|
||||
|
||||
except requests.exceptions.Timeout:
|
||||
logger.error(f"⏰ 请求超时 (60秒)")
|
||||
return False, "请求超时"
|
||||
except requests.exceptions.ConnectionError as e:
|
||||
logger.error(f"🔌 连接错误: {e}")
|
||||
return False, str(e)
|
||||
except Exception as e:
|
||||
logger.error(f"💥 未知错误: {e}")
|
||||
return False, str(e)
|
||||
|
||||
def test_gemini_breakdown():
|
||||
"""测试Gemini的问题分解能力"""
|
||||
|
||||
API_KEY = "AIzaSyAQ2TXFAzmTKm4aFqgrjkhjgsp95bDsAyE"
|
||||
BASE_URL = "https://gateway.ai.cloudflare.com/v1/e167cb36a5b95cb3cc8daf77a3f7d0b3/default/google-ai-studio"
|
||||
MODEL = "models/gemini-2.5-pro"
|
||||
|
||||
url = f"{BASE_URL}/v1beta/{MODEL}:generateContent"
|
||||
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"x-goog-api-key": API_KEY
|
||||
}
|
||||
|
||||
topic = "工作量证明vs无限制爬虫:从李时珍采药到AI数据获取的激励机制变革"
|
||||
|
||||
payload = {
|
||||
"contents": [
|
||||
{
|
||||
"parts": [
|
||||
{
|
||||
"text": f"你是太上老君,负责将复杂问题分解为多个子问题。请将以下问题分解为3-5个子问题,以JSON格式返回:\n\n{topic}\n\n返回格式:{{\"subtopics\": [{{\"title\": \"子问题标题\", \"description\": \"详细描述\"}}]}}"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"generationConfig": {
|
||||
"maxOutputTokens": 2000,
|
||||
"temperature": 0.7
|
||||
}
|
||||
}
|
||||
|
||||
try:
|
||||
logger.info("🧠 测试Gemini问题分解能力...")
|
||||
|
||||
response = requests.post(
|
||||
url,
|
||||
json=payload,
|
||||
headers=headers,
|
||||
timeout=60
|
||||
)
|
||||
|
||||
logger.info(f"📊 状态码: {response.status_code}")
|
||||
|
||||
if response.status_code == 200:
|
||||
result = response.json()
|
||||
logger.info(f"✅ 分解测试成功!")
|
||||
|
||||
# 提取内容
|
||||
if 'candidates' in result and len(result['candidates']) > 0:
|
||||
candidate = result['candidates'][0]
|
||||
if 'content' in candidate and 'parts' in candidate['content']:
|
||||
content = candidate['content']['parts'][0].get('text', '')
|
||||
logger.info(f"📋 分解结果:\n{content}")
|
||||
|
||||
# 尝试解析JSON
|
||||
try:
|
||||
# 提取JSON部分
|
||||
if '```json' in content:
|
||||
json_start = content.find('```json') + 7
|
||||
json_end = content.find('```', json_start)
|
||||
json_content = content[json_start:json_end].strip()
|
||||
elif '{' in content and '}' in content:
|
||||
json_start = content.find('{')
|
||||
json_end = content.rfind('}') + 1
|
||||
json_content = content[json_start:json_end]
|
||||
else:
|
||||
json_content = content
|
||||
|
||||
parsed_json = json.loads(json_content)
|
||||
logger.info(f"🎯 JSON解析成功: {json.dumps(parsed_json, ensure_ascii=False, indent=2)}")
|
||||
return True, parsed_json
|
||||
|
||||
except json.JSONDecodeError as e:
|
||||
logger.warning(f"⚠️ JSON解析失败: {e}")
|
||||
logger.warning(f"📝 原始内容: {content}")
|
||||
return True, content
|
||||
|
||||
return True, "响应格式异常"
|
||||
|
||||
else:
|
||||
logger.error(f"❌ 分解测试失败: {response.status_code}")
|
||||
logger.error(f"📋 错误响应: {response.text}")
|
||||
return False, response.text
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"💥 分解测试错误: {e}")
|
||||
return False, str(e)
|
||||
|
||||
if __name__ == "__main__":
|
||||
logger.info("🎯 开始Cloudflare Gemini API测试")
|
||||
|
||||
# 基础连接测试
|
||||
success1, result1 = test_cloudflare_gemini()
|
||||
|
||||
if success1:
|
||||
logger.info("🎉 基础测试通过!")
|
||||
|
||||
# 问题分解测试
|
||||
success2, result2 = test_gemini_breakdown()
|
||||
|
||||
if success2:
|
||||
logger.info("🎉 所有测试通过!Gemini API工作正常")
|
||||
logger.info("✅ 可以安全运行完整的循环赛系统")
|
||||
else:
|
||||
logger.error("💀 问题分解测试失败")
|
||||
else:
|
||||
logger.error("💀 基础连接测试失败")
|
||||
|
||||
logger.info("🏁 测试完成")
|
||||
436
modules/testing-framework/tests/test_cloudflare_memory_bank.py
Normal file
436
modules/testing-framework/tests/test_cloudflare_memory_bank.py
Normal file
@@ -0,0 +1,436 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Cloudflare Memory Bank 实现测试
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import asyncio
|
||||
import os
|
||||
import sys
|
||||
from unittest.mock import patch, MagicMock, AsyncMock
|
||||
from datetime import datetime
|
||||
|
||||
# 添加项目根目录到Python路径
|
||||
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
|
||||
|
||||
from src.jixia.memory.cloudflare_memory_bank import CloudflareMemoryBank, MemoryEntry
|
||||
|
||||
|
||||
class TestCloudflareMemoryBank(unittest.TestCase):
|
||||
"""测试CloudflareMemoryBank类"""
|
||||
|
||||
def setUp(self):
|
||||
"""测试前的设置"""
|
||||
# Mock掉 aiohttp.ClientSession 以避免实际网络请求
|
||||
self.patcher = patch('src.jixia.memory.cloudflare_memory_bank.aiohttp.ClientSession')
|
||||
self.mock_session_class = self.patcher.start()
|
||||
self.mock_session = AsyncMock()
|
||||
self.mock_session_class.return_value = self.mock_session
|
||||
|
||||
# Mock掉 get_cloudflare_config 以避免实际读取配置
|
||||
self.config_patcher = patch('src.jixia.memory.cloudflare_memory_bank.get_cloudflare_config')
|
||||
self.mock_get_config = self.config_patcher.start()
|
||||
self.mock_get_config.return_value = {
|
||||
'account_id': 'test-account',
|
||||
'api_token': 'test-token',
|
||||
'vectorize_index': 'test-index',
|
||||
'embed_model': '@cf/baai/bge-m3',
|
||||
'autorag_domain': 'test.example.com'
|
||||
}
|
||||
|
||||
# 创建CloudflareMemoryBank实例
|
||||
self.memory_bank = CloudflareMemoryBank()
|
||||
|
||||
# 重置一些内部状态
|
||||
self.memory_bank.config = self.mock_get_config.return_value
|
||||
self.memory_bank.account_id = 'test-account'
|
||||
self.memory_bank.api_token = 'test-token'
|
||||
self.memory_bank.vectorize_index = 'test-index'
|
||||
self.memory_bank.embed_model = '@cf/baai/bge-m3'
|
||||
self.memory_bank.autorag_domain = 'test.example.com'
|
||||
|
||||
def tearDown(self):
|
||||
"""测试后的清理"""
|
||||
self.patcher.stop()
|
||||
self.config_patcher.stop()
|
||||
|
||||
def test_init(self):
|
||||
"""测试初始化"""
|
||||
self.assertEqual(self.memory_bank.account_id, "test-account")
|
||||
self.assertEqual(self.memory_bank.api_token, "test-token")
|
||||
self.assertEqual(self.memory_bank.vectorize_index, "test-index")
|
||||
self.assertEqual(self.memory_bank.embed_model, "@cf/baai/bge-m3")
|
||||
self.assertEqual(self.memory_bank.autorag_domain, "test.example.com")
|
||||
|
||||
async def test_create_memory_bank(self):
|
||||
"""测试创建记忆空间"""
|
||||
memory_bank_id = await self.memory_bank.create_memory_bank("tieguaili")
|
||||
|
||||
# 验证返回的ID格式
|
||||
self.assertEqual(memory_bank_id, "cf_memory_tieguaili")
|
||||
|
||||
async def test_create_memory_bank_with_display_name(self):
|
||||
"""测试创建记忆空间时指定显示名称"""
|
||||
memory_bank_id = await self.memory_bank.create_memory_bank(
|
||||
"tieguaili",
|
||||
"铁拐李的专属记忆银行"
|
||||
)
|
||||
|
||||
# 验证返回的ID格式
|
||||
self.assertEqual(memory_bank_id, "cf_memory_tieguaili")
|
||||
|
||||
async def test_generate_embedding(self):
|
||||
"""测试生成嵌入向量"""
|
||||
# Mock响应
|
||||
mock_response = AsyncMock()
|
||||
mock_response.status = 200
|
||||
mock_response.json = AsyncMock(return_value={
|
||||
"result": {
|
||||
"data": [
|
||||
{
|
||||
"embedding": [0.1, 0.2, 0.3, 0.4, 0.5]
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
# Mock session.post
|
||||
self.mock_session.post.return_value.__aenter__.return_value = mock_response
|
||||
|
||||
# 调用方法
|
||||
embedding = await self.memory_bank._generate_embedding("测试文本")
|
||||
|
||||
# 验证结果
|
||||
self.assertEqual(embedding, [0.1, 0.2, 0.3, 0.4, 0.5])
|
||||
|
||||
# 验证调用了正确的URL和参数
|
||||
expected_url = "https://api.cloudflare.com/client/v4/accounts/test-account/ai/run/@cf/baai/bge-m3"
|
||||
self.mock_session.post.assert_called_once()
|
||||
call_args = self.mock_session.post.call_args
|
||||
self.assertEqual(call_args[0][0], expected_url)
|
||||
self.assertEqual(call_args[1]['json'], {"text": ["测试文本"]})
|
||||
|
||||
async def test_generate_embedding_api_error(self):
|
||||
"""测试生成嵌入向量时API错误"""
|
||||
# Mock响应
|
||||
mock_response = AsyncMock()
|
||||
mock_response.status = 500
|
||||
mock_response.text = AsyncMock(return_value="Internal Server Error")
|
||||
|
||||
# Mock session.post
|
||||
self.mock_session.post.return_value.__aenter__.return_value = mock_response
|
||||
|
||||
# 验证抛出异常
|
||||
with self.assertRaises(Exception) as context:
|
||||
await self.memory_bank._generate_embedding("测试文本")
|
||||
|
||||
self.assertIn("Failed to generate embedding", str(context.exception))
|
||||
|
||||
async def test_add_memory(self):
|
||||
"""测试添加记忆"""
|
||||
# Mock _generate_embedding 方法
|
||||
with patch.object(self.memory_bank, '_generate_embedding', new=AsyncMock(return_value=[0.1, 0.2, 0.3])) as mock_embed:
|
||||
# Mock upsert 响应
|
||||
mock_response = AsyncMock()
|
||||
mock_response.status = 200
|
||||
mock_response.json = AsyncMock(return_value={"result": {"upserted": 1}})
|
||||
|
||||
# Mock session.post
|
||||
self.mock_session.post.return_value.__aenter__.return_value = mock_response
|
||||
|
||||
# 添加记忆
|
||||
memory_id = await self.memory_bank.add_memory(
|
||||
agent_name="tieguaili",
|
||||
content="在讨论NVIDIA股票时,我倾向于逆向思维,关注潜在风险。",
|
||||
memory_type="preference",
|
||||
debate_topic="NVIDIA投资分析",
|
||||
metadata={"source": "manual"}
|
||||
)
|
||||
|
||||
# 验证返回的ID格式 (以mem_开头)
|
||||
self.assertTrue(memory_id.startswith("mem_tieguaili_"))
|
||||
|
||||
# 验证调用了生成嵌入的方法
|
||||
mock_embed.assert_called_once_with("在讨论NVIDIA股票时,我倾向于逆向思维,关注潜在风险。")
|
||||
|
||||
# 验证调用了upsert API
|
||||
self.mock_session.post.assert_called()
|
||||
|
||||
# 验证upsert调用的参数
|
||||
upsert_call = None
|
||||
for call in self.mock_session.post.call_args_list:
|
||||
if 'vectorize/indexes/test-index/upsert' in call[0][0]:
|
||||
upsert_call = call
|
||||
break
|
||||
|
||||
self.assertIsNotNone(upsert_call)
|
||||
call_args, call_kwargs = upsert_call
|
||||
self.assertIn("vectorize/indexes/test-index/upsert", call_args[0])
|
||||
self.assertIn("vectors", call_kwargs['json'])
|
||||
|
||||
async def test_add_memory_api_error(self):
|
||||
"""测试添加记忆时API错误"""
|
||||
# Mock _generate_embedding 方法
|
||||
with patch.object(self.memory_bank, '_generate_embedding', new=AsyncMock(return_value=[0.1, 0.2, 0.3])):
|
||||
# Mock upsert 响应
|
||||
mock_response = AsyncMock()
|
||||
mock_response.status = 500
|
||||
mock_response.text = AsyncMock(return_value="Internal Server Error")
|
||||
|
||||
# Mock session.post
|
||||
self.mock_session.post.return_value.__aenter__.return_value = mock_response
|
||||
|
||||
# 验证抛出异常
|
||||
with self.assertRaises(Exception) as context:
|
||||
await self.memory_bank.add_memory(
|
||||
agent_name="tieguaili",
|
||||
content="测试内容"
|
||||
)
|
||||
|
||||
self.assertIn("Failed to upsert memory", str(context.exception))
|
||||
|
||||
async def test_search_memories(self):
|
||||
"""测试搜索记忆"""
|
||||
# Mock _generate_embedding 方法
|
||||
with patch.object(self.memory_bank, '_generate_embedding', new=AsyncMock(return_value=[0.1, 0.2, 0.3])) as mock_embed:
|
||||
# Mock query 响应
|
||||
mock_response = AsyncMock()
|
||||
mock_response.status = 200
|
||||
mock_response.json = AsyncMock(return_value={
|
||||
"result": {
|
||||
"matches": [
|
||||
{
|
||||
"metadata": {
|
||||
"content": "在讨论NVIDIA股票时,我倾向于逆向思维,关注潜在风险。",
|
||||
"memory_type": "preference",
|
||||
"agent_name": "tieguaili"
|
||||
},
|
||||
"score": 0.95
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
# Mock session.post
|
||||
self.mock_session.post.return_value.__aenter__.return_value = mock_response
|
||||
|
||||
# 搜索记忆
|
||||
results = await self.memory_bank.search_memories(
|
||||
agent_name="tieguaili",
|
||||
query="NVIDIA",
|
||||
memory_type="preference",
|
||||
limit=5
|
||||
)
|
||||
|
||||
# 验证结果
|
||||
self.assertEqual(len(results), 1)
|
||||
self.assertEqual(results[0]["content"], "在讨论NVIDIA股票时,我倾向于逆向思维,关注潜在风险。")
|
||||
self.assertEqual(results[0]["relevance_score"], 0.95)
|
||||
|
||||
# 验证调用了生成嵌入的方法
|
||||
mock_embed.assert_called_once_with("NVIDIA")
|
||||
|
||||
# 验证调用了query API
|
||||
self.mock_session.post.assert_called()
|
||||
|
||||
# 验证query调用的参数
|
||||
query_call = None
|
||||
for call in self.mock_session.post.call_args_list:
|
||||
if 'vectorize/indexes/test-index/query' in call[0][0]:
|
||||
query_call = call
|
||||
break
|
||||
|
||||
self.assertIsNotNone(query_call)
|
||||
call_args, call_kwargs = query_call
|
||||
self.assertIn("vectorize/indexes/test-index/query", call_args[0])
|
||||
self.assertIn("vector", call_kwargs['json'])
|
||||
self.assertIn("filter", call_kwargs['json'])
|
||||
self.assertEqual(call_kwargs['json']['filter'], {"agent_name": "tieguaili", "memory_type": "preference"})
|
||||
|
||||
async def test_search_memories_api_error(self):
|
||||
"""测试搜索记忆时API错误"""
|
||||
# Mock _generate_embedding 方法
|
||||
with patch.object(self.memory_bank, '_generate_embedding', new=AsyncMock(return_value=[0.1, 0.2, 0.3])):
|
||||
# Mock query 响应
|
||||
mock_response = AsyncMock()
|
||||
mock_response.status = 500
|
||||
mock_response.text = AsyncMock(return_value="Internal Server Error")
|
||||
|
||||
# Mock session.post
|
||||
self.mock_session.post.return_value.__aenter__.return_value = mock_response
|
||||
|
||||
# 验证返回空列表而不是抛出异常
|
||||
results = await self.memory_bank.search_memories(
|
||||
agent_name="tieguaili",
|
||||
query="NVIDIA"
|
||||
)
|
||||
|
||||
self.assertEqual(results, [])
|
||||
|
||||
async def test_get_agent_context(self):
|
||||
"""测试获取智能体上下文"""
|
||||
# Mock search_memories 方法
|
||||
with patch.object(self.memory_bank, 'search_memories', new=AsyncMock()) as mock_search:
|
||||
# 设置mock返回值
|
||||
mock_search.side_effect = [
|
||||
[ # conversation memories
|
||||
{"content": "NVIDIA的估值过高,存在泡沫风险。", "relevance_score": 0.9}
|
||||
],
|
||||
[ # preference memories
|
||||
{"content": "倾向于逆向思维,关注潜在风险。", "relevance_score": 0.8}
|
||||
],
|
||||
[ # strategy memories
|
||||
{"content": "使用技术分析策略。", "relevance_score": 0.7}
|
||||
]
|
||||
]
|
||||
|
||||
# 获取上下文
|
||||
context = await self.memory_bank.get_agent_context("tieguaili", "NVIDIA投资分析")
|
||||
|
||||
# 验证上下文包含预期内容
|
||||
self.assertIn("# 铁拐李的记忆上下文", context)
|
||||
self.assertIn("## 历史对话记忆", context)
|
||||
self.assertIn("## 偏好记忆", context)
|
||||
self.assertIn("## 策略记忆", context)
|
||||
self.assertIn("NVIDIA的估值过高,存在泡沫风险。", context)
|
||||
self.assertIn("倾向于逆向思维,关注潜在风险。", context)
|
||||
self.assertIn("使用技术分析策略。", context)
|
||||
|
||||
async def test_get_agent_context_no_memories(self):
|
||||
"""测试获取智能体上下文但无相关记忆"""
|
||||
# Mock search_memories 方法
|
||||
with patch.object(self.memory_bank, 'search_memories', new=AsyncMock(return_value=[])):
|
||||
# 获取上下文
|
||||
context = await self.memory_bank.get_agent_context("tieguaili", "NVIDIA投资分析")
|
||||
|
||||
# 验证上下文包含暂无相关记忆的提示
|
||||
self.assertIn("# 铁拐李的记忆上下文", context)
|
||||
self.assertIn("暂无相关记忆。", context)
|
||||
|
||||
async def test_save_debate_session(self):
|
||||
"""测试保存辩论会话"""
|
||||
# Mock add_memory 方法
|
||||
with patch.object(self.memory_bank, 'add_memory', new=AsyncMock()) as mock_add:
|
||||
conversation_history = [
|
||||
{"agent": "tieguaili", "content": "NVIDIA的估值过高,存在泡沫风险。"},
|
||||
{"agent": "lvdongbin", "content": "NVIDIA在AI领域的领先地位不可忽视。"},
|
||||
{"agent": "tieguaili", "content": "但我们需要考虑竞争加剧和增长放缓的可能性。"}
|
||||
]
|
||||
|
||||
outcomes = {
|
||||
"winner": "lvdongbin",
|
||||
"insights": {
|
||||
"tieguaili": "铁拐李的风险意识值得肯定,但在AI趋势的判断上略显保守。"
|
||||
}
|
||||
}
|
||||
|
||||
# 保存辩论会话
|
||||
await self.memory_bank.save_debate_session(
|
||||
debate_topic="NVIDIA投资分析",
|
||||
participants=["tieguaili", "lvdongbin"],
|
||||
conversation_history=conversation_history,
|
||||
outcomes=outcomes
|
||||
)
|
||||
|
||||
# 验证调用了add_memory两次(对话总结和策略洞察)
|
||||
self.assertEqual(mock_add.call_count, 2)
|
||||
|
||||
# 验证第一次调用是对话总结
|
||||
call_args1 = mock_add.call_args_list[0][1]
|
||||
self.assertEqual(call_args1['agent_name'], 'tieguaili')
|
||||
self.assertEqual(call_args1['memory_type'], 'conversation')
|
||||
self.assertIn('铁拐李在本次辩论中的主要观点', call_args1['content'])
|
||||
|
||||
# 验证第二次调用是策略洞察
|
||||
call_args2 = mock_add.call_args_list[1][1]
|
||||
self.assertEqual(call_args2['agent_name'], 'tieguaili')
|
||||
self.assertEqual(call_args2['memory_type'], 'strategy')
|
||||
self.assertIn('铁拐李的风险意识值得肯定', call_args2['content'])
|
||||
|
||||
def test_summarize_conversation(self):
|
||||
"""测试对话总结"""
|
||||
conversation_history = [
|
||||
{"agent": "tieguaili", "content": "第一点看法:NVIDIA的估值过高,存在泡沫风险。"},
|
||||
{"agent": "lvdongbin", "content": "NVIDIA在AI领域的领先地位不可忽视。"},
|
||||
{"agent": "tieguaili", "content": "第二点看法:我们需要考虑竞争加剧和增长放缓的可能性。"},
|
||||
{"agent": "tieguaili", "content": "第三点看法:从技术分析角度看,股价已出现超买信号。"}
|
||||
]
|
||||
|
||||
summary = self.memory_bank._summarize_conversation(conversation_history, "tieguaili")
|
||||
|
||||
# 验证总结包含预期内容
|
||||
self.assertIn("铁拐李在本次辩论中的主要观点", summary)
|
||||
self.assertIn("第一点看法:NVIDIA的估值过高,存在泡沫风险。", summary)
|
||||
self.assertIn("第二点看法:我们需要考虑竞争加剧和增长放缓的可能性。", summary)
|
||||
self.assertIn("第三点看法:从技术分析角度看,股价已出现超买信号。", summary)
|
||||
|
||||
def test_extract_strategy_insight_winner(self):
|
||||
"""测试提取策略洞察 - 获胜者"""
|
||||
outcomes = {
|
||||
"winner": "tieguaili",
|
||||
"insights": {}
|
||||
}
|
||||
|
||||
insight = self.memory_bank._extract_strategy_insight(outcomes, "tieguaili")
|
||||
|
||||
self.assertIn("铁拐李在本次辩论中获胜", insight)
|
||||
|
||||
def test_extract_strategy_insight_from_insights(self):
|
||||
"""测试从洞察中提取策略洞察"""
|
||||
outcomes = {
|
||||
"winner": "lvdongbin",
|
||||
"insights": {
|
||||
"tieguaili": "铁拐李的风险意识值得肯定,但在AI趋势的判断上略显保守。"
|
||||
}
|
||||
}
|
||||
|
||||
insight = self.memory_bank._extract_strategy_insight(outcomes, "tieguaili")
|
||||
|
||||
self.assertEqual(insight, "铁拐李的风险意识值得肯定,但在AI趋势的判断上略显保守。")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# 创建一个异步测试运行器
|
||||
def run_async_test(test_case):
|
||||
"""运行异步测试用例"""
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
try:
|
||||
return loop.run_until_complete(test_case)
|
||||
finally:
|
||||
loop.close()
|
||||
|
||||
# 获取所有以test_开头的异步方法并运行它们
|
||||
suite = unittest.TestSuite()
|
||||
test_instance = TestCloudflareMemoryBank()
|
||||
test_instance.setUp()
|
||||
test_instance.addCleanup(test_instance.tearDown)
|
||||
|
||||
# 添加同步测试
|
||||
suite.addTest(TestCloudflareMemoryBank('test_init'))
|
||||
suite.addTest(TestCloudflareMemoryBank('test_summarize_conversation'))
|
||||
suite.addTest(TestCloudflareMemoryBank('test_extract_strategy_insight_winner'))
|
||||
suite.addTest(TestCloudflareMemoryBank('test_extract_strategy_insight_from_insights'))
|
||||
|
||||
# 添加异步测试
|
||||
async_tests = [
|
||||
'test_create_memory_bank',
|
||||
'test_create_memory_bank_with_display_name',
|
||||
'test_generate_embedding',
|
||||
'test_generate_embedding_api_error',
|
||||
'test_add_memory',
|
||||
'test_add_memory_api_error',
|
||||
'test_search_memories',
|
||||
'test_search_memories_api_error',
|
||||
'test_get_agent_context',
|
||||
'test_get_agent_context_no_memories',
|
||||
'test_save_debate_session'
|
||||
]
|
||||
|
||||
for test_name in async_tests:
|
||||
test_method = getattr(test_instance, test_name)
|
||||
suite.addTest(unittest.FunctionTestCase(lambda tm=test_method: run_async_test(tm())))
|
||||
|
||||
# 运行测试
|
||||
runner = unittest.TextTestRunner(verbosity=2)
|
||||
runner.run(suite)
|
||||
288
modules/testing-framework/tests/test_coordination_data.json
Normal file
288
modules/testing-framework/tests/test_coordination_data.json
Normal file
@@ -0,0 +1,288 @@
|
||||
{
|
||||
"chat_rooms": {
|
||||
"main_debate": {
|
||||
"id": "main_debate",
|
||||
"chat_type": "主辩论群",
|
||||
"name": "主辩论群",
|
||||
"description": "公开辩论的主要场所",
|
||||
"participants": [
|
||||
"正1",
|
||||
"正2",
|
||||
"正3",
|
||||
"正4",
|
||||
"反1",
|
||||
"反2",
|
||||
"反3",
|
||||
"反4"
|
||||
],
|
||||
"moderators": [
|
||||
"系统"
|
||||
],
|
||||
"is_active": true,
|
||||
"created_at": "2025-08-16T10:57:01.223754",
|
||||
"last_activity": "2025-08-16T10:57:01.223769",
|
||||
"settings": {
|
||||
"max_message_length": 500,
|
||||
"speaking_time_limit": 120,
|
||||
"auto_moderation": true
|
||||
},
|
||||
"message_count": 2
|
||||
},
|
||||
"positive_internal": {
|
||||
"id": "positive_internal",
|
||||
"chat_type": "内部讨论群",
|
||||
"name": "正方内部讨论群",
|
||||
"description": "正方团队内部策略讨论",
|
||||
"participants": [
|
||||
"正1",
|
||||
"正2",
|
||||
"正3",
|
||||
"正4"
|
||||
],
|
||||
"moderators": [
|
||||
"正1"
|
||||
],
|
||||
"is_active": true,
|
||||
"created_at": "2025-08-16T10:57:01.223755",
|
||||
"last_activity": "2025-08-16T10:57:01.223772",
|
||||
"settings": {
|
||||
"privacy_level": "high",
|
||||
"auto_archive": true
|
||||
},
|
||||
"message_count": 1
|
||||
},
|
||||
"negative_internal": {
|
||||
"id": "negative_internal",
|
||||
"chat_type": "内部讨论群",
|
||||
"name": "反方内部讨论群",
|
||||
"description": "反方团队内部策略讨论",
|
||||
"participants": [
|
||||
"反1",
|
||||
"反2",
|
||||
"反3",
|
||||
"反4"
|
||||
],
|
||||
"moderators": [
|
||||
"反1"
|
||||
],
|
||||
"is_active": true,
|
||||
"created_at": "2025-08-16T10:57:01.223756",
|
||||
"last_activity": "2025-08-16T10:57:01.223782",
|
||||
"settings": {
|
||||
"privacy_level": "high",
|
||||
"auto_archive": true
|
||||
},
|
||||
"message_count": 1
|
||||
},
|
||||
"strategy_meeting": {
|
||||
"id": "strategy_meeting",
|
||||
"chat_type": "策略会议群",
|
||||
"name": "策略会议群",
|
||||
"description": "高级策略制定和决策",
|
||||
"participants": [
|
||||
"正1",
|
||||
"反1",
|
||||
"系统"
|
||||
],
|
||||
"moderators": [
|
||||
"系统"
|
||||
],
|
||||
"is_active": true,
|
||||
"created_at": "2025-08-16T10:57:01.223756",
|
||||
"last_activity": "2025-08-16T10:57:01.223794",
|
||||
"settings": {
|
||||
"meeting_mode": true,
|
||||
"record_decisions": true
|
||||
},
|
||||
"message_count": 1
|
||||
},
|
||||
"human_intervention": {
|
||||
"id": "human_intervention",
|
||||
"chat_type": "Human干预群",
|
||||
"name": "Human干预群",
|
||||
"description": "人工干预和监督",
|
||||
"participants": [
|
||||
"Human",
|
||||
"系统"
|
||||
],
|
||||
"moderators": [
|
||||
"Human"
|
||||
],
|
||||
"is_active": true,
|
||||
"created_at": "2025-08-16T10:57:01.223757",
|
||||
"last_activity": "2025-08-16T10:57:01.223757",
|
||||
"settings": {
|
||||
"alert_threshold": "high",
|
||||
"auto_escalation": true
|
||||
},
|
||||
"message_count": 0
|
||||
},
|
||||
"observation": {
|
||||
"id": "observation",
|
||||
"chat_type": "观察群",
|
||||
"name": "观察群",
|
||||
"description": "观察和记录所有活动",
|
||||
"participants": [
|
||||
"观察者",
|
||||
"记录员"
|
||||
],
|
||||
"moderators": [
|
||||
"系统"
|
||||
],
|
||||
"is_active": true,
|
||||
"created_at": "2025-08-16T10:57:01.223758",
|
||||
"last_activity": "2025-08-16T10:57:01.223790",
|
||||
"settings": {
|
||||
"read_only": true,
|
||||
"full_logging": true
|
||||
},
|
||||
"message_count": 2
|
||||
}
|
||||
},
|
||||
"coordination_rules": {
|
||||
"escalate_urgent_to_human": {
|
||||
"id": "escalate_urgent_to_human",
|
||||
"name": "紧急情况升级到Human",
|
||||
"description": "当检测到紧急情况时,自动升级到Human干预群",
|
||||
"source_chat_types": [
|
||||
"主辩论群",
|
||||
"内部讨论群"
|
||||
],
|
||||
"target_chat_types": [
|
||||
"Human干预群"
|
||||
],
|
||||
"trigger_conditions": {
|
||||
"priority": 4,
|
||||
"keywords": [
|
||||
"紧急",
|
||||
"错误",
|
||||
"异常",
|
||||
"停止"
|
||||
]
|
||||
},
|
||||
"action": "升级",
|
||||
"priority": 1,
|
||||
"is_active": true,
|
||||
"created_at": "2025-08-16T10:57:01.223760"
|
||||
},
|
||||
"strategy_to_internal": {
|
||||
"id": "strategy_to_internal",
|
||||
"name": "策略决策分发到内部群",
|
||||
"description": "将策略会议的决策分发到相关内部讨论群",
|
||||
"source_chat_types": [
|
||||
"策略会议群"
|
||||
],
|
||||
"target_chat_types": [
|
||||
"内部讨论群"
|
||||
],
|
||||
"trigger_conditions": {
|
||||
"tags": [
|
||||
"决策",
|
||||
"策略",
|
||||
"指令"
|
||||
]
|
||||
},
|
||||
"action": "广播",
|
||||
"priority": 2,
|
||||
"is_active": true,
|
||||
"created_at": "2025-08-16T10:57:01.223760"
|
||||
},
|
||||
"filter_noise": {
|
||||
"id": "filter_noise",
|
||||
"name": "过滤噪音消息",
|
||||
"description": "过滤低质量或无关的消息",
|
||||
"source_chat_types": [
|
||||
"主辩论群"
|
||||
],
|
||||
"target_chat_types": [],
|
||||
"trigger_conditions": {
|
||||
"priority": 1,
|
||||
"content_length": {
|
||||
"max": 10
|
||||
}
|
||||
},
|
||||
"action": "过滤",
|
||||
"priority": 3,
|
||||
"is_active": true,
|
||||
"created_at": "2025-08-16T10:57:01.223761"
|
||||
},
|
||||
"archive_old_discussions": {
|
||||
"id": "archive_old_discussions",
|
||||
"name": "归档旧讨论",
|
||||
"description": "自动归档超过时间限制的讨论",
|
||||
"source_chat_types": [
|
||||
"内部讨论群"
|
||||
],
|
||||
"target_chat_types": [
|
||||
"观察群"
|
||||
],
|
||||
"trigger_conditions": {
|
||||
"age_hours": 24,
|
||||
"inactivity_hours": 2
|
||||
},
|
||||
"action": "归档",
|
||||
"priority": 4,
|
||||
"is_active": true,
|
||||
"created_at": "2025-08-16T10:57:01.223762"
|
||||
}
|
||||
},
|
||||
"status": {
|
||||
"total_rooms": 6,
|
||||
"active_rooms": 6,
|
||||
"total_messages": 7,
|
||||
"pending_messages": 7,
|
||||
"coordination_rules": 4,
|
||||
"active_rules": 4,
|
||||
"rooms": {
|
||||
"main_debate": {
|
||||
"name": "主辩论群",
|
||||
"type": "主辩论群",
|
||||
"participants": 8,
|
||||
"messages": 2,
|
||||
"last_activity": "2025-08-16T10:57:01.223769",
|
||||
"is_active": true
|
||||
},
|
||||
"positive_internal": {
|
||||
"name": "正方内部讨论群",
|
||||
"type": "内部讨论群",
|
||||
"participants": 4,
|
||||
"messages": 1,
|
||||
"last_activity": "2025-08-16T10:57:01.223772",
|
||||
"is_active": true
|
||||
},
|
||||
"negative_internal": {
|
||||
"name": "反方内部讨论群",
|
||||
"type": "内部讨论群",
|
||||
"participants": 4,
|
||||
"messages": 1,
|
||||
"last_activity": "2025-08-16T10:57:01.223782",
|
||||
"is_active": true
|
||||
},
|
||||
"strategy_meeting": {
|
||||
"name": "策略会议群",
|
||||
"type": "策略会议群",
|
||||
"participants": 3,
|
||||
"messages": 1,
|
||||
"last_activity": "2025-08-16T10:57:01.223794",
|
||||
"is_active": true
|
||||
},
|
||||
"human_intervention": {
|
||||
"name": "Human干预群",
|
||||
"type": "Human干预群",
|
||||
"participants": 2,
|
||||
"messages": 0,
|
||||
"last_activity": "2025-08-16T10:57:01.223757",
|
||||
"is_active": true
|
||||
},
|
||||
"observation": {
|
||||
"name": "观察群",
|
||||
"type": "观察群",
|
||||
"participants": 2,
|
||||
"messages": 2,
|
||||
"last_activity": "2025-08-16T10:57:01.223790",
|
||||
"is_active": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"export_time": "2025-08-16T10:57:01.223897"
|
||||
}
|
||||
117
modules/testing-framework/tests/test_custom_api.py
Normal file
117
modules/testing-framework/tests/test_custom_api.py
Normal file
@@ -0,0 +1,117 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
测试LiteLLM自定义API端点
|
||||
"""
|
||||
|
||||
import requests
|
||||
import json
|
||||
import os
|
||||
|
||||
def test_litellm_api():
|
||||
"""测试LiteLLM API端点"""
|
||||
api_url = "http://master.tailnet-68f9.ts.net:40012"
|
||||
|
||||
print(f"🔍 测试LiteLLM API端点: {api_url}")
|
||||
|
||||
# 获取用户的API密钥
|
||||
gemini_key = os.getenv('GEMINI_API_KEY', '')
|
||||
|
||||
# 尝试不同的API密钥格式
|
||||
test_keys = [
|
||||
f"sk-{gemini_key}", # 添加sk-前缀
|
||||
gemini_key, # 原始密钥
|
||||
"sk-test", # 测试密钥
|
||||
"test-key", # 简单测试
|
||||
]
|
||||
|
||||
for api_key in test_keys:
|
||||
if not api_key or api_key == "sk-":
|
||||
continue
|
||||
|
||||
print(f"\n🔑 测试API密钥: {api_key[:10]}...")
|
||||
|
||||
# 测试模型列表
|
||||
try:
|
||||
headers = {"x-litellm-api-key": api_key}
|
||||
response = requests.get(f"{api_url}/v1/models", headers=headers, timeout=10)
|
||||
print(f"模型列表状态码: {response.status_code}")
|
||||
|
||||
if response.status_code == 200:
|
||||
models = response.json()
|
||||
print(f"✅ 找到 {len(models.get('data', []))} 个可用模型")
|
||||
for model in models.get('data', [])[:3]: # 显示前3个模型
|
||||
print(f" - {model.get('id', 'unknown')}")
|
||||
|
||||
# 测试聊天完成
|
||||
test_payload = {
|
||||
"model": "gemini-2.5-flash",
|
||||
"messages": [
|
||||
{"role": "user", "content": "Hello, this is a test message. Please respond briefly."}
|
||||
],
|
||||
"max_tokens": 50
|
||||
}
|
||||
|
||||
chat_response = requests.post(
|
||||
f"{api_url}/v1/chat/completions",
|
||||
json=test_payload,
|
||||
headers=headers,
|
||||
timeout=30
|
||||
)
|
||||
|
||||
print(f"聊天完成状态码: {chat_response.status_code}")
|
||||
|
||||
if chat_response.status_code == 200:
|
||||
result = chat_response.json()
|
||||
content = result.get('choices', [{}])[0].get('message', {}).get('content', '')
|
||||
print(f"✅ API测试成功!响应: {content[:100]}...")
|
||||
print(f"\n🎉 可用的API配置:")
|
||||
print(f" - 端点: {api_url}/v1/chat/completions")
|
||||
print(f" - 头部: x-litellm-api-key: {api_key}")
|
||||
print(f" - 模型: gemini-2.5-flash")
|
||||
return True
|
||||
else:
|
||||
print(f"❌ 聊天测试失败: {chat_response.text[:200]}...")
|
||||
|
||||
elif response.status_code == 401:
|
||||
print(f"❌ 认证失败: {response.text[:100]}...")
|
||||
else:
|
||||
print(f"❌ 请求失败: {response.text[:100]}...")
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"❌ 连接失败: {e}")
|
||||
|
||||
return False
|
||||
|
||||
def test_environment_setup():
|
||||
"""测试环境变量设置"""
|
||||
print("\n🔧 当前环境变量:")
|
||||
gemini_key = os.getenv('GEMINI_API_KEY', '')
|
||||
google_key = os.getenv('GOOGLE_API_KEY', '')
|
||||
|
||||
print(f"GEMINI_API_KEY: {'已设置' if gemini_key else '未设置'} ({gemini_key[:10]}... 如果已设置)")
|
||||
print(f"GOOGLE_API_KEY: {'已设置' if google_key else '未设置'} ({google_key[:10]}... 如果已设置)")
|
||||
|
||||
return gemini_key
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("🚀 开始测试LiteLLM自定义API端点...")
|
||||
|
||||
# 检查环境
|
||||
api_key = test_environment_setup()
|
||||
|
||||
if not api_key:
|
||||
print("\n⚠️ 警告: 未找到GEMINI_API_KEY环境变量")
|
||||
|
||||
# 测试API
|
||||
success = test_litellm_api()
|
||||
|
||||
if success:
|
||||
print("\n✅ LiteLLM API端点测试成功!")
|
||||
print("\n💡 建议: 可以使用这个端点替代Google官方API")
|
||||
else:
|
||||
print("\n❌ LiteLLM API端点测试失败")
|
||||
print("\n🔍 可能的解决方案:")
|
||||
print(" 1. 检查LiteLLM服务器配置")
|
||||
print(" 2. 确认API密钥格式")
|
||||
print(" 3. 检查网络连接")
|
||||
159
modules/testing-framework/tests/test_enhanced_priority.py
Normal file
159
modules/testing-framework/tests/test_enhanced_priority.py
Normal file
@@ -0,0 +1,159 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
增强版优先级算法测试脚本
|
||||
测试新的优先级算法在起承转合辩论系统中的表现
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), 'src'))
|
||||
|
||||
from jixia.debates.qi_cheng_zhuan_he_debate import QiChengZhuanHeDebateSystem, DebateStage
|
||||
from jixia.debates.enhanced_priority_algorithm import EnhancedPriorityAlgorithm
|
||||
|
||||
def test_enhanced_priority_algorithm():
|
||||
"""测试增强版优先级算法"""
|
||||
print("🧪 开始测试增强版优先级算法")
|
||||
print("=" * 50)
|
||||
|
||||
# 创建辩论系统
|
||||
debate_system = QiChengZhuanHeDebateSystem()
|
||||
|
||||
# 模拟辩论场景
|
||||
test_scenarios = [
|
||||
{
|
||||
"name": "起阶段开始",
|
||||
"stage": DebateStage.QI,
|
||||
"progress": 1,
|
||||
"history": []
|
||||
},
|
||||
{
|
||||
"name": "承阶段中期",
|
||||
"stage": DebateStage.CHENG,
|
||||
"progress": 3,
|
||||
"history": [
|
||||
{"speaker": "正1", "content": "AI投资具有巨大潜力", "timestamp": "2024-01-01T10:00:00"},
|
||||
{"speaker": "反1", "content": "但风险也很高", "timestamp": "2024-01-01T10:01:00"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "转阶段激烈辩论",
|
||||
"stage": DebateStage.ZHUAN,
|
||||
"progress": 5,
|
||||
"history": [
|
||||
{"speaker": "正2", "content": "数据显示AI投资回报率很高", "timestamp": "2024-01-01T10:02:00"},
|
||||
{"speaker": "反2", "content": "这些数据可能有偏差", "timestamp": "2024-01-01T10:03:00"},
|
||||
{"speaker": "正3", "content": "我们有严格的风控措施", "timestamp": "2024-01-01T10:04:00"},
|
||||
{"speaker": "反3", "content": "风控措施并不能完全避免风险", "timestamp": "2024-01-01T10:05:00"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "合阶段总结",
|
||||
"stage": DebateStage.HE,
|
||||
"progress": 2,
|
||||
"history": [
|
||||
{"speaker": "正4", "content": "综合来看,AI投资利大于弊", "timestamp": "2024-01-01T10:06:00"},
|
||||
{"speaker": "反4", "content": "我们需要更谨慎的态度", "timestamp": "2024-01-01T10:07:00"}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
for i, scenario in enumerate(test_scenarios, 1):
|
||||
print(f"\n📋 测试场景 {i}: {scenario['name']}")
|
||||
print("-" * 30)
|
||||
|
||||
# 设置辩论状态
|
||||
debate_system.context.current_stage = scenario['stage']
|
||||
debate_system.context.stage_progress = scenario['progress']
|
||||
debate_system.context.debate_history = scenario['history']
|
||||
|
||||
# 获取推荐发言者
|
||||
try:
|
||||
recommended_speaker = debate_system._get_priority_speaker()
|
||||
analysis = debate_system.context.last_priority_analysis
|
||||
|
||||
print(f"🎯 推荐发言者: {recommended_speaker}")
|
||||
print(f"📊 优先级分数: {analysis.get('priority_score', 'N/A'):.3f}")
|
||||
|
||||
if 'analysis' in analysis:
|
||||
detailed_analysis = analysis['analysis']
|
||||
print(f"🔍 详细分析:")
|
||||
|
||||
# 显示推荐发言者的详细信息
|
||||
if recommended_speaker in detailed_analysis:
|
||||
speaker_info = detailed_analysis[recommended_speaker]
|
||||
print(f" - 发言者: {recommended_speaker}")
|
||||
print(f" - 优先级分数: {speaker_info.get('priority_score', 'N/A'):.3f}")
|
||||
print(f" - 分析时间: {speaker_info.get('analysis_timestamp', 'N/A')}")
|
||||
|
||||
profile = speaker_info.get('profile')
|
||||
if profile:
|
||||
print(f" - 团队: {profile.team}")
|
||||
print(f" - 发言次数: {profile.total_speech_count}")
|
||||
print(f" - 当前能量: {profile.current_energy:.2f}")
|
||||
print(f" - 辩论风格: {profile.debate_style}")
|
||||
|
||||
# 显示所有发言者的分数排名
|
||||
print(f"\n 📊 所有发言者排名:")
|
||||
sorted_speakers = sorted(detailed_analysis.items(),
|
||||
key=lambda x: x[1].get('priority_score', 0),
|
||||
reverse=True)
|
||||
for rank, (speaker, info) in enumerate(sorted_speakers[:5], 1):
|
||||
score = info.get('priority_score', 0)
|
||||
print(f" {rank}. {speaker}: {score:.3f}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ 测试失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
print("\n" + "=" * 50)
|
||||
print("✅ 增强版优先级算法测试完成")
|
||||
|
||||
def test_algorithm_performance():
|
||||
"""测试算法性能"""
|
||||
print("\n⚡ 性能测试")
|
||||
print("-" * 20)
|
||||
|
||||
import time
|
||||
|
||||
algorithm = EnhancedPriorityAlgorithm()
|
||||
available_speakers = ["正1", "正2", "正3", "正4", "反1", "反2", "反3", "反4"]
|
||||
|
||||
context = {
|
||||
"current_stage": "承",
|
||||
"stage_progress": 3,
|
||||
"max_progress": 6,
|
||||
"time_remaining": 0.5,
|
||||
"topic_keywords": ["AI", "投资", "风险"],
|
||||
"positive_team_score": 0.6,
|
||||
"negative_team_score": 0.4,
|
||||
"positive_recent_speeches": 3,
|
||||
"negative_recent_speeches": 2
|
||||
}
|
||||
|
||||
recent_speeches = [
|
||||
{"speaker": "正1", "content": "AI技术发展迅速"},
|
||||
{"speaker": "反1", "content": "但存在不确定性"}
|
||||
]
|
||||
|
||||
# 性能测试
|
||||
start_time = time.time()
|
||||
iterations = 100
|
||||
|
||||
for _ in range(iterations):
|
||||
speaker, score, analysis = algorithm.get_next_speaker(
|
||||
available_speakers, context, recent_speeches
|
||||
)
|
||||
|
||||
end_time = time.time()
|
||||
avg_time = (end_time - start_time) / iterations * 1000 # 转换为毫秒
|
||||
|
||||
print(f"📈 平均处理时间: {avg_time:.2f}ms")
|
||||
print(f"🔄 总迭代次数: {iterations}")
|
||||
print(f"⚡ 处理速度: {1000/avg_time:.0f} 次/秒")
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_enhanced_priority_algorithm()
|
||||
test_algorithm_performance()
|
||||
82
modules/testing-framework/tests/test_gemini_2_5_flash.py
Normal file
82
modules/testing-framework/tests/test_gemini_2_5_flash.py
Normal file
@@ -0,0 +1,82 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
测试 Gemini 2.5 Flash 模型
|
||||
"""
|
||||
|
||||
import os
|
||||
import requests
|
||||
import json
|
||||
|
||||
def test_gemini_2_5_flash():
|
||||
"""测试 Gemini 2.5 Flash 模型"""
|
||||
|
||||
# 获取环境变量
|
||||
base_url = os.getenv('GOOGLE_BASE_URL')
|
||||
api_key = os.getenv('GEMINI_API_KEY')
|
||||
|
||||
if not base_url or not api_key:
|
||||
print("❌ 环境变量未设置")
|
||||
print(f"GOOGLE_BASE_URL: {base_url}")
|
||||
print(f"GEMINI_API_KEY: {api_key}")
|
||||
return False
|
||||
|
||||
print("✅ 环境变量已设置")
|
||||
print(f"Base URL: {base_url}")
|
||||
print(f"API Key: {api_key[:10]}...{api_key[-4:]}")
|
||||
|
||||
# 构建请求URL
|
||||
model_name = "gemini-2.5-flash"
|
||||
url = f"{base_url}/v1beta/models/{model_name}:generateContent"
|
||||
|
||||
# 请求头
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"x-goog-api-key": api_key
|
||||
}
|
||||
|
||||
# 请求体
|
||||
payload = {
|
||||
"contents": [{
|
||||
"parts": [{
|
||||
"text": "你好,请简单介绍一下你自己。"
|
||||
}]
|
||||
}]
|
||||
}
|
||||
|
||||
try:
|
||||
print(f"\n🚀 测试 {model_name} 模型...")
|
||||
print(f"请求URL: {url}")
|
||||
|
||||
response = requests.post(url, headers=headers, json=payload, timeout=30)
|
||||
|
||||
print(f"响应状态码: {response.status_code}")
|
||||
|
||||
if response.status_code == 200:
|
||||
result = response.json()
|
||||
if 'candidates' in result and len(result['candidates']) > 0:
|
||||
content = result['candidates'][0]['content']['parts'][0]['text']
|
||||
print(f"✅ {model_name} 响应成功:")
|
||||
print(f"📝 回复: {content[:200]}...")
|
||||
return True
|
||||
else:
|
||||
print(f"❌ 响应格式异常: {result}")
|
||||
return False
|
||||
else:
|
||||
print(f"❌ 请求失败: {response.status_code}")
|
||||
print(f"错误信息: {response.text}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ 请求异常: {str(e)}")
|
||||
return False
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("🧪 Gemini 2.5 Flash 模型测试")
|
||||
print("=" * 50)
|
||||
|
||||
success = test_gemini_2_5_flash()
|
||||
|
||||
if success:
|
||||
print("\n🎉 测试成功!Gemini 2.5 Flash 模型工作正常")
|
||||
else:
|
||||
print("\n💥 测试失败!请检查配置")
|
||||
45
modules/testing-framework/tests/test_gemini_direct.py
Normal file
45
modules/testing-framework/tests/test_gemini_direct.py
Normal file
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
直接测试Google Gemini API连接
|
||||
"""
|
||||
|
||||
import os
|
||||
import google.generativeai as genai
|
||||
|
||||
def test_gemini_direct():
|
||||
"""直接测试Gemini API"""
|
||||
print("🔍 测试Gemini API直连...")
|
||||
|
||||
# 检查API密钥
|
||||
api_key = os.getenv('GOOGLE_API_KEY')
|
||||
if not api_key:
|
||||
print("❌ 未找到 GOOGLE_API_KEY")
|
||||
return False
|
||||
|
||||
print(f"✅ API密钥已配置 (长度: {len(api_key)})")
|
||||
|
||||
try:
|
||||
# 配置API
|
||||
genai.configure(api_key=api_key)
|
||||
|
||||
# 创建模型
|
||||
print("📝 创建Gemini模型...")
|
||||
model = genai.GenerativeModel('gemini-2.0-flash-exp')
|
||||
|
||||
# 发送测试消息
|
||||
print("💬 发送测试消息...")
|
||||
response = model.generate_content("请简单说'你好,我是Gemini'")
|
||||
|
||||
print(f"✅ 测试成功!回复: {response.text}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ 测试失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("🚀 Gemini直连测试")
|
||||
test_gemini_direct()
|
||||
44
modules/testing-framework/tests/test_google_adk.py
Normal file
44
modules/testing-framework/tests/test_google_adk.py
Normal file
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
测试 Google ADK 安装和基本功能
|
||||
"""
|
||||
|
||||
import os
|
||||
from google.adk import Agent
|
||||
|
||||
def test_adk_installation():
|
||||
"""测试 ADK 安装是否成功"""
|
||||
try:
|
||||
# 创建一个简单的测试智能体
|
||||
test_agent = Agent(
|
||||
name="测试智能体",
|
||||
model="gemini-2.0-flash-exp"
|
||||
)
|
||||
|
||||
print("✅ Google ADK 安装成功!")
|
||||
print(f"智能体名称: {test_agent.name}")
|
||||
print(f"使用模型: {test_agent.model}")
|
||||
print(f"描述: {test_agent.description}")
|
||||
|
||||
# 检查环境变量
|
||||
google_api_key = os.getenv('GOOGLE_API_KEY')
|
||||
if google_api_key:
|
||||
print(f"✅ GOOGLE_API_KEY 已配置 (长度: {len(google_api_key)} 字符)")
|
||||
else:
|
||||
print("⚠️ GOOGLE_API_KEY 未配置,需要设置 API 密钥")
|
||||
print("请访问 https://aistudio.google.com/ 获取 API 密钥")
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ ADK 安装测试失败: {e}")
|
||||
return False
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("🚀 开始测试 Google ADK 安装...")
|
||||
test_adk_installation()
|
||||
print("\n📝 下一步: 配置 GOOGLE_API_KEY 环境变量")
|
||||
print(" 1. 访问 https://aistudio.google.com/")
|
||||
print(" 2. 获取 API 密钥")
|
||||
print(" 3. 在 Doppler 中设置: doppler secrets set GOOGLE_API_KEY=your_key")
|
||||
505
modules/testing-framework/tests/test_human_intervention.py
Normal file
505
modules/testing-framework/tests/test_human_intervention.py
Normal file
@@ -0,0 +1,505 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Human干预系统测试脚本
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import time
|
||||
from datetime import datetime, timedelta
|
||||
from src.jixia.intervention.human_intervention_system import (
|
||||
DebateHealthMonitor, HealthStatus, InterventionLevel, AlertType
|
||||
)
|
||||
|
||||
class TestHumanInterventionSystem:
|
||||
"""Human干预系统测试类"""
|
||||
|
||||
def __init__(self):
|
||||
self.monitor = DebateHealthMonitor()
|
||||
self.test_results = []
|
||||
|
||||
# 添加事件处理器用于测试
|
||||
self.monitor.add_event_handler("alert_created", self._handle_alert_created)
|
||||
self.monitor.add_event_handler("intervention_executed", self._handle_intervention_executed)
|
||||
self.monitor.add_event_handler("human_notification", self._handle_human_notification)
|
||||
|
||||
self.received_alerts = []
|
||||
self.received_interventions = []
|
||||
self.received_notifications = []
|
||||
|
||||
async def _handle_alert_created(self, alert):
|
||||
"""处理警报创建事件"""
|
||||
self.received_alerts.append(alert)
|
||||
print(f"🚨 收到警报: {alert.alert_type.value} - {alert.message}")
|
||||
|
||||
async def _handle_intervention_executed(self, action):
|
||||
"""处理干预执行事件"""
|
||||
self.received_interventions.append(action)
|
||||
print(f"🛠️ 执行干预: {action.action_type} - {action.description}")
|
||||
|
||||
async def _handle_human_notification(self, notification):
|
||||
"""处理Human通知事件"""
|
||||
self.received_notifications.append(notification)
|
||||
print(f"👤 Human通知: {notification['message']}")
|
||||
|
||||
async def test_basic_health_monitoring(self):
|
||||
"""测试基本健康监控功能"""
|
||||
print("\n🧪 测试基本健康监控功能...")
|
||||
|
||||
# 正常辩论数据
|
||||
normal_debate_data = {
|
||||
"recent_messages": [
|
||||
{"sender": "正1", "content": "我认为人工智能投资具有巨大潜力,因为技术发展迅速,市场需求不断增长。首先,AI技术在各行各业都有广泛应用前景。"},
|
||||
{"sender": "反1", "content": "虽然AI投资有潜力,但我们也要考虑风险。技术泡沫、监管不确定性等因素都可能影响投资回报。"},
|
||||
{"sender": "正2", "content": "反方提到的风险确实存在,但是通过合理的投资策略和风险管理,我们可以最大化收益同时控制风险。"},
|
||||
{"sender": "反2", "content": "正方的观点有道理,不过我想补充一点:投资时机也很重要,现在可能不是最佳入场时机。"}
|
||||
],
|
||||
"topic_keywords": ["人工智能", "AI", "投资", "风险", "收益", "技术", "市场"],
|
||||
"system_status": {
|
||||
"error_rate": 0.01,
|
||||
"avg_response_time": 1.2,
|
||||
"system_load": 0.5
|
||||
}
|
||||
}
|
||||
|
||||
score, status = await self.monitor.analyze_debate_health(normal_debate_data)
|
||||
|
||||
success = score >= 70 and status in [HealthStatus.EXCELLENT, HealthStatus.GOOD]
|
||||
self.test_results.append(("基本健康监控", success, f"得分: {score:.1f}, 状态: {status.value}"))
|
||||
|
||||
print(f"✅ 正常辩论健康度: {score:.1f}分 ({status.value})")
|
||||
return success
|
||||
|
||||
async def test_quality_decline_detection(self):
|
||||
"""测试质量下降检测"""
|
||||
print("\n🧪 测试质量下降检测...")
|
||||
|
||||
# 低质量辩论数据
|
||||
low_quality_data = {
|
||||
"recent_messages": [
|
||||
{"sender": "正1", "content": "好"},
|
||||
{"sender": "反1", "content": "不好"},
|
||||
{"sender": "正2", "content": "是的"},
|
||||
{"sender": "反2", "content": "不是"},
|
||||
{"sender": "正1", "content": "对"},
|
||||
{"sender": "反1", "content": "错"},
|
||||
],
|
||||
"topic_keywords": ["人工智能", "AI", "投资"],
|
||||
"system_status": {
|
||||
"error_rate": 0.01,
|
||||
"avg_response_time": 1.0,
|
||||
"system_load": 0.4
|
||||
}
|
||||
}
|
||||
|
||||
initial_alert_count = len(self.received_alerts)
|
||||
score, status = await self.monitor.analyze_debate_health(low_quality_data)
|
||||
|
||||
# 检查是否触发了质量相关警报
|
||||
quality_alerts = [alert for alert in self.received_alerts[initial_alert_count:]
|
||||
if alert.alert_type == AlertType.QUALITY_DECLINE]
|
||||
|
||||
success = len(quality_alerts) > 0 and score < 50
|
||||
self.test_results.append(("质量下降检测", success, f"得分: {score:.1f}, 警报数: {len(quality_alerts)}"))
|
||||
|
||||
print(f"✅ 低质量辩论检测: {score:.1f}分, 触发警报: {len(quality_alerts)}个")
|
||||
return success
|
||||
|
||||
async def test_toxic_behavior_detection(self):
|
||||
"""测试有害行为检测"""
|
||||
print("\n🧪 测试有害行为检测...")
|
||||
|
||||
# 包含有害行为的数据
|
||||
toxic_data = {
|
||||
"recent_messages": [
|
||||
{"sender": "正1", "content": "我认为这个观点是正确的,有充分的理由支持。"},
|
||||
{"sender": "反1", "content": "你这个观点太愚蠢了!完全没有逻辑!"},
|
||||
{"sender": "正2", "content": "请保持理性讨论,不要进行人身攻击。"},
|
||||
{"sender": "反2", "content": "闭嘴!你们这些白痴根本不懂!"},
|
||||
{"sender": "正1", "content": "让我们回到正题,理性分析这个问题。"}
|
||||
],
|
||||
"topic_keywords": ["观点", "逻辑", "分析"],
|
||||
"system_status": {
|
||||
"error_rate": 0.02,
|
||||
"avg_response_time": 1.5,
|
||||
"system_load": 0.6
|
||||
}
|
||||
}
|
||||
|
||||
initial_alert_count = len(self.received_alerts)
|
||||
score, status = await self.monitor.analyze_debate_health(toxic_data)
|
||||
|
||||
# 检查是否触发了有害行为警报
|
||||
toxic_alerts = [alert for alert in self.received_alerts[initial_alert_count:]
|
||||
if alert.alert_type == AlertType.TOXIC_BEHAVIOR]
|
||||
|
||||
success = len(toxic_alerts) > 0
|
||||
self.test_results.append(("有害行为检测", success, f"警报数: {len(toxic_alerts)}, 文明度分数: {self.monitor.health_metrics['interaction_civility'].value:.1f}"))
|
||||
|
||||
print(f"✅ 有害行为检测: 触发警报: {len(toxic_alerts)}个")
|
||||
return success
|
||||
|
||||
async def test_emotional_escalation_detection(self):
|
||||
"""测试情绪升级检测"""
|
||||
print("\n🧪 测试情绪升级检测...")
|
||||
|
||||
# 情绪激动的数据
|
||||
emotional_data = {
|
||||
"recent_messages": [
|
||||
{"sender": "正1", "content": "我强烈反对这个观点!!!"},
|
||||
{"sender": "反1", "content": "你们完全错了!!!这太愤怒了!!!"},
|
||||
{"sender": "正2", "content": "我非常生气!!!这个讨论让我很讨厌!!!"},
|
||||
{"sender": "反2", "content": "大家都冷静一下!!!不要这么激动!!!"}
|
||||
],
|
||||
"topic_keywords": ["观点", "讨论"],
|
||||
"system_status": {
|
||||
"error_rate": 0.01,
|
||||
"avg_response_time": 1.0,
|
||||
"system_load": 0.5
|
||||
}
|
||||
}
|
||||
|
||||
initial_alert_count = len(self.received_alerts)
|
||||
score, status = await self.monitor.analyze_debate_health(emotional_data)
|
||||
|
||||
# 检查是否触发了情绪升级警报
|
||||
emotion_alerts = [alert for alert in self.received_alerts[initial_alert_count:]
|
||||
if alert.alert_type == AlertType.EMOTIONAL_ESCALATION]
|
||||
|
||||
success = len(emotion_alerts) > 0
|
||||
self.test_results.append(("情绪升级检测", success, f"警报数: {len(emotion_alerts)}, 情绪稳定性: {self.monitor.health_metrics['emotional_stability'].value:.1f}"))
|
||||
|
||||
print(f"✅ 情绪升级检测: 触发警报: {len(emotion_alerts)}个")
|
||||
return success
|
||||
|
||||
async def test_participation_imbalance_detection(self):
|
||||
"""测试参与不平衡检测"""
|
||||
print("\n🧪 测试参与不平衡检测...")
|
||||
|
||||
# 参与不平衡的数据
|
||||
imbalanced_data = {
|
||||
"recent_messages": [
|
||||
{"sender": "正1", "content": "我有很多观点要分享..."},
|
||||
{"sender": "正1", "content": "首先,我认为..."},
|
||||
{"sender": "正1", "content": "其次,我们应该..."},
|
||||
{"sender": "正1", "content": "最后,我建议..."},
|
||||
{"sender": "正1", "content": "总结一下..."},
|
||||
{"sender": "正1", "content": "补充一点..."},
|
||||
{"sender": "正1", "content": "再说一遍..."},
|
||||
{"sender": "反1", "content": "好的"}
|
||||
],
|
||||
"topic_keywords": ["观点", "建议"],
|
||||
"system_status": {
|
||||
"error_rate": 0.01,
|
||||
"avg_response_time": 1.0,
|
||||
"system_load": 0.5
|
||||
}
|
||||
}
|
||||
|
||||
initial_alert_count = len(self.received_alerts)
|
||||
score, status = await self.monitor.analyze_debate_health(imbalanced_data)
|
||||
|
||||
# 检查是否触发了参与不平衡警报
|
||||
balance_alerts = [alert for alert in self.received_alerts[initial_alert_count:]
|
||||
if alert.alert_type == AlertType.PARTICIPATION_IMBALANCE]
|
||||
|
||||
success = len(balance_alerts) > 0
|
||||
self.test_results.append(("参与不平衡检测", success, f"警报数: {len(balance_alerts)}, 平衡度: {self.monitor.health_metrics['participation_balance'].value:.1f}"))
|
||||
|
||||
print(f"✅ 参与不平衡检测: 触发警报: {len(balance_alerts)}个")
|
||||
return success
|
||||
|
||||
async def test_auto_intervention(self):
|
||||
"""测试自动干预功能"""
|
||||
print("\n🧪 测试自动干预功能...")
|
||||
|
||||
# 触发多种问题的数据
|
||||
problematic_data = {
|
||||
"recent_messages": [
|
||||
{"sender": "正1", "content": "你们都是白痴!!!"},
|
||||
{"sender": "反1", "content": "愚蠢!!!"},
|
||||
{"sender": "正2", "content": "垃圾观点!!!"},
|
||||
{"sender": "反2", "content": "讨厌!!!"}
|
||||
],
|
||||
"topic_keywords": ["观点"],
|
||||
"system_status": {
|
||||
"error_rate": 0.05,
|
||||
"avg_response_time": 3.0,
|
||||
"system_load": 0.9
|
||||
}
|
||||
}
|
||||
|
||||
initial_intervention_count = len(self.received_interventions)
|
||||
score, status = await self.monitor.analyze_debate_health(problematic_data)
|
||||
|
||||
# 检查是否执行了自动干预
|
||||
new_interventions = self.received_interventions[initial_intervention_count:]
|
||||
|
||||
success = len(new_interventions) > 0
|
||||
self.test_results.append(("自动干预功能", success, f"执行干预: {len(new_interventions)}次"))
|
||||
|
||||
print(f"✅ 自动干预: 执行了 {len(new_interventions)} 次干预")
|
||||
for intervention in new_interventions:
|
||||
print(f" - {intervention.action_type}: {intervention.description}")
|
||||
|
||||
return success
|
||||
|
||||
async def test_human_notification(self):
|
||||
"""测试Human通知功能"""
|
||||
print("\n🧪 测试Human通知功能...")
|
||||
|
||||
# 设置较低的通知阈值以便测试
|
||||
original_threshold = self.monitor.monitoring_config["human_notification_threshold"]
|
||||
self.monitor.monitoring_config["human_notification_threshold"] = InterventionLevel.MODERATE_GUIDANCE
|
||||
|
||||
# 严重问题数据
|
||||
critical_data = {
|
||||
"recent_messages": [
|
||||
{"sender": "正1", "content": "你"},
|
||||
{"sender": "反1", "content": "我"},
|
||||
{"sender": "正2", "content": "他"},
|
||||
{"sender": "反2", "content": "她"}
|
||||
],
|
||||
"topic_keywords": ["重要话题"],
|
||||
"system_status": {
|
||||
"error_rate": 0.1,
|
||||
"avg_response_time": 5.0,
|
||||
"system_load": 0.95
|
||||
}
|
||||
}
|
||||
|
||||
initial_notification_count = len(self.received_notifications)
|
||||
score, status = await self.monitor.analyze_debate_health(critical_data)
|
||||
|
||||
# 恢复原始阈值
|
||||
self.monitor.monitoring_config["human_notification_threshold"] = original_threshold
|
||||
|
||||
# 检查是否发送了Human通知
|
||||
new_notifications = self.received_notifications[initial_notification_count:]
|
||||
|
||||
success = len(new_notifications) > 0
|
||||
self.test_results.append(("Human通知功能", success, f"发送通知: {len(new_notifications)}次"))
|
||||
|
||||
print(f"✅ Human通知: 发送了 {len(new_notifications)} 次通知")
|
||||
return success
|
||||
|
||||
async def test_health_report_generation(self):
|
||||
"""测试健康报告生成"""
|
||||
print("\n🧪 测试健康报告生成...")
|
||||
|
||||
report = self.monitor.get_health_report()
|
||||
|
||||
required_fields = ["overall_score", "health_status", "metrics", "active_alerts",
|
||||
"recent_interventions", "monitoring_enabled", "last_check"]
|
||||
|
||||
success = all(field in report for field in required_fields)
|
||||
success = success and len(report["metrics"]) == 6 # 6个健康指标
|
||||
|
||||
self.test_results.append(("健康报告生成", success, f"包含字段: {len(report)}个"))
|
||||
|
||||
print(f"✅ 健康报告生成: 包含 {len(report)} 个字段")
|
||||
print(f" 整体得分: {report['overall_score']}")
|
||||
print(f" 健康状态: {report['health_status']}")
|
||||
print(f" 活跃警报: {report['active_alerts']}个")
|
||||
|
||||
return success
|
||||
|
||||
async def test_alert_resolution(self):
|
||||
"""测试警报解决功能"""
|
||||
print("\n🧪 测试警报解决功能...")
|
||||
|
||||
# 确保有一些警报
|
||||
if not self.monitor.active_alerts:
|
||||
# 创建一个测试警报
|
||||
from src.jixia.intervention.human_intervention_system import InterventionAlert
|
||||
test_alert = InterventionAlert(
|
||||
id="test_alert_123",
|
||||
alert_type=AlertType.QUALITY_DECLINE,
|
||||
severity=InterventionLevel.GENTLE_REMINDER,
|
||||
message="测试警报",
|
||||
affected_participants=[],
|
||||
metrics={"test": 50},
|
||||
timestamp=datetime.now()
|
||||
)
|
||||
self.monitor.active_alerts.append(test_alert)
|
||||
|
||||
# 解决第一个警报
|
||||
if self.monitor.active_alerts:
|
||||
alert_id = self.monitor.active_alerts[0].id
|
||||
success = self.monitor.resolve_alert(alert_id, "测试解决")
|
||||
|
||||
# 清理已解决的警报
|
||||
initial_count = len(self.monitor.active_alerts)
|
||||
self.monitor.clear_resolved_alerts()
|
||||
final_count = len(self.monitor.active_alerts)
|
||||
|
||||
success = success and (final_count < initial_count)
|
||||
else:
|
||||
success = True # 没有警报也算成功
|
||||
|
||||
self.test_results.append(("警报解决功能", success, f"解决并清理警报"))
|
||||
|
||||
print(f"✅ 警报解决: 功能正常")
|
||||
return success
|
||||
|
||||
async def test_monitoring_control(self):
|
||||
"""测试监控控制功能"""
|
||||
print("\n🧪 测试监控控制功能...")
|
||||
|
||||
# 测试禁用监控
|
||||
self.monitor.disable_monitoring()
|
||||
disabled_state = not self.monitor.monitoring_enabled
|
||||
|
||||
# 测试启用监控
|
||||
self.monitor.enable_monitoring()
|
||||
enabled_state = self.monitor.monitoring_enabled
|
||||
|
||||
success = disabled_state and enabled_state
|
||||
self.test_results.append(("监控控制功能", success, "启用/禁用功能正常"))
|
||||
|
||||
print(f"✅ 监控控制: 启用/禁用功能正常")
|
||||
return success
|
||||
|
||||
async def test_data_persistence(self):
|
||||
"""测试数据持久化"""
|
||||
print("\n🧪 测试数据持久化...")
|
||||
|
||||
try:
|
||||
# 保存监控数据
|
||||
test_filename = "test_monitoring_data.json"
|
||||
self.monitor.save_monitoring_data(test_filename)
|
||||
|
||||
# 检查文件是否存在并包含正确数据
|
||||
import os
|
||||
if os.path.exists(test_filename):
|
||||
with open(test_filename, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
|
||||
required_sections = ["health_metrics", "active_alerts", "intervention_history",
|
||||
"monitoring_config", "monitoring_enabled", "export_time"]
|
||||
success = all(section in data for section in required_sections)
|
||||
|
||||
# 清理测试文件
|
||||
os.remove(test_filename)
|
||||
else:
|
||||
success = False
|
||||
except Exception as e:
|
||||
print(f" 数据持久化错误: {e}")
|
||||
success = False
|
||||
|
||||
self.test_results.append(("数据持久化", success, "保存/加载功能正常"))
|
||||
|
||||
print(f"✅ 数据持久化: 功能正常")
|
||||
return success
|
||||
|
||||
async def test_performance(self):
|
||||
"""测试性能"""
|
||||
print("\n🧪 测试性能...")
|
||||
|
||||
# 准备测试数据
|
||||
test_data = {
|
||||
"recent_messages": [
|
||||
{"sender": f"用户{i%4}", "content": f"这是第{i}条测试消息,包含一些内容用于分析。"}
|
||||
for i in range(20)
|
||||
],
|
||||
"topic_keywords": ["测试", "性能", "分析", "消息"],
|
||||
"system_status": {
|
||||
"error_rate": 0.01,
|
||||
"avg_response_time": 1.0,
|
||||
"system_load": 0.5
|
||||
}
|
||||
}
|
||||
|
||||
# 性能测试
|
||||
iterations = 100
|
||||
start_time = time.time()
|
||||
|
||||
for _ in range(iterations):
|
||||
await self.monitor.analyze_debate_health(test_data)
|
||||
|
||||
end_time = time.time()
|
||||
total_time = end_time - start_time
|
||||
avg_time = total_time / iterations
|
||||
analyses_per_second = iterations / total_time
|
||||
|
||||
# 性能要求:平均处理时间 < 100ms
|
||||
success = avg_time < 0.1
|
||||
|
||||
self.test_results.append(("性能测试", success, f"平均处理时间: {avg_time*1000:.2f}ms, 处理速度: {analyses_per_second:.1f}次/秒"))
|
||||
|
||||
print(f"✅ 性能测试: 平均处理时间 {avg_time*1000:.2f}ms, 处理速度 {analyses_per_second:.1f}次/秒")
|
||||
return success
|
||||
|
||||
async def run_all_tests(self):
|
||||
"""运行所有测试"""
|
||||
print("🚀 开始Human干预系统测试...")
|
||||
print("=" * 60)
|
||||
|
||||
test_functions = [
|
||||
self.test_basic_health_monitoring,
|
||||
self.test_quality_decline_detection,
|
||||
self.test_toxic_behavior_detection,
|
||||
self.test_emotional_escalation_detection,
|
||||
self.test_participation_imbalance_detection,
|
||||
self.test_auto_intervention,
|
||||
self.test_human_notification,
|
||||
self.test_health_report_generation,
|
||||
self.test_alert_resolution,
|
||||
self.test_monitoring_control,
|
||||
self.test_data_persistence,
|
||||
self.test_performance
|
||||
]
|
||||
|
||||
passed_tests = 0
|
||||
total_tests = len(test_functions)
|
||||
|
||||
for test_func in test_functions:
|
||||
try:
|
||||
result = await test_func()
|
||||
if result:
|
||||
passed_tests += 1
|
||||
except Exception as e:
|
||||
print(f"❌ 测试失败: {test_func.__name__} - {e}")
|
||||
self.test_results.append((test_func.__name__, False, f"异常: {e}"))
|
||||
|
||||
# 输出测试结果
|
||||
print("\n" + "=" * 60)
|
||||
print("📊 测试结果汇总:")
|
||||
print("=" * 60)
|
||||
|
||||
for test_name, success, details in self.test_results:
|
||||
status = "✅ 通过" if success else "❌ 失败"
|
||||
print(f"{status} {test_name}: {details}")
|
||||
|
||||
success_rate = (passed_tests / total_tests) * 100
|
||||
print(f"\n🎯 总体测试结果: {passed_tests}/{total_tests} 通过 ({success_rate:.1f}%)")
|
||||
|
||||
if success_rate >= 90:
|
||||
print("🎉 Human干预系统测试优秀!")
|
||||
elif success_rate >= 80:
|
||||
print("👍 Human干预系统测试良好!")
|
||||
elif success_rate >= 70:
|
||||
print("⚠️ Human干预系统测试一般,需要改进。")
|
||||
else:
|
||||
print("❌ Human干预系统测试较差,需要重大改进。")
|
||||
|
||||
# 输出系统状态
|
||||
print("\n📋 系统状态报告:")
|
||||
report = self.monitor.get_health_report()
|
||||
print(f"监控状态: {'启用' if report['monitoring_enabled'] else '禁用'}")
|
||||
print(f"活跃警报: {report['active_alerts']}个")
|
||||
print(f"近期干预: {report['recent_interventions']}次")
|
||||
print(f"收到警报: {len(self.received_alerts)}个")
|
||||
print(f"执行干预: {len(self.received_interventions)}次")
|
||||
print(f"Human通知: {len(self.received_notifications)}次")
|
||||
|
||||
return success_rate >= 80
|
||||
|
||||
async def main():
|
||||
"""主函数"""
|
||||
tester = TestHumanInterventionSystem()
|
||||
await tester.run_all_tests()
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
147
modules/testing-framework/tests/test_memory_bank.py
Normal file
147
modules/testing-framework/tests/test_memory_bank.py
Normal file
@@ -0,0 +1,147 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
测试 Google ADK Memory Bank 功能
|
||||
"""
|
||||
|
||||
import os
|
||||
import asyncio
|
||||
from google.adk import Agent
|
||||
from google.adk.memory import MemoryBank, MemoryItem
|
||||
from datetime import datetime
|
||||
|
||||
async def test_memory_bank():
|
||||
"""测试Memory Bank基本功能"""
|
||||
print("🧠 测试 Google ADK Memory Bank...")
|
||||
|
||||
try:
|
||||
# 创建记忆银行
|
||||
memory_bank = MemoryBank(
|
||||
name="test_memory_bank",
|
||||
description="测试用的记忆银行"
|
||||
)
|
||||
|
||||
print("✅ Memory Bank 创建成功")
|
||||
|
||||
# 添加记忆项
|
||||
memory_item = MemoryItem(
|
||||
content="这是一个测试记忆:比特币在2021年达到历史最高点69000美元",
|
||||
metadata={
|
||||
"type": "market_data",
|
||||
"asset": "bitcoin",
|
||||
"timestamp": datetime.now().isoformat()
|
||||
}
|
||||
)
|
||||
|
||||
await memory_bank.add_memory(memory_item)
|
||||
print("✅ 记忆添加成功")
|
||||
|
||||
# 搜索记忆
|
||||
search_results = await memory_bank.search("比特币", limit=5)
|
||||
print(f"✅ 记忆搜索成功,找到 {len(search_results)} 条相关记忆")
|
||||
|
||||
for i, memory in enumerate(search_results):
|
||||
print(f" {i+1}. {memory.content}")
|
||||
|
||||
# 创建带记忆银行的智能体
|
||||
agent = Agent(
|
||||
name="测试智能体",
|
||||
model="gemini-2.0-flash-exp",
|
||||
instruction="你是一个测试智能体,请使用你的记忆银行来回答问题。",
|
||||
memory_bank=memory_bank
|
||||
)
|
||||
|
||||
print("✅ 带记忆银行的智能体创建成功")
|
||||
|
||||
return True
|
||||
|
||||
except ImportError as e:
|
||||
print(f"❌ Memory Bank 模块导入失败: {e}")
|
||||
print("💡 可能需要更新 Google ADK 版本或启用 Memory Bank 功能")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"❌ Memory Bank 测试失败: {e}")
|
||||
return False
|
||||
|
||||
async def test_simple_memory_simulation():
|
||||
"""模拟Memory Bank功能的简单实现"""
|
||||
print("\n🔄 使用简单模拟实现...")
|
||||
|
||||
class SimpleMemoryBank:
|
||||
def __init__(self, name: str, description: str):
|
||||
self.name = name
|
||||
self.description = description
|
||||
self.memories = []
|
||||
|
||||
async def add_memory(self, content: str, metadata: dict = None):
|
||||
memory = {
|
||||
"content": content,
|
||||
"metadata": metadata or {},
|
||||
"timestamp": datetime.now().isoformat()
|
||||
}
|
||||
self.memories.append(memory)
|
||||
|
||||
async def search(self, query: str, limit: int = 5):
|
||||
# 简单的关键词匹配
|
||||
results = []
|
||||
query_lower = query.lower()
|
||||
|
||||
for memory in self.memories:
|
||||
if query_lower in memory["content"].lower():
|
||||
results.append(memory)
|
||||
if len(results) >= limit:
|
||||
break
|
||||
|
||||
return results
|
||||
|
||||
# 测试简单实现
|
||||
memory_bank = SimpleMemoryBank(
|
||||
name="铁拐李记忆银行",
|
||||
description="铁拐李的逆向投资记忆"
|
||||
)
|
||||
|
||||
# 添加一些记忆
|
||||
memories = [
|
||||
"2000年互联网泡沫破裂,纳斯达克指数从5048点跌到1114点",
|
||||
"2008年金融危机,雷曼兄弟破产引发全球恐慌",
|
||||
"2020年3月疫情恐慌,美股熔断4次,但随后强劲反弹",
|
||||
"比特币从2017年的2万美元跌到2018年的3200美元"
|
||||
]
|
||||
|
||||
for memory in memories:
|
||||
await memory_bank.add_memory(memory, {"type": "historical_event"})
|
||||
|
||||
print(f"✅ 已添加 {len(memories)} 条记忆")
|
||||
|
||||
# 搜索测试
|
||||
search_queries = ["泡沫", "比特币", "金融危机"]
|
||||
|
||||
for query in search_queries:
|
||||
results = await memory_bank.search(query)
|
||||
print(f"\n🔍 搜索 '{query}' 找到 {len(results)} 条记忆:")
|
||||
for i, result in enumerate(results):
|
||||
print(f" {i+1}. {result['content']}")
|
||||
|
||||
return True
|
||||
|
||||
async def main():
|
||||
"""主测试函数"""
|
||||
print("🚀 Google ADK Memory Bank 功能测试")
|
||||
|
||||
# 检查API密钥
|
||||
api_key = os.getenv('GOOGLE_API_KEY')
|
||||
if not api_key:
|
||||
print("❌ 未找到 GOOGLE_API_KEY 环境变量")
|
||||
return
|
||||
|
||||
print(f"✅ API密钥已配置")
|
||||
|
||||
# 尝试真实的Memory Bank
|
||||
success = await test_memory_bank()
|
||||
|
||||
if not success:
|
||||
# 如果真实的Memory Bank不可用,使用模拟实现
|
||||
await test_simple_memory_simulation()
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
63
modules/testing-framework/tests/test_memory_bank_factory.py
Normal file
63
modules/testing-framework/tests/test_memory_bank_factory.py
Normal file
@@ -0,0 +1,63 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Memory Bank 模块测试
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import os
|
||||
import sys
|
||||
from unittest.mock import patch, MagicMock
|
||||
|
||||
# 添加项目根目录到Python路径
|
||||
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
|
||||
|
||||
from src.jixia.memory.factory import get_memory_backend
|
||||
from src.jixia.memory.base_memory_bank import MemoryBankProtocol
|
||||
|
||||
|
||||
class TestMemoryBankFactory(unittest.TestCase):
|
||||
"""测试记忆银行工厂函数"""
|
||||
|
||||
@patch('src.jixia.memory.factory.VertexMemoryBank')
|
||||
def test_get_memory_backend_always_returns_vertex(self, mock_vertex):
|
||||
"""测试 get_memory_backend 总是返回 Vertex AI 后端"""
|
||||
mock_instance = MagicMock()
|
||||
mock_vertex.from_config.return_value = mock_instance
|
||||
|
||||
# 不设置任何环境变量
|
||||
memory_bank = get_memory_backend()
|
||||
self.assertEqual(memory_bank, mock_instance)
|
||||
mock_vertex.from_config.assert_called_once()
|
||||
|
||||
@patch('src.jixia.memory.factory.VertexMemoryBank')
|
||||
def test_get_memory_backend_ignores_prefer_parameter(self, mock_vertex):
|
||||
"""测试 get_memory_backend 忽略 prefer 参数"""
|
||||
mock_instance = MagicMock()
|
||||
mock_vertex.from_config.return_value = mock_instance
|
||||
|
||||
# prefer 参数设置为 cloudflare,但应被忽略
|
||||
memory_bank = get_memory_backend(prefer="cloudflare")
|
||||
self.assertEqual(memory_bank, mock_instance)
|
||||
mock_vertex.from_config.assert_called_once()
|
||||
|
||||
|
||||
class TestMemoryBankProtocol(unittest.TestCase):
|
||||
"""测试MemoryBankProtocol协议"""
|
||||
|
||||
def test_protocol_methods(self):
|
||||
"""测试协议定义的方法"""
|
||||
# 创建一个实现MemoryBankProtocol的简单类用于测试
|
||||
class TestMemoryBank:
|
||||
async def create_memory_bank(self, agent_name: str, display_name = None): pass
|
||||
async def add_memory(self, agent_name: str, content: str, memory_type = "conversation", debate_topic = "", metadata = None): pass
|
||||
async def search_memories(self, agent_name: str, query: str, memory_type = None, limit = 10): pass
|
||||
async def get_agent_context(self, agent_name: str, debate_topic: str): pass
|
||||
async def save_debate_session(self, debate_topic: str, participants, conversation_history, outcomes = None): pass
|
||||
|
||||
# 验证TestMemoryBank是否符合MemoryBankProtocol协议
|
||||
self.assertIsInstance(TestMemoryBank(), MemoryBankProtocol)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# 运行测试
|
||||
unittest.main()
|
||||
384
modules/testing-framework/tests/test_multi_chat_coordination.py
Normal file
384
modules/testing-framework/tests/test_multi_chat_coordination.py
Normal file
@@ -0,0 +1,384 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
多群聊协调系统测试脚本
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
from datetime import datetime
|
||||
|
||||
# 添加项目路径
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), 'src'))
|
||||
|
||||
from jixia.coordination.multi_chat_coordinator import (
|
||||
MultiChatCoordinator, ChatType, MessagePriority, CoordinationAction
|
||||
)
|
||||
|
||||
async def test_basic_messaging():
|
||||
"""测试基本消息功能"""
|
||||
print("\n🧪 测试基本消息功能")
|
||||
print("=" * 50)
|
||||
|
||||
coordinator = MultiChatCoordinator()
|
||||
|
||||
# 测试正常消息发送
|
||||
message1 = await coordinator.send_message(
|
||||
"main_debate", "正1",
|
||||
"AI投资是未来科技发展的重要驱动力",
|
||||
MessagePriority.NORMAL, ["观点", "AI", "投资"]
|
||||
)
|
||||
print(f"✅ 消息1发送成功: {message1.id}")
|
||||
|
||||
message2 = await coordinator.send_message(
|
||||
"main_debate", "反1",
|
||||
"AI投资存在泡沫风险,需要谨慎对待",
|
||||
MessagePriority.NORMAL, ["反驳", "风险", "投资"]
|
||||
)
|
||||
print(f"✅ 消息2发送成功: {message2.id}")
|
||||
|
||||
# 测试内部讨论
|
||||
message3 = await coordinator.send_message(
|
||||
"positive_internal", "正2",
|
||||
"我们需要收集更多AI成功案例的数据",
|
||||
MessagePriority.HIGH, ["策略", "数据"]
|
||||
)
|
||||
print(f"✅ 内部消息发送成功: {message3.id}")
|
||||
|
||||
return coordinator
|
||||
|
||||
async def test_escalation_rules():
|
||||
"""测试升级规则"""
|
||||
print("\n🚨 测试升级规则")
|
||||
print("=" * 50)
|
||||
|
||||
coordinator = MultiChatCoordinator()
|
||||
|
||||
# 发送紧急消息,应该触发升级规则
|
||||
urgent_message = await coordinator.send_message(
|
||||
"main_debate", "正3",
|
||||
"系统检测到异常行为,需要紧急干预",
|
||||
MessagePriority.URGENT, ["紧急", "系统"]
|
||||
)
|
||||
print(f"🚨 紧急消息发送: {urgent_message.id}")
|
||||
|
||||
# 等待协调规则处理
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
# 检查Human干预群是否收到升级消息
|
||||
human_room = coordinator.chat_rooms["human_intervention"]
|
||||
escalated_messages = [msg for msg in human_room.message_history
|
||||
if "升级" in msg.tags]
|
||||
|
||||
if escalated_messages:
|
||||
print(f"✅ 升级规则生效,Human干预群收到 {len(escalated_messages)} 条升级消息")
|
||||
for msg in escalated_messages:
|
||||
print(f" 📨 {msg.sender}: {msg.content[:100]}...")
|
||||
else:
|
||||
print("❌ 升级规则未生效")
|
||||
|
||||
return coordinator
|
||||
|
||||
async def test_broadcast_rules():
|
||||
"""测试广播规则"""
|
||||
print("\n📢 测试广播规则")
|
||||
print("=" * 50)
|
||||
|
||||
coordinator = MultiChatCoordinator()
|
||||
|
||||
# 在策略会议群发送决策消息
|
||||
strategy_message = await coordinator.send_message(
|
||||
"strategy_meeting", "系统",
|
||||
"决策:采用数据驱动的论证策略",
|
||||
MessagePriority.HIGH, ["决策", "策略"]
|
||||
)
|
||||
print(f"📋 策略决策发送: {strategy_message.id}")
|
||||
|
||||
# 等待协调规则处理
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
# 检查内部讨论群是否收到广播消息
|
||||
broadcast_count = 0
|
||||
for room_id, room in coordinator.chat_rooms.items():
|
||||
if room.chat_type == ChatType.INTERNAL_DISCUSSION:
|
||||
broadcast_messages = [msg for msg in room.message_history
|
||||
if "广播" in msg.tags]
|
||||
if broadcast_messages:
|
||||
broadcast_count += len(broadcast_messages)
|
||||
print(f"✅ {room.name} 收到 {len(broadcast_messages)} 条广播消息")
|
||||
|
||||
if broadcast_count > 0:
|
||||
print(f"✅ 广播规则生效,总共发送 {broadcast_count} 条广播消息")
|
||||
else:
|
||||
print("❌ 广播规则未生效")
|
||||
|
||||
return coordinator
|
||||
|
||||
async def test_filter_rules():
|
||||
"""测试过滤规则"""
|
||||
print("\n🔍 测试过滤规则")
|
||||
print("=" * 50)
|
||||
|
||||
coordinator = MultiChatCoordinator()
|
||||
|
||||
# 发送低质量消息
|
||||
low_quality_message = await coordinator.send_message(
|
||||
"main_debate", "正4",
|
||||
"好的",
|
||||
MessagePriority.LOW
|
||||
)
|
||||
print(f"📝 低质量消息发送: {low_quality_message.id}")
|
||||
|
||||
# 等待协调规则处理
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
# 检查消息是否被过滤
|
||||
if low_quality_message.metadata.get("filtered"):
|
||||
print(f"✅ 过滤规则生效,消息被标记为已过滤")
|
||||
print(f" 过滤原因: {low_quality_message.metadata.get('filter_reason')}")
|
||||
else:
|
||||
print("❌ 过滤规则未生效")
|
||||
|
||||
return coordinator
|
||||
|
||||
async def test_discussion_merging():
|
||||
"""测试讨论合并"""
|
||||
print("\n🔗 测试讨论合并")
|
||||
print("=" * 50)
|
||||
|
||||
coordinator = MultiChatCoordinator()
|
||||
|
||||
# 发送相关消息
|
||||
messages = [
|
||||
("main_debate", "正1", "AI技术的发展速度令人惊叹", ["AI", "技术"]),
|
||||
("positive_internal", "正2", "我们应该强调AI技术的创新价值", ["AI", "创新"]),
|
||||
("negative_internal", "反1", "AI技术也带来了就业问题", ["AI", "就业"]),
|
||||
]
|
||||
|
||||
sent_messages = []
|
||||
for chat_id, sender, content, tags in messages:
|
||||
msg = await coordinator.send_message(chat_id, sender, content, tags=tags)
|
||||
sent_messages.append(msg)
|
||||
print(f"📨 发送消息: {sender} - {content[:30]}...")
|
||||
|
||||
# 发送触发合并的消息
|
||||
trigger_message = await coordinator.send_message(
|
||||
"main_debate", "系统",
|
||||
"需要整合关于AI技术的所有讨论",
|
||||
tags=["AI", "整合"]
|
||||
)
|
||||
print(f"🔗 触发合并消息: {trigger_message.id}")
|
||||
|
||||
# 等待协调规则处理
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
# 检查策略会议群是否收到合并摘要
|
||||
strategy_room = coordinator.chat_rooms["strategy_meeting"]
|
||||
merge_messages = [msg for msg in strategy_room.message_history
|
||||
if "合并" in msg.tags or "摘要" in msg.tags]
|
||||
|
||||
if merge_messages:
|
||||
print(f"✅ 讨论合并生效,策略会议群收到 {len(merge_messages)} 条摘要")
|
||||
for msg in merge_messages:
|
||||
print(f" 📋 摘要: {msg.content[:100]}...")
|
||||
else:
|
||||
print("❌ 讨论合并未生效")
|
||||
|
||||
return coordinator
|
||||
|
||||
async def test_permission_system():
|
||||
"""测试权限系统"""
|
||||
print("\n🔐 测试权限系统")
|
||||
print("=" * 50)
|
||||
|
||||
coordinator = MultiChatCoordinator()
|
||||
|
||||
# 测试正常权限
|
||||
try:
|
||||
normal_message = await coordinator.send_message(
|
||||
"main_debate", "正1", "这是一条正常消息"
|
||||
)
|
||||
print(f"✅ 正常权限测试通过: {normal_message.id}")
|
||||
except Exception as e:
|
||||
print(f"❌ 正常权限测试失败: {e}")
|
||||
|
||||
# 测试无权限用户
|
||||
try:
|
||||
unauthorized_message = await coordinator.send_message(
|
||||
"main_debate", "未授权用户", "这是一条未授权消息"
|
||||
)
|
||||
print(f"❌ 权限系统失效,未授权用户发送成功: {unauthorized_message.id}")
|
||||
except PermissionError as e:
|
||||
print(f"✅ 权限系统正常,拒绝未授权用户: {e}")
|
||||
except Exception as e:
|
||||
print(f"❌ 权限系统异常: {e}")
|
||||
|
||||
# 测试内部群权限
|
||||
try:
|
||||
internal_message = await coordinator.send_message(
|
||||
"positive_internal", "正2", "内部策略讨论"
|
||||
)
|
||||
print(f"✅ 内部群权限测试通过: {internal_message.id}")
|
||||
except Exception as e:
|
||||
print(f"❌ 内部群权限测试失败: {e}")
|
||||
|
||||
# 测试跨团队权限
|
||||
try:
|
||||
cross_team_message = await coordinator.send_message(
|
||||
"positive_internal", "反1", "反方试图进入正方内部群"
|
||||
)
|
||||
print(f"❌ 跨团队权限控制失效: {cross_team_message.id}")
|
||||
except PermissionError as e:
|
||||
print(f"✅ 跨团队权限控制正常: {e}")
|
||||
except Exception as e:
|
||||
print(f"❌ 跨团队权限控制异常: {e}")
|
||||
|
||||
return coordinator
|
||||
|
||||
async def test_system_status():
|
||||
"""测试系统状态"""
|
||||
print("\n📊 测试系统状态")
|
||||
print("=" * 50)
|
||||
|
||||
coordinator = MultiChatCoordinator()
|
||||
|
||||
# 发送一些测试消息
|
||||
test_messages = [
|
||||
("main_debate", "正1", "测试消息1"),
|
||||
("main_debate", "反1", "测试消息2"),
|
||||
("positive_internal", "正2", "内部消息1"),
|
||||
("negative_internal", "反2", "内部消息2"),
|
||||
("strategy_meeting", "系统", "策略消息1"),
|
||||
]
|
||||
|
||||
for chat_id, sender, content in test_messages:
|
||||
await coordinator.send_message(chat_id, sender, content)
|
||||
|
||||
# 获取系统状态
|
||||
status = coordinator.get_chat_status()
|
||||
|
||||
print(f"📈 系统状态报告:")
|
||||
print(f" 总群聊数: {status['total_rooms']}")
|
||||
print(f" 活跃群聊数: {status['active_rooms']}")
|
||||
print(f" 总消息数: {status['total_messages']}")
|
||||
print(f" 待处理消息: {status['pending_messages']}")
|
||||
print(f" 协调规则数: {status['coordination_rules']}")
|
||||
print(f" 活跃规则数: {status['active_rules']}")
|
||||
|
||||
print(f"\n📋 群聊详情:")
|
||||
for room_id, room_info in status['rooms'].items():
|
||||
print(f" 🏠 {room_info['name']} ({room_info['type']})")
|
||||
print(f" 参与者: {room_info['participants']} 人")
|
||||
print(f" 消息数: {room_info['messages']}")
|
||||
print(f" 活跃状态: {'✅' if room_info['is_active'] else '❌'}")
|
||||
|
||||
# 测试数据保存
|
||||
try:
|
||||
coordinator.save_coordination_data("test_coordination_data.json")
|
||||
print(f"\n💾 数据保存测试通过")
|
||||
except Exception as e:
|
||||
print(f"\n❌ 数据保存测试失败: {e}")
|
||||
|
||||
return coordinator
|
||||
|
||||
async def test_performance():
|
||||
"""测试性能"""
|
||||
print("\n⚡ 测试性能")
|
||||
print("=" * 50)
|
||||
|
||||
coordinator = MultiChatCoordinator()
|
||||
|
||||
# 批量发送消息测试
|
||||
start_time = datetime.now()
|
||||
message_count = 100
|
||||
|
||||
print(f"📤 发送 {message_count} 条消息...")
|
||||
|
||||
for i in range(message_count):
|
||||
chat_id = "main_debate" if i % 2 == 0 else "positive_internal"
|
||||
sender = f"测试用户{i % 4 + 1}"
|
||||
if chat_id == "positive_internal":
|
||||
sender = f"正{i % 4 + 1}"
|
||||
|
||||
content = f"性能测试消息 {i + 1}: 这是一条用于性能测试的消息内容"
|
||||
|
||||
try:
|
||||
await coordinator.send_message(chat_id, sender, content)
|
||||
except PermissionError:
|
||||
# 忽略权限错误,继续测试
|
||||
pass
|
||||
|
||||
end_time = datetime.now()
|
||||
duration = (end_time - start_time).total_seconds()
|
||||
|
||||
print(f"⏱️ 性能测试结果:")
|
||||
print(f" 总耗时: {duration:.3f} 秒")
|
||||
print(f" 平均每条消息: {duration/message_count*1000:.2f} 毫秒")
|
||||
print(f" 消息处理速度: {message_count/duration:.1f} 条/秒")
|
||||
|
||||
# 获取最终状态
|
||||
final_status = coordinator.get_chat_status()
|
||||
print(f" 最终消息总数: {final_status['total_messages']}")
|
||||
|
||||
return coordinator
|
||||
|
||||
async def run_all_tests():
|
||||
"""运行所有测试"""
|
||||
print("🚀 多群聊协调系统测试开始")
|
||||
print("=" * 60)
|
||||
|
||||
tests = [
|
||||
("基本消息功能", test_basic_messaging),
|
||||
("升级规则", test_escalation_rules),
|
||||
("广播规则", test_broadcast_rules),
|
||||
("过滤规则", test_filter_rules),
|
||||
("讨论合并", test_discussion_merging),
|
||||
("权限系统", test_permission_system),
|
||||
("系统状态", test_system_status),
|
||||
("性能测试", test_performance),
|
||||
]
|
||||
|
||||
results = []
|
||||
|
||||
for test_name, test_func in tests:
|
||||
try:
|
||||
print(f"\n🧪 开始测试: {test_name}")
|
||||
coordinator = await test_func()
|
||||
results.append((test_name, "✅ 通过", None))
|
||||
print(f"✅ {test_name} 测试完成")
|
||||
except Exception as e:
|
||||
results.append((test_name, "❌ 失败", str(e)))
|
||||
print(f"❌ {test_name} 测试失败: {e}")
|
||||
|
||||
# 测试结果总结
|
||||
print("\n" + "=" * 60)
|
||||
print("📊 测试结果总结")
|
||||
print("=" * 60)
|
||||
|
||||
passed = 0
|
||||
failed = 0
|
||||
|
||||
for test_name, status, error in results:
|
||||
print(f"{status} {test_name}")
|
||||
if error:
|
||||
print(f" 错误: {error}")
|
||||
|
||||
if "✅" in status:
|
||||
passed += 1
|
||||
else:
|
||||
failed += 1
|
||||
|
||||
print(f"\n📈 测试统计:")
|
||||
print(f" 通过: {passed}")
|
||||
print(f" 失败: {failed}")
|
||||
print(f" 总计: {passed + failed}")
|
||||
print(f" 成功率: {passed/(passed+failed)*100:.1f}%")
|
||||
|
||||
if failed == 0:
|
||||
print("\n🎉 所有测试通过!多群聊协调系统运行正常。")
|
||||
else:
|
||||
print(f"\n⚠️ 有 {failed} 个测试失败,需要检查相关功能。")
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(run_all_tests())
|
||||
26
modules/testing-framework/tests/test_openbb_fallback.py
Normal file
26
modules/testing-framework/tests/test_openbb_fallback.py
Normal file
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
验证在未安装 OpenBB 时,OpenBB Tab 的数据加载回退行为。
|
||||
该测试不强制要求安装 OpenBB,因此仅检查函数能返回非空 DataFrame。
|
||||
"""
|
||||
|
||||
import importlib
|
||||
import types
|
||||
import pandas as pd
|
||||
|
||||
from app.tabs.openbb_tab import _load_price_data
|
||||
|
||||
|
||||
def test_openbb_fallback_without_openbb():
|
||||
# 尝试卸载 openbb 以模拟未安装环境(若本地未安装会抛错,忽略)
|
||||
try:
|
||||
if 'openbb' in list(importlib.sys.modules.keys()):
|
||||
del importlib.sys.modules['openbb']
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
df = _load_price_data('AAPL', 180)
|
||||
assert isinstance(df, pd.DataFrame)
|
||||
assert not df.empty
|
||||
assert 'Date' in df.columns and 'Close' in df.columns
|
||||
188
modules/testing-framework/tests/test_openrouter_models.py
Normal file
188
modules/testing-framework/tests/test_openrouter_models.py
Normal file
@@ -0,0 +1,188 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
测试 OpenRouter 免费模型的八仙辩论系统
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import aiohttp
|
||||
import os
|
||||
|
||||
# --- 被测试的模型列表 (之前认为可能不太适合的) ---
|
||||
# 根据你之前的指示和 OpenRouter 网站信息,以下模型被标记为 'free'
|
||||
# 但我们将测试它们的实际表现,特别是针对辩论任务。
|
||||
# 注意: 'gpt-oss-20b' 名称可能不准确或已变更,我们使用一个常见的免费开源模型替代
|
||||
# 'Uncensored' 因安全风险不测试
|
||||
# 'Sarvam-M' 也进行测试
|
||||
MODELS_TO_TEST = [
|
||||
# "openchat/openchat-7b", # An alternative free model if needed for comparison
|
||||
"google/gemma-2-9b-it", # Google's Gemma 2 9B, free on OpenRouter
|
||||
"microsoft/phi-3-mini-128k-instruct", # Microsoft's Phi-3 Mini, free on OpenRouter
|
||||
"qwen/qwen3-coder-8b-instruct", # Qwen3 Coder 8B, free on OpenRouter (good baseline)
|
||||
"deepseek/deepseek-chat", # DeepSeek Chat, free on OpenRouter (good baseline)
|
||||
"mistralai/mistral-7b-instruct", # Mistral 7B Instruct, free on OpenRouter (good baseline)
|
||||
# --- Previously considered less suitable ---
|
||||
"openai/gpt-3.5-turbo", # Often free tier on OpenRouter
|
||||
"sophosympatheia/midnight-rose-70b", # An uncensored model, free, but we test it cautiously
|
||||
"sarvamai/sarvam-2b-m", # Sarvam 2B M, free on OpenRouter
|
||||
]
|
||||
|
||||
class OpenRouterAgent:
|
||||
"""使用 OpenRouter API 的代理"""
|
||||
|
||||
def __init__(self, name: str, personality: str, api_key: str, model: str):
|
||||
self.name = name
|
||||
self.personality = personality
|
||||
self.api_key = api_key
|
||||
self.model = model
|
||||
self.api_url = "https://openrouter.ai/api/v1"
|
||||
|
||||
async def generate_response(self, prompt: str, session: aiohttp.ClientSession) -> str:
|
||||
"""生成AI回应"""
|
||||
try:
|
||||
headers = {
|
||||
"Authorization": f"Bearer {self.api_key}",
|
||||
"HTTP-Referer": "https://github.com/bennyschmidt/liurenchaxin", # Optional, for OpenRouter analytics
|
||||
"X-Title": "BaXian Debate Test", # Optional, for OpenRouter analytics
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
|
||||
payload = {
|
||||
"model": self.model,
|
||||
"messages": [
|
||||
{"role": "system", "content": f"你是{self.name},{self.personality}。请用中文回答。"},
|
||||
{"role": "user", "content": prompt}
|
||||
],
|
||||
# Adjust these for better output in a test scenario
|
||||
"max_tokens": 500, # Reduced for quicker testing, but sufficient for short replies
|
||||
"temperature": 0.7 # Slightly lower for more deterministic replies in test
|
||||
}
|
||||
|
||||
async with session.post(
|
||||
f"{self.api_url}/chat/completions",
|
||||
headers=headers,
|
||||
json=payload,
|
||||
timeout=aiohttp.ClientTimeout(total=30)
|
||||
) as response:
|
||||
if response.status == 200:
|
||||
result = await response.json()
|
||||
content = result.get('choices', [{}])[0].get('message', {}).get('content', '')
|
||||
if content:
|
||||
return content.strip()
|
||||
else:
|
||||
error_msg = f"API returned no content for {self.name} using {self.model}. Full response: {result}"
|
||||
print(f"❌ {error_msg}")
|
||||
return f"[{self.name} 暂时无法回应]"
|
||||
else:
|
||||
error_text = await response.text()
|
||||
error_msg = f"API error ({response.status}) for {self.name} using {self.model}: {error_text[:200]}..."
|
||||
print(f"❌ {error_msg}")
|
||||
return f"[{self.name} API错误: {response.status}]"
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"Exception for {self.name} using {self.model}: {e}"
|
||||
print(f"❌ {error_msg}")
|
||||
return f"[{self.name} 连接错误]"
|
||||
|
||||
class SimpleDebateTest:
|
||||
"""简单的模型辩论测试"""
|
||||
|
||||
def __init__(self, api_key: str):
|
||||
self.api_key = api_key
|
||||
self.topic = "工作量证明vs无限制爬虫:从李时珍采药到AI数据获取的激励机制变革"
|
||||
|
||||
# Create a simple agent pair for quick testing
|
||||
self.agent1 = OpenRouterAgent(
|
||||
"吕洞宾",
|
||||
"八仙之首,男性代表,理性务实,善于分析问题的本质和长远影响。你代表男性视角,注重逻辑和实用性。",
|
||||
api_key, ""
|
||||
)
|
||||
self.agent2 = OpenRouterAgent(
|
||||
"何仙姑",
|
||||
"八仙中唯一的女性,温柔智慧,善于从情感和人文角度思考问题。你代表女性视角,注重关怀和和谐。",
|
||||
api_key, ""
|
||||
)
|
||||
|
||||
async def test_model(self, model_name: str) -> dict:
|
||||
"""测试单个模型"""
|
||||
print(f"\n--- Testing Model: {model_name} ---")
|
||||
|
||||
# Assign model to agents
|
||||
self.agent1.model = model_name
|
||||
self.agent2.model = model_name
|
||||
|
||||
results = {"model": model_name, "round1": "", "round2": "", "errors": []}
|
||||
|
||||
async with aiohttp.ClientSession() as session:
|
||||
# Round 1: Agent 1 speaks
|
||||
prompt1 = f"针对'{self.topic}'这个话题,请从你的角度阐述观点。要求:1)明确表达立场 2)提供具体论据 3)字数控制在150字以内"
|
||||
print(f"\n🗣️ {self.agent1.name} 发言:")
|
||||
try:
|
||||
reply1 = await self.agent1.generate_response(prompt1, session)
|
||||
print(f"{reply1}\n")
|
||||
results["round1"] = reply1
|
||||
except Exception as e:
|
||||
error_msg = f"Round 1 Error: {e}"
|
||||
print(f"❌ {error_msg}")
|
||||
results["errors"].append(error_msg)
|
||||
return results
|
||||
|
||||
# Round 2: Agent 2 responds
|
||||
prompt2 = f"针对'{self.topic}'这个话题,{self.agent1.name}刚才说:'{reply1}'。请从你的角度回应并阐述不同观点。要求:1)回应对方观点 2)提出自己的立场 3)字数控制在150字以内"
|
||||
print(f"🗣️ {self.agent2.name} 回应:")
|
||||
try:
|
||||
reply2 = await self.agent2.generate_response(prompt2, session)
|
||||
print(f"{reply2}\n")
|
||||
results["round2"] = reply2
|
||||
except Exception as e:
|
||||
error_msg = f"Round 2 Error: {e}"
|
||||
print(f"❌ {error_msg}")
|
||||
results["errors"].append(error_msg)
|
||||
|
||||
return results
|
||||
|
||||
async def main():
|
||||
"""主函数"""
|
||||
print("🚀 启动 OpenRouter 免费模型辩论测试...")
|
||||
|
||||
# 1. 获取 OpenRouter API 密钥
|
||||
api_key = os.getenv('OPENROUTER_API_KEY')
|
||||
if not api_key:
|
||||
print("❌ 错误: 未找到 OPENROUTER_API_KEY 环境变量")
|
||||
print("请设置环境变量: export OPENROUTER_API_KEY=your_api_key")
|
||||
return
|
||||
|
||||
tester = SimpleDebateTest(api_key)
|
||||
all_results = []
|
||||
|
||||
# 2. 依次测试每个模型
|
||||
for model_name in MODELS_TO_TEST:
|
||||
try:
|
||||
result = await tester.test_model(model_name)
|
||||
all_results.append(result)
|
||||
# Brief pause between models
|
||||
await asyncio.sleep(2)
|
||||
except Exception as e:
|
||||
print(f"❌ 测试模型 {model_name} 时发生未预期错误: {e}")
|
||||
all_results.append({"model": model_name, "round1": "", "round2": "", "errors": [f"Unexpected test error: {e}"]})
|
||||
|
||||
# 3. 输出测试总结
|
||||
print(f"\n\n--- 📊 测试总结 ---")
|
||||
for res in all_results:
|
||||
model = res['model']
|
||||
errors = res['errors']
|
||||
r1_ok = "✅" if res['round1'] and not any("无法回应" in res['round1'] or "错误" in res['round1'] for e in errors) else "❌"
|
||||
r2_ok = "✅" if res['round2'] and not any("无法回应" in res['round2'] or "错误" in res['round2'] for e in errors) else "❌"
|
||||
err_count = len(errors)
|
||||
|
||||
print(f"🔹 {model:<35} | R1: {r1_ok} | R2: {r2_ok} | Errors: {err_count}")
|
||||
|
||||
print("\n--- 📝 详细日志 ---")
|
||||
for res in all_results:
|
||||
if res['errors']:
|
||||
print(f"\n🔸 模型: {res['model']}")
|
||||
for err in res['errors']:
|
||||
print(f" - {err}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
404
modules/testing-framework/tests/test_optimized_debate_flow.py
Normal file
404
modules/testing-framework/tests/test_optimized_debate_flow.py
Normal file
@@ -0,0 +1,404 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
测试优化的辩论流程控制系统
|
||||
验证阶段转换和发言权争夺逻辑的改进
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import time
|
||||
import threading
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
# 添加项目路径
|
||||
sys.path.append('/home/ben/liurenchaxin/src')
|
||||
|
||||
from jixia.debates.optimized_debate_flow import (
|
||||
OptimizedDebateFlowController,
|
||||
FlowControlConfig,
|
||||
FlowControlMode,
|
||||
TransitionTrigger,
|
||||
SpeakerSelectionStrategy,
|
||||
DebateStage
|
||||
)
|
||||
|
||||
def test_basic_flow_control():
|
||||
"""测试基础流程控制"""
|
||||
print("🧪 测试基础流程控制")
|
||||
print("-" * 30)
|
||||
|
||||
controller = OptimizedDebateFlowController()
|
||||
|
||||
# 测试获取当前发言者
|
||||
speaker = controller.get_current_speaker()
|
||||
print(f"✅ 当前发言者: {speaker}")
|
||||
assert speaker is not None, "应该能获取到发言者"
|
||||
|
||||
# 测试记录发言
|
||||
controller.record_speech(speaker, "这是一个测试发言")
|
||||
print(f"✅ 发言记录成功,当前进度: {controller.stage_progress}")
|
||||
|
||||
# 测试流程状态
|
||||
status = controller.get_flow_status()
|
||||
print(f"✅ 流程状态: {status['current_stage']} 阶段")
|
||||
assert status['current_stage'] == '起', "应该在起阶段"
|
||||
|
||||
return True
|
||||
|
||||
def test_stage_transition():
|
||||
"""测试阶段转换"""
|
||||
print("\n🧪 测试阶段转换")
|
||||
print("-" * 30)
|
||||
|
||||
config = FlowControlConfig(
|
||||
mode=FlowControlMode.STRICT,
|
||||
transition_triggers=[TransitionTrigger.PROGRESS_BASED]
|
||||
)
|
||||
controller = OptimizedDebateFlowController(config)
|
||||
|
||||
initial_stage = controller.current_stage
|
||||
print(f"初始阶段: {initial_stage.value}")
|
||||
|
||||
# 模拟完成一个阶段的所有发言
|
||||
stage_config = controller.stage_configs[initial_stage]
|
||||
max_progress = stage_config["max_progress"]
|
||||
|
||||
for i in range(max_progress):
|
||||
speaker = controller.get_current_speaker()
|
||||
controller.record_speech(speaker, f"第{i+1}次发言")
|
||||
|
||||
if i == max_progress - 1:
|
||||
# 最后一次发言后应该自动转换阶段
|
||||
if controller._should_advance_stage():
|
||||
success = controller.advance_stage()
|
||||
print(f"✅ 阶段转换成功: {success}")
|
||||
print(f"新阶段: {controller.current_stage.value}")
|
||||
assert controller.current_stage != initial_stage, "阶段应该已经改变"
|
||||
break
|
||||
|
||||
return True
|
||||
|
||||
def test_speaker_selection_strategies():
|
||||
"""测试发言者选择策略"""
|
||||
print("\n🧪 测试发言者选择策略")
|
||||
print("-" * 30)
|
||||
|
||||
strategies = [
|
||||
SpeakerSelectionStrategy.ROUND_ROBIN,
|
||||
SpeakerSelectionStrategy.CONTEXT_AWARE,
|
||||
SpeakerSelectionStrategy.COMPETITIVE
|
||||
]
|
||||
|
||||
for strategy in strategies:
|
||||
print(f"\n测试策略: {strategy.value}")
|
||||
|
||||
config = FlowControlConfig(speaker_selection_strategy=strategy)
|
||||
controller = OptimizedDebateFlowController(config)
|
||||
|
||||
# 获取几个发言者
|
||||
speakers = []
|
||||
for i in range(3):
|
||||
speaker = controller.get_current_speaker()
|
||||
speakers.append(speaker)
|
||||
controller.record_speech(speaker, f"策略测试发言 {i+1}")
|
||||
|
||||
print(f"发言者序列: {speakers}")
|
||||
assert len(set(speakers)) > 0, f"策略 {strategy.value} 应该能选择发言者"
|
||||
|
||||
print("✅ 所有发言者选择策略测试通过")
|
||||
return True
|
||||
|
||||
def test_speaker_request_system():
|
||||
"""测试发言请求系统"""
|
||||
print("\n🧪 测试发言请求系统")
|
||||
print("-" * 30)
|
||||
|
||||
config = FlowControlConfig(
|
||||
speaker_selection_strategy=SpeakerSelectionStrategy.COMPETITIVE
|
||||
)
|
||||
controller = OptimizedDebateFlowController(config)
|
||||
|
||||
# 提交发言请求
|
||||
controller.request_speaking_turn("正1", "紧急反驳", urgency=5, topic_relevance=0.9)
|
||||
controller.request_speaking_turn("反2", "补充论据", urgency=2, topic_relevance=0.7)
|
||||
controller.request_speaking_turn("正3", "重要澄清", urgency=4, topic_relevance=0.8)
|
||||
|
||||
print(f"待处理请求数量: {len(controller.pending_requests)}")
|
||||
assert len(controller.pending_requests) == 3, "应该有3个待处理请求"
|
||||
|
||||
# 获取下一个发言者(应该是最高优先级的)
|
||||
next_speaker = controller.get_current_speaker()
|
||||
print(f"✅ 高优先级发言者: {next_speaker}")
|
||||
|
||||
# 记录发言后,请求应该被移除
|
||||
controller.record_speech(next_speaker, "响应紧急请求的发言")
|
||||
print(f"发言后待处理请求数量: {len(controller.pending_requests)}")
|
||||
|
||||
return True
|
||||
|
||||
def test_context_aware_selection():
|
||||
"""测试上下文感知选择"""
|
||||
print("\n🧪 测试上下文感知选择")
|
||||
print("-" * 30)
|
||||
|
||||
config = FlowControlConfig(
|
||||
speaker_selection_strategy=SpeakerSelectionStrategy.CONTEXT_AWARE
|
||||
)
|
||||
controller = OptimizedDebateFlowController(config)
|
||||
|
||||
# 模拟一些发言历史
|
||||
test_speeches = [
|
||||
("正1", "我支持AI投资"),
|
||||
("正1", "理由是技术发展迅速"), # 连续发言
|
||||
("反1", "但风险很高"),
|
||||
("正2", "我们有风控措施")
|
||||
]
|
||||
|
||||
for speaker, message in test_speeches:
|
||||
controller.record_speech(speaker, message)
|
||||
|
||||
# 分析当前上下文
|
||||
context = controller._analyze_current_context()
|
||||
print(f"当前上下文: {context}")
|
||||
|
||||
# 获取下一个发言者(应该避免连续发言)
|
||||
next_speaker = controller.get_current_speaker()
|
||||
print(f"✅ 上下文感知选择的发言者: {next_speaker}")
|
||||
|
||||
# 验证不是最近的发言者
|
||||
recent_speakers = [speech[0] for speech in test_speeches[-2:]]
|
||||
print(f"最近发言者: {recent_speakers}")
|
||||
|
||||
return True
|
||||
|
||||
def test_stage_metrics():
|
||||
"""测试阶段指标"""
|
||||
print("\n🧪 测试阶段指标")
|
||||
print("-" * 30)
|
||||
|
||||
controller = OptimizedDebateFlowController()
|
||||
|
||||
# 模拟一些发言
|
||||
test_speeches = [
|
||||
("吕洞宾", "AI投资是未来趋势,我们应该积极参与。数据显示这个领域的增长潜力巨大。"),
|
||||
("何仙姑", "但是我们也要考虑风险因素。"),
|
||||
("铁拐李", "我同意吕洞宾的观点,因为技术发展确实很快。"),
|
||||
("汉钟离", "然而市场波动性不容忽视。")
|
||||
]
|
||||
|
||||
for speaker, message in test_speeches:
|
||||
controller.record_speech(speaker, message)
|
||||
|
||||
# 检查阶段指标
|
||||
metrics = controller.current_stage_metrics
|
||||
print(f"发言数量: {metrics.speech_count}")
|
||||
print(f"质量分数: {metrics.quality_score:.3f}")
|
||||
print(f"参与平衡: {metrics.participation_balance:.3f}")
|
||||
print(f"转换准备度: {metrics.transition_readiness:.3f}")
|
||||
print(f"发言者分布: {metrics.speaker_distribution}")
|
||||
|
||||
assert metrics.speech_count == 4, "发言数量应该是4"
|
||||
assert 0 <= metrics.quality_score <= 1, "质量分数应该在0-1之间"
|
||||
assert 0 <= metrics.participation_balance <= 1, "参与平衡应该在0-1之间"
|
||||
|
||||
print("✅ 阶段指标计算正确")
|
||||
return True
|
||||
|
||||
def test_adaptive_mode():
|
||||
"""测试自适应模式"""
|
||||
print("\n🧪 测试自适应模式")
|
||||
print("-" * 30)
|
||||
|
||||
config = FlowControlConfig(
|
||||
mode=FlowControlMode.ADAPTIVE,
|
||||
transition_triggers=[TransitionTrigger.QUALITY_BASED, TransitionTrigger.PROGRESS_BASED],
|
||||
quality_threshold=0.7
|
||||
)
|
||||
controller = OptimizedDebateFlowController(config)
|
||||
|
||||
# 模拟高质量发言
|
||||
high_quality_speeches = [
|
||||
("吕洞宾", "根据最新的市场分析数据,AI投资领域在过去三年中显示出了显著的增长趋势。我们需要仔细分析这些数据背后的原因。"),
|
||||
("何仙姑", "虽然数据显示增长,但是我们也必须考虑到技术泡沫的可能性。历史上类似的技术热潮往往伴随着高风险。"),
|
||||
("铁拐李", "我认为关键在于风险管理。如果我们能够建立完善的风控体系,就能够在享受收益的同时控制风险。")
|
||||
]
|
||||
|
||||
for speaker, message in high_quality_speeches:
|
||||
controller.record_speech(speaker, message)
|
||||
|
||||
# 检查是否达到质量阈值
|
||||
if controller.current_stage_metrics.quality_score >= config.quality_threshold:
|
||||
print(f"✅ 达到质量阈值: {controller.current_stage_metrics.quality_score:.3f}")
|
||||
|
||||
# 检查是否应该转换阶段
|
||||
should_advance = controller._should_advance_stage()
|
||||
print(f"是否应该推进阶段: {should_advance}")
|
||||
break
|
||||
|
||||
return True
|
||||
|
||||
def test_event_system():
|
||||
"""测试事件系统"""
|
||||
print("\n🧪 测试事件系统")
|
||||
print("-" * 30)
|
||||
|
||||
controller = OptimizedDebateFlowController()
|
||||
|
||||
# 记录事件
|
||||
events_received = []
|
||||
|
||||
def event_handler(event):
|
||||
events_received.append(event.event_type)
|
||||
print(f"📢 收到事件: {event.event_type}")
|
||||
|
||||
# 注册事件处理器
|
||||
controller.add_event_handler("speech_recorded", event_handler)
|
||||
controller.add_event_handler("speaker_request", event_handler)
|
||||
|
||||
# 触发事件
|
||||
controller.record_speech("测试发言者", "测试消息")
|
||||
controller.request_speaking_turn("正1", "测试请求")
|
||||
|
||||
# 等待事件处理
|
||||
time.sleep(0.1)
|
||||
|
||||
print(f"收到的事件: {events_received}")
|
||||
assert "speech_recorded" in events_received, "应该收到发言记录事件"
|
||||
assert "speaker_request" in events_received, "应该收到发言请求事件"
|
||||
|
||||
print("✅ 事件系统工作正常")
|
||||
return True
|
||||
|
||||
def test_data_persistence():
|
||||
"""测试数据持久化"""
|
||||
print("\n🧪 测试数据持久化")
|
||||
print("-" * 30)
|
||||
|
||||
controller = OptimizedDebateFlowController()
|
||||
|
||||
# 模拟一些活动
|
||||
controller.record_speech("吕洞宾", "测试发言1")
|
||||
controller.record_speech("何仙姑", "测试发言2")
|
||||
controller.request_speaking_turn("正1", "测试请求")
|
||||
|
||||
# 保存数据
|
||||
filename = "test_flow_data.json"
|
||||
controller.save_flow_data(filename)
|
||||
|
||||
# 检查文件是否存在
|
||||
assert os.path.exists(filename), "数据文件应该被创建"
|
||||
|
||||
# 读取并验证数据
|
||||
import json
|
||||
with open(filename, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
|
||||
assert "config" in data, "数据应该包含配置信息"
|
||||
assert "current_state" in data, "数据应该包含当前状态"
|
||||
assert "debate_history" in data, "数据应该包含辩论历史"
|
||||
assert len(data["debate_history"]) == 2, "应该有2条发言记录"
|
||||
|
||||
print(f"✅ 数据持久化成功,文件大小: {os.path.getsize(filename)} 字节")
|
||||
|
||||
# 清理测试文件
|
||||
os.remove(filename)
|
||||
|
||||
return True
|
||||
|
||||
def test_performance():
|
||||
"""测试性能"""
|
||||
print("\n🧪 测试性能")
|
||||
print("-" * 30)
|
||||
|
||||
controller = OptimizedDebateFlowController()
|
||||
|
||||
# 测试发言者选择性能
|
||||
start_time = time.time()
|
||||
for i in range(100):
|
||||
speaker = controller.get_current_speaker()
|
||||
controller.record_speech(speaker, f"性能测试发言 {i}")
|
||||
|
||||
end_time = time.time()
|
||||
duration = end_time - start_time
|
||||
|
||||
print(f"100次发言处理耗时: {duration:.3f} 秒")
|
||||
print(f"平均每次处理时间: {duration/100*1000:.2f} 毫秒")
|
||||
print(f"处理速度: {100/duration:.1f} 次/秒")
|
||||
|
||||
assert duration < 5.0, "100次处理应该在5秒内完成"
|
||||
|
||||
# 测试并发性能
|
||||
def concurrent_speech_recording():
|
||||
for i in range(10):
|
||||
speaker = controller.get_current_speaker()
|
||||
controller.record_speech(speaker, f"并发测试发言 {threading.current_thread().name}-{i}")
|
||||
|
||||
start_time = time.time()
|
||||
threads = []
|
||||
for i in range(5):
|
||||
thread = threading.Thread(target=concurrent_speech_recording, name=f"Thread-{i}")
|
||||
threads.append(thread)
|
||||
thread.start()
|
||||
|
||||
for thread in threads:
|
||||
thread.join()
|
||||
|
||||
end_time = time.time()
|
||||
concurrent_duration = end_time - start_time
|
||||
|
||||
print(f"并发处理耗时: {concurrent_duration:.3f} 秒")
|
||||
print(f"总发言数: {len(controller.debate_history)}")
|
||||
|
||||
print("✅ 性能测试通过")
|
||||
return True
|
||||
|
||||
def run_comprehensive_test():
|
||||
"""运行综合测试"""
|
||||
print("🎭 优化的辩论流程控制系统 - 综合测试")
|
||||
print("=" * 60)
|
||||
|
||||
test_functions = [
|
||||
("基础流程控制", test_basic_flow_control),
|
||||
("阶段转换", test_stage_transition),
|
||||
("发言者选择策略", test_speaker_selection_strategies),
|
||||
("发言请求系统", test_speaker_request_system),
|
||||
("上下文感知选择", test_context_aware_selection),
|
||||
("阶段指标", test_stage_metrics),
|
||||
("自适应模式", test_adaptive_mode),
|
||||
("事件系统", test_event_system),
|
||||
("数据持久化", test_data_persistence),
|
||||
("性能测试", test_performance)
|
||||
]
|
||||
|
||||
passed = 0
|
||||
failed = 0
|
||||
|
||||
for test_name, test_func in test_functions:
|
||||
try:
|
||||
print(f"\n{'='*20} {test_name} {'='*20}")
|
||||
result = test_func()
|
||||
if result:
|
||||
print(f"✅ {test_name} - 通过")
|
||||
passed += 1
|
||||
else:
|
||||
print(f"❌ {test_name} - 失败")
|
||||
failed += 1
|
||||
except Exception as e:
|
||||
print(f"❌ {test_name} - 错误: {str(e)}")
|
||||
failed += 1
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print(f"📊 测试结果统计")
|
||||
print(f"通过: {passed}/{len(test_functions)} ({passed/len(test_functions)*100:.1f}%)")
|
||||
print(f"失败: {failed}/{len(test_functions)} ({failed/len(test_functions)*100:.1f}%)")
|
||||
|
||||
if failed == 0:
|
||||
print("🎉 所有测试通过!优化的辩论流程控制系统运行正常。")
|
||||
else:
|
||||
print(f"⚠️ 有 {failed} 个测试失败,需要进一步优化。")
|
||||
|
||||
return passed, failed
|
||||
|
||||
if __name__ == "__main__":
|
||||
run_comprehensive_test()
|
||||
83
modules/testing-framework/tests/test_simple_api.py
Normal file
83
modules/testing-framework/tests/test_simple_api.py
Normal file
@@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
简单的API测试脚本
|
||||
测试.env.example中的配置是否正确
|
||||
"""
|
||||
|
||||
import requests
|
||||
import json
|
||||
import logging
|
||||
|
||||
# 配置日志
|
||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def test_simple_api():
|
||||
"""简单的API测试"""
|
||||
|
||||
# 从.env.example读取的配置
|
||||
BASE_URL = "http://master.tailnet-68f9.ts.net:40012"
|
||||
API_KEY = "sk-0jdcGHZJpX2oUJmyEs7zVA"
|
||||
MODEL = "gemini/gemini-2.5-pro"
|
||||
|
||||
logger.info(f"🧪 测试配置:")
|
||||
logger.info(f"📡 BASE_URL: {BASE_URL}")
|
||||
logger.info(f"🔑 API_KEY: {API_KEY[:10]}...")
|
||||
logger.info(f"🤖 MODEL: {MODEL}")
|
||||
|
||||
# 最简单的请求
|
||||
payload = {
|
||||
"model": MODEL,
|
||||
"messages": [
|
||||
{"role": "user", "content": "Hello"}
|
||||
],
|
||||
"max_tokens": 50
|
||||
}
|
||||
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": f"Bearer {API_KEY}"
|
||||
}
|
||||
|
||||
try:
|
||||
logger.info("🚀 发送请求...")
|
||||
response = requests.post(
|
||||
f"{BASE_URL}/chat/completions",
|
||||
json=payload,
|
||||
headers=headers,
|
||||
timeout=120 # 增加超时时间
|
||||
)
|
||||
|
||||
logger.info(f"📊 状态码: {response.status_code}")
|
||||
|
||||
if response.status_code == 200:
|
||||
result = response.json()
|
||||
logger.info(f"✅ 请求成功!")
|
||||
logger.info(f"📋 响应: {json.dumps(result, ensure_ascii=False, indent=2)}")
|
||||
return True
|
||||
else:
|
||||
logger.error(f"❌ 请求失败: {response.status_code}")
|
||||
logger.error(f"📋 错误响应: {response.text}")
|
||||
return False
|
||||
|
||||
except requests.exceptions.Timeout:
|
||||
logger.error(f"⏰ 请求超时 (120秒)")
|
||||
return False
|
||||
except requests.exceptions.ConnectionError as e:
|
||||
logger.error(f"🔌 连接错误: {e}")
|
||||
return False
|
||||
except Exception as e:
|
||||
logger.error(f"💥 未知错误: {e}")
|
||||
return False
|
||||
|
||||
if __name__ == "__main__":
|
||||
logger.info("🎯 开始简单API测试")
|
||||
success = test_simple_api()
|
||||
|
||||
if success:
|
||||
logger.info("🎉 测试成功!")
|
||||
else:
|
||||
logger.error("💀 测试失败!")
|
||||
|
||||
logger.info("🏁 测试完成")
|
||||
80
modules/testing-framework/tests/test_single_model.py
Normal file
80
modules/testing-framework/tests/test_single_model.py
Normal file
@@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Test script for a single model from OpenRouter
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import aiohttp
|
||||
import os
|
||||
import json
|
||||
|
||||
# Get API key from environment or .env file
|
||||
api_key = os.getenv('OPENROUTER_API_KEY')
|
||||
if not api_key:
|
||||
with open(".env", "r") as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if line.startswith("sk-or-v1-"):
|
||||
api_key = line
|
||||
break
|
||||
|
||||
if not api_key:
|
||||
print("❌ No API key found")
|
||||
exit(1)
|
||||
|
||||
async def test_model(model_name):
|
||||
"""Test a single model"""
|
||||
# Remove :free tag for API call
|
||||
clean_model = model_name.split(":")[0]
|
||||
|
||||
print(f"🚀 Testing model: {model_name}")
|
||||
print(f" Clean name: {clean_model}")
|
||||
|
||||
url = "https://openrouter.ai/api/v1/chat/completions"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {api_key}",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
payload = {
|
||||
"model": clean_model,
|
||||
"messages": [
|
||||
{"role": "user", "content": "Explain the concept of 'working hard' in one short sentence."}
|
||||
],
|
||||
"max_tokens": 100
|
||||
}
|
||||
|
||||
print(f" Payload: {json.dumps(payload, indent=2)}")
|
||||
|
||||
try:
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.post(url, headers=headers, json=payload, timeout=30) as response:
|
||||
print(f" Status: {response.status}")
|
||||
|
||||
# Print response headers
|
||||
print(" Response Headers:")
|
||||
for key, value in response.headers.items():
|
||||
print(f" {key}: {value}")
|
||||
|
||||
if response.status == 200:
|
||||
result = await response.json()
|
||||
print(f" Full response: {json.dumps(result, indent=2)}")
|
||||
|
||||
content = result.get('choices', [{}])[0].get('message', {}).get('content', '')
|
||||
print(f"✅ Success - Content: '{content}'")
|
||||
return True
|
||||
else:
|
||||
error_text = await response.text()
|
||||
print(f"❌ Status {response.status}: {error_text}")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"💥 Exception: {str(e)}")
|
||||
return False
|
||||
|
||||
async def main():
|
||||
"""Main function"""
|
||||
model_to_test = "openai/gpt-oss-20b:free"
|
||||
await test_model(model_to_test)
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
80
modules/testing-framework/tests/test_single_model2.py
Normal file
80
modules/testing-framework/tests/test_single_model2.py
Normal file
@@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Test script for a single model from OpenRouter
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import aiohttp
|
||||
import os
|
||||
import json
|
||||
|
||||
# Get API key from environment or .env file
|
||||
api_key = os.getenv('OPENROUTER_API_KEY')
|
||||
if not api_key:
|
||||
with open(".env", "r") as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if line.startswith("sk-or-v1-"):
|
||||
api_key = line
|
||||
break
|
||||
|
||||
if not api_key:
|
||||
print("❌ No API key found")
|
||||
exit(1)
|
||||
|
||||
async def test_model(model_name):
|
||||
"""Test a single model"""
|
||||
# Remove :free tag for API call
|
||||
clean_model = model_name.split(":")[0]
|
||||
|
||||
print(f"🚀 Testing model: {model_name}")
|
||||
print(f" Clean name: {clean_model}")
|
||||
|
||||
url = "https://openrouter.ai/api/v1/chat/completions"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {api_key}",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
payload = {
|
||||
"model": clean_model,
|
||||
"messages": [
|
||||
{"role": "user", "content": "Explain the concept of 'working hard' in one short sentence."}
|
||||
],
|
||||
"max_tokens": 100
|
||||
}
|
||||
|
||||
print(f" Payload: {json.dumps(payload, indent=2)}")
|
||||
|
||||
try:
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.post(url, headers=headers, json=payload, timeout=30) as response:
|
||||
print(f" Status: {response.status}")
|
||||
|
||||
# Print response headers
|
||||
print(" Response Headers:")
|
||||
for key, value in response.headers.items():
|
||||
print(f" {key}: {value}")
|
||||
|
||||
if response.status == 200:
|
||||
result = await response.json()
|
||||
print(f" Full response: {json.dumps(result, indent=2)}")
|
||||
|
||||
content = result.get('choices', [{}])[0].get('message', {}).get('content', '')
|
||||
print(f"✅ Success - Content: '{content}'")
|
||||
return True
|
||||
else:
|
||||
error_text = await response.text()
|
||||
print(f"❌ Status {response.status}: {error_text}")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"💥 Exception: {str(e)}")
|
||||
return False
|
||||
|
||||
async def main():
|
||||
"""Main function"""
|
||||
model_to_test = "qwen/qwq-32b:free"
|
||||
await test_model(model_to_test)
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
80
modules/testing-framework/tests/test_single_model3.py
Normal file
80
modules/testing-framework/tests/test_single_model3.py
Normal file
@@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Test script for a single model from OpenRouter
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import aiohttp
|
||||
import os
|
||||
import json
|
||||
|
||||
# Get API key from environment or .env file
|
||||
api_key = os.getenv('OPENROUTER_API_KEY')
|
||||
if not api_key:
|
||||
with open(".env", "r") as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if line.startswith("sk-or-v1-"):
|
||||
api_key = line
|
||||
break
|
||||
|
||||
if not api_key:
|
||||
print("❌ No API key found")
|
||||
exit(1)
|
||||
|
||||
async def test_model(model_name):
|
||||
"""Test a single model"""
|
||||
# Remove :free tag for API call
|
||||
clean_model = model_name.split(":")[0]
|
||||
|
||||
print(f"🚀 Testing model: {model_name}")
|
||||
print(f" Clean name: {clean_model}")
|
||||
|
||||
url = "https://openrouter.ai/api/v1/chat/completions"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {api_key}",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
payload = {
|
||||
"model": clean_model,
|
||||
"messages": [
|
||||
{"role": "user", "content": "Explain the concept of 'working hard' in one short sentence."}
|
||||
],
|
||||
"max_tokens": 100
|
||||
}
|
||||
|
||||
print(f" Payload: {json.dumps(payload, indent=2)}")
|
||||
|
||||
try:
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.post(url, headers=headers, json=payload, timeout=30) as response:
|
||||
print(f" Status: {response.status}")
|
||||
|
||||
# Print response headers
|
||||
print(" Response Headers:")
|
||||
for key, value in response.headers.items():
|
||||
print(f" {key}: {value}")
|
||||
|
||||
if response.status == 200:
|
||||
result = await response.json()
|
||||
print(f" Full response: {json.dumps(result, indent=2)}")
|
||||
|
||||
content = result.get('choices', [{}])[0].get('message', {}).get('content', '')
|
||||
print(f"✅ Success - Content: '{content}'")
|
||||
return True
|
||||
else:
|
||||
error_text = await response.text()
|
||||
print(f"❌ Status {response.status}: {error_text}")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"💥 Exception: {str(e)}")
|
||||
return False
|
||||
|
||||
async def main():
|
||||
"""Main function"""
|
||||
model_to_test = "mistralai/mistral-small-3.1-24b-instruct:free"
|
||||
await test_model(model_to_test)
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
84
modules/testing-framework/tests/test_taishang_api.py
Normal file
84
modules/testing-framework/tests/test_taishang_api.py
Normal file
@@ -0,0 +1,84 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Test script for the Taishang Laojun API (Zhipu AI GLM-4.5)
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import aiohttp
|
||||
import json
|
||||
|
||||
async def test_taishang_api():
|
||||
"""Test the Taishang Laojun API"""
|
||||
# Zhipu AI API configuration
|
||||
zhipu_api_key = "cc95756306b2cb9748c8df15f9063eaf.hlvXbZeoLnPhyoLw"
|
||||
url = "https://open.bigmodel.cn/api/paas/v4/chat/completions"
|
||||
|
||||
messages = [
|
||||
{"role": "system", "content": "You are Taishang Laojun, a wise philosopher and project manager for the Ba Xian (Eight Immortals). You excel at deep analysis and strategic planning. Please respond in JSON format."},
|
||||
{"role": "user", "content": "Analyze the concept of 'working hard' and provide a JSON response with two keys: 'definition' and 'importance'."}
|
||||
]
|
||||
|
||||
data = {
|
||||
"model": "glm-4.5-air",
|
||||
"messages": messages,
|
||||
"max_tokens": 500,
|
||||
"temperature": 0.7,
|
||||
"stream": False,
|
||||
"tools": [],
|
||||
"tool_choice": "none"
|
||||
}
|
||||
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": f"Bearer {zhipu_api_key}"
|
||||
}
|
||||
|
||||
print("🚀 Testing Taishang Laojun API (Zhipu AI GLM-4.5)...")
|
||||
print(f" URL: {url}")
|
||||
print(f" Model: {data['model']}")
|
||||
print(f" Messages: {json.dumps(messages, ensure_ascii=False, indent=2)}")
|
||||
print(f" Data: {json.dumps(data, ensure_ascii=False, indent=2)}")
|
||||
|
||||
try:
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.post(url, headers=headers, json=data, timeout=30) as response:
|
||||
print(f" Status: {response.status}")
|
||||
|
||||
if response.status == 200:
|
||||
result = await response.json()
|
||||
print(f" Full response: {json.dumps(result, ensure_ascii=False, indent=2)}")
|
||||
|
||||
# Extract content
|
||||
if 'choices' in result and len(result['choices']) > 0:
|
||||
choice = result['choices'][0]
|
||||
content = ""
|
||||
|
||||
# Try to get content from different fields
|
||||
if 'message' in choice and 'content' in choice['message']:
|
||||
content = choice['message']['content']
|
||||
|
||||
# If content is empty, try reasoning_content
|
||||
if not content and 'message' in choice and 'reasoning_content' in choice['message']:
|
||||
content = choice['message']['reasoning_content']
|
||||
|
||||
if content:
|
||||
print(f"✅ Success - Content: {content[:200]}...") # Truncate for readability
|
||||
return True
|
||||
|
||||
print("❌ Content not found in response")
|
||||
return False
|
||||
else:
|
||||
error_text = await response.text()
|
||||
print(f"❌ Status {response.status}: {error_text}")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"💥 Exception: {str(e)}")
|
||||
return False
|
||||
|
||||
async def main():
|
||||
"""Main function"""
|
||||
await test_taishang_api()
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
745
modules/testing-framework/tests/test_v2_1_comprehensive.py
Normal file
745
modules/testing-framework/tests/test_v2_1_comprehensive.py
Normal file
@@ -0,0 +1,745 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
集夏v2.1.0 综合功能测试
|
||||
验证所有新功能的集成效果和系统稳定性
|
||||
"""
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
import time
|
||||
import threading
|
||||
import json
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
# 添加项目路径
|
||||
sys.path.append('/home/ben/liurenchaxin/src')
|
||||
|
||||
# 导入所有核心模块
|
||||
try:
|
||||
from jixia.debates.enhanced_priority_algorithm import EnhancedPriorityAlgorithm
|
||||
from jixia.debates.optimized_debate_flow import OptimizedDebateFlowController, FlowControlMode
|
||||
from jixia.intervention.human_intervention_system import DebateHealthMonitor
|
||||
from jixia.coordination.multi_chat_coordinator import MultiChatCoordinator
|
||||
except ImportError as e:
|
||||
print(f"❌ 模块导入失败: {e}")
|
||||
print("请确保所有模块都已正确安装")
|
||||
sys.exit(1)
|
||||
|
||||
class V2_1_IntegrationTester:
|
||||
"""v2.1.0 集成测试器"""
|
||||
|
||||
def __init__(self):
|
||||
self.test_results = {}
|
||||
self.performance_metrics = {}
|
||||
self.error_log = []
|
||||
|
||||
# 初始化各个组件
|
||||
try:
|
||||
self.priority_algorithm = EnhancedPriorityAlgorithm()
|
||||
self.flow_controller = OptimizedDebateFlowController()
|
||||
self.health_monitor = DebateHealthMonitor()
|
||||
self.chat_coordinator = MultiChatCoordinator()
|
||||
print("✅ 所有核心组件初始化成功")
|
||||
except Exception as e:
|
||||
print(f"❌ 组件初始化失败: {e}")
|
||||
self.error_log.append(f"初始化错误: {e}")
|
||||
|
||||
def test_priority_algorithm_integration(self):
|
||||
"""测试优先级算法集成"""
|
||||
print("\n🧪 测试优先级算法集成")
|
||||
print("-" * 40)
|
||||
|
||||
try:
|
||||
# 模拟辩论场景
|
||||
test_speeches = [
|
||||
{
|
||||
"speaker": "吕洞宾",
|
||||
"content": "根据最新的市场数据分析,AI投资领域显示出强劲的增长潜力。我们应该抓住这个机会。",
|
||||
"context": {"stage": "起", "topic": "AI投资", "recent_speakers": []}
|
||||
},
|
||||
{
|
||||
"speaker": "何仙姑",
|
||||
"content": "但是我们必须谨慎考虑风险因素!市场波动性很大。",
|
||||
"context": {"stage": "承", "topic": "AI投资", "recent_speakers": ["吕洞宾"]}
|
||||
},
|
||||
{
|
||||
"speaker": "铁拐李",
|
||||
"content": "我同意吕洞宾的观点,技术发展确实迅速,但何仙姑提到的风险也值得重视。",
|
||||
"context": {"stage": "转", "topic": "AI投资", "recent_speakers": ["吕洞宾", "何仙姑"]}
|
||||
}
|
||||
]
|
||||
|
||||
priorities = []
|
||||
for speech in test_speeches:
|
||||
analysis = self.priority_algorithm.analyze_speech(
|
||||
speech["content"],
|
||||
speech["speaker"],
|
||||
speech["context"]
|
||||
)
|
||||
|
||||
# 获取详细的分数分解
|
||||
speaker = speech["speaker"]
|
||||
context = speech["context"]
|
||||
recent_speeches = test_speeches[:test_speeches.index(speech)]
|
||||
|
||||
profile = self.priority_algorithm._get_or_create_speaker_profile(speaker)
|
||||
self.priority_algorithm._update_speaker_profile(profile, recent_speeches)
|
||||
|
||||
rebuttal_urgency = self.priority_algorithm._calculate_rebuttal_urgency(speaker, context, recent_speeches)
|
||||
argument_strength = self.priority_algorithm._calculate_argument_strength(speaker, profile)
|
||||
time_pressure = self.priority_algorithm._calculate_time_pressure(speaker, context)
|
||||
audience_reaction = self.priority_algorithm._calculate_audience_reaction(speaker, context)
|
||||
strategy_need = self.priority_algorithm._calculate_strategy_need(speaker, context, profile)
|
||||
|
||||
priority = self.priority_algorithm.calculate_priority(
|
||||
speaker,
|
||||
context,
|
||||
recent_speeches
|
||||
)
|
||||
priorities.append((speaker, priority))
|
||||
|
||||
print(f"发言者: {speaker}")
|
||||
print(f" 反驳紧急性: {rebuttal_urgency:.6f}")
|
||||
print(f" 论证强度: {argument_strength:.6f}")
|
||||
print(f" 时间压力: {time_pressure:.6f}")
|
||||
print(f" 观众反应: {audience_reaction:.6f}")
|
||||
print(f" 策略需求: {strategy_need:.6f}")
|
||||
print(f" 最终优先级: {priority:.6f}")
|
||||
print()
|
||||
|
||||
# 调试输出
|
||||
print(f"所有优先级值: {[p[1] for p in priorities]}")
|
||||
print(f"唯一优先级数量: {len(set(p[1] for p in priorities))}")
|
||||
print(f"优先级差异: {max(p[1] for p in priorities) - min(p[1] for p in priorities)}")
|
||||
|
||||
# 验证优先级计算
|
||||
assert all(0 <= p[1] <= 1 for p in priorities), "优先级应该在0-1之间"
|
||||
assert len(set(p[1] for p in priorities)) > 1, "不同发言应该有不同优先级"
|
||||
|
||||
self.test_results["priority_algorithm_integration"] = True
|
||||
print("✅ 优先级算法集成测试通过")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ 优先级算法集成测试失败: {e}")
|
||||
self.error_log.append(f"优先级算法集成错误: {e}")
|
||||
self.test_results["priority_algorithm_integration"] = False
|
||||
return False
|
||||
|
||||
def test_flow_controller_integration(self):
|
||||
"""测试流程控制器集成"""
|
||||
print("\n🧪 测试流程控制器集成")
|
||||
print("-" * 40)
|
||||
|
||||
try:
|
||||
# 测试与优先级算法的集成
|
||||
initial_stage = self.flow_controller.current_stage
|
||||
print(f"初始阶段: {initial_stage.value}")
|
||||
|
||||
# 模拟完整的辩论流程
|
||||
test_sequence = [
|
||||
("吕洞宾", "开场陈述:AI投资是未来发展的关键"),
|
||||
("何仙姑", "反方观点:需要谨慎评估风险"),
|
||||
("铁拐李", "补充论据:技术发展支持投资决策"),
|
||||
("汉钟离", "风险分析:市场不确定性因素"),
|
||||
("曹国舅", "综合观点:平衡收益与风险"),
|
||||
("蓝采和", "实践经验:类似投资案例分析"),
|
||||
("韩湘子", "未来展望:长期发展趋势"),
|
||||
("张果老", "总结陈词:理性投资建议")
|
||||
]
|
||||
|
||||
stage_transitions = 0
|
||||
for speaker, content in test_sequence:
|
||||
# 记录发言
|
||||
self.flow_controller.record_speech(speaker, content)
|
||||
|
||||
# 检查是否需要推进阶段
|
||||
if hasattr(self.flow_controller, '_should_advance_stage') and self.flow_controller._should_advance_stage():
|
||||
old_stage = self.flow_controller.current_stage
|
||||
if self.flow_controller.advance_stage():
|
||||
stage_transitions += 1
|
||||
print(f"阶段转换: {old_stage.value} -> {self.flow_controller.current_stage.value}")
|
||||
|
||||
# 获取流程状态
|
||||
status = self.flow_controller.get_flow_status()
|
||||
print(f"发言者: {speaker}, 当前阶段: {status['current_stage']}, 进度: {status['stage_progress']}")
|
||||
|
||||
# 验证流程控制
|
||||
final_status = self.flow_controller.get_flow_status()
|
||||
total_speeches = len(self.flow_controller.debate_history)
|
||||
assert total_speeches == len(test_sequence), f"发言总数应该匹配,期望{len(test_sequence)},实际{total_speeches}"
|
||||
assert stage_transitions > 0, "应该发生阶段转换"
|
||||
|
||||
self.test_results["flow_controller_integration"] = True
|
||||
print(f"✅ 流程控制器集成测试通过,发生了 {stage_transitions} 次阶段转换")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ 流程控制器集成测试失败: {e}")
|
||||
self.error_log.append(f"流程控制器集成错误: {e}")
|
||||
self.test_results["flow_controller_integration"] = False
|
||||
return False
|
||||
|
||||
def test_health_monitor_integration(self):
|
||||
"""测试健康监控集成"""
|
||||
print("\n🧪 测试健康监控集成")
|
||||
print("-" * 40)
|
||||
|
||||
try:
|
||||
# 模拟辩论数据
|
||||
debate_data = {
|
||||
"participants": ["吕洞宾", "何仙姑", "铁拐李", "汉钟离"],
|
||||
"speeches": [
|
||||
{"speaker": "吕洞宾", "content": "我强烈支持这个提案", "timestamp": datetime.now()},
|
||||
{"speaker": "何仙姑", "content": "我完全反对,这太危险了", "timestamp": datetime.now()},
|
||||
{"speaker": "铁拐李", "content": "让我们理性分析一下", "timestamp": datetime.now()},
|
||||
{"speaker": "汉钟离", "content": "数据显示情况复杂", "timestamp": datetime.now()}
|
||||
],
|
||||
"current_stage": "承",
|
||||
"duration": timedelta(minutes=15)
|
||||
}
|
||||
|
||||
# 更新健康监控
|
||||
self.health_monitor.update_metrics(debate_data)
|
||||
|
||||
# 检查健康状态
|
||||
health_status = self.health_monitor.get_health_status()
|
||||
health_report = self.health_monitor.get_health_report()
|
||||
print(f"健康状态: {health_status.value}")
|
||||
print(f"整体分数: {health_report['overall_score']:.1f}")
|
||||
print(f"监控指标数量: {len(health_report['metrics'])}")
|
||||
print(f"活跃警报: {health_report['active_alerts']}个")
|
||||
|
||||
# 模拟问题场景
|
||||
problematic_data = {
|
||||
"participants": ["吕洞宾", "何仙姑"],
|
||||
"speeches": [
|
||||
{"speaker": "吕洞宾", "content": "你们都是白痴!", "timestamp": datetime.now()},
|
||||
{"speaker": "吕洞宾", "content": "我说了算!", "timestamp": datetime.now()},
|
||||
{"speaker": "吕洞宾", "content": "闭嘴!", "timestamp": datetime.now()}
|
||||
],
|
||||
"current_stage": "转",
|
||||
"duration": timedelta(minutes=30)
|
||||
}
|
||||
|
||||
self.health_monitor.update_metrics(problematic_data)
|
||||
|
||||
# 检查是否触发警报
|
||||
alerts = self.health_monitor.active_alerts
|
||||
print(f"活跃警报数量: {len(alerts)}")
|
||||
|
||||
# 验证监控功能
|
||||
assert health_status is not None, "应该有健康状态"
|
||||
assert isinstance(health_status, type(health_status)), "健康状态应该是HealthStatus枚举"
|
||||
|
||||
self.test_results["health_monitor_integration"] = True
|
||||
print("✅ 健康监控集成测试通过")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ 健康监控集成测试失败: {e}")
|
||||
self.error_log.append(f"健康监控集成错误: {e}")
|
||||
self.test_results["health_monitor_integration"] = False
|
||||
return False
|
||||
|
||||
async def test_chat_coordinator_integration(self):
|
||||
"""测试多群聊协调集成"""
|
||||
print("\n🧪 测试多群聊协调集成")
|
||||
print("-" * 40)
|
||||
|
||||
try:
|
||||
# 模拟多群聊场景
|
||||
main_chat_message = {
|
||||
"chat_id": "main_debate",
|
||||
"speaker": "吕洞宾",
|
||||
"content": "我认为我们应该投资AI技术",
|
||||
"timestamp": datetime.now()
|
||||
}
|
||||
|
||||
# 处理主群聊消息
|
||||
await self.chat_coordinator.handle_message(main_chat_message)
|
||||
|
||||
# 模拟策略讨论
|
||||
strategy_message = {
|
||||
"chat_id": "strategy_positive",
|
||||
"speaker": "铁拐李",
|
||||
"content": "我们需要准备更多技术数据来支持论点",
|
||||
"timestamp": datetime.now()
|
||||
}
|
||||
|
||||
await self.chat_coordinator.handle_message(strategy_message)
|
||||
|
||||
# 检查消息路由
|
||||
routing_status = self.chat_coordinator.get_routing_status()
|
||||
print(f"路由状态: {routing_status}")
|
||||
|
||||
# 模拟协调决策
|
||||
coordination_result = await self.chat_coordinator.coordinate_response(
|
||||
main_chat_message,
|
||||
context={"stage": "承", "topic": "AI投资"}
|
||||
)
|
||||
|
||||
print(f"协调结果: {coordination_result}")
|
||||
|
||||
# 验证协调功能
|
||||
assert coordination_result is not None, "应该有协调结果"
|
||||
|
||||
self.test_results["chat_coordinator_integration"] = True
|
||||
print("✅ 多群聊协调集成测试通过")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ 多群聊协调集成测试失败: {e}")
|
||||
self.error_log.append(f"多群聊协调集成错误: {e}")
|
||||
self.test_results["chat_coordinator_integration"] = False
|
||||
return False
|
||||
|
||||
async def test_cross_component_integration(self):
|
||||
"""测试跨组件集成"""
|
||||
print("\n🧪 测试跨组件集成")
|
||||
print("-" * 40)
|
||||
|
||||
try:
|
||||
# 清空之前的发言历史
|
||||
self.flow_controller.debate_history.clear()
|
||||
|
||||
# 模拟完整的辩论流程
|
||||
debate_scenario = {
|
||||
"topic": "人工智能投资策略",
|
||||
"participants": ["吕洞宾", "何仙姑", "铁拐李", "汉钟离"],
|
||||
"duration": 30 # 分钟
|
||||
}
|
||||
|
||||
print(f"开始辩论: {debate_scenario['topic']}")
|
||||
|
||||
# 1. 流程控制器管理发言顺序
|
||||
speakers_sequence = []
|
||||
for i in range(8): # 模拟8轮发言
|
||||
speaker = self.flow_controller.get_current_speaker()
|
||||
speakers_sequence.append(speaker)
|
||||
|
||||
# 2. 生成发言内容(简化)
|
||||
content = f"这是{speaker}在第{i+1}轮的发言,关于{debate_scenario['topic']}"
|
||||
|
||||
# 3. 优先级算法分析发言
|
||||
context = {
|
||||
"stage": self.flow_controller.current_stage.value,
|
||||
"topic": debate_scenario['topic'],
|
||||
"recent_speakers": speakers_sequence[-3:]
|
||||
}
|
||||
|
||||
analysis = self.priority_algorithm.analyze_speech(content, speaker, context)
|
||||
|
||||
# 构建正确格式的recent_speeches
|
||||
recent_speeches = []
|
||||
for j, prev_speaker in enumerate(speakers_sequence):
|
||||
recent_speeches.append({
|
||||
"speaker": prev_speaker,
|
||||
"content": f"这是{prev_speaker}在第{j+1}轮的发言",
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
"team": "positive" if "正" in prev_speaker else "negative"
|
||||
})
|
||||
|
||||
priority = self.priority_algorithm.calculate_priority(speaker, context, recent_speeches)
|
||||
|
||||
# 4. 记录发言到流程控制器
|
||||
self.flow_controller.record_speech(speaker, content)
|
||||
|
||||
# 5. 更新健康监控
|
||||
debate_data = {
|
||||
"participants": debate_scenario['participants'],
|
||||
"speeches": [{"speaker": speaker, "content": content, "timestamp": datetime.now()}],
|
||||
"current_stage": self.flow_controller.current_stage.value,
|
||||
"duration": timedelta(minutes=i*2)
|
||||
}
|
||||
self.health_monitor.update_metrics(debate_data)
|
||||
|
||||
# 6. 多群聊协调处理
|
||||
message = {
|
||||
"chat_id": "main_debate",
|
||||
"speaker": speaker,
|
||||
"content": content,
|
||||
"timestamp": datetime.now()
|
||||
}
|
||||
# 异步调用
|
||||
try:
|
||||
await self.chat_coordinator.handle_message(message)
|
||||
except Exception as e:
|
||||
print(f"警告: 消息处理失败: {e}")
|
||||
|
||||
print(f"第{i+1}轮 - 发言者: {speaker}, 优先级: {priority:.3f}, 阶段: {context['stage']}")
|
||||
|
||||
# 验证集成效果
|
||||
print("\n开始获取各组件状态...")
|
||||
|
||||
try:
|
||||
flow_status = self.flow_controller.get_flow_status()
|
||||
print(f"✅ 流程状态获取成功: {type(flow_status)}")
|
||||
except Exception as e:
|
||||
print(f"❌ 流程状态获取失败: {e}")
|
||||
raise
|
||||
|
||||
try:
|
||||
health_status = self.health_monitor.get_health_status()
|
||||
print(f"✅ 健康状态获取成功: {type(health_status)}")
|
||||
except Exception as e:
|
||||
print(f"❌ 健康状态获取失败: {e}")
|
||||
raise
|
||||
|
||||
try:
|
||||
routing_status = self.chat_coordinator.get_routing_status()
|
||||
print(f"✅ 路由状态获取成功: {type(routing_status)}, 值: {routing_status}")
|
||||
except Exception as e:
|
||||
print(f"❌ 路由状态获取失败: {e}")
|
||||
raise
|
||||
|
||||
print(f"\n集成测试结果:")
|
||||
print(f"- 总发言数: {len(self.flow_controller.debate_history)}")
|
||||
print(f"- 当前阶段: {flow_status['current_stage']}")
|
||||
print(f"- 健康状态: {health_status.value}")
|
||||
|
||||
# 安全地访问routing_status
|
||||
if isinstance(routing_status, dict):
|
||||
print(f"- 活跃路由数: {routing_status.get('active_routes', 0)}")
|
||||
print(f"- 消息队列大小: {routing_status.get('message_queue_size', 0)}")
|
||||
print(f"- 总群聊数: {routing_status.get('total_rooms', 0)}")
|
||||
else:
|
||||
print(f"- 路由状态: {routing_status}")
|
||||
print(f"- 路由状态类型: {type(routing_status)}")
|
||||
|
||||
# 验证所有组件都正常工作
|
||||
total_speeches = len(self.flow_controller.debate_history)
|
||||
assert total_speeches == 8, f"应该记录8次发言,实际{total_speeches}次"
|
||||
assert health_status is not None, "应该有健康状态"
|
||||
assert len(speakers_sequence) == 8, "应该有8个发言者记录"
|
||||
|
||||
self.test_results["cross_component_integration"] = True
|
||||
print("✅ 跨组件集成测试通过")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
import traceback
|
||||
print(f"❌ 跨组件集成测试失败: {e}")
|
||||
print(f"详细错误信息:")
|
||||
traceback.print_exc()
|
||||
self.error_log.append(f"跨组件集成错误: {e}")
|
||||
self.test_results["cross_component_integration"] = False
|
||||
return False
|
||||
|
||||
def test_performance_under_load(self):
|
||||
"""测试负载下的性能"""
|
||||
print("\n🧪 测试负载下的性能")
|
||||
print("-" * 40)
|
||||
|
||||
try:
|
||||
# 性能测试参数
|
||||
num_speeches = 100
|
||||
num_threads = 5
|
||||
|
||||
def simulate_debate_load():
|
||||
"""模拟辩论负载"""
|
||||
thread_name = threading.current_thread().name
|
||||
for i in range(num_speeches // num_threads):
|
||||
try:
|
||||
# 模拟发言处理
|
||||
speaker = f"Speaker-{thread_name}-{i}"
|
||||
content = f"这是来自{speaker}的测试发言 {i}"
|
||||
|
||||
# 优先级计算
|
||||
context = {"stage": "承", "topic": "性能测试", "recent_speakers": []}
|
||||
analysis = self.priority_algorithm.analyze_speech(content, speaker, context)
|
||||
priority = self.priority_algorithm.calculate_priority(speaker, context, [])
|
||||
|
||||
# 流程记录
|
||||
self.flow_controller.record_speech(speaker, content)
|
||||
|
||||
# 健康监控
|
||||
debate_data = {
|
||||
"participants": [speaker],
|
||||
"speeches": [{"speaker": speaker, "content": content, "timestamp": datetime.now()}],
|
||||
"current_stage": "承",
|
||||
"duration": timedelta(seconds=i)
|
||||
}
|
||||
self.health_monitor.update_metrics(debate_data)
|
||||
|
||||
except Exception as e:
|
||||
self.error_log.append(f"负载测试错误 {thread_name}-{i}: {e}")
|
||||
|
||||
# 开始性能测试
|
||||
start_time = time.time()
|
||||
|
||||
threads = []
|
||||
for i in range(num_threads):
|
||||
thread = threading.Thread(target=simulate_debate_load, name=f"LoadTest-{i}")
|
||||
threads.append(thread)
|
||||
thread.start()
|
||||
|
||||
for thread in threads:
|
||||
thread.join()
|
||||
|
||||
end_time = time.time()
|
||||
duration = end_time - start_time
|
||||
|
||||
# 计算性能指标
|
||||
total_operations = num_speeches * 4 # 每次发言包含4个操作
|
||||
ops_per_second = total_operations / duration
|
||||
|
||||
self.performance_metrics = {
|
||||
"total_operations": total_operations,
|
||||
"duration": duration,
|
||||
"ops_per_second": ops_per_second,
|
||||
"avg_operation_time": duration / total_operations * 1000, # 毫秒
|
||||
"concurrent_threads": num_threads,
|
||||
"errors": len([e for e in self.error_log if "负载测试错误" in e])
|
||||
}
|
||||
|
||||
print(f"性能测试结果:")
|
||||
print(f"- 总操作数: {total_operations}")
|
||||
print(f"- 执行时间: {duration:.3f} 秒")
|
||||
print(f"- 操作速度: {ops_per_second:.1f} 操作/秒")
|
||||
print(f"- 平均操作时间: {self.performance_metrics['avg_operation_time']:.2f} 毫秒")
|
||||
print(f"- 并发线程: {num_threads}")
|
||||
print(f"- 错误数量: {self.performance_metrics['errors']}")
|
||||
|
||||
# 性能验证
|
||||
assert ops_per_second > 100, "操作速度应该超过100操作/秒"
|
||||
assert self.performance_metrics['errors'] == 0, "不应该有错误"
|
||||
|
||||
self.test_results["performance_under_load"] = True
|
||||
print("✅ 负载性能测试通过")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ 负载性能测试失败: {e}")
|
||||
self.error_log.append(f"负载性能测试错误: {e}")
|
||||
self.test_results["performance_under_load"] = False
|
||||
return False
|
||||
|
||||
def test_data_consistency(self):
|
||||
"""测试数据一致性"""
|
||||
print("\n🧪 测试数据一致性")
|
||||
print("-" * 40)
|
||||
|
||||
try:
|
||||
# 为了确保数据一致性测试的准确性,创建新的flow_controller实例
|
||||
from jixia.debates.optimized_debate_flow import OptimizedDebateFlowController, FlowControlMode
|
||||
test_flow_controller = OptimizedDebateFlowController()
|
||||
|
||||
# 模拟数据操作
|
||||
test_data = {
|
||||
"speakers": ["吕洞宾", "何仙姑", "铁拐李"],
|
||||
"speeches": [
|
||||
"AI投资具有巨大潜力",
|
||||
"但风险也不容忽视",
|
||||
"我们需要平衡收益与风险"
|
||||
]
|
||||
}
|
||||
|
||||
# 1. 保存流程控制器数据
|
||||
for i, (speaker, content) in enumerate(zip(test_data["speakers"], test_data["speeches"])):
|
||||
test_flow_controller.record_speech(speaker, content)
|
||||
print(f"记录发言 {i+1}: {speaker} - {content[:30]}...")
|
||||
|
||||
print(f"当前debate_history长度: {len(test_flow_controller.debate_history)}")
|
||||
|
||||
flow_data_file = "test_flow_consistency.json"
|
||||
test_flow_controller.save_flow_data(flow_data_file)
|
||||
|
||||
# 2. 保存健康监控数据
|
||||
debate_data = {
|
||||
"participants": test_data["speakers"],
|
||||
"speeches": [
|
||||
{"speaker": s, "content": c, "timestamp": datetime.now()}
|
||||
for s, c in zip(test_data["speakers"], test_data["speeches"])
|
||||
],
|
||||
"current_stage": "承",
|
||||
"duration": timedelta(minutes=10)
|
||||
}
|
||||
self.health_monitor.update_metrics(debate_data)
|
||||
|
||||
health_data_file = "test_health_consistency.json"
|
||||
self.health_monitor.save_monitoring_data(health_data_file)
|
||||
|
||||
# 3. 验证数据文件
|
||||
assert os.path.exists(flow_data_file), "流程数据文件应该存在"
|
||||
assert os.path.exists(health_data_file), "健康数据文件应该存在"
|
||||
|
||||
# 4. 读取并验证数据内容
|
||||
with open(flow_data_file, 'r', encoding='utf-8') as f:
|
||||
flow_data = json.load(f)
|
||||
|
||||
with open(health_data_file, 'r', encoding='utf-8') as f:
|
||||
health_data = json.load(f)
|
||||
|
||||
# 调试信息
|
||||
print(f"读取的flow_data中debate_history长度: {len(flow_data.get('debate_history', []))}")
|
||||
print(f"debate_history内容: {flow_data.get('debate_history', [])}")
|
||||
|
||||
# 验证数据完整性
|
||||
actual_count = len(flow_data.get("debate_history", []))
|
||||
assert actual_count == 3, f"应该有3条发言记录,实际有{actual_count}条"
|
||||
assert "health_metrics" in health_data, "应该包含健康指标"
|
||||
assert "monitoring_config" in health_data, "应该包含监控配置"
|
||||
|
||||
print(f"数据一致性验证:")
|
||||
print(f"- 流程数据记录: {len(flow_data['debate_history'])} 条")
|
||||
print(f"- 健康数据大小: {os.path.getsize(health_data_file)} 字节")
|
||||
print(f"- 流程数据大小: {os.path.getsize(flow_data_file)} 字节")
|
||||
|
||||
# 清理测试文件
|
||||
os.remove(flow_data_file)
|
||||
os.remove(health_data_file)
|
||||
|
||||
self.test_results["data_consistency"] = True
|
||||
print("✅ 数据一致性测试通过")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ 数据一致性测试失败: {e}")
|
||||
self.error_log.append(f"数据一致性错误: {e}")
|
||||
self.test_results["data_consistency"] = False
|
||||
return False
|
||||
|
||||
def generate_comprehensive_report(self):
|
||||
"""生成综合测试报告"""
|
||||
print("\n" + "=" * 60)
|
||||
print("📊 集夏v2.1.0 综合测试报告")
|
||||
print("=" * 60)
|
||||
|
||||
# 测试结果统计
|
||||
total_tests = len(self.test_results)
|
||||
passed_tests = sum(1 for result in self.test_results.values() if result)
|
||||
failed_tests = total_tests - passed_tests
|
||||
pass_rate = (passed_tests / total_tests) * 100 if total_tests > 0 else 0
|
||||
|
||||
print(f"\n🎯 测试结果统计:")
|
||||
print(f"- 总测试数: {total_tests}")
|
||||
print(f"- 通过测试: {passed_tests}")
|
||||
print(f"- 失败测试: {failed_tests}")
|
||||
print(f"- 通过率: {pass_rate:.1f}%")
|
||||
|
||||
# 详细测试结果
|
||||
print(f"\n📋 详细测试结果:")
|
||||
for test_name, result in self.test_results.items():
|
||||
status = "✅ 通过" if result else "❌ 失败"
|
||||
print(f"- {test_name}: {status}")
|
||||
|
||||
# 性能指标
|
||||
if self.performance_metrics:
|
||||
print(f"\n⚡ 性能指标:")
|
||||
for metric, value in self.performance_metrics.items():
|
||||
if isinstance(value, float):
|
||||
print(f"- {metric}: {value:.3f}")
|
||||
else:
|
||||
print(f"- {metric}: {value}")
|
||||
|
||||
# 错误日志
|
||||
if self.error_log:
|
||||
print(f"\n🚨 错误日志 ({len(self.error_log)} 条):")
|
||||
for i, error in enumerate(self.error_log[:5], 1): # 只显示前5条
|
||||
print(f"- {i}. {error}")
|
||||
if len(self.error_log) > 5:
|
||||
print(f"- ... 还有 {len(self.error_log) - 5} 条错误")
|
||||
|
||||
# 系统状态
|
||||
print(f"\n🔧 系统状态:")
|
||||
try:
|
||||
flow_status = self.flow_controller.get_flow_status()
|
||||
health_status = self.health_monitor.get_health_status()
|
||||
|
||||
print(f"- 流程控制器: 正常 (总发言: {flow_status.get('total_speeches', 0)})")
|
||||
print(f"- 健康监控: 正常 (状态: {health_status.value})")
|
||||
print(f"- 优先级算法: 正常")
|
||||
print(f"- 多群聊协调: 正常")
|
||||
except Exception as e:
|
||||
print(f"- 系统状态检查失败: {e}")
|
||||
|
||||
# 总结
|
||||
print(f"\n🎉 测试总结:")
|
||||
if pass_rate >= 90:
|
||||
print("🟢 系统状态优秀!所有核心功能运行正常,可以发布v2.1.0版本。")
|
||||
elif pass_rate >= 70:
|
||||
print("🟡 系统状态良好,但有部分功能需要优化。建议修复后再发布。")
|
||||
else:
|
||||
print("🔴 系统存在重大问题,需要进行全面修复后才能发布。")
|
||||
|
||||
return {
|
||||
"pass_rate": pass_rate,
|
||||
"total_tests": total_tests,
|
||||
"passed_tests": passed_tests,
|
||||
"failed_tests": failed_tests,
|
||||
"performance_metrics": self.performance_metrics,
|
||||
"error_count": len(self.error_log)
|
||||
}
|
||||
|
||||
async def run_all_tests(self):
|
||||
"""运行所有测试"""
|
||||
print("🚀 开始集夏v2.1.0综合功能测试")
|
||||
print("=" * 60)
|
||||
|
||||
# 同步测试方法
|
||||
sync_test_methods = [
|
||||
self.test_priority_algorithm_integration,
|
||||
self.test_flow_controller_integration,
|
||||
self.test_health_monitor_integration,
|
||||
self.test_performance_under_load,
|
||||
self.test_data_consistency
|
||||
]
|
||||
|
||||
# 异步测试方法
|
||||
async_test_methods = [
|
||||
self.test_chat_coordinator_integration,
|
||||
self.test_cross_component_integration
|
||||
]
|
||||
|
||||
start_time = time.time()
|
||||
|
||||
# 运行同步测试
|
||||
for test_method in sync_test_methods:
|
||||
try:
|
||||
test_method()
|
||||
except Exception as e:
|
||||
print(f"❌ 测试执行异常: {e}")
|
||||
self.error_log.append(f"测试执行异常: {e}")
|
||||
|
||||
# 运行异步测试
|
||||
for test_method in async_test_methods:
|
||||
try:
|
||||
await test_method()
|
||||
except Exception as e:
|
||||
print(f"❌ 测试执行异常: {e}")
|
||||
self.error_log.append(f"测试执行异常: {e}")
|
||||
|
||||
end_time = time.time()
|
||||
total_duration = end_time - start_time
|
||||
|
||||
print(f"\n⏱️ 总测试时间: {total_duration:.3f} 秒")
|
||||
|
||||
# 生成综合报告
|
||||
return self.generate_comprehensive_report()
|
||||
|
||||
async def main():
|
||||
"""主函数"""
|
||||
tester = V2_1_IntegrationTester()
|
||||
report = await tester.run_all_tests()
|
||||
|
||||
# 保存测试报告
|
||||
report_file = "v2_1_comprehensive_test_report.json"
|
||||
with open(report_file, 'w', encoding='utf-8') as f:
|
||||
json.dump({
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
"version": "v2.1.0",
|
||||
"test_results": tester.test_results,
|
||||
"performance_metrics": tester.performance_metrics,
|
||||
"error_log": tester.error_log,
|
||||
"summary": report
|
||||
}, f, ensure_ascii=False, indent=2)
|
||||
|
||||
print(f"\n📄 详细测试报告已保存到: {report_file}")
|
||||
|
||||
return report["pass_rate"] >= 70 # 70%通过率作为发布标准
|
||||
|
||||
if __name__ == "__main__":
|
||||
success = asyncio.run(main())
|
||||
sys.exit(0 if success else 1)
|
||||
90
modules/testing-framework/tests/test_vertex_ai_setup.py
Normal file
90
modules/testing-framework/tests/test_vertex_ai_setup.py
Normal file
@@ -0,0 +1,90 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
测试 Vertex AI 配置和连接
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
from config.settings import get_google_genai_config
|
||||
|
||||
def test_doppler_config():
|
||||
"""测试 Doppler 配置"""
|
||||
print("🔍 测试 Doppler 配置...")
|
||||
try:
|
||||
config = get_google_genai_config()
|
||||
print("✅ 成功读取 Google GenAI 配置")
|
||||
print(f" - API Key: {'已配置' if config.get('api_key') else '未配置'}")
|
||||
print(f" - Use Vertex AI: {config.get('use_vertex_ai', '未设置')}")
|
||||
print(f" - Project ID: {config.get('project_id', '未设置')}")
|
||||
print(f" - Location: {config.get('location', '未设置')}")
|
||||
print(f" - Memory Bank Enabled: {config.get('memory_bank_enabled', '未设置')}")
|
||||
return config
|
||||
except Exception as e:
|
||||
print(f"❌ 读取 Google GenAI 配置失败: {e}")
|
||||
return None
|
||||
|
||||
def test_environment_variables():
|
||||
"""测试环境变量"""
|
||||
print("\n🔍 测试环境变量...")
|
||||
adc_path = os.path.expanduser("~/.config/gcloud/application_default_credentials.json")
|
||||
if os.path.exists(adc_path):
|
||||
print("✅ 找到 Application Default Credentials 文件")
|
||||
else:
|
||||
print("❌ 未找到 Application Default Credentials 文件")
|
||||
|
||||
google_env_vars = [var for var in os.environ if var.startswith('GOOGLE_')]
|
||||
if google_env_vars:
|
||||
print("✅ 找到以下 Google 环境变量:")
|
||||
for var in google_env_vars:
|
||||
# 不显示敏感信息
|
||||
if 'KEY' in var or 'SECRET' in var or 'TOKEN' in var:
|
||||
print(f" - {var}: {'已设置' if os.environ.get(var) else '未设置'}")
|
||||
else:
|
||||
print(f" - {var}: {os.environ.get(var, '未设置')}")
|
||||
else:
|
||||
print("⚠️ 未找到 Google 环境变量")
|
||||
|
||||
def main():
|
||||
"""主函数"""
|
||||
print("🧪 Vertex AI 配置测试\n")
|
||||
|
||||
# 测试 Doppler 配置
|
||||
config = test_doppler_config()
|
||||
|
||||
# 测试环境变量
|
||||
test_environment_variables()
|
||||
|
||||
# 检查是否满足基本要求
|
||||
print("\n📋 配置检查摘要:")
|
||||
if config:
|
||||
project_id = config.get('project_id')
|
||||
api_key = config.get('api_key')
|
||||
|
||||
if project_id:
|
||||
print("✅ Google Cloud Project ID 已配置")
|
||||
else:
|
||||
print("❌ 未配置 Google Cloud Project ID")
|
||||
|
||||
if api_key:
|
||||
print("✅ Google API Key 已配置")
|
||||
else:
|
||||
print("❌ 未配置 Google API Key")
|
||||
|
||||
# 检查是否启用 Vertex AI
|
||||
use_vertex = config.get('use_vertex_ai', '').upper()
|
||||
if use_vertex == 'TRUE':
|
||||
print("✅ Vertex AI 已启用")
|
||||
else:
|
||||
print("❌ Vertex AI 未启用 (请检查 GOOGLE_GENAI_USE_VERTEXAI 环境变量)")
|
||||
|
||||
# 检查是否启用 Memory Bank
|
||||
memory_bank_enabled = config.get('memory_bank_enabled', '').upper()
|
||||
if memory_bank_enabled == 'TRUE':
|
||||
print("✅ Memory Bank 已启用")
|
||||
else:
|
||||
print("❌ Memory Bank 未启用 (请检查 VERTEX_MEMORY_BANK_ENABLED 环境变量)")
|
||||
else:
|
||||
print("❌ 无法读取配置,请检查 Doppler 配置")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
384
modules/testing-framework/tests/test_vertex_memory_bank.py
Normal file
384
modules/testing-framework/tests/test_vertex_memory_bank.py
Normal file
@@ -0,0 +1,384 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Vertex Memory Bank 实现测试
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import asyncio
|
||||
import os
|
||||
import sys
|
||||
from unittest.mock import patch, MagicMock, AsyncMock
|
||||
from datetime import datetime
|
||||
|
||||
# 添加项目根目录到Python路径
|
||||
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
|
||||
|
||||
from src.jixia.memory.vertex_memory_bank import VertexMemoryBank, MemoryEntry
|
||||
|
||||
|
||||
class TestVertexMemoryBank(unittest.TestCase):
|
||||
"""测试VertexMemoryBank类"""
|
||||
|
||||
def setUp(self):
|
||||
"""测试前的设置"""
|
||||
# Mock掉aiplatform.init以避免实际初始化
|
||||
patcher = patch('src.jixia.memory.vertex_memory_bank.aiplatform.init')
|
||||
self.mock_init = patcher.start()
|
||||
self.addCleanup(patcher.stop)
|
||||
|
||||
# 创建VertexMemoryBank实例
|
||||
self.memory_bank = VertexMemoryBank(
|
||||
project_id="test-project",
|
||||
location="us-central1"
|
||||
)
|
||||
|
||||
# 重置本地存储
|
||||
self.memory_bank.local_memories = {}
|
||||
self.memory_bank.memory_banks = {}
|
||||
|
||||
def test_init(self):
|
||||
"""测试初始化"""
|
||||
self.assertEqual(self.memory_bank.project_id, "test-project")
|
||||
self.assertEqual(self.memory_bank.location, "us-central1")
|
||||
self.assertEqual(self.memory_bank.local_memories, {})
|
||||
self.assertEqual(self.memory_bank.memory_banks, {})
|
||||
|
||||
# 验证调用了aiplatform.init
|
||||
self.mock_init.assert_called_once_with(project="test-project", location="us-central1")
|
||||
|
||||
def test_from_config(self):
|
||||
"""测试从配置创建实例"""
|
||||
with patch('src.jixia.memory.vertex_memory_bank.get_google_genai_config') as mock_config:
|
||||
mock_config.return_value = {
|
||||
'project_id': 'config-project',
|
||||
'location': 'europe-west1'
|
||||
}
|
||||
|
||||
memory_bank = VertexMemoryBank.from_config()
|
||||
|
||||
self.assertEqual(memory_bank.project_id, "config-project")
|
||||
self.assertEqual(memory_bank.location, "europe-west1")
|
||||
|
||||
def test_from_config_missing_project_id(self):
|
||||
"""测试从配置创建实例时缺少project_id"""
|
||||
with patch('src.jixia.memory.vertex_memory_bank.get_google_genai_config') as mock_config:
|
||||
mock_config.return_value = {
|
||||
'project_id': None,
|
||||
'location': 'europe-west1'
|
||||
}
|
||||
|
||||
with self.assertRaises(ValueError) as context:
|
||||
VertexMemoryBank.from_config()
|
||||
|
||||
self.assertIn("Google Cloud Project ID 未配置", str(context.exception))
|
||||
|
||||
async def test_create_memory_bank(self):
|
||||
"""测试创建记忆银行"""
|
||||
memory_bank_id = await self.memory_bank.create_memory_bank("tieguaili")
|
||||
|
||||
# 验证返回的ID格式
|
||||
self.assertEqual(memory_bank_id, "memory_bank_tieguaili_test-project")
|
||||
|
||||
# 验证内部状态
|
||||
self.assertIn("tieguaili", self.memory_bank.memory_banks)
|
||||
self.assertEqual(self.memory_bank.memory_banks["tieguaili"], memory_bank_id)
|
||||
self.assertIn("tieguaili", self.memory_bank.local_memories)
|
||||
self.assertEqual(self.memory_bank.local_memories["tieguaili"], [])
|
||||
|
||||
async def test_create_memory_bank_with_display_name(self):
|
||||
"""测试创建记忆银行时指定显示名称"""
|
||||
memory_bank_id = await self.memory_bank.create_memory_bank(
|
||||
"tieguaili",
|
||||
"铁拐李的专属记忆银行"
|
||||
)
|
||||
|
||||
# 验证返回的ID格式
|
||||
self.assertEqual(memory_bank_id, "memory_bank_tieguaili_test-project")
|
||||
|
||||
async def test_add_memory(self):
|
||||
"""测试添加记忆"""
|
||||
# 先创建记忆银行
|
||||
await self.memory_bank.create_memory_bank("tieguaili")
|
||||
|
||||
# 添加记忆
|
||||
memory_id = await self.memory_bank.add_memory(
|
||||
agent_name="tieguaili",
|
||||
content="在讨论NVIDIA股票时,我倾向于逆向思维,关注潜在风险。",
|
||||
memory_type="preference",
|
||||
debate_topic="NVIDIA投资分析",
|
||||
metadata={"source": "manual"}
|
||||
)
|
||||
|
||||
# 验证返回的ID格式
|
||||
self.assertEqual(memory_id, "memory_tieguaili_0")
|
||||
|
||||
# 验证记忆已存储
|
||||
self.assertEqual(len(self.memory_bank.local_memories["tieguaili"]), 1)
|
||||
|
||||
stored_memory = self.memory_bank.local_memories["tieguaili"][0]
|
||||
self.assertEqual(stored_memory["id"], memory_id)
|
||||
self.assertEqual(stored_memory["content"], "在讨论NVIDIA股票时,我倾向于逆向思维,关注潜在风险。")
|
||||
self.assertEqual(stored_memory["memory_type"], "preference")
|
||||
self.assertEqual(stored_memory["debate_topic"], "NVIDIA投资分析")
|
||||
self.assertIn("source", stored_memory["metadata"])
|
||||
self.assertEqual(stored_memory["metadata"]["source"], "manual")
|
||||
self.assertIn("agent_name", stored_memory["metadata"])
|
||||
self.assertEqual(stored_memory["metadata"]["agent_name"], "tieguaili")
|
||||
|
||||
async def test_add_memory_creates_bank_if_not_exists(self):
|
||||
"""测试添加记忆时自动创建记忆银行"""
|
||||
# 不先创建记忆银行,直接添加记忆
|
||||
memory_id = await self.memory_bank.add_memory(
|
||||
agent_name="tieguaili",
|
||||
content="测试内容"
|
||||
)
|
||||
|
||||
# 验证记忆银行已被自动创建
|
||||
self.assertIn("tieguaili", self.memory_bank.memory_banks)
|
||||
self.assertIn("tieguaili", self.memory_bank.local_memories)
|
||||
|
||||
# 验证记忆已存储
|
||||
self.assertEqual(len(self.memory_bank.local_memories["tieguaili"]), 1)
|
||||
|
||||
async def test_search_memories(self):
|
||||
"""测试搜索记忆"""
|
||||
# 先创建记忆银行并添加一些记忆
|
||||
await self.memory_bank.create_memory_bank("tieguaili")
|
||||
|
||||
await self.memory_bank.add_memory(
|
||||
agent_name="tieguaili",
|
||||
content="在讨论NVIDIA股票时,我倾向于逆向思维,关注潜在风险。",
|
||||
memory_type="preference",
|
||||
debate_topic="NVIDIA投资分析"
|
||||
)
|
||||
|
||||
await self.memory_bank.add_memory(
|
||||
agent_name="tieguaili",
|
||||
content="我喜欢关注苹果公司的创新产品发布会。",
|
||||
memory_type="preference",
|
||||
debate_topic="AAPL投资分析"
|
||||
)
|
||||
|
||||
# 搜索NVIDIA相关记忆
|
||||
results = await self.memory_bank.search_memories(
|
||||
agent_name="tieguaili",
|
||||
query="NVIDIA"
|
||||
)
|
||||
|
||||
self.assertEqual(len(results), 1)
|
||||
self.assertEqual(results[0]["content"], "在讨论NVIDIA股票时,我倾向于逆向思维,关注潜在风险。")
|
||||
self.assertIn("relevance_score", results[0])
|
||||
|
||||
async def test_search_memories_with_type_filter(self):
|
||||
"""测试带类型过滤的搜索记忆"""
|
||||
# 先创建记忆银行并添加不同类型的记忆
|
||||
await self.memory_bank.create_memory_bank("tieguaili")
|
||||
|
||||
await self.memory_bank.add_memory(
|
||||
agent_name="tieguaili",
|
||||
content="在讨论NVIDIA股票时,我倾向于逆向思维,关注潜在风险。",
|
||||
memory_type="preference",
|
||||
debate_topic="NVIDIA投资分析"
|
||||
)
|
||||
|
||||
await self.memory_bank.add_memory(
|
||||
agent_name="tieguaili",
|
||||
content="在NVIDIA的辩论中,我使用了技术分析策略。",
|
||||
memory_type="strategy",
|
||||
debate_topic="NVIDIA投资分析"
|
||||
)
|
||||
|
||||
# 搜索NVIDIA相关记忆,只返回preference类型
|
||||
results = await self.memory_bank.search_memories(
|
||||
agent_name="tieguaili",
|
||||
query="NVIDIA",
|
||||
memory_type="preference"
|
||||
)
|
||||
|
||||
self.assertEqual(len(results), 1)
|
||||
self.assertEqual(results[0]["metadata"]["memory_type"], "preference")
|
||||
|
||||
async def test_search_memories_no_results(self):
|
||||
"""测试搜索无结果的情况"""
|
||||
# 搜索不存在的记忆银行
|
||||
results = await self.memory_bank.search_memories(
|
||||
agent_name="nonexistent",
|
||||
query="test"
|
||||
)
|
||||
|
||||
self.assertEqual(results, [])
|
||||
|
||||
# 搜索空的记忆银行
|
||||
await self.memory_bank.create_memory_bank("tieguaili")
|
||||
results = await self.memory_bank.search_memories(
|
||||
agent_name="tieguaili",
|
||||
query="test"
|
||||
)
|
||||
|
||||
self.assertEqual(results, [])
|
||||
|
||||
async def test_get_agent_context(self):
|
||||
"""测试获取智能体上下文"""
|
||||
# 先创建记忆银行并添加一些记忆
|
||||
await self.memory_bank.create_memory_bank("tieguaili")
|
||||
|
||||
await self.memory_bank.add_memory(
|
||||
agent_name="tieguaili",
|
||||
content="在讨论NVIDIA股票时,我倾向于逆向思维,关注潜在风险。",
|
||||
memory_type="preference",
|
||||
debate_topic="NVIDIA投资分析"
|
||||
)
|
||||
|
||||
await self.memory_bank.add_memory(
|
||||
agent_name="tieguaili",
|
||||
content="在NVIDIA的辩论中,我使用了技术分析策略。",
|
||||
memory_type="strategy",
|
||||
debate_topic="NVIDIA投资分析"
|
||||
)
|
||||
|
||||
# 获取上下文
|
||||
context = await self.memory_bank.get_agent_context("tieguaili", "NVIDIA投资分析")
|
||||
|
||||
# 验证上下文包含预期内容
|
||||
self.assertIn("# 铁拐李的记忆上下文", context)
|
||||
self.assertIn("## 偏好记忆", context)
|
||||
self.assertIn("## 策略记忆", context)
|
||||
self.assertIn("在讨论NVIDIA股票时,我倾向于逆向思维,关注潜在风险。", context)
|
||||
self.assertIn("在NVIDIA的辩论中,我使用了技术分析策略。", context)
|
||||
|
||||
async def test_get_agent_context_no_memories(self):
|
||||
"""测试获取智能体上下文但无相关记忆"""
|
||||
# 先创建记忆银行
|
||||
await self.memory_bank.create_memory_bank("tieguaili")
|
||||
|
||||
# 获取上下文
|
||||
context = await self.memory_bank.get_agent_context("tieguaili", "NVIDIA投资分析")
|
||||
|
||||
# 验证上下文包含暂无相关记忆的提示
|
||||
self.assertIn("# 铁拐李的记忆上下文", context)
|
||||
self.assertIn("暂无相关记忆。", context)
|
||||
|
||||
async def test_save_debate_session(self):
|
||||
"""测试保存辩论会话"""
|
||||
conversation_history = [
|
||||
{"agent": "tieguaili", "content": "NVIDIA的估值过高,存在泡沫风险。"},
|
||||
{"agent": "lvdongbin", "content": "NVIDIA在AI领域的领先地位不可忽视。"},
|
||||
{"agent": "tieguaili", "content": "但我们需要考虑竞争加剧和增长放缓的可能性。"}
|
||||
]
|
||||
|
||||
outcomes = {
|
||||
"winner": "lvdongbin",
|
||||
"insights": {
|
||||
"tieguaili": "铁拐李的风险意识值得肯定,但在AI趋势的判断上略显保守。"
|
||||
}
|
||||
}
|
||||
|
||||
# 保存辩论会话
|
||||
await self.memory_bank.save_debate_session(
|
||||
debate_topic="NVIDIA投资分析",
|
||||
participants=["tieguaili", "lvdongbin"],
|
||||
conversation_history=conversation_history,
|
||||
outcomes=outcomes
|
||||
)
|
||||
|
||||
# 验证铁拐李的记忆已保存
|
||||
self.assertIn("tieguaili", self.memory_bank.local_memories)
|
||||
self.assertEqual(len(self.memory_bank.local_memories["tieguaili"]), 2)
|
||||
|
||||
# 验证第一条记忆是对话总结
|
||||
summary_memory = self.memory_bank.local_memories["tieguaili"][0]
|
||||
self.assertEqual(summary_memory["memory_type"], "conversation")
|
||||
self.assertIn("铁拐李在本次辩论中的主要观点", summary_memory["content"])
|
||||
|
||||
# 验证第二条记忆是策略洞察
|
||||
strategy_memory = self.memory_bank.local_memories["tieguaili"][1]
|
||||
self.assertEqual(strategy_memory["memory_type"], "strategy")
|
||||
self.assertIn("铁拐李的风险意识值得肯定", strategy_memory["content"])
|
||||
|
||||
def test_summarize_conversation(self):
|
||||
"""测试对话总结"""
|
||||
conversation_history = [
|
||||
{"agent": "tieguaili", "content": "第一点看法:NVIDIA的估值过高,存在泡沫风险。"},
|
||||
{"agent": "lvdongbin", "content": "NVIDIA在AI领域的领先地位不可忽视。"},
|
||||
{"agent": "tieguaili", "content": "第二点看法:我们需要考虑竞争加剧和增长放缓的可能性。"},
|
||||
{"agent": "tieguaili", "content": "第三点看法:从技术分析角度看,股价已出现超买信号。"}
|
||||
]
|
||||
|
||||
summary = self.memory_bank._summarize_conversation(conversation_history, "tieguaili")
|
||||
|
||||
# 验证总结包含预期内容
|
||||
self.assertIn("铁拐李在本次辩论中的主要观点", summary)
|
||||
self.assertIn("第一点看法:NVIDIA的估值过高,存在泡沫风险。", summary)
|
||||
self.assertIn("第二点看法:我们需要考虑竞争加剧和增长放缓的可能性。", summary)
|
||||
self.assertIn("第三点看法:从技术分析角度看,股价已出现超买信号。", summary)
|
||||
|
||||
def test_extract_strategy_insight_winner(self):
|
||||
"""测试提取策略洞察 - 获胜者"""
|
||||
outcomes = {
|
||||
"winner": "tieguaili",
|
||||
"insights": {}
|
||||
}
|
||||
|
||||
insight = self.memory_bank._extract_strategy_insight(outcomes, "tieguaili")
|
||||
|
||||
self.assertIn("铁拐李在本次辩论中获胜", insight)
|
||||
|
||||
def test_extract_strategy_insight_from_insights(self):
|
||||
"""测试从洞察中提取策略洞察"""
|
||||
outcomes = {
|
||||
"winner": "lvdongbin",
|
||||
"insights": {
|
||||
"tieguaili": "铁拐李的风险意识值得肯定,但在AI趋势的判断上略显保守。"
|
||||
}
|
||||
}
|
||||
|
||||
insight = self.memory_bank._extract_strategy_insight(outcomes, "tieguaili")
|
||||
|
||||
self.assertEqual(insight, "铁拐李的风险意识值得肯定,但在AI趋势的判断上略显保守。")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# 创建一个异步测试运行器
|
||||
def run_async_test(test_case):
|
||||
"""运行异步测试用例"""
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
try:
|
||||
return loop.run_until_complete(test_case)
|
||||
finally:
|
||||
loop.close()
|
||||
|
||||
# 获取所有以test_开头的异步方法并运行它们
|
||||
suite = unittest.TestSuite()
|
||||
test_instance = TestVertexMemoryBank()
|
||||
test_instance.setUp()
|
||||
|
||||
# 添加同步测试
|
||||
suite.addTest(TestVertexMemoryBank('test_init'))
|
||||
suite.addTest(TestVertexMemoryBank('test_from_config'))
|
||||
suite.addTest(TestVertexMemoryBank('test_from_config_missing_project_id'))
|
||||
suite.addTest(TestVertexMemoryBank('test_summarize_conversation'))
|
||||
suite.addTest(TestVertexMemoryBank('test_extract_strategy_insight_winner'))
|
||||
suite.addTest(TestVertexMemoryBank('test_extract_strategy_insight_from_insights'))
|
||||
|
||||
# 添加异步测试
|
||||
async_tests = [
|
||||
'test_create_memory_bank',
|
||||
'test_create_memory_bank_with_display_name',
|
||||
'test_add_memory',
|
||||
'test_add_memory_creates_bank_if_not_exists',
|
||||
'test_search_memories',
|
||||
'test_search_memories_with_type_filter',
|
||||
'test_search_memories_no_results',
|
||||
'test_get_agent_context',
|
||||
'test_get_agent_context_no_memories',
|
||||
'test_save_debate_session'
|
||||
]
|
||||
|
||||
for test_name in async_tests:
|
||||
test_method = getattr(test_instance, test_name)
|
||||
suite.addTest(unittest.FunctionTestCase(lambda tm=test_method: run_async_test(tm())))
|
||||
|
||||
# 运行测试
|
||||
runner = unittest.TextTestRunner(verbosity=2)
|
||||
runner.run(suite)
|
||||
@@ -0,0 +1,72 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
测试 Vertex AI Memory Bank 功能
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
|
||||
# 添加项目根目录到Python路径
|
||||
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '.')))
|
||||
|
||||
from src.jixia.memory.factory import get_memory_backend
|
||||
|
||||
async def test_vertex_memory_bank():
|
||||
"""测试 Vertex Memory Bank 功能"""
|
||||
print("🧪 Vertex AI Memory Bank 功能测试\n")
|
||||
|
||||
try:
|
||||
# 获取 Vertex Memory Bank 后端
|
||||
print("🔍 正在获取 Vertex Memory Bank 后端...")
|
||||
memory_bank = get_memory_backend(prefer='vertex')
|
||||
print("✅ 成功获取 Vertex Memory Bank 后端\n")
|
||||
|
||||
# 测试创建记忆银行
|
||||
print("🔍 正在为吕洞宾创建记忆银行...")
|
||||
bank_id = await memory_bank.create_memory_bank("lvdongbin", "吕洞宾的记忆银行")
|
||||
print(f"✅ 成功为吕洞宾创建记忆银行: {bank_id}\n")
|
||||
|
||||
# 测试添加记忆
|
||||
print("🔍 正在为吕洞宾添加记忆...")
|
||||
memory_id = await memory_bank.add_memory(
|
||||
agent_name="lvdongbin",
|
||||
content="在讨论NVIDIA股票时,我倾向于使用DCF模型评估其内在价值,并关注其在AI领域的竞争优势。",
|
||||
memory_type="preference",
|
||||
debate_topic="NVIDIA投资分析",
|
||||
metadata={"confidence": "high"}
|
||||
)
|
||||
print(f"✅ 成功为吕洞宾添加记忆: {memory_id}\n")
|
||||
|
||||
# 测试搜索记忆
|
||||
print("🔍 正在搜索吕洞宾关于NVIDIA的记忆...")
|
||||
results = await memory_bank.search_memories(
|
||||
agent_name="lvdongbin",
|
||||
query="NVIDIA",
|
||||
memory_type="preference"
|
||||
)
|
||||
print(f"✅ 搜索完成,找到 {len(results)} 条相关记忆\n")
|
||||
|
||||
if results:
|
||||
print("🔍 搜索结果:")
|
||||
for i, result in enumerate(results, 1):
|
||||
print(f" {i}. {result['content']}")
|
||||
print(f" 相关性评分: {result['relevance_score']:.4f}\n")
|
||||
|
||||
# 测试获取上下文
|
||||
print("🔍 正在获取吕洞宾关于NVIDIA投资分析的上下文...")
|
||||
context = await memory_bank.get_agent_context("lvdongbin", "NVIDIA投资分析")
|
||||
print("✅ 成功获取上下文\n")
|
||||
print("🔍 上下文内容:")
|
||||
print(context)
|
||||
print("\n")
|
||||
|
||||
print("🎉 Vertex AI Memory Bank 功能测试完成!")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ 测试过程中发生错误: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(test_vertex_memory_bank())
|
||||
90
modules/testing-framework/tests/validate_models.py
Normal file
90
modules/testing-framework/tests/validate_models.py
Normal file
@@ -0,0 +1,90 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Script to validate model availability on OpenRouter
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import aiohttp
|
||||
import os
|
||||
|
||||
# Read models from .env file
|
||||
models = []
|
||||
with open(".env", "r") as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if line.endswith(":free"):
|
||||
models.append(line)
|
||||
|
||||
# Get API key from environment or .env file
|
||||
api_key = os.getenv('OPENROUTER_API_KEY')
|
||||
if not api_key:
|
||||
with open(".env", "r") as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if line.startswith("sk-or-v1-"):
|
||||
api_key = line
|
||||
break
|
||||
|
||||
if not api_key:
|
||||
print("❌ No API key found")
|
||||
exit(1)
|
||||
|
||||
async def test_model(session, model):
|
||||
"""Test if a model is available on OpenRouter"""
|
||||
# Remove :free tag for API call
|
||||
clean_model = model.split(":")[0]
|
||||
|
||||
url = "https://openrouter.ai/api/v1/chat/completions"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {api_key}",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
payload = {
|
||||
"model": clean_model,
|
||||
"messages": [
|
||||
{"role": "user", "content": "Hello, world!"}
|
||||
],
|
||||
"max_tokens": 10
|
||||
}
|
||||
|
||||
try:
|
||||
async with session.post(url, headers=headers, json=payload, timeout=10) as response:
|
||||
if response.status == 200:
|
||||
return model, True, "Available"
|
||||
else:
|
||||
error_text = await response.text()
|
||||
return model, False, f"Status {response.status}: {error_text[:100]}"
|
||||
except Exception as e:
|
||||
return model, False, f"Exception: {str(e)[:100]}"
|
||||
|
||||
async def main():
|
||||
"""Main function"""
|
||||
print(f"🔍 Testing {len(models)} models from .env file...")
|
||||
|
||||
async with aiohttp.ClientSession() as session:
|
||||
tasks = [test_model(session, model) for model in models]
|
||||
results = await asyncio.gather(*tasks)
|
||||
|
||||
print("\n📊 Results:")
|
||||
valid_models = []
|
||||
invalid_models = []
|
||||
|
||||
for model, is_valid, message in results:
|
||||
if is_valid:
|
||||
print(f"✅ {model:<50} - {message}")
|
||||
valid_models.append(model)
|
||||
else:
|
||||
print(f"❌ {model:<50} - {message}")
|
||||
invalid_models.append(model)
|
||||
|
||||
print(f"\n✅ Valid models ({len(valid_models)}):")
|
||||
for model in valid_models:
|
||||
print(f" {model}")
|
||||
|
||||
print(f"\n❌ Invalid models ({len(invalid_models)}):")
|
||||
for model in invalid_models:
|
||||
print(f" {model}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
Reference in New Issue
Block a user