use anyhow::Result;
use minijinja::value::Value;
use std::collections::HashMap;
use std::sync::Arc;
use crate::preprocessor::media::MediaDecoder;
pub mod deepseek_v32;
mod template;
pub use template::{ChatTemplate, ContextMixins};
#[derive(Debug)]
pub enum TokenInput {
Single(Vec<u32>),
Batch(Vec<Vec<u32>>),
}
#[derive(Debug)]
pub enum TextInput {
Single(String),
Batch(Vec<String>),
}
#[derive(Debug)]
pub enum PromptInput {
Tokens(TokenInput),
Text(TextInput),
}
pub trait OAIChatLikeRequest {
fn model(&self) -> String;
fn messages(&self) -> Value;
fn typed_messages(
&self,
) -> Option<&[dynamo_async_openai::types::ChatCompletionRequestMessage]> {
None
}
fn tools(&self) -> Option<Value> {
None
}
fn tool_choice(&self) -> Option<Value> {
None
}
fn response_format(&self) -> Option<Value> {
None
}
fn should_add_generation_prompt(&self) -> bool;
fn chat_template_args(&self) -> Option<&HashMap<String, serde_json::Value>> {
None
}
fn prompt_input_type(&self) -> PromptInput {
PromptInput::Text(TextInput::Single(String::new()))
}
fn extract_tokens(&self) -> Option<TokenInput> {
None
}
fn extract_text(&self) -> Option<TextInput> {
None
}
fn media_io_kwargs(&self) -> Option<&MediaDecoder> {
None
}
}
pub trait OAIPromptFormatter: Send + Sync + 'static {
fn supports_add_generation_prompt(&self) -> bool;
fn render(&self, req: &dyn OAIChatLikeRequest) -> Result<String>;
}
#[derive(Clone)]
pub enum PromptFormatter {
OAI(Arc<dyn OAIPromptFormatter>),
}
#[derive(Debug, Default)]
pub struct NoOpFormatter;
impl OAIPromptFormatter for NoOpFormatter {
fn supports_add_generation_prompt(&self) -> bool {
false
}
fn render(&self, req: &dyn OAIChatLikeRequest) -> Result<String> {
let messages = req.messages();
let first_message = messages
.get_item_by_index(0)
.map_err(|_| anyhow::Error::msg("No message at index 0 or messages array is empty"))?;
let content = first_message
.get_attr("content")
.map_err(|_| anyhow::Error::msg("First message has no 'content' field"))?;
let content_str = content
.as_str()
.ok_or_else(|| anyhow::Error::msg("Message content is not a string"))?
.to_string();
Ok(content_str)
}
}
impl PromptFormatter {
pub fn no_op() -> Self {
Self::OAI(Arc::new(NoOpFormatter))
}
}