mirror of
https://github.com/foss42/apidash.git
synced 2025-12-02 10:49:49 +08:00
refactor: remove unused Message class; update AI model handling in ChatViewmodel
This commit is contained in:
@@ -1,16 +1,5 @@
|
|||||||
import '../view/widgets/chat_bubble.dart';
|
import '../view/widgets/chat_bubble.dart';
|
||||||
|
|
||||||
// Create a Message class that extends the existing ChatMessage for compatibility
|
|
||||||
class Message extends ChatMessage {
|
|
||||||
const Message({
|
|
||||||
required super.id,
|
|
||||||
required super.content,
|
|
||||||
required super.role,
|
|
||||||
required super.timestamp,
|
|
||||||
required super.messageType,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
class ChatState {
|
class ChatState {
|
||||||
final Map<String, List<ChatMessage>> chatSessions; // requestId -> messages
|
final Map<String, List<ChatMessage>> chatSessions; // requestId -> messages
|
||||||
final bool isGenerating;
|
final bool isGenerating;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'package:apidash_core/apidash_core.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:genai/genai.dart' as genai;
|
|
||||||
import 'package:apidash/providers/providers.dart';
|
import 'package:apidash/providers/providers.dart';
|
||||||
import 'package:apidash/models/models.dart';
|
import 'package:apidash/models/models.dart';
|
||||||
import 'package:nanoid/nanoid.dart';
|
import 'package:nanoid/nanoid.dart';
|
||||||
@@ -20,11 +20,11 @@ class ChatViewmodel extends StateNotifier<ChatState> {
|
|||||||
ChatRemoteRepository get _repo => _ref.read(chatRepositoryProvider);
|
ChatRemoteRepository get _repo => _ref.read(chatRepositoryProvider);
|
||||||
// Currently selected request and AI model are read from app providers
|
// Currently selected request and AI model are read from app providers
|
||||||
RequestModel? get _currentRequest => _ref.read(selectedRequestModelProvider);
|
RequestModel? get _currentRequest => _ref.read(selectedRequestModelProvider);
|
||||||
genai.AIRequestModel? get _selectedAIModel {
|
AIRequestModel? get _selectedAIModel {
|
||||||
final json = _ref.read(settingsProvider).defaultAIModel;
|
final json = _ref.read(settingsProvider).defaultAIModel;
|
||||||
if (json == null) return null;
|
if (json == null) return null;
|
||||||
try {
|
try {
|
||||||
return genai.AIRequestModel.fromJson(json);
|
return AIRequestModel.fromJson(json);
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -40,9 +40,12 @@ class ChatViewmodel extends StateNotifier<ChatState> {
|
|||||||
ChatMessageType type = ChatMessageType.general,
|
ChatMessageType type = ChatMessageType.general,
|
||||||
bool countAsUser = true,
|
bool countAsUser = true,
|
||||||
}) async {
|
}) async {
|
||||||
|
debugPrint(
|
||||||
|
'[Chat] sendMessage start: type=$type, countAsUser=$countAsUser');
|
||||||
final ai = _selectedAIModel;
|
final ai = _selectedAIModel;
|
||||||
if (text.trim().isEmpty && countAsUser) return;
|
if (text.trim().isEmpty && countAsUser) return;
|
||||||
if (ai == null) {
|
if (ai == null) {
|
||||||
|
debugPrint('[Chat] No AI model configured');
|
||||||
_appendSystem(
|
_appendSystem(
|
||||||
'AI model is not configured. Please set one in AI Request tab.',
|
'AI model is not configured. Please set one in AI Request tab.',
|
||||||
type,
|
type,
|
||||||
@@ -51,6 +54,7 @@ class ChatViewmodel extends StateNotifier<ChatState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final requestId = _currentRequest?.id ?? 'global';
|
final requestId = _currentRequest?.id ?? 'global';
|
||||||
|
debugPrint('[Chat] using requestId=$requestId');
|
||||||
|
|
||||||
if (countAsUser) {
|
if (countAsUser) {
|
||||||
_addMessage(
|
_addMessage(
|
||||||
@@ -66,26 +70,38 @@ class ChatViewmodel extends StateNotifier<ChatState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final systemPrompt = _composeSystemPrompt(_currentRequest, type);
|
final systemPrompt = _composeSystemPrompt(_currentRequest, type);
|
||||||
|
final userPrompt = (text.trim().isEmpty && !countAsUser)
|
||||||
|
? 'Please complete the task based on the provided context.'
|
||||||
|
: text;
|
||||||
final enriched = ai.copyWith(
|
final enriched = ai.copyWith(
|
||||||
systemPrompt: systemPrompt,
|
systemPrompt: systemPrompt,
|
||||||
userPrompt: text,
|
userPrompt: userPrompt,
|
||||||
stream: true,
|
stream: true,
|
||||||
);
|
);
|
||||||
|
debugPrint(
|
||||||
|
'[Chat] prompts prepared: system=${systemPrompt.length} chars, user=${userPrompt.length} chars');
|
||||||
|
|
||||||
// start stream
|
// start stream
|
||||||
_sub?.cancel();
|
_sub?.cancel();
|
||||||
state = state.copyWith(isGenerating: true, currentStreamingResponse: '');
|
state = state.copyWith(isGenerating: true, currentStreamingResponse: '');
|
||||||
|
bool receivedAnyChunk = false;
|
||||||
_sub = _repo.streamChat(request: enriched).listen(
|
_sub = _repo.streamChat(request: enriched).listen(
|
||||||
(chunk) {
|
(chunk) {
|
||||||
|
receivedAnyChunk = true;
|
||||||
|
if (chunk.isEmpty) return;
|
||||||
|
debugPrint('[Chat] chunk(${chunk.length})');
|
||||||
state = state.copyWith(
|
state = state.copyWith(
|
||||||
currentStreamingResponse: state.currentStreamingResponse + (chunk),
|
currentStreamingResponse: state.currentStreamingResponse + (chunk),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
onError: (e) {
|
onError: (e) {
|
||||||
|
debugPrint('[Chat] stream error: $e');
|
||||||
state = state.copyWith(isGenerating: false);
|
state = state.copyWith(isGenerating: false);
|
||||||
_appendSystem('Error: $e', type);
|
_appendSystem('Error: $e', type);
|
||||||
},
|
},
|
||||||
onDone: () {
|
onDone: () async {
|
||||||
|
debugPrint(
|
||||||
|
'[Chat] stream done. total=${state.currentStreamingResponse.length}, anyChunk=$receivedAnyChunk');
|
||||||
if (state.currentStreamingResponse.isNotEmpty) {
|
if (state.currentStreamingResponse.isNotEmpty) {
|
||||||
_addMessage(
|
_addMessage(
|
||||||
requestId,
|
requestId,
|
||||||
@@ -97,6 +113,31 @@ class ChatViewmodel extends StateNotifier<ChatState> {
|
|||||||
messageType: type,
|
messageType: type,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
} else if (!receivedAnyChunk) {
|
||||||
|
// Fallback to non-streaming request
|
||||||
|
debugPrint(
|
||||||
|
'[Chat] no streamed content; attempting non-streaming fallback');
|
||||||
|
try {
|
||||||
|
final fallback =
|
||||||
|
await _repo.sendChat(request: enriched.copyWith(stream: false));
|
||||||
|
if (fallback != null && fallback.isNotEmpty) {
|
||||||
|
_addMessage(
|
||||||
|
requestId,
|
||||||
|
ChatMessage(
|
||||||
|
id: nanoid(),
|
||||||
|
content: fallback,
|
||||||
|
role: MessageRole.system,
|
||||||
|
timestamp: DateTime.now(),
|
||||||
|
messageType: type,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
_appendSystem('No response received from the AI.', type);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
debugPrint('[Chat] fallback error: $err');
|
||||||
|
_appendSystem('Error: $err', type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
state = state.copyWith(
|
state = state.copyWith(
|
||||||
isGenerating: false,
|
isGenerating: false,
|
||||||
|
|||||||
Reference in New Issue
Block a user