142 lines
5.4 KiB
Rust
142 lines
5.4 KiB
Rust
use async_openai::types::chat::*;
|
|
use chrono::Duration;
|
|
use serde::{Deserialize, Serialize};
|
|
use sqlite::OpenFlags;
|
|
|
|
use crate::prediction::{GeneratedResponses, PossibleResponse};
|
|
|
|
#[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() })),
|
|
ConversationEntry::SystemMessage(_) => 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, Default, Serialize, Deserialize, Clone)]
|
|
pub struct StageDirection {
|
|
pub episode_number: u32,
|
|
pub time_remaining: Duration,
|
|
pub narrative: String,
|
|
pub artifacts: Vec<String>,
|
|
pub current_playlist: Vec<PlaylistEntry>
|
|
}
|
|
|
|
#[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 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, format!("BFF.fm - Episode {}", self.episode_number).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, Default, Clone)]
|
|
pub struct StageActions {
|
|
pub direction: StageDirection,
|
|
pub additions: Vec<ConversationEntry>
|
|
}
|
|
|
|
#[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>,
|
|
}
|
|
|
|
impl Scene {
|
|
pub fn new(reply_options: GeneratedResponses, conversation: Vec<ConversationEntry>) -> Self {
|
|
Self {
|
|
reply_options,
|
|
conversation,
|
|
}
|
|
}
|
|
|
|
pub fn conversation(&self) -> &Vec<ConversationEntry> {
|
|
&self.conversation
|
|
}
|
|
|
|
pub fn conversation_mut(&mut self) -> &mut Vec<ConversationEntry> {
|
|
&mut self.conversation
|
|
}
|
|
|
|
pub fn reply_options(&self) -> &Vec<PossibleResponse> {
|
|
&self.reply_options.responses
|
|
}
|
|
|
|
pub fn reply_options_mut(&mut self) -> &mut Vec<PossibleResponse> {
|
|
&mut self.reply_options.responses
|
|
}
|
|
} |