mgokg commited on
Commit
dddd462
·
verified ·
1 Parent(s): 668da24

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +92 -296
app.py CHANGED
@@ -1,312 +1,108 @@
1
  import gradio as gr
2
- import requests
3
  import os
4
- from bs4 import BeautifulSoup
5
 
 
 
 
6
 
7
- def fetch_ai_overview(query: str) -> str:
8
- """
9
- Scrapt die Google-Suchergebnisseite und extrahiert den AI Overview (KI-Übersicht).
10
- Gibt den Text zurück oder eine Fehlermeldung.
11
- """
12
- headers = {
13
- "User-Agent": (
14
- "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
15
- "AppleWebKit/537.36 (KHTML, like Gecko) "
16
- "Chrome/124.0.0.0 Safari/537.36"
17
- ),
18
- "Accept-Language": "de-DE,de;q=0.9",
19
- "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
20
- }
21
-
22
- params = {
23
- "q": query,
24
- "hl": "de",
25
- "gl": "de",
26
- }
27
-
28
  try:
29
- resp = requests.get(
30
- "https://duck.ai/duckchat/v1/chat",
31
- headers=headers,
32
- params=params,
33
- timeout=10,
34
  )
35
- resp.raise_for_status()
36
- soup = BeautifulSoup(resp.text, "html.parser")
37
- # Den Body-Tag finden
38
- body = soup.find('body')
39
- clean_text = body.get_text(separator=' ', strip=True)
40
-
41
- return clean_text
42
-
43
- # Google AI Overview sitzt in verschiedenen möglichen Containern.
44
- # Wir probieren mehrere bekannte Selektoren.
45
- ai_selectors = [
46
- # AI Overview Container (neu)
47
- {"class": "Ww4FFb"}, # AI snapshot block
48
- ]
49
-
50
- for sel in ai_selectors:
51
- block = soup.find(attrs=sel)
52
- if block:
53
- text = block.get_text(separator="\n", strip=True)
54
- if len(text) > 50:
55
- return text
56
-
57
- # Fallback: suche nach dem div mit "AI Overview"-Label
58
- for div in soup.find_all("div"):
59
- text = div.get_text(separator="\n", strip=True)
60
- if ("KI-Übersicht" in text or "AI Overview" in text) and len(text) > 100:
61
- # Nimm den nächsten Geschwister-/Kind-Block
62
- siblings = div.find_next_siblings()
63
- if siblings:
64
- sibling_text = "\n".join(
65
- s.get_text(separator="\n", strip=True) for s in siblings[:3]
66
- )
67
- if len(sibling_text) > 100:
68
- return sibling_text
69
- return text
70
-
71
- # Letzter Fallback: gesamter featured snippet / answer box
72
- for sel in [{"class": "hgKElc"}, {"class": "ILfuVd"}, {"class": "c2xzTb"}]:
73
- block = soup.find(attrs=sel)
74
- if block:
75
- text = block.get_text(separator="\n", strip=True)
76
- if len(text) > 50:
77
- return text
78
-
79
- return "ℹ️ Keine KI-Übersicht gefunden. Google zeigt sie möglicherweise nicht für diese Suchanfrage an, oder der Block wurde dynamisch geladen (JavaScript-Rendering erforderlich)."
80
-
81
- except requests.exceptions.Timeout:
82
- return "⏱️ Zeitüberschreitung bei der Google-Anfrage."
83
- except requests.exceptions.HTTPError as e:
84
- return f"HTTP-Fehler: {e.response.status_code}"
85
  except Exception as e:
86
- return f"Fehler: {str(e)}"
87
-
88
-
89
- def google_search(query: str, num_results: int = 5) -> str:
90
- API_KEY = os.environ.get("GOOGLE_API_KEY", "")
91
- CSE_CX = "77f1602c0ff764edb"
92
-
93
- if not API_KEY:
94
- return "❌ Kein API-Key gefunden."
95
- if not query.strip():
96
- return "Bitte gib einen Suchbegriff ein."
97
-
98
- # --- KI-Übersicht scrapen ---
99
- ai_text = fetch_ai_overview(query)
100
- ai_section = f"## 🤖 KI-Übersicht\n\n{ai_text}\n\n---\n\n"
101
-
102
- # --- Normale Suchergebnisse via API ---
103
- try:
104
- resp = requests.get(
105
- "https://www.googleapis.com/customsearch/v1",
106
- params={
107
- "key": API_KEY,
108
- "cx": CSE_CX,
109
- "q": query,
110
- "num": max(1, min(int(num_results), 10)),
111
- },
112
- timeout=8,
113
- )
114
- resp.raise_for_status()
115
- data = resp.json()
116
- items = data.get("items", [])
117
-
118
- if not items:
119
- return ai_section + "Keine weiteren Suchergebnisse gefunden."
120
-
121
- snippets = []
122
- for item in items:
123
- title = item.get("title", "")
124
- link = item.get("link", "")
125
- snippet = item.get("snippet", "").replace("\n", " ")
126
- snippets.append(f"### {title}\n**URL:** {link}\n\n{snippet}")
127
-
128
- return ai_section + "\n\n---\n\n".join(snippets)
129
-
130
- except requests.exceptions.HTTPError as e:
131
- return ai_section + f"HTTP-Fehler: {e.response.status_code} – {e.response.text}"
132
- except requests.exceptions.Timeout:
133
- return ai_section + "Zeitüberschreitung bei der API-Anfrage."
134
- except Exception as e:
135
- return ai_section + f"Google-Suchfehler: {str(e)}"
136
-
137
-
138
- demo = gr.Interface(
139
- fn=google_search,
140
- inputs=[
141
- gr.Textbox(label="Suchanfrage", placeholder="Wonach suchst du?"),
142
- gr.Slider(minimum=1, maximum=10, value=5, step=1, label="Anzahl Ergebnisse"),
143
- ],
144
- outputs=gr.Markdown(label="Ergebnisse"),
145
- )
146
-
147
- if __name__ == "__main__":
148
- demo.launch()
149
-
150
-
151
-
152
-
153
-
154
  """
155
 
156
- import gradio as gr
157
- import requests
158
- import os
159
- from bs4 import BeautifulSoup
160
-
161
-
162
- def fetch_body_text(url: str, timeout: int = 6) -> str:
163
-
164
- try:
165
- headers = {"User-Agent": "Mozilla/5.0 (compatible; GoogleSearchBot/1.0)"}
166
- resp = requests.get(url, headers=headers, timeout=timeout)
167
- resp.raise_for_status()
168
- soup = BeautifulSoup(resp.text, "html.parser")
169
-
170
- # Remove script/style tags before extracting text
171
- for tag in soup(["script", "style", "noscript", "head"]):
172
- tag.decompose()
173
-
174
- body = soup.body
175
- if body:
176
- text = body.get_text(separator="\n", strip=True)
177
- else:
178
- text = soup.get_text(separator="\n", strip=True)
179
 
180
- # Collapse excessive blank lines
181
- lines = [line for line in text.splitlines() if line.strip()]
182
- return "\n".join(lines)
183
-
184
- except Exception as e:
185
- return f"⚠️ Konnte Seite nicht laden: {e}"
186
 
 
 
187
 
188
- def google_search(query: str, num_results: int = 5) -> str:
189
- API_KEY = os.environ.get("GOOGLE_API_KEY", "")
190
- CSE_CX = "77f1602c0ff764edb"
191
-
192
- if not API_KEY:
193
- return "❌ Kein API-Key gefunden. Bitte `GOOGLE_API_KEY` als Umgebungsvariable setzen."
194
- if not query.strip():
195
- return "Bitte gib einen Suchbegriff ein."
196
-
197
- try:
198
- resp = requests.get(
199
- "https://www.googleapis.com/customsearch/v1",
200
- params={
201
- "key": API_KEY,
202
- "cx": CSE_CX,
203
- "q": query,
204
- "num": max(1, min(int(num_results), 10)),
205
- },
206
- timeout=8,
207
  )
208
- resp.raise_for_status()
209
- data = resp.json()
210
- items = data.get("items", [])
211
-
212
- if not items:
213
- return "Keine Suchergebnisse gefunden."
214
-
215
- results = []
216
- for item in items:
217
- title = item.get("title", "")
218
- link = item.get("link", "")
219
-
220
- body_text = fetch_body_text(link)
221
-
222
- results.append(
223
- f"### {title}\n"
224
- f"**URL:** {link}\n\n"
225
- f"```\n{body_text[:3000]}\n```" # cap per result to avoid huge output
226
- )
227
-
228
- return "\n\n---\n\n".join(results)
229
-
230
- except requests.exceptions.HTTPError as e:
231
- return f"HTTP-Fehler: {e.response.status_code} – {e.response.text}"
232
- except requests.exceptions.Timeout:
233
- return "Zeitüberschreitung bei der Anfrage. Bitte erneut versuchen."
234
- except Exception as e:
235
- return f"Google-Suchfehler: {str(e)}"
236
-
237
-
238
- demo = gr.Interface(
239
- fn=google_search,
240
- inputs=[
241
- gr.Textbox(label="Suchanfrage", placeholder="Wonach suchst du?"),
242
- gr.Slider(minimum=1, maximum=10, value=5, step=1, label="Anzahl Ergebnisse"),
243
- ],
244
- outputs=gr.Markdown(label="Ergebnisse"),
245
- )
246
 
247
- if __name__ == "__main__":
248
- demo.launch()
249
-
250
-
251
-
252
-
253
- import gradio as gr
254
- import requests
255
- import os
256
-
257
- def google_search(query: str, num_results: int = 5) -> str:
258
- API_KEY = os.environ.get("GOOGLE_API_KEY", "")
259
- CSE_CX = "77f1602c0ff764edb"
260
-
261
- if not API_KEY:
262
- return "❌ Kein API-Key gefunden. Bitte `GOOGLE_API_KEY` als Umgebungsvariable setzen."
263
- if not query.strip():
264
- return "Bitte gib einen Suchbegriff ein."
265
-
266
- try:
267
- resp = requests.get(
268
- "https://www.googleapis.com/customsearch/v1",
269
- params={
270
- "key": API_KEY,
271
- "cx": CSE_CX,
272
- "q": query,
273
- "num": max(1, min(int(num_results), 10)),
274
- },
275
- timeout=8,
276
  )
277
- resp.raise_for_status()
278
- data = resp.json()
279
- items = data.get("items", [])
280
- print(data)
281
- if not items:
282
- return "Keine Suchergebnisse gefunden."
283
-
284
- snippets = []
285
- for item in items:
286
- title = item.get("title", "")
287
- link = item.get("link", "")
288
- snippet = item.get("snippet", "").replace("\n", " ")
289
- snippets.append(f"### {title}\nURL: {link}\n\n{snippet}")
290
-
291
- return "\n\n---\n\n".join(snippets)
292
-
293
- except requests.exceptions.HTTPError as e:
294
- return f"HTTP-Fehler: {e.response.status_code} – {e.response.text}"
295
- except requests.exceptions.Timeout:
296
- return "Zeitüberschreitung bei der Anfrage. Bitte erneut versuchen."
297
- except Exception as e:
298
- return f"Google-Suchfehler: {str(e)}"
299
-
300
-
301
- demo = gr.Interface(
302
- fn=google_search,
303
- inputs=[
304
- gr.Textbox(label="Suchanfrage", placeholder="Wonach suchst du?"),
305
- gr.Slider(minimum=1, maximum=10, value=5, step=1, label="Anzahl Ergebnisse"),
306
- ],
307
- outputs=gr.Markdown(label="Ergebnisse"),
308
- )
309
 
310
- if __name__ == "__main__":
311
- demo.launch()
312
- """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import gradio as gr
2
+ from litellm import completion
3
  import os
 
4
 
5
+ # Puter API Konfiguration
6
+ PUTER_TOKEN = os.getenv("PUTER_API_KEY")
7
+ PUTER_API_BASE = "https://api.puter.com/puterai/openai/v1/"
8
 
9
+ def respond(message, history, model):
10
+ if history is None:
11
+ history = []
12
+ messages = [{"role": "user", "content": message}]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  try:
14
+ response = completion(
15
+ model=f"openai/{model}",
16
+ messages=messages,
17
+ api_key=PUTER_TOKEN,
18
+ api_base=PUTER_API_BASE,
19
  )
20
+ assistant_reply = response.choices[0].message.content
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  except Exception as e:
22
+ assistant_reply = f"**Fehler:** {str(e)}"
23
+ history.append((message, assistant_reply))
24
+ chat_md = "\n\n".join(
25
+ [f"**User:** {u}\n\n**Assistant:** {a}" for u, a in history]
26
+ )
27
+ return chat_md, history, ""
28
+
29
+ css = """
30
+ :root { color-scheme: dark; }
31
+ body, .gradio-container {
32
+ background: #0f1115 !important;
33
+ color: #e6e6e6 !important;
34
+ font-family: 'Inter', system-ui, -apple-system, sans-serif;
35
+ }
36
+ #title {
37
+ font-size: 1.8rem;
38
+ font-weight: 700;
39
+ margin-bottom: 0.4rem;
40
+ }
41
+ #subtitle {
42
+ color: #b3b3b3;
43
+ margin-bottom: 1.2rem;
44
+ }
45
+ .gr-box, .gr-input, .gr-textbox, .gr-dropdown {
46
+ background: #151823 !important;
47
+ border: 1px solid #2a2f3a !important;
48
+ color: #e6e6e6 !important;
49
+ border-radius: 12px !important;
50
+ }
51
+ .gr-button {
52
+ background: linear-gradient(135deg, #6c5ce7, #00d2ff) !important;
53
+ color: #fff !important;
54
+ border-radius: 12px !important;
55
+ border: none !important;
56
+ font-weight: 600 !important;
57
+ }
58
+ .gr-button:hover {
59
+ filter: brightness(1.08);
60
+ }
61
+ #output-markdown {
62
+ background: #11141b !important;
63
+ border: 1px solid #2a2f3a !important;
64
+ border-radius: 16px !important;
65
+ padding: 16px !important;
66
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  """
68
 
69
+ # css passed to gr.Blocks, not demo.launch()
70
+ with gr.Blocks(css=css) as demo:
71
+ gr.Markdown("# puter.js in Python via LiteLLM", elem_id="title")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
 
73
+ # state declared INSIDE gr.Blocks before it's referenced
74
+ state = gr.State([])
 
 
 
 
75
 
76
+ with gr.Row():
77
+ output = gr.Markdown(value="", elem_id="output-markdown")
78
 
79
+ with gr.Row():
80
+ model = gr.Dropdown(
81
+ choices=["gpt-4o-mini", "gpt-5.2-codex", "claude-sonnet-4", "gemini-2.5-flash"],
82
+ value="gpt-4o-mini",
83
+ label="Modell auswählen"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
 
86
+ with gr.Row():
87
+ msg = gr.Textbox(
88
+ label="Deine Nachricht",
89
+ placeholder="Schreibe hier...",
90
+ lines=2,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
 
93
+ with gr.Row():
94
+ submit_btn = gr.Button("Senden")
95
+
96
+ # ✅ state now exists when referenced here
97
+ submit_btn.click(
98
+ fn=respond,
99
+ inputs=[msg, state, model],
100
+ outputs=[output, state, msg]
101
+ )
102
+ msg.submit(
103
+ fn=respond,
104
+ inputs=[msg, state, model],
105
+ outputs=[output, state, msg]
106
+ )
107
+
108
+ demo.launch()