Save verified Mithqal AI project progress
This commit is contained in:
+109
-8
@@ -14,9 +14,42 @@ class ChatCubit extends Cubit<ChatState> {
|
||||
Future<void> _loadModelName() async {
|
||||
try {
|
||||
final modelName = await _api.getModelName();
|
||||
if (!isClosed) emit(state.copyWith(modelName: modelName));
|
||||
final models = await _api.getAvailableModels();
|
||||
if (!isClosed) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
modelName: modelName,
|
||||
availableModels: models,
|
||||
selectedModel: state.selectedModel ?? modelName,
|
||||
),
|
||||
);
|
||||
}
|
||||
} catch (_) {
|
||||
if (!isClosed) emit(state.copyWith(modelName: 'تعذر الاتصال بالخادم'));
|
||||
if (!isClosed) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
modelName: 'تعذر الاتصال بالخادم',
|
||||
availableModels: const [],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void selectModel(String model) {
|
||||
if (state.availableModels.contains(model)) {
|
||||
emit(state.copyWith(selectedModel: model, clearError: true));
|
||||
}
|
||||
}
|
||||
|
||||
void toggleWorkspaceMode() {
|
||||
if (!state.isSending) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
isWorkspaceMode: !state.isWorkspaceMode,
|
||||
clearError: true,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,20 +109,79 @@ class ChatCubit extends Cubit<ChatState> {
|
||||
}
|
||||
|
||||
Future<void> send(String text) async {
|
||||
await _sendWithHistory(text, state.messages);
|
||||
}
|
||||
|
||||
Future<void> regenerateLastAnswer() async {
|
||||
if (state.isSending) return;
|
||||
final messages = state.messages;
|
||||
if (messages.length < 2 ||
|
||||
messages.last.fromUser ||
|
||||
!messages[messages.length - 2].fromUser) {
|
||||
return;
|
||||
}
|
||||
final history = messages.sublist(0, messages.length - 1);
|
||||
await _sendWithHistory(
|
||||
history.last.text,
|
||||
history,
|
||||
appendUserMessage: false,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> editLastQuestion(String text) async {
|
||||
if (state.isSending || text.trim().isEmpty) return;
|
||||
final messages = state.messages;
|
||||
final questionIndex = messages.lastIndexWhere(
|
||||
(message) => message.fromUser,
|
||||
);
|
||||
if (questionIndex < 0 || questionIndex != messages.length - 2) return;
|
||||
final history = [
|
||||
...messages.take(questionIndex),
|
||||
ChatMessage(text.trim(), fromUser: true),
|
||||
];
|
||||
await _sendWithHistory(text.trim(), history, appendUserMessage: false);
|
||||
}
|
||||
|
||||
Future<void> _sendWithHistory(
|
||||
String text,
|
||||
List<ChatMessage> history, {
|
||||
bool appendUserMessage = true,
|
||||
}) async {
|
||||
final prompt = text.trim();
|
||||
if (prompt.isEmpty || state.isSending || state.isLoadingHistory) return;
|
||||
final messages = [...state.messages, ChatMessage(prompt, fromUser: true)];
|
||||
final messages =
|
||||
appendUserMessage
|
||||
? [...history, ChatMessage(prompt, fromUser: true)]
|
||||
: List<ChatMessage>.from(history);
|
||||
final originalMessages = state.messages;
|
||||
var answer = '';
|
||||
emit(state.copyWith(messages: messages, isSending: true, clearError: true));
|
||||
try {
|
||||
await _saveCurrent(messages);
|
||||
if (appendUserMessage) await _saveCurrent(messages);
|
||||
if (isClosed) return;
|
||||
emit(
|
||||
state.copyWith(
|
||||
messages: [...messages, const ChatMessage('', fromUser: false)],
|
||||
),
|
||||
);
|
||||
await for (final delta in _api.completeStream(messages)) {
|
||||
if (state.isWorkspaceMode) {
|
||||
answer = await _api.askWorkspaceAgent(
|
||||
prompt,
|
||||
model: state.selectedModel,
|
||||
);
|
||||
if (isClosed) return;
|
||||
if (answer.trim().isEmpty) {
|
||||
throw Exception('لم يصل نص في إجابة الوكيل.');
|
||||
}
|
||||
final updated = [...messages, ChatMessage(answer, fromUser: false)];
|
||||
emit(state.copyWith(messages: updated, isSending: false));
|
||||
await _saveCurrent(updated);
|
||||
return;
|
||||
}
|
||||
await for (final delta in _api.completeStream(
|
||||
messages,
|
||||
model: state.selectedModel,
|
||||
)) {
|
||||
if (isClosed) return;
|
||||
answer += delta;
|
||||
emit(
|
||||
@@ -106,7 +198,9 @@ class ChatCubit extends Cubit<ChatState> {
|
||||
} catch (error) {
|
||||
if (isClosed) return;
|
||||
final partial =
|
||||
answer.isEmpty
|
||||
!appendUserMessage
|
||||
? originalMessages
|
||||
: answer.isEmpty
|
||||
? messages
|
||||
: [...messages, ChatMessage(answer, fromUser: false)];
|
||||
emit(
|
||||
@@ -116,7 +210,7 @@ class ChatCubit extends Cubit<ChatState> {
|
||||
error: error.toString(),
|
||||
),
|
||||
);
|
||||
if (answer.isNotEmpty) {
|
||||
if (appendUserMessage && answer.isNotEmpty) {
|
||||
try {
|
||||
await _saveCurrent(partial);
|
||||
} catch (_) {
|
||||
@@ -181,7 +275,14 @@ class ChatCubit extends Cubit<ChatState> {
|
||||
final url = value.trim();
|
||||
if (url.isEmpty) return;
|
||||
_api.setBaseUrl(url);
|
||||
emit(state.copyWith(apiBaseUrl: _api.baseUrl, clearError: true));
|
||||
emit(
|
||||
state.copyWith(
|
||||
apiBaseUrl: _api.baseUrl,
|
||||
availableModels: const [],
|
||||
clearSelectedModel: true,
|
||||
clearError: true,
|
||||
),
|
||||
);
|
||||
_loadModelName();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,8 +59,11 @@ class ChatState {
|
||||
this.activeConversationId,
|
||||
this.isLoadingHistory = true,
|
||||
this.isSending = false,
|
||||
this.isWorkspaceMode = false,
|
||||
this.error,
|
||||
this.modelName = 'جارٍ اكتشاف النموذج…',
|
||||
this.availableModels = const [],
|
||||
this.selectedModel,
|
||||
required this.apiBaseUrl,
|
||||
});
|
||||
|
||||
@@ -69,8 +72,11 @@ class ChatState {
|
||||
final String? activeConversationId;
|
||||
final bool isLoadingHistory;
|
||||
final bool isSending;
|
||||
final bool isWorkspaceMode;
|
||||
final String? error;
|
||||
final String modelName;
|
||||
final List<String> availableModels;
|
||||
final String? selectedModel;
|
||||
final String apiBaseUrl;
|
||||
|
||||
ChatState copyWith({
|
||||
@@ -80,9 +86,13 @@ class ChatState {
|
||||
bool clearActiveConversation = false,
|
||||
bool? isLoadingHistory,
|
||||
bool? isSending,
|
||||
bool? isWorkspaceMode,
|
||||
String? error,
|
||||
bool clearError = false,
|
||||
String? modelName,
|
||||
List<String>? availableModels,
|
||||
String? selectedModel,
|
||||
bool clearSelectedModel = false,
|
||||
String? apiBaseUrl,
|
||||
}) => ChatState(
|
||||
messages: messages ?? this.messages,
|
||||
@@ -93,8 +103,12 @@ class ChatState {
|
||||
: (activeConversationId ?? this.activeConversationId),
|
||||
isLoadingHistory: isLoadingHistory ?? this.isLoadingHistory,
|
||||
isSending: isSending ?? this.isSending,
|
||||
isWorkspaceMode: isWorkspaceMode ?? this.isWorkspaceMode,
|
||||
error: clearError ? null : (error ?? this.error),
|
||||
modelName: modelName ?? this.modelName,
|
||||
availableModels: availableModels ?? this.availableModels,
|
||||
selectedModel:
|
||||
clearSelectedModel ? null : (selectedModel ?? this.selectedModel),
|
||||
apiBaseUrl: apiBaseUrl ?? this.apiBaseUrl,
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user