added send functionality to icon.

This commit is contained in:
Joshua
2024-07-10 13:44:16 -06:00
parent 097b99e0e6
commit 711991c7bf
13 changed files with 363 additions and 281 deletions
@@ -1,3 +1,4 @@
import 'package:app/theme.dart';
import 'package:flutter/material.dart';
import 'chat.dart';
@@ -26,9 +27,12 @@ class ChatBubbleWidget extends StatelessWidget{
bottomRight: c.role ? const Radius.circular(12.0) : const Radius
.circular(0.0),
),
color: c.role ? Colors.blue[200] : Colors.grey[200],
color: c.role ? AppTheme.darkest : AppTheme.dark,
),
child: Text(
c.content,
style: AppTheme.bodyMedium,
),
child: Text(c.content),
),
],
);
@@ -18,7 +18,7 @@ class Conversation with ChangeNotifier {
}
void loadChats() {
chats = Server.getChatsByConversationID(conversationID);
chats = Backend.getChatsByConversationID(conversationID);
}
void setLabel() {
@@ -20,7 +20,7 @@ class ConversationThreadModel extends FlutterFlowModel<ConversationThreadWidget>
@override
void initState(BuildContext context) {
conversation = Server.getLoadedConversation();
conversation = Backend.getLoadedConversation();
promptBoxModel = createModel(context, () => PromptBoxModel());
}
@@ -53,9 +53,7 @@ class _ConversationThreadWidgetState extends State<ConversationThreadWidget> {
return Container(
width: double.infinity,
height: double.infinity,
decoration: const BoxDecoration(
color: AppTheme.primaryBackground,
),
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
@@ -65,12 +63,12 @@ class _ConversationThreadWidgetState extends State<ConversationThreadWidget> {
listenable: _model.conversation,
builder: (BuildContext context, Widget? child) {
return ListView.builder(
itemCount: Server.getLoadedConversation().chats.length,
itemCount: Backend.getLoadedConversation().chats.length,
padding: const EdgeInsets.fromLTRB(0, 12, 0, 24,),
reverse: false,
scrollDirection: Axis.vertical,
itemBuilder: (BuildContext context, int index) {
return ChatBubbleWidget(c: Server.getLoadedConversation().chats[index]);
return ChatBubbleWidget(c: Backend.getLoadedConversation().chats[index]);
},
);
},
@@ -79,7 +77,7 @@ class _ConversationThreadWidgetState extends State<ConversationThreadWidget> {
Container(
width: double.infinity,
decoration: const BoxDecoration(
color: AppTheme.secondaryBackground,
color: AppTheme.medium,
boxShadow: [
BoxShadow(
blurRadius: 3,
@@ -95,18 +93,18 @@ class _ConversationThreadWidgetState extends State<ConversationThreadWidget> {
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Row(
mainAxisSize: MainAxisSize.max,
children: [
Expanded(
child: Padding(
padding: const EdgeInsetsDirectional.fromSTEB(0, 12, 0, 0),
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Row(
// mainAxisSize: MainAxisSize.max,
// children: [
// Expanded(
// child: Padding(
// padding: const EdgeInsetsDirectional.fromSTEB(0, 12, 0, 0),
// child: SingleChildScrollView(
// scrollDirection: Axis.horizontal,
// child: Row(
// mainAxisSize: MainAxisSize.max,
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// FlutterFlowMediaDisplay(
// path: '',
// imageBuilder: (path) => ClipRRect(
@@ -121,7 +119,7 @@ class _ConversationThreadWidgetState extends State<ConversationThreadWidget> {
// fit: BoxFit.cover,
// ),
// ),
// TODO
// // TODO
// videoPlayerBuilder: (path) =>
// FlutterFlowVideoPlayer(
// path: path,
@@ -133,36 +131,36 @@ class _ConversationThreadWidgetState extends State<ConversationThreadWidget> {
// allowPlaybackSpeedMenu: false,
// ),
// ),
Align(
alignment: const AlignmentDirectional(-1, -1),
// TODO: Make the delete button conditional upon media upload.
child: FlutterFlowIconButton(
borderColor:
AppTheme.error,
borderRadius: 20,
borderWidth: 2,
buttonSize: 40,
fillColor: AppTheme.primaryBackground,
icon: const Icon(
Icons.delete_outline_rounded,
color: AppTheme.error,
size: 24,
),
onPressed: () {
print('IconButton pressed ...');
},
),
),
]
.divide(const SizedBox(width: 8))
.addToStart(const SizedBox(width: 16))
.addToEnd(const SizedBox(width: 16)),
),
),
),
),
],
),
// Align(
// alignment: const AlignmentDirectional(-1, -1),
// // TODO: Make the delete button conditional upon media upload.
// child: FlutterFlowIconButton(
// borderColor:
// AppTheme.error,
// borderRadius: 20,
// borderWidth: 2,
// buttonSize: 40,
// fillColor: AppTheme.primaryBackground,
// icon: const Icon(
// Icons.delete_outline_rounded,
// color: AppTheme.error,
// size: 24,
// ),
// onPressed: () {
// print('IconButton pressed ...');
// },
// ),
// ),
// ]
// .divide(const SizedBox(width: 8))
// .addToStart(const SizedBox(width: 16))
// .addToEnd(const SizedBox(width: 16)),
// ),
// ),
// ),
// ),
// ],
// ),
Form(
key: _model.formKey,
autovalidateMode: AutovalidateMode.disabled,
@@ -1,3 +1,4 @@
import 'package:app/components/conversation_thread/conversation.dart';
import 'package:flutterflow_ui/flutterflow_ui.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
@@ -9,14 +10,18 @@ import 'model_item_model.dart';
export 'model_item_model.dart';
class ModelItemWidget extends StatefulWidget {
const ModelItemWidget({super.key});
final Conversation conversation;
const ModelItemWidget({super.key, required this.conversation});
@override
State<ModelItemWidget> createState() => _ModelItemWidgetState();
State<ModelItemWidget> createState() => _ModelItemWidgetState(conversation);
}
class _ModelItemWidgetState extends State<ModelItemWidget> {
late ModelItemModel _model;
late Conversation conversation;
_ModelItemWidgetState(this.conversation);
@override
void setState(VoidCallback callback) {
@@ -78,22 +83,22 @@ class _ModelItemWidgetState extends State<ModelItemWidget> {
),
),
),
const Expanded(
Expanded(
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(12, 0, 8, 0),
padding: const EdgeInsetsDirectional.fromSTEB(12, 0, 8, 0),
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Randy Peterson',
Text( // Label
conversation.conversationLabel,
style: AppTheme.bodyMedium,
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(0, 4, 0, 0),
child: Text(
'name@domainname.com',
padding: const EdgeInsetsDirectional.fromSTEB(0, 4, 0, 0),
child: Text( // Sub-label
conversation.conversationSubLabel,
style: AppTheme.bodySmall,
),
),
@@ -17,6 +17,7 @@ class PromptBoxWidget extends StatefulWidget {
class _PromptBoxWidgetState extends State<PromptBoxWidget> {
late PromptBoxModel _model;
late String entry_text;
@override
void setState(VoidCallback callback) {
@@ -69,7 +70,7 @@ class _PromptBoxWidgetState extends State<PromptBoxWidget> {
buttonSize: 40,
icon: const Icon(
Icons.file_upload_outlined,
color: AppTheme.secondaryText,
color: AppTheme.darkest,
size: 30,
),
onPressed: () {
@@ -88,7 +89,7 @@ class _PromptBoxWidgetState extends State<PromptBoxWidget> {
buttonSize: 40,
icon: const Icon(
Icons.photo_outlined,
color: AppTheme.secondaryText,
color: AppTheme.darkest,
size: 30,
),
onPressed: () {
@@ -105,13 +106,28 @@ class _PromptBoxWidgetState extends State<PromptBoxWidget> {
borderRadius: 30,
borderWidth: 1,
buttonSize: 40,
icon: const Icon(
Icons.mic_none,
color: AppTheme.secondaryText,
icon: // Backend.stt.speechToText.isListening ?
// const Icon(
// Icons.mic_none,
// color: AppTheme.error,
// size: 30,
// ) :
const Icon(
Icons.mic_off_outlined,
color: AppTheme.darkest,
size: 30,
),
onPressed: () {
print('IconButton pressed ...');
if(Backend.stt.isSpeechEnabled()) {
if(Backend.stt.speechToText.isListening) {
print('De-activating STT.');
Backend.stt.stopListening();
}
print('Activating STT.');
entry_text = Backend.stt.startListening() as String;
} else {
print('Microphone is unavailable for STT');
}
},
),
),
@@ -126,7 +142,7 @@ class _PromptBoxWidgetState extends State<PromptBoxWidget> {
buttonSize: 40,
icon: const Icon(
Icons.videocam_outlined,
color: AppTheme.secondaryText,
color: AppTheme.darkest,
size: 30,
),
onPressed: () {
@@ -145,7 +161,7 @@ class _PromptBoxWidgetState extends State<PromptBoxWidget> {
buttonSize: 40,
icon: const Icon(
Icons.camera_alt_outlined,
color: AppTheme.secondaryText,
color: AppTheme.darkest,
size: 30,
),
onPressed: () {
@@ -206,21 +222,28 @@ class _PromptBoxWidgetState extends State<PromptBoxWidget> {
),
filled: true,
fillColor: AppTheme.alternate,
suffixIcon: const Icon(
suffixIcon: GestureDetector(
onTap: () {
// TODO: Connect with multimedia
entry_text = _model.textController.text;
Backend.respondWhenReady(entry_text);
_model.textController?.clear(); // Clear the text field
},
child: const Icon(
Icons.send,
color: AppTheme.primary,
size: 30,
),
),
style: AppTheme.bodyMedium,
),
style: AppTheme.displayMedium,
textAlign: TextAlign.start,
maxLines: 5,
minLines: 1,
validator: _model.textControllerValidator.asValidator(context),
textInputAction: TextInputAction.send, // "Send" on keyboard
onFieldSubmitted: (text) {
// TODO: Clear text box
Server.respondWhenReady(text); // TODO: Connect with multimedia
Backend.respondWhenReady(text); // TODO: Connect with multimedia
_model.textController?.clear(); // Clear the text field
},
),
+9 -6
View File
@@ -28,13 +28,14 @@ BottomNavigationBarItem _buildNavigationItem(int index) {
iconData = Icons.settings;
break;
case 1:
label = 'Home';
iconData = Icons.home;
label = 'Chats';
iconData = Icons.chat;
break;
}
return BottomNavigationBarItem(
icon: Icon(iconData),
label: label,
backgroundColor: AppTheme.lightest,
);
}
@@ -63,15 +64,15 @@ class MyApp extends ConsumerWidget {
final selectedIndex = ref.watch(selectedIndexProvider);
return MaterialApp(
title: 'App',
title: 'One AI',
home: Scaffold(
backgroundColor: AppTheme.secondaryBackground,
backgroundColor: AppTheme.medium,
appBar: AppBar(
backgroundColor: AppTheme.secondaryBackground,
automaticallyImplyLeading: false,
title: const Text(
'App',
style: AppTheme.headlineLarge,
'One AI',
style: AppTheme.displayLarge,
),
actions: const [],
centerTitle: false,
@@ -79,6 +80,8 @@ class MyApp extends ConsumerWidget {
),
body: _pages[selectedIndex],
bottomNavigationBar: BottomNavigationBar(
backgroundColor: AppTheme.darkest,
selectedItemColor: AppTheme.lightest,
// Set the number of items to the length of the pages list
items: List.generate(_pages.length, (index) => _buildNavigationItem(index)),
currentIndex: selectedIndex,
@@ -59,7 +59,7 @@ class _ConversationWidgetState extends State<ConversationWidget> {
buttonSize: 60,
icon: const Icon(
Icons.arrow_back_rounded,
color: AppTheme.primaryTextColor,
color: AppTheme.lightest,
size: 30,
),
onPressed: () async {
@@ -80,21 +80,16 @@ class _ConversationWidgetState extends State<ConversationWidget> {
title: wrapWithModel(
model: _model.modelItemModel,
updateCallback: () => setState(() {}),
child: const ModelItemWidget(),
child: ModelItemWidget(conversation: conversation,),
),
actions: [
Padding(
padding: const EdgeInsetsDirectional.fromSTEB(0, 8, 16, 8),
// ---------- Options Button
child: FlutterFlowIconButton(
borderColor: AppTheme.alternate,
borderRadius: 12,
borderWidth: 2,
buttonSize: 40,
fillColor: AppTheme.primaryBackground,
icon: const Icon(
Icons.more_vert,
color: AppTheme.primaryTextColor,
color: AppTheme.lightest,
size: 24,
),
onPressed: () async {
@@ -6,7 +6,6 @@ import 'package:app/util/server.dart';
import 'package:flutterflow_ui/flutterflow_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'conversations_list_model.dart';
export 'conversations_list_model.dart';
@@ -29,10 +28,10 @@ class _ConversationsListWidgetState extends State<ConversationsListWidget> {
@override
void initState() {
super.initState();
Server().init();
Backend().init();
if(conversations.isEmpty) {
List<Conversation> convoys = Server.conversations;
List<Conversation> convoys = Backend.conversations;
for(Conversation c in convoys) {
conversations.add(ConversationWidget(conversation: c,));
}
@@ -55,17 +54,12 @@ class _ConversationsListWidgetState extends State<ConversationsListWidget> {
: FocusScope.of(context).unfocus(),
child: SafeArea(
top: true,
child: Column(
child: Stack(
children: [
Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Padding(
padding: EdgeInsetsDirectional.fromSTEB(16, 0, 0, 0),
child: Text(
'Conversations',
style: AppTheme.labelMedium,
),
),
Expanded(
child: Align(
alignment: const AlignmentDirectional(0, 0),
@@ -78,23 +72,31 @@ class _ConversationsListWidgetState extends State<ConversationsListWidget> {
return Align(
alignment: const AlignmentDirectional(0, 0),
child: InkWell(
splashColor: Colors.transparent,
focusColor: Colors.transparent,
hoverColor: Colors.transparent,
highlightColor: Colors.transparent,
splashColor: AppTheme.accent,
focusColor: AppTheme.lightest,
hoverColor: AppTheme.dark,
highlightColor: AppTheme.darkest,
// TODO
// onTap: () async {
// context.pushNamed('Conversation');
// },
child: Container(
decoration: const BoxDecoration(
//color: AppTheme.darkest,
border: Border(
top: BorderSide(width: 2.0, color: AppTheme.darkest),
),
),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
width: 100,
height: 100,
decoration: const BoxDecoration(color: AppTheme.secondaryBackground,),
decoration: const BoxDecoration(color: AppTheme.lightest,),
child: const Align(
alignment: AlignmentDirectional(0, 0),
child: Icon(
@@ -114,7 +116,7 @@ class _ConversationsListWidgetState extends State<ConversationsListWidget> {
minWidth: MediaQuery.sizeOf(context).width,
),
decoration: const BoxDecoration(
color: AppTheme.secondaryBackground,
color: AppTheme.lightest,
shape: BoxShape.rectangle,
),
child: Column(
@@ -129,7 +131,7 @@ class _ConversationsListWidgetState extends State<ConversationsListWidget> {
children: [
Text(
conversations[index].conversation.conversationLabel,
style: AppTheme.headlineLarge,
style: AppTheme.labelLarge,
),
],
),
@@ -143,7 +145,7 @@ class _ConversationsListWidgetState extends State<ConversationsListWidget> {
Expanded(
child: Text(
conversations[index].conversation.conversationSubLabel,
style: AppTheme.bodyMedium,
style: AppTheme.labelSmall,
),
),
],
@@ -158,7 +160,7 @@ class _ConversationsListWidgetState extends State<ConversationsListWidget> {
width: 100,
height: 100,
decoration: const BoxDecoration(
color: AppTheme.secondaryBackground,
color: AppTheme.lightest,
),
child: const Icon(
Icons.chevron_right_rounded,
@@ -168,15 +170,13 @@ class _ConversationsListWidgetState extends State<ConversationsListWidget> {
),
],
),
),
onTap: () => {
// TODO: Need to implement.
// Get the conversation object based on the index
// Use Navigator to push a new ConversationWidget with conversation data
Server.loadConversation(index),
Backend.loadConversation(index),
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ConversationWidget(conversation: Server.getLoadedConversation(),),
builder: (context) => ConversationWidget(conversation: Backend.getLoadedConversation(),),
),
)
},
@@ -192,6 +192,29 @@ class _ConversationsListWidgetState extends State<ConversationsListWidget> {
),
],
),
Positioned(
bottom: 20.0, // Adjust positioning as needed
right: 20.0, // Adjust positioning as needed
child: FloatingActionButton(
onPressed: () => {
Backend.loadConversation(Backend.maxConversationID), // TODO: Dynamically get the next ID
conversations.add(ConversationWidget(conversation: Backend.getLoadedConversation())),
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ConversationWidget(conversation: Backend.getLoadedConversation(),),
),
), // Handle the button press
},
backgroundColor: AppTheme.darkest,
child: const Icon(
Icons.bubble_chart,
color: AppTheme.lightest,
),
),
),
],
),
),
);
}
+30 -22
View File
@@ -1,37 +1,45 @@
import 'package:flutter/material.dart';
class AppTheme {
static const primary = Colors.deepPurple;
static const secondary = Colors.deepPurpleAccent;
static const tertiary = Colors.white;
static const alternate = Colors.deepPurple;
static const darkest = Color.fromARGB(255, 45, 45, 145);
static const dark = Color.fromARGB(255, 81, 81, 196);
static const medium = Color.fromARGB(255, 107, 107, 201);
static const light = Color.fromARGB(255, 155, 155, 255);
static const lightest = Color.fromARGB(255, 172, 175, 255);
static const accent = Color.fromARGB(255, 255, 113, 0);
static const accent2 = Color.fromARGB(255, 255, 164, 79);
static const accent1 = Colors.amber;
static const accent4 = Colors.amber;
static const primaryBackground = darkest;
static const secondaryBackground = medium;
static const primaryTextColor = darkest;
static const primaryText = TextStyle(color: primaryTextColor, fontSize: 16);
static const secondaryText = dark;
static const primaryBackground = Colors.deepPurpleAccent;
static const secondaryBackground = Colors.deepPurple;
static const accent1 = lightest;
static const accent4 = accent2;
static const primary = dark;
static const secondary = medium;
static const tertiary = light;
static const alternate = lightest;
static const primaryTextColor = Colors.white;
static const primaryText = TextStyle(color: primaryTextColor, fontSize: 12);
static const secondaryText = Colors.white;
static const bodyLarge = TextStyle(color: Colors.white, fontSize: 24);
static const bodyMedium = TextStyle(color: Colors.white, fontSize: 12);
static const bodySmall = TextStyle(color: Colors.white, fontSize: 10);
static const bodyLarge = TextStyle(color: light, fontSize: 24, fontWeight: FontWeight.bold);
static const bodyMedium = TextStyle(color: lightest, fontSize: 16);
static const bodySmall = TextStyle(color: light, fontSize: 12);
static const error = Colors.red;
static const info = Colors.grey;
static const displaySmall = TextStyle(color: Colors.white, fontSize: 12);
static const displayLarge = TextStyle(color: darkest, fontSize: 24, fontWeight: FontWeight.bold);
static const displayMedium = TextStyle(color: dark, fontSize: 16, fontWeight: FontWeight.bold);
static const displaySmall = TextStyle(color: lightest, fontSize: 12, fontWeight: FontWeight.bold);
static const labelLarge = TextStyle(color: Colors.black, fontSize: 24);
static const labelMedium = TextStyle(color: Colors.grey, fontSize: 16);
static const labelSmall = TextStyle(color: Colors.grey, fontSize: 12);
static const labelLarge = TextStyle(color: darkest, fontSize: 24, fontWeight: FontWeight.bold);
static const labelMedium = TextStyle(color: dark, fontSize: 16, fontWeight: FontWeight.bold);
static const labelSmall = TextStyle(color: medium, fontSize: 12, fontWeight: FontWeight.bold);
static const headlineLarge = TextStyle(color: Colors.blue, fontWeight: FontWeight.bold);
static const headlineMedium = TextStyle(color: Colors.blue, fontWeight: FontWeight.bold);
static const headlineSmall = TextStyle(color: Colors.blue, fontWeight: FontWeight.bold);
static const headlineLarge = TextStyle(color: medium, fontWeight: FontWeight.bold);
static const headlineMedium = TextStyle(color: light, fontWeight: FontWeight.bold);
static const headlineSmall = TextStyle(color: lightest, fontWeight: FontWeight.bold);
static const titleLarge = TextStyle(fontFamily: 'Outfit', letterSpacing: 0, fontSize: 24);
static const titleSmall = TextStyle(fontFamily: 'Outfit', letterSpacing: 0, fontSize: 16);
+5
View File
@@ -0,0 +1,5 @@
class Model {
late String name;
Model(this.name);
}
+26 -8
View File
@@ -6,11 +6,13 @@ import 'package:app/components/conversation_thread/chat.dart';
import 'package:app/util/speech_to_text.dart';
import 'model.dart';
// Uses Singleton design pattern to ensure that any server references across the app are using the same instance.
class Server {
class Backend {
// SERVER VARIABLES
static final Server _single_server = Server._internal();
Server._internal();
static final Backend _single_backend = Backend._internal();
Backend._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/"; // For emulated device in testing
//static final url = "http://192.168.1.68:11434/api"; // For local access to home server
@@ -28,30 +30,36 @@ class Server {
// PRIVACY VARIABLES
static bool _historyEnabled = true;
static late int conversationID;
static late int maxConversationID;
static List<Conversation> conversations = [];
static List<Chat> loadedChats = [];
// RUNTIME & STATUS VARIABLES
static late Model model;
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
factory Server() {
factory Backend() {
// Speech-To-Text engine activation.
_speechEnabled = stt.isSpeechEnabled();
// loadedChats = conversations[conversationID].chats;
return _single_server;
return _single_backend;
}
void init() {
initiated = true;
// TODO: Dynamically get available models and models that can be pulled.
// TODO: Dynamically get the user's default model
model = Model("llama3"); // Primarily used llama3, testing gemma2
// TODO: Dynamically obtain conversations.
conversations.add(
Conversation.completeConversation(
@@ -65,6 +73,8 @@ class Server {
)
);
maxConversationID = conversations.length;
// conversations.add(
// Conversation.completeConversation(
// 1,
@@ -81,9 +91,12 @@ class Server {
// PRIMARY INTERFACE
@Deprecated("Use STT interface directly and use respondWhenReady().")
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.";
if (!_speechEnabled) {
return "Unable to process Speech-To-Text on-device.";
}
prompt = stt.getTextWhenReady() as String;
conversations[conversationID].add(Chat(prompt, true));
@@ -109,6 +122,11 @@ class Server {
// Load conversation should be called prior to any other server requests.
static void loadConversation(id) {
conversationID = id;
if(maxConversationID == id) {
conversations.add(Conversation(conversationID, "Conversation $id", "Another AI conversation"));
maxConversationID++;
}
loadedChats = conversations[conversationID].chats;
}
@@ -144,7 +162,7 @@ class Server {
List<Map<String, String>> messageList = convertMessages();
data = {
"model": "llama3",
"model": model.name,
"messages": messageList,
"stream": false,
};
@@ -152,7 +170,7 @@ class Server {
else {
endpoint = "generate";
data = {
"model": "llama3",
"model": model.name,
"prompt": prompt,
"stream": false,
};
+9 -9
View File
@@ -3,15 +3,15 @@ import 'package:speech_to_text/speech_to_text.dart' as stt;
/// Handles standard Speech-To-Text using on-device processing.
class SpeechToText {
final stt.SpeechToText _speechToText = stt.SpeechToText();
bool _speechEnabled = false;
final stt.SpeechToText speechToText = stt.SpeechToText();
bool speechEnabled = false;
String text = "";
// Check if speech recognition is enabled.
bool isSpeechEnabled() => _speechEnabled;
bool isSpeechEnabled() => speechEnabled;
Future<String> getTextWhenReady() async {
await _speechToText.stop();
await speechToText.stop();
return text;
}
@@ -22,22 +22,22 @@ class SpeechToText {
void reset() => text = "";
/// Start a speech recognition session
void _startListening() async => await _speechToText.listen(onResult: _onSpeechResult);
void startListening() async => await speechToText.listen(onResult: onSpeechResult);
/// Manually stop the active speech recognition session
/// Note that there are also timeouts that each platform enforces
/// and the SpeechToText plugin supports setting timeouts on the
/// listen method.
void _stopListening() async => await _speechToText.stop();
void stopListening() async => await speechToText.stop();
SpeechToText() {
_initSpeech();
initSpeech();
}
/// This has to happen only once per app
void _initSpeech() async => _speechEnabled = await _speechToText.initialize();
void initSpeech() async => speechEnabled = await speechToText.initialize();
/// This is the callback that the SpeechToText plugin calls when
/// the platform returns recognized words.
void _onSpeechResult(SpeechRecognitionResult result) => text = result.recognizedWords;
String onSpeechResult(SpeechRecognitionResult result) => (text = result.recognizedWords);
}