use crate::error::{AppError, Result};
use serde::{Deserialize, Serialize};
const API_URL: &str = "https://api.openai.com/v1/chat/completions";
#[derive(Debug, Serialize)]
struct ChatRequest<'a> {
model: &'a str,
messages: Vec<ChatMessage<'a>>
}
#[derive(Debug, Serialize)]
struct ChatMessage<'a> {
role: &'a str,
content: &'a str,
}
#[derive(Debug, Deserialize)]
struct ChatResponse {
choices: Vec<Choice>,
}
#[derive(Debug, Deserialize)]
struct Choice {
message: Message,
}
#[derive(Debug, Deserialize)]
struct Message {
content: String,
}
fn build_prompt(log_data: &str) -> String {
format!(
r#"System: You are 'Log Genius', a world-class software developer and DevOps expert. Your mission is to analyze complex log data provided by the user and offer a clear, actionable solution. Your response MUST be in English and strictly follow the format below, using Markdown.
---
[Summary] 💡
{{Provide a 1-2 sentence executive summary of the problem here.}}
[Potential Causes] 🧐
{{List the 1-3 most likely causes in a numbered list.}}
1. {{Cause 1}}
2. {{Cause 2}}
[Suggested Solutions] 🛠️
{{Provide specific, actionable solutions for each cause. If code changes are needed, show them clearly as an indented code block, specifying the file to be modified.}}
1. {{Solution for Cause 1}}
# e.g., in docker-compose.yml
services:
web:
depends_on:
db:
condition: service_healthy
2. {{Solution for Cause 2}}
---
If the provided log does not seem to contain an error and looks like a normal operational log, state in the [Summary] section: "This appears to be a standard operational log with no specific errors found." and omit the other sections.
User:
{}
"#,
log_data
)
}
pub async fn analyze_log(api_key: &str, log_data: &str) -> Result<String> {
let client = reqwest::Client::new();
let prompt_content = build_prompt(log_data);
let request_body = ChatRequest {
model: "gpt-4o",
messages: vec![ChatMessage {
role: "user",
content: &prompt_content,
}],
};
let response = client
.post(API_URL)
.bearer_auth(api_key)
.json(&request_body)
.send()
.await?
.json::<ChatResponse>()
.await?;
if let Some(choice) = response.choices.into_iter().next() {
Ok(choice.message.content)
} else {
Err(AppError::NoResponse)
}
}