import logging import os from logging import getLogger import gradio as gr from google import genai from google.genai import types logger = getLogger(__name__) # Configure logger to show info level messages logging.basicConfig(level=logging.INFO) logger.setLevel(logging.INFO) logger.info("Logger configured to show INFO level messages") def get_sources(response): """Zbiera źródła z groundingMetadata""" try: if not response.candidates or not response.candidates[0].grounding_metadata: logger.info("Brak grounding metadata - brak źródeł") return [] grounding_meta = response.candidates[0].grounding_metadata chunks = grounding_meta.grounding_chunks if not chunks: logger.info("Brak chunks - brak źródeł") return [] # Zbierz unikalne źródła z URI sources = [] seen_uris = set() for chunk in chunks: if chunk.web and chunk.web.uri: uri = chunk.web.uri if uri not in seen_uris: seen_uris.add(uri) # Spróbuj wyciągnąć tytuł z chunk jeśli dostępny title = getattr(chunk.web, 'title', '') if hasattr(chunk.web, 'title') else '' if not title: # Jeśli brak tytułu, użyj domeny z URL from urllib.parse import urlparse parsed = urlparse(uri) title = parsed.netloc or uri sources.append({ 'title': title, 'url': uri }) logger.info(f"Znaleziono {len(sources)} unikalnych źródeł") return sources except Exception as e: logger.error(f"Błąd podczas zbierania źródeł: {e}", exc_info=True) return [] def format_sources_section(sources): """Formatuje sekcję źródeł""" if not sources: return "" sources_text = "\n\n## Źródła:\n" for i, source in enumerate(sources, 1): sources_text += f"{i}. [{source['title']}]({source['url']})\n" return sources_text def generate(link: str, request: gr.Request): """Funkcja pobierająca link od użytkownika i generująca streszczenie.""" # Pokaż loading state na początku yield "🔄 **Generuję streszczenie artykułu...**\n\nProszę czekać, może to potrwać kilka chwil." try: client = genai.Client( vertexai=False, api_key=os.getenv("GOOGLE_API_KEY") ) prompt = f""" Otrzymujesz link do artykułu. Twoje zadanie to przygotowanie syntetycznego streszczenia na potrzeby YouTube oraz social media. Zwróć wynik w następującej strukturze: ## Tytuł: Przepisz dokładnie tytuł artykułu ## Podsumowanie: Jedno-dwa zdania, które jasno wyjaśniają, czego dotyczy artykuł. ## Sugestie do odcinka YouTube: Wypunktuj rzeczy, które warto poruszyć w odcinku (najważniejsze wątki, ciekawe fakty, potencjalne tematy do rozwinięcia): - Opis tematu - dodatkowe wyjaśnienie - Kolejny temat - kontekst ## Najważniejsze informacje: Zbierz kluczowe dane i fakty, nie pomijaj liczb, wyników, cytowanych źródeł: - Konkretny fakt/liczba/wynik - kontekst i wyjaśnienie - Następna informacja - dodatkowe szczegóły ## Cytaty z artykułu: Jeśli w artykule są cytaty bohaterów lub ekspertów, wypisz je w formacie: > **"pełny cytat"** - imię i nazwisko osoby, stanowisko Pogrub najważniejsze fragmenty cytatów. Nie wymyślaj cytatów, jeśli ich nie ma – pomiń ten punkt. ## Ciekawostki: Jeśli w artykule pojawiają się ciekawe lub zaskakujące informacje, wypisz je tutaj. Możesz dodać dodatkowe fakty znalezione w internecie, pod warunkiem, że są aktualne i zgodne z treścią artykułu: - Ciekawa informacja - dodatkowy kontekst - Dodatkowy fakt z internetu - wyjaśnienie pochodzenia ## Timestamp do odcinka YouTube: Zaproponuj timestamp w formacie: - 00:00 **Wprowadzenie** - 02:30 **Główne wątki** - 05:00 **Najważniejsze fakty** - 08:00 **Podsumowanie** ### ZASADY: - Wszystko musi być zgodne z treścią artykułu - Nie wymyślaj cytatów ani faktów - Jeśli dany punkt nie występuje w artykule, pomiń go bez komentarza - Używaj pogrubień (**tekst**) dla kluczowych informacji - NIE dodawaj linków markdown - będą dodane automatycznie Źródło: {link} """ model = "gemini-2.5-flash" # Uproszczona konfiguracja - użyj prompt jako string tools = [ types.Tool(google_search=types.GoogleSearch()), ] generate_content_config = types.GenerateContentConfig( temperature=0.0, top_p=0.95, max_output_tokens=8192, tools=tools, ) # Wygeneruj odpowiedź (bez streamingu) response = client.models.generate_content( model=model, contents=prompt, config=generate_content_config, ) if response and response.text: # Zbierz źródła z groundingMetadata sources = get_sources(response) # Loguj informacje o groundingu if (response.candidates and response.candidates[0].grounding_metadata): grounding_meta = response.candidates[0].grounding_metadata if hasattr(grounding_meta, 'web_search_queries'): logger.info(f"Zapytania wyszukiwania: {grounding_meta.web_search_queries}") if hasattr(grounding_meta, 'grounding_chunks') and grounding_meta.grounding_chunks: logger.info(f"Liczba źródeł: {len(grounding_meta.grounding_chunks)}") # Połącz odpowiedź z sekcją źródeł final_result = response.text + format_sources_section(sources) yield final_result else: yield "❌ **Błąd:** Nie udało się wygenerować streszczenia. Spróbuj ponownie." except Exception as e: # Return error message yield f"❌ **Błąd:** {str(e)}" with gr.Blocks() as demo: _ = gr.Markdown("## Streszczenia newsów\nWklej link do artykułu, a wygeneruję z niego najważniejsze informacje w formie podsumowania i punktów.") with gr.Row(): link_input = gr.Textbox(label="Link do artykułu", placeholder="https://akademiatriathlonu.pl/...") output = gr.Markdown(label="Streszczenie") submit_btn = gr.Button("Generuj streszczenie") _ = submit_btn.click(fn=generate, inputs=[link_input], outputs=[output]) _ = demo.launch(show_error=True)