No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.
 
 
 
 
 
 

260 líneas
8.2 KiB

  1. import 'dart:convert';
  2. import 'dart:io';
  3. import 'package:dio/dio.dart';
  4. import 'package:logger/logger.dart';
  5. import 'package:http/http.dart' as http;
  6. class ApiClient {
  7. static final _client = Dio();
  8. static String _baseUrl = 'https://www.aitoyyun.com';
  9. static get(
  10. {String baseUrl = 'https://www.aitoyyun.com',
  11. required String url,
  12. required Map<String, dynamic> param,
  13. required Function(Map<String, dynamic>) onSuccess,
  14. required Function(String) onFailed}) async {
  15. _baseUrl = baseUrl;
  16. try {
  17. Response response = await _client.get(
  18. _baseUrl + url.trim(),
  19. options: Options(
  20. headers: {"Accept": 'application/json'},
  21. sendTimeout: const Duration(seconds: 10),
  22. receiveTimeout: const Duration(seconds: 10)),
  23. queryParameters: param,
  24. );
  25. final jsonData = response.data;
  26. _progressData(
  27. jsonData: jsonData, onSuccess: onSuccess, onFailed: onFailed);
  28. } on DioException catch (e) {
  29. _progressError(response: e.response, onFailed: onFailed);
  30. }
  31. }
  32. static post(
  33. {required String url,
  34. String? token,
  35. required Map<String, dynamic> param,
  36. required Function(Map<String, dynamic>) onSuccess,
  37. required Function(String) onFailed}) async {
  38. try {
  39. // Logger().i('---url: ${_baseUrl + url.trim()}---param: $param-----token: $token');
  40. Response response = await _client.post(
  41. _baseUrl + url.trim(),
  42. options: Options(
  43. headers: {'Authorization': token ?? ''},
  44. sendTimeout: const Duration(seconds: 10),
  45. receiveTimeout: const Duration(seconds: 10)),
  46. queryParameters: param,
  47. data: param,
  48. );
  49. final jsonData = response.data;
  50. _progressData(
  51. jsonData: jsonData, onSuccess: onSuccess, onFailed: onFailed);
  52. } on DioException catch (e) {
  53. _progressError(response: e.response, onFailed: onFailed);
  54. }
  55. }
  56. static put(
  57. {required String url,
  58. required Map<String, dynamic> param,
  59. required Function(Map<String, dynamic>) onSuccess,
  60. required Function(String) onFailed}) async {
  61. try {
  62. Response response = await _client.put(
  63. _baseUrl + url.trim(),
  64. options: Options(
  65. headers: {"Accept": 'application/json'},
  66. sendTimeout: const Duration(seconds: 10),
  67. receiveTimeout: const Duration(seconds: 10)),
  68. queryParameters: param,
  69. data: param,
  70. );
  71. final jsonData = response.data;
  72. _progressData(
  73. jsonData: jsonData, onSuccess: onSuccess, onFailed: onFailed);
  74. } on DioException catch (e) {
  75. _progressError(response: e.response, onFailed: onFailed);
  76. }
  77. }
  78. static delete(
  79. {required String url,
  80. required Map<String, dynamic> param,
  81. required Function(Map<String, dynamic>) onSuccess,
  82. required Function(String) onFailed}) async {
  83. try {
  84. Response response = await _client.delete(
  85. _baseUrl + url.trim(),
  86. options: Options(
  87. headers: {"Accept": 'application/json'},
  88. sendTimeout: const Duration(seconds: 10),
  89. receiveTimeout: const Duration(seconds: 10)),
  90. queryParameters: param,
  91. data: param,
  92. );
  93. final jsonData = response.data;
  94. _progressData(
  95. jsonData: jsonData, onSuccess: onSuccess, onFailed: onFailed);
  96. } on DioException catch (e) {
  97. _progressError(response: e.response, onFailed: onFailed);
  98. }
  99. }
  100. static void _progressData(
  101. {required Map<String, dynamic> jsonData,
  102. required Function(Map<String, dynamic>) onSuccess,
  103. required Function(String) onFailed}) {
  104. // Logger().i('--_progressData------${jsonData}');
  105. if (jsonData['code'] == 0) {
  106. onSuccess(jsonData);
  107. } else {
  108. onFailed(jsonData['msg'].toString());
  109. }
  110. }
  111. static void _progressError(
  112. {Response? response, required Function(String) onFailed}) {
  113. if (response != null && response.data != null) {
  114. Logger().i('_progressError---------${response.data}');
  115. if (response.data.runtimeType == String) {
  116. onFailed('返回数据格式错误');
  117. } else {
  118. if (response.data['errCode'] != null) {
  119. final jsonData = response.data;
  120. onFailed(jsonData['errMsg'].toString());
  121. } else {
  122. final jsonData = response.data;
  123. onFailed(jsonData['state']['msg'].toString());
  124. }
  125. }
  126. } else {
  127. onFailed('请求失败');
  128. }
  129. }
  130. static final String login = '/api/home/user_sgin';
  131. static final String getPin = '/api/home/user_verification';
  132. // static final String aiChat = '/api/home/ai_chat';
  133. static final String deepseekApiKey = 'sk-3adfd188a3134e718bbf704f525aff17';
  134. static Stream<String> aiChat(String prompt) async* {
  135. final client = HttpClient();
  136. try {
  137. final request = await client
  138. .postUrl(Uri.parse('https://api.deepseek.com/chat/completions'));
  139. // 设置流式请求头
  140. request.headers
  141. ..set('Content-Type', 'application/json')
  142. ..set('Authorization', 'Bearer $deepseekApiKey')
  143. ..set('Accept', 'text/event-stream');
  144. // 构建请求体
  145. final requestBody = jsonEncode({
  146. 'model': 'deepseek-chat',
  147. 'stream': true,
  148. 'messages': [
  149. {'role': 'user', 'content': prompt}
  150. ]
  151. });
  152. // 写入请求体
  153. request.add(utf8.encode(requestBody));
  154. final response = await request.close();
  155. // 检查状态码
  156. if (response.statusCode != 200) {
  157. throw Exception('API请求失败: ${response.statusCode}');
  158. }
  159. // 处理流数据
  160. String buffer = '';
  161. await for (final chunk in response.transform(utf8.decoder)) {
  162. buffer += chunk;
  163. // 分割完整事件(假设使用SSE格式)
  164. while (buffer.contains('\n\n')) {
  165. final eventEnd = buffer.indexOf('\n\n');
  166. final event = buffer.substring(0, eventEnd);
  167. buffer = buffer.substring(eventEnd + 2);
  168. if (event.startsWith('data: ')) {
  169. final dataContent = event.substring(6);
  170. // 增加有效性检查
  171. if (dataContent == '[DONE]') {
  172. // print('流式传输结束');
  173. continue; // 跳过特殊结束标记
  174. }
  175. final jsonData = jsonDecode(event.substring(6));
  176. yield jsonData['choices'][0]['delta']['content'];
  177. }
  178. }
  179. }
  180. } finally {
  181. client.close();
  182. }
  183. }
  184. static final String dbAppkey = '418ec475-e2dc-4b76-8aca-842d81bc3466';
  185. static final String dbModelId = 'ep-20250203161136-9lrxg';
  186. static Stream<String> dbChat(String userMessage) async* {
  187. final client = http.Client();
  188. final url =
  189. Uri.parse('https://ark.cn-beijing.volces.com/api/v3/chat/completions');
  190. final headers = {
  191. 'Content-Type': 'application/json',
  192. 'Authorization': 'Bearer $dbAppkey',
  193. };
  194. final requestBody = {
  195. "model": dbModelId,
  196. "messages": [
  197. {"role": "system", "content": "你是豆包,是由字节跳动开发的 AI 人工智能助手."},
  198. {"role": "user", "content": userMessage}
  199. ],
  200. "stream": true,
  201. };
  202. try {
  203. final request = http.Request('POST', url)
  204. ..headers.addAll(headers)
  205. ..body = jsonEncode(requestBody);
  206. final response = await client.send(request);
  207. //流式处理响应数据
  208. await for (final chunk in response.stream
  209. .transform(utf8.decoder)
  210. .transform(const LineSplitter())) {
  211. if (chunk.isEmpty) continue;
  212. // 假设豆包API使用类似OpenAI的流式格式(data: {...})
  213. if (chunk.startsWith('data:')) {
  214. final jsonStr = chunk.substring(5).trim();
  215. if (jsonStr == '[DONE]') break; // 流结束标志
  216. try {
  217. final data = jsonDecode(jsonStr);
  218. final content = data['choices'][0]['delta']['content'] ?? '';
  219. if (content.isNotEmpty) {
  220. yield content; // 逐块返回生成的文本
  221. }
  222. } catch (e) {
  223. // print('JSON解析错误: $e');
  224. }
  225. // print('请求成功: $jsonStr');
  226. }
  227. }
  228. } catch (e) {
  229. print('请求异常: $e');
  230. }
  231. }
  232. }