Spaces:
Running
Running
""" | |
π The Content Creator's Journey (AI-Powered Edition) | |
================================================== | |
This version replaces all mocked functions with real generative AI models | |
for image analysis, content generation, and translation. | |
- Stage 1: Inspiration Hub (Summarization AI) | |
- Stage 2: Creative Studio (Image-to-Text and Text Generation AI) | |
- Stage 3: Globalization Suite (Translation AI) | |
Author: Gemini | |
Date: July 4, 2025 | |
""" | |
import os | |
import re | |
import gradio as gr | |
import arxiv | |
import nltk | |
from transformers import pipeline | |
from youtube_transcript_api import YouTubeTranscriptApi, NoTranscriptFound | |
from youtube_transcript_api.formatters import TextFormatter | |
from PIL import Image | |
# --- Model & Pipeline Setup (Lazy Loading) --- | |
# Dictionary to hold our models, loaded only when needed. | |
models = {} | |
def get_pipeline(task, model_name): | |
"""Initializes and returns a pipeline, caching it for reuse.""" | |
if model_name not in models: | |
print(f"π Initializing {task} pipeline with model {model_name}...") | |
models[model_name] = pipeline(task, model=model_name) | |
print(f"β {model_name} loaded.") | |
return models[model_name] | |
# --- Stage 1: The Spark (Inspiration Hub) --- | |
# This section already uses a real summarization model, so no changes are needed here. | |
# (Functions search_arxiv_papers and summarize_youtube_from_url are omitted for brevity but remain the same) | |
# ... (Previous code for Stage 1 remains here) ... | |
# --- Stage 2: The Craft (Creative Studio) --- | |
def analyze_image_with_ai(image: Image.Image) -> (str, dict): | |
"""Uses a real AI model to generate a description of the image.""" | |
captioner = get_pipeline("image-to-text", "Salesforce/blip-image-captioning-large") | |
description = captioner(image)[0]['generated_text'] | |
analysis = {"description": description} | |
report = ( | |
f"**π¨ AI Vision Analysis:**\n\n" | |
f"- **Image Content:** {description}" | |
) | |
return report, analysis | |
def generate_creative_content_with_ai(style: str, audience: str, image_analysis: dict, custom_prompt: str) -> (str, str): | |
"""Uses a real LLM to generate content based on a detailed prompt.""" | |
generator = get_pipeline("text-generation", "gpt2") | |
image_desc = image_analysis.get("description", "a visual scene") | |
# Create a detailed prompt for the LLM | |
prompt = ( | |
f"Create a '{style}' for a '{audience}' audience. " | |
f"The content should be inspired by the following scene: '{image_desc}'. " | |
f"Follow this specific instruction: '{custom_prompt if custom_prompt else 'Be creative and engaging'}'.\n\n" | |
f"Here is the content:" | |
) | |
# Generate text and clean it up | |
generated_outputs = generator(prompt, max_length=150, num_return_sequences=1, pad_token_id=generator.tokenizer.eos_token_id) | |
generated_text = generated_outputs[0]['generated_text'] | |
# Clean the output by removing the initial prompt | |
clean_text = generated_text.replace(prompt, "").strip() | |
# The analytics are now informational rather than predictive | |
analytics_report = ( | |
f"**π Generation Details:**\n\n" | |
f"- **Model Used:** gpt2\n" | |
f"- **Core Prompt:** Based on a photo of '{image_desc[:40]}...'" | |
) | |
return clean_text, analytics_report | |
def run_creative_studio(uploaded_image, style, audience, custom_prompt): | |
"""Interface function to run the full AI-powered 'Craft' stage.""" | |
if uploaded_image is None: | |
return "β Please upload an image.", "", "" | |
try: | |
image = uploaded_image | |
analysis_report, image_analysis = analyze_image_with_ai(image) | |
generated_text, analytics = generate_creative_content_with_ai(style, audience, image_analysis, custom_prompt) | |
return analysis_report, generated_text, analytics | |
except Exception as e: | |
return f"β οΈ Error: {e}", "", "" | |
# --- Stage 3: The Reach (Globalization Suite) --- | |
def translate_content_with_ai(text: str, languages: list) -> str: | |
"""Translates content using real AI models.""" | |
if not text: | |
return "β Please provide text to translate." | |
if not languages: | |
return "β Please select at least one language." | |
lang_model_map = { | |
"German π©πͺ": "Helsinki-NLP/opus-mt-en-de", | |
"Spanish πͺπΈ": "Helsinki-NLP/opus-mt-en-es", | |
"Japanese π―π΅": "Helsinki-NLP/opus-mt-en-jap", | |
} | |
translations = [f"### π Translated Content\n"] | |
for lang_name in languages: | |
model_name = lang_model_map.get(lang_name) | |
if model_name: | |
translator = get_pipeline("translation", model_name) | |
translated_text = translator(text)[0]['translation_text'] | |
translations.append(f"**{lang_name.upper()} VERSION:**\n\n{translated_text}") | |
return "\n\n---\n\n".join(translations) | |
# --- Full Gradio UI --- | |
# The UI structure remains the same, but the functions it calls are now AI-powered. | |
# The code for create_ui(), search_arxiv_papers, and summarize_youtube_from_url is omitted here | |
# for brevity, as it doesn't change from the previous version. You can just plug the | |
# new functions above into your existing app.py file. | |
# --- Helper functions from previous version to make the file runnable --- | |
def search_arxiv_papers(topic: str) -> str: | |
if not topic: return "β Please enter a topic to search." | |
summarizer = get_pipeline("summarization", "sshleifer/distilbart-cnn-12-6") | |
search = arxiv.Search(query=topic, max_results=3, sort_by=arxiv.SortCriterion.Relevance) | |
results = [f"**π {res.title}**\n\n**Summary:** {summarizer(res.summary.replace(' ', ' '), max_length=80, min_length=20, do_sample=False)[0]['summary_text']}\n\n**π [Read Paper]({res.pdf_url})**" for res in search.results()] | |
return "\n\n---\n\n".join(results) if results else "No papers found." | |
def summarize_youtube_from_url(video_url: str) -> str: | |
if not video_url: return "β Please enter a YouTube URL." | |
video_id_match = re.search(r"(?:v=|\/)([0-9A-Za-z_-]{11}).*", video_url) | |
if not video_id_match: return "β Invalid YouTube URL." | |
video_id = video_id_match.group(1) | |
try: | |
transcript_list = YouTubeTranscriptApi.get_transcript(video_id) | |
transcript_text = " ".join([d['text'] for d in transcript_list]) | |
if len(transcript_text) < 200: return "Transcript too short." | |
summarizer = get_pipeline("summarization", "sshleifer/distilbart-cnn-12-6") | |
summary = summarizer(transcript_text, max_length=100, min_length=30, do_sample=False) | |
return f"**β Summary:**\n\n{summary[0]['summary_text']}" | |
except NoTranscriptFound: return "β No transcript available." | |
except Exception as e: return f"β οΈ Error: {e}" | |
def create_ui(): | |
css = """.gradio-container { font-family: 'Inter', sans-serif; background: #f5f7fa; } .tab-item { background: white; border-radius: 12px; padding: 25px; border: 1px solid #e0e0e0; } footer { display: none !important }""" | |
with gr.Blocks(theme=gr.themes.Base(), css=css, title="The Content Creator's Journey") as app: | |
gr.Markdown("""<div style="text-align: center; padding: 20px; background: #1f2937; color: white; border-radius: 12px;"><h1 style="font-size: 2.5em; margin: 0; font-weight: 700;">π The Content Creator's Journey</h1><p style="font-size: 1.2em; margin-top: 5px;">From a spark of an idea to a global message, in three stages.</p></div>""") | |
with gr.Tabs() as tabs: | |
with gr.TabItem("1. The Spark: Inspiration Hub", id=0, elem_classes=["tab-item"]): | |
gr.Markdown("### Every great creation starts with an idea. Research any topic to get summarized insights from academia and popular culture.") | |
with gr.Row(variant="panel"): | |
with gr.Column(min_width=400): | |
gr.Markdown("#### π¬ Academic Insights (from arXiv)") | |
inspire_topic = gr.Textbox(label="Enter a Topic to Search Papers", placeholder="e.g., 'sustainable technology'") | |
arxiv_btn = gr.Button("Search arXiv") | |
inspire_arxiv_output = gr.Markdown() | |
with gr.Column(min_width=400): | |
gr.Markdown("#### πΊ Video Insights (from YouTube URL)") | |
inspire_yt_url = gr.Textbox(label="Paste a YouTube Video URL", placeholder="e.g., 'https://www.youtube.com/watch?v=...'") | |
yt_btn = gr.Button("Summarize Video") | |
inspire_yt_output = gr.Markdown() | |
arxiv_btn.click(fn=search_arxiv_papers, inputs=inspire_topic, outputs=inspire_arxiv_output) | |
yt_btn.click(fn=summarize_youtube_from_url, inputs=inspire_yt_url, outputs=inspire_yt_output) | |
with gr.TabItem("2. The Craft: Creative Studio", id=1, elem_classes=["tab-item"]): | |
gr.Markdown("### Transform your idea into a polished piece of content. Upload a visual anchor and let the AI help you write.") | |
with gr.Row(variant="panel"): | |
with gr.Column(scale=1): | |
craft_image = gr.Image(label="πΌοΈ Upload a Visual Anchor", type="pil") | |
craft_style = gr.Dropdown(choices=["βοΈ Blog Post", "π¬ Social Media Caption", "π‘ Video Script Hook"], value="βοΈ Blog Post", label="π Content Format") | |
craft_audience = gr.Dropdown(choices=["π Experts", "π§ General Audience", "π©βπ» Tech Enthusiasts"], value="π§ General Audience", label="π₯ Target Audience") | |
craft_prompt = gr.Textbox(label="π Key Message or Note", placeholder="e.g., 'Focus on the human element...'") | |
craft_btn = gr.Button("π¨ Craft My Content") | |
with gr.Column(scale=2): | |
craft_analysis_output = gr.Markdown(label="AI Vision Analysis") | |
craft_text_output = gr.Textbox(label="βοΈ Generated Content", lines=10) | |
craft_analytics_output = gr.Markdown(label="Performance Analytics") | |
craft_btn.click(fn=run_creative_studio, inputs=[craft_image, craft_style, craft_audience, craft_prompt], outputs=[craft_analysis_output, craft_text_output, craft_analytics_output]) | |
with gr.TabItem("3. The Reach: Globalization Suite", id=2, elem_classes=["tab-item"]): | |
gr.Markdown("### Your masterpiece is ready. Now, adapt it for a global audience with our translation suite.") | |
with gr.Row(variant="panel"): | |
with gr.Column(scale=2): | |
reach_text_input = gr.Textbox(label="Paste Content Here (from Stage 2)", lines=8) | |
reach_lang_select = gr.CheckboxGroup(choices=["German π©πͺ", "Spanish πͺπΈ", "Japanese π―π΅"], label="π Select Languages") | |
reach_btn = gr.Button("π Globalize My Content") | |
with gr.Column(scale=3): | |
reach_output = gr.Markdown(label="Adapted for Global Audiences") | |
reach_btn.click(fn=translate_content_with_ai, inputs=[reach_text_input, reach_lang_select], outputs=reach_output) | |
return app | |
if __name__ == "__main__": | |
# To enable lazy loading of models, the UI is created first. | |
# The get_pipeline function will handle model loading upon first use. | |
app = create_ui() | |
app.launch(debug=True) |