Nguyen5 commited on
Commit
ea9c422
·
1 Parent(s): 99af630
Files changed (1) hide show
  1. app.py +75 -55
app.py CHANGED
@@ -1,3 +1,5 @@
 
 
1
  import os
2
  import gradio as gr
3
  from gradio_pdf import PDF
@@ -13,10 +15,10 @@ from speech_io import transcribe_audio, synthesize_speech
13
 
14
  ASR_LANGUAGE_HINT = os.getenv("ASR_LANGUAGE", "de")
15
 
 
16
  # =====================================================
17
- # BACKEND INITIALIZATION
18
  # =====================================================
19
-
20
  print("📚 Lade Dokumente…")
21
  docs = load_all_documents()
22
 
@@ -43,17 +45,18 @@ hg_url = hg_meta.get("viewer_url")
43
  def format_sources(src):
44
  if not src:
45
  return ""
46
- out = ["", "## 📚 Quellen"]
47
  for s in src:
48
- line = f"- [{s['source']}]({s['url']})"
 
49
  if s.get("page") is not None:
50
  line += f" (Seite {s['page']})"
51
- out.append(line)
52
- return "\n".join(out)
53
 
54
 
55
  # =====================================================
56
- # Core Chat-Funktion
57
  # =====================================================
58
  def chat_fn(text_input, audio_path, history):
59
  text = (text_input or "").strip()
@@ -73,17 +76,21 @@ def chat_fn(text_input, audio_path, history):
73
  ans, sources = answer(text, retriever, llm)
74
  bot_msg = ans + format_sources(sources)
75
 
76
- # Chat format wie ChatGPT
77
  history = history + [
78
  {"role": "user", "content": text},
79
  {"role": "assistant", "content": bot_msg},
80
  ]
81
 
82
- tts_audio = synthesize_speech(bot_msg)
 
83
 
84
- return history, tts_audio, "", None
85
 
86
 
 
 
 
87
  def read_last_answer(history):
88
  if not history:
89
  return None
@@ -94,85 +101,95 @@ def read_last_answer(history):
94
 
95
 
96
  # =====================================================
97
- # UI – ChatGPT-STYLE
98
  # =====================================================
99
  CUSTOM_CSS = """
100
- /* === GLOBAL BACKGROUND === */
 
 
101
  body {
102
  background-color: #f0f0f0 !important;
103
  }
104
 
105
- /* === CENTER CHAT AREA LIKE CHATGPT === */
106
  .gradio-container {
107
  max-width: 820px !important;
108
  margin: 0 auto !important;
109
- padding-bottom: 120px !important; /* Platz für Input-Bar */
110
  }
111
 
112
- /* === CHAT BUBBLES === */
113
  .chatbot .message.user {
114
- background-color: #ffffff !important;
115
- color: #000 !important;
116
- border-radius: 12px !important;
117
- padding: 12px 14px !important;
 
118
  max-width: 85% !important;
119
  }
120
 
121
  .chatbot .message.assistant {
122
  background-color: #e6e6e6 !important;
123
- color: #000 !important;
124
- border-radius: 12px !important;
125
- padding: 12px 14px !important;
 
126
  max-width: 85% !important;
127
  }
128
 
129
- /* === INPUT BAR FIXED AT BOTTOM LIKE CHATGPT === */
130
  #input-bar {
131
  position: fixed !important;
132
  bottom: 0;
133
  left: 0;
134
  right: 0;
135
- background: #ffffff;
136
  padding: 14px 20px;
137
- box-shadow: 0 -2px 10px rgba(0,0,0,0.08);
138
  display: flex;
139
- gap: 10px;
140
  align-items: center;
141
  z-index: 999;
142
  }
143
 
144
  #input-text textarea {
145
- min-height: 50px !important;
146
- resize: none;
147
  }
148
 
 
149
  .send-btn {
150
  background-color: #0b57d0 !important;
151
  color: white !important;
152
  border-radius: 8px !important;
153
- height: 50px !important;
154
  }
155
 
156
- /* Microphone button round */
157
  .mic-btn button {
158
  border-radius: 50% !important;
159
- width: 50px !important;
160
- height: 50px !important;
161
  }
 
 
162
  """
163
 
164
 
165
- with gr.Blocks(css=CUSTOM_CSS, title="Prüfungsrechts-Chatbot") as demo:
 
 
 
 
 
 
166
 
167
  # Titel
 
168
  gr.Markdown(
169
- "<h1 style='text-align:center;'>🧑‍⚖️ Prüfungsrechts-Chatbot</h1>",
170
- )
171
- gr.Markdown(
172
- "<p style='text-align:center;'>Fragen zur Prüfungsordnung & zum Hochschulgesetz NRW – wie ChatGPT, aber spezialisiert.</p>"
173
  )
174
 
175
- # CHAT WINDOW (groß, wie ChatGPT)
176
  chatbot = gr.Chatbot(
177
  label="Chat",
178
  elem_classes=["chatbot"],
@@ -180,22 +197,18 @@ with gr.Blocks(css=CUSTOM_CSS, title="Prüfungsrechts-Chatbot") as demo:
180
  show_label=False,
181
  )
182
 
183
- voice_out = gr.Audio(
184
- label="Vorgelesene Antwort",
185
- type="numpy",
186
- interactive=False,
187
- visible=False,
188
- )
189
 
190
- # FIXED INPUT BAR = CHATGPT
191
  with gr.Row(elem_id="input-bar"):
192
  chat_text = gr.Textbox(
193
- placeholder="Frag etwas oder nutze das Mikrofon…",
194
  label=None,
195
- lines=1,
196
  elem_id="input-text",
 
197
  scale=10,
198
  )
 
199
  chat_audio = gr.Audio(
200
  sources=["microphone"],
201
  type="filepath",
@@ -203,9 +216,10 @@ with gr.Blocks(css=CUSTOM_CSS, title="Prüfungsrechts-Chatbot") as demo:
203
  elem_classes=["mic-btn"],
204
  scale=1,
205
  )
 
206
  send_btn = gr.Button("Senden", elem_classes=["send-btn"], scale=2)
207
 
208
- # Input logic
209
  chat_text.submit(
210
  chat_fn,
211
  [chat_text, chat_audio, chatbot],
@@ -222,19 +236,25 @@ with gr.Blocks(css=CUSTOM_CSS, title="Prüfungsrechts-Chatbot") as demo:
222
  [chatbot, voice_out, chat_text, chat_audio],
223
  )
224
 
225
- # Read button (optional)
226
- read_btn = gr.Button("🔁 Antwort erneut vorlesen")
227
- read_btn.click(read_last_answer, [chatbot], [voice_out])
 
228
 
229
- # Quellen & Dokumente unten
230
  with gr.Accordion("📄 Quellen & Dokumente", open=False):
231
- gr.Markdown("### Prüfungsordnung")
232
  PDF(pdf_meta["pdf_url"], height=250)
 
233
  gr.Markdown("### Hochschulgesetz NRW")
234
  if isinstance(hg_url, str) and hg_url.startswith("http"):
235
- gr.Markdown(f"[Viewer öffnen]({hg_url})")
236
  else:
237
- gr.Markdown("Viewer nicht verfügbar.")
 
238
 
 
 
 
239
  if __name__ == "__main__":
240
  demo.queue().launch(ssr_mode=False, show_error=True)
 
1
+ # app.py – Prüfungsrechts-Chatbot (RAG + Sprache) – UI kiểu ChatGPT
2
+
3
  import os
4
  import gradio as gr
5
  from gradio_pdf import PDF
 
15
 
16
  ASR_LANGUAGE_HINT = os.getenv("ASR_LANGUAGE", "de")
17
 
18
+
19
  # =====================================================
20
+ # INITIALISIERUNG
21
  # =====================================================
 
22
  print("📚 Lade Dokumente…")
23
  docs = load_all_documents()
24
 
 
45
  def format_sources(src):
46
  if not src:
47
  return ""
48
+ lines = ["", "## 📚 Quellen"]
49
  for s in src:
50
+ url = s["url"]
51
+ line = f"- [{s['source']}]({url})"
52
  if s.get("page") is not None:
53
  line += f" (Seite {s['page']})"
54
+ lines.append(line)
55
+ return "\n".join(lines)
56
 
57
 
58
  # =====================================================
59
+ # Chat-Funktion
60
  # =====================================================
61
  def chat_fn(text_input, audio_path, history):
62
  text = (text_input or "").strip()
 
76
  ans, sources = answer(text, retriever, llm)
77
  bot_msg = ans + format_sources(sources)
78
 
79
+ # Neues Chat-Element
80
  history = history + [
81
  {"role": "user", "content": text},
82
  {"role": "assistant", "content": bot_msg},
83
  ]
84
 
85
+ # TTS
86
+ tts = synthesize_speech(bot_msg)
87
 
88
+ return history, tts, "", None
89
 
90
 
91
+ # =====================================================
92
+ # Button: Antwort erneut vorlesen
93
+ # =====================================================
94
  def read_last_answer(history):
95
  if not history:
96
  return None
 
101
 
102
 
103
  # =====================================================
104
+ # CSSUI giống ChatGPT
105
  # =====================================================
106
  CUSTOM_CSS = """
107
+ <style>
108
+
109
+ /* === Hintergrund wie ChatGPT === */
110
  body {
111
  background-color: #f0f0f0 !important;
112
  }
113
 
114
+ /* === Zentralisiertes Chat-Fenster === */
115
  .gradio-container {
116
  max-width: 820px !important;
117
  margin: 0 auto !important;
118
+ padding-bottom: 120px !important;
119
  }
120
 
121
+ /* === ChatGPT Bubble-Style === */
122
  .chatbot .message.user {
123
+ background-color: white !important;
124
+ color: black !important;
125
+ border-radius: 14px !important;
126
+ padding: 12px 16px !important;
127
+ margin-bottom: 10px !important;
128
  max-width: 85% !important;
129
  }
130
 
131
  .chatbot .message.assistant {
132
  background-color: #e6e6e6 !important;
133
+ color: black !important;
134
+ border-radius: 14px !important;
135
+ padding: 12px 16px !important;
136
+ margin-bottom: 10px !important;
137
  max-width: 85% !important;
138
  }
139
 
140
+ /* === Input Bar giống ChatGPT === */
141
  #input-bar {
142
  position: fixed !important;
143
  bottom: 0;
144
  left: 0;
145
  right: 0;
146
+ background: white;
147
  padding: 14px 20px;
148
+ box-shadow: 0 -2px 10px rgba(0,0,0,0.1);
149
  display: flex;
150
+ gap: 12px;
151
  align-items: center;
152
  z-index: 999;
153
  }
154
 
155
  #input-text textarea {
156
+ min-height: 52px !important;
157
+ resize: none !important;
158
  }
159
 
160
+ /* Send Button giống ChatGPT */
161
  .send-btn {
162
  background-color: #0b57d0 !important;
163
  color: white !important;
164
  border-radius: 8px !important;
165
+ height: 52px !important;
166
  }
167
 
168
+ /* Microphone Button Rund */
169
  .mic-btn button {
170
  border-radius: 50% !important;
171
+ width: 52px !important;
172
+ height: 52px !important;
173
  }
174
+
175
+ </style>
176
  """
177
 
178
 
179
+ # =====================================================
180
+ # UI – Gradio Blocks
181
+ # =====================================================
182
+ with gr.Blocks(title="Prüfungsrechts-Chatbot") as demo:
183
+
184
+ # CSS injizieren
185
+ gr.HTML(CUSTOM_CSS)
186
 
187
  # Titel
188
+ gr.Markdown("<h1 style='text-align:center;'>🧑‍⚖️ Prüfungsrechts-Chatbot</h1>")
189
  gr.Markdown(
190
+ "<p style='text-align:center;'>Ein Chatbot speziell für Prüfungsordnung & Hochschulgesetz NRW – mit Spracheingabe wie ChatGPT.</p>"
 
 
 
191
  )
192
 
 
193
  chatbot = gr.Chatbot(
194
  label="Chat",
195
  elem_classes=["chatbot"],
 
197
  show_label=False,
198
  )
199
 
200
+ voice_out = gr.Audio(type="numpy", visible=False)
 
 
 
 
 
201
 
202
+ # === ChatGPT Input Bar ===
203
  with gr.Row(elem_id="input-bar"):
204
  chat_text = gr.Textbox(
205
+ placeholder="Frage eingeben oder Mikrofon benutzen…",
206
  label=None,
 
207
  elem_id="input-text",
208
+ lines=1,
209
  scale=10,
210
  )
211
+
212
  chat_audio = gr.Audio(
213
  sources=["microphone"],
214
  type="filepath",
 
216
  elem_classes=["mic-btn"],
217
  scale=1,
218
  )
219
+
220
  send_btn = gr.Button("Senden", elem_classes=["send-btn"], scale=2)
221
 
222
+ # Events – Text + Audio
223
  chat_text.submit(
224
  chat_fn,
225
  [chat_text, chat_audio, chatbot],
 
236
  [chatbot, voice_out, chat_text, chat_audio],
237
  )
238
 
239
+ # Antwort wiederholen
240
+ gr.Button("🔁 Antwort erneut vorlesen").click(
241
+ read_last_answer, [chatbot], [voice_out]
242
+ )
243
 
244
+ # Quellen-Accordion
245
  with gr.Accordion("📄 Quellen & Dokumente", open=False):
246
+ gr.Markdown("### Prüfungsordnung (PDF)")
247
  PDF(pdf_meta["pdf_url"], height=250)
248
+
249
  gr.Markdown("### Hochschulgesetz NRW")
250
  if isinstance(hg_url, str) and hg_url.startswith("http"):
251
+ gr.Markdown(f"[Im Viewer öffnen]({hg_url})")
252
  else:
253
+ gr.Markdown("Kein Viewer verfügbar.")
254
+
255
 
256
+ # =====================================================
257
+ # Start
258
+ # =====================================================
259
  if __name__ == "__main__":
260
  demo.queue().launch(ssr_mode=False, show_error=True)