马良AI写作初始化仓库

This commit is contained in:
邓滨杰
2025-09-10 00:07:52 +08:00
parent 3c06bb1a03
commit 39c0f8840f
1309 changed files with 318528 additions and 0 deletions

View File

@@ -0,0 +1,250 @@
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:ainoval/services/api_service/repositories/universal_ai_repository.dart';
import 'package:ainoval/models/ai_request_models.dart';
import 'package:ainoval/utils/logger.dart';
import 'universal_ai_event.dart';
import 'universal_ai_state.dart';
/// 通用AI请求BLoC
class UniversalAIBloc extends Bloc<UniversalAIEvent, UniversalAIState> {
final UniversalAIRepository _repository;
StreamSubscription? _streamSubscription;
UniversalAIBloc({
required UniversalAIRepository repository,
}) : _repository = repository,
super(const UniversalAIInitial()) {
on<SendAIRequestEvent>(_onSendAIRequest);
on<SendAIStreamRequestEvent>(_onSendAIStreamRequest);
on<PreviewAIRequestEvent>(_onPreviewAIRequest);
on<EstimateCostEvent>(_onEstimateCost);
on<StopStreamRequestEvent>(_onStopStreamRequest);
on<ClearResponseEvent>(_onClearResponse);
on<ResetStateEvent>(_onResetState);
}
/// 处理发送AI请求事件非流式
Future<void> _onSendAIRequest(
SendAIRequestEvent event,
Emitter<UniversalAIState> emit,
) async {
try {
emit(const UniversalAILoading(message: '正在发送请求...'));
AppLogger.d('UniversalAIBloc', '发送非流式AI请求: ${event.request.requestType}');
final response = await _repository.sendRequest(event.request);
emit(UniversalAISuccess(response: response));
AppLogger.d('UniversalAIBloc', '非流式AI请求完成');
} catch (e, stackTrace) {
AppLogger.e('UniversalAIBloc', '发送AI请求失败', e, stackTrace);
emit(UniversalAIError(
message: '请求失败: ${e.toString()}',
details: stackTrace.toString(),
));
}
}
/// 处理发送流式AI请求事件
Future<void> _onSendAIStreamRequest(
SendAIStreamRequestEvent event,
Emitter<UniversalAIState> emit,
) async {
try {
// 先取消之前的流式请求
await _streamSubscription?.cancel();
emit(const UniversalAILoading(message: '正在连接AI服务...'));
AppLogger.d('UniversalAIBloc', '开始流式AI请求: ${event.request.requestType}');
StringBuffer buffer = StringBuffer();
int tokenCount = 0;
bool isStreamCompleted = false;
final stream = _repository.streamRequest(event.request);
// 🚀 使用 emit.forEach 确保在事件处理器内部处理完整个流
await emit.forEach<UniversalAIResponse>(
stream,
onData: (response) {
// 🚀 检查是否收到结束信号
if (response.finishReason != null) {
AppLogger.i('UniversalAIBloc', '收到流式生成结束信号: ${response.finishReason}');
isStreamCompleted = true;
// 🚀 立即返回成功状态,不再发送流式状态
return UniversalAISuccess(
response: UniversalAIResponse(
id: response.id,
requestType: event.request.requestType,
content: buffer.toString(),
finishReason: response.finishReason,
model: response.model,
createdAt: response.createdAt,
metadata: response.metadata,
),
isStreaming: false, // 标记为非流式状态
);
}
// 🚀 只有在未完成时才累积内容
if (!isStreamCompleted && response.content.isNotEmpty) {
buffer.write(response.content);
tokenCount += response.tokenUsage?.completionTokens ?? 1;
//AppLogger.v('UniversalAIBloc', '收到流式响应片段,长度: ${response.content.length}');
return UniversalAIStreaming(
partialResponse: buffer.toString(),
tokenCount: tokenCount,
);
}
// 🚀 如果已完成或内容为空,保持当前状态
return emit.isDone ? const UniversalAIInitial() : const UniversalAIStreaming(partialResponse: '');
},
onError: (error, stackTrace) {
AppLogger.e('UniversalAIBloc', '流式AI请求错误', error, stackTrace);
return UniversalAIError(
message: '流式请求失败: ${error.toString()}',
details: stackTrace.toString(),
);
},
);
// 🚀 如果流正常结束但没有收到结束信号,手动发出成功状态
if (!isStreamCompleted && !emit.isDone) {
AppLogger.d('UniversalAIBloc', '流式AI请求完成无结束信号');
emit(UniversalAISuccess(
response: UniversalAIResponse(
id: DateTime.now().millisecondsSinceEpoch.toString(),
requestType: event.request.requestType,
content: buffer.toString(),
finishReason: 'stop',
),
isStreaming: false,
));
}
} catch (e, stackTrace) {
AppLogger.e('UniversalAIBloc', '流式AI请求失败', e, stackTrace);
emit(UniversalAIError(
message: '流式请求失败: ${e.toString()}',
details: stackTrace.toString(),
));
}
}
/// 处理预览AI请求事件
Future<void> _onPreviewAIRequest(
PreviewAIRequestEvent event,
Emitter<UniversalAIState> emit,
) async {
try {
emit(const UniversalAILoading(message: '正在生成预览...'));
AppLogger.d('UniversalAIBloc', '预览AI请求: ${event.request.requestType}');
final previewResponse = await _repository.previewRequest(event.request);
emit(UniversalAIPreviewSuccess(
previewResponse: previewResponse,
request: event.request,
));
AppLogger.d('UniversalAIBloc', '预览生成完成');
} catch (e, stackTrace) {
AppLogger.e('UniversalAIBloc', '预览AI请求失败', e, stackTrace);
emit(UniversalAIError(
message: '预览失败: ${e.toString()}',
details: stackTrace.toString(),
));
}
}
/// 🚀 新增:处理积分预估事件
Future<void> _onEstimateCost(
EstimateCostEvent event,
Emitter<UniversalAIState> emit,
) async {
try {
emit(const UniversalAILoading(message: '正在预估积分成本...'));
AppLogger.d('UniversalAIBloc', '预估AI请求积分成本: ${event.request.requestType}');
final costEstimation = await _repository.estimateCost(event.request);
if (costEstimation.success) {
emit(UniversalAICostEstimationSuccess(
costEstimation: costEstimation,
request: event.request,
));
AppLogger.d('UniversalAIBloc', '积分预估完成: ${costEstimation.estimatedCost}积分');
} else {
emit(UniversalAIError(
message: costEstimation.errorMessage ?? '积分预估失败',
canRetry: true,
));
}
} catch (e, stackTrace) {
AppLogger.e('UniversalAIBloc', '积分预估失败', e, stackTrace);
emit(UniversalAIError(
message: '积分预估失败: ${e.toString()}',
details: stackTrace.toString(),
canRetry: true,
));
}
}
/// 处理停止流式请求事件
Future<void> _onStopStreamRequest(
StopStreamRequestEvent event,
Emitter<UniversalAIState> emit,
) async {
AppLogger.d('UniversalAIBloc', '停止流式请求');
await _streamSubscription?.cancel();
_streamSubscription = null;
// 保留当前的部分响应
String? partialResponse;
if (state is UniversalAIStreaming) {
partialResponse = (state as UniversalAIStreaming).partialResponse;
}
emit(UniversalAICancelled(partialResponse: partialResponse));
}
/// 处理清除响应事件
Future<void> _onClearResponse(
ClearResponseEvent event,
Emitter<UniversalAIState> emit,
) async {
AppLogger.d('UniversalAIBloc', '清除响应');
emit(const UniversalAIInitial());
}
/// 处理重置状态事件
Future<void> _onResetState(
ResetStateEvent event,
Emitter<UniversalAIState> emit,
) async {
AppLogger.d('UniversalAIBloc', '重置状态');
await _streamSubscription?.cancel();
_streamSubscription = null;
emit(const UniversalAIInitial());
}
@override
Future<void> close() {
_streamSubscription?.cancel();
return super.close();
}
}

View File

@@ -0,0 +1,65 @@
import 'package:ainoval/models/ai_request_models.dart';
import 'package:equatable/equatable.dart';
/// 通用AI请求事件基类
abstract class UniversalAIEvent extends Equatable {
const UniversalAIEvent();
@override
List<Object?> get props => [];
}
/// 发送AI请求事件非流式
class SendAIRequestEvent extends UniversalAIEvent {
const SendAIRequestEvent(this.request);
final UniversalAIRequest request;
@override
List<Object?> get props => [request];
}
/// 发送流式AI请求事件
class SendAIStreamRequestEvent extends UniversalAIEvent {
const SendAIStreamRequestEvent(this.request);
final UniversalAIRequest request;
@override
List<Object?> get props => [request];
}
/// 预览AI请求事件
class PreviewAIRequestEvent extends UniversalAIEvent {
const PreviewAIRequestEvent(this.request);
final UniversalAIRequest request;
@override
List<Object?> get props => [request];
}
/// 停止流式请求事件
class StopStreamRequestEvent extends UniversalAIEvent {
const StopStreamRequestEvent();
}
/// 清除响应事件
class ClearResponseEvent extends UniversalAIEvent {
const ClearResponseEvent();
}
/// 重置状态事件
class ResetStateEvent extends UniversalAIEvent {
const ResetStateEvent();
}
/// 🚀 新增:积分预估事件
class EstimateCostEvent extends UniversalAIEvent {
const EstimateCostEvent(this.request);
final UniversalAIRequest request;
@override
List<Object?> get props => [request];
}

View File

@@ -0,0 +1,113 @@
import 'package:ainoval/models/ai_request_models.dart';
import 'package:equatable/equatable.dart';
/// 通用AI请求状态基类
abstract class UniversalAIState extends Equatable {
const UniversalAIState();
@override
List<Object?> get props => [];
}
/// 初始状态
class UniversalAIInitial extends UniversalAIState {
const UniversalAIInitial();
}
/// 加载中状态
class UniversalAILoading extends UniversalAIState {
const UniversalAILoading({
this.progress,
this.message,
});
final double? progress;
final String? message;
@override
List<Object?> get props => [progress, message];
}
/// 流式响应进行中状态
class UniversalAIStreaming extends UniversalAIState {
const UniversalAIStreaming({
required this.partialResponse,
this.tokenCount = 0,
});
final String partialResponse;
final int tokenCount;
@override
List<Object?> get props => [partialResponse, tokenCount];
}
/// 请求成功状态
class UniversalAISuccess extends UniversalAIState {
const UniversalAISuccess({
required this.response,
this.isStreaming = false,
});
final UniversalAIResponse response;
final bool isStreaming;
@override
List<Object?> get props => [response, isStreaming];
}
/// 预览成功状态
class UniversalAIPreviewSuccess extends UniversalAIState {
const UniversalAIPreviewSuccess({
required this.previewResponse,
required this.request,
});
final UniversalAIPreviewResponse previewResponse;
final UniversalAIRequest request;
@override
List<Object?> get props => [previewResponse, request];
}
/// 错误状态
class UniversalAIError extends UniversalAIState {
const UniversalAIError({
required this.message,
this.details,
this.canRetry = true,
});
final String message;
final String? details;
final bool canRetry;
@override
List<Object?> get props => [message, details, canRetry];
}
/// 请求被取消状态
class UniversalAICancelled extends UniversalAIState {
const UniversalAICancelled({
this.partialResponse,
});
final String? partialResponse;
@override
List<Object?> get props => [partialResponse];
}
/// 🚀 新增:积分预估成功状态
class UniversalAICostEstimationSuccess extends UniversalAIState {
const UniversalAICostEstimationSuccess({
required this.costEstimation,
required this.request,
});
final CostEstimationResponse costEstimation;
final UniversalAIRequest request;
@override
List<Object?> get props => [costEstimation, request];
}