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
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;
|
|
}
|
|
}
|