|
|
import os |
|
|
import time |
|
|
import logging |
|
|
import gradio as gr |
|
|
|
|
|
logging.basicConfig(level=logging.INFO) |
|
|
logger = logging.getLogger(__name__) |
|
|
|
|
|
|
|
|
MODAL_AVAILABLE = False |
|
|
generate_content_with_llm = None |
|
|
|
|
|
try: |
|
|
import modal |
|
|
logger.info(f"Modal version: {modal.__version__}") |
|
|
|
|
|
|
|
|
modal_token_id = os.environ.get("MODAL_TOKEN_ID") |
|
|
modal_token_secret = os.environ.get("MODAL_TOKEN_SECRET") |
|
|
if modal_token_id and modal_token_secret: |
|
|
try: |
|
|
|
|
|
logger.info("π Attempting to connect to Modal functions...") |
|
|
|
|
|
|
|
|
try: |
|
|
generate_content_with_llm = modal.Function.from_name( |
|
|
"content-creation-agent", |
|
|
"generate_content_with_llm" |
|
|
) |
|
|
|
|
|
|
|
|
health_check_func = modal.Function.from_name( |
|
|
"content-creation-agent", |
|
|
"health_check" |
|
|
) |
|
|
|
|
|
|
|
|
test_result = health_check_func.remote() |
|
|
logger.info(f"β
Modal health check passed: {test_result}") |
|
|
|
|
|
MODAL_AVAILABLE = True |
|
|
logger.info("β
Modal successfully connected to main AI function") |
|
|
|
|
|
except Exception as e: |
|
|
logger.warning(f"β οΈ Modal main function connection failed: {e}") |
|
|
|
|
|
try: |
|
|
generate_content_with_llm = modal.Function.from_name( |
|
|
"content-creation-agent", |
|
|
"generate_fallback_content" |
|
|
) |
|
|
|
|
|
|
|
|
health_check_func = modal.Function.from_name( |
|
|
"content-creation-agent", |
|
|
"health_check" |
|
|
) |
|
|
test_result = health_check_func.remote() |
|
|
logger.info(f"β
Modal health check passed: {test_result}") |
|
|
|
|
|
MODAL_AVAILABLE = True |
|
|
logger.info("β
Modal connected using fallback function (still high quality!)") |
|
|
except Exception as e2: |
|
|
logger.warning(f"β οΈ Modal fallback also failed: {e2}") |
|
|
MODAL_AVAILABLE = False |
|
|
except Exception as main_e: |
|
|
logger.warning(f"β οΈ Modal connection failed: {main_e}") |
|
|
MODAL_AVAILABLE = False |
|
|
else: |
|
|
logger.warning("β οΈ MODAL_TOKEN_ID and MODAL_TOKEN_SECRET not found in environment variables") |
|
|
logger.info("π‘ To fix this, add MODAL_TOKEN_ID and MODAL_TOKEN_SECRET to your HuggingFace Space environment variables") |
|
|
|
|
|
|
|
|
except ImportError: |
|
|
logger.warning("β οΈ Modal package not available") |
|
|
except Exception as e: |
|
|
logger.warning(f"β οΈ Modal setup failed: {e}") |
|
|
|
|
|
logger.info(f"Modal Status: {'β
Available' if MODAL_AVAILABLE else 'β Unavailable'}") |
|
|
|
|
|
def generate_fallback_content(lyrics, artist, title): |
|
|
"""High-quality local content generation""" |
|
|
|
|
|
|
|
|
lyrics_lower = lyrics.lower() |
|
|
|
|
|
|
|
|
mood = "uplifting" |
|
|
if any(word in lyrics_lower for word in ['cry', 'tear', 'pain', 'hurt', 'lost', 'broken', 'sad', 'lonely', 'dark']): |
|
|
mood = "emotional" |
|
|
elif any(word in lyrics_lower for word in ['energy', 'power', 'fire', 'strong', 'fight', 'drive', 'force', 'intense']): |
|
|
mood = "energetic" |
|
|
elif any(word in lyrics_lower for word in ['love', 'happy', 'joy', 'hope', 'dream', 'light', 'beautiful', 'amazing']): |
|
|
mood = "inspiring" |
|
|
|
|
|
|
|
|
theme_words = [] |
|
|
if any(word in lyrics_lower for word in ['love', 'heart', 'romance', 'kiss', 'together']): |
|
|
theme_words.append('love') |
|
|
if any(word in lyrics_lower for word in ['dream', 'hope', 'future', 'tomorrow', 'vision']): |
|
|
theme_words.append('dreams') |
|
|
if any(word in lyrics_lower for word in ['night', 'dark', 'star', 'moon', 'midnight']): |
|
|
theme_words.append('night') |
|
|
if any(word in lyrics_lower for word in ['life', 'living', 'journey', 'path', 'way']): |
|
|
theme_words.append('life') |
|
|
if any(word in lyrics_lower for word in ['freedom', 'free', 'escape', 'break', 'liberation']): |
|
|
theme_words.append('freedom') |
|
|
if any(word in lyrics_lower for word in ['time', 'moment', 'forever', 'always', 'memory']): |
|
|
theme_words.append('time') |
|
|
|
|
|
themes_text = ', '.join(theme_words[:3]) if theme_words else 'deep emotions' |
|
|
|
|
|
|
|
|
genre = 'indie' |
|
|
if any(word in lyrics_lower for word in ['rock', 'guitar', 'band', 'drums', 'electric', 'amp']): |
|
|
genre = 'rock' |
|
|
elif any(word in lyrics_lower for word in ['pop', 'radio', 'catchy', 'dance', 'party', 'club']): |
|
|
genre = 'pop' |
|
|
elif any(word in lyrics_lower for word in ['rap', 'flow', 'beats', 'hip', 'street', 'rhyme']): |
|
|
genre = 'hiphop' |
|
|
elif any(word in lyrics_lower for word in ['electronic', 'synth', 'edm', 'techno', 'digital']): |
|
|
genre = 'electronic' |
|
|
elif any(word in lyrics_lower for word in ['acoustic', 'folk', 'country', 'traditional']): |
|
|
genre = 'acoustic' |
|
|
|
|
|
|
|
|
base_hashtags = { |
|
|
'youtube': [f'{genre}music', 'newmusic', 'musicvideo', f'{mood}music', 'originalmusic', 'independentartist', 'songwriter', 'musicdiscovery', 'viral', 'subscribe', 'newrelease', 'musicproducer', 'instamusic', 'unsignedartist', 'emergingartist'], |
|
|
'twitter': [f'{genre}', 'newmusic', 'nowplaying', f'{mood}', 'musicvideo', 'viral'], |
|
|
'instagram': [f'{genre}vibes', 'newmusic', 'instamusic', f'{mood}', 'musicpost', 'originalmusic', 'artist', 'viral', 'trending', 'musiclover', 'songwriter', 'independentartist', 'newrelease', 'musicdiscovery', 'vibes'], |
|
|
'facebook': [f'{genre}music', 'newmusic', 'originalmusic', f'{mood}', 'musicvideo', 'viral'], |
|
|
'minds': ['independentmusic', 'originalmusic', 'newmusic', 'creative', 'authentic'], |
|
|
'gab': ['originalmusic', 'independent', 'authentic', 'realmusic', 'newmusic'] |
|
|
} |
|
|
|
|
|
|
|
|
for platform in base_hashtags: |
|
|
for theme in theme_words[:2]: |
|
|
base_hashtags[platform].append(f'{theme}music') |
|
|
|
|
|
|
|
|
hashtags = {} |
|
|
limits = {'youtube': 15, 'instagram': 15, 'twitter': 6, 'facebook': 6, 'minds': 5, 'gab': 5} |
|
|
|
|
|
for platform, tags in base_hashtags.items(): |
|
|
limit = limits.get(platform, 10) |
|
|
formatted_tags = ' '.join(f'#{tag}' for tag in tags[:limit]) |
|
|
hashtags[platform] = formatted_tags |
|
|
|
|
|
artist_display = artist if artist.strip() else "Anonymous Artist" |
|
|
by_artist = f" - {artist_display}" if artist.strip() else "" |
|
|
|
|
|
if artist.strip(): |
|
|
|
|
|
return { |
|
|
'youtube': f"""π΅ {title}{by_artist} π΅ |
|
|
|
|
|
Experience this latest music video! This {mood} track explores themes of {themes_text}. |
|
|
|
|
|
π¬ Watch the full music video above |
|
|
πΏ Stream on all platforms |
|
|
π Subscribe for more music videos |
|
|
π Like if you enjoyed this track |
|
|
|
|
|
π LYRICS: |
|
|
{lyrics} |
|
|
|
|
|
{hashtags['youtube']}""", |
|
|
|
|
|
'twitter': f"π΅ NEW MUSIC VIDEO: '{title}'{by_artist} is here! This {mood} track will give you all the feels π«\n\nπ¬ Watch: [Link]\n\n{hashtags['twitter']}", |
|
|
|
|
|
'instagram': f"""π΅β¨ '{title}' Official Music Video is LIVE! β¨π΅ |
|
|
|
|
|
{artist_display} delivers another {mood} masterpiece that speaks to the soul π« |
|
|
|
|
|
π¬ Full video in bio |
|
|
π What's your favorite lyric? Comment below! |
|
|
|
|
|
{hashtags['instagram']}""", |
|
|
|
|
|
'facebook': f"""π΅ MUSIC VIDEO PREMIERE π΅ |
|
|
|
|
|
New music video for '{title}'{by_artist} just dropped! |
|
|
|
|
|
This {mood} track captures the essence of {themes_text} in a beautiful way. The visuals perfectly complement the powerful lyrics. |
|
|
|
|
|
π¬ Watch the full video now! |
|
|
π¬ Let us know what you think in the comments |
|
|
π Share with friends who love good music |
|
|
|
|
|
{hashtags['facebook']}""", |
|
|
|
|
|
'minds': f"""π΅ New Music Alert! |
|
|
|
|
|
{artist_display} - '{title}' Official Music Video |
|
|
|
|
|
This {mood} track showcases incredible artistry and meaningful lyrics. Independent artists like {artist_display} are creating the future of music. |
|
|
|
|
|
Support independent music and check out this latest release! |
|
|
|
|
|
{hashtags['minds']}""", |
|
|
|
|
|
'gab': f"""New Music Video Drop! |
|
|
|
|
|
'{title}'{by_artist} |
|
|
|
|
|
Real music with real meaning. This {mood} track reminds us why authentic artistry matters in today's world. |
|
|
|
|
|
Give it a listen and support independent creators! |
|
|
|
|
|
{hashtags['gab']}""" |
|
|
} |
|
|
else: |
|
|
|
|
|
return { |
|
|
'youtube': f"""π΅ {title} π΅ |
|
|
|
|
|
Experience this captivating music video! This {mood} track explores themes of {themes_text}. |
|
|
|
|
|
π¬ Watch the full music video above |
|
|
πΏ Available on all streaming platforms |
|
|
π Subscribe for more amazing music videos |
|
|
π Like if this track moved you |
|
|
|
|
|
π LYRICS: |
|
|
{lyrics} |
|
|
|
|
|
{hashtags['youtube']}""", |
|
|
|
|
|
'twitter': f"π΅ NEW MUSIC VIDEO: '{title}' is here! This {mood} track will give you all the feels π«\n\nπ¬ Watch: [Link]\n\n{hashtags['twitter']}", |
|
|
|
|
|
'instagram': f"""π΅β¨ '{title}' Official Music Video is LIVE! β¨π΅ |
|
|
|
|
|
Another {mood} masterpiece that speaks to the soul π« |
|
|
|
|
|
π¬ Full video in bio |
|
|
π What's your favorite lyric? Comment below! |
|
|
|
|
|
{hashtags['instagram']}""", |
|
|
|
|
|
'facebook': f"""π΅ MUSIC VIDEO PREMIERE π΅ |
|
|
|
|
|
'{title}' official music video just dropped! |
|
|
|
|
|
This {mood} track captures the essence of {themes_text} in a beautiful way. The visuals perfectly complement the powerful lyrics. |
|
|
|
|
|
π¬ Watch the full video now! |
|
|
π¬ Let us know what you think in the comments |
|
|
π Share with friends who love good music |
|
|
|
|
|
{hashtags['facebook']}""", |
|
|
|
|
|
'minds': f"""π΅ New Music Alert! |
|
|
|
|
|
'{title}' Official Music Video |
|
|
|
|
|
This {mood} track showcases incredible artistry and meaningful lyrics. Independent music continues to push creative boundaries. |
|
|
|
|
|
Support independent music and check out this latest release! |
|
|
|
|
|
{hashtags['minds']}""", |
|
|
|
|
|
'gab': f"""New Music Video Drop! |
|
|
|
|
|
'{title}' |
|
|
|
|
|
Real music with real meaning. This {mood} track reminds us why authentic artistry matters in today's world. |
|
|
|
|
|
Give it a listen and support independent creators! |
|
|
|
|
|
{hashtags['gab']}""" |
|
|
} |
|
|
|
|
|
def generate_all_content(lyrics, artist, title, use_modal): |
|
|
"""Generate content with Modal toggle""" |
|
|
if not lyrics.strip() or not title.strip(): |
|
|
error_msg = "β Please provide both lyrics and song title" |
|
|
return [""] * 6 + [error_msg] |
|
|
|
|
|
start_time = time.time() |
|
|
|
|
|
|
|
|
empty_outputs = [""] * 6 |
|
|
if use_modal and MODAL_AVAILABLE: |
|
|
status_msg = "β³ Generating content with Modal AI..." |
|
|
else: |
|
|
status_msg = "β³ Generating content with local templates..." |
|
|
yield empty_outputs + [status_msg] |
|
|
|
|
|
try: |
|
|
if use_modal and MODAL_AVAILABLE and generate_content_with_llm: |
|
|
|
|
|
try: |
|
|
logger.info("π Attempting Modal AI generation...") |
|
|
result = generate_content_with_llm.remote(lyrics, artist, title) |
|
|
|
|
|
|
|
|
if isinstance(result, dict) and len(result) > 0: |
|
|
content = result |
|
|
status_msg = f"β
Generated with Modal AI in {time.time() - start_time:.2f}s" |
|
|
logger.info("β
Modal AI generation successful") |
|
|
else: |
|
|
raise ValueError("Invalid result from Modal function") |
|
|
|
|
|
except Exception as modal_error: |
|
|
logger.warning(f"β οΈ Modal AI generation failed: {modal_error}") |
|
|
|
|
|
content = generate_fallback_content(lyrics, artist, title) |
|
|
status_msg = f"β οΈ Modal failed, used local fallback in {time.time() - start_time:.2f}s" |
|
|
else: |
|
|
|
|
|
if use_modal and not MODAL_AVAILABLE: |
|
|
status_msg = "β οΈ Modal unavailable, using local generation..." |
|
|
content = generate_fallback_content(lyrics, artist, title) |
|
|
if not (use_modal and not MODAL_AVAILABLE): |
|
|
status_msg = f"β
Generated with local templates in {time.time() - start_time:.2f}s" |
|
|
|
|
|
except Exception as e: |
|
|
logger.error(f"β Unexpected error: {e}") |
|
|
content = generate_fallback_content(lyrics, artist, title) |
|
|
status_msg = f"β Error occurred, used local fallback in {time.time() - start_time:.2f}s" |
|
|
|
|
|
|
|
|
platforms = ['youtube', 'twitter', 'instagram', 'facebook', 'minds', 'gab'] |
|
|
platform_outputs = [content.get(platform, f"Error generating {platform} content") for platform in platforms] |
|
|
yield platform_outputs + [status_msg] |
|
|
|
|
|
|
|
|
with gr.Blocks(theme=gr.themes.Soft(), title="π΅ Music Content Creator") as demo: |
|
|
gr.Markdown(f""" |
|
|
# π΅ AI Content Generator for Musicians π¬ |
|
|
|
|
|
Transform your song lyrics into compelling social media content! |
|
|
|
|
|
**β¨ Features:** |
|
|
- π€ AI-powered content generation (when Modal is available) |
|
|
- π± Platform-optimized content for YouTube, Twitter, Instagram, Facebook, Minds, and Gab |
|
|
- π― Smart hashtag generation based on lyrics analysis |
|
|
- π€ Support for both named artists and anonymous releases |
|
|
|
|
|
**π§ Backend Status:** {"π’ Modal Available" if MODAL_AVAILABLE else "π‘ Local Mode Only"} |
|
|
|
|
|
{"" if MODAL_AVAILABLE else "π‘ **To enable AI generation:** Add your Modal token to the HuggingFace Space environment variables"} |
|
|
""") |
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(scale=2): |
|
|
lyrics_input = gr.Textbox( |
|
|
lines=8, |
|
|
label="π΅ Song Lyrics", |
|
|
placeholder="Enter your complete song lyrics here...", |
|
|
info="Paste the full lyrics of your song" |
|
|
) |
|
|
with gr.Column(scale=1): |
|
|
artist_input = gr.Textbox( |
|
|
label="π€ Artist Name", |
|
|
placeholder="Artist Name (Optional)", |
|
|
info="Leave blank for anonymous releases" |
|
|
) |
|
|
title_input = gr.Textbox( |
|
|
label="π΅ Song Title", |
|
|
placeholder="Song Title", |
|
|
info="The title of your song" |
|
|
) |
|
|
|
|
|
|
|
|
modal_toggle = gr.Radio( |
|
|
choices=[ |
|
|
("π€ AI Generation (Modal)", True), |
|
|
("π Local Templates", False) |
|
|
], |
|
|
value=MODAL_AVAILABLE, |
|
|
label="Generation Method", |
|
|
info="Choose between AI-powered generation or local templates" |
|
|
) |
|
|
|
|
|
run_button = gr.Button("π Generate Content", variant="primary", size="lg") |
|
|
|
|
|
gr.Markdown("## π± Generated Social Media Content") |
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(): |
|
|
youtube_output = gr.Textbox(label="πΊ YouTube Description", lines=12) |
|
|
twitter_output = gr.Textbox(label="π¦ Twitter/X Post", lines=4) |
|
|
instagram_output = gr.Textbox(label="πΈ Instagram Caption", lines=6) |
|
|
with gr.Column(): |
|
|
facebook_output = gr.Textbox(label="π Facebook Post", lines=6) |
|
|
minds_output = gr.Textbox(label="π§ Minds Post", lines=4) |
|
|
gab_output = gr.Textbox(label="π¬ Gab Post", lines=4) |
|
|
|
|
|
status = gr.Markdown("Ready to generate content!") |
|
|
|
|
|
|
|
|
run_button.click( |
|
|
fn=generate_all_content, |
|
|
inputs=[lyrics_input, artist_input, title_input, modal_toggle], |
|
|
outputs=[youtube_output, twitter_output, instagram_output, facebook_output, minds_output, gab_output, status] |
|
|
) |
|
|
|
|
|
|
|
|
gr.Examples( |
|
|
examples=[ |
|
|
[ |
|
|
"Here's an example with some sample lyrics\nAbout dreams and aspirations\nReaching for the stars tonight\nNothing's gonna stop this fight\nWe'll keep on climbing higher\nUntil we touch the sky", |
|
|
"", |
|
|
"Dreams Tonight", |
|
|
MODAL_AVAILABLE |
|
|
], |
|
|
[ |
|
|
"Love is in the air tonight\nHearts beating as one\nDancing under moonlight\nUntil the morning sun\nThis feeling never ends\nLove conquers all", |
|
|
"Romantic Vibes", |
|
|
"Moonlight Dance", |
|
|
False |
|
|
] |
|
|
], |
|
|
inputs=[lyrics_input, artist_input, title_input, modal_toggle], |
|
|
label="π‘ Try these examples" |
|
|
) |
|
|
|
|
|
|
|
|
gr.Markdown(f""" |
|
|
--- |
|
|
**π‘ Tips:** |
|
|
- **AI Generation:** Uses GPT-2 on Modal for creative, context-aware content |
|
|
- **Local Templates:** Fast, rule-based generation that always works |
|
|
- **Modal Credits:** Can be used for LLM inference and GPU-intensive functions ([Modal Docs](https://modal.com/docs)) |
|
|
- **Best Results:** Include rich, descriptive lyrics for better theme detection |
|
|
|
|
|
**π§ Status:** {"β
Modal Working" if MODAL_AVAILABLE else "π‘ Local Mode Only"} |
|
|
|
|
|
{"" if MODAL_AVAILABLE else "**To enable Modal AI:** Add MODAL_TOKEN to your HuggingFace Space environment variables"} |
|
|
""") |
|
|
|
|
|
if __name__ == "__main__": |
|
|
demo.launch() |