Initial working version
This commit is contained in:
commit
b3f15e3cd6
4 changed files with 176 additions and 0 deletions
9
.env.example
Normal file
9
.env.example
Normal file
|
@ -0,0 +1,9 @@
|
|||
# OpenAPI API
|
||||
OPENAI_API_KEY=your_openai_api_key
|
||||
OPENAI_API_URL=https://api.openai.com/v1/images/generate-description # Update this to the actual endpoint
|
||||
OPENAI_MODEL=gpt-4-vision # Update to the model you want to use
|
||||
|
||||
# WordPress API
|
||||
WP_URL=https://yourwordpresssite.com
|
||||
WP_USERNAME=your_wp_username
|
||||
WP_PASSWORD=your_wp_application_password
|
0
.gitignore
vendored
Normal file
0
.gitignore
vendored
Normal file
12
Cargo.toml
Normal file
12
Cargo.toml
Normal file
|
@ -0,0 +1,12 @@
|
|||
[package]
|
||||
name = "image_wp_uploader"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
reqwest = { version = "0.11", features = ["json"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
dotenvy = "0.15"
|
||||
base64 = "0.21" # Use the latest version of the crate
|
155
src/main.rs
Normal file
155
src/main.rs
Normal file
|
@ -0,0 +1,155 @@
|
|||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use base64::engine::general_purpose::STANDARD;
|
||||
use base64::Engine; // Import the Engine trait
|
||||
|
||||
use reqwest::Client;
|
||||
use serde_json::Value;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Config {
|
||||
wp_url: String,
|
||||
wp_username: String,
|
||||
wp_password: String,
|
||||
openai_api_url: String,
|
||||
openai_api_key: String,
|
||||
openai_model: String,
|
||||
}
|
||||
|
||||
async fn generate_description(config: &Config, image_data: &[u8]) -> Result<String, Box<dyn std::error::Error>> {
|
||||
let client = Client::new();
|
||||
|
||||
// Encode the image data in base64 using STANDARD engine
|
||||
let encoded_image = STANDARD.encode(image_data);
|
||||
|
||||
// Call OpenAI API with gpt-4-turbo
|
||||
let response = client
|
||||
.post(&config.openai_api_url)
|
||||
.header("Authorization", format!("Bearer {}", config.openai_api_key))
|
||||
.json(&serde_json::json!({
|
||||
"model": config.openai_model,
|
||||
"messages": [
|
||||
{
|
||||
"role": "system",
|
||||
"content": "You are an AI assistant that describes images for blog posts."
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Describe the content of this image.",
|
||||
"image": encoded_image
|
||||
}
|
||||
]
|
||||
}))
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
let response_text = response.text().await?;
|
||||
let json: Value = serde_json::from_str(&response_text)?;
|
||||
|
||||
// Safely extract the description
|
||||
let description = json["choices"]
|
||||
.get(0)
|
||||
.and_then(|choice| choice["message"]["content"].as_str())
|
||||
.unwrap_or("No description generated")
|
||||
.to_string();
|
||||
|
||||
Ok(description)
|
||||
}
|
||||
|
||||
async fn upload_to_wordpress(
|
||||
wp_url: &str,
|
||||
wp_username: &str,
|
||||
wp_password: &str,
|
||||
image_data: &[u8],
|
||||
filename: &str,
|
||||
description: &str,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let client = Client::new();
|
||||
|
||||
// Encode the authentication string using base64::engine
|
||||
let auth = STANDARD.encode(format!("{}:{}", wp_username, wp_password));
|
||||
|
||||
// Upload image to WordPress
|
||||
let response = client
|
||||
.post(format!("{}/wp-json/wp/v2/media", wp_url))
|
||||
.header("Authorization", format!("Basic {}", auth))
|
||||
.header("Content-Disposition", format!("attachment; filename=\"{}\"", filename))
|
||||
.body(image_data.to_vec())
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
let response_text = response.text().await?;
|
||||
|
||||
// Deserialize the response as a JSON object (Value)
|
||||
let json: Value = serde_json::from_str(&response_text)?;
|
||||
|
||||
// Safely extract the media_id from the response
|
||||
let media_id = json["id"]
|
||||
.as_i64()
|
||||
.unwrap_or(0) as i32;
|
||||
|
||||
// Create a post with the image and description
|
||||
client
|
||||
.post(format!("{}/wp-json/wp/v2/posts", wp_url))
|
||||
.header("Authorization", format!("Basic {}", auth))
|
||||
.json(&serde_json::json!({
|
||||
"title": filename,
|
||||
"content": description,
|
||||
"status": "publish",
|
||||
"featured_media": media_id,
|
||||
}))
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn process_image(config: &Config, image_path: &str) -> Result<(), Box<dyn std::error::Error>> {
|
||||
// Read the image file
|
||||
let mut file = File::open(image_path)?;
|
||||
let mut image_data = Vec::new();
|
||||
file.read_to_end(&mut image_data)?;
|
||||
|
||||
// Generate description from OpenAI
|
||||
let description = generate_description(config, &image_data).await?;
|
||||
|
||||
// Upload image and create WordPress post
|
||||
let filename = image_path.split('/').last().unwrap_or("image");
|
||||
upload_to_wordpress(
|
||||
&config.wp_url,
|
||||
&config.wp_username,
|
||||
&config.wp_password,
|
||||
&image_data,
|
||||
filename,
|
||||
&description,
|
||||
).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
// Read command-line arguments
|
||||
let args: Vec<String> = env::args().collect();
|
||||
if args.len() < 2 {
|
||||
eprintln!("Usage: {} <path_to_image>", args[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
let image_path = &args[1];
|
||||
|
||||
// Load configuration from .env or configuration file
|
||||
let config = Config {
|
||||
wp_url: "https://falko.zurell.de".to_string(),
|
||||
wp_username: "falko".to_string(),
|
||||
wp_password: "G6FI qmWi OG1M vXqP 1p5j rDDS".to_string(),
|
||||
openai_api_url: "https://api.openai.com/v1/chat/completions".to_string(),
|
||||
openai_api_key: "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".to_string(),
|
||||
openai_model: "gpt-4.0".to_string(),
|
||||
};
|
||||
|
||||
if let Err(e) = process_image(&config, image_path).await {
|
||||
eprintln!("Error processing image: {}", e);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue