main: switch the app to use a message sink for UI messages, even though this can be blocking
This commit is contained in:
+31
-27
@@ -84,19 +84,22 @@ struct StageEventArgs {
|
||||
#[derive(Debug)]
|
||||
struct App {
|
||||
scene: Scene,
|
||||
end_time: DateTime<Utc>,
|
||||
|
||||
next_reply_options: Vec<PossibleResponse>,
|
||||
reply_state: ListState,
|
||||
conversation_state: ListState,
|
||||
user_input: Input,
|
||||
end_time: DateTime<Utc>,
|
||||
throbber_state: ThrobberState,
|
||||
prediction_request_sink: watch::Sender<Scene>,
|
||||
is_requesting: bool,
|
||||
audio_level: f64,
|
||||
recording_audio: bool,
|
||||
audio_control_sink: watch::Sender<AudioRecordRequest>,
|
||||
focus_state: FocusState,
|
||||
tts_request_sink: mpsc::Sender<String>
|
||||
|
||||
audio_control_sink: watch::Sender<AudioRecordRequest>,
|
||||
prediction_request_sink: watch::Sender<Scene>,
|
||||
tts_request_sink: mpsc::Sender<String>,
|
||||
sys_message_sink: mpsc::Sender<String>
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -106,7 +109,7 @@ enum FocusState {
|
||||
}
|
||||
|
||||
impl App {
|
||||
fn new(prediction_request_sink: watch::Sender<Scene>, audio_control_sink: watch::Sender<AudioRecordRequest>, tts_request_sink: mpsc::Sender<String>) -> Self {
|
||||
fn new(prediction_request_sink: watch::Sender<Scene>, audio_control_sink: watch::Sender<AudioRecordRequest>, tts_request_sink: mpsc::Sender<String>, sys_message_sink: mpsc::Sender<String>) -> Self {
|
||||
Self {
|
||||
scene: Scene::default(),
|
||||
next_reply_options: Vec::new(),
|
||||
@@ -121,7 +124,8 @@ impl App {
|
||||
recording_audio: false,
|
||||
audio_control_sink,
|
||||
focus_state: FocusState::UserInput,
|
||||
tts_request_sink
|
||||
tts_request_sink,
|
||||
sys_message_sink
|
||||
}
|
||||
}
|
||||
|
||||
@@ -355,65 +359,65 @@ impl App {
|
||||
match command {
|
||||
"/bandcamp" => {
|
||||
self.add_bandcamp_artifact(arg).await;
|
||||
self.scene.insert_conversation(ConversationEntry::SystemMessage(format!("Added Bandcamp artifact from {}", arg)));
|
||||
self.sys_message_sink.send(format!("Added Bandcamp artifact from {}", arg)).await.unwrap();
|
||||
self.scene.insert_conversation(ConversationEntry::ShipComputer(format!("Incoming transmission.")));
|
||||
},
|
||||
"/episode" => {
|
||||
if let Ok(episode_number) = arg.trim().parse::<u32>() {
|
||||
self.scene.direction.episode_number = episode_number;
|
||||
self.scene.insert_conversation(ConversationEntry::SystemMessage(format!("Updated episode number: {}", self.scene.direction.episode_number)));
|
||||
self.sys_message_sink.send(format!("Updated episode number: {}", self.scene.direction.episode_number)).await.unwrap();
|
||||
self.reload_mixxx_playlist();
|
||||
} else {
|
||||
self.scene.insert_conversation(ConversationEntry::SystemMessage("Invalid episode number format. Use /episode [number]".into()));
|
||||
self.sys_message_sink.send("Invalid episode number format. Use /episode [number]".into()).await.unwrap();
|
||||
}
|
||||
},
|
||||
"/reload" => {
|
||||
self.load();
|
||||
self.load().await;
|
||||
self.reload_mixxx_playlist();
|
||||
},
|
||||
"/timer" => {
|
||||
if let Ok(minutes) = arg.trim().parse::<i64>() {
|
||||
self.end_time = Utc::now() + Duration::minutes(minutes);
|
||||
self.scene.insert_conversation(ConversationEntry::SystemMessage(format!("Set timer for {} minutes.", minutes)));
|
||||
self.sys_message_sink.send(format!("Set timer for {} minutes.", minutes)).await.unwrap();
|
||||
} else {
|
||||
self.scene.insert_conversation(ConversationEntry::SystemMessage("Invalid timer format. Use /timer [minutes]".into()));
|
||||
self.sys_message_sink.send("Invalid timer format. Use /timer [minutes]".into()).await.unwrap();
|
||||
}
|
||||
}
|
||||
"/clear" => {
|
||||
match arg.trim() {
|
||||
"playlist" => {
|
||||
self.scene.direction.current_playlist.clear();
|
||||
self.scene.insert_conversation(ConversationEntry::SystemMessage("Cleared current playlist.".into()));
|
||||
self.sys_message_sink.send("Cleared current playlist.".into()).await.unwrap();
|
||||
return;
|
||||
},
|
||||
"artifacts" => {
|
||||
self.scene.direction.artifacts.clear();
|
||||
self.scene.insert_conversation(ConversationEntry::SystemMessage("Cleared artifacts.".into()));
|
||||
self.sys_message_sink.send("Cleared artifacts.".into()).await.unwrap();
|
||||
return;
|
||||
},
|
||||
"all" => {
|
||||
self.scene = Scene::default();
|
||||
self.scene.insert_conversation(ConversationEntry::SystemMessage("Cleared all data.".into()));
|
||||
self.sys_message_sink.send("Cleared all data.".into()).await.unwrap();
|
||||
},
|
||||
"conversation" => {
|
||||
self.scene.conversation.clear();
|
||||
self.scene.insert_conversation(ConversationEntry::SystemMessage("Cleared conversation.".into()));
|
||||
self.sys_message_sink.send("Cleared conversation.".into()).await.unwrap();
|
||||
},
|
||||
_ => {
|
||||
self.scene.insert_conversation(ConversationEntry::SystemMessage("Unknown clear command. Use /clear [playlist|artifacts|all]".into()));
|
||||
self.sys_message_sink.send("Unknown clear command. Use /clear [playlist|artifacts|all]".into()).await.unwrap();
|
||||
}
|
||||
}
|
||||
return;
|
||||
},
|
||||
"/narrative" => {
|
||||
self.scene.direction.narrative = arg.to_string();
|
||||
self.scene.insert_conversation(ConversationEntry::SystemMessage(format!("Updated stage direction: {}", self.scene.direction.narrative)));
|
||||
self.sys_message_sink.send(format!("Updated stage direction: {}", self.scene.direction.narrative)).await.unwrap();
|
||||
},
|
||||
"/event" => {
|
||||
self.scene.insert_conversation(ConversationEntry::StageDirection(arg.to_string()));
|
||||
}
|
||||
_ => {
|
||||
self.scene.insert_conversation(ConversationEntry::SystemMessage("Unknown command. Available commands: /bandcamp [url], /episode [number], /narrative [text], /reset".into()));
|
||||
self.sys_message_sink.send("Unknown command. Available commands: /bandcamp [url], /episode [number], /narrative [text], /reset".into()).await.unwrap();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -445,15 +449,15 @@ impl App {
|
||||
std::fs::write("save.json", save_data).unwrap();
|
||||
}
|
||||
|
||||
fn load(&mut self) {
|
||||
async fn load(&mut self) {
|
||||
if let Ok(save_data) = std::fs::read_to_string("save.json") {
|
||||
if let Ok(scene) = serde_json::from_str(&save_data) {
|
||||
self.scene = scene;
|
||||
// FIXME: These should get wiped out when we save as well, or even better, be completely excluded via a custom serde implementation.
|
||||
self.scene.conversation.retain(|line| { if let ConversationEntry::SystemMessage(_) = line { false } else { true }});
|
||||
self.scene.insert_conversation(ConversationEntry::SystemMessage("Loaded stored session.".into()));
|
||||
self.sys_message_sink.send("Loaded stored session.".into()).await.unwrap();
|
||||
} else {
|
||||
self.scene.insert_conversation(ConversationEntry::SystemMessage("Failed to load saved session!".into()));
|
||||
self.sys_message_sink.send("Failed to load saved session!".into()).await.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -534,13 +538,13 @@ async fn main() {
|
||||
|
||||
let mut terminal: Terminal<CrosstermBackend<std::io::Stdout>> = ratatui::init();
|
||||
|
||||
let (sys_message_sender, mut sys_message_receiver) = tokio::sync::mpsc::channel(5);
|
||||
let (sys_message_sink, mut sys_message_src) = tokio::sync::mpsc::channel(32);
|
||||
let tts_request_sender = start_tts().await;
|
||||
let (prediction_request_in, mut prediction_out) = prediction::start_prediction().await;
|
||||
let (mut audio_state_receiver, audio_control_in, mut transcription_out) = transcription::start_transcription(sys_message_sender).await;
|
||||
let (mut audio_state_receiver, audio_control_in, mut transcription_out) = transcription::start_transcription(sys_message_sink.clone()).await;
|
||||
|
||||
let mut app = App::new(prediction_request_in, audio_control_in, tts_request_sender);
|
||||
app.load();
|
||||
let mut app = App::new(prediction_request_in, audio_control_in, tts_request_sender, sys_message_sink);
|
||||
app.load().await;
|
||||
|
||||
let mut events = EventStream::new();
|
||||
let mut last_tick = Instant::now();
|
||||
@@ -564,7 +568,7 @@ async fn main() {
|
||||
_ = audio_state_receiver.changed() => {
|
||||
app.audio_level = *audio_state_receiver.borrow_and_update();
|
||||
},
|
||||
maybe_message = sys_message_receiver.recv() => {
|
||||
maybe_message = sys_message_src.recv() => {
|
||||
if let Some(message) = maybe_message {
|
||||
app.scene.insert_conversation(ConversationEntry::SystemMessage(message));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user