- 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,80 +115,62 @@ 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: [
Text( Stack(
snapshot.requireData, children: [
textAlign: TextAlign.left, Text(
style: TextStyle( snapshot.requireData,
color: textAlign: TextAlign.left,
MzanziInnovationHub.of(context)!.theme.secondaryColor(), style: TextStyle(
fontSize: _chatFrontSize, color: MzanziInnovationHub.of(context)!
fontWeight: FontWeight.bold, .theme
), .secondaryColor(),
), fontSize: _chatFrontSize,
const SizedBox(height: 15), fontWeight: FontWeight.bold,
Visibility( ),
visible: _aiThinking == false, ),
child: MIHButton( Positioned(
onTap: () { bottom: 0,
setState(() { right: 0,
_chatHistory.add( child: Visibility(
ollama.Message( visible: _aiThinking == false,
role: ollama.MessageRole.assistant, child: IconButton.filled(
content: snapshot.requireData, iconSize: 25,
autofocus: true,
onPressed: () {
_captureAIResponse(snapshot.requireData);
Navigator.of(context).pop();
},
focusColor: MzanziInnovationHub.of(context)!
.theme
.successColor(),
icon: Icon(
Icons.check,
color: MzanziInnovationHub.of(context)!
.theme
.primaryColor(),
), ),
); ),
});
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); // MIHButton(
Navigator.of(context).pop(); // onTap: () {
}, // _captureAIResponse(snapshot.requireData);
buttonText: "Continue", // Navigator.of(context).pop();
buttonColor: // },
MzanziInnovationHub.of(context)!.theme.successColor(), // buttonText: "Continue",
textColor: // buttonColor: MzanziInnovationHub.of(context)!
MzanziInnovationHub.of(context)!.theme.primaryColor(), // .theme
), // .successColor(),
// textColor: MzanziInnovationHub.of(context)!
// .theme
// .primaryColor(),
// ),
),
),
],
), ),
], ],
); );
@@ -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,
), ),