import os import time import streamlit as st from google import genai from google.genai.types import Tool, GenerateContentConfig, GoogleSearch import google.api_core # --- Configuration --- st.set_page_config( page_title="AI Niche Content Idea Generator", page_icon="💡", layout="centered", ) # --- Patreon Link --- PATREON_URL = "https://www.patreon.com/cineAI" # --- Model List --- FALLBACK_MODELS = [ "gemini-2.0-flash-thinking-exp-01-21", "gemini-2.5-flash-preview-04-17", "gemini-1.5-flash", "gemini-1.5-pro", "gemini-2.0-flash", "gemini-2.0-flash-lite", "gemini-2.5-pro-preview-03-25", ] # --- Authentication --- api_key = "" try: api_key = st.secrets["GOOGLE_API_KEY"] api_key_configured = True except (KeyError, FileNotFoundError): st.error("🚨 Google API Key not found! Please go to the settings, then find the `Variables and secrets` item and click `New secret`, insert your Google API key.") api_key_configured = False st.stop() # --- Helper Function for API Call with Fallback & Advanced Mode --- def generate_content_ideas(niche, audience, content_format, num_ideas=4, advanced_mode=False): """Generates content ideas using Google Generative AI, with fallback and optional search.""" if not api_key_configured: return "API Key not configured. Cannot proceed." # --- Base Prompt --- base_prompt = f""" Act as an expert content strategist specializing in the niche: '{niche}'. Your task is to generate {num_ideas} fresh, specific, and engaging content ideas tailored for the following target audience: '{audience}'. The desired content format is: '{content_format}'. Focus on providing unique angles, addressing potential pain points or interests of the audience, and suggesting topics that are relevant within the niche. Avoid generic ideas. """ # --- Enhance Prompt for Advanced Mode --- if advanced_mode: prompt = base_prompt + f""" **IMPORTANT: Leverage current information from the web using the available search tool** to identify *trending topics*, *recent developments*, or *very specific audience questions* within the '{niche}' niche related to the '{audience}' audience. Ground your ideas in potentially searchable, up-to-date information. """ else: prompt = base_prompt + """ Generate the ideas based on your general knowledge of the niche and audience. """ # --- Add Formatting Instruction --- prompt += """ Please format the output as a numbered list. Each idea should be concise but descriptive. Example for niche 'Sustainable Gardening', audience 'Urban Beginners', format 'Blog Post Titles': 1. 5 Easy-to-Grow Vegetables for Your Tiny Balcony Garden 2. Composting in Apartments: A No-Smell Guide for City Dwellers 3. Choosing the Right Recycled Pots for Your Indoor Plants 4. How to Attract Pollinators to Your Urban Oasis 5. Watering Wisely: Saving Water in Your Container Garden Now, generate the ideas for the requested niche, audience, and format: """ last_error = None last_error_message = "" # --- Tool Configuration --- if advanced_mode: google_search_tool = Tool(google_search=GoogleSearch()) config = GenerateContentConfig( tools=[google_search_tool], response_modalities=['TEXT'], # system_instruction=system_instruction_google_search, max_output_tokens=4100, ) else: config = None tool_status_msg = " (Advanced Mode with Google Search 🔍)" if advanced_mode else "" for model_name in FALLBACK_MODELS: st.info(f"🧠 Attempting generation with model: `{model_name}`{tool_status_msg}...") try: model = genai.Client(api_key=api_key) response = model.models.generate_content( model=model_name, contents=prompt, config=config, ) # --- Check for successful response (handle potential blocks) --- if hasattr(response, 'text') and response.text: st.success(f"✅ Successfully generated ideas using `{model_name}`!") return response.text elif hasattr(response, 'prompt_feedback') and response.prompt_feedback.block_reason: error_message = f"⚠️ Generation blocked by `{model_name}`. Reason: {response.prompt_feedback.block_reason.name}. Trying next model..." st.warning(error_message) last_error = BlockingIOError(f"{model_name}: Blocked - {response.prompt_feedback.block_reason.name}") last_error_message = error_message time.sleep(0.5) continue else: error_message = f"⚠️ Generation failed with `{model_name}` (empty or invalid response structure). Trying next model..." st.warning(error_message) last_error = ValueError(f"{model_name}: Empty/Invalid response") last_error_message = error_message time.sleep(1) continue # --- Catch Specific API Errors --- except google.api_core.exceptions.ResourceExhausted as e: error_message = f"⏳ Model `{model_name}` likely rate limited: {e}. Trying next model..." st.warning(error_message) last_error = e last_error_message = error_message time.sleep(3) continue except google.api_core.exceptions.ServiceUnavailable as e: error_message = f"☁️ Model `{model_name}` unavailable: {e}. Trying next model..." st.warning(error_message) last_error = e last_error_message = error_message time.sleep(3) continue except (google.api_core.exceptions.InvalidArgument, ValueError) as e: err_str = str(e).lower() if "tool" in err_str or "function" in err_str or "retriever" in err_str: error_message = f"🔧 Model `{model_name}` might not support the requested tool or configuration: {e}. Trying next model..." st.warning(error_message) else: error_message = f"🚫 Invalid argument for `{model_name}`: {e}. Trying next model..." st.warning(error_message) last_error = e last_error_message = error_message continue except google.api_core.exceptions.GoogleAPIError as e: error_message = f"🚫 API Error with `{model_name}`: {e}. Trying next model..." st.warning(error_message) last_error = e last_error_message = error_message continue # --- Catch General Errors --- except Exception as e: error_message = f"❌ Unexpected error with `{model_name}`: {type(e).__name__} - {e}. Trying next model..." st.warning(error_message) last_error = e last_error_message = error_message continue st.error("💥 All attempts failed.") final_error_message = "⚠️ Failed to generate ideas after trying all configured models." if last_error: final_error_message += f"\nLast known issue: {last_error_message}" return final_error_message # --- Streamlit App Interface --- st.sidebar.title("Support This Tool") st.sidebar.markdown(f""" If you find this AI Content Idea Generator useful, please consider supporting its ongoing development and hosting costs. [**💖 Support on Patreon**]({PATREON_URL}) Your support helps keep this tool running and allows for future improvements! """) st.title("🚀 AI Niche Content Idea Generator") st.markdown("Define your niche, audience, and format. Use **Advanced Mode** for potentially more current ideas!") st.divider() # --- User Inputs --- with st.form("content_idea_form"): st.subheader("Tell us about your content needs:") niche = st.text_input("🎯 Enter your Niche:", placeholder="e.g., Sustainable Home Decor, Retro PC Gaming") audience = st.text_area("👥 Describe your Target Audience:", placeholder="e.g., Eco-conscious millennials, 90s Gamers", height=100) content_format_options = ["Blog Post Titles", "Social Media Captions", "YouTube Video Ideas", "Podcast Topics", "Newsletter Subjects", "TikTok Video Concepts", "LinkedIn Article Headlines"] content_format = st.selectbox("✍️ Select Desired Content Format:", options=content_format_options) num_ideas_slider = st.slider("🔢 Number of ideas:", min_value=3, max_value=15, value=4) advanced_mode_toggle = st.toggle("🔍 Advanced Mode (Use Google Search)", value=False, help="May use Google Search for more current ideas. Works best with Gemini models.") submitted = st.form_submit_button("✨ Generate Ideas!") # --- Output --- if submitted: if not niche or not audience or not content_format: st.warning("⚠️ Please fill in all the fields.") elif api_key_configured: mode_msg = " (Advanced Mode)" if advanced_mode_toggle else "" with st.spinner(f"🧠 Thinking up brilliant ideas{mode_msg}..."): generated_ideas = generate_content_ideas( niche, audience, content_format, num_ideas_slider, advanced_mode=advanced_mode_toggle ) st.divider() st.subheader("💡 Here are your content ideas:") if generated_ideas and not generated_ideas.startswith(("⚠️", "💥")): st.markdown(generated_ideas) st.success("Ideas generated successfully!") st.markdown("---") st.markdown(f"**Hope these ideas help!** If this tool saved you time or sparked creativity, consider [supporting the creator on Patreon]({PATREON_URL}).") elif generated_ideas: st.error(generated_ideas) else: st.error("An unexpected issue occurred. No ideas were generated or returned.") else: st.error("API Key is not configured.")