Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ tui-textarea = "0.7"
# ansi-to-tui = "7.0.0"
vt100 = "0.15"
codepage-437 = "0.1.0"
reqwest = { version = "0.11", features = ["json"] }
tokio = { version = "1", features = ["full"] }
# Vendored ratatui-image dependencies
icy_sixel = "0.1.1"
base64 = "0.21.2"
Expand Down
90 changes: 90 additions & 0 deletions src/chatgpt_client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
use anyhow::{Result, anyhow};
use serde::{Deserialize, Serialize};

#[derive(Serialize)]
pub struct ChatGPTRequest {
pub model: String,
pub messages: Vec<Message>,
pub max_tokens: usize,
pub temperature: f32,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Message {
pub role: String,
pub content: String,
}

#[derive(Deserialize, Debug)]
pub struct ChatGPTResponse {
pub choices: Vec<Choice>,
}

#[derive(Deserialize, Debug)]
pub struct Choice {
pub message: Message,
}

pub struct ChatGPTClient {
api_key: String,
client: reqwest::Client,
}

impl ChatGPTClient {
pub fn new(api_key: String) -> Result<Self> {
if api_key.is_empty() {
return Err(anyhow!(
"ChatGPT API key not found. Please set OPENAI_API_KEY environment variable."
));
}

Ok(ChatGPTClient {
api_key,
client: reqwest::Client::new(),
})
}

pub async fn summarize(&self, text: &str, language_instruction: &str) -> Result<String> {
let prompt = format!("{}{}", language_instruction, text);

let request = ChatGPTRequest {
model: "gpt-3.5-turbo".to_string(),
messages: vec![Message {
role: "user".to_string(),
content: prompt,
}],
max_tokens: 500,
temperature: 0.7,
};

let response = self
.client
.post("https://api.openai.com/v1/chat/completions")
.header("Authorization", format!("Bearer {}", self.api_key))
.header("Content-Type", "application/json")
.json(&request)
.send()
.await
.map_err(|e| anyhow!("Failed to send request to ChatGPT: {}", e))?;

if !response.status().is_success() {
let status = response.status();
let body = response
.text()
.await
.unwrap_or_else(|_| "Unknown error".to_string());
return Err(anyhow!("ChatGPT API error ({}): {}", status, body));
}

let gpt_response: ChatGPTResponse = response
.json()
.await
.map_err(|e| anyhow!("Failed to parse ChatGPT response: {}", e))?;

if let Some(choice) = gpt_response.choices.first() {
Ok(choice.message.content.clone())
} else {
Err(anyhow!("No response from ChatGPT"))
}
}
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
// Export modules for use in tests
pub mod book_manager;
pub mod bookmarks;
pub mod chatgpt_client;
pub mod color_mode;
pub mod comments;
pub use inputs::event_source;
pub mod components;
pub mod images;
pub mod preferences;
// Vendored ratatui-image
pub mod vendored;
pub use vendored::ratatui_image;
Expand Down
Loading