Spaces:
Running
Running
| import gradio as gr | |
| from youtube_transcript_api import YouTubeTranscriptApi | |
| from transformers import pipeline | |
| import re | |
| # Model yükleme (ilk çalıştırmada indirir) | |
| summarizer = pipeline("summarization", model="facebook/bart-large-cnn") | |
| sentiment_analyzer = pipeline( | |
| "sentiment-analysis", | |
| model="cardiffnlp/twitter-roberta-base-sentiment-latest" | |
| ) | |
| LABEL_MAP = { | |
| "positive": "Olumlu", | |
| "negative": "Olumsuz", | |
| "neutral": "Nötr" | |
| } | |
| def extract_video_id(url: str) -> str: | |
| patterns = [ | |
| r"v=([a-zA-Z0-9_-]{11})", | |
| r"youtu\.be/([a-zA-Z0-9_-]{11})", | |
| r"embed/([a-zA-Z0-9_-]{11})", | |
| ] | |
| for pattern in patterns: | |
| match = re.search(pattern, url) | |
| if match: | |
| return match.group(1) | |
| raise ValueError("Geçersiz YouTube URL'si") | |
| def get_transcript(video_id: str) -> str: | |
| try: | |
| transcript = YouTubeTranscriptApi.get_transcript(video_id, languages=["tr", "en"]) | |
| return " ".join([t["text"] for t in transcript]) | |
| except Exception: | |
| try: | |
| transcript = YouTubeTranscriptApi.get_transcript(video_id) | |
| return " ".join([t["text"] for t in transcript]) | |
| except Exception as e: | |
| raise ValueError(f"Transkript alınamadı: {str(e)}") | |
| def chunk_text(text: str, max_tokens: int = 1000) -> list[str]: | |
| words = text.split() | |
| chunks = [] | |
| current = [] | |
| for word in words: | |
| current.append(word) | |
| if len(current) >= max_tokens: | |
| chunks.append(" ".join(current)) | |
| current = [] | |
| if current: | |
| chunks.append(" ".join(current)) | |
| return chunks | |
| def summarize_text(text: str) -> str: | |
| if len(text.split()) < 50: | |
| return "Transkript çok kısa, özet oluşturulamadı." | |
| chunks = chunk_text(text, max_tokens=900) | |
| summaries = [] | |
| for chunk in chunks[:4]: # max 4 chunk | |
| result = summarizer(chunk, max_length=150, min_length=40, do_sample=False) | |
| summaries.append(result[0]["summary_text"]) | |
| return " ".join(summaries) | |
| def analyze_sentiment(text: str) -> dict: | |
| chunks = chunk_text(text, max_tokens=200) | |
| scores = {"positive": 0, "negative": 0, "neutral": 0} | |
| for chunk in chunks[:10]: # max 10 chunk | |
| result = sentiment_analyzer(chunk[:512])[0] | |
| label = result["label"].lower() | |
| if label in scores: | |
| scores[label] += result["score"] | |
| total = sum(scores.values()) | |
| if total == 0: | |
| return scores | |
| return {k: round(v / total * 100, 1) for k, v in scores.items()} | |
| def extract_keywords(text: str) -> str: | |
| words = re.findall(r'\b[a-zA-ZğüşöçıİĞÜŞÖÇ]{4,}\b', text.lower()) | |
| freq = {} | |
| stopwords = {"this", "that", "with", "have", "from", "they", "will", "been", | |
| "were", "your", "what", "when", "here", "there", "more", "also", | |
| "just", "like", "some", "than", "then", "into", "over", "after"} | |
| for w in words: | |
| if w not in stopwords: | |
| freq[w] = freq.get(w, 0) + 1 | |
| top = sorted(freq.items(), key=lambda x: x[1], reverse=True)[:10] | |
| return ", ".join([w for w, _ in top]) | |
| def analyze_youtube(url: str): | |
| if not url.strip(): | |
| return "URL girin.", "", "", "" | |
| try: | |
| video_id = extract_video_id(url) | |
| transcript = get_transcript(video_id) | |
| summary = summarize_text(transcript) | |
| sentiment = analyze_sentiment(transcript) | |
| keywords = extract_keywords(transcript) | |
| sentiment_text = ( | |
| f"Olumlu: %{sentiment['positive']}\n" | |
| f"Olumsuz: %{sentiment['negative']}\n" | |
| f"Nötr: %{sentiment['neutral']}" | |
| ) | |
| dominant = max(sentiment, key=sentiment.get) | |
| dominant_tr = LABEL_MAP.get(dominant, dominant) | |
| return ( | |
| summary, | |
| sentiment_text, | |
| f"Genel Ton: {dominant_tr}", | |
| keywords | |
| ) | |
| except ValueError as e: | |
| return str(e), "", "", "" | |
| except Exception as e: | |
| return f"Hata: {str(e)}", "", "", "" | |
| with gr.Blocks(title="YouTube Video Analizci", theme=gr.themes.Soft()) as demo: | |
| gr.Markdown("# YouTube Video Analizci") | |
| gr.Markdown("YouTube video URL'si girin — transkript özetini, duygu analizini ve anahtar kelimeleri çıkarır.") | |
| with gr.Row(): | |
| url_input = gr.Textbox( | |
| label="YouTube URL", | |
| placeholder="https://www.youtube.com/watch?v=...", | |
| scale=4 | |
| ) | |
| analyze_btn = gr.Button("Analiz Et", variant="primary", scale=1) | |
| with gr.Row(): | |
| summary_out = gr.Textbox(label="Video Özeti", lines=6, scale=3) | |
| with gr.Column(scale=1): | |
| sentiment_out = gr.Textbox(label="Duygu Analizi", lines=3) | |
| tone_out = gr.Textbox(label="Genel Ton", lines=1) | |
| keywords_out = gr.Textbox(label="Anahtar Kelimeler", lines=2) | |
| analyze_btn.click( | |
| fn=analyze_youtube, | |
| inputs=[url_input], | |
| outputs=[summary_out, sentiment_out, tone_out, keywords_out] | |
| ) | |
| gr.Examples( | |
| examples=[["https://www.youtube.com/watch?v=dQw4w9WgXcQ"]], | |
| inputs=[url_input] | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() | |