llm_api_access/
anthropic.rs1use serde::{Deserialize, Serialize};
3use reqwest::header::{HeaderMap, HeaderValue};
4use reqwest::Client;
5use std::env;
6use crate::errors::GeneralError;
7use dotenv::dotenv;
8
9use crate::structs::general::Message;
10
11#[derive(Debug, Serialize, Clone)]
14pub struct AnthropicRequest {
15 pub model: String,
16 pub max_tokens: usize,
17 pub messages: Vec<Message>,
18}
19
20#[derive(Debug, Deserialize)]
21pub struct AnthropicResult {
22 pub response: AnthropicMessage,
23}
24
25#[derive(Debug, Deserialize)]
26pub struct AnthropicMessage {
27 pub content: String,
28}
29
30const MODEL: &str = "claude-3-7-sonnet-20250219";
31const MAX_TOKENS: usize = 4096;
32
33use std::str;
34
35#[derive(Debug, Deserialize)]
36pub struct AnthropicResponse {
37 pub id: String,
38 pub role: String,
39 pub content: Vec<Content>,
40 }
42
43#[derive(Debug, Deserialize)]
44pub struct Content {
45 pub text: String,
46 }
48
49pub async fn call_anthropic(
50 messages: Vec<Message>,
51) -> Result<String, Box<dyn std::error::Error + Send + Sync>> {
52 dotenv().ok();
53
54 let api_key: String = env::var("ANTHROPIC_API_KEY").map_err(|_| GeneralError {
55 message: "ANTHROPIC API KEY not found in environment variables".to_string(),
56 })?;
57
58 let url: &str = "https://api.anthropic.com/v1/messages";
59
60 let mut headers: HeaderMap = HeaderMap::new();
61
62 headers.insert(
63 "x-api-key",
64 HeaderValue::from_str(&api_key)
65 .map_err(|e| -> Box<dyn std::error::Error + Send + Sync> {
66 Box::new(GeneralError {
67 message: format!("Invalid Anthropic API key: {}", e.to_string()),
68 })
69 })?,
70 );
71
72 headers.insert(
73 "anthropic-version",
74 HeaderValue::from_str("2023-06-01")
75 .map_err(|e| -> Box<dyn std::error::Error + Send + Sync> {
76 Box::new(GeneralError {
77 message: format!("Failed to set Anthropic version header: {}", e.to_string()),
78 })
79 })?,
80 );
81
82 headers.insert(
83 "content-type",
84 HeaderValue::from_str("application/json")
85 .map_err(|e| -> Box<dyn std::error::Error + Send + Sync> {
86 Box::new(GeneralError {
87 message: format!("Failed to set content-type header: {}", e.to_string()),
88 })
89 })?,
90 );
91
92 let client = Client::builder()
93 .default_headers(headers)
94 .build()
95 .map_err(|e| -> Box<dyn std::error::Error + Send + Sync> {
96 Box::new(GeneralError {
97 message: format!("Failed to create HTTP client: {}", e.to_string()),
98 })
99 })?;
100
101 let processed_messages = messages.into_iter().map(|mut message| {
103 if message.role == "model" {
104 message.role = "assistant".to_string();
105 }
106 message
107 }).collect::<Vec<Message>>();
108
109 let request: AnthropicRequest = AnthropicRequest {
110 model: MODEL.to_string(),
111 max_tokens: MAX_TOKENS,
112 messages: processed_messages,
113 };
114
115 let res = client
116 .post(url)
117 .json(&request)
118 .send()
119 .await
120 .map_err(|e| {
121 println!("{:?}", e);
122 Box::new(GeneralError {
123 message: format!("Failed to send request to Anthropic API: {}", e.to_string()),
124 }) as Box<dyn std::error::Error + Send + Sync>
125 })?;
126
127 let rspns_strng = res.text().await.map_err(|e: reqwest::Error| {
129 Box::new(GeneralError {
130 message: format!("Failed to read response from Anthropic API: {}", e.to_string()),
131 }) as Box<dyn std::error::Error + Send + Sync>
132 })?;
133
134 if rspns_strng.contains("invalid x-api-key") {
137 return Err(Box::new(GeneralError {
138 message: "Invalid Anthropic API key. Please check your API key and try again."
139 .to_string(),
140 }));
141 }
142
143 let res: AnthropicResponse = serde_json::from_str(&rspns_strng).map_err(|e| {
144 println!("AnthropicResponse res: {:?}", e);
145 Box::new(GeneralError {
146 message: format!(
147 "Failed to parse response from Anthropic API: {}",
148 e.to_string()
149 ),
150 }) as Box<dyn std::error::Error + Send + Sync>
151 })?;
152
153 Ok(res.content[0].text.clone())
154}