integrated code from one-ai-mobile repo. working on GUI integration now.

This commit is contained in:
Joshua
2024-07-07 14:15:29 -06:00
parent 2625a2ec6c
commit 80f20e73a9
10 changed files with 221 additions and 12 deletions
@@ -0,0 +1,3 @@
class ConversationBubblesModel {
}
@@ -0,0 +1,3 @@
class ConversationBubblesWidget {
}
@@ -1,4 +1,4 @@
import '/components/conversation_bubbles/conversation_bubbles_widget.dart'; import '../conversation_bubbles/conversation_bubbles_model.dart';
import '/components/prompt_box/prompt_box_widget.dart'; import '/components/prompt_box/prompt_box_widget.dart';
import 'package:flutterflow_ui/flutterflow_ui.dart'; import 'package:flutterflow_ui/flutterflow_ui.dart';
import 'conversation_thread_widget.dart' show ConversationThreadWidget; import 'conversation_thread_widget.dart' show ConversationThreadWidget;
@@ -13,7 +13,8 @@ class ConversationThreadModel
final formKey = GlobalKey<FormState>(); final formKey = GlobalKey<FormState>();
// Model for ConversationBubbles component. // Model for ConversationBubbles component.
//late ConversationBubblesModel conversationBubblesModel; late ConversationBubblesModel conversationBubblesModel;
// Model for PromptBox component. // Model for PromptBox component.
late PromptBoxModel promptBoxModel; late PromptBoxModel promptBoxModel;
@@ -55,12 +55,7 @@ class _ConversationThreadWidgetState extends State<ConversationThreadWidget> {
children: [ children: [
Expanded( Expanded(
child: ListView( child: ListView(
padding: const EdgeInsets.fromLTRB( padding: const EdgeInsets.fromLTRB(0, 12, 0, 24,),
0,
12,
0,
24,
),
reverse: true, reverse: true,
scrollDirection: Axis.vertical, scrollDirection: Axis.vertical,
children: [ children: [
@@ -142,14 +137,14 @@ class _ConversationThreadWidgetState extends State<ConversationThreadWidget> {
// ), // ),
Align( Align(
alignment: const AlignmentDirectional(-1, -1), alignment: const AlignmentDirectional(-1, -1),
// TODO: Make the delete button conditional upon media upload.
child: FlutterFlowIconButton( child: FlutterFlowIconButton(
borderColor: borderColor:
AppTheme.error, AppTheme.error,
borderRadius: 20, borderRadius: 20,
borderWidth: 2, borderWidth: 2,
buttonSize: 40, buttonSize: 40,
fillColor: AppTheme fillColor: AppTheme.primaryBackground,
.primaryBackground,
icon: const Icon( icon: const Icon(
Icons.delete_outline_rounded, Icons.delete_outline_rounded,
color: AppTheme.error, color: AppTheme.error,
@@ -3,8 +3,6 @@ import '/components/conversation_thread/conversation_thread_widget.dart';
import '/components/model_item/model_item_widget.dart'; import '/components/model_item/model_item_widget.dart';
import 'package:flutterflow_ui/flutterflow_ui.dart'; import 'package:flutterflow_ui/flutterflow_ui.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';
import 'package:app/theme.dart'; import 'package:app/theme.dart';
@@ -48,6 +46,7 @@ class _ConversationWidgetState extends State<ConversationWidget> {
appBar: AppBar( appBar: AppBar(
backgroundColor: AppTheme.primaryBackground, backgroundColor: AppTheme.primaryBackground,
automaticallyImplyLeading: false, automaticallyImplyLeading: false,
// ---------- Back Button
leading: FlutterFlowIconButton( leading: FlutterFlowIconButton(
borderColor: Colors.transparent, borderColor: Colors.transparent,
borderRadius: 30, borderRadius: 30,
@@ -81,6 +80,7 @@ class _ConversationWidgetState extends State<ConversationWidget> {
actions: [ actions: [
Padding( Padding(
padding: const EdgeInsetsDirectional.fromSTEB(0, 8, 16, 8), padding: const EdgeInsetsDirectional.fromSTEB(0, 8, 16, 8),
// ---------- Options Button
child: FlutterFlowIconButton( child: FlutterFlowIconButton(
borderColor: AppTheme.alternate, borderColor: AppTheme.alternate,
borderRadius: 12, borderRadius: 12,
+129
View File
@@ -0,0 +1,129 @@
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:app/util/speech_to_text.dart';
class Server {
// TODO: One-time process to establish server connection is required for easy setup/maintenance.
final url = "http://10.0.2.2:11434";
final headers = {'Content-Type': 'application/json'};
final SpeechToText stt = SpeechToText();
late bool _speechEnabled;
String prompt = "";
String response = "";
Server() {
// Speech-To-Text engine activation.
_speechEnabled = stt.isSpeechEnabled();
// TODO: Initialize all different components of STT, TTS, LLM, etc.
// TODO: Handshake w/ server to validate identity
}
// 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.";
setPrompt(stt.getTextWhenReady() as String);
constructPrompt();
httpSendRequest();
return response;
}
// Arbitrary prompt, used for standard text interaction rather than STT.
void setPrompt(String p) => prompt = p;
// Get the last response or request a response from the server.
String getResponse() {
if(response.isEmpty) {
constructPrompt();
httpSendRequest();
}
return response;
}
// Get the latest prompt.
String getPrompt() => prompt;
// Formats the prompt in JSON.
String constructPrompt() {
// Construct the JSON payload
final Map<String, dynamic> data = {
"model":
"llama3", // TODO: Allow for different models to be dynamically selected.
"prompt": prompt,
"stream": false // TODO: Allow for toggleable states between stream
// TODO: Allow for additional flags, ie. continuous conversation, images, etc.
};
// Encode the JSON payload
final String body = json.encode(data);
return body;
}
// Send the HTTP request to the server.
void httpSendRequest() async {
String json = constructPrompt();
// Send the HTTP POST request
final serverResponse = await http.post(
Uri.parse('$url/api/generate'),
headers: headers,
body: json,
);
if (serverResponse.statusCode == 200) {
Map<String, dynamic> re = jsonDecode(serverResponse.body);
response = re["response"]!;
} else {
response = ('Error: ${serverResponse.statusCode}');
}
}
}
//
//
// // GUI components
// child: Column(
// mainAxisAlignment: MainAxisAlignment.center,
// children: <Widget>[
// Container(
// padding: const EdgeInsets.all(16),
// child: const Text(
// 'Recognized words:',
// style: TextStyle(fontSize: 20.0),
// ),
// ),
// Expanded(
// child: Container(
// padding: const EdgeInsets.all(16),
// child: Text(
// // If listening is active show the recognized words
// _speechToText.isListening
// ? prompt
// // If listening isn't active but could be tell the user
// // how to start it, otherwise indicate that speech
// // recognition is not yet ready or not supported on
// // the target device
// : _speechEnabled
// ? responseFromAI
// : 'Speech disabled',
// ),
// ),
// ),
// ],
// ),
// ),
// floatingActionButton: FloatingActionButton(
// onPressed:
// // If not yet listening for speech start, otherwise stop
// //sendPrompt,
// _speechToText.isNotListening ? _startListening : sendPrompt,
// tooltip: 'Listen',
// child: Icon(_speechToText.isNotListening ? Icons.mic_off : Icons.mic),
// ),
+43
View File
@@ -0,0 +1,43 @@
import 'package:speech_to_text/speech_recognition_result.dart';
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;
String text = "";
// Check if speech recognition is enabled.
bool isSpeechEnabled() => _speechEnabled;
Future<String> getTextWhenReady() async {
await _speechToText.stop();
return text;
}
// Retrieve the text.
String getText() => text;
// Reset either after saving the text or prior to using STT again.
void reset() => text = "";
/// Start a speech recognition session
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();
SpeechToText() {
_initSpeech();
}
/// This has to happen only once per app
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;
}
@@ -8,6 +8,7 @@ import Foundation
import path_provider_foundation import path_provider_foundation
import rive_common import rive_common
import shared_preferences_foundation import shared_preferences_foundation
import speech_to_text_macos
import sqflite import sqflite
import url_launcher_macos import url_launcher_macos
import video_player_avfoundation import video_player_avfoundation
@@ -16,6 +17,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
RivePlugin.register(with: registry.registrar(forPlugin: "RivePlugin")) RivePlugin.register(with: registry.registrar(forPlugin: "RivePlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
SpeechToTextMacosPlugin.register(with: registry.registrar(forPlugin: "SpeechToTextMacosPlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
FVPVideoPlayerPlugin.register(with: registry.registrar(forPlugin: "FVPVideoPlayerPlugin")) FVPVideoPlayerPlugin.register(with: registry.registrar(forPlugin: "FVPVideoPlayerPlugin"))
+32
View File
@@ -696,6 +696,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.1" version: "2.2.1"
pedantic:
dependency: transitive
description:
name: pedantic
sha256: "67fc27ed9639506c856c840ccce7594d0bdcd91bc8d53d6e52359449a1d50602"
url: "https://pub.dev"
source: hosted
version: "1.11.1"
percent_indicator: percent_indicator:
dependency: transitive dependency: transitive
description: description:
@@ -917,6 +925,30 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.10.0" version: "1.10.0"
speech_to_text:
dependency: "direct main"
description:
name: speech_to_text
sha256: "57fef1d41bdebe298e84842c89bb4ac91f31cdbec7830c8cb1fc6b91d03abd42"
url: "https://pub.dev"
source: hosted
version: "6.6.0"
speech_to_text_macos:
dependency: transitive
description:
name: speech_to_text_macos
sha256: e685750f7542fcaa087a5396ee471e727ec648bf681f4da83c84d086322173f6
url: "https://pub.dev"
source: hosted
version: "1.1.0"
speech_to_text_platform_interface:
dependency: transitive
description:
name: speech_to_text_platform_interface
sha256: a0df1a907091ea09880077dc25aae02af9f79811264e6e97ddb08639b7f771c2
url: "https://pub.dev"
source: hosted
version: "2.2.0"
sprintf: sprintf:
dependency: transitive dependency: transitive
description: description:
+1
View File
@@ -45,6 +45,7 @@ dependencies:
easy_debounce: any easy_debounce: any
video_player: ^2.9.1 video_player: ^2.9.1
flutter_riverpod: ^2.5.1 flutter_riverpod: ^2.5.1
speech_to_text: ^6.6.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter