You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

259 lines
8.2 KiB

import 'dart:io';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
/// 检查火山语音识别服务配置
///
/// 该工具用于验证火山语音识别服务的配置是否正确,包括:
/// 1. 检查环境变量是否设置
/// 2. 检查网络连接
/// 3. 检查认证是否有效
void main() async {
// 加载环境变量
await dotenv.load();
print('======== 火山语音识别服务配置检查 ========');
// 检查环境变量
final appId = dotenv.env['VOLCANO_APP_ID'];
final appKey = dotenv.env['VOLCANO_APP_KEY'];
final cluster = dotenv.env['VOLCANO_CLUSTER'];
print('\n1. 检查环境变量:');
if (appId == null || appId.isEmpty) {
print('❌ VOLCANO_APP_ID 未设置');
} else {
print('✅ VOLCANO_APP_ID: ${appId.substring(0, 3)}***${appId.substring(appId.length - 3)} (长度: ${appId.length})');
}
if (appKey == null || appKey.isEmpty) {
print('❌ VOLCANO_APP_KEY 未设置');
} else {
print('✅ VOLCANO_APP_KEY: ${appKey.substring(0, 3)}***${appKey.substring(appKey.length - 3)} (长度: ${appKey.length})');
}
if (cluster == null || cluster.isEmpty) {
print('❌ VOLCANO_CLUSTER 未设置,将使用默认值 cn-beijing');
} else {
print('✅ VOLCANO_CLUSTER: $cluster');
}
// 使用默认值
final effectiveCluster = cluster ?? 'cn-beijing';
if (appId == null || appId.isEmpty || appKey == null || appKey.isEmpty) {
print('\n❌ 环境变量配置不完整,请检查 .env 文件');
exit(1);
}
// 检查网络连接
print('\n2. 检查网络连接:');
try {
final result = await InternetAddress.lookup('openspeech.bytedance.com');
if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
print('✅ 网络连接正常,可以访问 openspeech.bytedance.com');
} else {
print('❌ 无法连接到 openspeech.bytedance.com');
}
} catch (e) {
print('❌ 网络连接异常: $e');
}
// 检查认证是否有效
print('\n3. 检查认证有效性:');
http.Response? authResponse;
try {
// 构建请求URL - 更新为大模型流式识别API路径
final url = 'https://openspeech.bytedance.com/api/v3/sauc/bigmodel';
// 构建请求头 - 不再添加Bearer前缀
final headers = {
'Content-Type': 'application/json',
'Authorization': appKey, // 不再添加Bearer前缀
};
// 构建请求体 - 添加resourceId参数
final body = jsonEncode({
'app_id': appId,
'cluster': effectiveCluster,
'resource_id': appId, // 资源ID暂时使用与APP_ID相同的值
'ping': true, // 只是ping服务,不进行实际识别
});
print('正在发送测试请求...');
print('请求URL: $url');
print('请求头: Authorization=${appKey.substring(0, 3)}***');
print('集群区域: $effectiveCluster');
// 发送请求
authResponse = await http.post(
Uri.parse(url),
headers: headers,
body: body,
).timeout(const Duration(seconds: 5));
// 检查响应
if (authResponse.statusCode == 200) {
print('✅ 认证有效,服务响应正常');
print('响应内容: ${authResponse.body}');
} else {
print('❌ 认证无效或服务异常,状态码: ${authResponse.statusCode}');
print('错误信息: ${authResponse.body}');
// 解析错误信息
try {
final errorJson = jsonDecode(authResponse.body);
final errorCode = errorJson['code'];
final errorMsg = errorJson['message'];
if (errorCode == 401) {
print('\n认证错误,可能的原因:');
print('1. APP_KEY 格式不正确');
print('2. APP_ID 与 APP_KEY 不匹配');
print('3. 账户未开通大模型流式语音识别服务或服务已过期');
print('4. 资源ID不正确或未授权');
} else if (errorCode == 400) {
print('\nWebSocket握手错误,可能的原因:');
print('1. 集群区域设置不正确 (当前: $effectiveCluster)');
print('2. 请求参数格式不正确');
print('3. 尝试使用不同的集群区域,如 cn-shanghai 或 cn-guangzhou');
} else {
print('\n未知错误:');
print('错误码: $errorCode');
print('错误信息: $errorMsg');
}
} catch (e) {
print('\n解析错误信息失败: $e');
if (authResponse.statusCode == 400) {
print('\nWebSocket握手错误,可能的原因:');
print('1. 集群区域设置不正确 (当前: $effectiveCluster)');
print('2. 请求参数格式不正确');
print('3. 尝试使用不同的集群区域,如 cn-shanghai 或 cn-guangzhou');
}
}
}
} catch (e) {
print('❌ 请求异常: $e');
}
print('\n======== 检查完成 ========');
print('\n提示: 如果您使用的是大模型流式识别SDK,请确保:');
print('1. 使用了正确的API路径: /api/v3/sauc/bigmodel');
print('2. 不要在Token前添加Bearer前缀');
print('3. 设置了正确的资源ID');
print('4. 设置了协议类型为PROTOCOL_TYPE_SEED');
print('5. 设置了正确的集群区域 (当前: $effectiveCluster)');
// 尝试其他集群区域
if (authResponse != null && authResponse.statusCode == 400) {
print('\n尝试其他集群区域:');
final alternativeClusters = [
'cn-shanghai',
'cn-guangzhou',
'cn-hongkong',
'ap-singapore',
'us-east-1',
'us-west-1'
];
bool foundWorkingCluster = false;
for (final altCluster in alternativeClusters) {
if (altCluster != effectiveCluster) {
print('\n尝试集群区域: $altCluster');
final success = await _testCluster(appId, appKey, altCluster);
if (success) {
foundWorkingCluster = true;
print('\n✅ 找到可用的集群区域: $altCluster');
print('建议在 .env 文件中设置 VOLCANO_CLUSTER=$altCluster');
// 尝试更新.env文件
try {
await _updateEnvFile(altCluster);
} catch (e) {
print('无法自动更新.env文件: $e');
}
break;
}
}
}
if (!foundWorkingCluster) {
print('\n❌ 所有集群区域测试均失败');
print('请联系火山引擎技术支持获取正确的集群区域');
}
}
}
/// 测试不同的集群区域
Future<bool> _testCluster(String appId, String appKey, String cluster) async {
try {
final url = 'https://openspeech.bytedance.com/api/v3/sauc/bigmodel';
final headers = {
'Content-Type': 'application/json',
'Authorization': appKey,
};
final body = jsonEncode({
'app_id': appId,
'cluster': cluster,
'resource_id': appId,
'ping': true,
});
final response = await http.post(
Uri.parse(url),
headers: headers,
body: body,
).timeout(const Duration(seconds: 5));
if (response.statusCode == 200) {
print('✅ 集群区域 $cluster 可用,认证有效');
return true;
} else {
print('❌ 集群区域 $cluster 不可用,状态码: ${response.statusCode}');
return false;
}
} catch (e) {
print('❌ 测试集群区域 $cluster 时出错: $e');
return false;
}
}
/// 尝试更新.env文件
Future<void> _updateEnvFile(String newCluster) async {
try {
final file = File('.env');
if (!await file.exists()) {
print('❌ .env文件不存在,无法自动更新');
return;
}
String content = await file.readAsString();
// 检查是否已有VOLCANO_CLUSTER
final clusterRegex = RegExp(r'VOLCANO_CLUSTER=.*');
if (clusterRegex.hasMatch(content)) {
// 替换现有的VOLCANO_CLUSTER
content = content.replaceAll(clusterRegex, 'VOLCANO_CLUSTER=$newCluster');
} else {
// 添加新的VOLCANO_CLUSTER
content += '\nVOLCANO_CLUSTER=$newCluster';
}
// 写入文件
await file.writeAsString(content);
print('✅ 已自动更新.env文件中的VOLCANO_CLUSTER=$newCluster');
} catch (e) {
print('❌ 更新.env文件失败: $e');
throw e;
}
}