linusedman commited on
Commit
388464c
·
verified ·
1 Parent(s): 5ce66f0

Removed the .env support since it is not in use anymore

Browse files
Files changed (1) hide show
  1. chatbot.py +225 -227
chatbot.py CHANGED
@@ -1,227 +1,225 @@
1
- # -*- coding: utf-8 -*-
2
- """
3
- Created on Wed Oct 15 11:06:24 2025
4
- Updated on Sun Oct 19 13:32:50 2025
5
-
6
- @author 1: Lovisa
7
- @author 2: Agnes
8
- @author 3: Linus
9
- """
10
-
11
- import os
12
- from dotenv import load_dotenv
13
- from google import genai
14
- from google.genai import types
15
- import gradio as gr
16
- import mimetypes
17
- import pdfplumber
18
- from PIL import Image
19
-
20
- load_dotenv()
21
- KEY = os.environ.get("GEMINI_API_KEY")
22
- FAISS_INDEX = os.environ.get("FAISS_FOLDER")
23
-
24
- client = genai.Client(api_key=KEY)
25
-
26
- default_model = "gemini-2.5-flash"
27
-
28
- from langchain_community.vectorstores import FAISS # "db" to store and retrieve embeddings
29
- from langchain_huggingface import HuggingFaceEmbeddings
30
-
31
- embeddings = HuggingFaceEmbeddings(model_name="KBLab/sentence-bert-swedish-cased")
32
-
33
- db = FAISS.load_local(FAISS_INDEX, embeddings, allow_dangerous_deserialization=True) # Load the vector database
34
-
35
- def response_stream(inputs, history):
36
- user_text = ""
37
- user_images = []
38
-
39
- if isinstance(inputs, dict):
40
- user_text = inputs.get("text", "").lower()
41
- files = inputs.get("files", [])
42
-
43
- if files:
44
- for file_path in files:
45
- try:
46
- mime_type, _ = mimetypes.guess_type(file_path) # Guesses "the filetype based on its filename, path or URL, given by url"
47
-
48
- if mime_type and mime_type.startswith("image/"):
49
- # Handle image input
50
- user_images.append(Image.open(file_path))
51
-
52
- elif mime_type and mime_type.startswith("text/"):
53
- # Handle plain text input
54
- with open(file_path, "r", encoding="utf-8", errors="ignore") as f:
55
- user_text += "\n" + f.read()
56
-
57
- elif mime_type == "application/pdf" or file_path.lower().endswith(".pdf"):
58
- # Handle PDF input
59
- try:
60
- with pdfplumber.open(file_path) as pdf:
61
- pdf_text = "\n".join(page.extract_text() or "" for page in pdf.pages)
62
- user_text += "\n" + pdf_text
63
- except Exception as e:
64
- user_text += f"\n(Kunde inte läsa PDF: {e})"
65
-
66
- else:
67
- # Unsupported file types
68
- user_text += "\n(Filtypen stöds inte ännu.)"
69
- except Exception as e:
70
- user_text += "\nFel vid läsning av fil {file_path}: {e}"
71
-
72
- else:
73
- user_text = inputs.lower()
74
-
75
- # special greetings from example file
76
- if user_text=="hej":
77
- yield "Hej, jag är din livsmedelsexpert. Vad kan jag hjälpa dig med?"
78
- return
79
- elif "hejdå" in user_text:
80
- yield "Hejdå! Ha en fortsatt trevlig dag :)"
81
- return
82
-
83
- history_text = "Fortsätt konversationen.\n\n"
84
- for user_msg, bot_msg in history:
85
- history_text += f"Användare: {user_msg}\nAssistent: {bot_msg}\n"
86
-
87
- # Add context from RAG if any text has been inputted by the user
88
- if len(user_text) > 0:
89
- context = db.similarity_search(user_text, k=5)
90
- history_text += "\n\n" + "Kontext:\n" + "".join([chunk.page_content + "\n Source: " + chunk.metadata["source"] for chunk in context]) + "\n"
91
-
92
- # Add latest user input
93
- history_text += f"Användare: {user_text}\nAssistent:"
94
-
95
- contents = []
96
- if len(user_images) > 0:
97
- contents.extend(user_images)
98
-
99
- contents.append(history_text)
100
-
101
- try:
102
- gemini_stream = client.models.generate_content_stream(
103
- model=default_model,
104
- contents=contents,
105
- config=types.GenerateContentConfig(
106
- temperature=0.0,
107
- max_output_tokens=2000,
108
- system_instruction="Du är en livsmedelsexpert med djup kunskap inom Sveriges och EUs lagar kring livsmedel.\
109
- Besvara användarens frågor enligt kontexten, ta hänsyn till alla filer som användaren tillhandahåller.\
110
- Var artig och pedagogisk. OM några förordningar finns med i kontexten SÅ avsluta varje meddelande med en lista av de relevanta förordningarna.",
111
- thinking_config=types.ThinkingConfig(thinking_budget=0),
112
- safety_settings=[
113
- types.SafetySetting(
114
- category="HARM_CATEGORY_DANGEROUS_CONTENT",
115
- threshold="BLOCK_MEDIUM_AND_ABOVE"
116
- ),
117
- types.SafetySetting(
118
- category="HARM_CATEGORY_HARASSMENT",
119
- threshold="BLOCK_MEDIUM_AND_ABOVE"
120
- ),
121
- types.SafetySetting(
122
- category="HARM_CATEGORY_SEXUALLY_EXPLICIT",
123
- threshold="BLOCK_MEDIUM_AND_ABOVE"
124
- ),
125
- types.SafetySetting(
126
- category="HARM_CATEGORY_HATE_SPEECH",
127
- threshold="BLOCK_MEDIUM_AND_ABOVE"
128
- )
129
- ]
130
- )
131
- )
132
-
133
- # Yield chunks for live updates
134
- partial_response = ""
135
- for chunk in gemini_stream:
136
- if chunk.text:
137
- partial_response += chunk.text
138
- yield partial_response
139
-
140
-
141
- except Exception as e:
142
- # Handle streaming failure without crashing the chatbot
143
- yield "Ursäkta, ett fel uppstod! Kan du upprepa dig snälla!"
144
- return
145
-
146
- with gr.Blocks(
147
- fill_height=True,
148
- css="""
149
- /* Colors commonly used on the website of livsmedelsverket and the kontrollwiki
150
- orange-crayola: #f2712e;
151
- white: #ffffff;
152
- van-dyke: #4c3d38;
153
- verdigris: #6cacad;
154
- dark-cyan: #2a898b;
155
- */
156
-
157
- /* Top title */
158
- .title {
159
- text-align: center;
160
- color: #f2712e;
161
- font-size: 60px;
162
- font-weight:bold;
163
- }
164
-
165
- /* Title text */
166
- .gradio-container .prose h1 {
167
- color: #f2712e !important;
168
- }
169
-
170
- /* Whole app background */
171
- .gradio-container {
172
- background-color: #6cacad !important;
173
- }
174
-
175
- #chat-bot .multimodal-textbox textarea {
176
- background-color: #ffffff;
177
- color: #4c3d38;
178
- border: 2px solid #6cacad;
179
- border-radius: 8px;
180
- padding: 6px;
181
- }
182
- #info-box .info-container {
183
- background-color: #f8b88b;
184
- color: #ffffff;
185
- padding: 12px;
186
- border: 2px solid #f2712e;
187
- border-radius: 10px ;
188
- }
189
-
190
- #info-box h3 {
191
- color: #f2712e !important;
192
- """) as demo:
193
- gr.HTML(
194
- """
195
- <div class="title">FoodLex</div>
196
- """
197
- )
198
- with gr.Row():
199
- with gr.Column(scale=3):
200
- with gr.Group(elem_id="chat-bot"):
201
- chatbot = gr.ChatInterface(
202
- fn=response_stream,
203
- chatbot=gr.Chatbot(height=600),
204
- multimodal=True,
205
- textbox=gr.MultimodalTextbox(
206
- placeholder="Fråga mig något, så hjälper jag dig!",
207
- file_count="multiple"),
208
- title="Din livsmedelsexpert",
209
- )
210
- with gr.Column(scale=1):
211
- with gr.Group(elem_id="info-box"):
212
- gr.HTML(
213
- """
214
- <div class="info-container">
215
- <h3>Viktig information</h3>
216
- <p>Hej kära användare! Jag är din AI-livsmedelsexpert, här för att hjälpa dig med frågor kring livsmedel och relaterade lagar i Sverige och EU.<br><br>
217
- Trots min expertis kan jag ibland göra misstag, så tveka inte att dubbelkolla viktig information. Jag hämtar kontext från konsoliderade
218
- versioner av EU-lagar fram till september 2025, så för de allra senaste uppdateringarna rekommenderar jag att du konsulterar officiella
219
- källor såsom EUR-Lex eller experter inom området.<br><br>
220
- Tack för att du använder vår tjänst!</p>
221
- </div>
222
- """
223
- )
224
-
225
- if __name__ == "__main__":
226
-
227
- demo.launch(share=False)
 
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Created on Wed Oct 15 11:06:24 2025
4
+ Updated on Sun Oct 19 13:32:50 2025
5
+
6
+ @author 1: Lovisa
7
+ @author 2: Agnes
8
+ @author 3: Linus
9
+ """
10
+
11
+ import os
12
+ from google import genai
13
+ from google.genai import types
14
+ import gradio as gr
15
+ import mimetypes
16
+ import pdfplumber
17
+ from PIL import Image
18
+
19
+ KEY = os.environ.get("GEMINI_API_KEY")
20
+ FAISS_INDEX = os.environ.get("FAISS_FOLDER")
21
+
22
+ client = genai.Client(api_key=KEY)
23
+
24
+ default_model = "gemini-2.5-flash"
25
+
26
+ from langchain_community.vectorstores import FAISS # "db" to store and retrieve embeddings
27
+ from langchain_huggingface import HuggingFaceEmbeddings
28
+
29
+ embeddings = HuggingFaceEmbeddings(model_name="KBLab/sentence-bert-swedish-cased")
30
+
31
+ db = FAISS.load_local(FAISS_INDEX, embeddings, allow_dangerous_deserialization=True) # Load the vector database
32
+
33
+ def response_stream(inputs, history):
34
+ user_text = ""
35
+ user_images = []
36
+
37
+ if isinstance(inputs, dict):
38
+ user_text = inputs.get("text", "").lower()
39
+ files = inputs.get("files", [])
40
+
41
+ if files:
42
+ for file_path in files:
43
+ try:
44
+ mime_type, _ = mimetypes.guess_type(file_path) # Guesses "the filetype based on its filename, path or URL, given by url"
45
+
46
+ if mime_type and mime_type.startswith("image/"):
47
+ # Handle image input
48
+ user_images.append(Image.open(file_path))
49
+
50
+ elif mime_type and mime_type.startswith("text/"):
51
+ # Handle plain text input
52
+ with open(file_path, "r", encoding="utf-8", errors="ignore") as f:
53
+ user_text += "\n" + f.read()
54
+
55
+ elif mime_type == "application/pdf" or file_path.lower().endswith(".pdf"):
56
+ # Handle PDF input
57
+ try:
58
+ with pdfplumber.open(file_path) as pdf:
59
+ pdf_text = "\n".join(page.extract_text() or "" for page in pdf.pages)
60
+ user_text += "\n" + pdf_text
61
+ except Exception as e:
62
+ user_text += f"\n(Kunde inte läsa PDF: {e})"
63
+
64
+ else:
65
+ # Unsupported file types
66
+ user_text += "\n(Filtypen stöds inte ännu.)"
67
+ except Exception as e:
68
+ user_text += "\nFel vid läsning av fil {file_path}: {e}"
69
+
70
+ else:
71
+ user_text = inputs.lower()
72
+
73
+ # special greetings from example file
74
+ if user_text=="hej":
75
+ yield "Hej, jag är din livsmedelsexpert. Vad kan jag hjälpa dig med?"
76
+ return
77
+ elif "hejdå" in user_text:
78
+ yield "Hejdå! Ha en fortsatt trevlig dag :)"
79
+ return
80
+
81
+ history_text = "Fortsätt konversationen.\n\n"
82
+ for user_msg, bot_msg in history:
83
+ history_text += f"Användare: {user_msg}\nAssistent: {bot_msg}\n"
84
+
85
+ # Add context from RAG if any text has been inputted by the user
86
+ if len(user_text) > 0:
87
+ context = db.similarity_search(user_text, k=5)
88
+ history_text += "\n\n" + "Kontext:\n" + "".join([chunk.page_content + "\n Source: " + chunk.metadata["source"] for chunk in context]) + "\n"
89
+
90
+ # Add latest user input
91
+ history_text += f"Användare: {user_text}\nAssistent:"
92
+
93
+ contents = []
94
+ if len(user_images) > 0:
95
+ contents.extend(user_images)
96
+
97
+ contents.append(history_text)
98
+
99
+ try:
100
+ gemini_stream = client.models.generate_content_stream(
101
+ model=default_model,
102
+ contents=contents,
103
+ config=types.GenerateContentConfig(
104
+ temperature=0.0,
105
+ max_output_tokens=2000,
106
+ system_instruction="Du är en livsmedelsexpert med djup kunskap inom Sveriges och EUs lagar kring livsmedel.\
107
+ Besvara användarens frågor enligt kontexten, ta hänsyn till alla filer som användaren tillhandahåller.\
108
+ Var artig och pedagogisk. OM några förordningar finns med i kontexten avsluta varje meddelande med en lista av de relevanta förordningarna.",
109
+ thinking_config=types.ThinkingConfig(thinking_budget=0),
110
+ safety_settings=[
111
+ types.SafetySetting(
112
+ category="HARM_CATEGORY_DANGEROUS_CONTENT",
113
+ threshold="BLOCK_MEDIUM_AND_ABOVE"
114
+ ),
115
+ types.SafetySetting(
116
+ category="HARM_CATEGORY_HARASSMENT",
117
+ threshold="BLOCK_MEDIUM_AND_ABOVE"
118
+ ),
119
+ types.SafetySetting(
120
+ category="HARM_CATEGORY_SEXUALLY_EXPLICIT",
121
+ threshold="BLOCK_MEDIUM_AND_ABOVE"
122
+ ),
123
+ types.SafetySetting(
124
+ category="HARM_CATEGORY_HATE_SPEECH",
125
+ threshold="BLOCK_MEDIUM_AND_ABOVE"
126
+ )
127
+ ]
128
+ )
129
+ )
130
+
131
+ # Yield chunks for live updates
132
+ partial_response = ""
133
+ for chunk in gemini_stream:
134
+ if chunk.text:
135
+ partial_response += chunk.text
136
+ yield partial_response
137
+
138
+
139
+ except Exception as e:
140
+ # Handle streaming failure without crashing the chatbot
141
+ yield "Ursäkta, ett fel uppstod! Kan du upprepa dig snälla!"
142
+ return
143
+
144
+ with gr.Blocks(
145
+ fill_height=True,
146
+ css="""
147
+ /* Colors commonly used on the website of livsmedelsverket and the kontrollwiki
148
+ orange-crayola: #f2712e;
149
+ white: #ffffff;
150
+ van-dyke: #4c3d38;
151
+ verdigris: #6cacad;
152
+ dark-cyan: #2a898b;
153
+ */
154
+
155
+ /* Top title */
156
+ .title {
157
+ text-align: center;
158
+ color: #f2712e;
159
+ font-size: 60px;
160
+ font-weight:bold;
161
+ }
162
+
163
+ /* Title text */
164
+ .gradio-container .prose h1 {
165
+ color: #f2712e !important;
166
+ }
167
+
168
+ /* Whole app background */
169
+ .gradio-container {
170
+ background-color: #6cacad !important;
171
+ }
172
+
173
+ #chat-bot .multimodal-textbox textarea {
174
+ background-color: #ffffff;
175
+ color: #4c3d38;
176
+ border: 2px solid #6cacad;
177
+ border-radius: 8px;
178
+ padding: 6px;
179
+ }
180
+ #info-box .info-container {
181
+ background-color: #f8b88b;
182
+ color: #ffffff;
183
+ padding: 12px;
184
+ border: 2px solid #f2712e;
185
+ border-radius: 10px ;
186
+ }
187
+
188
+ #info-box h3 {
189
+ color: #f2712e !important;
190
+ """) as demo:
191
+ gr.HTML(
192
+ """
193
+ <div class="title">FoodLex</div>
194
+ """
195
+ )
196
+ with gr.Row():
197
+ with gr.Column(scale=3):
198
+ with gr.Group(elem_id="chat-bot"):
199
+ chatbot = gr.ChatInterface(
200
+ fn=response_stream,
201
+ chatbot=gr.Chatbot(height=600),
202
+ multimodal=True,
203
+ textbox=gr.MultimodalTextbox(
204
+ placeholder="Fråga mig något, så hjälper jag dig!",
205
+ file_count="multiple"),
206
+ title="Din livsmedelsexpert",
207
+ )
208
+ with gr.Column(scale=1):
209
+ with gr.Group(elem_id="info-box"):
210
+ gr.HTML(
211
+ """
212
+ <div class="info-container">
213
+ <h3>Viktig information</h3>
214
+ <p>Hej kära användare! Jag är din AI-livsmedelsexpert, här för att hjälpa dig med frågor kring livsmedel och relaterade lagar i Sverige och EU.<br><br>
215
+ Trots min expertis kan jag ibland göra misstag, så tveka inte att dubbelkolla viktig information. Jag hämtar kontext från konsoliderade
216
+ versioner av EU-lagar fram till september 2025, för de allra senaste uppdateringarna rekommenderar jag att du konsulterar officiella
217
+ källor såsom EUR-Lex eller experter inom området.<br><br>
218
+ Tack för att du använder vår tjänst!</p>
219
+ </div>
220
+ """
221
+ )
222
+
223
+ if __name__ == "__main__":
224
+
225
+ demo.launch(share=False)