wwydmanski commited on
Commit
543780f
·
verified ·
1 Parent(s): 13a421d

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +184 -0
app.py ADDED
@@ -0,0 +1,184 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ import os
3
+ from logging import getLogger
4
+
5
+ import gradio as gr
6
+ from google import genai
7
+ from google.genai import types
8
+
9
+ logger = getLogger(__name__)
10
+
11
+ # Configure logger to show info level messages
12
+ logging.basicConfig(level=logging.INFO)
13
+ logger.setLevel(logging.INFO)
14
+ logger.info("Logger configured to show INFO level messages")
15
+
16
+
17
+
18
+ def get_sources(response):
19
+ """Zbiera źródła z groundingMetadata"""
20
+ try:
21
+ if not response.candidates or not response.candidates[0].grounding_metadata:
22
+ logger.info("Brak grounding metadata - brak źródeł")
23
+ return []
24
+
25
+ grounding_meta = response.candidates[0].grounding_metadata
26
+ chunks = grounding_meta.grounding_chunks
27
+
28
+ if not chunks:
29
+ logger.info("Brak chunks - brak źródeł")
30
+ return []
31
+
32
+ # Zbierz unikalne źródła z URI
33
+ sources = []
34
+ seen_uris = set()
35
+
36
+ for chunk in chunks:
37
+ if chunk.web and chunk.web.uri:
38
+ uri = chunk.web.uri
39
+ if uri not in seen_uris:
40
+ seen_uris.add(uri)
41
+ # Spróbuj wyciągnąć tytuł z chunk jeśli dostępny
42
+ title = getattr(chunk.web, 'title', '') if hasattr(chunk.web, 'title') else ''
43
+ if not title:
44
+ # Jeśli brak tytułu, użyj domeny z URL
45
+ from urllib.parse import urlparse
46
+ parsed = urlparse(uri)
47
+ title = parsed.netloc or uri
48
+
49
+ sources.append({
50
+ 'title': title,
51
+ 'url': uri
52
+ })
53
+
54
+ logger.info(f"Znaleziono {len(sources)} unikalnych źródeł")
55
+ return sources
56
+
57
+ except Exception as e:
58
+ logger.error(f"Błąd podczas zbierania źródeł: {e}", exc_info=True)
59
+ return []
60
+
61
+
62
+ def format_sources_section(sources):
63
+ """Formatuje sekcję źródeł"""
64
+ if not sources:
65
+ return ""
66
+
67
+ sources_text = "\n\n## Źródła:\n"
68
+ for i, source in enumerate(sources, 1):
69
+ sources_text += f"{i}. [{source['title']}]({source['url']})\n"
70
+
71
+ return sources_text
72
+
73
+
74
+ def generate(link: str, request: gr.Request):
75
+ """Funkcja pobierająca link od użytkownika i generująca streszczenie."""
76
+ # Pokaż loading state na początku
77
+ yield "🔄 **Generuję streszczenie artykułu...**\n\nProszę czekać, może to potrwać kilka chwil."
78
+
79
+ try:
80
+ client = genai.Client(
81
+ vertexai=False,
82
+ api_key=os.getenv("GOOGLE_API_KEY")
83
+ )
84
+
85
+ prompt = f"""
86
+ Otrzymujesz link do artykułu. Twoje zadanie to przygotowanie syntetycznego streszczenia na potrzeby YouTube oraz social media.
87
+ Zwróć wynik w następującej strukturze:
88
+
89
+ ## Tytuł:
90
+ Przepisz dokładnie tytuł artykułu
91
+
92
+ ## Podsumowanie:
93
+ Jedno-dwa zdania, które jasno wyjaśniają, czego dotyczy artykuł.
94
+
95
+ ## Sugestie do odcinka YouTube:
96
+ Wypunktuj rzeczy, które warto poruszyć w odcinku (najważniejsze wątki, ciekawe fakty, potencjalne tematy do rozwinięcia):
97
+ - Opis tematu - dodatkowe wyjaśnienie
98
+ - Kolejny temat - kontekst
99
+
100
+ ## Najważniejsze informacje:
101
+ Zbierz kluczowe dane i fakty, nie pomijaj liczb, wyników, cytowanych źródeł:
102
+ - Konkretny fakt/liczba/wynik - kontekst i wyjaśnienie
103
+ - Następna informacja - dodatkowe szczegóły
104
+
105
+ ## Cytaty z artykułu:
106
+ Jeśli w artykule są cytaty bohaterów lub ekspertów, wypisz je w formacie:
107
+ > **"pełny cytat"** - imię i nazwisko osoby, stanowisko
108
+
109
+ Pogrub najważniejsze fragmenty cytatów. Nie wymyślaj cytatów, jeśli ich nie ma – pomiń ten punkt.
110
+
111
+ ## Ciekawostki:
112
+ 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:
113
+ - Ciekawa informacja - dodatkowy kontekst
114
+ - Dodatkowy fakt z internetu - wyjaśnienie pochodzenia
115
+
116
+ ## Timestamp do odcinka YouTube:
117
+ Zaproponuj timestamp w formacie:
118
+ - 00:00 **Wprowadzenie**
119
+ - 02:30 **Główne wątki**
120
+ - 05:00 **Najważniejsze fakty**
121
+ - 08:00 **Podsumowanie**
122
+
123
+ ### ZASADY:
124
+ - Wszystko musi być zgodne z treścią artykułu
125
+ - Nie wymyślaj cytatów ani faktów
126
+ - Jeśli dany punkt nie występuje w artykule, pomiń go bez komentarza
127
+ - Używaj pogrubień (**tekst**) dla kluczowych informacji
128
+ - NIE dodawaj linków markdown - będą dodane automatycznie
129
+
130
+ Źródło: {link}
131
+ """
132
+
133
+ model = "gemini-2.5-flash"
134
+
135
+ # Uproszczona konfiguracja - użyj prompt jako string
136
+ tools = [
137
+ types.Tool(google_search=types.GoogleSearch()),
138
+ ]
139
+ generate_content_config = types.GenerateContentConfig(
140
+ temperature=0.0,
141
+ top_p=0.95,
142
+ max_output_tokens=8192,
143
+ tools=tools,
144
+ )
145
+
146
+ # Wygeneruj odpowiedź (bez streamingu)
147
+ response = client.models.generate_content(
148
+ model=model,
149
+ contents=prompt,
150
+ config=generate_content_config,
151
+ )
152
+
153
+ if response and response.text:
154
+ # Zbierz źródła z groundingMetadata
155
+ sources = get_sources(response)
156
+
157
+ # Loguj informacje o groundingu
158
+ if (response.candidates and response.candidates[0].grounding_metadata):
159
+ grounding_meta = response.candidates[0].grounding_metadata
160
+ if hasattr(grounding_meta, 'web_search_queries'):
161
+ logger.info(f"Zapytania wyszukiwania: {grounding_meta.web_search_queries}")
162
+ if hasattr(grounding_meta, 'grounding_chunks') and grounding_meta.grounding_chunks:
163
+ logger.info(f"Liczba źródeł: {len(grounding_meta.grounding_chunks)}")
164
+
165
+ # Połącz odpowiedź z sekcją źródeł
166
+ final_result = response.text + format_sources_section(sources)
167
+
168
+ yield final_result
169
+ else:
170
+ yield "❌ **Błąd:** Nie udało się wygenerować streszczenia. Spróbuj ponownie."
171
+
172
+ except Exception as e:
173
+ # Return error message
174
+ yield f"❌ **Błąd:** {str(e)}"
175
+
176
+ with gr.Blocks() as demo:
177
+ _ = gr.Markdown("## Streszczenia newsów\nWklej link do artykułu, a wygeneruję z niego najważniejsze informacje w formie podsumowania i punktów.")
178
+ with gr.Row():
179
+ link_input = gr.Textbox(label="Link do artykułu", placeholder="https://akademiatriathlonu.pl/...")
180
+ output = gr.Markdown(label="Streszczenie")
181
+ submit_btn = gr.Button("Generuj streszczenie")
182
+ _ = submit_btn.click(fn=generate, inputs=[link_input], outputs=[output])
183
+
184
+ _ = demo.launch(show_error=True)