Insta_auto / app.py
cryogenic22's picture
Update app.py
034005e verified
Raw History Blame Contribute Delete
18.5 kB
import streamlit as st
import os
import json
from datetime import datetime
from crewai import Agent, Task, Crew
from langchain_openai import OpenAI
from openai import OpenAI as OpenAIClient
import logging
import requests
import replicate
import random
from PIL import Image, ImageDraw, ImageFont
from io import BytesIO
import textwrap
# Set up logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# Constants for directory paths
BASE_DIR = "data"
QUOTES_DIR = os.path.join(BASE_DIR, "quotes")
IMAGES_DIR = os.path.join(BASE_DIR, "images")
FINAL_IMAGES_DIR = os.path.join(BASE_DIR, "final_images")
MUSIC_DIR = os.path.join(BASE_DIR, "music") # New directory for storing music files
# Ensure the directories exist
try:
os.makedirs(QUOTES_DIR, exist_ok=True)
os.makedirs(IMAGES_DIR, exist_ok=True)
os.makedirs(FINAL_IMAGES_DIR, exist_ok=True)
os.makedirs(MUSIC_DIR, exist_ok=True) # Create music directory
logger.info(f"Directories successfully created or verified: {BASE_DIR}, {QUOTES_DIR}, {IMAGES_DIR}, {FINAL_IMAGES_DIR}, {MUSIC_DIR}")
except Exception as e:
logger.error(f"Error creating directories: {str(e)}")
def log_message(message, type="info"):
if 'process_logs' not in st.session_state:
st.session_state.process_logs = []
timestamp = datetime.now().strftime("%H:%M:%S")
st.session_state.process_logs.append({
"timestamp": timestamp,
"message": message,
"type": type
})
class SpiritualThemes:
TRADITIONS = {
"Eastern": ["Buddhism", "Hinduism", "Taoism", "Zen", "Vedanta", "Yoga Philosophy"],
"Western": ["Christian Mysticism", "Sufi Wisdom", "Kabbalah", "Greek Philosophy"],
"Indigenous": ["Native American Wisdom", "Aboriginal Spirituality", "African Traditional"],
"Modern": ["Mindfulness", "Contemporary Philosophy", "Integrative Spirituality"]
}
THEMES = ["Inner Peace", "Mindfulness", "Compassion", "Wisdom", "Self-Discovery",
"Unity", "Balance", "Transformation", "Enlightenment", "Purpose"]
QUOTE_STYLES = ["contemplative", "inspirational", "philosophical", "practical wisdom",
"mystical insight", "ancient teaching", "modern interpretation"]
class ContentGenerator:
def __init__(self, openai_api_key, replicate_api_key):
self.llm = OpenAI(api_key=openai_api_key, temperature=0.7)
self.openai_client = OpenAIClient(api_key=openai_api_key)
self.replicate_client = replicate.Client(api_token=replicate_api_key)
def _generate_prompt_variation(self):
tradition_category = random.choice(list(SpiritualThemes.TRADITIONS.keys()))
themes = random.sample(SpiritualThemes.THEMES, 2)
return f"""Generate a spiritual quote from {tradition_category} wisdom tradition.
Focus on themes of {themes[0]} and {themes[1]}.
Make it profound yet accessible.
Format: Return only the quote text on first line, then author name on second line."""
def _get_fallback_quote(self):
fallback_quotes = [
{"text": "Be the change you wish to see in the world.",
"author": "Mahatma Gandhi", "tradition": "Modern Spirituality"},
{"text": "Peace comes from within. Do not seek it without.",
"author": "Buddha", "tradition": "Buddhism"},
{"text": "Love is the bridge between you and everything.",
"author": "Rumi", "tradition": "Sufi Wisdom"}
]
quote = random.choice(fallback_quotes)
quote.update({
"theme": random.choice(SpiritualThemes.THEMES),
"generated_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"source": "fallback"
})
log_message("ℹ️ Using fallback quote system", "info")
return quote
def generate_quote(self):
try:
log_message("🎯 Starting quote generation")
response = self.openai_client.chat.completions.create(
model="gpt-4",
messages=[{
"role": "system",
"content": "Generate a spiritual quote with attribution."
}, {
"role": "user",
"content": self._generate_prompt_variation()
}],
temperature=0.7
)
text = response.choices[0].message.content
lines = text.split('\n')
quote_text = lines[0] if lines else ""
author = lines[1].replace('-', '').strip() if len(lines) > 1 else "Unknown"
tradition = random.choice(list(SpiritualThemes.TRADITIONS.keys()))
theme = random.choice(SpiritualThemes.THEMES)
result = {
"text": quote_text,
"author": author,
"tradition": tradition,
"theme": theme,
"generated_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}
# Save the quote to a file
filename = f"quote_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
file_path = os.path.join(QUOTES_DIR, filename)
try:
with open(file_path, 'w') as f:
json.dump(result, f, indent=4)
log_message(f"✨ Generated quote saved at {file_path}")
logger.info(f"Quote saved successfully at: {file_path}")
except Exception as e:
log_message(f"❌ Failed to save quote to file: {str(e)}", "error")
logger.error(f"Error saving quote: {str(e)}")
return result
except Exception as e:
log_message(f"❌ Quote generation failed: {str(e)}")
return self._get_fallback_quote()
def generate_image(self, quote, tradition, theme):
try:
log_message("🎨 Starting image generation")
style_prompts = {
"Buddhism": "zen minimalism, misty mountains, lotus flowers",
"Hinduism": "mandala patterns, sacred geometry, vibrant cosmos",
"Taoism": "flowing water, yin-yang harmony, natural elements",
"default": "serene minimalism, sacred geometry, natural elements"
}
style = style_prompts.get(tradition, style_prompts["default"])
prompt = f"""Create a spiritual and contemplative image inspired by this theme: '{theme}'
Style inspiration: {style}
Mood: serene, inspiring, contemplative
Requirements: Suitable for Instagram, space for text overlay, balanced composition"""
response = self.openai_client.images.generate(
model="dall-e-3",
prompt=prompt,
size="1024x1024",
quality="standard",
n=1
)
image_url = response.data[0].url
# Download and save the generated image
image_response = requests.get(image_url)
if image_response.status_code == 200:
filename = f"image_{datetime.now().strftime('%Y%m%d_%H%M%S')}.jpg"
file_path = os.path.join(IMAGES_DIR, filename)
try:
with open(file_path, 'wb') as f:
f.write(image_response.content)
log_message(f"✨ Image generated and saved at {file_path}")
logger.info(f"Image saved successfully at: {file_path}")
except Exception as e:
log_message(f"❌ Failed to save image to file: {str(e)}", "error")
logger.error(f"Error saving image: {str(e)}")
else:
raise Exception("Failed to download image")
return image_url
except Exception as e:
log_message(f"❌ Image generation failed: {str(e)}", "error")
logger.error(f"Image generation failed: {str(e)}")
raise
def generate_audio(self, tradition, theme):
try:
log_message("🎡 Starting audio generation")
music_prompts = {
"Buddhism": "Tibetan singing bowls and gentle bells with peaceful ambient drones",
"Hinduism": "Indian bansuri flute with gentle tabla rhythms",
"Modern Spirituality": "Ambient synthesizer with crystal bowls",
"default": "Peaceful ambient music with gentle bells"
}
prompt = music_prompts.get(tradition, music_prompts["default"])
output = self.replicate_client.run(
"meta/musicgen:671ac645ce5e552cc63a54a2bbff63fcf798043055d2dac5fc9e36a837eedcfb",
input={
"prompt": prompt,
"model_version": "stereo-large",
"output_format": "mp3",
"duration": 15
}
)
audio_url = output if isinstance(output, str) else str(output)
# Download and save the generated music
music_response = requests.get(audio_url)
if music_response.status_code == 200:
filename = f"music_{datetime.now().strftime('%Y%m%d_%H%M%S')}.mp3"
file_path = os.path.join(MUSIC_DIR, filename)
try:
with open(file_path, 'wb') as f:
f.write(music_response.content)
log_message(f"✨ Music generated and saved at {file_path}")
logger.info(f"Music saved successfully at: {file_path}")
except Exception as e:
log_message(f"❌ Failed to save music to file: {str(e)}", "error")
logger.error(f"Error saving music: {str(e)}")
else:
raise Exception("Failed to download audio")
return audio_url
except Exception as e:
log_message(f"❌ Music generation failed: {str(e)}", "error")
logger.error(f"Music generation failed: {str(e)}")
raise
def create_image_with_quote(self, image_url, quote_text, author):
try:
response = requests.get(image_url)
img = Image.open(BytesIO(response.content))
width, height = img.size
# Create blank image for text overlay
txt = Image.new('RGBA', (width, height), (255, 255, 255, 0))
d = ImageDraw.Draw(txt)
# Semi-transparent background for text
d.rectangle([0, height / 2 - 100, width, height / 2 + 100], fill=(0, 0, 0, 127))
try:
quote_font = ImageFont.truetype("DejaVuSans-Bold", 40)
author_font = ImageFont.truetype("DejaVuSans", 30)
except:
quote_font = author_font = ImageFont.load_default()
# Word wrap the quote text
max_width = width - 40 # Leave some padding on both sides
lines = textwrap.wrap(quote_text, width=40)
# Draw each line of the wrapped text
y_offset = height / 2 - 100 # Starting Y position for the quote
for line in lines:
# Calculate the text size using textbbox
bbox = d.textbbox((0, 0), line, font=quote_font)
line_width = bbox[2] - bbox[0]
line_height = bbox[3] - bbox[1]
x_position = (width - line_width) / 2 # Center the line horizontally
d.text((x_position, y_offset), line, font=quote_font, fill=(255, 255, 255, 255))
y_offset += line_height + 5 # Move to the next line, with a small line gap
# Draw the author text below the quote
author_y_position = y_offset + 20 # Leave some space below the quote for the author
author_text = f"- {author}"
author_bbox = d.textbbox((0, 0), author_text, font=author_font)
author_width = author_bbox[2] - author_bbox[0]
author_x_position = (width - author_width) / 2
d.text((author_x_position, author_y_position), author_text, font=author_font, fill=(255, 255, 255, 255))
# Combine the original image with the overlay
out = Image.alpha_composite(img.convert('RGBA'), txt)
# Convert the image to bytes and save to a file
buffer = BytesIO()
out.convert('RGB').save(buffer, format='JPEG')
final_image_bytes = buffer.getvalue()
filename = f"final_image_{datetime.now().strftime('%Y%m%d_%H%M%S')}.jpg"
file_path = os.path.join(FINAL_IMAGES_DIR, filename)
try:
with open(file_path, 'wb') as f:
f.write(final_image_bytes)
log_message(f"✨ Final image saved at {file_path}")
logger.info(f"Final image saved successfully at: {file_path}")
except Exception as e:
log_message(f"❌ Failed to save final image to file: {str(e)}", "error")
logger.error(f"Error saving final image: {str(e)}")
return final_image_bytes
except Exception as e:
log_message(f"Error creating overlay: {str(e)}", "error")
logger.error(f"Error creating image with quote: {str(e)}")
return None
def generate_hashtags(tradition, theme):
base_tags = ["#spirituality", "#mindfulness", "#wisdom", "#inspiration"]
tradition_tags = {
"Buddhism": ["#buddhism", "#zen", "#buddhist"],
"Hinduism": ["#hinduism", "#vedanta", "#yoga"],
"Taoism": ["#taoism", "#tao", "#balance"],
"Modern Spirituality": ["#spiritual", "#awakening", "#growth"]
}
theme_tags = {
"Inner Peace": ["#peace", "#calm", "#serenity"],
"Mindfulness": ["#mindful", "#present", "#awareness"],
"Wisdom": ["#wisdom", "#truth", "#knowledge"]
}
custom_tags = tradition_tags.get(tradition, []) + theme_tags.get(theme, [])
return list(set(base_tags + custom_tags))[:10]
def main():
st.set_page_config(page_title="Spiritual Content Generator", page_icon="πŸ•‰οΈ", layout="wide")
# Initialize session states
if 'process_logs' not in st.session_state:
st.session_state.process_logs = []
for state_var in ['generated_content', 'generated_image', 'generated_audio']:
if state_var not in st.session_state:
st.session_state[state_var] = None
if not all(key in st.secrets for key in ['OPENAI_API_KEY', 'REPLICATE_API_TOKEN']):
st.error("Missing API keys in secrets!")
st.stop()
# Create columns for content and debug log
col1, col2 = st.columns([2, 1])
with col1:
st.title("πŸ•‰οΈ Spiritual Content Generator")
generator = ContentGenerator(st.secrets["OPENAI_API_KEY"], st.secrets["REPLICATE_API_TOKEN"])
# Step 1: Generate Quote
if st.button("Generate Quote"):
try:
quote_data = generator.generate_quote()
st.session_state.generated_content = quote_data
st.success("✨ Quote generated!")
st.json(quote_data)
except Exception as e:
st.error(f"Error generating quote: {str(e)}")
# Step 2: Create Image with Quote
if st.session_state.generated_content and st.button("Create Image"):
try:
image_url = generator.generate_image(
st.session_state.generated_content["text"],
st.session_state.generated_content["tradition"],
st.session_state.generated_content["theme"]
)
st.session_state.generated_image = image_url
st.success("✨ Image created!")
st.image(image_url)
except Exception as e:
st.error(f"Error generating image: {str(e)}")
# Step 3: Generate Music
if st.session_state.generated_content and st.button("Generate Music"):
try:
audio_url = generator.generate_audio(
st.session_state.generated_content["tradition"],
st.session_state.generated_content["theme"]
)
st.session_state.generated_audio = audio_url
st.success("✨ Music generated!")
audio_response = requests.get(audio_url)
if audio_response.status_code == 200:
st.audio(audio_response.content, format='audio/mp3')
except Exception as e:
st.error(f"Error generating audio: {str(e)}")
# Step 4: Preview Quote on Image
if st.session_state.generated_content and st.session_state.generated_image:
st.subheader("Final Preview")
final_image = generator.create_image_with_quote(
st.session_state.generated_image,
st.session_state.generated_content['text'],
st.session_state.generated_content['author']
)
if final_image:
st.image(final_image)
st.download_button("πŸ“₯ Download Image", final_image,
"spiritual_quote.jpg", "image/jpeg")
# Generate Instagram Caption
hashtags = generate_hashtags(
st.session_state.generated_content['tradition'],
st.session_state.generated_content.get('theme', 'Wisdom')
)
caption = f"""✨ Wisdom from {st.session_state.generated_content['tradition']} ✨
"{st.session_state.generated_content['text']}"
- {st.session_state.generated_content['author']}
{' '.join(hashtags)}"""
st.text_area("Instagram Caption", caption, height=200)
# Live debug log
with col2:
st.markdown("### πŸ” Live Debug Log")
placeholder = st.empty()
def update_logs():
with placeholder.container():
for log in st.session_state.process_logs:
if log["type"] == "error":
st.error(f"{log['timestamp']} - {log['message']}")
else:
st.info(f"{log['timestamp']} - {log['message']}")
update_logs()
if __name__ == "__main__":
main()