You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

239 lines
8.9 KiB

use std::{sync::mpsc::{self, Receiver, Sender}, time::Duration};
use chrono::Local;
use eframe::{
egui::{
self, CentralPanel, ComboBox, DragValue, Grid, Layout, ScrollArea, Sense, Slider, TextEdit,
Window,
},
emath::Align,
epaint::Vec2,
};
use egui_notify::Toasts;
use crate::{
ai::{generate_with_mpsc, Params, Response, ResponseType},
config::{AI, CONFIG},
history::{read_all_history, write_history, HistoryEntry},
};
pub struct App {
toasts: Toasts,
output: String,
selected_ai: AI,
params: Params,
history_open: bool,
history: Vec<HistoryEntry>,
open_history_entry: Option<HistoryEntry>,
tx: Sender<Response>,
rx: Receiver<Response>,
}
impl Default for App {
fn default() -> Self {
let (tx, rx) = mpsc::channel();
Self {
toasts: Default::default(),
output: "Awaiting generation...".to_string(),
selected_ai: CONFIG.ai[0].clone(),
params: Default::default(),
history_open: false,
history: vec![],
open_history_entry: None,
tx,
rx,
}
}
}
impl eframe::App for App {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
if let Ok(recieved) = self.rx.try_recv() {
if recieved.response_type == ResponseType::Success {
self.output = recieved.output.trim().to_string();
} else {
self.output = "Failed to generate!".to_string();
self.toasts
.error("Failed to generate! Error printed to console.");
eprintln!("{}", recieved.output);
}
match write_history(HistoryEntry {
date: Local::now(),
selected_ai: self.selected_ai.name.clone(),
params: self.params.clone(),
result: self.output.clone(),
}) {
Ok(_) => {}
Err(error) => {
self.toasts
.error(format!("Failed to write history! {}", error));
}
}
}
CentralPanel::default().show(ctx, |ui| {
Window::new("History")
.open(&mut self.history_open)
.collapsible(false)
.hscroll(true)
.show(ctx, |ui| {
if let Some(entry) = self.open_history_entry.clone() {
ui.set_max_width(580.0);
ui.horizontal(|ui| {
// maybe make these param indicators look more like the main ui somehow
ui.label(format!("{} - AI", entry.selected_ai));
ui.separator();
ui.label(format!(
"{} - Temperature",
entry.params.temperature.to_string()
));
ui.separator();
ui.label(format!(
"{} - Max Tokens",
entry.params.max_tokens.to_string()
));
ui.with_layout(Layout::right_to_left(Align::Max), |ui| {
if ui.button("Back").clicked() {
self.open_history_entry = None;
}
});
});
ui.with_layout(Layout::left_to_right(Align::Min), |ui| {
ScrollArea::vertical()
.id_source("history_prompt_scroll")
.show(ui, |ui| {
ui.add(TextEdit::multiline(&mut entry.params.prompt.as_str()));
});
ScrollArea::vertical()
.id_source("history_output_scroll")
.show(ui, |ui| {
ui.add(TextEdit::multiline(&mut entry.result.as_str()));
});
})
.response
.rect
.width();
} else {
ScrollArea::vertical()
.id_source("history_scroll")
.show(ui, |ui| {
Grid::new("history_grid").num_columns(1).show(
ui,
|ui| {
for entry in &self.history {
let response = ui
.horizontal(|ui| {
ui.label(&entry.selected_ai);
ui.label(
entry
.date
.format("%Y-%m-%d %H:%M:%S")
.to_string(),
)
})
.response;
let clickable =
ui.allocate_rect(response.rect, Sense::click());
if clickable.clicked() {
self.open_history_entry = Some(entry.clone());
}
ui.end_row()
}
},
);
});
}
});
ui.vertical(|ui| {
if ui.button("Generate!").clicked() {
self.output = "Generating...".to_string();
generate_with_mpsc(
self.selected_ai.clone(),
self.params.clone(),
self.tx.clone(),
)
}
ui.horizontal(|ui| {
ComboBox::from_label("AI")
.selected_text(&self.selected_ai.name)
.show_ui(ui, |ui| {
for ai in &CONFIG.ai {
ui.selectable_value(&mut self.selected_ai, ai.clone(), &ai.name);
}
});
ui.separator();
ui.add(
Slider::new(&mut self.params.temperature, 0.0..=2.0)
.text("Temperature")
.show_value(true),
);
ui.separator();
ui.add(DragValue::new(&mut self.params.max_tokens));
ui.label("Max Tokens");
ui.with_layout(Layout::right_to_left(Align::Max), |ui| {
ui.add_visible_ui(CONFIG.app.history_dir.is_some(), |ui| {
if ui.button("History").clicked() {
// add proper error handling
self.history = read_all_history().unwrap();
self.history_open = true;
}
});
});
});
ui.with_layout(Layout::left_to_right(Align::Min), |ui| {
let size = ui.available_size();
ScrollArea::vertical()
.id_source("prompt_scroll")
.show(ui, |ui| {
ui.add_sized(
Vec2::new(size.x / 2.0, size.y),
TextEdit::multiline(&mut self.params.prompt),
);
});
ScrollArea::vertical()
.id_source("output_scroll")
.show(ui, |ui| {
ui.add_sized(
Vec2::new(size.x / 2.0, size.y),
TextEdit::multiline(&mut self.output.as_str()),
);
});
});
});
self.toasts.show(ctx);
ctx.request_repaint_after(Duration::from_secs(1))
});
}
}