integrated code from one-ai-mobile repo. working on GUI integration now.
This commit is contained in:
@@ -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,
|
||||||
|
|||||||
@@ -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),
|
||||||
|
// ),
|
||||||
@@ -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"))
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user