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.
125 lines
3.1 KiB
125 lines
3.1 KiB
import 'dart:convert';
|
|
|
|
import 'package:http/http.dart' as http;
|
|
|
|
import '../../core/utils/logger.dart';
|
|
import '../models/appconfig.dart';
|
|
import 'ai_service.dart';
|
|
|
|
class DeapsoundAIService implements AiService {
|
|
late final String baseUrl;
|
|
late final String apiKey;
|
|
late final String model;
|
|
|
|
DeapsoundAIService() {
|
|
apiKey = AppConfig.env('OPENAI_API_KEY') ?? '';
|
|
baseUrl = AppConfig.env('OPENAI_BASE_URL') ?? '';
|
|
model = AppConfig.env('OPENAI_MODEL') ?? '';
|
|
}
|
|
|
|
@override
|
|
Future<String> sendMessage({
|
|
required List<Map<String, String>> messages,
|
|
String? systemPrompt,
|
|
String? userProperties,
|
|
}) async {
|
|
final url = Uri.parse(baseUrl);
|
|
|
|
final headers = {
|
|
'Content-Type': 'application/json',
|
|
'Authorization': 'Bearer $apiKey',
|
|
};
|
|
|
|
final requestBody = {
|
|
"model": model,
|
|
"messages": messages,
|
|
};
|
|
|
|
try {
|
|
final response = await http.post(
|
|
url,
|
|
headers: headers,
|
|
body: jsonEncode(requestBody),
|
|
);
|
|
if (response.statusCode != 200) {
|
|
throw Exception('Unknown error');
|
|
}
|
|
|
|
final result = jsonDecode(response.body);
|
|
|
|
return result['choices'].first['message']['content'];
|
|
} catch (e) {
|
|
throw Exception('Unknown error');
|
|
}
|
|
}
|
|
|
|
@override
|
|
Stream sendMessageStream({
|
|
required List<Map<String, String>> messages,
|
|
String? systemPrompt,
|
|
String? userProperties,
|
|
}) async* {
|
|
final client = http.Client();
|
|
final url = Uri.parse('https://api.deapsound.com/ai/funcchat');
|
|
|
|
List contextsList = [];
|
|
String msg = '';
|
|
for (var i = 0; i < messages.length; i++) {
|
|
Map item = messages[i];
|
|
if (i < messages.length - 1) {
|
|
if (item['role'] == 'user') {
|
|
contextsList.add(item['content']);
|
|
}
|
|
} else {
|
|
msg = item['content'];
|
|
}
|
|
}
|
|
|
|
final headers = {
|
|
'Content-Type': 'application/json',
|
|
'Authorization': apiKey,
|
|
};
|
|
|
|
final requestBody = {"contexts": contextsList, "msg": msg};
|
|
|
|
try {
|
|
final request = http.Request('POST', url)
|
|
..headers.addAll(headers)
|
|
..body = jsonEncode(requestBody);
|
|
final response = await client.send(request);
|
|
|
|
//流式处理响应数据
|
|
await for (final chunk in response.stream
|
|
.transform(utf8.decoder)
|
|
.transform(const LineSplitter())) {
|
|
if (chunk.isEmpty) continue;
|
|
|
|
if (chunk.startsWith('data:')) {
|
|
final jsonStr = chunk.substring(5).trim();
|
|
|
|
try {
|
|
final data = jsonDecode(jsonStr);
|
|
if (data['role'] == 'card') {
|
|
yield data['meta'];
|
|
if (data['meta']['musicaudio'] != null) {
|
|
break;
|
|
}
|
|
}
|
|
if (data['role'] == 'ai') {
|
|
String content = data['content'] ?? '';
|
|
if (content.isNotEmpty) {
|
|
yield content;
|
|
}
|
|
}
|
|
} catch (e) {
|
|
Logger.error('JSON解析错误: $e');
|
|
}
|
|
}
|
|
}
|
|
} catch (e) {
|
|
Logger.error('请求异常: $e');
|
|
} finally {
|
|
client.close();
|
|
}
|
|
}
|
|
}
|
|
|