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 chrono::{DateTime, Utc};
|
||||||
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
|
||||||
@@ -42,4 +43,9 @@ impl Into<Artifact> for bandcamp::Artist {
|
|||||||
fn into(self) -> Artifact {
|
fn into(self) -> Artifact {
|
||||||
Artifact::Bandcamp(self.into())
|
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 ratatui::prelude::*;
|
||||||
use tui_skeleton::{AnimationMode, SkeletonText};
|
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 scene;
|
||||||
mod events;
|
mod events;
|
||||||
@@ -22,6 +22,7 @@ mod tts;
|
|||||||
mod prediction;
|
mod prediction;
|
||||||
mod audio;
|
mod audio;
|
||||||
mod artifacts;
|
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: 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.
|
// 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 async_openai::{Client, config::OpenAIConfig, types::chat::{ChatCompletionMessageToolCalls, ChatCompletionRequestAssistantMessageArgs, ChatCompletionRequestMessage, ChatCompletionRequestSystemMessageArgs, ChatCompletionRequestToolMessageArgs, ChatCompletionTool, ChatCompletionTools, CreateChatCompletionRequestArgs, FinishReason, FunctionObjectArgs, ResponseFormat, ResponseFormatJsonSchema}};
|
||||||
use bandcamp::SearchResultItem;
|
use bandcamp::SearchResultItem;
|
||||||
use schemars::{JsonSchema, schema_for};
|
use schemars::{JsonSchema, schema_for};
|
||||||
@@ -7,7 +5,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
use serde_json::{Serializer, ser::CompactFormatter};
|
use serde_json::{Serializer, ser::CompactFormatter};
|
||||||
use tokio::sync::{mpsc, watch};
|
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");
|
const SYSTEM_PROMPT: &str = include_str!("system-prompt.txt");
|
||||||
@@ -47,20 +45,6 @@ struct StageEventArgs {
|
|||||||
event: StageEvent
|
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)]
|
#[derive(Default, Debug)]
|
||||||
struct ToolResults {
|
struct ToolResults {
|
||||||
result: Option<String>,
|
result: Option<String>,
|
||||||
@@ -132,26 +116,9 @@ impl Session {
|
|||||||
|
|
||||||
async fn tool_artifact_query(&mut self, args: BeatsQueryArgs) -> ToolResults {
|
async fn tool_artifact_query(&mut self, args: BeatsQueryArgs) -> ToolResults {
|
||||||
let mut messages = vec![];
|
let mut messages = vec![];
|
||||||
let mut beets_cmd = Command::new("beet");
|
messages.push(ConversationEntry::ShipComputer(format!("Executing archive query {:?}", args)));
|
||||||
beets_cmd.args(["export", "-f", "json", "-i", "title,label,year,genres,album,artist"]);
|
if let Ok(output) = args.execute() {
|
||||||
if let Some(artist) = args.artist {
|
self.scenery.artifacts.push(output);
|
||||||
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()));
|
|
||||||
} else {
|
} else {
|
||||||
messages.push(ConversationEntry::ShipComputer("Unable to execute query!".into()));
|
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 chrono::{DateTime, Duration, Utc};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlite::OpenFlags;
|
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 mod conversation;
|
||||||
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 = ();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct StageDirection {
|
pub struct StageDirection {
|
||||||
Reference in New Issue
Block a user