- add system prompt

- add new deepseek r1 model
- fix stream builder
- show streaming complete check
This commit is contained in:
2025-01-30 12:55:50 +02:00
parent 90b6c16f13
commit 57ca02db58

View File

@@ -36,7 +36,7 @@ class _AiChatState extends State<AiChat> {
late types.User _user; late types.User _user;
late types.User _mihAI; late types.User _mihAI;
String systemPromt = String systemPromt =
"You are a helpful and friendly AI assistant. You are running on a system called MIH which was created by \"Mzansi Innovation Hub\" a South African based company."; "You are a helpful and friendly AI assistant. You are running on a system called 'MIH' which was created by 'Mzansi Innovation Hub' a South African based company. The name we have given you is 'Mzansi Ai'. Please keep your thinking to a few paragraphs and your answer to one short paragraph.";
bool _aiThinking = false; bool _aiThinking = false;
final client = ollama.OllamaClient( final client = ollama.OllamaClient(
baseUrl: "${AppEnviroment.baseAiUrl}/api", baseUrl: "${AppEnviroment.baseAiUrl}/api",
@@ -50,6 +50,17 @@ class _AiChatState extends State<AiChat> {
}); });
} }
void _loadMessages() async {
final response = await rootBundle.loadString('assets/messages.json');
final messages = (jsonDecode(response) as List)
.map((e) => types.Message.fromJson(e as Map<String, dynamic>))
.toList();
setState(() {
_messages = messages;
});
}
void _handleSendPressed(types.PartialText message) { void _handleSendPressed(types.PartialText message) {
final textMessage = types.TextMessage( final textMessage = types.TextMessage(
author: _user, author: _user,
@@ -94,13 +105,9 @@ class _AiChatState extends State<AiChat> {
Widget responseWindow( Widget responseWindow(
Stream<String> aiChatStream, Stream<String> aiChatStream,
// StreamSubscription<String> aiChatSubscription,
) { ) {
StreamSubscription<String> aiChatSubscription =
aiChatStream.listen((response) {});
types.TextMessage textMessage;
return StreamBuilder( return StreamBuilder(
stream: _generateChatCompletionWithHistoryStream("", client), stream: aiChatStream,
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.hasData) { if (snapshot.hasData) {
return MihAppWindow( return MihAppWindow(
@@ -108,81 +115,63 @@ class _AiChatState extends State<AiChat> {
windowTitle: 'Mzansi AI Thoughts', windowTitle: 'Mzansi AI Thoughts',
windowTools: const [], windowTools: const [],
onWindowTapClose: () { onWindowTapClose: () {
if (_aiThinking) { _captureAIResponse(snapshot.requireData);
aiChatSubscription.cancel();
}
setState(() {
_chatHistory.add(
ollama.Message(
role: ollama.MessageRole.assistant,
content: snapshot.requireData,
),
);
});
textMessage = types.TextMessage(
author: _mihAI,
createdAt: DateTime.now().millisecondsSinceEpoch,
id: const Uuid().v4(),
// metadata: <String, dynamic>{
// "thoughts": snapshot.requireData
// },
text: snapshot.requireData
.replaceAll("<think>\n\n", "Thinking:\n")
.replaceAll("<think>\n", "Thinking:\n")
.replaceAll("</think>\n\n", "Answer:\n"), //message.text,
);
_addMessage(textMessage);
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
windowBody: [ windowBody: [
Stack(
children: [
Text( Text(
snapshot.requireData, snapshot.requireData,
textAlign: TextAlign.left, textAlign: TextAlign.left,
style: TextStyle( style: TextStyle(
color: color: MzanziInnovationHub.of(context)!
MzanziInnovationHub.of(context)!.theme.secondaryColor(), .theme
.secondaryColor(),
fontSize: _chatFrontSize, fontSize: _chatFrontSize,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
const SizedBox(height: 15), Positioned(
Visibility( bottom: 0,
right: 0,
child: Visibility(
visible: _aiThinking == false, visible: _aiThinking == false,
child: MIHButton( child: IconButton.filled(
onTap: () { iconSize: 25,
setState(() { autofocus: true,
_chatHistory.add( onPressed: () {
ollama.Message( _captureAIResponse(snapshot.requireData);
role: ollama.MessageRole.assistant,
content: snapshot.requireData,
),
);
});
textMessage = types.TextMessage(
author: _mihAI,
createdAt: DateTime.now().millisecondsSinceEpoch,
id: const Uuid().v4(),
// metadata: <String, dynamic>{
// "thoughts": snapshot.requireData
// },
text: snapshot.requireData
.replaceAll("<think>\n\n", "Thinking:\n")
.replaceAll("<think>\n", "Thinking:\n")
.replaceAll(
"</think>\n\n", "Answer:\n"), //message.text,
);
_addMessage(textMessage);
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
buttonText: "Continue", focusColor: MzanziInnovationHub.of(context)!
buttonColor: .theme
MzanziInnovationHub.of(context)!.theme.successColor(), .successColor(),
textColor: icon: Icon(
MzanziInnovationHub.of(context)!.theme.primaryColor(), Icons.check,
color: MzanziInnovationHub.of(context)!
.theme
.primaryColor(),
), ),
), ),
// MIHButton(
// onTap: () {
// _captureAIResponse(snapshot.requireData);
// Navigator.of(context).pop();
// },
// buttonText: "Continue",
// buttonColor: MzanziInnovationHub.of(context)!
// .theme
// .successColor(),
// textColor: MzanziInnovationHub.of(context)!
// .theme
// .primaryColor(),
// ),
),
),
],
),
], ],
); );
} else { } else {
@@ -202,15 +191,28 @@ class _AiChatState extends State<AiChat> {
); );
} }
void _loadMessages() async { void _captureAIResponse(String responseMessage) {
final response = await rootBundle.loadString('assets/messages.json'); types.TextMessage textMessage;
final messages = (jsonDecode(response) as List)
.map((e) => types.Message.fromJson(e as Map<String, dynamic>))
.toList();
setState(() { setState(() {
_messages = messages; _chatHistory.add(
ollama.Message(
role: ollama.MessageRole.assistant,
content: responseMessage,
),
);
}); });
textMessage = types.TextMessage(
author: _mihAI,
createdAt: DateTime.now().millisecondsSinceEpoch,
id: const Uuid().v4(),
text: responseMessage
.replaceAll("<think>\n\n", "**Thinking:**\n")
.replaceAll("<think>\n", "**Thinking:**\n")
.replaceAll("</think>\n\n", "\n**Answer:**\n"), //message.text,
);
_addMessage(textMessage);
} }
Stream<String> _generateChatCompletionWithHistoryStream( Stream<String> _generateChatCompletionWithHistoryStream(
@@ -234,20 +236,14 @@ class _AiChatState extends State<AiChat> {
setState(() { setState(() {
_aiThinking = false; _aiThinking = false;
}); });
// print(text);
} }
void _resetChat() { void _resetChat() {
setState(() { setState(() {
_messages = []; _messages = [];
_chatHistory = []; _chatHistory = [];
_loadMessages(); _loadMessages();
}); });
// Navigator.of(context).popAndPushNamed(
// '/mzansi-ai',
// arguments: widget.signedInUser,
// );
} }
ChatTheme getChatTheme() { ChatTheme getChatTheme() {
@@ -301,14 +297,14 @@ class _AiChatState extends State<AiChat> {
firstName: "Mzansi AI", firstName: "Mzansi AI",
id: const Uuid().v4(), id: const Uuid().v4(),
); );
_modelCopntroller.text = 'deepseek-r1:1.5b'; _modelCopntroller.text = 'deepseek-r1';
_fontSizeCopntroller.text = _chatFrontSize.ceil().toString(); _fontSizeCopntroller.text = _chatFrontSize.ceil().toString();
// _chatHistory.add( _chatHistory.add(
// ollama.Message( ollama.Message(
// role: ollama.MessageRole.system, role: ollama.MessageRole.system,
// content: systemPromt, content: systemPromt,
// ), ),
// ); );
_loadMessages(); _loadMessages();
} }
@@ -406,7 +402,10 @@ class _AiChatState extends State<AiChat> {
child: MIHDropdownField( child: MIHDropdownField(
controller: _modelCopntroller, controller: _modelCopntroller,
hintText: "AI Model", hintText: "AI Model",
dropdownOptions: const ['deepseek-r1:1.5b'], dropdownOptions: const [
'deepseek-r1:1.5b',
'deepseek-r1'
],
required: true, required: true,
editable: true, editable: true,
), ),