src: split out conversation and archive bits into separate modules
This commit is contained in:
@@ -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 = ();
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
use chrono::{DateTime, Duration, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlite::OpenFlags;
|
||||
|
||||
use crate::{artifacts::Artifact, prediction::{GeneratedResponses, PossibleResponse}, scene::conversation::ConversationEntry};
|
||||
|
||||
pub mod conversation;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct StageDirection {
|
||||
pub episode_number: u32,
|
||||
#[serde(skip)]
|
||||
pub end_time: DateTime<Utc>,
|
||||
pub narrative: String,
|
||||
pub current_playlist: Vec<PlaylistEntry>
|
||||
}
|
||||
|
||||
impl StageDirection {
|
||||
pub fn time_remaining(&self) -> Duration {
|
||||
self.end_time.signed_duration_since(Utc::now())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for StageDirection {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
episode_number: 0,
|
||||
end_time: Utc::now() + Duration::hours(2),
|
||||
narrative: Default::default(),
|
||||
current_playlist: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
||||
pub struct Scenery {
|
||||
pub artifacts: Vec<Artifact>
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum MixxxError {
|
||||
Sql(sqlite::Error)
|
||||
}
|
||||
|
||||
impl From<sqlite::Error> for MixxxError {
|
||||
fn from(value: sqlite::Error) -> Self {
|
||||
Self::Sql(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl StageDirection {
|
||||
pub fn reload_mixxx_playlist(&mut self) -> Result<(), MixxxError> {
|
||||
self.current_playlist.clear();
|
||||
let playlist_name = format!("BFF.fm - Episode {}", self.episode_number);
|
||||
let connection = sqlite::Connection::open_thread_safe_with_flags("mixxxdb.sqlite", OpenFlags::new().with_read_only())?;
|
||||
let query = "SELECT id FROM Playlists WHERE name = ? ORDER BY id DESC LIMIT 1";
|
||||
let mut statement = connection.prepare(query)?;
|
||||
statement.bind((1, playlist_name.as_str()))?;
|
||||
statement.next()?;
|
||||
let latest_id = statement.read::<i64, _>("id").unwrap();
|
||||
|
||||
let query = "SELECT title, artist, album, comment, url, bpm FROM library LEFT JOIN PlaylistTracks ON PlaylistTracks.track_id = library.id WHERE PlaylistTracks.playlist_id = ? ORDER BY position";
|
||||
for track in connection.prepare(query).unwrap().into_iter().bind((1, latest_id)).unwrap().map(|row| row.unwrap()) {
|
||||
let title = track.try_read::<&str, _>("title").unwrap_or("Untitled Track");
|
||||
let artist = track.try_read::<&str, _>("artist").unwrap_or("Unknown Artist");
|
||||
let album = track.try_read::<&str, _>("album").unwrap_or("Unknown Album");
|
||||
let bpm = track.try_read::<f64, _>("bpm").unwrap_or(0.);
|
||||
self.current_playlist.push(PlaylistEntry {
|
||||
artist: artist.into(),
|
||||
album: album.into(),
|
||||
title: title.into(),
|
||||
bpm
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum PredictionAction {
|
||||
ConversationAppend(ConversationEntry),
|
||||
SetEpisodeNumber(u32),
|
||||
GeneratePredictions,
|
||||
SetNarrative(String),
|
||||
SetShowEndTime(DateTime<Utc>)
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
||||
pub struct PlaylistEntry {
|
||||
pub artist: String,
|
||||
pub album: String,
|
||||
pub title: String,
|
||||
pub bpm: f64
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||
pub struct Scene {
|
||||
reply_options: GeneratedResponses,
|
||||
conversation: Vec<ConversationEntry>,
|
||||
pub direction: StageDirection,
|
||||
pub tokens_consumed: usize,
|
||||
scenery: Scenery
|
||||
}
|
||||
|
||||
impl Scene {
|
||||
pub fn new(reply_options: GeneratedResponses, conversation: Vec<ConversationEntry>, scenery: Scenery, tokens_consumed: usize, direction: StageDirection) -> Self {
|
||||
Self {
|
||||
reply_options,
|
||||
conversation,
|
||||
scenery,
|
||||
tokens_consumed,
|
||||
direction
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scenery(&self) -> &Scenery {
|
||||
&self.scenery
|
||||
}
|
||||
|
||||
pub fn conversation(&self) -> &Vec<ConversationEntry> {
|
||||
&self.conversation
|
||||
}
|
||||
|
||||
pub fn reply_options(&self) -> &Vec<PossibleResponse> {
|
||||
&self.reply_options.responses
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user