Spaces:
Runtime error
Runtime error
Download app.py from bradcharl14/AutoContentForge-AI: direct link, hf CLI and curl.
- Browser
- Download file 14 kB
-
https://huggingface.co/spaces/bradcharl14/AutoContentForge-AI/resolve/main/app.py
- Command line
-
hf download hf://spaces/bradcharl14/AutoContentForge-AI/app.py
-
curl -L -o app.py https://huggingface.co/spaces/bradcharl14/AutoContentForge-AI/resolve/main/app.py
14 kB
| import os | |
| import warnings | |
| import logging | |
| # Suppress technical initialization warnings from Torch/Transformers/HF | |
| os.environ["TORCH_LOGS"] = "-all" | |
| os.environ["TORCH_CPP_LOG_LEVEL"] = "3" | |
| os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3" | |
| os.environ["HUGGINGFACE_HUB_VERBOSITY"] = "error" | |
| warnings.filterwarnings("ignore", message=".*torch.classes.*") | |
| logging.getLogger("torch").setLevel(logging.ERROR) | |
| import streamlit as st | |
| # Page Config must be first Streamlit command | |
| st.set_page_config( | |
| page_title="AutoContentForge AI", | |
| page_icon="⚒️", | |
| layout="wide", | |
| initial_sidebar_state="expanded", | |
| ) | |
| from streamlit_calendar import calendar | |
| from forge_utils import ContentExtractor, ForgeAI | |
| # Initialize ForgeAI with caching | |
| def get_forge(): | |
| return ForgeAI() | |
| forge = get_forge() | |
| # Session State for Content | |
| if 'forge_results' not in st.session_state: | |
| st.session_state.forge_results = None | |
| if 'extracted_content' not in st.session_state: | |
| st.session_state.extracted_content = None | |
| # Custom CSS for Premium Look | |
| st.markdown(""" | |
| <style> | |
| /* Global Text Color */ | |
| .stApp { | |
| color: #ffffff; | |
| } | |
| .main { | |
| background-color: #0e1117; | |
| color: #ffffff; | |
| } | |
| p, span, label, h1, h2, h3, h4, h5, h6 { | |
| color: #ffffff !important; | |
| } | |
| /* Sidebar Carbon Black */ | |
| [data-testid="stSidebar"] { | |
| background-color: #1a1c1e; | |
| border-right: 1px solid rgba(255, 255, 255, 0.05); | |
| } | |
| /* Global Button Styling - Force Red */ | |
| button, [data-testid="stBaseButton-secondary"], [data-testid="stBaseButton-primary"] { | |
| background-color: #4A4A4A !important; | |
| color: white !important; | |
| border: none !important; | |
| border-radius: 6px !important; | |
| transition: all 0.3s ease !important; | |
| } | |
| button:hover, [data-testid="stBaseButton-secondary"]:hover, [data-testid="stBaseButton-primary"]:hover { | |
| background-color: #4A4A4A !important; | |
| transform: translateY(-1px) !important; | |
| box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1) !important; | |
| color: white !important; | |
| } | |
| button:active { | |
| background-color: #991b1b !important; | |
| transform: translateY(0px) !important; | |
| } | |
| /* Fix Help Tooltips (Black text on white background) */ | |
| div[data-testid="stTooltipContent"] { | |
| background-color: #ffffff !important; | |
| color: #000000 !important; | |
| border: 1px solid #ddd !important; | |
| } | |
| div[data-testid="stTooltipContent"] p { | |
| color: #000000 !important; | |
| } | |
| /* Ensure help icons themselves are visible */ | |
| [data-testid="stWidgetLabel"] .st-at { | |
| color: #4A4A4A !important; | |
| } | |
| /* Tab and other refinements */ | |
| .stTabs [data-baseweb="tab-list"] { | |
| gap: 24px; | |
| background-color: transparent; | |
| } | |
| .stTabs [data-baseweb="tab"] { | |
| height: 50px; | |
| white-space: pre-wrap; | |
| background-color: #1a1c24; | |
| border-radius: 4px 4px 0px 0px; | |
| color: #ffffff !important; | |
| font-size: 16px; | |
| font-weight: 500; | |
| padding: 10px 20px; | |
| } | |
| .stTabs [aria-selected="true"] { | |
| background-color: #6d28d9 !important; | |
| border-bottom: 2px solid #8b5cf6 !important; | |
| } | |
| .pro-glass-card { | |
| background: rgba(255, 255, 255, 0.05); | |
| backdrop-filter: blur(10px); | |
| border: 1px solid rgba(255, 255, 255, 0.1); | |
| border-radius: 12px; | |
| padding: 20px; | |
| margin-bottom: 20px; | |
| color: #ffffff; | |
| } | |
| .platform-card { | |
| background: #1a1c24; | |
| border-left: 5px solid #6d28d9; | |
| padding: 15px; | |
| border-radius: 8px; | |
| margin-bottom: 10px; | |
| color: #ffffff; | |
| } | |
| .sidebar-pro-cta { | |
| background: linear-gradient(135deg, #6d28d9, #305CDE); | |
| color: white !important; | |
| padding: 15px; | |
| border-radius: 8px; | |
| text-align: center; | |
| margin-bottom: 20px; | |
| } | |
| .sidebar-pro-cta small, .sidebar-pro-cta strong { | |
| color: white !important; | |
| } | |
| </style> | |
| """, unsafe_allow_html=True) | |
| # Sidebar Branding & Pro CTA | |
| with st.sidebar: | |
| st.title("⚒️ AutoContentForge AI") | |
| st.caption("Automate Your Content. Forge Every Platform.") | |
| st.markdown("---") | |
| st.markdown(""" | |
| <div class="sidebar-pro-cta"> | |
| <strong>🚀 Upgrade to Pro</strong><br> | |
| <small>Self-Hosted Docker Version</small><br> | |
| <br> | |
| • Direct Social Posting<br> | |
| • Full Bulk Scheduling<br> | |
| • Video Automation<br> | |
| • Google Docs sync | |
| </div> | |
| """, unsafe_allow_html=True) | |
| if st.button("Contact for Pro Version", use_container_width=True): | |
| st.info("Email: rajue@smackcoders.com with subject 'AutoContentForge AI Pro Inquiry'") | |
| st.markdown("---") | |
| st.markdown("### Resources") | |
| st.markdown("[Documentation](#)") | |
| st.markdown("[Pricing](#)") | |
| st.markdown("[YouTube Channel](#)") | |
| # Main Navigation Tabs | |
| tab1, tab2, tab3 = st.tabs([ | |
| "📝 Single Post", | |
| "📦 Bulk Posting", | |
| "⚙️ Admin Settings" | |
| ]) | |
| # Initialize session states for the new workflow | |
| if 'master_variations' not in st.session_state: | |
| st.session_state.master_variations = None | |
| if 'selected_variation' not in st.session_state: | |
| st.session_state.selected_variation = None | |
| if 'current_hashtags' not in st.session_state: | |
| st.session_state.current_hashtags = "" | |
| # Module 1: Single Post | |
| with tab1: | |
| st.header("📝 Create Single Social Post") | |
| st.write("Fetch from a URL or use the manual editor to forge your master variations.") | |
| col_in, col_out = st.columns([1, 1.2]) | |
| with col_in: | |
| st.subheader("1. Source Content") | |
| input_mode = st.radio( | |
| "Input Mode", | |
| ["URL Fetch", "Manual Editor"], | |
| horizontal=True, | |
| help="Choose 'URL Fetch' to extract content from a website, or 'Manual Editor' to paste your own text directly." | |
| ) | |
| if input_mode == "URL Fetch": | |
| source_url = st.text_input( | |
| "Enter Content URL", | |
| placeholder="https://example.com/blog-post", | |
| help="Paste the full link (including https://) of the article or blog post you want to repurpose." | |
| ) | |
| if st.button("🚀 Fetch & Analyze"): | |
| if not source_url or "://" not in source_url: | |
| st.error("Please enter a valid URL (including https://)") | |
| else: | |
| with st.spinner("Forging 3 master variations..."): | |
| extracted = ContentExtractor.from_url(source_url) | |
| if "error" in extracted: | |
| st.error(extracted["error"]) | |
| else: | |
| st.session_state.extracted_content = extracted | |
| st.session_state.master_variations = forge.generate_master_variations(extracted['text']) | |
| st.session_state.current_hashtags = forge.extract_hashtags(extracted['text']) | |
| st.session_state.selected_variation = None # Reset selection | |
| st.success("Successfully generated 3 variations!") | |
| else: | |
| pasted_title = st.text_input("Post Title (Optional)", help="Give your post a title for easier tracking.") | |
| pasted_text = st.text_area( | |
| "Master Content / Article Text", | |
| height=200, | |
| help="Paste the core content you want to turn into social posts. Aim for at least 50 words for the best AI results." | |
| ) | |
| if st.button("✨ Generate Variations"): | |
| if len(pasted_text) < 50: | |
| st.warning("Please provide more content for better AI results.") | |
| else: | |
| with st.spinner("Processing..."): | |
| st.session_state.extracted_content = {"title": pasted_title or "Manual Input", "text": pasted_text} | |
| st.session_state.master_variations = forge.generate_master_variations(pasted_text) | |
| st.session_state.current_hashtags = forge.extract_hashtags(pasted_text) | |
| st.session_state.selected_variation = None | |
| st.success("Variations generated!") | |
| if st.session_state.master_variations: | |
| st.markdown("---") | |
| st.subheader("2. Choose Master Variation") | |
| st.info("💡 **Tip:** Each variation has a different tone. Expand them to see which one fits your brand voice best.") | |
| for var in st.session_state.master_variations: | |
| with st.expander(f"🔹 {var['type']}", expanded=(st.session_state.selected_variation == var['id'])): | |
| st.write(var['text']) | |
| if st.button(f"Select {var['type']}", key=f"sel_{var['id']}", help=f"Choose the {var['type']} to be adapted for your social networks."): | |
| st.session_state.selected_variation = var['id'] | |
| st.rerun() | |
| with col_out: | |
| st.subheader("3. Preview & Adapt") | |
| if not st.session_state.selected_variation: | |
| st.info("Select a master variation on the left to see platform-specific previews.") | |
| else: | |
| selected_var_obj = next(v for v in st.session_state.master_variations if v['id'] == st.session_state.selected_variation) | |
| platforms = st.multiselect( | |
| "Select Social Networks", | |
| ["LinkedIn", "Twitter/X", "Instagram", "Facebook", "YouTube", "Bluesky"], | |
| default=["LinkedIn", "Twitter/X"], | |
| help="Choose which platforms you want to generate previews for. The AI will format your selected variation for each." | |
| ) | |
| if st.session_state.extracted_content.get("images"): | |
| st.image(st.session_state.extracted_content['images'][0], caption="Extracted Media", width=300) | |
| else: | |
| st.write("📸 *No media found. You can add media in the Pro version or manual editor.*") | |
| st.markdown("---") | |
| for platform in platforms: | |
| adapted_text = forge.adapt_for_platform(selected_var_obj['text'], platform, st.session_state.current_hashtags) | |
| with st.container(): | |
| st.markdown(f""" | |
| <div class="platform-card"> | |
| <strong>{platform} Preview</strong><br> | |
| <p style='font-size: 0.9em; color: #ccc;'> | |
| {adapted_text if isinstance(adapted_text, str) else adapted_text.get('title')} | |
| </p> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| if isinstance(adapted_text, dict) and platform == "YouTube": | |
| st.caption(f"Description: {adapted_text.get('description')}") | |
| if st.button("📅 Post / Schedule Now", type="primary"): | |
| st.success("✅ Successfully queued! (Flow simulation)") | |
| st.balloons() | |
| st.info("🔒 In Pro: This would instantly publish or sync to your drag-and-drop calendar.") | |
| # Module 2: Bulk Posting | |
| with tab2: | |
| st.header("📦 Bulk URL Posting") | |
| st.write("Forge content from multiple URLs at once. Perfect for content migration or high-volume publishing.") | |
| bulk_urls = st.text_area( | |
| "List of URLs (one per line)", | |
| height=250, | |
| placeholder="https://site.com/post-1\nhttps://site.com/post-2", | |
| help="Enter a list of blog post links. In the Pro version, the AI will process all of them in one batch." | |
| ) | |
| st.markdown(""" | |
| <div class="pro-glass-card"> | |
| <strong>Pro Feature Highlights:</strong><br> | |
| • Automatic batch processing of sitemaps<br> | |
| • Intelligent image matching for bulk lists<br> | |
| • Scheduled intervals (e.g., 1 post every 2 hours)<br> | |
| • CSV / JSON Export for external schedulers | |
| </div> | |
| """, unsafe_allow_html=True) | |
| st.button("🚀 Process Bulk List", disabled=True, help="This feature is exclusive to the Pro version.") | |
| st.markdown("---") | |
| if st.button("Unlock Bulk & Automation", key="bulk_pro", help="Contact us to upgrade to the full self-hosted version."): | |
| st.info("Email: rajue@smackcoders.com with subject 'AutoContentForge AI Pro Inquiry'") | |
| # Module 3: Admin Settings | |
| with tab3: | |
| st.header("⚙️ Admin Settings") | |
| st.write("Authorize and manage your social network connections.") | |
| networks = [ | |
| {"name": "LinkedIn", "icon": "👔"}, | |
| {"name": "Twitter/X", "icon": "🐦"}, | |
| {"name": "Instagram", "icon": "📸"}, | |
| {"name": "Facebook", "icon": "👥"}, | |
| {"name": "YouTube", "icon": "🎥"}, | |
| {"name": "Bluesky", "icon": "🦋"} | |
| ] | |
| cols = st.columns(3) | |
| for i, net in enumerate(networks): | |
| with cols[i % 3]: | |
| st.markdown(f"### {net['icon']} {net['name']}") | |
| st.button(f"Authorize {net['name']}", key=f"auth_btn_{net['name']}", help=f"Connect your {net['name']} account via OAuth for direct posting.") | |
| st.caption(f"Status: Not Connected") | |
| st.markdown("---") | |
| st.subheader("Global Settings") | |
| st.checkbox("Auto-add smart hashtags to all posts", value=True, help="Automatically suggest and append hashtags based on content analysis.") | |
| st.checkbox("Notify me on successful publishing", value=True, help="Send a notification once a post is live on the selected platform.") | |
| st.selectbox("Default AI Tone", ["Professional", "Conversational", "Exciting", "Detailed"], help="Select the default voice for your AI-generated master variations.") | |
| if st.button("Save Settings", help="Save your preferences for future sessions."): | |
| st.success("Settings saved locally! (Simulation)") | |