diff --git a/README.md b/README.md index 4946f9c..c3f18d4 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,63 @@ # Instagram Pixelfed Batch Upload -This program takes a folder and iterates over the images and creates Pixelfed postings with a specified batch size. -The description of the post can be given via the config.json. +![Tool illustration](assets/pixelfed-bot_illustration_small.png "Littel Robot describing the pictures for you.") + +This program takes a folder, iterates over the images and creates Pixelfed postings with a specified batch size. + +There are 4 different options for the image description (ALT text) supported now: + +1. ChatGPT/OpenAI mode: generating the image description using the OpenAI API and respective model. You'll need to provide your OpenAI API access key and the model you wanna use. + +2. Local/Ollama mode: generate the image description using a local/own installation of Ollama. You'll have to configure the base URL of your ollama installation, an (optional) access key and the model to be used. + +3.) File mode: reading the image description from a text file with the same name as the image + a configurable extension. + +4.) No description: don't generate an image description, just batch upload the pictures. + + +The description of the post can be given via the `config.json`. Two variables in the post description can be give (see the `config.json.example` ). -Usage: `./pixelfed_batch_uploader ../../Downloads/Instagram-Backup/media/posts/201406 --title "June 2014"` +``` +Usage: pixelfed_batch_uploader [OPTIONS] --title --image-path <IMAGE_PATH> + +Options: + -m, --mode <MODE> + Image description mode + + [default: file] + + Possible values: + - chat-gpt: Use ChatGTP + - file: Taking from a file + - local: Local LLM + - none + + -t, --title <TITLE> + The title of the posting + + -i, --image-path <IMAGE_PATH> + The path to the file to read + + -c, --config <FILE> + Sets a custom config file + + -v, --visibility <private> + + + -h, --help + Print help (see a summary with '-h') + + -V, --version + Print version +``` + +Example: `Usage: `./pixelfed_batch_uploader -i ../../Downloads/Instagram-Backup/media/posts/201406 --title "June 2014" -m local` The `config.json` must be in the same directory the program is called from (`$PWD`) -[![asciicast](https://asciinema.mxhdr.net/a/6.svg)](https://asciinema.mxhdr.net/a/6) - Check the [package of this repo](https://repos.mxhdr.net/maxheadroom/insta-import-pixelfed/packages) to get pre-compiled binaries for macOS (Apple Silicon), Linux x86_64, Windows ARM -## OpenAI Integration for Image Description - -Added OpenAI integration to generate image descriptions and put them into the ALT text for each image. If an `openai_api_key` is present in the `config.json` then the Image description is fetched from the OpenAI API. diff --git a/assets/pixelfed-bot_illustration.png b/assets/pixelfed-bot_illustration.png new file mode 100644 index 0000000..89f8990 Binary files /dev/null and b/assets/pixelfed-bot_illustration.png differ diff --git a/assets/pixelfed-bot_illustration_small.png b/assets/pixelfed-bot_illustration_small.png new file mode 100644 index 0000000..835ea0b Binary files /dev/null and b/assets/pixelfed-bot_illustration_small.png differ diff --git a/config.json.example b/config.json.example index 9325124..e87fad6 100644 --- a/config.json.example +++ b/config.json.example @@ -1,12 +1,15 @@ { - "pixelfed_url": "https://pixelfed.example.com", - // See https://docs.pixelfed.org/running-pixelfed/installation.html#setting-up-services - "access_token": "sdg;lkjrglksjh;lkshj;lksjthrst;hoijrt;ihj;sithj;itjh", - "visibility": "unlisted", - "batch_size": 10, - "default_text": "Instagram dump from @title@ @batch@ #instabackup #instaimport #instaexit", - // https://help.openai.com/en/articles/4936850-where-do-i-find-my-openai-api-key - "openai_api_key": "0bff275feca7baab5ac508e635543f59fff42d4436c9918cd37c330f9adb4eb4fda643c212794b800bb05fb26016f55425c6755a3525c64792197e4d0fbe95d5", + "pixelfed_url": "https://pxl.mxhdr.net", + "pixelfed_access_token": "longstringofpersonalaccesstokenfromyourpixelfedaccount", + "pixelfed_visibility": "public", + "pixelfed_batch_size": 20, + "pixelfed_default_text": "Instagram dump from @title@ @batch@ #instabackup #instaimport #instaexit", + "openai_api_key": "youropenapiaccesskey", "openai_api_url": "https://api.openai.com/v1/chat/completions", - "openai_model": "gpt-4o" + "openai_model": "gpt-4o", + "ollama_api_key": "yourollamaaccesskey_mightbeoptional", + "ollama_api_url": "http://localhost:11434/api/generate", + "ollama_model": "llama3.2-vision:11b-instruct-q8_0", + "caption_extension": ".caption.txt", + "prompt": "Imagine you are posting on social media and want to provide image descriptions for people with vision disabilities. Those people might use screen readers. That’s why you want to put an ALT text for images so those people can understand what is shown in the picture. Try to detect the main topic and mood or intention of the picture. If there is visible and readable text in the image, then also provide that text. Complete the sentence: “This picture shows” and respond in plain text format with less than 5000 characters?" } diff --git a/src/image_description.rs b/src/image_description.rs index 691246a..e5e418a 100644 --- a/src/image_description.rs +++ b/src/image_description.rs @@ -41,21 +41,27 @@ struct LlamaModel { pub fn get_description_from_file( image_name: String, file_config: FileConfig, -) -> Result<String, Box<dyn super::Error>> { +) -> Result<String, Box<dyn std::error::Error>> { //read image caption from a local file that //has the same name than the image with the extension ".caption.txt" let caption_extension = file_config.caption_extension; let captionname = format!("{}{}", &image_name, caption_extension); debug!("Looking for {}", &captionname); - let caption_data = std::fs::read_to_string(captionname); + let caption_data = match std::fs::read_to_string(captionname) { + Ok(caption) => caption, + Err(e) => { + error!("Failed to find caption file: {}", &e.to_string()); + std::process::exit(1); + } + }; println!( "Description fetched successfully from FILE for {}", &image_name ); - Ok(caption_data.unwrap()) + Ok(caption_data) } // fetch image description from ChatGPT diff --git a/src/main.rs b/src/main.rs index ee99069..6314ad3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -42,6 +42,8 @@ enum Mode { File, /// Local LLM Local, + // No Image Description + None, } #[derive(Debug, Deserialize)] diff --git a/src/pixelfed.rs b/src/pixelfed.rs index 715be04..72dc70a 100644 --- a/src/pixelfed.rs +++ b/src/pixelfed.rs @@ -129,6 +129,11 @@ pub fn bulk_upload_images( info!("Description generated by OLLAMA: {}", &description.clone()); media_descriptions.push(description.clone()); } + super::Mode::None => { + // No impage description wanted + description = "".to_string(); + media_descriptions.push(description.clone()) + } } println!("Uploading image {} to Pixelfed", &image_path.to_string());