Spaces:
Sleeping
Sleeping
| import os | |
| import gradio as gr | |
| from huggingface_hub import InferenceClient | |
| # ── Model (ücretsiz HF Inference API) ───────────────────────────────────────── | |
| # HF_TOKEN ortam değişkeni Space'in Secrets kısmına eklenir (ücretsiz) | |
| client = InferenceClient( | |
| api_key=os.environ.get("HF_TOKEN"), | |
| ) | |
| # ── Prompt ───────────────────────────────────────────────────────────────────── | |
| def build_messages(niche: str, audience: str) -> list: | |
| audience_line = f"Target audience: {audience}" if audience.strip() else "Target audience: General TikTok users" | |
| return [ | |
| { | |
| "role": "system", | |
| "content": "You are a TikTok viral content analyst AI. Your task is to identify viral video opportunities based on patterns, not random ideas. Always use clear formatting with emojis." | |
| }, | |
| { | |
| "role": "user", | |
| "content": f"""INPUT: | |
| - Niche: {niche} | |
| - {audience_line} | |
| - Platform: TikTok | |
| STEP 1: Briefly analyze what makes content go viral in this niche: | |
| - Best hook styles | |
| - Key emotional triggers | |
| - Video structure patterns | |
| STEP 2: Generate 10 viral video ideas. For each idea provide: | |
| 1. 🎬 Title | |
| 2. 🪝 Hook (first sentence spoken in the video) | |
| 3. 💡 Concept (what happens) | |
| 4. 🔥 Why it can go viral | |
| 5. ⭐ Virality Score: X/10 | |
| STEP 3: Give 3 specific improvements to boost virality in this niche. | |
| Rules: | |
| - Be specific and creative, avoid generic ideas | |
| - Think like the TikTok algorithm | |
| - Focus on scroll-stopping content | |
| - Use clear formatting with emojis""" | |
| } | |
| ] | |
| # ── Inference (streaming) ────────────────────────────────────────────────────── | |
| def analyze(niche: str, audience: str): | |
| if not niche.strip(): | |
| yield "⚠️ Lütfen bir niche (konu) girin." | |
| return | |
| messages = build_messages(niche.strip(), audience.strip()) | |
| output = "" | |
| try: | |
| stream = client.chat.completions.create( | |
| model="meta-llama/Meta-Llama-3.1-8B-Instruct", | |
| messages=messages, | |
| max_tokens=2500, | |
| temperature=0.8, | |
| stream=True, | |
| ) | |
| for chunk in stream: | |
| delta = chunk.choices[0].delta.content or "" | |
| output += delta | |
| yield output | |
| except Exception as e: | |
| yield f"❌ Hata oluştu: {str(e)}\n\nHF_TOKEN'ınızı Space Secrets'a eklediğinizden emin olun." | |
| # ── CSS ──────────────────────────────────────────────────────────────────────── | |
| CSS = """ | |
| @import url('https://fonts.googleapis.com/css2?family=Bebas+Neue&family=Plus+Jakarta+Sans:wght@300;400;500;600&display=swap'); | |
| :root { | |
| --bg: #0a0a0a; | |
| --card: #161616; | |
| --border: #222; | |
| --red: #fe2c55; | |
| --cyan: #25f4ee; | |
| --white: #f0f0f0; | |
| --muted: #555; | |
| --font-d: 'Bebas Neue', sans-serif; | |
| --font-b: 'Plus Jakarta Sans', sans-serif; | |
| --r: 12px; | |
| } | |
| body, .gradio-container { | |
| background: var(--bg) !important; | |
| color: var(--white) !important; | |
| font-family: var(--font-b) !important; | |
| } | |
| #hdr { padding: 44px 24px 24px; text-align: center; } | |
| #hdr .logo { | |
| font-family: var(--font-d); | |
| font-size: clamp(3rem, 10vw, 5.5rem); | |
| letter-spacing: 3px; | |
| background: linear-gradient(135deg, var(--red) 0%, #ff6b8a 45%, var(--cyan) 100%); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| animation: glow 3s ease-in-out infinite; | |
| } | |
| @keyframes glow { | |
| 0%,100% { filter: drop-shadow(0 0 18px rgba(254,44,85,.45)); } | |
| 50% { filter: drop-shadow(0 0 35px rgba(37,244,238,.45)); } | |
| } | |
| #hdr .sub { | |
| color: var(--muted); font-size:.82rem; | |
| letter-spacing:.14em; text-transform:uppercase; margin-top:6px; | |
| } | |
| #hdr .badge { | |
| display:inline-block; margin-top:12px; padding:4px 16px; | |
| border:1px solid var(--red); border-radius:100px; | |
| font-size:.68rem; letter-spacing:.1em; color:var(--red); text-transform:uppercase; | |
| } | |
| #stats { | |
| display:flex; justify-content:center; gap:48px; | |
| padding:22px 0 26px; border-bottom:1px solid var(--border); margin-bottom:26px; | |
| } | |
| #stats .val { | |
| font-family:var(--font-d); font-size:2.2rem; | |
| background:linear-gradient(135deg,var(--red),var(--cyan)); | |
| -webkit-background-clip:text; -webkit-text-fill-color:transparent; | |
| } | |
| #stats .lbl { font-size:.66rem; letter-spacing:.1em; text-transform:uppercase; color:var(--muted); margin-top:2px; } | |
| #tips { display:flex; gap:10px; flex-wrap:wrap; justify-content:center; padding:0 0 26px; } | |
| #tips .tip { | |
| background:var(--card); border:1px solid var(--border); border-radius:100px; | |
| padding:5px 14px; font-size:.7rem; color:var(--muted); | |
| } | |
| label span { | |
| color:var(--muted) !important; font-size:.7rem !important; | |
| letter-spacing:.1em !important; text-transform:uppercase !important; | |
| } | |
| textarea, input[type="text"] { | |
| background:var(--card) !important; border:1px solid var(--border) !important; | |
| border-radius:var(--r) !important; color:var(--white) !important; | |
| font-family:var(--font-b) !important; font-size:.95rem !important; | |
| transition:border-color .2s, box-shadow .2s !important; | |
| } | |
| textarea:focus, input[type="text"]:focus { | |
| border-color:var(--red) !important; | |
| box-shadow:0 0 0 3px rgba(254,44,85,.12) !important; | |
| } | |
| button.primary { | |
| background:var(--red) !important; border:none !important; | |
| border-radius:var(--r) !important; color:#fff !important; | |
| font-family:var(--font-d) !important; font-size:1.1rem !important; | |
| letter-spacing:.15em !important; padding:13px 32px !important; | |
| transition:transform .15s, box-shadow .15s !important; | |
| } | |
| button.primary:hover { | |
| transform:translateY(-2px) !important; | |
| box-shadow:0 8px 28px rgba(254,44,85,.45) !important; | |
| } | |
| button.secondary { | |
| background:transparent !important; border:1px solid var(--border) !important; | |
| border-radius:var(--r) !important; color:var(--muted) !important; | |
| font-family:var(--font-b) !important; transition:border-color .2s, color .2s !important; | |
| } | |
| button.secondary:hover { border-color:var(--cyan) !important; color:var(--cyan) !important; } | |
| .gr-markdown { | |
| background:var(--card) !important; border:1px solid var(--border) !important; | |
| border-radius:var(--r) !important; padding:24px !important; | |
| font-size:.88rem !important; line-height:1.8 !important; | |
| color:#bbb !important; min-height:340px; | |
| } | |
| .gr-markdown h1,.gr-markdown h2 { | |
| font-family:var(--font-d) !important; letter-spacing:.06em !important; color:var(--white) !important; | |
| } | |
| .gr-markdown h3 { color:var(--cyan) !important; font-size:.82rem !important; text-transform:uppercase !important; } | |
| .gr-markdown strong { color:var(--red) !important; } | |
| .gr-markdown code { | |
| background:#1a1a1a !important; border-radius:4px !important; | |
| padding:2px 7px !important; color:var(--cyan) !important; | |
| } | |
| .gr-group, .gr-box { | |
| background:#111 !important; border:1px solid var(--border) !important; border-radius:var(--r) !important; | |
| } | |
| #footer { | |
| text-align:center; padding:20px; color:var(--muted); | |
| font-size:.7rem; letter-spacing:.08em; | |
| border-top:1px solid var(--border); margin-top:32px; | |
| } | |
| ::-webkit-scrollbar { width:4px; } | |
| ::-webkit-scrollbar-track { background:var(--bg); } | |
| ::-webkit-scrollbar-thumb { background:#2a2a2a; border-radius:4px; } | |
| """ | |
| HEADER = """ | |
| <div id="hdr"> | |
| <div class="logo">ViralAI</div> | |
| <div class="sub">TikTok Viral İçerik Analiz Motoru</div> | |
| <div class="badge">⚡ Llama 3.1 8B · Ücretsiz</div> | |
| </div> | |
| <div id="stats"> | |
| <div class="stat"><div class="val">10</div><div class="lbl">Video Fikri</div></div> | |
| <div class="stat"><div class="val">AI</div><div class="lbl">Virality Skoru</div></div> | |
| <div class="stat"><div class="val">∞</div><div class="lbl">Niche Desteği</div></div> | |
| </div> | |
| <div id="tips"> | |
| <div class="tip">🎯 Hook analizi</div> | |
| <div class="tip">🔥 Scroll-stopping içerik</div> | |
| <div class="tip">🧠 Algoritma odaklı</div> | |
| <div class="tip">📈 Virality tahmini</div> | |
| <div class="tip">🛠 İyileştirme önerileri</div> | |
| </div> | |
| """ | |
| FOOTER = """ | |
| <div id="footer"> | |
| VIRAIAI · Llama 3.1 8B Instruct · Hugging Face Inference API | |
| </div> | |
| """ | |
| # ── UI ───────────────────────────────────────────────────────────────────────── | |
| with gr.Blocks(css=CSS, title="ViralAI — TikTok Viral Content Analyzer") as demo: | |
| gr.HTML(HEADER) | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| niche_input = gr.Textbox( | |
| label="Niche / Konu", | |
| placeholder="örn: fitness, kripto, yemek tarifleri, girişimcilik…", | |
| lines=2, | |
| ) | |
| audience_input = gr.Textbox( | |
| label="Hedef Kitle (opsiyonel)", | |
| placeholder="örn: 18-25 yaş, kadın, öğrenciler…", | |
| lines=2, | |
| ) | |
| with gr.Row(): | |
| clear_btn = gr.Button("Temizle", variant="secondary") | |
| analyze_btn = gr.Button("⚡ Analiz Et", variant="primary") | |
| gr.HTML(""" | |
| <div style="margin-top:18px;padding:16px;background:#161616;border:1px solid #222; | |
| border-radius:12px;font-size:.76rem;color:#444;line-height:1.8;"> | |
| <div style="color:#333;font-size:.66rem;letter-spacing:.1em; | |
| text-transform:uppercase;margin-bottom:8px;">Kurulum</div> | |
| 1. HF Space oluştur (Gradio)<br> | |
| 2. <span style="color:#fe2c55">Settings → Secrets</span>'a git<br> | |
| 3. <code style="color:#25f4ee;background:#1a1a1a;padding:1px 5px;border-radius:3px">HF_TOKEN</code> ekle (ücretsiz)<br> | |
| 4. Deploy et, kullanmaya başla ✅ | |
| </div> | |
| """) | |
| with gr.Column(scale=2): | |
| output = gr.Markdown( | |
| value="*Niche gir ve analiz et butonuna bas…*", | |
| elem_classes=["prose"], | |
| ) | |
| gr.HTML(FOOTER) | |
| analyze_btn.click(fn=analyze, inputs=[niche_input, audience_input], outputs=output) | |
| clear_btn.click( | |
| fn=lambda: ("", "", "*Niche gir ve analiz et butonuna bas…*"), | |
| inputs=[], | |
| outputs=[niche_input, audience_input, output], | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() | |