src: split out conversation and archive bits into separate modules
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::artifacts::Artifact;
|
||||
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone, JsonSchema)]
|
||||
pub struct BeatsQueryArgs {
|
||||
artist: Option<String>,
|
||||
album: Option<String>,
|
||||
genre: Option<String>,
|
||||
title: Option<String>,
|
||||
year: Option<u32>
|
||||
}
|
||||
|
||||
impl BeatsQueryArgs {
|
||||
pub fn execute(self) -> Result<Artifact, ()> {
|
||||
let mut beets_cmd = Command::new("beet");
|
||||
beets_cmd.args(["export", "-f", "json", "-i", "title,label,year,genres,album,artist"]);
|
||||
if let Some(artist) = self.artist {
|
||||
beets_cmd.arg(format!("artist:{}", artist));
|
||||
}
|
||||
if let Some(genre) = self.genre {
|
||||
beets_cmd.arg(format!("genre:{}", genre));
|
||||
}
|
||||
if let Some(album) = self.album {
|
||||
beets_cmd.arg(format!("album:{}", album));
|
||||
}
|
||||
if let Some(title) = self.title {
|
||||
beets_cmd.arg(format!("title:{}", title));
|
||||
}
|
||||
if let Some(year) = self.year {
|
||||
beets_cmd.arg(format!("year:{}", year));
|
||||
}
|
||||
|
||||
if let Ok(output) = beets_cmd.stdout(Stdio::piped()).spawn().unwrap().wait_with_output() {
|
||||
//messages.push(ConversationEntry::ShipComputer(format!("Executing archive query {:?}", beets_cmd)));
|
||||
Ok(Artifact::BeetsTrack(serde_json::from_str(str::from_utf8(&output.stdout).unwrap()).unwrap()))
|
||||
} else {
|
||||
Err(())
|
||||
//messages.push(ConversationEntry::ShipComputer("Unable to execute query!".into()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
||||
@@ -43,3 +44,8 @@ impl Into<Artifact> for bandcamp::Artist {
|
||||
Artifact::Bandcamp(self.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)]
|
||||
pub struct BandcampQueryArgs {
|
||||
pub query: String
|
||||
}
|
||||
+2
-1
@@ -13,7 +13,7 @@ use futures::{StreamExt, future::FutureExt};
|
||||
use ratatui::prelude::*;
|
||||
use tui_skeleton::{AnimationMode, SkeletonText};
|
||||
|
||||
use crate::{audio::{AudioInputControl, start_audio_input}, prediction::{SessionControl, SessionUpdate}, scene::{ConversationEntry, PredictionAction, Scene, Scenery, StageDirection}, transcription::TranscriptionControl, tts::{TtsControl, start_tts}};
|
||||
use crate::{audio::{AudioInputControl, start_audio_input}, prediction::{SessionControl, SessionUpdate}, scene::{PredictionAction, Scene, Scenery, StageDirection, conversation::ConversationEntry}, transcription::TranscriptionControl, tts::{TtsControl, start_tts}};
|
||||
|
||||
mod scene;
|
||||
mod events;
|
||||
@@ -22,6 +22,7 @@ mod tts;
|
||||
mod prediction;
|
||||
mod audio;
|
||||
mod artifacts;
|
||||
mod archive;
|
||||
|
||||
// TODO: We should be able to delete entries from the conversation, or at least go back and edit something I said.
|
||||
// TODO: I want a "mark" command or keyboard shortcut, that inserts a marker into the log, so I know where to come back for the next speaking segment.
|
||||
|
||||
+4
-37
@@ -1,5 +1,3 @@
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
use async_openai::{Client, config::OpenAIConfig, types::chat::{ChatCompletionMessageToolCalls, ChatCompletionRequestAssistantMessageArgs, ChatCompletionRequestMessage, ChatCompletionRequestSystemMessageArgs, ChatCompletionRequestToolMessageArgs, ChatCompletionTool, ChatCompletionTools, CreateChatCompletionRequestArgs, FinishReason, FunctionObjectArgs, ResponseFormat, ResponseFormatJsonSchema}};
|
||||
use bandcamp::SearchResultItem;
|
||||
use schemars::{JsonSchema, schema_for};
|
||||
@@ -7,7 +5,7 @@ use serde::{Deserialize, Serialize};
|
||||
use serde_json::{Serializer, ser::CompactFormatter};
|
||||
use tokio::sync::{mpsc, watch};
|
||||
|
||||
use crate::{SaveData, artifacts::{Artifact, BandcampResult}, scene::{ConversationEntry, PredictionAction, Scene, Scenery, StageDirection}};
|
||||
use crate::{SaveData, archive::BeatsQueryArgs, artifacts::BandcampQueryArgs, scene::{PredictionAction, Scene, Scenery, StageDirection, conversation::ConversationEntry}};
|
||||
|
||||
|
||||
const SYSTEM_PROMPT: &str = include_str!("system-prompt.txt");
|
||||
@@ -47,20 +45,6 @@ struct StageEventArgs {
|
||||
event: StageEvent
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone, JsonSchema)]
|
||||
struct BeatsQueryArgs {
|
||||
artist: Option<String>,
|
||||
album: Option<String>,
|
||||
genre: Option<String>,
|
||||
title: Option<String>,
|
||||
year: Option<u32>
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)]
|
||||
struct BandcampQueryArgs {
|
||||
query: String
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
struct ToolResults {
|
||||
result: Option<String>,
|
||||
@@ -132,26 +116,9 @@ impl Session {
|
||||
|
||||
async fn tool_artifact_query(&mut self, args: BeatsQueryArgs) -> ToolResults {
|
||||
let mut messages = vec![];
|
||||
let mut beets_cmd = Command::new("beet");
|
||||
beets_cmd.args(["export", "-f", "json", "-i", "title,label,year,genres,album,artist"]);
|
||||
if let Some(artist) = args.artist {
|
||||
beets_cmd.arg(format!("artist:{}", artist));
|
||||
}
|
||||
if let Some(genre) = args.genre {
|
||||
beets_cmd.arg(format!("genre:{}", genre));
|
||||
}
|
||||
if let Some(album) = args.album {
|
||||
beets_cmd.arg(format!("album:{}", album));
|
||||
}
|
||||
if let Some(title) = args.title {
|
||||
beets_cmd.arg(format!("title:{}", title));
|
||||
}
|
||||
if let Some(year) = args.year {
|
||||
beets_cmd.arg(format!("year:{}", year));
|
||||
}
|
||||
if let Ok(output) = beets_cmd.stdout(Stdio::piped()).spawn().unwrap().wait_with_output() {
|
||||
messages.push(ConversationEntry::ShipComputer(format!("Executing archive query {:?}", beets_cmd)));
|
||||
self.scenery.artifacts.push(Artifact::BeetsTrack(serde_json::from_str(str::from_utf8(&output.stdout).unwrap()).unwrap()));
|
||||
messages.push(ConversationEntry::ShipComputer(format!("Executing archive query {:?}", args)));
|
||||
if let Ok(output) = args.execute() {
|
||||
self.scenery.artifacts.push(output);
|
||||
} else {
|
||||
messages.push(ConversationEntry::ShipComputer("Unable to execute query!".into()));
|
||||
};
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
use async_openai::types::chat::{ChatCompletionRequestAssistantMessage, ChatCompletionRequestAssistantMessageContent, ChatCompletionRequestMessage, ChatCompletionRequestSystemMessage, ChatCompletionRequestSystemMessageContent, ChatCompletionRequestUserMessage, ChatCompletionRequestUserMessageContent};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum ConversationEntry {
|
||||
User(String),
|
||||
Eva(String),
|
||||
ShipComputer(String),
|
||||
StageDirection(String),
|
||||
SystemMessage(String)
|
||||
}
|
||||
|
||||
impl TryInto<ChatCompletionRequestMessage> for ConversationEntry {
|
||||
fn try_into(self) -> Result<ChatCompletionRequestMessage, Self::Error> {
|
||||
match self {
|
||||
ConversationEntry::User(text) => Ok(ChatCompletionRequestMessage::User(ChatCompletionRequestUserMessage { content: text.into(), ..Default::default()})),
|
||||
ConversationEntry::Eva(text) => Ok(ChatCompletionRequestMessage::Assistant(ChatCompletionRequestAssistantMessage { content: Some(text.into()), ..Default::default()})),
|
||||
ConversationEntry::ShipComputer(text) => Ok(ChatCompletionRequestMessage::System(ChatCompletionRequestSystemMessage { content: text.into(), name: Some("ship-computer".into()), ..Default::default() })),
|
||||
ConversationEntry::StageDirection(text) => Ok(ChatCompletionRequestMessage::System(ChatCompletionRequestSystemMessage { content: text.into(), name: Some("stage-direction".into()), ..Default::default() })),
|
||||
_ => Err(())
|
||||
}
|
||||
}
|
||||
|
||||
type Error = ();
|
||||
}
|
||||
|
||||
|
||||
impl TryInto<ConversationEntry> for ChatCompletionRequestMessage {
|
||||
fn try_into(self) -> Result<ConversationEntry, Self::Error> {
|
||||
match self {
|
||||
ChatCompletionRequestMessage::User(ChatCompletionRequestUserMessage { content: ChatCompletionRequestUserMessageContent::Text(msg), ..}) => Ok(ConversationEntry::User(msg)),
|
||||
ChatCompletionRequestMessage::Assistant(ChatCompletionRequestAssistantMessage { content: Some(ChatCompletionRequestAssistantMessageContent::Text(msg)), ..}) => Ok(ConversationEntry::Eva(msg)),
|
||||
ChatCompletionRequestMessage::System(ChatCompletionRequestSystemMessage { content: ChatCompletionRequestSystemMessageContent::Text(msg), name: Some(name), ..}) => {
|
||||
match name.as_str() {
|
||||
"ship-computer" => Ok(ConversationEntry::ShipComputer(msg)),
|
||||
"stage-direction" => Ok(ConversationEntry::StageDirection(msg)),
|
||||
_ => Err(())
|
||||
}
|
||||
},
|
||||
_ => Err(())
|
||||
}
|
||||
}
|
||||
|
||||
type Error = ();
|
||||
}
|
||||
@@ -1,52 +1,10 @@
|
||||
use async_openai::types::chat::*;
|
||||
use chrono::{DateTime, Duration, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlite::OpenFlags;
|
||||
|
||||
use crate::{artifacts::Artifact, prediction::{GeneratedResponses, PossibleResponse}};
|
||||
use crate::{artifacts::Artifact, prediction::{GeneratedResponses, PossibleResponse}, scene::conversation::ConversationEntry};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum ConversationEntry {
|
||||
User(String),
|
||||
Eva(String),
|
||||
ShipComputer(String),
|
||||
StageDirection(String),
|
||||
SystemMessage(String)
|
||||
}
|
||||
|
||||
impl TryInto<ChatCompletionRequestMessage> for ConversationEntry {
|
||||
fn try_into(self) -> Result<ChatCompletionRequestMessage, Self::Error> {
|
||||
match self {
|
||||
ConversationEntry::User(text) => Ok(ChatCompletionRequestMessage::User(ChatCompletionRequestUserMessage { content: text.into(), ..Default::default()})),
|
||||
ConversationEntry::Eva(text) => Ok(ChatCompletionRequestMessage::Assistant(ChatCompletionRequestAssistantMessage { content: Some(text.into()), ..Default::default()})),
|
||||
ConversationEntry::ShipComputer(text) => Ok(ChatCompletionRequestMessage::System(ChatCompletionRequestSystemMessage { content: text.into(), name: Some("ship-computer".into()), ..Default::default() })),
|
||||
ConversationEntry::StageDirection(text) => Ok(ChatCompletionRequestMessage::System(ChatCompletionRequestSystemMessage { content: text.into(), name: Some("stage-direction".into()), ..Default::default() })),
|
||||
_ => Err(())
|
||||
}
|
||||
}
|
||||
|
||||
type Error = ();
|
||||
}
|
||||
|
||||
|
||||
impl TryInto<ConversationEntry> for ChatCompletionRequestMessage {
|
||||
fn try_into(self) -> Result<ConversationEntry, Self::Error> {
|
||||
match self {
|
||||
ChatCompletionRequestMessage::User(ChatCompletionRequestUserMessage { content: ChatCompletionRequestUserMessageContent::Text(msg), ..}) => Ok(ConversationEntry::User(msg)),
|
||||
ChatCompletionRequestMessage::Assistant(ChatCompletionRequestAssistantMessage { content: Some(ChatCompletionRequestAssistantMessageContent::Text(msg)), ..}) => Ok(ConversationEntry::Eva(msg)),
|
||||
ChatCompletionRequestMessage::System(ChatCompletionRequestSystemMessage { content: ChatCompletionRequestSystemMessageContent::Text(msg), name: Some(name), ..}) => {
|
||||
match name.as_str() {
|
||||
"ship-computer" => Ok(ConversationEntry::ShipComputer(msg)),
|
||||
"stage-direction" => Ok(ConversationEntry::StageDirection(msg)),
|
||||
_ => Err(())
|
||||
}
|
||||
},
|
||||
_ => Err(())
|
||||
}
|
||||
}
|
||||
|
||||
type Error = ();
|
||||
}
|
||||
pub mod conversation;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct StageDirection {
|
||||
Reference in New Issue
Block a user