CoolFace
Apppublic

K2-k2/VibeCraft-AI

sourceHugging Facemitupdated 5mo agoView on Hugging Face
0likes
app.py199 linesDownload Raw Back to root
1import streamlit as st2import google.generativeai as genai3from PIL import Image4import streamlit.components.v1 as components5import os6import base647 8# --- 1. LOGO PREPARATION ---9logo_path = "logo.png"10 11def get_base64_image(path):12    try:13        with open(path, "rb") as f:14            return base64.b64encode(f.read()).decode()15    except:16        return ""17 18logo_base64 = get_base64_image(logo_path)19 20# --- 2. PAGE CONFIG & STYLING ---21st.set_page_config(page_title="VibeCraft AI", layout="wide", page_icon=logo_path)22 23# Enhanced CSS for side-by-side alignment on all devices24st.markdown(f"""25<style>26    /* Force Sidebar & Main Header to be Flex (Side-by-Side) on Mobile/Desktop */27    .brand-container {{28        display: flex;29        align-items: center;30        gap: 12px;31        margin-bottom: 10px;32    }}33    .brand-text {{34        font-weight: 800;35        margin: 0;36        line-height: 1.1;37        font-family: 'Helvetica Neue', Arial, sans-serif;38    }}39    .main-title {{ font-size: clamp(1.4rem, 5vw, 2.2rem); color: #1c1e21; }}40    .sidebar-title {{ font-size: 1.1rem; color: #1c1e21; }}41    42    .caption-draft-card {{43        background-color: #f9f9f9;44        padding: 20px;45        border-radius: 12px;46        border: 1px solid #e1e8ed;47        margin-bottom: 5px;48    }}49    .caption-text {{50        font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;51        font-size: 16px;52        color: #1c1e21;53        line-height: 1.6;54        white-space: pre-wrap;55    }}56    .feel-header-clean {{57        color: #1c1e21;58        font-weight: bold;59        font-size: 17px;60        margin-bottom: 5px;61        text-transform: uppercase;62        display: inline-block;63    }}64    /* Fix for invisible gray box */65    iframe {{ background: transparent !important; border: none !important; }}66</style>67""", unsafe_allow_html=True)68 69# --- 3. THE IMPROVED COPY BUTTON (VISIBLE & WORKING) ---70def copy_button_js(text, label, key):71    # Fixed height=75 ensures the button is not cut off on mobile72    js_code = f"""73    <div id="container_{key}">74        <script>75        function copyText_{key}() {{76            const textToCopy = `{text.replace("`", "\\`").replace("$", "\\$")}`;77            navigator.clipboard.writeText(textToCopy).then(() => {{78                const btn = document.getElementById('btn_{key}');79                btn.innerHTML = "โœ… Copied!";80                btn.style.backgroundColor = "#000000";81                btn.style.color = "#ffffff";82                setTimeout(() => {{ 83                    btn.innerHTML = "๐Ÿ“‹ {label}"; 84                    btn.style.backgroundColor = "#ffffff";85                    btn.style.color = "#000000";86                }}, 2000);87            }});88        }}89        </script>90        <button id="btn_{key}" onclick="copyText_{key}()" style="91            background-color: #ffffff; border: 1px solid #000000;92            color: #000000; padding: 10px 20px; border-radius: 8px;93            cursor: pointer; font-size: 14px; font-weight: 600;94            display: flex; align-items: center; width: 100%;95            justify-content: center; transition: 0.3s;96        ">97            ๐Ÿ“‹ {label}98        </button>99    </div>100    """101    components.html(js_code, height=75)102 103# --- 4. SIDEBAR BRANDING (ALWAYS SIDE-BY-SIDE) ---104with st.sidebar:105    st.markdown(f"""106        <div class="brand-container">107            <img src="data:image/png;base64,{logo_base64}" width="32">108            <h2 class="brand-text sidebar-title">VibeCraft AI</h2>109        </div>110    """, unsafe_allow_html=True)111    112    st.markdown("---")113    st.title("โš™๏ธ Settings")114    api_key = st.text_input("Gemini API Key (optional)", type="password")115    selected_vibe = st.selectbox("Choose the Vibe:", ["Gen-Z / Witty", "Desi / Trendy", "Shayari / Poetic", "Hindi / Desi", "Hinglish / Urban", "Professional", "Aesthetic / Poetic", "Minimalist", "Savage", "Educational", "Storyteller", "Hype / Energetic"])116 117# --- 5. MAIN HEADER (ALWAYS SIDE-BY-SIDE) ---118st.markdown(f"""119    <div class="brand-container">120        <img src="data:image/png;base64,{logo_base64}" width="55">121        <div>122            <h1 class="brand-text main-title">VibeCraft AI</h1>123            <p style="margin:0; color:#65676b; font-size:0.9rem;">โœจ <i>Turn your raw visuals into viral vibes</i></p>124        </div>125    </div>126""", unsafe_allow_html=True)127 128st.divider()129 130# --- 6. CORE APP LOGIC ---131uploaded_file = st.file_uploader("Upload Image...", type=["jpg", "jpeg", "png"])132 133if uploaded_file:134    img = Image.open(uploaded_file)135    st.subheader("Selected Image:")136    st.image(img, width=280) 137    st.divider()138 139    if st.button("โœจ Generate Captions", key="write_btn"):140        # API Key Logic141        if api_key:142            final_key = api_key143        else:144            try:145                # Fetch from Hugging Face Secrets146                final_key = os.getenv("GOOGLE_API_KEY_N")147            except:148                st.error("Please enter an API Key in sidebar or configure hugging face Secrets!")149                st.stop()150            151        genai.configure(api_key=final_key)152        model = genai.GenerativeModel('gemini-2.5-flash-lite')153            154        with st.spinner("AI is crafting vibes..."):155            try:156                # Determine the language and script instruction157                if "Hinglish" in selected_vibe:158                    lang_instr = "Write in Hinglish (Hindi words using English/Latin alphabet)."159                elif any(word in selected_vibe for word in ["Desi", "Shayari", "Hindi"]):160                    lang_instr = "Write strictly in Hindi using Devanagari script."161                else:162                    lang_instr = "Write the captions in English."163                164                prompt = f"Analyze this image. Vibe: {selected_vibe}.{lang_instr}. Write 3 creative captions. Format: ### FEEL: [Header] TEXT: [Caption + Hashtags]"165                response = model.generate_content([prompt, img])166                if response.text:167                    raw_parts = response.text.split('###')168                    processed = []169                    for part in raw_parts:170                        if "FEEL:" in part and "TEXT:" in part:171                            f = part.split("FEEL:")[1].split("TEXT:")[0].strip()172                            t = part.split("TEXT:")[1].strip()173                            processed.append({"feel": f, "text": t})174                    st.session_state.results = processed175            except Exception as e:176                st.info("You have reached the limit. Please wait a minute or try again tomorrow!")177                st.error(f"{e}")178 179else:180    st.info("Please upload an image to get viral captions")181 182# --- 7. DISPLAY RESULTS ---183if st.session_state.get('results'):184    st.subheader(f"Drafts for: {selected_vibe}")185    for i, item in enumerate(st.session_state.results[:3]):186        st.markdown(f"""187        <div class="caption-draft-card">188            <div class="feel-header-clean">โœจ {item['feel']}</div>189            <div class="caption-text">{item['text']}</div>190        </div>191        """, unsafe_allow_html=True)192        copy_button_js(item['text'], f"Copy Caption {i+1}", f"btn_{i}")193        st.write("") 194 195    if st.button("Clear All"):196        st.session_state.results = None197        st.rerun()198        199