refactor: 重构聊天数据层至core并简化首页UI
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:social_app/core/chat/chat_api.dart';
|
||||
import 'package:social_app/data/network/i_api_client.dart';
|
||||
|
||||
class ChatApiImpl implements ChatApi {
|
||||
ChatApiImpl(this._apiClient);
|
||||
|
||||
final IApiClient _apiClient;
|
||||
|
||||
@override
|
||||
Future<Map<String, dynamic>> createRun(Map<String, dynamic> runInput) async {
|
||||
final response = await _apiClient.post<Map<String, dynamic>>(
|
||||
'/api/v1/agent/runs',
|
||||
data: runInput,
|
||||
);
|
||||
final payload = response.data;
|
||||
if (payload is! Map<String, dynamic>) {
|
||||
throw StateError('Invalid /agent/runs response');
|
||||
}
|
||||
return payload;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Stream<String>> streamRunEvents(
|
||||
String threadId, {
|
||||
String? lastEventId,
|
||||
}) {
|
||||
final headers = <String, String>{'Accept': 'text/event-stream'};
|
||||
if (lastEventId != null && lastEventId.isNotEmpty) {
|
||||
headers['Last-Event-ID'] = lastEventId;
|
||||
}
|
||||
return _apiClient.getSseLines(
|
||||
'/api/v1/agent/runs/$threadId/events',
|
||||
headers: headers,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Map<String, dynamic>> fetchHistory({
|
||||
String? threadId,
|
||||
DateTime? beforeDate,
|
||||
}) async {
|
||||
final path = _buildHistoryPath(threadId: threadId, beforeDate: beforeDate);
|
||||
final response = await _apiClient.get<Map<String, dynamic>>(path);
|
||||
final payload = response.data;
|
||||
if (payload is! Map<String, dynamic>) {
|
||||
throw StateError('Invalid /agent/history response');
|
||||
}
|
||||
return payload;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Map<String, dynamic>> uploadAttachment({
|
||||
required String threadId,
|
||||
required String filename,
|
||||
required String mimeType,
|
||||
required Uint8List bytes,
|
||||
}) async {
|
||||
final formData = FormData.fromMap({
|
||||
'threadId': threadId,
|
||||
'file': MultipartFile.fromBytes(
|
||||
bytes,
|
||||
filename: filename,
|
||||
contentType: DioMediaType.parse(mimeType),
|
||||
),
|
||||
});
|
||||
final response = await _apiClient.post<Map<String, dynamic>>(
|
||||
'/api/v1/agent/attachments',
|
||||
data: formData,
|
||||
);
|
||||
final payload = response.data;
|
||||
if (payload is! Map<String, dynamic>) {
|
||||
throw StateError('Invalid /agent/attachments response');
|
||||
}
|
||||
return payload;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Uint8List> fetchAttachmentPreview(String previewPath) async {
|
||||
final response = await _apiClient.get<List<int>>(
|
||||
previewPath,
|
||||
options: Options(responseType: ResponseType.bytes),
|
||||
);
|
||||
final payload = response.data;
|
||||
if (payload is! List<int>) {
|
||||
throw StateError('Invalid attachment payload');
|
||||
}
|
||||
return Uint8List.fromList(payload);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String> transcribeAudio(String filePath) async {
|
||||
final formData = FormData.fromMap({
|
||||
'audio': await MultipartFile.fromFile(
|
||||
filePath,
|
||||
filename: 'recording.wav',
|
||||
contentType: DioMediaType('audio', 'wav'),
|
||||
),
|
||||
});
|
||||
final response = await _apiClient.post<Map<String, dynamic>>(
|
||||
'/api/v1/agent/transcribe',
|
||||
data: formData,
|
||||
);
|
||||
final payload = response.data;
|
||||
if (payload is! Map<String, dynamic>) {
|
||||
throw StateError('Invalid /agent/transcribe response');
|
||||
}
|
||||
final transcript = payload['transcript'];
|
||||
if (transcript is! String) {
|
||||
throw StateError('Missing transcript in /agent/transcribe response');
|
||||
}
|
||||
return transcript;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> cancelRun({
|
||||
required String threadId,
|
||||
required String runId,
|
||||
}) async {
|
||||
final encodedRunId = Uri.encodeQueryComponent(runId);
|
||||
await _apiClient.post<Map<String, dynamic>>(
|
||||
'/api/v1/agent/runs/$threadId/cancel?runId=$encodedRunId',
|
||||
);
|
||||
}
|
||||
|
||||
static String _buildHistoryPath({String? threadId, DateTime? beforeDate}) {
|
||||
final query = <String>[];
|
||||
if (threadId != null && threadId.isNotEmpty) {
|
||||
query.add('threadId=${Uri.encodeQueryComponent(threadId)}');
|
||||
}
|
||||
if (beforeDate != null) {
|
||||
final day = DateTime(beforeDate.year, beforeDate.month, beforeDate.day);
|
||||
query.add('before=${day.toIso8601String().substring(0, 10)}');
|
||||
}
|
||||
if (query.isEmpty) {
|
||||
return '/api/v1/agent/history';
|
||||
}
|
||||
return '/api/v1/agent/history?${query.join('&')}';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user