dynamic chat bubbles implemented along with conversation support. currently only hard-coded dummy data.
This commit is contained in:
+102
-65
@@ -1,4 +1,5 @@
|
||||
import 'dart:convert';
|
||||
import 'package:app/components/conversation_thread/conversation.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
import 'package:app/components/conversation_thread/chat.dart';
|
||||
@@ -7,12 +8,34 @@ import 'package:app/util/speech_to_text.dart';
|
||||
|
||||
// Uses Singleton design pattern to ensure that any server references across the app are using the same instance.
|
||||
class Server {
|
||||
// SERVER VARIABLES
|
||||
static final Server _single_server = Server._internal();
|
||||
Server._internal();
|
||||
// TODO: One-time process to establish server connection is required for easy setup/maintenance.
|
||||
static final url = "http://10.0.2.2:11434/api/";
|
||||
static String endpoint = "";
|
||||
static final Map<String, String> headers = {'Content-Type': 'application/json'};
|
||||
|
||||
// STT variables
|
||||
|
||||
|
||||
// AI VARIABLES
|
||||
static final SpeechToText stt = SpeechToText();
|
||||
static late bool _speechEnabled;
|
||||
|
||||
static final Server _single_server = Server._internal();
|
||||
|
||||
|
||||
// PRIVACY VARIABLES
|
||||
static bool _historyEnabled = true;
|
||||
static late int conversationID;
|
||||
static List<Conversation> conversations = [];
|
||||
static List<Chat> loadedChats = [];
|
||||
|
||||
|
||||
|
||||
// RUNTIME & STATUS VARIABLES
|
||||
static String prompt = "";
|
||||
static String response = "";
|
||||
static bool initiated = false;
|
||||
|
||||
// TODO: Verify all different components of STT, TTS, LLM, etc have been initialized.
|
||||
// TODO: Handshake w/ server to validate identity
|
||||
@@ -20,41 +43,83 @@ class Server {
|
||||
// Speech-To-Text engine activation.
|
||||
_speechEnabled = stt.isSpeechEnabled();
|
||||
|
||||
// loadedChats = conversations[conversationID].chats;
|
||||
|
||||
return _single_server;
|
||||
}
|
||||
|
||||
Server._internal();
|
||||
void init() {
|
||||
initiated = true;
|
||||
|
||||
// TODO: One-time process to establish server connection is required for easy setup/maintenance.
|
||||
// Server variables
|
||||
final url = "http://10.0.2.2:11434/api/";
|
||||
String endpoint = "";
|
||||
Map<String, String> headers = {'Content-Type': 'application/json'};
|
||||
|
||||
// Status variables
|
||||
bool _historyEnabled = true;
|
||||
// TODO: Dynamically obtain conversations.
|
||||
conversations.add(
|
||||
Conversation.completeConversation(
|
||||
0,
|
||||
"Test label",
|
||||
"Test sub-label",
|
||||
[
|
||||
(Chat("This is just a test. Only reply Yes.", true)),
|
||||
(Chat("Yes.", false)),
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
// Context variables
|
||||
List<Chat> chats = [
|
||||
(Chat("This is just a test. Only reply Yes.", true)),
|
||||
(Chat("Yes.", false)),
|
||||
];
|
||||
|
||||
// Runtime variables
|
||||
String prompt = "";
|
||||
String response = "";
|
||||
int conversationID = 0;
|
||||
|
||||
List<Chat> getConversationByID(conversationID) {
|
||||
// TODO: Implement conversation IDs & retrieval from server
|
||||
this.conversationID = conversationID;
|
||||
return chats;
|
||||
conversations.add(
|
||||
Conversation.completeConversation(
|
||||
1,
|
||||
"Label test",
|
||||
"Sub-label Test",
|
||||
[
|
||||
(Chat("A different test. Only reply No.", true)),
|
||||
(Chat("No.", false)),
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: Integrate with getConversationByID()
|
||||
List<Map<String, String>> convertMessages() {
|
||||
|
||||
|
||||
// PRIMARY INTERFACE
|
||||
static Future<String> sttGetResponseWhenReady() async {
|
||||
// TODO: In case on-device STT is unavailable, use server-side STT service.
|
||||
if (!_speechEnabled) "Unable to process Speech-To-Text on-device.";
|
||||
|
||||
prompt = stt.getTextWhenReady() as String;
|
||||
conversations[conversationID].add(Chat(prompt, true));
|
||||
httpSendRequest();
|
||||
conversations[conversationID].add(Chat(response, false));
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
static void respondWhenReady(String p) async {
|
||||
prompt = p;
|
||||
conversations[conversationID].add(Chat(prompt, true));
|
||||
httpSendRequest();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// CONVERSATION MANAGEMENT
|
||||
static List<Conversation> getConversationsList() { return conversations; }
|
||||
|
||||
static Conversation getLoadedConversation() { return conversations[conversationID]; }
|
||||
|
||||
// Load conversation should be called prior to any other server requests.
|
||||
static void loadConversation(id) {
|
||||
conversationID = id;
|
||||
loadedChats = conversations[conversationID].chats;
|
||||
}
|
||||
|
||||
static List<Chat> getChatsByConversationID(id) { return conversations[id].chats; }
|
||||
|
||||
|
||||
|
||||
// SERVER UTILS
|
||||
static List<Map<String, String>> convertMessages() {
|
||||
// TODO: Integrate with getConversationByID()
|
||||
List<Map<String, String>> messageList = [];
|
||||
for (Chat c in chats) {
|
||||
for (Chat c in loadedChats) {
|
||||
messageList.add({
|
||||
"role": c.role ? "user" : "assistant",
|
||||
"content": c.content,
|
||||
@@ -64,41 +129,15 @@ class Server {
|
||||
return messageList;
|
||||
}
|
||||
|
||||
// Using native on-device Speech-To-Text capability, get the server response when ready.
|
||||
Future<String> sttGetResponseWhenReady() async {
|
||||
// TODO: In case on-device STT is unavailable, use server-side STT service.
|
||||
if (!_speechEnabled) "Unable to process Speech-To-Text on-device.";
|
||||
|
||||
prompt = stt.getTextWhenReady() as String;
|
||||
httpSendRequest();
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
Future<String> getResponseWhenReady(String p) async {
|
||||
prompt = p;
|
||||
httpSendRequest();
|
||||
return response;
|
||||
}
|
||||
|
||||
// Get the last response or request a response from the server.
|
||||
String getResponse() {
|
||||
httpSendRequest();
|
||||
return response;
|
||||
}
|
||||
|
||||
// Get the latest prompt.
|
||||
String getPrompt() => prompt;
|
||||
|
||||
// Formats the prompt in JSON.
|
||||
String constructPrompt() {
|
||||
static String constructPrompt() {
|
||||
// TODO: Allow for additional flags, ie. continuous conversation, images, etc.
|
||||
// TODO: Allow for toggleable states between stream
|
||||
// TODO: Allow for different models to be dynamically selected.
|
||||
Map<String, dynamic> data;
|
||||
|
||||
if(_historyEnabled) {
|
||||
chats = [...chats, Chat(prompt, true)];
|
||||
loadedChats = [...loadedChats, Chat(prompt, true)];
|
||||
endpoint = "chat";
|
||||
|
||||
List<Map<String, String>> messageList = convertMessages();
|
||||
@@ -123,9 +162,8 @@ class Server {
|
||||
}
|
||||
|
||||
// Send the HTTP request to the server.
|
||||
void httpSendRequest() async {
|
||||
static void httpSendRequest() async {
|
||||
String json = constructPrompt();
|
||||
print("\n\nJSON:\n$json\n\n");
|
||||
|
||||
// Send the HTTP POST request
|
||||
final serverResponse = await http.post(
|
||||
@@ -138,15 +176,14 @@ class Server {
|
||||
Map<String, dynamic> re = jsonDecode(serverResponse.body);
|
||||
if(_historyEnabled) {
|
||||
response = re["message"]["content"];
|
||||
chats = [...chats, Chat(response, false)];
|
||||
loadedChats = [...loadedChats, Chat(response, false)];
|
||||
} else {
|
||||
response = re["response"];
|
||||
}
|
||||
}
|
||||
print("\n\nresponse:\n$response");
|
||||
print("\nRaw chats variable:\n");
|
||||
for(Chat c in chats) {
|
||||
print(c.content);
|
||||
}
|
||||
conversations[conversationID].add(Chat(response, false));
|
||||
|
||||
prompt = "";
|
||||
response = "";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user