...
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -63,4 +63,7 @@ sidebars.ts
|
||||
|
||||
tsconfig.json
|
||||
Cargo.toml.bak
|
||||
for_augment
|
||||
for_augment
|
||||
|
||||
myenv.sh
|
||||
|
||||
|
@@ -27,6 +27,7 @@ members = [
|
||||
"rhai",
|
||||
"herodo",
|
||||
"packages/clients/hetznerclient",
|
||||
"packages/ai/codemonkey",
|
||||
]
|
||||
resolver = "2"
|
||||
|
||||
|
14
config/README.md
Normal file
14
config/README.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# Environment Configuration
|
||||
|
||||
To set up your environment variables:
|
||||
|
||||
1. Copy the template file to `env.sh`:
|
||||
|
||||
```bash
|
||||
cp config/myenv_templ.sh config/env.sh
|
||||
```
|
||||
|
||||
2. Edit `config/env.sh` and fill in your specific values for the variables.
|
||||
|
||||
3. This file (`config/env.sh`) is excluded from version control by the project's `.gitignore` configuration, ensuring your sensitive information remains local and is never committed to the repository.
|
||||
|
6
config/myenv_templ.sh
Normal file
6
config/myenv_templ.sh
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
|
||||
export OPENROUTER_API_KEY=""
|
||||
export GROQ_API_KEY=""
|
||||
export CEREBRAS_API_KEY=""
|
||||
export OPENAI_API_KEY="sk-xxxxxxx"
|
15
examples_rust/ai/Cargo.toml
Normal file
15
examples_rust/ai/Cargo.toml
Normal file
@@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "openrouter_example"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[workspace]
|
||||
|
||||
[[bin]]
|
||||
name = "openrouter_example"
|
||||
path = "openrouter_example.rs"
|
||||
|
||||
[dependencies]
|
||||
codemonkey = { path = "../../packages/ai/codemonkey" }
|
||||
openai-api-rs = "6.0.8"
|
||||
tokio = { version = "1.0", features = ["full"] }
|
47
examples_rust/ai/openrouter_example.rs
Normal file
47
examples_rust/ai/openrouter_example.rs
Normal file
@@ -0,0 +1,47 @@
|
||||
use codemonkey::{create_ai_provider, AIProviderType, CompletionRequestBuilder, Message, MessageRole, Content};
|
||||
use std::error::Error;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn Error>> {
|
||||
|
||||
let (mut provider, provider_type) = create_ai_provider(AIProviderType::OpenRouter)?;
|
||||
|
||||
let messages = vec![Message {
|
||||
role: MessageRole::user,
|
||||
content: Content::Text("Explain the concept of a factory design pattern in Rust.".to_string()),
|
||||
name: None,
|
||||
tool_calls: None,
|
||||
tool_call_id: None,
|
||||
}];
|
||||
|
||||
println!("Sending request to OpenRouter...");
|
||||
let response = CompletionRequestBuilder::new(
|
||||
&mut *provider,
|
||||
"openai/gpt-oss-120b".to_string(), // Model name as specified by the user
|
||||
messages,
|
||||
provider_type, // Pass the provider_type
|
||||
)
|
||||
.temperature(1.0)
|
||||
.max_tokens(8192)
|
||||
.top_p(1.0)
|
||||
.reasoning_effort("medium")
|
||||
.stream(false)
|
||||
.openrouter_options(|builder| {
|
||||
builder.provider(
|
||||
codemonkey::OpenRouterProviderOptionsBuilder::new()
|
||||
.order(vec!["cerebras"])
|
||||
.build(),
|
||||
)
|
||||
})
|
||||
.completion()
|
||||
.await?;
|
||||
|
||||
for choice in response.choices {
|
||||
if let Some(content) = choice.message.content {
|
||||
print!("{}", content);
|
||||
}
|
||||
}
|
||||
println!();
|
||||
|
||||
Ok(())
|
||||
}
|
13
examples_rust/ai/run.sh
Executable file
13
examples_rust/ai/run.sh
Executable file
@@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Change to directory where this script is located
|
||||
cd "$(dirname "${BASH_SOURCE[0]}")"
|
||||
|
||||
source ../../config/myenv.sh
|
||||
|
||||
# Build the example
|
||||
cargo build
|
||||
|
||||
# Run the example
|
||||
cargo run --bin openrouter_example
|
10
packages/ai/codemonkey/Cargo.toml
Normal file
10
packages/ai/codemonkey/Cargo.toml
Normal file
@@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "codemonkey"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
async-trait = "0.1.80"
|
||||
openrouter-rs = "0.4.5"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
227
packages/ai/codemonkey/src/lib.rs
Normal file
227
packages/ai/codemonkey/src/lib.rs
Normal file
@@ -0,0 +1,227 @@
|
||||
use async_trait::async_trait;
|
||||
use openrouter_rs::{OpenRouterClient, api::chat::*, types::Role, ChatCompletionResponse}; // Added ChatCompletionResponse here
|
||||
use std::env;
|
||||
use std::error::Error;
|
||||
|
||||
// Re-export Message and MessageRole for easier use in client code
|
||||
pub use openrouter_rs::api::chat::Message;
|
||||
pub use openrouter_rs::types::Role as MessageRole;
|
||||
// Removed the problematic import for ChatCompletionResponse
|
||||
// pub use openrouter_rs::api::chat::chat_completion::ChatCompletionResponse;
|
||||
|
||||
#[async_trait]
|
||||
pub trait AIProvider {
|
||||
async fn completion(
|
||||
&mut self,
|
||||
request: CompletionRequest,
|
||||
) -> Result<ChatCompletionResponse, Box<dyn Error>>;
|
||||
}
|
||||
|
||||
pub struct CompletionRequest {
|
||||
pub model: String,
|
||||
pub messages: Vec<Message>,
|
||||
pub temperature: Option<f64>,
|
||||
pub max_tokens: Option<i64>,
|
||||
pub top_p: Option<f64>,
|
||||
pub stream: Option<bool>,
|
||||
pub stop: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
pub struct CompletionRequestBuilder<'a> {
|
||||
provider: &'a mut dyn AIProvider,
|
||||
model: String,
|
||||
messages: Vec<Message>,
|
||||
temperature: Option<f64>,
|
||||
max_tokens: Option<i64>,
|
||||
top_p: Option<f64>,
|
||||
stream: Option<bool>,
|
||||
stop: Option<Vec<String>>,
|
||||
provider_type: AIProviderType,
|
||||
}
|
||||
|
||||
impl<'a> CompletionRequestBuilder<'a> {
|
||||
pub fn new(provider: &'a mut dyn AIProvider, model: String, messages: Vec<Message>, provider_type: AIProviderType) -> Self {
|
||||
Self {
|
||||
provider,
|
||||
model,
|
||||
messages,
|
||||
temperature: None,
|
||||
max_tokens: None,
|
||||
top_p: None,
|
||||
stream: None,
|
||||
stop: None,
|
||||
provider_type,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn temperature(mut self, temperature: f64) -> Self {
|
||||
self.temperature = Some(temperature);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn max_tokens(mut self, max_tokens: i64) -> Self {
|
||||
self.max_tokens = Some(max_tokens);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn top_p(mut self, top_p: f64) -> Self {
|
||||
self.top_p = Some(top_p);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn stream(mut self, stream: bool) -> Self {
|
||||
self.stream = Some(stream);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn stop(mut self, stop: Vec<String>) -> Self {
|
||||
self.stop = Some(stop);
|
||||
self
|
||||
}
|
||||
|
||||
pub async fn completion(self) -> Result<ChatCompletionResponse, Box<dyn Error>> {
|
||||
let request = CompletionRequest {
|
||||
model: self.model,
|
||||
messages: self.messages,
|
||||
temperature: self.temperature,
|
||||
max_tokens: self.max_tokens,
|
||||
top_p: self.top_p,
|
||||
stream: self.stream,
|
||||
stop: self.stop,
|
||||
};
|
||||
self.provider.completion(request).await
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GroqAIProvider {
|
||||
client: OpenRouterClient,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl AIProvider for GroqAIProvider {
|
||||
async fn completion(
|
||||
&mut self,
|
||||
request: CompletionRequest,
|
||||
) -> Result<ChatCompletionResponse, Box<dyn Error>> {
|
||||
let chat_request = ChatCompletionRequest::builder()
|
||||
.model(request.model)
|
||||
.messages(request.messages)
|
||||
.temperature(request.temperature.unwrap_or(1.0))
|
||||
.max_tokens(request.max_tokens.map(|x| x as u32).unwrap_or(2048))
|
||||
.top_p(request.top_p.unwrap_or(1.0))
|
||||
.stream(request.stream.unwrap_or(false)) // Corrected to field assignment
|
||||
.stop(request.stop.unwrap_or_default())
|
||||
.build()?;
|
||||
|
||||
let result = self.client.send_chat_completion(&chat_request).await?;
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct OpenAIProvider {
|
||||
client: OpenRouterClient,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl AIProvider for OpenAIProvider {
|
||||
async fn completion(
|
||||
&mut self,
|
||||
request: CompletionRequest,
|
||||
) -> Result<ChatCompletionResponse, Box<dyn Error>> {
|
||||
let chat_request = ChatCompletionRequest::builder()
|
||||
.model(request.model)
|
||||
.messages(request.messages)
|
||||
.temperature(request.temperature.unwrap_or(1.0))
|
||||
.max_tokens(request.max_tokens.map(|x| x as u32).unwrap_or(2048))
|
||||
.top_p(request.top_p.unwrap_or(1.0))
|
||||
.stream(request.stream.unwrap_or(false)) // Corrected to field assignment
|
||||
.stop(request.stop.unwrap_or_default())
|
||||
.build()?;
|
||||
|
||||
let result = self.client.send_chat_completion(&chat_request).await?;
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct OpenRouterAIProvider {
|
||||
client: OpenRouterClient,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl AIProvider for OpenRouterAIProvider {
|
||||
async fn completion(
|
||||
&mut self,
|
||||
request: CompletionRequest,
|
||||
) -> Result<ChatCompletionResponse, Box<dyn Error>> {
|
||||
let chat_request = ChatCompletionRequest::builder()
|
||||
.model(request.model)
|
||||
.messages(request.messages)
|
||||
.temperature(request.temperature.unwrap_or(1.0))
|
||||
.max_tokens(request.max_tokens.map(|x| x as u32).unwrap_or(2048))
|
||||
.top_p(request.top_p.unwrap_or(1.0))
|
||||
.stream(request.stream.unwrap_or(false)) // Corrected to field assignment
|
||||
.stop(request.stop.unwrap_or_default())
|
||||
.build()?;
|
||||
|
||||
let result = self.client.send_chat_completion(&chat_request).await?;
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CerebrasAIProvider {
|
||||
client: OpenRouterClient,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl AIProvider for CerebrasAIProvider {
|
||||
async fn completion(
|
||||
&mut self,
|
||||
request: CompletionRequest,
|
||||
) -> Result<ChatCompletionResponse, Box<dyn Error>> {
|
||||
let chat_request = ChatCompletionRequest::builder()
|
||||
.model(request.model)
|
||||
.messages(request.messages)
|
||||
.temperature(request.temperature.unwrap_or(1.0))
|
||||
.max_tokens(request.max_tokens.map(|x| x as u32).unwrap_or(2048))
|
||||
.top_p(request.top_p.unwrap_or(1.0))
|
||||
.stream(request.stream.unwrap_or(false)) // Corrected to field assignment
|
||||
.stop(request.stop.unwrap_or_default())
|
||||
.build()?;
|
||||
|
||||
let result = self.client.send_chat_completion(&chat_request).await?;
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum AIProviderType {
|
||||
Groq,
|
||||
OpenAI,
|
||||
OpenRouter,
|
||||
Cerebras,
|
||||
}
|
||||
|
||||
pub fn create_ai_provider(provider_type: AIProviderType) -> Result<(Box<dyn AIProvider>, AIProviderType), Box<dyn Error>> {
|
||||
match provider_type {
|
||||
AIProviderType::Groq => {
|
||||
let api_key = env::var("GROQ_API_KEY")?;
|
||||
let client = OpenRouterClient::builder().api_key(api_key).build()?;
|
||||
Ok((Box::new(GroqAIProvider { client }), AIProviderType::Groq))
|
||||
}
|
||||
AIProviderType::OpenAI => {
|
||||
let api_key = env::var("OPENAI_API_KEY")?;
|
||||
let client = OpenRouterClient::builder().api_key(api_key).build()?;
|
||||
Ok((Box::new(OpenAIProvider { client }), AIProviderType::OpenAI))
|
||||
}
|
||||
AIProviderType::OpenRouter => {
|
||||
let api_key = env::var("OPENROUTER_API_KEY")?;
|
||||
let client = OpenRouterClient::builder().api_key(api_key).build()?;
|
||||
Ok((Box::new(OpenRouterAIProvider { client }), AIProviderType::OpenRouter))
|
||||
}
|
||||
AIProviderType::Cerebras => {
|
||||
let api_key = env::var("CEREBRAS_API_KEY")?;
|
||||
let client = OpenRouterClient::builder().api_key(api_key).build()?;
|
||||
Ok((Box::new(CerebrasAIProvider { client }), AIProviderType::Cerebras))
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user