ui: add some sfx integration to the UI, fix a json crash
This commit is contained in:
+3
-4
@@ -134,13 +134,12 @@ async fn main() {
|
|||||||
|
|
||||||
let (audio_ctrl, mic_stream, tts_output, sfx_output) = start_audio_input().await;
|
let (audio_ctrl, mic_stream, tts_output, sfx_output) = start_audio_input().await;
|
||||||
let tts_ctrl = start_tts(tts_output).await;
|
let tts_ctrl = start_tts(tts_output).await;
|
||||||
let mut sfx_ctrl = start_sfx(sfx_output).await;
|
let sfx_ctrl = start_sfx(sfx_output).await;
|
||||||
sfx_ctrl.play_ambient().await.unwrap();
|
|
||||||
let transcription_ctrl = transcription::start_transcription(mic_stream).await;
|
let transcription_ctrl = transcription::start_transcription(mic_stream).await;
|
||||||
|
|
||||||
let prediction_ctrl = prediction::conversation_task(saved_session, conversation_src, sfx_ctrl).await;
|
let prediction_ctrl = prediction::conversation_task(saved_session, conversation_src, sfx_ctrl.clone()).await;
|
||||||
|
|
||||||
let mut app = Ui::new(prediction_ctrl, audio_ctrl, transcription_ctrl, tts_ctrl);
|
let mut app = Ui::new(prediction_ctrl, audio_ctrl, transcription_ctrl, tts_ctrl, sfx_ctrl);
|
||||||
|
|
||||||
let mut events = EventStream::new();
|
let mut events = EventStream::new();
|
||||||
|
|
||||||
|
|||||||
@@ -99,7 +99,11 @@ impl Conversation {
|
|||||||
self.backlog.push(entry.clone());
|
self.backlog.push(entry.clone());
|
||||||
self.event_sink.send(SessionUpdate::Conversation(self.backlog.clone())).unwrap();
|
self.event_sink.send(SessionUpdate::Conversation(self.backlog.clone())).unwrap();
|
||||||
match entry {
|
match entry {
|
||||||
ConversationEntry::Spoken(_, _) => {
|
ConversationEntry::Spoken(speaker, _) => {
|
||||||
|
match speaker {
|
||||||
|
Speaker::User => (),
|
||||||
|
_ => self.sfx.play_ambient().await.unwrap(),
|
||||||
|
}
|
||||||
if let Ok(next_msg) = TryInto::<ChatCompletionRequestMessage>::try_into(entry) {
|
if let Ok(next_msg) = TryInto::<ChatCompletionRequestMessage>::try_into(entry) {
|
||||||
self.send_to(Speaker::Eva, next_msg.clone()).await;
|
self.send_to(Speaker::Eva, next_msg.clone()).await;
|
||||||
let cxt = self.context_for_speaker(Speaker::Eva).await;
|
let cxt = self.context_for_speaker(Speaker::Eva).await;
|
||||||
@@ -158,11 +162,11 @@ impl Conversation {
|
|||||||
async fn process_dialog(&mut self, speaker: Speaker, value: Value) {
|
async fn process_dialog(&mut self, speaker: Speaker, value: Value) {
|
||||||
match speaker {
|
match speaker {
|
||||||
Speaker::Eva => {
|
Speaker::Eva => {
|
||||||
let next_options = serde_json::from_value(value).unwrap();
|
// TODO: Handle crash from bad json
|
||||||
|
let next_options = serde_json::from_value(value).unwrap_or_default();
|
||||||
self.event_sink.send(SessionUpdate::Responses(next_options)).unwrap();
|
self.event_sink.send(SessionUpdate::Responses(next_options)).unwrap();
|
||||||
},
|
},
|
||||||
Speaker::ShipComputer => {
|
Speaker::ShipComputer => {
|
||||||
self.sfx.play_ambient().await.unwrap();
|
|
||||||
let response: ComputerResponse = serde_json::from_value(value).unwrap();
|
let response: ComputerResponse = serde_json::from_value(value).unwrap();
|
||||||
self.insert(ConversationEntry::Spoken(Speaker::ShipComputer, response.message)).await;
|
self.insert(ConversationEntry::Spoken(Speaker::ShipComputer, response.message)).await;
|
||||||
if response.finished.unwrap_or_default() {
|
if response.finished.unwrap_or_default() {
|
||||||
@@ -326,8 +330,8 @@ pub async fn conversation_task(save_data: SaveData, sys_log_messages: tokio::syn
|
|||||||
]),
|
]),
|
||||||
event_sink,
|
event_sink,
|
||||||
input_src,
|
input_src,
|
||||||
|
eva_backlog: save_data.messages,
|
||||||
backlog,
|
backlog,
|
||||||
eva_backlog: Default::default(),
|
|
||||||
tokens_consumed: save_data.tokens_consumed,
|
tokens_consumed: save_data.tokens_consumed,
|
||||||
direction: save_data.direction,
|
direction: save_data.direction,
|
||||||
archive,
|
archive,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use tokio::time::Instant;
|
|||||||
use tui_input::{Input, backend::crossterm::EventHandler};
|
use tui_input::{Input, backend::crossterm::EventHandler};
|
||||||
use tui_skeleton::{AnimationMode, Block, Constraint, SkeletonText};
|
use tui_skeleton::{AnimationMode, Block, Constraint, SkeletonText};
|
||||||
|
|
||||||
use crate::{audio::AudioInputControl, prediction::{GeneratedResponses, PredictionAction, SessionControl, SessionUpdate}, scene::{Scene, conversation::{ConversationEntry, Speaker}}, transcription::TranscriptionControl, tts::TtsControl};
|
use crate::{audio::AudioInputControl, prediction::{GeneratedResponses, PredictionAction, SessionControl, SessionUpdate}, scene::{Scene, conversation::{ConversationEntry, Speaker}}, sfx::SfxControl, transcription::TranscriptionControl, tts::TtsControl};
|
||||||
use crate::widgets::*;
|
use crate::widgets::*;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -30,7 +30,8 @@ pub struct Ui {
|
|||||||
audio: AudioInputControl,
|
audio: AudioInputControl,
|
||||||
tts: TtsControl,
|
tts: TtsControl,
|
||||||
predictions: SessionControl,
|
predictions: SessionControl,
|
||||||
conversation: Vec<ConversationEntry>
|
conversation: Vec<ConversationEntry>,
|
||||||
|
sfx: SfxControl
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -40,7 +41,7 @@ enum FocusState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Ui {
|
impl Ui {
|
||||||
pub fn new(predictions: SessionControl, audio: AudioInputControl, transcription: TranscriptionControl, tts: TtsControl) -> Self {
|
pub fn new(predictions: SessionControl, audio: AudioInputControl, transcription: TranscriptionControl, tts: TtsControl, sfx: SfxControl) -> Self {
|
||||||
Self {
|
Self {
|
||||||
scene: Default::default(),
|
scene: Default::default(),
|
||||||
reply_state: Default::default(),
|
reply_state: Default::default(),
|
||||||
@@ -58,7 +59,8 @@ impl Ui {
|
|||||||
predictions,
|
predictions,
|
||||||
last_tick: Instant::now(),
|
last_tick: Instant::now(),
|
||||||
conversation: vec![],
|
conversation: vec![],
|
||||||
reply_options: Default::default()
|
reply_options: Default::default(),
|
||||||
|
sfx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,6 +195,9 @@ impl Ui {
|
|||||||
"/computer" => {
|
"/computer" => {
|
||||||
self.predictions.insert(PredictionAction::ComputerCommand(arg.to_string())).await;
|
self.predictions.insert(PredictionAction::ComputerCommand(arg.to_string())).await;
|
||||||
},
|
},
|
||||||
|
"/ambient" => {
|
||||||
|
self.sfx.play_ambient().await.unwrap()
|
||||||
|
},
|
||||||
_ => {
|
_ => {
|
||||||
log::error!("Unknown command. Available commands: /episode [number], /narrative [text], /event [text], /computer [text], /timer [minutes]");
|
log::error!("Unknown command. Available commands: /episode [number], /narrative [text], /event [text], /computer [text], /timer [minutes]");
|
||||||
}
|
}
|
||||||
@@ -220,6 +225,7 @@ impl Ui {
|
|||||||
let row_num = self.conversation_state.selected().unwrap();
|
let row_num = self.conversation_state.selected().unwrap();
|
||||||
if let ConversationEntry::Spoken(Speaker::Eva, text) = &self.conversation[self.conversation.len() - 1 - row_num] {
|
if let ConversationEntry::Spoken(Speaker::Eva, text) = &self.conversation[self.conversation.len() - 1 - row_num] {
|
||||||
self.tts.speak(text.clone()).await.unwrap();
|
self.tts.speak(text.clone()).await.unwrap();
|
||||||
|
self.sfx.play_ambient().await.unwrap();
|
||||||
self.focus_state = FocusState::UserInput;
|
self.focus_state = FocusState::UserInput;
|
||||||
self.conversation_state.select(None);
|
self.conversation_state.select(None);
|
||||||
self.reply_state.select_first();
|
self.reply_state.select_first();
|
||||||
|
|||||||
Reference in New Issue
Block a user