use serde::{Deserialize, Serialize};
use serde_json::Value;
use crate::completion::provider_options::reply_field;
use crate::completion::{ExtensionOptions, ProviderExtension, ReplyExtras};
use crate::message::Api;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct PerplexityExt;
impl ProviderExtension for PerplexityExt {
const PROVIDER: &'static str = super::PROVIDER_NAME;
type Options = PerplexityOptions;
type Extras = PerplexityExtras;
}
#[non_exhaustive]
#[derive(Clone, Debug, Default, PartialEq, Serialize)]
pub struct PerplexityOptions {}
impl PerplexityOptions {
pub fn new() -> Self {
Self::default()
}
}
impl ExtensionOptions for PerplexityOptions {
type Ext = PerplexityExt;
}
#[non_exhaustive]
#[derive(Clone, Debug, Default, PartialEq)]
pub struct PerplexityExtras {
pub citations: Option<Vec<String>>,
pub search_results: Option<Vec<SearchResult>>,
pub images: Option<Vec<Value>>,
pub related_questions: Option<Vec<String>>,
pub cost: Option<PerplexityCost>,
pub search_context_size: Option<String>,
}
#[non_exhaustive]
#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize)]
pub struct SearchResult {
#[serde(default)]
pub title: Option<String>,
#[serde(default)]
pub url: Option<String>,
#[serde(default)]
pub date: Option<String>,
#[serde(default)]
pub last_updated: Option<String>,
#[serde(default)]
pub snippet: Option<String>,
#[serde(default)]
pub source: Option<String>,
}
#[non_exhaustive]
#[derive(Clone, Copy, Debug, Default, PartialEq, Deserialize)]
pub struct PerplexityCost {
#[serde(default)]
pub input_tokens_cost: Option<f64>,
#[serde(default)]
pub output_tokens_cost: Option<f64>,
#[serde(default)]
pub request_cost: Option<f64>,
#[serde(default)]
pub total_cost: Option<f64>,
}
impl ReplyExtras for PerplexityExtras {
fn from_reply(_api: &Api, raw: &Value) -> Result<Self, serde_json::Error> {
Ok(Self {
citations: reply_field(raw, "/citations")?,
search_results: reply_field(raw, "/search_results")?,
images: reply_field(raw, "/images")?,
related_questions: reply_field(raw, "/related_questions")?,
cost: reply_field(raw, "/usage/cost")?,
search_context_size: reply_field(raw, "/usage/search_context_size")?,
})
}
}
#[cfg(test)]
mod tests;