import 'dart:convert'; import 'package:http/http.dart' as http; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'ai_service.dart'; class VolcanoAIService implements AiService { final String apiKey; static const String _baseUrl = 'https://ark.cn-beijing.volces.com/api/v3'; static const String _chatEndpoint = '/chat/completions'; VolcanoAIService() : apiKey = dotenv.env['VOLCANO_AI_API_KEY'] ?? '' { if (apiKey.isEmpty) { throw VolcanoAIException('火山AI配置信息不完整,请检查环境变量'); } } // 生成个性化问候语 Stream generateGreeting({ required String agentName, required String systemPrompt, }) { final messages = [ {'role': 'system', 'content': systemPrompt}, {'role': 'user', 'content': '请用一句简短的话向我打个招呼,要符合你的身份和性格特点,不要超过18个字。'}, ]; return sendMessageStream( messages: messages, systemPrompt: systemPrompt, ); } // 非流式输出方法 @override Future sendMessage({ required List> messages, String? systemPrompt, String? userProperties, }) async { final url = Uri.parse('$_baseUrl$_chatEndpoint'); final fullMessages = [ {'role': 'system', 'content': systemPrompt}, ...messages, ]; try { final response = await http.post( url, headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer $apiKey', }, body: json.encode({ 'model': 'doubao-1-5-lite-32k-250115', 'messages': fullMessages, 'temperature': 0.7, 'max_tokens': 2000, 'stream': false, }), ); if (response.statusCode == 200) { final data = json.decode(response.body); if (data['choices'] != null && data['choices'].isNotEmpty && data['choices'][0]['message'] != null) { return data['choices'][0]['message']['content']; } throw VolcanoAIException('Invalid response format'); } else { final error = json.decode(response.body); throw VolcanoAIException( error['error']?['message'] ?? 'Unknown error occurred', ); } } catch (e) { if (e is VolcanoAIException) rethrow; throw VolcanoAIException('Failed to communicate with AI service: $e'); } } // 流式输出方法 @override Stream sendMessageStream({ required List> messages, String? systemPrompt, String? userProperties, }) async* { final url = Uri.parse('$_baseUrl$_chatEndpoint'); final fullMessages = [ {'role': 'system', 'content': systemPrompt}, ...messages, ]; try { final request = http.Request('POST', url); request.headers.addAll({ 'Content-Type': 'application/json', 'Authorization': 'Bearer $apiKey', 'Accept': 'text/event-stream', }); request.body = json.encode({ 'model': 'doubao-1-5-lite-32k-250115', 'messages': fullMessages, 'temperature': 0.7, 'max_tokens': 2000, 'stream': true, }); final response = await http.Client().send(request); if (response.statusCode != 200) { final error = await response.stream.bytesToString(); throw VolcanoAIException(json.decode(error)['error']?['message'] ?? 'Unknown error occurred'); } await for (final chunk in response.stream .transform(utf8.decoder) .transform(const LineSplitter())) { if (chunk.isEmpty) continue; if (chunk.startsWith('data: ')) { final data = chunk.substring(6); if (data == '[DONE]') break; try { final jsonData = json.decode(data); if (jsonData['choices'] != null && jsonData['choices'].isNotEmpty && jsonData['choices'][0]['delta'] != null && jsonData['choices'][0]['delta']['content'] != null) { yield jsonData['choices'][0]['delta']['content'] as String; } } catch (e) { // 忽略无效的JSON数据 continue; } } } } catch (e) { if (e is VolcanoAIException) rethrow; throw VolcanoAIException('Failed to communicate with AI service: $e'); } } } class VolcanoAIException implements Exception { final String message; VolcanoAIException(this.message); @override String toString() => message; }