Spaces:
Build error
Build error
File size: 18,508 Bytes
dad14a7 034005e dad14a7 dbd6d61 89c10f1 601b821 89c10f1 5b9b8a9 327fb20 80c56d2 601b821 f28ffa0 601b821 f28ffa0 034005e f28ffa0 034005e f28ffa0 99794e5 5b9b8a9 eca1131 5b9b8a9 eca1131 085e2ba 3d7449a 4f36ea4 3d7449a eca1131 3d7449a eca1131 3d7449a 19d7397 ed522c8 4f36ea4 ed522c8 4f36ea4 ed522c8 4f36ea4 eca1131 4f36ea4 f28ffa0 034005e f28ffa0 4f36ea4 ed522c8 eca1131 3d7449a eca1131 3d7449a f28ffa0 034005e f28ffa0 3d7449a 034005e 3d7449a 9fea641 53d4507 9fea641 80c56d2 9fea641 80c56d2 9fea641 eca1131 80c56d2 be8874d 80c56d2 be8874d 80c56d2 9fea641 80c56d2 f28ffa0 9fea641 f28ffa0 034005e f28ffa0 80c56d2 9fea641 034005e 9fea641 327fb20 b154f07 dad14a7 eca1131 62de772 4aef699 eca1131 89c10f1 eca1131 89c10f1 62de772 b5052bb 62de772 b5052bb eca1131 be8874d eca1131 be8874d 62de772 eca1131 be8874d 62de772 b5052bb 62de772 b5052bb 034005e be8874d 62de772 be8874d 9fea641 be8874d 9fea641 62de772 b399962 c84a31c be8874d 62de772 dad14a7 be8874d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 | 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()
|