-
Notifications
You must be signed in to change notification settings - Fork 138
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Sample Project for Automatic Content Creation #403
Open
theperiperi
wants to merge
5
commits into
cloudinary:master
Choose a base branch
from
theperiperi:sample-project
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -39,4 +39,4 @@ script: | |
notifications: | ||
email: | ||
recipients: | ||
- sdk_developers@cloudinary.com | ||
- sdk_developers@cloudinary.com |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
# Social Media Content Creation API with Cloudinary | ||
|
||
This project demonstrates a simple Flask API for social media content creation. The API allows users to upload images, apply transformations suitable for social media (like resizing, cropping, and adjusting image formats), and optionally set custom public IDs. Additionally, the API provides functionality to clean up old uploads by tag. | ||
|
||
## Features | ||
|
||
- Upload images for social media content creation. | ||
- Apply transformations such as resizing, cropping, and format adjustment for optimal display on platforms like Instagram, Facebook, and Twitter. | ||
- Option to assign custom public IDs for better image management. | ||
- Cleanup of previously uploaded images by tag. | ||
- **Image Uploading**: Easily upload images to Cloudinary for use in your content. | ||
- **Image Transformation**: Utilize powerful transformation capabilities to manipulate images directly in your content generation process. | ||
- **Content Delivery**: Benefit from fast and efficient image delivery through Cloudinary's global CDN. | ||
- **AI Integration**: Enhance your content generation logic by integrating AI models for dynamic content creation. | ||
- **Dynamic Content Creation**: Create personalized content based on user preferences or trends. | ||
|
||
## Prerequisites | ||
|
||
Before running this project, ensure you have: | ||
|
||
1. [Python 3.x](https://www.python.org/downloads/) | ||
2. A [Cloudinary account](https://cloudinary.com/users/register/free) | ||
3. Cloudinary Python SDK installed via pip. | ||
|
||
## Setup Instructions | ||
|
||
### 1. Install Dependencies | ||
|
||
After cloning or downloading this repository, install the required packages using `pip`: | ||
|
||
```bash | ||
pip install flask cloudinary | ||
``` | ||
|
||
### 2. Configure Cloudinary | ||
|
||
You need to configure the CLOUDINARY_URL environment variable with your Cloudinary credentials. You can find your credentials in the Cloudinary Management Console. | ||
|
||
For Linux/MacOS (bash/zsh): | ||
```bash | ||
export CLOUDINARY_URL=cloudinary://<API-Key>:<API-Secret>@<Cloud-name> | ||
``` | ||
|
||
For Windows (Command Prompt/PowerShell): | ||
```bash | ||
set CLOUDINARY_URL=cloudinary://<API-Key>:<API-Secret>@<Cloud-name> | ||
``` | ||
|
||
### 3. Running the Flask App | ||
|
||
Start the Flask server by running: | ||
|
||
```bash | ||
python app.py | ||
``` | ||
|
||
The server will be available at http://127.0.0.1:5000/. | ||
|
||
## Usage | ||
|
||
### 1. Uploading an Image for Social Media | ||
|
||
To upload an image with transformations applied (suitable for social media), send a POST request to the /generate_post endpoint with the image file. You can optionally provide a public_id for the image. | ||
|
||
- **Endpoint**: /generate_post | ||
- **Method**: POST | ||
- **Parameters**: | ||
- image (required): The image file to upload. | ||
- public_id (optional): Custom public ID for the image. | ||
|
||
**Image Transformations**: | ||
|
||
The API will automatically resize the image to a 1:1 aspect ratio (200x200px), perfect for profile pictures, thumbnails, or other social media purposes. | ||
|
||
**Example with cURL**: | ||
|
||
```bash | ||
curl -X POST http://localhost:5000/generate_post \ | ||
-F "image=@/path/to/your/social_media_image.jpg" \ | ||
-F "public_id=my_custom_id" | ||
``` | ||
|
||
**Example Response**: | ||
```bash | ||
{ | ||
"status": "success", | ||
"image_url": "http://res.cloudinary.com/<cloud-name>/image/upload/v12345678/my_custom_id.jpg" | ||
} | ||
``` | ||
The image is transformed (resized to 200x200, cropped to fill), optimized for social media platforms. | ||
|
||
### 2. Cleaning Up Uploaded Images | ||
|
||
To delete all images uploaded with the default tag (set as python_sample_basic), you can run: | ||
|
||
```bash | ||
python app.py cleanup | ||
``` | ||
|
||
This will delete all images tagged under DEFAULT_TAG. | ||
|
||
## Recommended Image Transformations for Social Media | ||
|
||
- **Profile Pictures/Thumbnails**: Resize to 200x200px with a 1:1 aspect ratio. | ||
- **Banners**: Crop to 1200x400px for optimal display on platforms like Twitter. | ||
- **Story Images**: Resize to 1080x1920px (vertical aspect ratio) for Instagram or Snapchat stories. | ||
|
||
**Example Transformations in the Code**: | ||
|
||
Resize and Crop: Automatically applied transformation in the API: | ||
|
||
```bash | ||
url, options = cloudinary_url( | ||
response['public_id'], | ||
format=response['format'], | ||
width=200, | ||
height=200, | ||
crop="fill" | ||
) | ||
``` | ||
|
||
This resizes the uploaded image to 200x200 pixels and crops it to fit. | ||
|
||
## Additional Functionality | ||
|
||
- **Setting Custom Public IDs**: You can assign custom public IDs for uploaded images, which is useful for managing content more effectively. | ||
- **Dynamic Transformations**: Feel free to modify the transformations in upload_file() to match specific platform requirements (e.g., square thumbnails, vertical or horizontal banners, etc.). | ||
|
||
### Environment Variables (Optional) | ||
|
||
If you prefer, you can store the CLOUDINARY_URL in a .env file to make environment configuration easier: | ||
|
||
```bash | ||
CLOUDINARY_URL=cloudinary://<API-Key>:<API-Secret>@<Cloud-name> | ||
``` | ||
After creating the .env file, load it by running: | ||
```bash | ||
source .env | ||
``` | ||
|
||
## Conclusion | ||
|
||
This project is designed to help you quickly set up an image uploading API tailored to social media content creation needs. It handles image transformations, easy uploads, and content management using Cloudinary. By leveraging the features of `pycloudinary`, you can create a robust content generation system that enhances your posts with relevant images. | ||
|
||
Good luck and happy posting! |
134 changes: 134 additions & 0 deletions
134
samples/content-creation/cloudinary-ai-post-generator.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
#!/usr/bin/env python | ||
import os | ||
import sys | ||
|
||
from cloudinary.api import delete_resources_by_tag, resources_by_tag | ||
from cloudinary.uploader import upload | ||
from cloudinary.utils import cloudinary_url | ||
from flask import Flask, request, jsonify | ||
|
||
# Initialize Flask app | ||
app = Flask(__name__) | ||
|
||
# Config | ||
os.chdir(os.path.join(os.path.dirname(sys.argv[0]), '.')) | ||
if os.path.exists('settings.py'): | ||
exec(open('settings.py').read()) | ||
|
||
DEFAULT_TAG = "python_sample_basic" | ||
|
||
|
||
def dump_response(response): | ||
"""Function to print and handle upload response""" | ||
print("Upload response:") | ||
for key in sorted(response.keys()): | ||
print(" %s: %s" % (key, response[key])) | ||
|
||
|
||
def upload_file(file_path, public_id=None, mood=None, theme=None): | ||
"""Upload a file to Cloudinary with options for custom public ID and transformations""" | ||
print(f"--- Uploading {file_path}") | ||
|
||
# Define transformations based on mood | ||
transformations = [] | ||
|
||
if mood == "happy": | ||
transformations.append({"effect": "brightness:30"}) # Increase brightness | ||
elif mood == "sad": | ||
transformations.append({"effect": "grayscale"}) # Convert to grayscale | ||
|
||
# Add text overlay based on theme | ||
if theme: | ||
transformations.append({ | ||
"overlay": { | ||
"font_family": "Arial", | ||
"font_size": 20, | ||
"text": f"{theme.capitalize()} - {mood.capitalize()}", | ||
"text_color": "white" | ||
}, | ||
"gravity": "north", | ||
"y": 10 | ||
}) | ||
|
||
# Upload with transformations | ||
response = upload( | ||
file_path, | ||
public_id=public_id, | ||
transformation=transformations, | ||
tags=DEFAULT_TAG | ||
) | ||
|
||
dump_response(response) | ||
|
||
url, options = cloudinary_url( | ||
response['public_id'], | ||
format=response['format'], | ||
width=200, | ||
height=150, | ||
crop="fill" | ||
) | ||
print("Image URL: " + url) | ||
return url | ||
|
||
|
||
@app.route('/generate_post', methods=['POST']) | ||
def generate_post(): | ||
"""API endpoint to handle post generation and image upload""" | ||
try: | ||
# Get image file from request | ||
image = request.files.get('image') | ||
|
||
if not image: | ||
return jsonify({"error": "No image file provided"}), 400 | ||
|
||
# Create uploads directory if it doesn't exist | ||
uploads_dir = os.path.join(os.path.dirname(__file__), 'uploads') | ||
os.makedirs(uploads_dir, exist_ok=True) | ||
|
||
# Save image locally | ||
file_path = os.path.join(uploads_dir, image.filename) | ||
image.save(file_path) | ||
|
||
# Upload file to Cloudinary | ||
public_id = request.form.get('public_id', None) | ||
mood = request.form.get('mood', None) | ||
theme = request.form.get('theme', None) | ||
image_url = upload_file(file_path, public_id=public_id, mood=mood, theme=theme) | ||
|
||
# Clean up the local file after upload | ||
os.remove(file_path) | ||
|
||
# Return response | ||
return jsonify({"status": "success", "image_url": image_url}) | ||
|
||
except Exception as e: | ||
print(f"Error: {str(e)}") # Log the error | ||
return jsonify({"error": str(e)}), 500 | ||
|
||
|
||
def cleanup(): | ||
"""Cleanup resources by tag""" | ||
response = resources_by_tag(DEFAULT_TAG) | ||
resources = response.get('resources', []) | ||
if not resources: | ||
print("No images found") | ||
return | ||
print(f"Deleting {len(resources)} images...") | ||
delete_resources_by_tag(DEFAULT_TAG) | ||
print("Done!") | ||
|
||
|
||
@app.route('/') | ||
def index(): | ||
return app.send_static_file('index.html') | ||
|
||
|
||
if __name__ == '__main__': | ||
if len(sys.argv) > 1: | ||
if sys.argv[1] == 'upload': | ||
upload_file("sample.jpg") | ||
elif sys.argv[1] == 'cleanup': | ||
cleanup() | ||
else: | ||
print("--- Starting Flask server ---") | ||
app.run(debug=True) |
File renamed without changes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import cloudinary | ||
|
||
cloudinary.config( | ||
cloud_name = "xxx", | ||
api_key = "xxx", | ||
api_secret = "xxx" | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
<title>Image Upload</title> | ||
<style> | ||
body { | ||
font-family: Arial, sans-serif; | ||
margin: 20px; | ||
} | ||
form { | ||
margin-bottom: 20px; | ||
} | ||
input[type="file"], input[type="text"], select { | ||
margin-bottom: 10px; | ||
width: 100%; | ||
padding: 8px; | ||
box-sizing: border-box; | ||
} | ||
button { | ||
padding: 10px 15px; | ||
background-color: #4CAF50; | ||
color: white; | ||
border: none; | ||
cursor: pointer; | ||
} | ||
button:hover { | ||
background-color: #45a049; | ||
} | ||
#response { | ||
margin-top: 20px; | ||
} | ||
</style> | ||
</head> | ||
<body> | ||
<h1>Upload Image to Cloudinary</h1> | ||
<form id="uploadForm"> | ||
<input type="file" name="image" accept="image/*" required> | ||
<input type="text" name="public_id" placeholder="Public ID (optional)"> | ||
<input type="text" name="mood" placeholder="Mood (e.g., happy, sad)" required> | ||
<input type="text" name="theme" placeholder="Theme (e.g., nature, technology)" required> | ||
<select name="aspect_ratio" required> | ||
<option value="1:1">1:1</option> | ||
<option value="16:9">16:9</option> | ||
<option value="4:3">4:3</option> | ||
<option value="2:1">2:1</option> | ||
</select> | ||
<button type="submit">Upload</button> | ||
</form> | ||
<div id="response"></div> | ||
|
||
<script> | ||
document.getElementById('uploadForm').addEventListener('submit', function(event) { | ||
event.preventDefault(); | ||
const formData = new FormData(this); | ||
fetch('/generate_post', { | ||
method: 'POST', | ||
body: formData | ||
}) | ||
.then(response => response.json()) | ||
.then(data => { | ||
const responseDiv = document.getElementById('response'); | ||
if (data.error) { | ||
responseDiv.innerHTML = `<p style="color: red;">Error: ${data.error}</p>`; | ||
} else { | ||
responseDiv.innerHTML = `<p style="color: green;">Success! Image URL: <a href="${data.image_url}" target="_blank">${data.image_url}</a></p>`; | ||
responseDiv.innerHTML += `<p>Generated Content: ${data.content}</p>`; | ||
} | ||
}) | ||
.catch(error => { | ||
document.getElementById('response').innerHTML = `<p style="color: red;">Error: ${error.message}</p>`; | ||
}); | ||
}); | ||
</script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These values set here break things for someone who is using
CLOUDINARY_URL
environment variable.You can keep this file, just comment it out.