mixvideo-v2/cargos/gemini-sdk/src/lib.rs

167 lines
5.6 KiB
Rust

//! # Gemini SDK
//!
//! A simple Rust SDK for Google Gemini AI services.
//!
//! ## Features
//!
//! - **Simple Interface**: Send text + attachments to Gemini AI
//! - **Type Safety**: Strong typing with compile-time error checking
//! - **Easy Integration**: Minimal external dependencies
//!
//! ## Quick Start
//!
//! ```rust,no_run
//! use gemini_sdk::{GeminiSDK, MessageRequest, Attachment, Agent};
//!
//! #[tokio::main]
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//! // Initialize SDK
//! let mut sdk = GeminiSDK::new()?;
//!
//! // Create an agent (optional)
//! let agent = Agent::new("assistant", "Assistant", "You are a helpful assistant");
//! sdk.add_agent(agent);
//!
//! // Send a message with attachment
//! let request = MessageRequest {
//! text: "Analyze this image".to_string(),
//! attachments: vec![Attachment::new("./image.jpg")],
//! agent_id: Some("assistant".to_string()),
//! };
//!
//! let response = sdk.send_message(request).await?;
//! println!("Response: {}", response.content);
//!
//! Ok(())
//! }
//! ```
pub mod sdk;
pub mod agent;
pub mod attachment;
pub mod error;
// Re-export main types for convenience
pub use sdk::{GeminiSDK, MessageRequest, MessageResponse};
pub use agent::Agent;
pub use attachment::Attachment;
pub use error::{SDKError, Result};
/// SDK version
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
/// Default configuration for the SDK
#[derive(Debug, Clone)]
pub struct GeminiConfig {
pub base_url: String,
pub bearer_token: String,
pub timeout: u64,
pub model_name: String,
pub max_retries: u32,
pub retry_delay: u64,
pub temperature: f32,
pub max_tokens: u32,
pub cloudflare_project_id: String,
pub cloudflare_gateway_id: String,
pub google_project_id: String,
pub regions: Vec<String>,
}
impl Default for GeminiConfig {
fn default() -> Self {
Self {
base_url: "https://bowongai-dev--bowong-ai-video-gemini-fastapi-webapp.modal.run".to_string(),
bearer_token: "bowong7777".to_string(),
timeout: 120,
model_name: "gemini-2.5-pro".to_string(),
max_retries: 3,
retry_delay: 2,
temperature: 0.7,
max_tokens: 64000,
cloudflare_project_id: "67720b647ff2b55cf37ba3ef9e677083".to_string(),
cloudflare_gateway_id: "bowong-dev".to_string(),
google_project_id: "gen-lang-client-0413414134".to_string(),
regions: vec![
"us-central1".to_string(),
"us-east1".to_string(),
"europe-west1".to_string(),
],
}
}
}
impl GeminiConfig {
/// Create configuration from environment variables
pub fn from_env() -> Self {
Self {
base_url: std::env::var("GEMINI_BASE_URL")
.unwrap_or_else(|_| Self::default().base_url),
bearer_token: std::env::var("GEMINI_BEARER_TOKEN")
.unwrap_or_else(|_| Self::default().bearer_token),
timeout: std::env::var("GEMINI_TIMEOUT")
.ok()
.and_then(|s| s.parse().ok())
.unwrap_or(Self::default().timeout),
model_name: std::env::var("GEMINI_MODEL_NAME")
.unwrap_or_else(|_| Self::default().model_name),
max_retries: std::env::var("GEMINI_MAX_RETRIES")
.ok()
.and_then(|s| s.parse().ok())
.unwrap_or(Self::default().max_retries),
retry_delay: std::env::var("GEMINI_RETRY_DELAY")
.ok()
.and_then(|s| s.parse().ok())
.unwrap_or(Self::default().retry_delay),
temperature: std::env::var("GEMINI_TEMPERATURE")
.ok()
.and_then(|s| s.parse().ok())
.unwrap_or(Self::default().temperature),
max_tokens: std::env::var("GEMINI_MAX_TOKENS")
.ok()
.and_then(|s| s.parse().ok())
.unwrap_or(Self::default().max_tokens),
cloudflare_project_id: std::env::var("GEMINI_CLOUDFLARE_PROJECT_ID")
.unwrap_or_else(|_| Self::default().cloudflare_project_id),
cloudflare_gateway_id: std::env::var("GEMINI_CLOUDFLARE_GATEWAY_ID")
.unwrap_or_else(|_| Self::default().cloudflare_gateway_id),
google_project_id: std::env::var("GEMINI_GOOGLE_PROJECT_ID")
.unwrap_or_else(|_| Self::default().google_project_id),
regions: std::env::var("GEMINI_REGIONS")
.ok()
.map(|s| s.split(',').map(|s| s.trim().to_string()).collect())
.unwrap_or_else(|| Self::default().regions),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_config_default() {
let config = GeminiConfig::default();
assert!(!config.base_url.is_empty());
assert!(!config.bearer_token.is_empty());
assert!(config.timeout > 0);
assert!(!config.model_name.is_empty());
assert!(config.max_retries > 0);
assert!(config.temperature >= 0.0 && config.temperature <= 2.0);
assert!(config.max_tokens > 0);
assert!(!config.regions.is_empty());
}
#[test]
fn test_config_from_env() {
// Test that from_env doesn't panic and returns valid config
let config = GeminiConfig::from_env();
assert!(!config.base_url.is_empty());
assert!(!config.bearer_token.is_empty());
}
#[test]
fn test_version() {
assert!(!VERSION.is_empty());
}
}