GoshawkVortexAI's picture
Update app.py
40f89e0 verified
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 &nbsp;·&nbsp; Llama 3.1 8B Instruct &nbsp;·&nbsp; 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()