feat: more
This commit is contained in:
60
src/main.rs
60
src/main.rs
@@ -1,3 +1,59 @@
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
use clap::Parser;
|
||||
use secrecy::SecretString;
|
||||
use tracing_subscriber::{EnvFilter, fmt::format::FmtSpan};
|
||||
|
||||
mod openai;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
struct AppArgs {
|
||||
#[arg(long)]
|
||||
cloudflare_workers_api_key: Vec<SecretString>,
|
||||
|
||||
#[arg(long)]
|
||||
google_ai_studio_api_key: Vec<SecretString>,
|
||||
|
||||
#[arg(long)]
|
||||
groq_api_key: Vec<SecretString>,
|
||||
|
||||
#[arg(long)]
|
||||
hugging_face_api_key: Vec<SecretString>,
|
||||
|
||||
#[arg(long)]
|
||||
mistral_api_key: Vec<SecretString>,
|
||||
|
||||
#[arg(long)]
|
||||
openrouter_api_key: Vec<SecretString>,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
struct Args {
|
||||
#[arg(long = "tracing-directives", env = "RUST_LOG", default_value_t = Default::default())]
|
||||
env_filter: EnvFilter,
|
||||
|
||||
#[command(flatten)]
|
||||
app_args: AppArgs,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let args = Parser::parse();
|
||||
let Args {
|
||||
env_filter,
|
||||
app_args,
|
||||
} = args;
|
||||
|
||||
tracing_subscriber::fmt()
|
||||
.pretty()
|
||||
.with_span_events(FmtSpan::NEW | FmtSpan::CLOSE)
|
||||
.with_env_filter(env_filter)
|
||||
.init();
|
||||
tracing::debug!(?app_args, "using");
|
||||
let AppArgs {
|
||||
cloudflare_workers_api_key,
|
||||
google_ai_studio_api_key,
|
||||
groq_api_key,
|
||||
hugging_face_api_key,
|
||||
mistral_api_key,
|
||||
openrouter_api_key,
|
||||
} = app_args;
|
||||
}
|
||||
|
||||
81
src/openai.rs
Normal file
81
src/openai.rs
Normal file
@@ -0,0 +1,81 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use schemars::{JsonSchema, Schema, SchemaGenerator};
|
||||
use serde::{Deserialize, Serialize, ser::SerializeMap as _};
|
||||
use typed_builder::TypedBuilder;
|
||||
use url::Url;
|
||||
|
||||
#[derive(Debug, TypedBuilder, Serialize, Deserialize)]
|
||||
struct Message {
|
||||
role: String,
|
||||
content: String,
|
||||
}
|
||||
|
||||
struct StructuredOutputJson<S>(PhantomData<S>);
|
||||
|
||||
impl<S> Serialize for StructuredOutputJson<S>
|
||||
where
|
||||
S: JsonSchema,
|
||||
{
|
||||
fn serialize<Serializer>(
|
||||
&self,
|
||||
serializer: Serializer,
|
||||
) -> Result<Serializer::Ok, Serializer::Error>
|
||||
where
|
||||
Serializer: serde::Serializer,
|
||||
{
|
||||
let mut map = serializer.serialize_map(Some(3))?;
|
||||
map.serialize_entry("strict", &true)?;
|
||||
map.serialize_entry("name", &S::schema_name())?;
|
||||
map.serialize_entry(
|
||||
"schema",
|
||||
&SchemaGenerator::default().into_root_schema_for::<S>(),
|
||||
)?;
|
||||
map.end()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ResponseFormat<OutputFormat> {
|
||||
Json { schema: PhantomData<OutputFormat> },
|
||||
}
|
||||
|
||||
impl<OutputFormat> Serialize for ResponseFormat<OutputFormat>
|
||||
where
|
||||
OutputFormat: JsonSchema,
|
||||
{
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
let mut map = serializer.serialize_map(Some(2))?;
|
||||
map.serialize_entry("type", "json_schema")?;
|
||||
map.serialize_entry(
|
||||
"json_schema",
|
||||
&StructuredOutputJson::<OutputFormat>(Default::default()),
|
||||
)?;
|
||||
map.end()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, TypedBuilder, Serialize)]
|
||||
#[serde(bound(serialize = "ResponseFormat<OutputSchema>: Serialize"))]
|
||||
struct ChatCompletionsRequest<OutputSchema> {
|
||||
model: String,
|
||||
|
||||
messages: Vec<Message>,
|
||||
|
||||
response_format: ResponseFormat<OutputSchema>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct Choice {
|
||||
finish_reason: String, // I don't care
|
||||
|
||||
message: Message,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct ChatCompletionsResponse {
|
||||
choices: Vec<Choice>,
|
||||
}
|
||||
Reference in New Issue
Block a user