Upload 18 files
Browse filesUpload Calm.i Chatbot Update
- .gitattributes +4 -0
- README.md +13 -0
- app.py +1743 -0
- assets/background_image/hintergrund.jpg +3 -0
- assets/chat_icons/human.png +0 -0
- assets/chat_icons/robot.png +0 -0
- assets/home_screen/home_screen.png +3 -0
- assets/home_screen/home_screen2.png +3 -0
- assets/home_screen/home_screen3.png +3 -0
- assets/logo/logo.png +0 -0
- assets/tab_icons/chat.png +0 -0
- assets/tab_icons/home.png +0 -0
- assets/tab_icons/mediensammlung.png +0 -0
- assets/tab_icons/notfallplan.png +0 -0
- assets/tab_icons/schlafplan.png +0 -0
- assets/tab_icons/timemanagement.png +0 -0
- requirements.txt +4 -0
- style.css +43 -0
- theme.py +14 -0
.gitattributes
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
assets/background_image/hintergrund.jpg filter=lfs diff=lfs merge=lfs -text
|
| 2 |
+
assets/home_screen/home_screen.png filter=lfs diff=lfs merge=lfs -text
|
| 3 |
+
assets/home_screen/home_screen2.png filter=lfs diff=lfs merge=lfs -text
|
| 4 |
+
assets/home_screen/home_screen3.png filter=lfs diff=lfs merge=lfs -text
|
README.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: Calm.i
|
| 3 |
+
emoji: 🏢
|
| 4 |
+
colorFrom: purple
|
| 5 |
+
colorTo: blue
|
| 6 |
+
sdk: gradio
|
| 7 |
+
sdk_version: 6.1.0
|
| 8 |
+
app_file: app.py
|
| 9 |
+
pinned: false
|
| 10 |
+
short_description: chatbot for stress - sleep and panicmanagement
|
| 11 |
+
---
|
| 12 |
+
|
| 13 |
+
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
app.py
ADDED
|
@@ -0,0 +1,1743 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import time
|
| 3 |
+
import gradio as gr
|
| 4 |
+
from openai import OpenAI
|
| 5 |
+
import PyPDF2
|
| 6 |
+
import chromadb
|
| 7 |
+
from chromadb.utils import embedding_functions
|
| 8 |
+
import json
|
| 9 |
+
from concurrent.futures import ThreadPoolExecutor
|
| 10 |
+
|
| 11 |
+
from theme import CustomTheme
|
| 12 |
+
|
| 13 |
+
# Konfiguration
|
| 14 |
+
CONTEXT_SIZE = 30
|
| 15 |
+
CHUNK_SIZE = 100
|
| 16 |
+
CHUNK_OVERLAP = 10
|
| 17 |
+
|
| 18 |
+
# OpenAI Client initialisieren
|
| 19 |
+
client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
|
| 20 |
+
|
| 21 |
+
# ChromaDB initialisieren
|
| 22 |
+
chroma_client = chromadb.PersistentClient(path="./chroma_db")
|
| 23 |
+
openai_ef = embedding_functions.OpenAIEmbeddingFunction(
|
| 24 |
+
api_key=os.environ.get("OPENAI_API_KEY"),
|
| 25 |
+
model_name="text-embedding-3-small"
|
| 26 |
+
)
|
| 27 |
+
|
| 28 |
+
# Globale Variablen für personalisierte Inhalte
|
| 29 |
+
user_profile = {}
|
| 30 |
+
personalized_content = {
|
| 31 |
+
"schlafplan": "",
|
| 32 |
+
"mediensammlung": "",
|
| 33 |
+
"timemanagement": ""
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def chunk_text(text, chunk_size=CHUNK_SIZE, overlap=CHUNK_OVERLAP):
|
| 38 |
+
"""Teilt Text in überlappende Chunks"""
|
| 39 |
+
chunks = []
|
| 40 |
+
start = 0
|
| 41 |
+
while start < len(text):
|
| 42 |
+
end = start + chunk_size
|
| 43 |
+
chunk = text[start:end]
|
| 44 |
+
if chunk.strip():
|
| 45 |
+
chunks.append(chunk)
|
| 46 |
+
start = end - overlap
|
| 47 |
+
return chunks
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
def load_documents_to_vectordb(path="./stress/"):
|
| 51 |
+
"""Lädt Dokumente und speichert sie in ChromaDB"""
|
| 52 |
+
try:
|
| 53 |
+
chroma_client.delete_collection(name="documents")
|
| 54 |
+
except:
|
| 55 |
+
pass
|
| 56 |
+
|
| 57 |
+
collection = chroma_client.create_collection(
|
| 58 |
+
name="documents",
|
| 59 |
+
embedding_function=openai_ef
|
| 60 |
+
)
|
| 61 |
+
|
| 62 |
+
doc_id = 0
|
| 63 |
+
|
| 64 |
+
for filename in os.listdir(path):
|
| 65 |
+
filepath = os.path.join(path, filename)
|
| 66 |
+
|
| 67 |
+
if os.path.isdir(filepath):
|
| 68 |
+
continue
|
| 69 |
+
|
| 70 |
+
print(f"Verarbeite: {filename}")
|
| 71 |
+
|
| 72 |
+
try:
|
| 73 |
+
text = ""
|
| 74 |
+
|
| 75 |
+
if filename.endswith('.pdf'):
|
| 76 |
+
with open(filepath, 'rb') as f:
|
| 77 |
+
pdf_reader = PyPDF2.PdfReader(f)
|
| 78 |
+
for page_num, page in enumerate(pdf_reader.pages, 1):
|
| 79 |
+
page_text = page.extract_text()
|
| 80 |
+
if page_text.strip():
|
| 81 |
+
page_chunks = chunk_text(page_text)
|
| 82 |
+
|
| 83 |
+
for i, chunk in enumerate(page_chunks):
|
| 84 |
+
collection.add(
|
| 85 |
+
documents=[chunk],
|
| 86 |
+
metadatas=[{
|
| 87 |
+
"filename": filename,
|
| 88 |
+
"page": page_num,
|
| 89 |
+
"chunk_id": i,
|
| 90 |
+
"total_chunks": len(page_chunks),
|
| 91 |
+
"source_type": "pdf"
|
| 92 |
+
}],
|
| 93 |
+
ids=[f"doc_{doc_id}"]
|
| 94 |
+
)
|
| 95 |
+
doc_id += 1
|
| 96 |
+
|
| 97 |
+
print(f" → PDF mit {len(pdf_reader.pages)} Seiten verarbeitet")
|
| 98 |
+
|
| 99 |
+
elif filename.endswith(('.txt', '.md')):
|
| 100 |
+
with open(filepath, 'r', encoding='utf-8') as f:
|
| 101 |
+
text = f.read()
|
| 102 |
+
|
| 103 |
+
if text.strip():
|
| 104 |
+
chunks = chunk_text(text)
|
| 105 |
+
|
| 106 |
+
for i, chunk in enumerate(chunks):
|
| 107 |
+
collection.add(
|
| 108 |
+
documents=[chunk],
|
| 109 |
+
metadatas=[{
|
| 110 |
+
"filename": filename,
|
| 111 |
+
"page": "N/A",
|
| 112 |
+
"chunk_id": i,
|
| 113 |
+
"total_chunks": len(chunks),
|
| 114 |
+
"source_type": "text"
|
| 115 |
+
}],
|
| 116 |
+
ids=[f"doc_{doc_id}"]
|
| 117 |
+
)
|
| 118 |
+
doc_id += 1
|
| 119 |
+
|
| 120 |
+
print(f" → {len(chunks)} Chunks erstellt")
|
| 121 |
+
|
| 122 |
+
except Exception as e:
|
| 123 |
+
print(f"Fehler beim Laden von {filename}: {e}")
|
| 124 |
+
|
| 125 |
+
print(f"\nGesamt: {doc_id} Chunks in VectorDB gespeichert")
|
| 126 |
+
return collection
|
| 127 |
+
|
| 128 |
+
|
| 129 |
+
def get_relevant_context(query, collection, n_results=CONTEXT_SIZE):
|
| 130 |
+
"""Sucht die relevantesten Dokument-Chunks für eine Anfrage"""
|
| 131 |
+
results = collection.query(
|
| 132 |
+
query_texts=[query],
|
| 133 |
+
n_results=n_results
|
| 134 |
+
)
|
| 135 |
+
|
| 136 |
+
context = ""
|
| 137 |
+
if results['documents']:
|
| 138 |
+
for i, (doc, metadata) in enumerate(zip(results['documents'][0], results['metadatas'][0])):
|
| 139 |
+
if metadata.get('page'):
|
| 140 |
+
source_info = f"{metadata['filename']}, Seite {metadata['page']}"
|
| 141 |
+
else:
|
| 142 |
+
source_info = f"{metadata['filename']}"
|
| 143 |
+
|
| 144 |
+
context += f"\n--- Quelle {i+1}: {source_info} (Chunk {metadata['chunk_id']+1}/{metadata['total_chunks']}) ---\n"
|
| 145 |
+
context += doc + "\n"
|
| 146 |
+
|
| 147 |
+
return context
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
def generate_personalized_content(user_info, content_type, schlafplan_context="", user_wunsch=""):
|
| 151 |
+
"""Generiert personalisierten Content basierend auf Nutzerprofil"""
|
| 152 |
+
|
| 153 |
+
# Basis-Kontext für konsistente Zeiten
|
| 154 |
+
schlafplan_referenz = ""
|
| 155 |
+
if schlafplan_context:
|
| 156 |
+
schlafplan_referenz = f"""
|
| 157 |
+
|
| 158 |
+
WICHTIG - Verwende exakt diese Schlafenszeiten aus dem bereits erstellten Schlafplan:
|
| 159 |
+
{schlafplan_context}
|
| 160 |
+
|
| 161 |
+
Alle Zeitangaben müssen mit diesen Schlafenszeiten übereinstimmen!
|
| 162 |
+
"""
|
| 163 |
+
|
| 164 |
+
# Wunsch-Kontext wenn User Änderungen möchte
|
| 165 |
+
wunsch_kontext = ""
|
| 166 |
+
if user_wunsch:
|
| 167 |
+
wunsch_kontext = f"""
|
| 168 |
+
|
| 169 |
+
WICHTIG - ÄNDERUNGSWUNSCH:
|
| 170 |
+
Der Nutzer möchte folgende Änderung: {user_wunsch}
|
| 171 |
+
Berücksichtige diesen Wunsch bei der Erstellung und passe den Plan entsprechend an!
|
| 172 |
+
"""
|
| 173 |
+
|
| 174 |
+
prompts = {
|
| 175 |
+
"schlafplan": f"""Erstelle einen personalisierten Schlafplan basierend auf folgenden Informationen:
|
| 176 |
+
|
| 177 |
+
Nutzerprofil:
|
| 178 |
+
{json.dumps(user_info, indent=2, ensure_ascii=False)}
|
| 179 |
+
{wunsch_kontext}
|
| 180 |
+
|
| 181 |
+
Erstelle einen konkreten, umsetzbaren Schlafplan mit:
|
| 182 |
+
1. Individuellen Schlafenszeiten basierend auf dem Chronotyp (z.B. "Schlafenszeit: 22:30 Uhr, Aufstehzeit: 6:30 Uhr")
|
| 183 |
+
2. Spezifischen Abendroutinen
|
| 184 |
+
3. Angepassten Tipps für die genannten Schlafprobleme
|
| 185 |
+
4. Konkreten Empfehlungen für die persönliche Situation
|
| 186 |
+
|
| 187 |
+
WICHTIG: Nenne die exakten Uhrzeiten für Schlafenszeit und Aufstehzeit klar und deutlich am Anfang!
|
| 188 |
+
|
| 189 |
+
Formatiere die Antwort in Markdown mit klarer Struktur und praktischen Beispielen.""",
|
| 190 |
+
|
| 191 |
+
"mediensammlung": f"""Erstelle eine personalisierte Medien und Tools basierend auf:
|
| 192 |
+
|
| 193 |
+
Nutzerprofil:
|
| 194 |
+
{json.dumps(user_info, indent=2, ensure_ascii=False)}
|
| 195 |
+
{schlafplan_referenz}
|
| 196 |
+
{wunsch_kontext}
|
| 197 |
+
|
| 198 |
+
Empfehle:
|
| 199 |
+
1. Spezifische Atemübungen für die genannten Probleme
|
| 200 |
+
2. Passende Musik-Playlists und Genres
|
| 201 |
+
3. Geeignete Meditations-Apps und -Techniken
|
| 202 |
+
4. Konkrete Videos/Podcasts mit Links (falls möglich)
|
| 203 |
+
5. Individuell angepasste Entspannungstechniken
|
| 204 |
+
6. Buchempfehlungen zu Stressbewältigung, Achtsamkeit, Schlaf oder den genannten Themen (mit Autor und kurzer Beschreibung warum das Buch passt)
|
| 205 |
+
|
| 206 |
+
Formatiere in Markdown mit praktischen Links und Zeitangaben.""",
|
| 207 |
+
|
| 208 |
+
"timemanagement": f"""Erstelle einen personalisierten Time-Management-Plan:
|
| 209 |
+
|
| 210 |
+
Nutzerprofil:
|
| 211 |
+
{json.dumps(user_info, indent=2, ensure_ascii=False)}
|
| 212 |
+
{schlafplan_referenz}
|
| 213 |
+
{wunsch_kontext}
|
| 214 |
+
|
| 215 |
+
Entwickle:
|
| 216 |
+
1. **Tagesplan als Markdown-Tabelle** mit folgender Struktur:
|
| 217 |
+
| Uhrzeit | Tätigkeit | Hinweise |
|
| 218 |
+
|---------|-----------|----------|
|
| 219 |
+
(Fülle mit konkreten Zeiten vom Aufstehen bis Schlafenszeit basierend auf dem Schlafplan)
|
| 220 |
+
|
| 221 |
+
2. Priorisierungssystem für die persönliche Situation
|
| 222 |
+
3. Konkrete Techniken gegen Prokrastination
|
| 223 |
+
4. Pausen- und Energiemanagement-Plan
|
| 224 |
+
5. Realistische Ziele und Tracking-Methoden
|
| 225 |
+
|
| 226 |
+
WICHTIG:
|
| 227 |
+
- Der Tagesplan muss mit den Schlafenszeiten aus dem Schlafplan übereinstimmen!
|
| 228 |
+
- Die Tabelle MUSS in Markdown-Format sein mit | als Trennzeichen
|
| 229 |
+
|
| 230 |
+
Formatiere in Markdown mit der Tabelle am Anfang und den weiteren Tipps darunter."""
|
| 231 |
+
}
|
| 232 |
+
|
| 233 |
+
try:
|
| 234 |
+
response = client.chat.completions.create(
|
| 235 |
+
model="gpt-4o-mini",
|
| 236 |
+
messages=[
|
| 237 |
+
{"role": "system", "content": "Du bist ein Experte für personalisierte Selbsthilfe-Pläne. Erstelle praktische, umsetzbare und wissenschaftlich fundierte Empfehlungen."},
|
| 238 |
+
{"role": "user", "content": prompts[content_type]}
|
| 239 |
+
],
|
| 240 |
+
temperature=0.7,
|
| 241 |
+
max_tokens=2000
|
| 242 |
+
)
|
| 243 |
+
return response.choices[0].message.content
|
| 244 |
+
except Exception as e:
|
| 245 |
+
print(f"Fehler bei Personalisierung: {e}")
|
| 246 |
+
return "Personalisierung konnte nicht erstellt werden. Bitte versuche es später erneut."
|
| 247 |
+
|
| 248 |
+
|
| 249 |
+
def collect_user_info(message, history):
|
| 250 |
+
"""Sammelt Nutzerinformationen für Personalisierung"""
|
| 251 |
+
global user_profile, personalized_content, logo_inline_html
|
| 252 |
+
|
| 253 |
+
# Fragen-Flow
|
| 254 |
+
questions = [
|
| 255 |
+
"Hallo! Ich bin calm.i\n\nUm dir die bestmögliche Unterstützung zu bieten, würde ich dich gerne besser kennenlernen. Das dauert nur 2-3 Minuten.\n\n**Frage 1/7:** Wie heißt du? (Oder wie möchtest du genannt werden?)",
|
| 256 |
+
|
| 257 |
+
"**Frage 2/7:** Bist du eher ein Morgenmensch oder Nachtmensch?\n\n(Wann fühlst du dich am produktivsten?)",
|
| 258 |
+
|
| 259 |
+
"**Frage 3/7:** Wie sieht dein aktueller Schlaf aus?\n\n- Wie viele Stunden schläfst du durchschnittlich?\n- Hast du Einschlaf- oder Durchschlafprobleme?",
|
| 260 |
+
|
| 261 |
+
"**Frage 4/7:** Was sind deine größten Stressquellen im Alltag?\n\n(z.B. Arbeit, Studium, Familie, Gesundheit...)",
|
| 262 |
+
|
| 263 |
+
"**Frage 5/7:** Hast du bereits Erfahrungen mit Entspannungstechniken?\n\n(z.B. Meditation, Atemübungen, Progressive Muskelentspannung...)",
|
| 264 |
+
|
| 265 |
+
"**Frage 6/7:** Wie viel Zeit hast du täglich für Selbstfürsorge?\n\n(Realistisch betrachtet - 10 Min, 30 Min, 1 Stunde?)",
|
| 266 |
+
|
| 267 |
+
"**Frage 7/7:** Gibt es spezielle Themen, bei denen du Unterstützung brauchst?\n\n(z.B. Zeitmanagement, Schlafprobleme, Panikattacken, Prüfungsangst...)"
|
| 268 |
+
]
|
| 269 |
+
|
| 270 |
+
# Initialisierung beim ersten Aufruf (User sagt "ja" oder ähnliches)
|
| 271 |
+
if 'question_count' not in user_profile:
|
| 272 |
+
message_lower = message.lower().strip()
|
| 273 |
+
# Prüfe ob Nutzer den Test machen möchte
|
| 274 |
+
if any(word in message_lower for word in ['ja', 'los', 'geht', 'gerne', 'okay', 'ok', 'klar', 'start']):
|
| 275 |
+
user_profile['question_count'] = 0
|
| 276 |
+
user_profile['answers'] = []
|
| 277 |
+
return questions[0] # Starte mit Frage 1/7 (Name)
|
| 278 |
+
# Prüfe ob Nutzer den Test überspringen möchte
|
| 279 |
+
elif any(word in message_lower for word in ['nicht', 'später', 'nein', 'skip', 'überspringen']):
|
| 280 |
+
user_profile['personalization_done'] = True
|
| 281 |
+
user_profile['test_skipped'] = True
|
| 282 |
+
user_profile['question_count'] = -1 # Markiere als übersprungen
|
| 283 |
+
user_profile['answers'] = []
|
| 284 |
+
return f"Kein Problem! Du kannst den Test jederzeit später machen, indem du mich einfach darum bittest.\n\nWie kann ich dir heute helfen?"
|
| 285 |
+
else:
|
| 286 |
+
# Unklare Antwort - frage nochmal
|
| 287 |
+
user_profile['question_count'] = -1 # Setze auf -1 damit wir wissen dass gefragt wurde
|
| 288 |
+
user_profile['answers'] = []
|
| 289 |
+
return f"Möchtest du den kurzen Fragebogen jetzt ausfüllen?\n\nAntworte einfach mit **\"Ja\"** um zu starten oder **\"Jetzt nicht\"** um direkt zu chatten."
|
| 290 |
+
|
| 291 |
+
# Warte auf Entscheidung für Test (wenn unklare Antwort beim ersten Mal)
|
| 292 |
+
if user_profile['question_count'] == -1:
|
| 293 |
+
message_lower = message.lower().strip()
|
| 294 |
+
# Prüfe ob Nutzer den Test machen möchte
|
| 295 |
+
if any(word in message_lower for word in ['ja', 'los', 'geht', 'gerne', 'okay', 'ok', 'klar', 'start', 'test']):
|
| 296 |
+
user_profile['question_count'] = 0
|
| 297 |
+
return questions[0] # Starte mit Frage 1/7 (Name)
|
| 298 |
+
# Prüfe ob Nutzer den Test überspringen möchte
|
| 299 |
+
elif any(word in message_lower for word in ['nicht', 'später', 'nein', 'skip', 'überspringen']):
|
| 300 |
+
user_profile['personalization_done'] = True
|
| 301 |
+
user_profile['test_skipped'] = True
|
| 302 |
+
return f"Kein Problem! Du kannst den Test jederzeit später machen, indem du mich einfach darum bittest.\n\nWie kann ich dir heute helfen?"
|
| 303 |
+
else:
|
| 304 |
+
# Unklare Antwort - frage nochmal
|
| 305 |
+
return f"Möchtest du den kurzen Fragebogen jetzt ausfüllen?\n\nAntworte einfach mit **\"Ja\"** um zu starten oder **\"Jetzt nicht\"** um direkt zu chatten."
|
| 306 |
+
|
| 307 |
+
# Speichere Antwort (nur wenn Test läuft)
|
| 308 |
+
if user_profile['question_count'] >= 0 and user_profile['question_count'] < len(questions):
|
| 309 |
+
user_profile['answers'].append(message)
|
| 310 |
+
|
| 311 |
+
# Nächste Frage oder Abschluss
|
| 312 |
+
user_profile['question_count'] += 1
|
| 313 |
+
|
| 314 |
+
if user_profile['question_count'] < len(questions):
|
| 315 |
+
return questions[user_profile['question_count']]
|
| 316 |
+
elif user_profile['question_count'] == len(questions):
|
| 317 |
+
# Alle Fragen beantwortet - generiere personalisierten Content DIREKT
|
| 318 |
+
user_info = {
|
| 319 |
+
"name": user_profile['answers'][0],
|
| 320 |
+
"chronotyp": user_profile['answers'][1],
|
| 321 |
+
"schlaf": user_profile['answers'][2],
|
| 322 |
+
"stressquellen": user_profile['answers'][3],
|
| 323 |
+
"erfahrungen": user_profile['answers'][4],
|
| 324 |
+
"zeit": user_profile['answers'][5],
|
| 325 |
+
"themen": user_profile['answers'][6]
|
| 326 |
+
}
|
| 327 |
+
|
| 328 |
+
# Generiere Schlafplan ZUERST (als Basis für konsistente Zeiten)
|
| 329 |
+
print("Generiere personalisierten Schlafplan...")
|
| 330 |
+
personalized_content["schlafplan"] = generate_personalized_content(user_info, "schlafplan")
|
| 331 |
+
|
| 332 |
+
# Dann Medien und Tools und Time Management PARALLEL mit Schlafplan-Kontext
|
| 333 |
+
print("Generiere Medien und Tools und Time Management parallel...")
|
| 334 |
+
with ThreadPoolExecutor(max_workers=2) as executor:
|
| 335 |
+
future_medien = executor.submit(generate_personalized_content, user_info, "mediensammlung", personalized_content["schlafplan"])
|
| 336 |
+
future_time = executor.submit(generate_personalized_content, user_info, "timemanagement", personalized_content["schlafplan"])
|
| 337 |
+
|
| 338 |
+
personalized_content["mediensammlung"] = future_medien.result()
|
| 339 |
+
personalized_content["timemanagement"] = future_time.result()
|
| 340 |
+
|
| 341 |
+
user_profile['personalization_done'] = True
|
| 342 |
+
|
| 343 |
+
return f"""**Fertig, {user_info['name']}!**
|
| 344 |
+
|
| 345 |
+
Deine personalisierten Inhalte sind jetzt verfügbar:
|
| 346 |
+
|
| 347 |
+
**Schlafplan** - Speziell für dich erstellt
|
| 348 |
+
**Medien und Tools** - Angepasst an deine Bedürfnisse
|
| 349 |
+
**Time Management** - Passend zu deinem Tagesrhythmus
|
| 350 |
+
|
| 351 |
+
**Schau sie dir in den entsprechenden Tabs an!**
|
| 352 |
+
|
| 353 |
+
Wie kann ich dir jetzt helfen?"""
|
| 354 |
+
else:
|
| 355 |
+
# Normaler Chat nach Personalisierung
|
| 356 |
+
return None # Signal für normalen Chat
|
| 357 |
+
|
| 358 |
+
|
| 359 |
+
def response(message, history):
|
| 360 |
+
"""Generiert eine Antwort mit OpenAI Streaming und RAG"""
|
| 361 |
+
global user_profile
|
| 362 |
+
|
| 363 |
+
print(f"\n=== RESPONSE CALLED ===")
|
| 364 |
+
print(f"Message: {message}")
|
| 365 |
+
print(f"Question count: {user_profile.get('question_count', 'not set')}")
|
| 366 |
+
print(f"Personalization done: {user_profile.get('personalization_done', 'not set')}")
|
| 367 |
+
|
| 368 |
+
# Standard Tab-Werte (keine Änderung)
|
| 369 |
+
tab_unchanged = gr.update()
|
| 370 |
+
|
| 371 |
+
# Flag um AI-Aufruf zu verhindern
|
| 372 |
+
skip_ai = False
|
| 373 |
+
|
| 374 |
+
# Prüfe ob Personalisierung läuft
|
| 375 |
+
if 'personalization_done' not in user_profile or not user_profile['personalization_done']:
|
| 376 |
+
personalization_response = collect_user_info(message, history)
|
| 377 |
+
print(f"Personalization response: {personalization_response[:100] if personalization_response else 'None'}...")
|
| 378 |
+
if personalization_response:
|
| 379 |
+
skip_ai = True
|
| 380 |
+
# Nach der 7. Frage: Aktualisiere Tabs automatisch
|
| 381 |
+
if personalized_content.get("schlafplan"):
|
| 382 |
+
schlafplan_text = f'<div class="resource-content">\n\n{personalized_content["schlafplan"]}\n\n</div>'
|
| 383 |
+
medien_text = f'<div class="resource-content">\n\n{personalized_content["mediensammlung"]}\n\n</div>'
|
| 384 |
+
time_text = f'<div class="resource-content">\n\n{personalized_content["timemanagement"]}\n\n</div>'
|
| 385 |
+
yield personalization_response, schlafplan_text, medien_text, time_text
|
| 386 |
+
return
|
| 387 |
+
else:
|
| 388 |
+
yield personalization_response, tab_unchanged, tab_unchanged, tab_unchanged
|
| 389 |
+
return
|
| 390 |
+
|
| 391 |
+
# Normaler Chat-Modus
|
| 392 |
+
message_lower = message.lower()
|
| 393 |
+
|
| 394 |
+
# Prüfe ob User den Test später machen möchte (nur wenn noch nicht gemacht)
|
| 395 |
+
if user_profile.get('test_skipped') and any(word in message_lower for word in ['test', 'fragebogen', 'personalisier', 'fragen', 'profil']):
|
| 396 |
+
# Reset für Test - setze question_count zurück aber nicht auf 0 (sonst wird message als Antwort gespeichert)
|
| 397 |
+
user_profile.clear() # Lösche alles
|
| 398 |
+
user_profile['question_count'] = 0
|
| 399 |
+
user_profile['answers'] = []
|
| 400 |
+
user_profile['personalization_done'] = False
|
| 401 |
+
|
| 402 |
+
# Zeige die erste Frage (gleicher Test wie beim Start!)
|
| 403 |
+
first_q = "Hallo! Ich bin calm.i\n\nUm dir die bestmögliche Unterstützung zu bieten, würde ich dich gerne besser kennenlernen. Das dauert nur 2-3 Minuten.\n\n**Frage 1/7:** Wie heißt du? (Oder wie möchtest du genannt werden?)"
|
| 404 |
+
yield first_q, tab_unchanged, tab_unchanged, tab_unchanged
|
| 405 |
+
return
|
| 406 |
+
|
| 407 |
+
# Prüfe ob User Test wiederholen möchte (nachdem Test schon gemacht wurde)
|
| 408 |
+
if user_profile.get('personalization_done') and not user_profile.get('test_skipped'):
|
| 409 |
+
if any(word in message_lower for word in ['test wiederholen', 'fragebogen wiederholen', 'neu starten', 'test nochmal', 'von vorne']):
|
| 410 |
+
# Reset für Test-Wiederholung
|
| 411 |
+
user_profile.clear() # Lösche alles
|
| 412 |
+
user_profile['question_count'] = 0
|
| 413 |
+
user_profile['answers'] = []
|
| 414 |
+
user_profile['personalization_done'] = False
|
| 415 |
+
|
| 416 |
+
# Zeige die erste Frage (gleicher Test wie beim Start!)
|
| 417 |
+
first_q = "Hallo! Ich bin calm.i\n\nUm dir die bestmögliche Unterstützung zu bieten, würde ich dich gerne besser kennenlernen. Das dauert nur 2-3 Minuten.\n\n**Frage 1/7:** Wie heißt du? (Oder wie möchtest du genannt werden?)"
|
| 418 |
+
yield first_q, tab_unchanged, tab_unchanged, tab_unchanged
|
| 419 |
+
return
|
| 420 |
+
|
| 421 |
+
# Prüfe ob User Anpassungen an personalisierten Inhalten möchte
|
| 422 |
+
if user_profile.get('personalization_done') and user_profile.get('answers'):
|
| 423 |
+
# Erkenne welche Art von Änderung (auch ohne explizite Plan-Nennung)
|
| 424 |
+
mentions_name = any(word in message_lower for word in ['name', 'heiße', 'heisse', 'genannt', 'nenne'])
|
| 425 |
+
mentions_chronotyp = any(word in message_lower for word in ['morgenmensch', 'nachtmensch', 'eule', 'lerche', 'chronotyp'])
|
| 426 |
+
mentions_sleep = any(word in message_lower for word in ['schlaf', 'stunden', 'schlafenszeit', 'aufstehzeit', 'einschlafen', 'durchschlafen'])
|
| 427 |
+
mentions_stress = any(word in message_lower for word in ['stress', 'stressquell', 'arbeit', 'familie', 'studium'])
|
| 428 |
+
mentions_time_available = any(word in message_lower for word in ['verfügbar', 'minuten täglich', 'zeit für'])
|
| 429 |
+
mentions_topics = any(word in message_lower for word in ['thema', 'themen', 'fokus', 'unterstützung', 'hilfe bei'])
|
| 430 |
+
|
| 431 |
+
# Erkenne explizite Plan-Nennung
|
| 432 |
+
mentions_schlafplan = any(word in message_lower for word in ['schlafplan'])
|
| 433 |
+
mentions_medien = any(word in message_lower for word in ['mediensammlung', 'medien', 'musik', 'meditation', 'buch', 'bücher'])
|
| 434 |
+
mentions_timeplan = any(word in message_lower for word in ['time management', 'zeitmanagement', 'tagesplan'])
|
| 435 |
+
|
| 436 |
+
# Erkenne ob es eine Änderungsanfrage ist (erweitert!)
|
| 437 |
+
is_update_request = any(word in message_lower for word in ['änder', 'anpass', 'aktualisier', 'modifizier', 'neu', 'anders', 'update', 'jetzt', 'meinte', 'eigentlich', 'korrektur', 'falsch'])
|
| 438 |
+
|
| 439 |
+
# ODER: Wenn User direkt etwas über sich aussagt (z.B. "mein name ist", "ich bin")
|
| 440 |
+
is_direct_statement = any(phrase in message_lower for phrase in ['mein name ist', 'ich heiße', 'ich heisse', 'nenne mich', 'ich bin jetzt', 'ich schlafe jetzt'])
|
| 441 |
+
|
| 442 |
+
# Wenn eine Änderung erkannt wird
|
| 443 |
+
if (is_update_request or is_direct_statement) and (mentions_name or mentions_chronotyp or mentions_sleep or mentions_stress or mentions_time_available or mentions_topics or mentions_schlafplan or mentions_medien or mentions_timeplan):
|
| 444 |
+
# Baue user_info mit aktuellen Daten
|
| 445 |
+
user_info = {
|
| 446 |
+
"name": user_profile['answers'][0],
|
| 447 |
+
"chronotyp": user_profile['answers'][1],
|
| 448 |
+
"schlaf": user_profile['answers'][2],
|
| 449 |
+
"stressquellen": user_profile['answers'][3],
|
| 450 |
+
"erfahrungen": user_profile['answers'][4],
|
| 451 |
+
"zeit": user_profile['answers'][5],
|
| 452 |
+
"themen": user_profile['answers'][6]
|
| 453 |
+
}
|
| 454 |
+
|
| 455 |
+
# Entscheide welche Pläne aktualisiert werden müssen
|
| 456 |
+
update_schlafplan = False
|
| 457 |
+
update_medien = False
|
| 458 |
+
update_time = False
|
| 459 |
+
|
| 460 |
+
# Wenn spezifischer Plan genannt wird
|
| 461 |
+
if mentions_schlafplan:
|
| 462 |
+
update_schlafplan = True
|
| 463 |
+
elif mentions_medien:
|
| 464 |
+
update_medien = True
|
| 465 |
+
elif mentions_timeplan:
|
| 466 |
+
update_time = True
|
| 467 |
+
else:
|
| 468 |
+
# Automatische Zuordnung basierend auf Änderungstyp
|
| 469 |
+
if mentions_name:
|
| 470 |
+
# Name betrifft alle Pläne
|
| 471 |
+
update_schlafplan = update_medien = update_time = True
|
| 472 |
+
elif mentions_chronotyp or mentions_sleep:
|
| 473 |
+
# Chronotyp/Schlaf betrifft Schlafplan und Time Management
|
| 474 |
+
update_schlafplan = True
|
| 475 |
+
update_time = True
|
| 476 |
+
elif mentions_stress or mentions_topics:
|
| 477 |
+
# Stress/Themen betreffen Medien und Tools
|
| 478 |
+
update_medien = True
|
| 479 |
+
elif mentions_time_available:
|
| 480 |
+
# Verfügbare Zeit betrifft Time Management
|
| 481 |
+
update_time = True
|
| 482 |
+
|
| 483 |
+
# Aktualisiere die betroffenen Pläne
|
| 484 |
+
updated_plans = []
|
| 485 |
+
|
| 486 |
+
print(f"\n=== UPDATING PLANS ===")
|
| 487 |
+
print(f"Update Schlafplan: {update_schlafplan}")
|
| 488 |
+
print(f"Update Medien: {update_medien}")
|
| 489 |
+
print(f"Update Time: {update_time}")
|
| 490 |
+
print(f"User message: {message}")
|
| 491 |
+
|
| 492 |
+
# Zeige welche Pläne aktualisiert werden
|
| 493 |
+
plans_to_update = []
|
| 494 |
+
if update_schlafplan:
|
| 495 |
+
plans_to_update.append("Schlafplan")
|
| 496 |
+
if update_medien:
|
| 497 |
+
plans_to_update.append("Medien und Tools")
|
| 498 |
+
if update_time:
|
| 499 |
+
plans_to_update.append("Time Management")
|
| 500 |
+
|
| 501 |
+
if len(plans_to_update) > 1:
|
| 502 |
+
plans_list = ", ".join(plans_to_update)
|
| 503 |
+
yield f"Ich aktualisiere: **{plans_list}**. Das kann einen Moment dauern...", tab_unchanged, tab_unchanged, tab_unchanged
|
| 504 |
+
elif len(plans_to_update) == 1:
|
| 505 |
+
yield f"Ich aktualisiere deinen **{plans_to_update[0]}**...", tab_unchanged, tab_unchanged, tab_unchanged
|
| 506 |
+
|
| 507 |
+
if update_schlafplan:
|
| 508 |
+
print("Generiere Schlafplan...")
|
| 509 |
+
new_schlafplan = generate_personalized_content(user_info, "schlafplan", "", message)
|
| 510 |
+
print(f"Schlafplan generiert! Länge: {len(new_schlafplan)} Zeichen")
|
| 511 |
+
personalized_content["schlafplan"] = new_schlafplan
|
| 512 |
+
schlafplan_text = f'<div class="resource-content">\n\n{new_schlafplan}\n\n</div>'
|
| 513 |
+
updated_plans.append("Schlafplan")
|
| 514 |
+
# Zeige Fortschritt
|
| 515 |
+
if update_medien or update_time:
|
| 516 |
+
yield f"✓ Schlafplan fertig! Arbeite weiter...", schlafplan_text, tab_unchanged, tab_unchanged
|
| 517 |
+
else:
|
| 518 |
+
schlafplan_text = tab_unchanged
|
| 519 |
+
|
| 520 |
+
if update_medien:
|
| 521 |
+
print("Generiere Medien und Tools...")
|
| 522 |
+
new_medien = generate_personalized_content(user_info, "mediensammlung", personalized_content.get("schlafplan", ""), message)
|
| 523 |
+
print(f"Medien und Tools generiert! Länge: {len(new_medien)} Zeichen")
|
| 524 |
+
personalized_content["mediensammlung"] = new_medien
|
| 525 |
+
medien_text = f'<div class="resource-content">\n\n{new_medien}\n\n</div>'
|
| 526 |
+
updated_plans.append("Medien und Tools")
|
| 527 |
+
# Zeige Fortschritt
|
| 528 |
+
if update_time:
|
| 529 |
+
yield f"✓ Medien und Tools fertig! Arbeite weiter...", schlafplan_text, medien_text, tab_unchanged
|
| 530 |
+
else:
|
| 531 |
+
medien_text = tab_unchanged
|
| 532 |
+
|
| 533 |
+
if update_time:
|
| 534 |
+
print("Generiere Time Management...")
|
| 535 |
+
new_time = generate_personalized_content(user_info, "timemanagement", personalized_content.get("schlafplan", ""), message)
|
| 536 |
+
print(f"Time Management generiert! Länge: {len(new_time)} Zeichen")
|
| 537 |
+
personalized_content["timemanagement"] = new_time
|
| 538 |
+
time_text = f'<div class="resource-content">\n\n{new_time}\n\n</div>'
|
| 539 |
+
updated_plans.append("Time Management")
|
| 540 |
+
else:
|
| 541 |
+
time_text = tab_unchanged
|
| 542 |
+
|
| 543 |
+
# Ausgabe
|
| 544 |
+
if len(updated_plans) == 1:
|
| 545 |
+
response_msg = f"Dein **{updated_plans[0]}** wurde aktualisiert! Schau ihn dir im entsprechenden Tab an."
|
| 546 |
+
elif len(updated_plans) > 1:
|
| 547 |
+
plans_str = ", ".join(updated_plans[:-1]) + f" und {updated_plans[-1]}"
|
| 548 |
+
response_msg = f"Deine Pläne (**{plans_str}**) wurden aktualisiert! Schau sie dir in den entsprechenden Tabs an."
|
| 549 |
+
else:
|
| 550 |
+
response_msg = "Ich habe deine Anfrage verstanden, aber konnte keinen Plan zuordnen. Kannst du präziser sagen, welchen Plan ich anpassen soll?"
|
| 551 |
+
|
| 552 |
+
yield response_msg, schlafplan_text, medien_text, time_text
|
| 553 |
+
return
|
| 554 |
+
|
| 555 |
+
context = get_relevant_context(message, collection, n_results=CONTEXT_SIZE)
|
| 556 |
+
|
| 557 |
+
# Füge Nutzerprofil zum Kontext hinzu
|
| 558 |
+
user_context = ""
|
| 559 |
+
if user_profile.get('answers'):
|
| 560 |
+
user_context = f"""
|
| 561 |
+
|
| 562 |
+
NUTZERPROFIL:
|
| 563 |
+
- Name: {user_profile['answers'][0]}
|
| 564 |
+
- Chronotyp: {user_profile['answers'][1]}
|
| 565 |
+
- Schlaf: {user_profile['answers'][2]}
|
| 566 |
+
- Stressquellen: {user_profile['answers'][3]}
|
| 567 |
+
- Erfahrungen: {user_profile['answers'][4]}
|
| 568 |
+
- Verfügbare Zeit: {user_profile['answers'][5]}
|
| 569 |
+
- Fokusthemen: {user_profile['answers'][6]}
|
| 570 |
+
"""
|
| 571 |
+
|
| 572 |
+
system_prompt = f"""Du bist calm.i, ein einfühlsamer Chatbot für Stress- und Selbstfürsorge.
|
| 573 |
+
|
| 574 |
+
KONTEXT:
|
| 575 |
+
---------------------
|
| 576 |
+
{context}
|
| 577 |
+
---------------------
|
| 578 |
+
{user_context}
|
| 579 |
+
|
| 580 |
+
KRITISCH - HÖCHSTE PRIORITÄT:
|
| 581 |
+
Falls es sich um einen AKUTEN NOTFALL wie eine Panikattacke handelt:
|
| 582 |
+
- Antworte SOFORT mit konkreten Lösungsvorschlägen und begrüße den Nutzer NICHT
|
| 583 |
+
- KEINE einleitende Empathie
|
| 584 |
+
- verweise auf die Notfallnummern,
|
| 585 |
+
- MAXIMAL 3 kurze, direkte Handlungsanweisungen
|
| 586 |
+
- Erst danach kannst du einfühlsam nachfragen
|
| 587 |
+
- Falls es sich um ein Thema handelt, welches sich nicht direkt
|
| 588 |
+
um Stress, Schlaf, Panik oder andere mentale Probleme handelt:
|
| 589 |
+
erzähle, dass du für dieses Thema nicht zuständig bist
|
| 590 |
+
|
| 591 |
+
DEINE ROLLE
|
| 592 |
+
- Du kennst den Nutzer bereits durch das Profil
|
| 593 |
+
- Beziehe dich auf seine spezifische Situation
|
| 594 |
+
- Nutze seinen Namen und seine Präferenzen
|
| 595 |
+
- Du bist eine ruhige, verständnisvolle Begleitung
|
| 596 |
+
|
| 597 |
+
KLARE GRENZEN
|
| 598 |
+
- Du bist KEIN Ersatz für Therapie oder ärztliche Behandlung
|
| 599 |
+
- Bei Lebensgefahr: Telefonseelsorge 0800 1110111, Notruf 112
|
| 600 |
+
|
| 601 |
+
SPRACHE & STIL
|
| 602 |
+
- Deutsch, Du-Form
|
| 603 |
+
- verwende empathische Ausdrücke, welche variieren
|
| 604 |
+
- Warm, ruhig, wertschätzend
|
| 605 |
+
- Kurze, klare Sätze
|
| 606 |
+
- Validiere Gefühle
|
| 607 |
+
"""
|
| 608 |
+
|
| 609 |
+
# WICHTIG: Wenn Personalisierung läuft, AI NICHT aufrufen!
|
| 610 |
+
if 'personalization_done' not in user_profile or not user_profile['personalization_done']:
|
| 611 |
+
print("ERROR: AI sollte nicht aufgerufen werden während Personalisierung läuft!")
|
| 612 |
+
return
|
| 613 |
+
|
| 614 |
+
messages = [{"role": "system", "content": system_prompt}]
|
| 615 |
+
|
| 616 |
+
for msg in history:
|
| 617 |
+
if msg["role"] == "user":
|
| 618 |
+
messages.append({"role": "user", "content": msg["content"]})
|
| 619 |
+
elif msg["role"] == "assistant":
|
| 620 |
+
messages.append({"role": "assistant", "content": msg["content"]})
|
| 621 |
+
|
| 622 |
+
messages.append({"role": "user", "content": message})
|
| 623 |
+
|
| 624 |
+
stream = client.chat.completions.create(
|
| 625 |
+
model="gpt-4o-mini",
|
| 626 |
+
messages=messages,
|
| 627 |
+
temperature=0.1,
|
| 628 |
+
stream=True,
|
| 629 |
+
stream_options={"include_usage": True}
|
| 630 |
+
)
|
| 631 |
+
|
| 632 |
+
answer = ""
|
| 633 |
+
|
| 634 |
+
for chunk in stream:
|
| 635 |
+
if hasattr(chunk, 'usage') and chunk.usage:
|
| 636 |
+
print(f"\nToken-Usage: {chunk.usage.total_tokens}")
|
| 637 |
+
|
| 638 |
+
if chunk.choices and len(chunk.choices) > 0 and chunk.choices[0].delta.content:
|
| 639 |
+
text = chunk.choices[0].delta.content
|
| 640 |
+
time.sleep(0.05)
|
| 641 |
+
answer += text
|
| 642 |
+
yield answer, tab_unchanged, tab_unchanged, tab_unchanged
|
| 643 |
+
|
| 644 |
+
|
| 645 |
+
# VectorDB beim Start initialisieren
|
| 646 |
+
print("Initialisiere VectorDB...")
|
| 647 |
+
try:
|
| 648 |
+
collection = chroma_client.get_collection(
|
| 649 |
+
name="documents",
|
| 650 |
+
embedding_function=openai_ef
|
| 651 |
+
)
|
| 652 |
+
print(f"VectorDB geladen mit {collection.count()} Chunks")
|
| 653 |
+
except:
|
| 654 |
+
print("Erstelle neue VectorDB und lade Dokumente...")
|
| 655 |
+
collection = load_documents_to_vectordb()
|
| 656 |
+
|
| 657 |
+
|
| 658 |
+
theme = CustomTheme()
|
| 659 |
+
|
| 660 |
+
def main():
|
| 661 |
+
import base64
|
| 662 |
+
|
| 663 |
+
background_image_base64 = ""
|
| 664 |
+
try:
|
| 665 |
+
with open("./assets/background_image/hintergrund.jpg", "rb") as img_file:
|
| 666 |
+
background_image_base64 = base64.b64encode(img_file.read()).decode('utf-8')
|
| 667 |
+
print("Hintergrundbild geladen")
|
| 668 |
+
except FileNotFoundError:
|
| 669 |
+
print("Warnung: hintergrund.jpg nicht gefunden")
|
| 670 |
+
|
| 671 |
+
home_screen_base64 = ""
|
| 672 |
+
try:
|
| 673 |
+
with open("./assets/home_screen/home_screen.png", "rb") as img_file:
|
| 674 |
+
home_screen_base64 = base64.b64encode(img_file.read()).decode('utf-8')
|
| 675 |
+
print("Home-Screen Bild geladen")
|
| 676 |
+
except FileNotFoundError:
|
| 677 |
+
print("Warnung: home_screen.png nicht gefunden")
|
| 678 |
+
|
| 679 |
+
logo_base64 = ""
|
| 680 |
+
try:
|
| 681 |
+
with open("./assets/logo/logo.png", "rb") as logo_file:
|
| 682 |
+
logo_base64 = base64.b64encode(logo_file.read()).decode('utf-8')
|
| 683 |
+
print("Logo geladen")
|
| 684 |
+
except FileNotFoundError:
|
| 685 |
+
print("Warnung: logo.png nicht gefunden")
|
| 686 |
+
|
| 687 |
+
# Erstelle Logo-HTML für Inline-Verwendung
|
| 688 |
+
global logo_inline_html
|
| 689 |
+
logo_inline_html = f'<img src="data:image/png;base64,{logo_base64}" class="logo-inline" alt="">' if logo_base64 else ""
|
| 690 |
+
|
| 691 |
+
# Lade Tab-Icons
|
| 692 |
+
tab_icons = {}
|
| 693 |
+
icon_names = ["home", "chat", "schlafplan", "mediensammlung", "timemanagement", "notfallplan"]
|
| 694 |
+
for icon_name in icon_names:
|
| 695 |
+
try:
|
| 696 |
+
with open(f"./assets/tab_icons/{icon_name}.png", "rb") as icon_file:
|
| 697 |
+
tab_icons[icon_name] = base64.b64encode(icon_file.read()).decode('utf-8')
|
| 698 |
+
print(f"Icon '{icon_name}' geladen")
|
| 699 |
+
except FileNotFoundError:
|
| 700 |
+
print(f"Warnung: {icon_name}.png nicht gefunden")
|
| 701 |
+
tab_icons[icon_name] = ""
|
| 702 |
+
|
| 703 |
+
custom_css = f"""
|
| 704 |
+
@import url('https://fonts.googleapis.com/css2?family=Nunito:wght@700&display=swap');
|
| 705 |
+
|
| 706 |
+
[class*="gradio-container"] {{
|
| 707 |
+
background: url("data:image/jpeg;base64,{background_image_base64}") no-repeat center center fixed !important;
|
| 708 |
+
background-size: cover !important;
|
| 709 |
+
}}
|
| 710 |
+
|
| 711 |
+
/* Home-Tab: Vollbild-Bild */
|
| 712 |
+
.home-screen-container {{
|
| 713 |
+
position: fixed !important;
|
| 714 |
+
top: 0 !important;
|
| 715 |
+
left: 0 !important;
|
| 716 |
+
width: 100vw !important;
|
| 717 |
+
height: 100vh !important;
|
| 718 |
+
z-index: 50 !important;
|
| 719 |
+
overflow: visible !important;
|
| 720 |
+
pointer-events: none !important;
|
| 721 |
+
}}
|
| 722 |
+
|
| 723 |
+
.home-screen-image {{
|
| 724 |
+
width: 100% !important;
|
| 725 |
+
height: 100% !important;
|
| 726 |
+
object-fit: cover !important;
|
| 727 |
+
pointer-events: none !important;
|
| 728 |
+
}}
|
| 729 |
+
|
| 730 |
+
.home-chat-button {{
|
| 731 |
+
pointer-events: auto !important;
|
| 732 |
+
}}
|
| 733 |
+
|
| 734 |
+
#home {{
|
| 735 |
+
position: relative !important;
|
| 736 |
+
z-index: 1 !important;
|
| 737 |
+
}}
|
| 738 |
+
|
| 739 |
+
/* Tab-Menü über dem Bild und klickbar */
|
| 740 |
+
.tabs, [role="tablist"] {{
|
| 741 |
+
position: relative !important;
|
| 742 |
+
z-index: 100 !important;
|
| 743 |
+
pointer-events: auto !important;
|
| 744 |
+
}}
|
| 745 |
+
|
| 746 |
+
/* Home-Tab Chat-Button */
|
| 747 |
+
.home-chat-button {{
|
| 748 |
+
position: fixed !important;
|
| 749 |
+
bottom: -670px !important;
|
| 750 |
+
left: 63.5% !important;
|
| 751 |
+
transform: translateX(-50%) !important;
|
| 752 |
+
font-family: 'Nunito', sans-serif !important;
|
| 753 |
+
font-weight: 700 !important;
|
| 754 |
+
font-size: 18px !important;
|
| 755 |
+
color: #805EA4 !important;
|
| 756 |
+
background-color: #FBF8FC !important;
|
| 757 |
+
border: none !important;
|
| 758 |
+
border-radius: 15px !important;
|
| 759 |
+
padding: 15px 30px !important;
|
| 760 |
+
cursor: pointer !important;
|
| 761 |
+
z-index: 200 !important;
|
| 762 |
+
pointer-events: auto !important;
|
| 763 |
+
display: block !important;
|
| 764 |
+
visibility: visible !important;
|
| 765 |
+
transition: background-color 0.3s ease !important;
|
| 766 |
+
}}
|
| 767 |
+
|
| 768 |
+
.home-chat-button:hover {{
|
| 769 |
+
background-color: #7E5A9B !important;
|
| 770 |
+
color: #FFFFFF !important;
|
| 771 |
+
}}
|
| 772 |
+
|
| 773 |
+
footer {{
|
| 774 |
+
display: none !important;
|
| 775 |
+
visibility: hidden !important;
|
| 776 |
+
opacity: 0 !important;
|
| 777 |
+
}}
|
| 778 |
+
|
| 779 |
+
.footer {{
|
| 780 |
+
display: none !important;
|
| 781 |
+
}}
|
| 782 |
+
|
| 783 |
+
div.gradio-container footer,
|
| 784 |
+
div.gradio-container .footer,
|
| 785 |
+
[class*="footer"] {{
|
| 786 |
+
display: none !important;
|
| 787 |
+
visibility: hidden !important;
|
| 788 |
+
height: 0 !important;
|
| 789 |
+
overflow: hidden !important;
|
| 790 |
+
}}
|
| 791 |
+
|
| 792 |
+
.gradio-container a[href*="gradio"] {{
|
| 793 |
+
display: none !important;
|
| 794 |
+
}}
|
| 795 |
+
|
| 796 |
+
.contain a {{
|
| 797 |
+
display: none !important;
|
| 798 |
+
}}
|
| 799 |
+
|
| 800 |
+
footer svg {{
|
| 801 |
+
display: none !important;
|
| 802 |
+
}}
|
| 803 |
+
|
| 804 |
+
.gradio-container > div > div:last-child {{
|
| 805 |
+
display: none !important;
|
| 806 |
+
}}
|
| 807 |
+
|
| 808 |
+
[class*="Footer"] {{
|
| 809 |
+
display: none !important;
|
| 810 |
+
}}
|
| 811 |
+
|
| 812 |
+
.wrap.svelte-* footer {{
|
| 813 |
+
display: none !important;
|
| 814 |
+
}}
|
| 815 |
+
|
| 816 |
+
.footer-wrapper,
|
| 817 |
+
.gradio-footer,
|
| 818 |
+
#footer,
|
| 819 |
+
[data-testid="footer"] {{
|
| 820 |
+
display: none !important;
|
| 821 |
+
}}
|
| 822 |
+
|
| 823 |
+
#logo-container {{
|
| 824 |
+
position: fixed !important;
|
| 825 |
+
top: 50px !important;
|
| 826 |
+
left: 20px !important;
|
| 827 |
+
z-index: 2000 !important;
|
| 828 |
+
background: white !important;
|
| 829 |
+
border-radius: 50% !important;
|
| 830 |
+
padding: 1px !important;
|
| 831 |
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15) !important;
|
| 832 |
+
}}
|
| 833 |
+
|
| 834 |
+
#logo-container img {{
|
| 835 |
+
width: 80px !important;
|
| 836 |
+
height: 80px !important;
|
| 837 |
+
border-radius: 50% !important;
|
| 838 |
+
object-fit: cover !important;
|
| 839 |
+
display: block !important;
|
| 840 |
+
}}
|
| 841 |
+
|
| 842 |
+
#CHATBOT {{
|
| 843 |
+
background: transparent !important;
|
| 844 |
+
backdrop-filter: none !important;
|
| 845 |
+
border: none !important;
|
| 846 |
+
box-shadow: none !important;
|
| 847 |
+
border-radius: 25px !important;
|
| 848 |
+
margin-top: 20px !important;
|
| 849 |
+
}}
|
| 850 |
+
|
| 851 |
+
#CHATBOT .message-buttons,
|
| 852 |
+
#CHATBOT .action-buttons,
|
| 853 |
+
#CHATBOT button[title="Copy message"],
|
| 854 |
+
#CHATBOT button[title="Retry"],
|
| 855 |
+
#CHATBOT button[title="Undo"],
|
| 856 |
+
.message-row button,
|
| 857 |
+
.message .copy-button,
|
| 858 |
+
.message-buttons-row,
|
| 859 |
+
#CHATBOT .chatbot-header button,
|
| 860 |
+
.chatbot-header button,
|
| 861 |
+
[class*="chatbot"] button[aria-label],
|
| 862 |
+
button[title="Clear"],
|
| 863 |
+
button[title*="Copy"],
|
| 864 |
+
.chatbot-controls,
|
| 865 |
+
#component-* button[aria-label="Clear"],
|
| 866 |
+
#component-* button[aria-label*="Copy"],
|
| 867 |
+
.chatbot button,
|
| 868 |
+
#CHATBOT ~ * button,
|
| 869 |
+
[id^="component-"] button[aria-label] {{
|
| 870 |
+
display: none !important;
|
| 871 |
+
visibility: hidden !important;
|
| 872 |
+
opacity: 0 !important;
|
| 873 |
+
pointer-events: none !important;
|
| 874 |
+
}}
|
| 875 |
+
|
| 876 |
+
.message.bot {{
|
| 877 |
+
background: #7E5A9B !important;
|
| 878 |
+
font-family: 'Nunito', sans-serif !important;
|
| 879 |
+
font-weight: 700 !important;
|
| 880 |
+
color: #F4F1F7 !important;
|
| 881 |
+
font-size: 16px !important;
|
| 882 |
+
border-radius: 25px !important;
|
| 883 |
+
padding: 15px 20px !important;
|
| 884 |
+
}}
|
| 885 |
+
.message.bot p, .message.bot span, .message.bot div, .message.bot strong, .message.bot b {{
|
| 886 |
+
font-family: 'Nunito', sans-serif !important;
|
| 887 |
+
font-weight: 700 !important;
|
| 888 |
+
color: #F4F1F7 !important;
|
| 889 |
+
font-size: 16px !important;
|
| 890 |
+
}}
|
| 891 |
+
.message.bot * {{
|
| 892 |
+
color: #F4F1F7 !important;
|
| 893 |
+
}}
|
| 894 |
+
.message.user {{
|
| 895 |
+
background: #7E5A9B !important;
|
| 896 |
+
font-family: 'Nunito', sans-serif !important;
|
| 897 |
+
font-weight: 700 !important;
|
| 898 |
+
color: #F4F1F7 !important;
|
| 899 |
+
font-size: 16px !important;
|
| 900 |
+
border-radius: 25px !important;
|
| 901 |
+
padding: 15px 20px !important;
|
| 902 |
+
}}
|
| 903 |
+
.message.user p, .message.user span, .message.user div {{
|
| 904 |
+
font-family: 'Nunito', sans-serif !important;
|
| 905 |
+
font-weight: 700 !important;
|
| 906 |
+
color: #F4F1F7 !important;
|
| 907 |
+
font-size: 16px !important;
|
| 908 |
+
}}
|
| 909 |
+
|
| 910 |
+
textarea, input[type="text"], .input-text {{
|
| 911 |
+
font-family: 'Nunito', sans-serif !important;
|
| 912 |
+
font-weight: 700 !important;
|
| 913 |
+
color: #2F2F2F !important;
|
| 914 |
+
font-size: 16px !important;
|
| 915 |
+
border-radius: 25px !important;
|
| 916 |
+
}}
|
| 917 |
+
|
| 918 |
+
.textbox textarea {{
|
| 919 |
+
font-family: 'Nunito', sans-serif !important;
|
| 920 |
+
font-weight: 700 !important;
|
| 921 |
+
color: #2F2F2F !important;
|
| 922 |
+
font-size: 16px !important;
|
| 923 |
+
border-radius: 25px !important;
|
| 924 |
+
}}
|
| 925 |
+
|
| 926 |
+
.avatar-container img {{
|
| 927 |
+
object-fit: cover !important;
|
| 928 |
+
width: 100% !important;
|
| 929 |
+
height: 100% !important;
|
| 930 |
+
transform: scale(1.5) !important;
|
| 931 |
+
}}
|
| 932 |
+
img.avatar-image {{
|
| 933 |
+
object-fit: cover !important;
|
| 934 |
+
width: 100% !important;
|
| 935 |
+
height: 100% !important;
|
| 936 |
+
transform: scale(1.5) !important;
|
| 937 |
+
}}
|
| 938 |
+
.message img {{
|
| 939 |
+
object-fit: cover !important;
|
| 940 |
+
width: 100% !important;
|
| 941 |
+
height: 100% !important;
|
| 942 |
+
transform: scale(1.5) !important;
|
| 943 |
+
}}
|
| 944 |
+
|
| 945 |
+
.resource-content {{
|
| 946 |
+
background: rgba(255, 255, 255, 0.95) !important;
|
| 947 |
+
padding: 30px !important;
|
| 948 |
+
border-radius: 25px !important;
|
| 949 |
+
margin: 20px auto !important;
|
| 950 |
+
max-width: 800px !important;
|
| 951 |
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1) !important;
|
| 952 |
+
}}
|
| 953 |
+
|
| 954 |
+
.resource-content h1, .resource-content h2, .resource-content h3 {{
|
| 955 |
+
font-family: 'Nunito', sans-serif !important;
|
| 956 |
+
color: #411F61 !important;
|
| 957 |
+
}}
|
| 958 |
+
|
| 959 |
+
.resource-content p, .resource-content li {{
|
| 960 |
+
font-family: 'Nunito', sans-serif !important;
|
| 961 |
+
font-size: 16px !important;
|
| 962 |
+
line-height: 1.6 !important;
|
| 963 |
+
color: #2F2F2F !important;
|
| 964 |
+
}}
|
| 965 |
+
|
| 966 |
+
/* Accordion/Dropdown Styling */
|
| 967 |
+
.crisis-dropdown {{
|
| 968 |
+
margin: 15px 0 !important;
|
| 969 |
+
border: 2px solid #7E5A9B !important;
|
| 970 |
+
border-radius: 15px !important;
|
| 971 |
+
overflow: hidden !important;
|
| 972 |
+
background: #FBF8FC !important;
|
| 973 |
+
}}
|
| 974 |
+
|
| 975 |
+
.crisis-dropdown summary {{
|
| 976 |
+
padding: 15px 20px !important;
|
| 977 |
+
font-family: 'Nunito', sans-serif !important;
|
| 978 |
+
font-weight: 700 !important;
|
| 979 |
+
font-size: 18px !important;
|
| 980 |
+
color: #411F61 !important;
|
| 981 |
+
cursor: pointer !important;
|
| 982 |
+
list-style: none !important;
|
| 983 |
+
background: #FBF8FC !important;
|
| 984 |
+
transition: background-color 0.3s ease !important;
|
| 985 |
+
}}
|
| 986 |
+
|
| 987 |
+
.crisis-dropdown summary::-webkit-details-marker {{
|
| 988 |
+
display: none !important;
|
| 989 |
+
}}
|
| 990 |
+
|
| 991 |
+
.crisis-dropdown summary::before {{
|
| 992 |
+
content: '▸' !important;
|
| 993 |
+
display: inline-block !important;
|
| 994 |
+
margin-right: 12px !important;
|
| 995 |
+
color: #7E5A9B !important;
|
| 996 |
+
font-size: 22px !important;
|
| 997 |
+
line-height: 1 !important;
|
| 998 |
+
transition: transform 0.3s ease, color 0.3s ease !important;
|
| 999 |
+
transform-origin: center !important;
|
| 1000 |
+
}}
|
| 1001 |
+
|
| 1002 |
+
.crisis-dropdown[open] summary::before {{
|
| 1003 |
+
content: '▾' !important;
|
| 1004 |
+
}}
|
| 1005 |
+
|
| 1006 |
+
.crisis-dropdown summary:hover::before {{
|
| 1007 |
+
color: #FFFFFF !important;
|
| 1008 |
+
}}
|
| 1009 |
+
|
| 1010 |
+
.crisis-dropdown summary:hover {{
|
| 1011 |
+
background: #7E5A9B !important;
|
| 1012 |
+
color: #FFFFFF !important;
|
| 1013 |
+
}}
|
| 1014 |
+
|
| 1015 |
+
.crisis-dropdown .dropdown-content {{
|
| 1016 |
+
padding: 20px !important;
|
| 1017 |
+
background: #FFFFFF !important;
|
| 1018 |
+
border-top: 2px solid #7E5A9B !important;
|
| 1019 |
+
}}
|
| 1020 |
+
|
| 1021 |
+
.crisis-dropdown .dropdown-content p,
|
| 1022 |
+
.crisis-dropdown .dropdown-content li {{
|
| 1023 |
+
margin: 8px 0 !important;
|
| 1024 |
+
}}
|
| 1025 |
+
|
| 1026 |
+
html {{
|
| 1027 |
+
overflow-y: scroll !important;
|
| 1028 |
+
}}
|
| 1029 |
+
|
| 1030 |
+
body {{
|
| 1031 |
+
overflow-y: scroll !important;
|
| 1032 |
+
}}
|
| 1033 |
+
|
| 1034 |
+
button.primary {{
|
| 1035 |
+
background: #7E5A9B !important;
|
| 1036 |
+
border-color: #7E5A9B !important;
|
| 1037 |
+
}}
|
| 1038 |
+
|
| 1039 |
+
button.primary:hover {{
|
| 1040 |
+
background: #6B3FA0 !important;
|
| 1041 |
+
border-color: #6B3FA0 !important;
|
| 1042 |
+
}}
|
| 1043 |
+
|
| 1044 |
+
/* Tab-Container: Entfernt Gradio-Standard-Borders und erstellt Stacking Context */
|
| 1045 |
+
.tabs {{
|
| 1046 |
+
border-bottom: none !important;
|
| 1047 |
+
border: none !important;
|
| 1048 |
+
box-shadow: none !important;
|
| 1049 |
+
position: relative !important;
|
| 1050 |
+
}}
|
| 1051 |
+
|
| 1052 |
+
[class*="tabs"] {{
|
| 1053 |
+
border-bottom: none !important;
|
| 1054 |
+
border: none !important;
|
| 1055 |
+
box-shadow: none !important;
|
| 1056 |
+
}}
|
| 1057 |
+
|
| 1058 |
+
div[role="tablist"] {{
|
| 1059 |
+
border-bottom: none !important;
|
| 1060 |
+
border: none !important;
|
| 1061 |
+
box-shadow: none !important;
|
| 1062 |
+
position: relative !important;
|
| 1063 |
+
}}
|
| 1064 |
+
|
| 1065 |
+
.tab-nav {{
|
| 1066 |
+
border-bottom: none !important;
|
| 1067 |
+
box-shadow: none !important;
|
| 1068 |
+
}}
|
| 1069 |
+
|
| 1070 |
+
[class*="tab"][class*="nav"] {{
|
| 1071 |
+
border-bottom: none !important;
|
| 1072 |
+
box-shadow: none !important;
|
| 1073 |
+
}}
|
| 1074 |
+
|
| 1075 |
+
.gradio-tabs {{
|
| 1076 |
+
border-bottom: none !important;
|
| 1077 |
+
box-shadow: none !important;
|
| 1078 |
+
}}
|
| 1079 |
+
|
| 1080 |
+
.tab-container {{
|
| 1081 |
+
border-bottom: none !important;
|
| 1082 |
+
border: none !important;
|
| 1083 |
+
box-shadow: none !important;
|
| 1084 |
+
}}
|
| 1085 |
+
|
| 1086 |
+
[class*="tab-container"] {{
|
| 1087 |
+
border-bottom: none !important;
|
| 1088 |
+
border: none !important;
|
| 1089 |
+
box-shadow: none !important;
|
| 1090 |
+
}}
|
| 1091 |
+
|
| 1092 |
+
/* Svelte-generierte Tab-Klassen */
|
| 1093 |
+
[class*="svelte"][role="tablist"],
|
| 1094 |
+
div[role="tablist"][class*="svelte"] {{
|
| 1095 |
+
border-bottom: none !important;
|
| 1096 |
+
border: none !important;
|
| 1097 |
+
box-shadow: none !important;
|
| 1098 |
+
}}
|
| 1099 |
+
|
| 1100 |
+
/* Alle Elemente im Tab-Bereich */
|
| 1101 |
+
.tabs > div,
|
| 1102 |
+
.tabs > div > div,
|
| 1103 |
+
.gradio-tabs > div {{
|
| 1104 |
+
border-bottom: none !important;
|
| 1105 |
+
border: none !important;
|
| 1106 |
+
box-shadow: none !important;
|
| 1107 |
+
}}
|
| 1108 |
+
|
| 1109 |
+
/* Gradio Tab-Nav Wrapper */
|
| 1110 |
+
.tab-nav > div,
|
| 1111 |
+
[class*="tab-nav"] {{
|
| 1112 |
+
border-bottom: none !important;
|
| 1113 |
+
border: none !important;
|
| 1114 |
+
box-shadow: none !important;
|
| 1115 |
+
}}
|
| 1116 |
+
|
| 1117 |
+
.tabs button {{
|
| 1118 |
+
border-bottom: none !important;
|
| 1119 |
+
position: relative !important;
|
| 1120 |
+
}}
|
| 1121 |
+
|
| 1122 |
+
.tabs button[aria-selected="true"] {{
|
| 1123 |
+
border-bottom: none !important;
|
| 1124 |
+
}}
|
| 1125 |
+
|
| 1126 |
+
.tabs button[aria-selected="true"]::after {{
|
| 1127 |
+
content: '' !important;
|
| 1128 |
+
position: absolute !important;
|
| 1129 |
+
bottom: 0 !important;
|
| 1130 |
+
left: 0 !important;
|
| 1131 |
+
right: 0 !important;
|
| 1132 |
+
height: 3px !important;
|
| 1133 |
+
background: #7b5ea0 !important;
|
| 1134 |
+
border-radius: 3px !important;
|
| 1135 |
+
z-index: 2 !important;
|
| 1136 |
+
}}
|
| 1137 |
+
|
| 1138 |
+
* {{
|
| 1139 |
+
--color-accent: #7b5ea0 !important;
|
| 1140 |
+
--color-accent-soft: #6B3FA0 !important;
|
| 1141 |
+
}}
|
| 1142 |
+
|
| 1143 |
+
#load-status {{
|
| 1144 |
+
text-align: center !important;
|
| 1145 |
+
padding: 10px !important;
|
| 1146 |
+
font-family: 'Nunito', sans-serif !important;
|
| 1147 |
+
font-size: 18px !important;
|
| 1148 |
+
font-weight: 700 !important;
|
| 1149 |
+
color: #7E5A9B !important;
|
| 1150 |
+
margin-top: 10px !important;
|
| 1151 |
+
}}
|
| 1152 |
+
|
| 1153 |
+
/* Tab Icons */
|
| 1154 |
+
.tabs button {{
|
| 1155 |
+
display: flex !important;
|
| 1156 |
+
align-items: center !important;
|
| 1157 |
+
gap: 8px !important;
|
| 1158 |
+
font-family: 'Nunito', sans-serif !important;
|
| 1159 |
+
color: #7E5A9B !important;
|
| 1160 |
+
}}
|
| 1161 |
+
|
| 1162 |
+
.tab-icon {{
|
| 1163 |
+
width: 20px !important;
|
| 1164 |
+
height: 20px !important;
|
| 1165 |
+
display: inline-block !important;
|
| 1166 |
+
margin-right: 4px !important;
|
| 1167 |
+
background: transparent !important;
|
| 1168 |
+
background-color: transparent !important;
|
| 1169 |
+
}}
|
| 1170 |
+
|
| 1171 |
+
.logo-inline {{
|
| 1172 |
+
width: 32px !important;
|
| 1173 |
+
height: 32px !important;
|
| 1174 |
+
display: inline-block !important;
|
| 1175 |
+
vertical-align: text-top !important;
|
| 1176 |
+
margin: 0 2px !important;
|
| 1177 |
+
border-radius: 50% !important;
|
| 1178 |
+
}}
|
| 1179 |
+
|
| 1180 |
+
#CHATBOT .logo-inline,
|
| 1181 |
+
.message .logo-inline,
|
| 1182 |
+
.chatbot .logo-inline {{
|
| 1183 |
+
width: 16px !important;
|
| 1184 |
+
height: 16px !important;
|
| 1185 |
+
vertical-align: middle !important;
|
| 1186 |
+
margin: 0 6px !important;
|
| 1187 |
+
border: 0.5px solid white !important;
|
| 1188 |
+
}}
|
| 1189 |
+
|
| 1190 |
+
/* Chat-Tab: Chatfenster Layout */
|
| 1191 |
+
#chat {{
|
| 1192 |
+
display: flex !important;
|
| 1193 |
+
flex-direction: column !important;
|
| 1194 |
+
height: calc(100vh - 120px) !important;
|
| 1195 |
+
position: relative !important;
|
| 1196 |
+
}}
|
| 1197 |
+
|
| 1198 |
+
/* Chatbot-Nachrichten Bereich scrollbar */
|
| 1199 |
+
#CHATBOT {{
|
| 1200 |
+
flex: 1 !important;
|
| 1201 |
+
overflow-y: auto !important;
|
| 1202 |
+
margin-bottom: 100px !important;
|
| 1203 |
+
max-height: calc(100vh - 180px) !important;
|
| 1204 |
+
padding-bottom: 80px !important;
|
| 1205 |
+
}}
|
| 1206 |
+
|
| 1207 |
+
/* Chat-Nachrichten Container - mehr Platz für Nachrichten */
|
| 1208 |
+
.bubble-wrap {{
|
| 1209 |
+
max-height: none !important;
|
| 1210 |
+
height: auto !important;
|
| 1211 |
+
overflow-y: auto !important;
|
| 1212 |
+
padding-bottom: 100px !important;
|
| 1213 |
+
}}
|
| 1214 |
+
|
| 1215 |
+
[role="log"] {{
|
| 1216 |
+
max-height: none !important;
|
| 1217 |
+
height: auto !important;
|
| 1218 |
+
overflow-y: auto !important;
|
| 1219 |
+
padding-bottom: 100px !important;
|
| 1220 |
+
}}
|
| 1221 |
+
|
| 1222 |
+
/* Eingabefeld: Entferne weißen Strich */
|
| 1223 |
+
.gr-group,
|
| 1224 |
+
.gr-group *,
|
| 1225 |
+
.gr-group::before,
|
| 1226 |
+
.gr-group::after,
|
| 1227 |
+
.gr-group .styler,
|
| 1228 |
+
.gr-group .styler::before,
|
| 1229 |
+
.gr-group .styler::after {{
|
| 1230 |
+
border-top: none !important;
|
| 1231 |
+
border-color: transparent !important;
|
| 1232 |
+
box-shadow: none !important;
|
| 1233 |
+
}}
|
| 1234 |
+
|
| 1235 |
+
/* Tab-Menü: Entferne weißen Strich unter den Tabs */
|
| 1236 |
+
.tabs,
|
| 1237 |
+
.tabs *,
|
| 1238 |
+
.tabs::before,
|
| 1239 |
+
.tabs::after,
|
| 1240 |
+
.tabitem,
|
| 1241 |
+
.tabitem::before,
|
| 1242 |
+
.tabitem::after,
|
| 1243 |
+
.tab-nav,
|
| 1244 |
+
.tab-nav::before,
|
| 1245 |
+
.tab-nav::after,
|
| 1246 |
+
.tab-nav *,
|
| 1247 |
+
[role="tablist"],
|
| 1248 |
+
[role="tablist"]::before,
|
| 1249 |
+
[role="tablist"]::after,
|
| 1250 |
+
.svelte-1p9262q,
|
| 1251 |
+
.svelte-1p9262q::before,
|
| 1252 |
+
.svelte-1p9262q::after,
|
| 1253 |
+
.svelte-7xavid,
|
| 1254 |
+
.svelte-7xavid::before,
|
| 1255 |
+
.svelte-7xavid::after,
|
| 1256 |
+
div[class*="svelte"]::before,
|
| 1257 |
+
div[class*="svelte"]::after {{
|
| 1258 |
+
border: none !important;
|
| 1259 |
+
border-top: none !important;
|
| 1260 |
+
border-bottom: none !important;
|
| 1261 |
+
border-color: transparent !important;
|
| 1262 |
+
box-shadow: none !important;
|
| 1263 |
+
}}
|
| 1264 |
+
|
| 1265 |
+
/* Entferne alle horizontalen Linien/Striche */
|
| 1266 |
+
hr, .divider, [class*="divider"], [class*="separator"] {{
|
| 1267 |
+
display: none !important;
|
| 1268 |
+
border: none !important;
|
| 1269 |
+
background: transparent !important;
|
| 1270 |
+
}}
|
| 1271 |
+
|
| 1272 |
+
/* Gradio Tab Container - alle Borders entfernen */
|
| 1273 |
+
.gradio-container *::before,
|
| 1274 |
+
.gradio-container *::after {{
|
| 1275 |
+
border: none !important;
|
| 1276 |
+
border-color: transparent !important;
|
| 1277 |
+
}}
|
| 1278 |
+
|
| 1279 |
+
/* Spezifisch für Tab-Buttons */
|
| 1280 |
+
button[role="tab"],
|
| 1281 |
+
button[role="tab"]::before,
|
| 1282 |
+
button[role="tab"]::after {{
|
| 1283 |
+
border: none !important;
|
| 1284 |
+
border-bottom: none !important;
|
| 1285 |
+
box-shadow: none !important;
|
| 1286 |
+
}}
|
| 1287 |
+
"""
|
| 1288 |
+
|
| 1289 |
+
custom_js = f"""
|
| 1290 |
+
function removeFooter() {{
|
| 1291 |
+
const footers = document.querySelectorAll('footer, .footer, [class*="footer"], [class*="Footer"]');
|
| 1292 |
+
footers.forEach(footer => {{
|
| 1293 |
+
footer.style.display = 'none';
|
| 1294 |
+
footer.style.visibility = 'hidden';
|
| 1295 |
+
footer.remove();
|
| 1296 |
+
}});
|
| 1297 |
+
|
| 1298 |
+
const gradioLinks = document.querySelectorAll('a[href*="gradio"]');
|
| 1299 |
+
gradioLinks.forEach(link => {{
|
| 1300 |
+
link.style.display = 'none';
|
| 1301 |
+
link.remove();
|
| 1302 |
+
}});
|
| 1303 |
+
}}
|
| 1304 |
+
|
| 1305 |
+
function removeChatButtons() {{
|
| 1306 |
+
const chatButtons = document.querySelectorAll(`
|
| 1307 |
+
#CHATBOT button,
|
| 1308 |
+
.chatbot button,
|
| 1309 |
+
button[aria-label="Clear"],
|
| 1310 |
+
button[aria-label*="Copy"],
|
| 1311 |
+
button[title="Clear"],
|
| 1312 |
+
button[title*="Copy"],
|
| 1313 |
+
[id*="chatbot"] button[aria-label],
|
| 1314 |
+
[id*="component-"] button[aria-label]
|
| 1315 |
+
`);
|
| 1316 |
+
chatButtons.forEach(btn => {{
|
| 1317 |
+
if (!btn.closest('form')) {{
|
| 1318 |
+
btn.style.display = 'none';
|
| 1319 |
+
btn.style.visibility = 'hidden';
|
| 1320 |
+
btn.style.opacity = '0';
|
| 1321 |
+
btn.remove();
|
| 1322 |
+
}}
|
| 1323 |
+
}});
|
| 1324 |
+
}}
|
| 1325 |
+
|
| 1326 |
+
// Home-Tab Hintergrundbild setzen
|
| 1327 |
+
const homeScreenBase64 = '{home_screen_base64}';
|
| 1328 |
+
|
| 1329 |
+
function setHomeBackground() {{
|
| 1330 |
+
// Versuche verschiedene Selektoren
|
| 1331 |
+
let homeTab = document.querySelector('#home');
|
| 1332 |
+
|
| 1333 |
+
if (!homeTab) {{
|
| 1334 |
+
// Fallback: Finde Tab-Panel mit id="home"
|
| 1335 |
+
homeTab = document.querySelector('[id="home"]');
|
| 1336 |
+
}}
|
| 1337 |
+
|
| 1338 |
+
if (homeTab && homeScreenBase64) {{
|
| 1339 |
+
homeTab.style.background = 'url("data:image/png;base64,' + homeScreenBase64 + '") no-repeat center center';
|
| 1340 |
+
homeTab.style.backgroundSize = 'cover';
|
| 1341 |
+
homeTab.style.minHeight = 'calc(100vh - 100px)';
|
| 1342 |
+
homeTab.style.position = 'relative';
|
| 1343 |
+
|
| 1344 |
+
// Auch den gradio-container Hintergrund für Home überschreiben
|
| 1345 |
+
const container = document.querySelector('[class*="gradio-container"]');
|
| 1346 |
+
const homeButton = document.querySelector('button[id*="home"]');
|
| 1347 |
+
|
| 1348 |
+
// Prüfe ob Home-Tab aktiv ist
|
| 1349 |
+
if (homeButton && homeButton.classList.contains('selected')) {{
|
| 1350 |
+
if (container) {{
|
| 1351 |
+
container.style.background = 'url("data:image/png;base64,' + homeScreenBase64 + '") no-repeat center center fixed';
|
| 1352 |
+
container.style.backgroundSize = 'cover';
|
| 1353 |
+
}}
|
| 1354 |
+
}}
|
| 1355 |
+
}}
|
| 1356 |
+
|
| 1357 |
+
console.log('Home Tab gefunden:', homeTab);
|
| 1358 |
+
}}
|
| 1359 |
+
|
| 1360 |
+
// Tab-Wechsel beobachten und Hintergrund wechseln
|
| 1361 |
+
const defaultBackground = 'url("data:image/jpeg;base64,{background_image_base64}") no-repeat center center fixed';
|
| 1362 |
+
|
| 1363 |
+
function observeTabChanges() {{
|
| 1364 |
+
const tabs = document.querySelectorAll('[role="tab"]');
|
| 1365 |
+
const container = document.querySelector('[class*="gradio-container"]');
|
| 1366 |
+
|
| 1367 |
+
tabs.forEach(tab => {{
|
| 1368 |
+
tab.addEventListener('click', () => {{
|
| 1369 |
+
setTimeout(() => {{
|
| 1370 |
+
const isHomeTab = tab.textContent.includes('Home') || tab.id.includes('home');
|
| 1371 |
+
if (container) {{
|
| 1372 |
+
if (isHomeTab) {{
|
| 1373 |
+
container.style.background = 'url("data:image/png;base64,' + homeScreenBase64 + '") no-repeat center center fixed';
|
| 1374 |
+
}} else {{
|
| 1375 |
+
container.style.background = defaultBackground;
|
| 1376 |
+
}}
|
| 1377 |
+
container.style.backgroundSize = 'cover';
|
| 1378 |
+
}}
|
| 1379 |
+
}}, 50);
|
| 1380 |
+
}});
|
| 1381 |
+
}});
|
| 1382 |
+
}}
|
| 1383 |
+
|
| 1384 |
+
function fixChatInputPosition() {{
|
| 1385 |
+
// Finde das Textarea im Chat
|
| 1386 |
+
const textarea = document.querySelector('textarea[placeholder="Type a message..."]');
|
| 1387 |
+
if (!textarea) return;
|
| 1388 |
+
|
| 1389 |
+
// Finde den nächsten Container mit class "gr-group" (das ist nur die Eingabezeile)
|
| 1390 |
+
let container = textarea.closest('.gr-group');
|
| 1391 |
+
if (!container) {{
|
| 1392 |
+
// Fallback: gehe nur 4 Ebenen hoch (nur bis zur Eingabezeile)
|
| 1393 |
+
container = textarea;
|
| 1394 |
+
for (let i = 0; i < 4; i++) {{
|
| 1395 |
+
if (container.parentElement) {{
|
| 1396 |
+
container = container.parentElement;
|
| 1397 |
+
}}
|
| 1398 |
+
}}
|
| 1399 |
+
}}
|
| 1400 |
+
|
| 1401 |
+
// Style nur den Eingabe-Container
|
| 1402 |
+
container.style.position = 'fixed';
|
| 1403 |
+
container.style.bottom = '15px';
|
| 1404 |
+
container.style.left = '240px';
|
| 1405 |
+
container.style.right = 'auto';
|
| 1406 |
+
container.style.width = 'calc(100% - 460px)';
|
| 1407 |
+
container.style.background = 'transparent';
|
| 1408 |
+
container.style.padding = '15px 20px';
|
| 1409 |
+
container.style.zIndex = '1000';
|
| 1410 |
+
|
| 1411 |
+
// Mache das Textarea größer
|
| 1412 |
+
textarea.style.fontSize = '16px';
|
| 1413 |
+
textarea.style.padding = '12px 15px';
|
| 1414 |
+
textarea.style.minHeight = '50px';
|
| 1415 |
+
|
| 1416 |
+
// Mache Container-Elemente transparent (aber nicht das Eingabefeld selbst)
|
| 1417 |
+
const styler = container.querySelector('.styler');
|
| 1418 |
+
if (styler) {{
|
| 1419 |
+
styler.style.background = 'transparent';
|
| 1420 |
+
styler.style.border = 'none';
|
| 1421 |
+
styler.style.boxShadow = 'none';
|
| 1422 |
+
styler.style.setProperty('--layout-gap', '0px');
|
| 1423 |
+
styler.style.setProperty('--form-gap-width', '0px');
|
| 1424 |
+
}}
|
| 1425 |
+
|
| 1426 |
+
const row = container.querySelector('.row');
|
| 1427 |
+
if (row) {{
|
| 1428 |
+
row.style.background = 'transparent';
|
| 1429 |
+
row.style.border = 'none';
|
| 1430 |
+
row.style.boxShadow = 'none';
|
| 1431 |
+
}}
|
| 1432 |
+
|
| 1433 |
+
const form = container.querySelector('.form');
|
| 1434 |
+
if (form) {{
|
| 1435 |
+
form.style.background = 'transparent';
|
| 1436 |
+
form.style.border = 'none';
|
| 1437 |
+
form.style.boxShadow = 'none';
|
| 1438 |
+
}}
|
| 1439 |
+
|
| 1440 |
+
const block = container.querySelector('.block');
|
| 1441 |
+
if (block) {{
|
| 1442 |
+
block.style.background = 'transparent';
|
| 1443 |
+
block.style.border = 'none';
|
| 1444 |
+
block.style.boxShadow = 'none';
|
| 1445 |
+
}}
|
| 1446 |
+
|
| 1447 |
+
const label = container.querySelector('label');
|
| 1448 |
+
if (label) {{
|
| 1449 |
+
label.style.background = 'transparent';
|
| 1450 |
+
label.style.border = 'none';
|
| 1451 |
+
label.style.boxShadow = 'none';
|
| 1452 |
+
}}
|
| 1453 |
+
|
| 1454 |
+
// Passe Chatbot-Höhe an
|
| 1455 |
+
const chatbot = document.querySelector('#CHATBOT');
|
| 1456 |
+
if (chatbot) {{
|
| 1457 |
+
chatbot.style.maxHeight = 'calc(100vh - 80px)';
|
| 1458 |
+
chatbot.style.height = 'calc(100vh - 80px)';
|
| 1459 |
+
chatbot.style.marginBottom = '0px';
|
| 1460 |
+
chatbot.style.paddingBottom = '120px';
|
| 1461 |
+
chatbot.style.overflowY = 'auto';
|
| 1462 |
+
}}
|
| 1463 |
+
|
| 1464 |
+
// Passe die bubble-wrap (Nachrichten-Container) Höhe an
|
| 1465 |
+
const bubbleWrap = document.querySelector('.bubble-wrap');
|
| 1466 |
+
if (bubbleWrap) {{
|
| 1467 |
+
bubbleWrap.style.maxHeight = 'calc(100vh - 80px)';
|
| 1468 |
+
bubbleWrap.style.height = 'auto';
|
| 1469 |
+
bubbleWrap.style.overflowY = 'auto';
|
| 1470 |
+
bubbleWrap.style.paddingBottom = '140px';
|
| 1471 |
+
}}
|
| 1472 |
+
|
| 1473 |
+
// Passe role="log" Container an
|
| 1474 |
+
const logContainer = document.querySelector('[role="log"]');
|
| 1475 |
+
if (logContainer) {{
|
| 1476 |
+
logContainer.style.maxHeight = 'calc(100vh - 80px)';
|
| 1477 |
+
logContainer.style.paddingBottom = '140px';
|
| 1478 |
+
logContainer.style.overflowY = 'auto';
|
| 1479 |
+
}}
|
| 1480 |
+
}}
|
| 1481 |
+
|
| 1482 |
+
function addTabIcons() {{
|
| 1483 |
+
const tabIcons = {{
|
| 1484 |
+
'Home': '{tab_icons.get("home", "")}',
|
| 1485 |
+
'Chat': '{tab_icons.get("chat", "")}',
|
| 1486 |
+
'Schlafplan': '{tab_icons.get("schlafplan", "")}',
|
| 1487 |
+
'Medien und Tools': '{tab_icons.get("mediensammlung", "")}',
|
| 1488 |
+
'Time Management': '{tab_icons.get("timemanagement", "")}',
|
| 1489 |
+
'Notfallplan': '{tab_icons.get("notfallplan", "")}'
|
| 1490 |
+
}};
|
| 1491 |
+
|
| 1492 |
+
const tabs = document.querySelectorAll('.tabs button');
|
| 1493 |
+
tabs.forEach(tab => {{
|
| 1494 |
+
const tabText = tab.textContent.trim();
|
| 1495 |
+
|
| 1496 |
+
if (tabIcons[tabText] && tabIcons[tabText] !== '' && !tab.querySelector('.tab-icon')) {{
|
| 1497 |
+
const icon = document.createElement('img');
|
| 1498 |
+
icon.className = 'tab-icon';
|
| 1499 |
+
icon.src = 'data:image/png;base64,' + tabIcons[tabText];
|
| 1500 |
+
tab.insertBefore(icon, tab.firstChild);
|
| 1501 |
+
}}
|
| 1502 |
+
}});
|
| 1503 |
+
}}
|
| 1504 |
+
|
| 1505 |
+
function changeTabColors() {{
|
| 1506 |
+
const tabs = document.querySelectorAll('.tabs button');
|
| 1507 |
+
tabs.forEach(tab => {{
|
| 1508 |
+
if (tab.hasAttribute('style')) {{
|
| 1509 |
+
const style = tab.getAttribute('style');
|
| 1510 |
+
const newStyle = style.replace(/border-bottom-color:\\s*rgb\\(255,\\s*165,\\s*0\\)/g, 'border-bottom-color: #411F61')
|
| 1511 |
+
.replace(/border-bottom-color:\\s*orange/g, 'border-bottom-color: #411F61');
|
| 1512 |
+
tab.setAttribute('style', newStyle);
|
| 1513 |
+
}}
|
| 1514 |
+
|
| 1515 |
+
const observer = new MutationObserver(mutations => {{
|
| 1516 |
+
mutations.forEach(mutation => {{
|
| 1517 |
+
if (mutation.attributeName === 'style') {{
|
| 1518 |
+
const style = tab.getAttribute('style');
|
| 1519 |
+
if (style && (style.includes('rgb(255, 165, 0)') || style.includes('orange'))) {{
|
| 1520 |
+
const newStyle = style.replace(/border-bottom-color:\\s*rgb\\(255,\\s*165,\\s*0\\)/g, 'border-bottom-color: #411F61')
|
| 1521 |
+
.replace(/border-bottom-color:\\s*orange/g, 'border-bottom-color: #411F61');
|
| 1522 |
+
tab.setAttribute('style', newStyle);
|
| 1523 |
+
}}
|
| 1524 |
+
}}
|
| 1525 |
+
}});
|
| 1526 |
+
}});
|
| 1527 |
+
|
| 1528 |
+
observer.observe(tab, {{ attributes: true, attributeFilter: ['style'] }});
|
| 1529 |
+
}});
|
| 1530 |
+
}}
|
| 1531 |
+
|
| 1532 |
+
function initCustomizations() {{
|
| 1533 |
+
removeFooter();
|
| 1534 |
+
removeChatButtons();
|
| 1535 |
+
changeTabColors();
|
| 1536 |
+
addTabIcons();
|
| 1537 |
+
fixChatInputPosition();
|
| 1538 |
+
setHomeBackground();
|
| 1539 |
+
observeTabChanges();
|
| 1540 |
+
}}
|
| 1541 |
+
|
| 1542 |
+
if (document.readyState === 'loading') {{
|
| 1543 |
+
document.addEventListener('DOMContentLoaded', initCustomizations);
|
| 1544 |
+
}} else {{
|
| 1545 |
+
initCustomizations();
|
| 1546 |
+
}}
|
| 1547 |
+
|
| 1548 |
+
setTimeout(initCustomizations, 100);
|
| 1549 |
+
setTimeout(initCustomizations, 500);
|
| 1550 |
+
setTimeout(initCustomizations, 1000);
|
| 1551 |
+
setTimeout(initCustomizations, 2000);
|
| 1552 |
+
|
| 1553 |
+
const observer = new MutationObserver(() => {{
|
| 1554 |
+
removeFooter();
|
| 1555 |
+
removeChatButtons();
|
| 1556 |
+
fixChatInputPosition();
|
| 1557 |
+
}});
|
| 1558 |
+
|
| 1559 |
+
observer.observe(document.body, {{
|
| 1560 |
+
childList: true,
|
| 1561 |
+
subtree: true
|
| 1562 |
+
}});
|
| 1563 |
+
"""
|
| 1564 |
+
|
| 1565 |
+
with gr.Blocks(title="calm.i") as demo:
|
| 1566 |
+
if logo_base64:
|
| 1567 |
+
gr.HTML(f'<div id="logo-container"><img src="data:image/png;base64,{logo_base64}" alt="calm.i Logo"></div>')
|
| 1568 |
+
|
| 1569 |
+
# Vordefinierte Markdown-Komponenten für personalisierte Inhalte (werden später gerendert)
|
| 1570 |
+
schlafplan_display = gr.Markdown(value="""
|
| 1571 |
+
<div class="resource-content">
|
| 1572 |
+
Dein persönlicher Schlafplan
|
| 1573 |
+
|
| 1574 |
+
Dieser Bereich wird personalisiert, sobald du die Fragen im Chat beantwortet hast.
|
| 1575 |
+
|
| 1576 |
+
Gehe zum **Chat-Tab** und starte das Gespräch mit mir!
|
| 1577 |
+
</div>
|
| 1578 |
+
""", render=False)
|
| 1579 |
+
medien_display = gr.Markdown(value="""
|
| 1580 |
+
<div class="resource-content">
|
| 1581 |
+
Deine persönliche Medien und Tools
|
| 1582 |
+
|
| 1583 |
+
Dieser Bereich wird personalisiert, sobald du die Fragen im Chat beantwortet hast.
|
| 1584 |
+
|
| 1585 |
+
Gehe zum **Chat-Tab** und starte das Gespräch mit mir!
|
| 1586 |
+
</div>
|
| 1587 |
+
""", render=False)
|
| 1588 |
+
time_display = gr.Markdown(value="""
|
| 1589 |
+
<div class="resource-content">
|
| 1590 |
+
Dein persönlicher Time-Management-Plan
|
| 1591 |
+
|
| 1592 |
+
Dieser Bereich wird personalisiert, sobald du die Fragen im Chat beantwortet hast.
|
| 1593 |
+
|
| 1594 |
+
Gehe zum **Chat-Tab** und starte das Gespräch mit mir!
|
| 1595 |
+
</div>
|
| 1596 |
+
""", render=False)
|
| 1597 |
+
|
| 1598 |
+
with gr.Tabs() as tabs:
|
| 1599 |
+
with gr.Tab("Home", id="home"):
|
| 1600 |
+
gr.HTML(f'''
|
| 1601 |
+
<div class="home-screen-container">
|
| 1602 |
+
<img src="data:image/png;base64,{home_screen_base64}" class="home-screen-image" alt="Home Screen">
|
| 1603 |
+
</div>
|
| 1604 |
+
<button class="home-chat-button" onclick="document.querySelectorAll('[role=tab]')[1].click()">Jetzt mit Calm.i chatten</button>
|
| 1605 |
+
''')
|
| 1606 |
+
|
| 1607 |
+
with gr.Tab("Chat", id="chat"):
|
| 1608 |
+
chatbot_chat = gr.Chatbot(
|
| 1609 |
+
value=[{"role": "assistant", "content": f"Hallo! Ich bin calm.i {logo_inline_html}\n\nSchön, dass du hier bist! Ich kann dir mit Stress, Schlaf und Selbstfürsorge helfen.\n\n**Möchtest du einen kurzen Fragebogen (2-3 Minuten) ausfüllen?** Damit kann ich personalisierte Pläne für dich erstellen (Schlafplan, Medien und Tools, Time Management).\n\n**Antworte mit:**\n- \"Ja\" oder \"Los geht's\" → um den Test jetzt zu machen\n- \"Jetzt nicht\" oder \"Später\" → um direkt zu chatten\n\n---\n\n**!!! Wichtiger Hinweis !!!**\n*Calm.i ist kein Ersatz für therapeutische Behandlung! Es handelt sich um einen Chatbot, der mit Tipps und individuellen Planungstools eine Unterstützung darstellen kann. Bitte wenden Sie sich im Zweifel umgehend an professionelle Hilfe!*"}],
|
| 1610 |
+
show_label=False,
|
| 1611 |
+
avatar_images=("./assets/chat_icons/human.png", "./assets/chat_icons/robot.png"),
|
| 1612 |
+
elem_id="CHATBOT"
|
| 1613 |
+
)
|
| 1614 |
+
|
| 1615 |
+
chatinterface = gr.ChatInterface(
|
| 1616 |
+
fn=response,
|
| 1617 |
+
chatbot=chatbot_chat,
|
| 1618 |
+
additional_outputs=[schlafplan_display, medien_display, time_display]
|
| 1619 |
+
)
|
| 1620 |
+
|
| 1621 |
+
with gr.Tab("Schlafplan"):
|
| 1622 |
+
schlafplan_display.render()
|
| 1623 |
+
|
| 1624 |
+
with gr.Tab("Medien und Tools"):
|
| 1625 |
+
medien_display.render()
|
| 1626 |
+
|
| 1627 |
+
with gr.Tab("Time Management"):
|
| 1628 |
+
time_display.render()
|
| 1629 |
+
|
| 1630 |
+
with gr.Tab("Notfallplan"):
|
| 1631 |
+
gr.Markdown("""
|
| 1632 |
+
<div class="resource-content">
|
| 1633 |
+
|
| 1634 |
+
# Notfallplan
|
| 1635 |
+
|
| 1636 |
+
## Bei akuten Krisen stehen dir diese Hilfen zur Verfügung
|
| 1637 |
+
|
| 1638 |
+
### Wichtigste Kontakte
|
| 1639 |
+
|
| 1640 |
+
**Bei akuter Lebensgefahr:**
|
| 1641 |
+
- **Notruf: 112** (Feuerwehr & Rettungsdienst)
|
| 1642 |
+
- **Polizei: 110**
|
| 1643 |
+
|
| 1644 |
+
**Telefonseelsorge** (24/7, anonym, kostenlos)
|
| 1645 |
+
- **0800 111 0 111** (Evangelisch)
|
| 1646 |
+
- **0800 111 0 222** (Katholisch)
|
| 1647 |
+
|
| 1648 |
+
**Ärztlicher Bereitschaftsdienst**
|
| 1649 |
+
- **116 117** (Bei nicht lebensbedrohlichen Problemen außerhalb der Praxiszeiten)
|
| 1650 |
+
|
| 1651 |
+
<details class="crisis-dropdown">
|
| 1652 |
+
<summary>Nummer gegen Kummer</summary>
|
| 1653 |
+
<div class="dropdown-content">
|
| 1654 |
+
|
| 1655 |
+
- **Kinder- & Jugendtelefon: 116 111** (Mo-Sa 14-20 Uhr)
|
| 1656 |
+
- **Elterntelefon: 0800 111 0 550** (Mo-Fr 9-17 Uhr, Di+Do auch bis 19 Uhr)
|
| 1657 |
+
|
| 1658 |
+
</div>
|
| 1659 |
+
</details>
|
| 1660 |
+
|
| 1661 |
+
<details class="crisis-dropdown">
|
| 1662 |
+
<summary>Muslimisches Seelsorge-Telefon</summary>
|
| 1663 |
+
<div class="dropdown-content">
|
| 1664 |
+
|
| 1665 |
+
- **030 443 509 821** (24/7, mehrsprachig)
|
| 1666 |
+
|
| 1667 |
+
</div>
|
| 1668 |
+
</details>
|
| 1669 |
+
|
| 1670 |
+
<details class="crisis-dropdown">
|
| 1671 |
+
<summary>Info-Telefon Depression</summary>
|
| 1672 |
+
<div class="dropdown-content">
|
| 1673 |
+
|
| 1674 |
+
- **0800 334 4533** (Mo, Di, Do 13-17 Uhr, Mi+Fr 8:30-12:30 Uhr)
|
| 1675 |
+
|
| 1676 |
+
</div>
|
| 1677 |
+
</details>
|
| 1678 |
+
|
| 1679 |
+
<details class="crisis-dropdown">
|
| 1680 |
+
<summary>Psychiatrische Notdienste</summary>
|
| 1681 |
+
<div class="dropdown-content">
|
| 1682 |
+
|
| 1683 |
+
Google: "Psychiatrischer Notdienst [deine Stadt]"
|
| 1684 |
+
|
| 1685 |
+
</div>
|
| 1686 |
+
</details>
|
| 1687 |
+
|
| 1688 |
+
<details class="crisis-dropdown">
|
| 1689 |
+
<summary>Bei Suizidgedanken</summary>
|
| 1690 |
+
<div class="dropdown-content">
|
| 1691 |
+
|
| 1692 |
+
**Du bist nicht allein. Es gibt Hilfe.**
|
| 1693 |
+
|
| 1694 |
+
1. **Rufe sofort** eine der oben genannten Nummern an
|
| 1695 |
+
2. **Wende dich** an eine Vertrauensperson (Familie, Freund*in)
|
| 1696 |
+
3. **Gehe** zur nächsten psychiatrischen Notaufnahme oder rufe 112
|
| 1697 |
+
|
| 1698 |
+
</div>
|
| 1699 |
+
</details>
|
| 1700 |
+
|
| 1701 |
+
<details class="crisis-dropdown">
|
| 1702 |
+
<summary>Online-Beratung</summary>
|
| 1703 |
+
<div class="dropdown-content">
|
| 1704 |
+
|
| 1705 |
+
- **[U25] Deutschland:** [www.u25-deutschland.de](https://www.u25-deutschland.de) (E-Mail-Beratung für unter 25-Jährige)
|
| 1706 |
+
- **Deutsche Gesellschaft für Suizidprävention:** [www.suizidprophylaxe.de](https://www.suizidprophylaxe.de)
|
| 1707 |
+
|
| 1708 |
+
</div>
|
| 1709 |
+
</details>
|
| 1710 |
+
|
| 1711 |
+
<details class="crisis-dropdown">
|
| 1712 |
+
<summary>Wichtig zu wissen</summary>
|
| 1713 |
+
<div class="dropdown-content">
|
| 1714 |
+
|
| 1715 |
+
- **Anonymität:** Telefonseelsorge und viele Beratungen sind anonym
|
| 1716 |
+
- **Kostenlos:** Alle Notfallnummern sind kostenlos
|
| 1717 |
+
- **Keine Scheu:** Lieber einmal zu viel anrufen als zu wenig
|
| 1718 |
+
- **Du bist wichtig:** Dein Leben hat Wert, auch wenn es sich gerade nicht so anfühlt
|
| 1719 |
+
|
| 1720 |
+
</div>
|
| 1721 |
+
</details>
|
| 1722 |
+
|
| 1723 |
+
---
|
| 1724 |
+
|
| 1725 |
+
**Dieser Chatbot ersetzt keine professionelle Hilfe!**
|
| 1726 |
+
|
| 1727 |
+
Bei akuten Krisen wende dich bitte an die oben genannten Stellen.
|
| 1728 |
+
|
| 1729 |
+
</div>
|
| 1730 |
+
""")
|
| 1731 |
+
|
| 1732 |
+
|
| 1733 |
+
demo.launch(
|
| 1734 |
+
server_name="0.0.0.0",
|
| 1735 |
+
server_port=7860,
|
| 1736 |
+
inbrowser=True,
|
| 1737 |
+
css=custom_css,
|
| 1738 |
+
js=custom_js
|
| 1739 |
+
)
|
| 1740 |
+
|
| 1741 |
+
|
| 1742 |
+
if __name__ == "__main__":
|
| 1743 |
+
main()
|
assets/background_image/hintergrund.jpg
ADDED
|
Git LFS Details
|
assets/chat_icons/human.png
ADDED
|
|
assets/chat_icons/robot.png
ADDED
|
|
assets/home_screen/home_screen.png
ADDED
|
Git LFS Details
|
assets/home_screen/home_screen2.png
ADDED
|
Git LFS Details
|
assets/home_screen/home_screen3.png
ADDED
|
Git LFS Details
|
assets/logo/logo.png
ADDED
|
assets/tab_icons/chat.png
ADDED
|
|
assets/tab_icons/home.png
ADDED
|
|
assets/tab_icons/mediensammlung.png
ADDED
|
|
assets/tab_icons/notfallplan.png
ADDED
|
|
assets/tab_icons/schlafplan.png
ADDED
|
|
assets/tab_icons/timemanagement.png
ADDED
|
|
requirements.txt
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
openai
|
| 2 |
+
gradio==6.1.0
|
| 3 |
+
PyPDF2
|
| 4 |
+
chromadb
|
style.css
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[class*="gradio-container"] {
|
| 2 |
+
background: url("/file/hintergrund.jpg") no-repeat center center fixed !important;
|
| 3 |
+
background-size: cover !important;
|
| 4 |
+
}
|
| 5 |
+
/* Chatbot Box */
|
| 6 |
+
#CHATBOT {
|
| 7 |
+
background: rgba(65, 31, 97, 0.7) !important;
|
| 8 |
+
backdrop-filter: blur(6px);
|
| 9 |
+
border-radius: 12px;
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
/* Nachrichten */
|
| 13 |
+
.message.bot {
|
| 14 |
+
background: #6B1DAF !important;
|
| 15 |
+
font-family: "Lucida Handwriting" !important;
|
| 16 |
+
}
|
| 17 |
+
|
| 18 |
+
.message.user {
|
| 19 |
+
background: #AC73DE !important;
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
/* Tabellen kompakter machen */
|
| 23 |
+
.resource-content table {
|
| 24 |
+
border-collapse: collapse;
|
| 25 |
+
width: 100%;
|
| 26 |
+
margin: 10px 0;
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
.resource-content table th,
|
| 30 |
+
.resource-content table td {
|
| 31 |
+
padding: 4px 8px;
|
| 32 |
+
border: 1px solid rgba(255, 255, 255, 0.3);
|
| 33 |
+
line-height: 1.2;
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
.resource-content table th {
|
| 37 |
+
background: rgba(107, 29, 175, 0.5);
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
.resource-content table tr {
|
| 41 |
+
margin: 0;
|
| 42 |
+
padding: 0;
|
| 43 |
+
}
|
theme.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from gradio.themes.base import Base
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
class CustomTheme(Base):
|
| 5 |
+
def __init__(self):
|
| 6 |
+
super().__init__()
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
super().set(
|
| 10 |
+
body_background_fill="#231332",
|
| 11 |
+
body_background_fill_dark="blue",
|
| 12 |
+
input_background_fill="#fff5dd",
|
| 13 |
+
input_background_fill_dark="#231332"
|
| 14 |
+
)
|