refactoring
partially implement tts for human interface
This commit is contained in:
@@ -105,6 +105,7 @@ pub struct OllamaConfig {
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct OllamaModelConfig {
|
||||
#[serde(rename = "from-model")]
|
||||
pub from_model: String,
|
||||
pub name: String,
|
||||
pub system_prompt: Option<String>,
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
use crate::human_interface::{HumanInterface, HumanInterfaceError};
|
||||
use own_mcp::audio::models::VoiceRequest;
|
||||
use own_mcp::audio::{AudioClient, AudioClientTrait};
|
||||
use own_mcp::mcp::chat::PermissionAnswer;
|
||||
use std::path::Path;
|
||||
use tokio::fs::create_dir_all;
|
||||
|
||||
const TEMPORARY_AUDIO_PATH: &str = "temporary_audio";
|
||||
|
||||
struct Audio {
|
||||
client: AudioClient,
|
||||
}
|
||||
|
||||
impl Audio {
|
||||
async fn new(client: AudioClient) -> Result<Self, HumanInterfaceError> {
|
||||
create_dir_all(TEMPORARY_AUDIO_PATH)
|
||||
.await
|
||||
.map_err(HumanInterfaceError::IoError)?;
|
||||
Ok(Self { client })
|
||||
}
|
||||
}
|
||||
|
||||
impl HumanInterface for Audio {
|
||||
async fn agent_message(&mut self, message: String) -> Result<(), HumanInterfaceError> {
|
||||
let bytes = self
|
||||
.client
|
||||
.tts(VoiceRequest {
|
||||
text: message,
|
||||
config: None,
|
||||
})
|
||||
.await
|
||||
.map_err(|e| HumanInterfaceError::Other(format!("Failed getting tts: {e}")))?;
|
||||
|
||||
tokio::fs::write(Path::new(TEMPORARY_AUDIO_PATH).join("tts.wav"), &bytes)
|
||||
.await
|
||||
.map_err(|e| HumanInterfaceError::IoError(e))
|
||||
}
|
||||
|
||||
async fn expect_user_message(&mut self) -> Result<String, HumanInterfaceError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn ask_for_permission(
|
||||
&self,
|
||||
mcp_server_name: String,
|
||||
tool_name: String,
|
||||
) -> Result<PermissionAnswer, HumanInterfaceError> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_tts_fetching() {
|
||||
let mut human_interface = Audio::new(
|
||||
AudioClient::new(
|
||||
url::Url::parse("https://audio.mboemer.de"
|
||||
).unwrap()).
|
||||
with_authorization(
|
||||
"Basic bWlsYW46a3lLRVIjOVJAaDlAXldBI3pVXkAhb0pRIXViczNNV0g3U1NzQDVUenppJVFmciY5WEpxJXB1YmN6YiEkdmY1Z2FQd0N2aEd3".to_string())
|
||||
).await.unwrap();
|
||||
|
||||
human_interface
|
||||
.agent_message(String::from("Peter ist jetzt in deinem PC."))
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ impl CommandLine {
|
||||
}
|
||||
|
||||
impl HumanInterface for CommandLine {
|
||||
fn agent_message(&mut self, message: String) {
|
||||
async fn agent_message(&mut self, message: String) -> Result<(), HumanInterfaceError> {
|
||||
// stopped waiting for message
|
||||
if let Some(progress_bar) = &self.progress_bar {
|
||||
progress_bar.finish_and_clear();
|
||||
@@ -30,6 +30,7 @@ impl HumanInterface for CommandLine {
|
||||
}
|
||||
|
||||
println!("{}: {}",style( tlt!("assistant")).bold().italic(),message);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn expect_user_message(&mut self) -> Result<String, HumanInterfaceError> {
|
||||
@@ -63,9 +64,5 @@ impl HumanInterface for CommandLine {
|
||||
false => Ok(PermissionAnswer::Denied),
|
||||
}
|
||||
}
|
||||
|
||||
async fn run(&mut self) -> Result<(), HumanInterfaceError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
pub mod cli;
|
||||
pub mod audio;
|
||||
|
||||
use thiserror::Error;
|
||||
use own_mcp::mcp::chat::PermissionAnswer;
|
||||
@@ -12,11 +13,9 @@ pub enum HumanInterfaceError {
|
||||
}
|
||||
|
||||
pub trait HumanInterface {
|
||||
fn agent_message(&mut self, message: String);
|
||||
fn agent_message(&mut self, message: String) -> impl Future<Output = Result<(), HumanInterfaceError>>;
|
||||
|
||||
fn expect_user_message(&mut self) -> impl Future<Output = Result<String, HumanInterfaceError>>;
|
||||
|
||||
fn ask_for_permission(&self, mcp_server_name: String, tool_name:String) -> impl Future<Output = Result<PermissionAnswer, HumanInterfaceError>>;
|
||||
|
||||
fn run(&mut self) -> impl Future<Output = Result<(), HumanInterfaceError>>;
|
||||
}
|
||||
+13
-6
@@ -7,9 +7,9 @@ use crate::config::Config;
|
||||
use crate::human_interface::HumanInterface;
|
||||
use crate::i18n::translate;
|
||||
use crate::model::create_model_from_config;
|
||||
use base64::Engine;
|
||||
use clap::Parser;
|
||||
use std::fmt::Display;
|
||||
use base64::Engine;
|
||||
|
||||
/// partial mcp client with cli and voice interaction
|
||||
#[derive(Parser, Debug)]
|
||||
@@ -31,7 +31,7 @@ fn basic_auth_tool() {
|
||||
.interact()
|
||||
.unwrap();
|
||||
|
||||
let encoded= base64::prelude::BASE64_STANDARD.encode(format!("{}:{}", username, password));
|
||||
let encoded = base64::prelude::BASE64_STANDARD.encode(format!("{}:{}", username, password));
|
||||
println!("Basic {}", encoded);
|
||||
}
|
||||
|
||||
@@ -86,7 +86,6 @@ async fn main() {
|
||||
);
|
||||
|
||||
let mut human_interface = human_interface::cli::CommandLine::new();
|
||||
human_interface.run().await.unwrap();
|
||||
|
||||
loop {
|
||||
let user_message = human_interface.expect_user_message().await.unwrap();
|
||||
@@ -96,13 +95,21 @@ async fn main() {
|
||||
immutable_interface
|
||||
.ask_for_permission(mcp_server_name, tool_name)
|
||||
.await
|
||||
.inspect_err(exit_msg!("Human interface error"))
|
||||
.inspect_err(exit_msg!(
|
||||
"Human interface error while asking for permission"
|
||||
))
|
||||
.unwrap()
|
||||
})
|
||||
.await
|
||||
.inspect_err(exit_msg!("failed communicating with agent"))
|
||||
.inspect_err(exit_msg!("Failed communicating with agent."))
|
||||
.unwrap();
|
||||
human_interface
|
||||
.agent_message(agent_message.content)
|
||||
.await
|
||||
.inspect_err(exit_msg!(
|
||||
"Human interface error while trying to display message"
|
||||
))
|
||||
.unwrap();
|
||||
human_interface.agent_message(agent_message.content);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+18
-3
@@ -1,10 +1,10 @@
|
||||
use crate::translate;
|
||||
use crate::config::OllamaModelConfig;
|
||||
use crate::tlt;
|
||||
use crate::translate;
|
||||
use ollama_rs::Ollama;
|
||||
use ollama_rs::error::OllamaError;
|
||||
use ollama_rs::models::ModelOptions;
|
||||
use ollama_rs::models::create::{CreateModelRequest, CreateModelStatus};
|
||||
use crate::tlt;
|
||||
|
||||
pub async fn create_model_from_config(
|
||||
ollama: &Ollama,
|
||||
@@ -14,7 +14,22 @@ pub async fn create_model_from_config(
|
||||
.num_ctx(config.context_size.unwrap_or(2048)) // 2048 is the ollama default.
|
||||
.temperature(config.temperature.unwrap_or(0.8)); // 0.8 is the ollama default
|
||||
|
||||
let system_prompt = config.system_prompt.clone().unwrap_or(tlt!("system_prompt"));
|
||||
let system_prompt = config
|
||||
.system_prompt
|
||||
.clone()
|
||||
.unwrap_or(tlt!("system_prompt"));
|
||||
|
||||
// print message to warn user of long waiting times
|
||||
if let Ok(models) = ollama.list_local_models().await
|
||||
&& !models.iter().any(|m| m.name == config.from_model)
|
||||
{
|
||||
let message = format!(
|
||||
"Model `{}` is not installed and will be downloaded first.",
|
||||
config.from_model
|
||||
);
|
||||
log::info!("{}", message);
|
||||
println!("{}", console::style(message).yellow().bold());
|
||||
}
|
||||
|
||||
ollama
|
||||
.create_model(
|
||||
|
||||
Reference in New Issue
Block a user