# app.py import gradio as gr import yake from transformers import AutoTokenizer, AutoModelForSeq2SeqLM import math # --- Models / tools (küçük ve CPU-dostu) MODEL_NAME = "google/flan-t5-small" tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME) model = AutoModelForSeq2SeqLM.from_pretrained(MODEL_NAME) # YAKE keyword extractor (çok hafif) def extract_keywords(text, lang="en", max_kw=8): kw_extractor = yake.KeywordExtractor(lan=lang, n=1, top=max_kw) kws = kw_extractor.extract_keywords(text) # returns list of keywords (sorted) return [kw for kw, score in kws] # Basit SEO puanı hesaplama def seo_score(title, description, keywords, tags): score = 0 # title presence & length if title and title.strip(): score += 15 L = len(title) if 40 <= L <= 70: score += 20 elif 30 <= L < 40 or 71 <= L <= 90: score += 10 # keywords in title/description kw_in_title = sum(1 for k in keywords if k.lower() in (title or "").lower()) kw_in_desc = sum(1 for k in keywords if k.lower() in (description or "").lower()) score += min(20, kw_in_title * 10) score += min(15, kw_in_desc * 5) # description length dlen = len(description or "") if dlen >= 300: score += 20 elif dlen >= 150: score += 10 # tags if tags: if 3 <= len(tags) <= 15: score += 10 elif len(tags) > 15: score += 5 # normalize return min(100, score) # Title & description generator (Flan-T5) def gen_suggestions(main_text, keywords, max_titles=3): prompt = ( "You are an assistant that generates catchy YouTube video titles and an SEO-optimized description.\n" f"Main content: {main_text}\n" f"Keywords: {', '.join(keywords)}\n" "Produce 3 short catchy titles (each <70 chars) and one SEO-friendly description (2 paragraphs). " "Return clearly, titles separated by '||' then '---' then the description." ) inputs = tokenizer(prompt, return_tensors="pt") out = model.generate(**inputs, max_new_tokens=300) text = tokenizer.decode(out[0], skip_special_tokens=True) # Try to split results if "||" in text: parts = text.split("---") titles = parts[0].split("||") desc = parts[1].strip() if len(parts) > 1 else "" else: # fallback: guess lines = [l.strip() for l in text.split("\n") if l.strip()] titles = lines[:max_titles] desc = "\n".join(lines[max_titles:]) titles = [t.strip() for t in titles if t.strip()] return titles[:max_titles], desc # Gradio function def analyze(title, description, lang_choice): text = (title or "") + "\n" + (description or "") lang = "tr" if lang_choice == "Türkçe" else "en" # extract keywords keywords = extract_keywords(text, lang=lang, max_kw=8) # generate suggestions gen_titles, gen_desc = gen_suggestions(text if text.strip() else "Short video about ...", keywords) # tags: use keywords as tags (shorten) tags = [k.replace(" ", "_") for k in keywords][:12] # score score = seo_score(title, description, keywords, tags) return { "SEO Skoru (0-100)": score, "Çıkarılan Anahtar Kelimeler": ", ".join(keywords), "Önerilen Başlıklar": "\n".join([f"- {t}" for t in gen_titles]), "Önerilen Açıklama": gen_desc, "Önerilen Etiketler (tags)": ", ".join(tags) } # Gradio UI with gr.Blocks() as demo: gr.Markdown("## YouTube SEO Asistanı — Basit & Ücretsiz (örnek)") with gr.Row(): with gr.Column(scale=2): title_in = gr.Textbox(label="Mevcut başlık (isteğe bağlı)", lines=1, placeholder="Var olan videonuzun başlığını yazın") desc_in = gr.Textbox(label="Açıklama / Transcript / İçerik", lines=8, placeholder="Video açıklaması veya transkriptinizi buraya yapıştırın") lang = gr.Radio(choices=["Türkçe", "English"], value="Türkçe", label="Dil") btn = gr.Button("Analiz Et") with gr.Column(scale=1): score_out = gr.Label(num_top_classes=1, label="Sonuç") result_box = gr.JSON(label="Detaylı Öneriler") btn.click(fn=analyze, inputs=[title_in, desc_in, lang], outputs=[score_out, result_box]) if __name__ == "__main__": demo.launch()