diff --git a/PKGBUILD b/PKGBUILD index 7e4d73d..18e1cb0 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -1,5 +1,5 @@ pkgname=worldcoder -pkgver=0.1.0 +pkgver=0.1.1 pkgrel=1 makedepends=('rust' 'cargo') arch=('i686' 'x86_64' 'armv6h' 'armv7h') diff --git a/src/llm_integration/content_llm.rs b/src/llm_integration/content_llm.rs index 4fcc680..61a0888 100644 --- a/src/llm_integration/content_llm.rs +++ b/src/llm_integration/content_llm.rs @@ -27,48 +27,111 @@ impl ContentAI { if is_open { egui::SidePanel::right("ai_assistant").show_inside(ui, |ui| { - Self::ui_continue(self, ui, project); + Self::ui_main(self, ui, project); }); } self.open = is_open; } - fn ui_continue(&mut self, ui: &mut egui::Ui, project: &mut ProjectSettings) { + fn ui_output_box(&mut self, ui: &mut egui::Ui, project: &mut ProjectSettings) { + egui::TopBottomPanel::bottom("llm_output") + .resizable(true) + .show_inside(ui, |ui| { + let mut ready_lock = self.ready.lock().unwrap(); + + ui.horizontal(|ui| { + if *ready_lock == ReadyState::Generating { + if ui.button("Cancel").clicked() { + *ready_lock = ReadyState::Halted; + } + if ui.button("Stop").clicked() { + *ready_lock = ReadyState::Idle; + } + ui.spinner(); + ui.label("Generating..."); + } + + if *ready_lock == ReadyState::Idle { + let continue_content = || { + let context_override = self.context_override.clone(); + let content = self.content.clone(); + let instruction = self.instruction.clone(); + let project = project.clone(); + let ai_context = project.ai_context.clone(); + let result = self.result.clone(); + let ready = self.ready.clone(); + + let options = AIOptions { + max_completion_tokens: self.max_tokens, + reasoning_effort: self.reasoning_effort, + temperature: self.temperature, + model_override: if !self.model_override.is_empty() { + Some(self.model_override.clone()) + } else { + None + }, + }; + + result.lock().unwrap().clear(); + + std::thread::spawn(move || { + let result = crate::llm_integration::content_llm::continue_content( + ai_context + "\n" + &context_override, + content, + instruction, + options, + project, + result, + ready.clone(), + ); + if let Err(e) = result { + eprintln!("Error in content generation: {e}"); + } + }); + }; + + if ui.button("Generate ").clicked() { + continue_content(); + } + + ui.label("Idle"); + } + + // show regardless of state + if ui.button("Insert").clicked() { + *self.ready.lock().unwrap() = ReadyState::Ready; + } + + if ui.button("Clear").clicked() { + self.result.lock().unwrap().clear(); + } + }); + + ui.separator(); + + egui::ScrollArea::both() + .auto_shrink([false, false]) + .id_salt("llm_output") + .max_width(ui.available_width()) + // .max_height(ui.available_height() / 3.0) + .show(ui, |ui| { + ui.add( + egui::TextEdit::multiline(&mut *self.result.lock().unwrap()) + .font(egui::TextStyle::Monospace) + .interactive(false) + .desired_rows(0) + .frame(false) + .desired_width(ui.available_width()) + .lock_focus(true) + .hint_text("Content will appear here..."), + ); + }); + }); + } + + fn ui_main(&mut self, ui: &mut egui::Ui, project: &mut ProjectSettings) { { ui.weak("(The model will see current file content)"); - ui.separator(); - - // Instructions - egui::ScrollArea::both() - .id_salt("continue_instruction") - .auto_shrink([true, false]) - .max_height(ui.available_height() / 4.0) - .max_width(ui.available_width()) - .show(ui, |ui| { - ui.add( - egui::TextEdit::multiline(&mut self.instruction) - .frame(false) - .desired_width(ui.available_width()) - .hint_text("Writing Instructions"), - ); - }); - ui.separator(); - - // Context - egui::ScrollArea::both() - .id_salt("continue_context") - .auto_shrink([true, false]) - .max_height(ui.available_height() / 4.0) - .max_width(ui.available_width()) - .show(ui, |ui| { - ui.add( - egui::TextEdit::multiline(&mut self.context_override) - .frame(false) - .desired_width(ui.available_width()) - .hint_text("Any additional context?"), - ); - }); - ui.separator(); egui::Grid::new("continue_grid") .num_columns(2) @@ -123,107 +186,39 @@ impl ContentAI { ui.end_row(); }); + self.ui_output_box(ui, project); + ui.separator(); - let mut ready_lock = self.ready.lock().unwrap(); + // Instructions + egui::ScrollArea::both() + .id_salt("continue_instruction") + .auto_shrink([true, false]) + .max_height(ui.available_height() / 2.0) + .max_width(ui.available_width()) + .show(ui, |ui| { + ui.add( + egui::TextEdit::multiline(&mut self.instruction) + .frame(false) + .desired_width(ui.available_width()) + .hint_text("Writing Instructions"), + ); + }); + ui.separator(); - match *ready_lock { - ReadyState::Idle => { - let continue_content = || { - let context_override = self.context_override.clone(); - let content = self.content.clone(); - let instruction = self.instruction.clone(); - let project = project.clone(); - let ai_context = project.ai_context.clone(); - let result = self.result.clone(); - let ready = self.ready.clone(); - - let options = AIOptions { - max_completion_tokens: self.max_tokens, - reasoning_effort: self.reasoning_effort, - temperature: self.temperature, - model_override: if !self.model_override.is_empty() { - Some(self.model_override.clone()) - } else { - None - }, - }; - - result.lock().unwrap().clear(); - - std::thread::spawn(move || { - let result = crate::llm_integration::content_llm::continue_content( - ai_context + "\n" + &context_override, - content, - instruction, - options, - project, - result, - ready.clone(), - ); - if let Err(e) = result { - eprintln!("Error in content generation: {e}"); - } - }); - }; - - ui.horizontal(|ui| { - if ui.button("Generate ").clicked() { - continue_content(); - } - - ui.label("Idle"); - }); - } - - ReadyState::Generating => { - ui.horizontal(|ui| { - if ui.button("Cancel").clicked() { - *ready_lock = ReadyState::Halted; - } - if ui.button("Stop").clicked() { - *ready_lock = ReadyState::Idle; - } - ui.spinner(); - ui.label("Generating..."); - }); - } - - ReadyState::Halted => {} - ReadyState::Ready => {} - } - - egui::TopBottomPanel::bottom("llm_output") - .resizable(true) - .show_inside(ui, |ui| { - egui::ScrollArea::both() - .auto_shrink([false, false]) - .id_salt("llm_output") - .max_width(ui.available_width()) - // .max_height(ui.available_height() / 3.0) - .show(ui, |ui| { - ui.add( - egui::TextEdit::multiline(&mut *self.result.lock().unwrap()) - .font(egui::TextStyle::Monospace) - .interactive(false) - .desired_rows(0) - .frame(false) - .desired_width(ui.available_width()) - .lock_focus(true) - .hint_text("Content will appear here..."), - ); - }); - - ui.separator(); - ui.horizontal(|ui| { - if ui.button("Insert").clicked() { - *ready_lock = ReadyState::Ready; - } - - if ui.button("Clear").clicked() { - self.result.lock().unwrap().clear(); - } - }); + // Context + egui::ScrollArea::both() + .id_salt("continue_context") + .auto_shrink([true, false]) + .max_height(ui.available_height()) + .max_width(ui.available_width()) + .show(ui, |ui| { + ui.add( + egui::TextEdit::multiline(&mut self.context_override) + .frame(false) + .desired_width(ui.available_width()) + .hint_text("Any additional context?"), + ); }); } }