added hint to .env file when calling the program

This commit is contained in:
Falko Zurell 2024-11-18 23:39:10 +01:00
parent fdf0095463
commit 9b54328892
2 changed files with 52 additions and 10 deletions

View file

@ -25,3 +25,5 @@ Generated description: Aerial view of a circular lake surrounded by dense forest
Successfully uploaded image to WordPress with description
Image URL: https://example.wordpress.com/wp-content/uploads/2024/11/DJI_0247-scaled.jpg
```
Hint: make sure that the `.env` file is located in $PWD when calling the script

View file

@ -3,7 +3,7 @@ use reqwest::{self, multipart};
use serde_json::{json, Value};
use std::env;
use std::error::Error;
use std::path::Path;
use std::path::{Path, PathBuf};
use tokio;
use base64::{Engine as _, engine::general_purpose::STANDARD};
@ -32,6 +32,38 @@ impl Config {
}
}
fn validate_image_path(path_str: &str) -> Result<PathBuf, Box<dyn Error>> {
let path = PathBuf::from(path_str);
// Check if path exists
if !path.exists() {
return Err(format!("Image path does not exist: {}", path_str).into());
}
// Check if it's a file
if !path.is_file() {
return Err(format!("Path is not a file: {}", path_str).into());
}
// Check file extension
match path.extension().and_then(|ext| ext.to_str()) {
Some(ext) => {
let lower_ext = ext.to_lowercase();
if !["jpg", "jpeg", "png", "gif"].contains(&lower_ext.as_str()) {
return Err(format!("Unsupported file type: {}", ext).into());
}
}
None => return Err("File has no extension".into()),
}
// Try to canonicalize the path (resolve symlinks and normalize)
let canonical_path = path.canonicalize()
.map_err(|e| format!("Failed to resolve path: {}", e))?;
println!("Using image file: {}", canonical_path.display());
Ok(canonical_path)
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
// Get image path from command line arguments
@ -40,24 +72,29 @@ async fn main() -> Result<(), Box<dyn Error>> {
eprintln!("Usage: {} <image_path>", args[0]);
std::process::exit(1);
}
let image_path = &args[1];
// Validate and normalize the image path
let image_path = validate_image_path(&args[1])?;
// Load configuration
let config = Config::from_env()?;
// Get image description from ChatGPT
let description = get_image_description(&config, image_path).await?;
let description = get_image_description(&config, &image_path).await?;
println!("Generated description: {}", description);
// Upload image to WordPress and set ALT text
upload_to_wordpress(&config, image_path, &description).await?;
upload_to_wordpress(&config, &image_path, &description).await?;
Ok(())
}
async fn get_image_description(config: &Config, image_path: &str) -> Result<String, Box<dyn Error>> {
async fn get_image_description(config: &Config, image_path: &Path) -> Result<String, Box<dyn Error>> {
// Read and encode image
let image_data = std::fs::read(image_path)?;
let image_data = tokio::fs::read(image_path)
.await
.map_err(|e| format!("Failed to read image file: {}", e))?;
let base64_image = STANDARD.encode(&image_data);
// Create ChatGPT API request
@ -67,7 +104,7 @@ async fn get_image_description(config: &Config, image_path: &str) -> Result<Stri
.header("Authorization", format!("Bearer {}", config.openai_api_key))
.header("Content-Type", "application/json")
.json(&json!({
"model": config.openai_model, // Now using the model from config
"model": config.openai_model,
"max_tokens": 300,
"messages": [
{
@ -112,12 +149,15 @@ async fn get_image_description(config: &Config, image_path: &str) -> Result<Stri
async fn upload_to_wordpress(
config: &Config,
image_path: &str,
image_path: &Path,
description: &str,
) -> Result<(), Box<dyn Error>> {
let client = reqwest::Client::new();
let file_data = tokio::fs::read(image_path).await?;
let filename = Path::new(image_path)
let file_data = tokio::fs::read(image_path)
.await
.map_err(|e| format!("Failed to read image for upload: {}", e))?;
let filename = image_path
.file_name()
.ok_or("Invalid filename")?
.to_str()