src: adopt the log crate and feed logs into the UI

This commit is contained in:
2026-06-09 20:24:11 +02:00
parent eeb27656c7
commit 96ec57b2d9
5 changed files with 97 additions and 41 deletions
+30 -11
View File
@@ -1,12 +1,15 @@
use std::{cell::RefCell, rc::Rc, sync::Arc};
use async_openai::types::chat::ChatCompletionRequestMessage;
use chrono::{Duration, Utc};
use futures_timer::Delay;
use serde::{Deserialize, Serialize};
use ratatui::{Frame, layout::{Constraint, Direction, Layout}, widgets::{Block, BorderType, Clear, Gauge, List, ListDirection, ListState, Paragraph, Wrap}};
use static_cell::StaticCell;
use throbber_widgets_tui::{Throbber, ThrobberState};
use crossterm::{event::{self, EventStream, KeyCode, KeyModifiers}};
use tokio::time::Instant;
use tokio::{sync::RwLock, time::Instant};
use tui_input::{Input, backend::crossterm::EventHandler};
use futures::{StreamExt, future::FutureExt};
@@ -492,6 +495,20 @@ impl SaveData {
}
}
struct SysMessageLogger(Arc<tokio::sync::mpsc::UnboundedSender<String>>);
impl log::Log for SysMessageLogger {
fn enabled(&self, metadata: &log::Metadata) -> bool {
true
}
fn flush(&self) {}
fn log(&self, record: &log::Record) {
self.0.send(format!("{}", record.args())).unwrap();
}
}
#[tokio::main]
async fn main() {
let (panic_hook, eyre_hook) = color_eyre::config::HookBuilder::default()
@@ -505,6 +522,13 @@ async fn main() {
println!("Panic: {}", msg);
}));
let (sys_message_sink, sys_message_src) = tokio::sync::mpsc::unbounded_channel();
static LOGGER: StaticCell<SysMessageLogger> = StaticCell::new();
let logger = LOGGER.init(SysMessageLogger(Arc::new(sys_message_sink)));
log::set_logger(logger).unwrap();
log::set_max_level(log::LevelFilter::Info);
dotenv::dotenv().ok();
if std::env::var("OPENAI_API_KEY").is_err() {
@@ -514,23 +538,21 @@ async fn main() {
let mut terminal: Terminal<CrosstermBackend<std::io::Stdout>> = ratatui::init();
let (sys_message_sink, mut sys_message_src) = tokio::sync::mpsc::channel(32);
let saved_session = if let Ok(save_data) = std::fs::read_to_string("save.json") {
if let Ok(ret) = serde_json::from_str(&save_data) {
sys_message_sink.send("Loaded session from save.json".into()).await.unwrap();
log::info!("Loaded session from save.json");
ret
} else {
sys_message_sink.send("Could not load saved session!".into()).await.unwrap();
log::warn!("Could not load saved session!");
SaveData::default()
}
} else {
sys_message_sink.send("Creating new session in save.json".into()).await.unwrap();
log::info!("Creating new session in save.json");
SaveData::default()
};
let prediction_ctrl = prediction::start_prediction(saved_session).await;
let (audio_ctrl, mic_stream, tts_output) = start_audio_input(&sys_message_sink).await;
let prediction_ctrl = prediction::start_prediction(saved_session, sys_message_src).await;
let (audio_ctrl, mic_stream, tts_output) = start_audio_input().await;
let tts_ctrl = start_tts(tts_output).await;
let transcription_ctrl = transcription::start_transcription(mic_stream).await;
@@ -551,9 +573,6 @@ async fn main() {
tokio::select! {
_ = delay => (),
Some(next_log) = sys_message_src.recv() => {
app.predictions.insert(PredictionAction::ConversationAppend(ConversationEntry::SystemMessage(next_log))).await;
},
next_update = app.predictions.changed() => {
match next_update {
SessionUpdate::Thinking(is_thinking) => app.is_requesting = is_thinking,