use artificial::{
ArtificialClient,
generic::{GenericMessage, GenericRole},
model::{Model, OpenAiModel},
template::PromptTemplate,
};
use artificial_openai::OpenAiAdapterBuilder;
use artificial_prompt::chain::PromptChain;
use artificial_types::{fragments::StaticFragment, outputs::result::ThinkResult};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
const BASE_SYSTEM_ROLE: &str = include_str!("data/role/base_system.md");
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
struct Advice {
suggestion: String,
}
struct AdvicePrompt {
history: Vec<GenericMessage>,
}
impl AdvicePrompt {
fn new(history: &[(&str, GenericRole)]) -> Self {
let msgs = history
.iter()
.map(|(txt, role)| GenericMessage::new((*txt).into(), *role))
.collect();
Self { history: msgs }
}
}
impl artificial::template::IntoPrompt for AdvicePrompt {
type Message = GenericMessage;
fn into_prompt(self) -> Vec<Self::Message> {
let mut chain = PromptChain::new().with(StaticFragment::from(BASE_SYSTEM_ROLE));
for message in self.history {
chain = chain.with(message);
}
chain.build()
}
}
impl PromptTemplate for AdvicePrompt {
type Output = ThinkResult<Advice>;
const MODEL: Model = Model::OpenAi(OpenAiModel::Gpt4o);
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let backend = OpenAiAdapterBuilder::new_from_env().build()?;
let client = ArtificialClient::new(backend);
let history = [
("I failed my Rust borrow checker again.", GenericRole::User),
("Keep calm and add more lifetimes.", GenericRole::Assistant),
("Any other tips?", GenericRole::User),
];
let advice = client.chat_complete(AdvicePrompt::new(&history)).await?;
println!("Status: {:?}", advice.status);
println!("Reasoning: {}", advice.reasoning);
println!("Confidence: {}", advice.confidence);
println!(
"LLM says:\n {}",
advice.data.map(|d| d.suggestion).unwrap_or_default()
);
Ok(())
}