Insta_auto / app.py
cryogenic22's picture
Update app.py
034005e verified
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()