use openai_ergonomic::{
Builder, ChatCompletionBuilder, Client, LangfuseConfig, LangfuseInterceptor,
};
use opentelemetry::{global, trace::TracerProvider};
use opentelemetry_langfuse::ExporterBuilder;
use opentelemetry_sdk::{
runtime::Tokio,
trace::{span_processor_with_async_runtime::BatchSpanProcessor, SdkTracerProvider},
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::fmt()
.with_env_filter(
tracing_subscriber::EnvFilter::from_default_env()
.add_directive("openai_ergonomic=debug".parse()?),
)
.init();
let exporter = ExporterBuilder::from_env()?.build()?;
let provider = SdkTracerProvider::builder()
.with_span_processor(BatchSpanProcessor::builder(exporter, Tokio).build())
.build();
global::set_tracer_provider(provider.clone());
let tracer = provider.tracer("openai-ergonomic");
let langfuse_interceptor =
std::sync::Arc::new(LangfuseInterceptor::new(tracer, LangfuseConfig::new()));
let client = Client::from_env()?
.with_interceptor(Box::new(langfuse_interceptor.clone()))
.build();
println!(" OpenAI client initialized with Langfuse observability");
println!(" Traces will be sent to Langfuse for monitoring\n");
println!("Example 1: Simple chat completion");
println!("---------------------------------");
let chat_builder = client
.chat_simple("What is the capital of France? Answer in one word.")
.build()?;
let response = client.execute_chat(chat_builder).await?;
println!("Response: {:?}\n", response.content());
println!("Example 2: Chat with builder pattern");
println!("-------------------------------------");
let chat_builder = client
.chat()
.system("You are a helpful assistant that speaks like a pirate.")
.user("Tell me about the ocean in 2 sentences.")
.temperature(0.7)
.max_tokens(100)
.build()?;
let response = client.execute_chat(chat_builder).await?;
println!("Response: {:?}\n", response.content());
println!("Example 3: Conversation");
println!("-----------------------");
let chat_builder = client
.chat()
.system("You are a math tutor.")
.user("What is 2 + 2?")
.assistant("2 + 2 equals 4.")
.user("And what about 3 + 3?")
.build()?;
let response = client.execute_chat(chat_builder).await?;
println!("Response: {:?}\n", response.content());
println!("Example 4: Error handling");
println!("-------------------------");
let chat_builder = ChatCompletionBuilder::new("non-existent-model")
.user("This should fail")
.build()?;
let result = client.execute_chat(chat_builder).await;
match result {
Ok(_) => println!("Unexpected success"),
Err(e) => println!("Expected error captured: {e}\n"),
}
println!("Example 5: Embeddings");
println!("--------------------");
let embeddings_builder = client.embeddings().text(
"text-embedding-ada-002",
"The quick brown fox jumps over the lazy dog",
);
let embeddings = client.embeddings().create(embeddings_builder).await?;
println!("Generated {} embedding(s)\n", embeddings.data.len());
println!("Example 6: Custom metadata via interceptor context");
println!("---------------------------------------------------");
langfuse_interceptor.set_session_id("demo-session-123");
langfuse_interceptor.set_user_id("demo-user-456");
langfuse_interceptor.add_tags(vec!["example".to_string(), "demo".to_string()]);
let chat_builder = client
.chat_simple("Say 'Hello from custom session!'")
.build()?;
let response = client.execute_chat(chat_builder).await?;
println!("Response with custom metadata: {:?}\n", response.content());
langfuse_interceptor.clear_context();
println!(" All examples completed!");
println!(" Check your Langfuse dashboard to see the traces");
println!(" - Look for traces with operation name 'chat'");
println!(" - Each trace includes request/response details, token usage, and timing");
println!(" - Example 6 will have custom session_id, user_id, and tags");
println!("\n⏳ Flushing spans to Langfuse...");
provider.shutdown()?;
Ok(())
}