Kadi-IAM commited on
Commit
b0eeae2
1 Parent(s): 0063b11

Upload 5 files

Browse files
Files changed (3) hide show
  1. README.md +3 -1
  2. app.py +137 -86
  3. start.py +1 -1
README.md CHANGED
@@ -10,4 +10,6 @@ app_file: start.py
10
  pinned: false
11
  ---
12
 
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
10
  pinned: false
11
  ---
12
 
13
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
14
+
15
+ A simple RAG-chatbot which is linked to Kadi-demo instance using OAuth2 in Kadi.
app.py CHANGED
@@ -7,34 +7,35 @@ Ref: https://kadi.readthedocs.io/en/stable/httpapi/intro.html#oauth2-tokens
7
  Notes:
8
  1. register an application in Kadi (Setting->Applications)
9
  - Name: KadiOAuthTest
10
- - Website URL: http://127.0.0.1:8000
11
- - Redirect URIs: http://localhost:8000/auth
12
 
13
  And you will get Client ID and Client Secret, note them down and set in this file.
14
 
15
- 2. Start this app, and open browser with address "http://localhost:8000/"
16
-
17
  """
18
 
19
  import json
20
-
21
  import uvicorn
 
 
 
 
 
 
 
 
22
  from fastapi import FastAPI, Depends
23
  from starlette.responses import RedirectResponse
24
  from starlette.middleware.sessions import SessionMiddleware
25
  from authlib.integrations.starlette_client import OAuth, OAuthError
26
  from fastapi import Request
27
- import gradio as gr
28
- import kadi_apy
29
  from kadi_apy import KadiManager
30
  from requests.compat import urljoin
31
  from typing import List, Tuple
32
- import pymupdf
33
  from sentence_transformers import SentenceTransformer
34
- import numpy as np
35
- import faiss
36
  from dotenv import load_dotenv
37
- import os
38
 
39
  # Kadi OAuth settings
40
  load_dotenv()
@@ -44,6 +45,7 @@ SECRET_KEY = os.environ["SECRET_KEY"]
44
  huggingfacehub_api_token = os.environ["huggingfacehub_api_token"]
45
 
46
  from huggingface_hub import login
 
47
  login(token=huggingfacehub_api_token)
48
 
49
  # Set up OAuth
@@ -54,6 +56,7 @@ oauth = OAuth()
54
  instance = "my_instance" # "demo kit instance"
55
  host = "https://demo-kadi4mat.iam.kit.edu"
56
 
 
57
  base_url = host
58
  oauth.register(
59
  name="kadi4mat",
@@ -70,15 +73,22 @@ oauth.register(
70
 
71
  # Global LLM client
72
  from huggingface_hub import InferenceClient
 
73
  client = InferenceClient("meta-llama/Meta-Llama-3-8B-Instruct")
74
 
 
 
 
 
 
 
 
75
 
76
- embeddings_client = InferenceClient(model="sentence-transformers/all-mpnet-base-v2", token=huggingfacehub_api_token)
77
- # embeddings_model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2", trust_remote_code=True) # unused
78
- embeddings_model = SentenceTransformer("sentence-transformers/all-mpnet-base-v2", trust_remote_code=True)
79
 
80
  # Dependency to get the current user
81
  def get_user(request: Request):
 
 
82
  if "user_access_token" in request.session:
83
  token = request.session["user_access_token"]
84
  else:
@@ -97,14 +107,17 @@ def get_user(request: Request):
97
 
98
  @app.get("/")
99
  def public(request: Request, user=Depends(get_user)):
 
 
100
  root_url = gr.route_utils.get_root_url(request, "/", None)
101
- print("root url", root_url)
102
  if user:
103
  return RedirectResponse(url=f"{root_url}/gradio/")
104
  else:
105
  return RedirectResponse(url=f"{root_url}/main/")
106
 
107
 
 
108
  @app.route("/logout")
109
  async def logout(request: Request):
110
  request.session.pop("user", None)
@@ -114,24 +127,26 @@ async def logout(request: Request):
114
  return RedirectResponse(url="/")
115
 
116
 
 
117
  @app.route("/login")
118
  async def login(request: Request):
119
  root_url = gr.route_utils.get_root_url(request, "/login", None)
120
  redirect_uri = request.url_for("auth") # f"{root_url}/auth"
121
- redirect_uri = redirect_uri.replace(scheme='https')
122
- print("-----------in login")
123
- print("root_urlt", root_url)
124
- print("redirect_uri", redirect_uri)
125
- print("request", request)
126
  return await oauth.kadi4mat.authorize_redirect(request, redirect_uri)
127
 
128
 
 
129
  @app.route("/auth")
130
  async def auth(request: Request):
131
  root_url = gr.route_utils.get_root_url(request, "/auth", None)
132
- print("*****+ in auth")
133
- print("root_urlt", root_url)
134
- print("request", request)
135
  try:
136
  access_token = await oauth.kadi4mat.authorize_access_token(request)
137
  request.session["user_access_token"] = access_token["access_token"]
@@ -144,10 +159,13 @@ async def auth(request: Request):
144
 
145
 
146
  def greet(request: gr.Request):
 
 
147
  return f"Welcome to Kadichat, you're logged in as: {request.username}"
148
 
149
 
150
  def get_files_in_record(record_id, user_token, top_k=10):
 
151
 
152
  manager = KadiManager(instance=instance, host=host, pat=user_token)
153
 
@@ -192,6 +210,7 @@ def get_files_in_record(record_id, user_token, top_k=10):
192
 
193
 
194
  def get_all_records(user_token):
 
195
 
196
  if not user_token:
197
  return []
@@ -233,13 +252,16 @@ def get_all_records(user_token):
233
 
234
 
235
  def _init_user_token(request: gr.Request):
 
 
236
  user_token = request.request.session["user_access_token"]
237
  return user_token
238
 
239
 
 
240
  with gr.Blocks() as login_demo:
241
  gr.Markdown(
242
- """<br/><br/><br/><br/><br/><br/><br/><br/>
243
  <center>
244
  <h1>Welcome to KadiChat!</h1>
245
  <br/><br/>
@@ -247,7 +269,7 @@ with gr.Blocks() as login_demo:
247
  <br/><br/>
248
  Chat with Record in Kadi.</center>
249
  """
250
- )
251
  # Note: kadichat-logo is hosted on https://postimage.io/
252
 
253
  with gr.Row():
@@ -257,7 +279,7 @@ with gr.Blocks() as login_demo:
257
  btn = gr.Button("Sign in with Kadi (demo-instance)")
258
  with gr.Column():
259
  _btn_placeholder2 = gr.Button(visible=False)
260
-
261
  gr.Markdown(
262
  """<br/><br/><br/><br/>
263
  <center>
@@ -274,87 +296,92 @@ with gr.Blocks() as login_demo:
274
  """
275
  btn.click(None, js=_js_redirect)
276
 
277
- import tempfile
278
- import os
279
- import pymupdf
280
 
 
281
  class SimpleRAG:
282
  def __init__(self) -> None:
283
  self.documents = []
284
  self.embeddings_model = None
285
  self.embeddings = None
286
  self.index = None
287
- #self.load_pdf("Brandt et al_2024_Kadi_info_page.pdf")
288
- #self.build_vector_db()
289
 
290
  def load_pdf(self, file_path: str) -> None:
291
  """Extracts text from a PDF file and stores it in the property documents by page."""
 
292
  doc = pymupdf.open(file_path)
293
  self.documents = []
294
  for page_num in range(len(doc)):
295
  page = doc[page_num]
296
  text = page.get_text()
297
  self.documents.append({"page": page_num + 1, "content": text})
298
- print("PDF processed successfully!")
299
-
300
 
301
  def build_vector_db(self) -> None:
302
  """Builds a vector database using the content of the PDF."""
303
  if self.embeddings_model is None:
304
- self.embeddings_model = SentenceTransformer("jinaai/jina-embeddings-v2-small-en", trust_remote_code=True) # jinaai/jina-embeddings-v2-base-de?
305
- # Use embeddings_client
306
- print("now doing embedding")
307
- print("len of documents", len(self.documents))
308
- import time
309
- start =time.time()
310
- #embedding_responses = embeddings_client.post(json={"inputs":[doc["content"] for doc in self.documents]}, task="feature-extraction")
311
- #self.embeddings = np.array(json.loads(embedding_responses.decode()))
312
- self.embeddings = self.embeddings_model.encode([doc["content"] for doc in self.documents], show_progress_bar=True)
313
- end = time.time()
314
- print("cost time", end-start)
 
315
  self.index = faiss.IndexFlatL2(self.embeddings.shape[1])
316
  self.index.add(np.array(self.embeddings))
317
  print("Vector database built successfully!")
318
 
319
  def search_documents(self, query: str, k: int = 4) -> List[str]:
320
  """Searches for relevant documents using vector similarity."""
 
 
321
  # query_embedding = self.embeddings_model.encode([query], show_progress_bar=False)
322
- embedding_responses = embeddings_client.post(json={"inputs": [query]}, task="feature-extraction")
 
 
323
  query_embedding = json.loads(embedding_responses.decode())
324
  D, I = self.index.search(np.array(query_embedding), k)
325
  results = [self.documents[i]["content"] for i in I[0]]
326
  return results if results else ["No relevant documents found."]
327
 
 
328
  def chunk_text(text, chunk_size=2048, overlap_size=256, separators=["\n\n", "\n"]):
329
  """Chunk text into pieces of specified size with overlap, considering separators."""
330
-
331
  # Split the text by the separators
332
  for sep in separators:
333
  text = text.replace(sep, "\n")
334
-
335
  chunks = []
336
  start = 0
337
-
338
  while start < len(text):
339
  # Determine the end of the chunk, accounting for overlap and the chunk size
340
  end = min(len(text), start + chunk_size)
341
-
342
  # Find a natural break point at the newline to avoid cutting words
343
  if end < len(text):
344
- while end > start and text[end] != '\n':
345
  end -= 1
346
-
347
  chunk = text[start:end].strip() # Strip trailing whitespace
348
  chunks.append(chunk)
349
-
350
  # Move the start position forward by the overlap size
351
  start += chunk_size - overlap_size
352
-
353
  return chunks
354
-
 
355
  def load_and_chunk_pdf(file_path):
356
  """Extracts text from a PDF file and stores it in the property documents by chunks."""
357
-
358
  with pymupdf.open(file_path) as pdf:
359
  text = ""
360
  for page in pdf:
@@ -364,11 +391,13 @@ def load_and_chunk_pdf(file_path):
364
  documents = []
365
  for chunk in chunks:
366
  documents.append({"content": chunk, "metadata": pdf.metadata})
367
-
368
  return documents
369
 
370
- def load_pdf(file_path: str) -> None:
 
371
  """Extracts text from a PDF file and stores it in the property documents by page."""
 
372
  doc = pymupdf.open(file_path)
373
  documents = []
374
  for page_num in range(len(doc)):
@@ -377,12 +406,15 @@ def load_pdf(file_path: str) -> None:
377
  documents.append({"page": page_num + 1, "content": text})
378
  print("PDF processed successfully!")
379
  return documents
380
-
 
381
  def prepare_file_for_chat(record_id, file_names, token, progress=gr.Progress()):
 
 
382
  if not file_names:
383
  raise gr.Error("No file selected")
384
  progress(0, desc="Starting")
385
- # Create connection to kadi
386
  manager = KadiManager(instance=instance, host=host, pat=token)
387
  record = manager.record(identifier=record_id)
388
  progress(0.2, desc="Loading files...")
@@ -409,8 +441,12 @@ def prepare_file_for_chat(record_id, file_names, token, progress=gr.Progress()):
409
  progress(1, desc="ready to chat")
410
  return "ready to chat", user_rag
411
 
 
412
  def preprocess_response(response: str) -> str:
413
  """Preprocesses the response to make it more polished."""
 
 
 
414
  # response = response.strip()
415
  # response = response.replace("\n\n", "\n")
416
  # response = response.replace(" ,", ",")
@@ -422,12 +458,15 @@ def preprocess_response(response: str) -> str:
422
 
423
 
424
  def respond(message: str, history: List[Tuple[str, str]], user_session_rag):
425
-
 
426
  # message is the current input query from user
427
  # RAG
428
  retrieved_docs = user_session_rag.search_documents(message)
429
  context = "\n".join(retrieved_docs)
430
- system_message = "You are an assistant to help user to answer question related to Kadi based on Relevant documents.\nRelevant documents: {}".format(context)
 
 
431
  messages = [{"role": "assistant", "content": system_message}]
432
 
433
  # Add history for conversational chat, TODO
@@ -439,13 +478,21 @@ def respond(message: str, history: List[Tuple[str, str]], user_session_rag):
439
 
440
  messages.append({"role": "user", "content": f"\nQuestion: {message}"})
441
 
442
- print("-----------------")
443
- print(messages)
444
- print("-----------------")
445
  # Get anwser from LLM
446
- response = client.chat_completion(messages, max_tokens=2048, temperature=0.0) #, top_p=0.9)
447
- response_content = "".join([choice.message['content'] for choice in response.choices if 'content' in choice.message])
448
-
 
 
 
 
 
 
 
 
449
  # Process response
450
  polished_response = preprocess_response(response_content)
451
 
@@ -462,10 +509,9 @@ with gr.Blocks() as main_demo:
462
  # State for storing user token
463
  _state_user_token = gr.State([])
464
 
465
- user_session_rag = gr.State(
466
- "placeholder"#, time_to_live=3600
467
- ) # clean state after 1h
468
-
469
  with gr.Row():
470
  with gr.Column(scale=7):
471
  m = gr.Markdown("Welcome to Chatbot!")
@@ -496,7 +542,9 @@ with gr.Blocks() as main_demo:
496
 
497
  parse_files = gr.Button("Parse files")
498
  # message_box = gr.Markdown("")
499
- message_box = gr.Textbox(label="", value="progress bar", interactive=False)
 
 
500
  # Interactions
501
  # Update file list after selecting record
502
  record_list.select(
@@ -505,13 +553,15 @@ with gr.Blocks() as main_demo:
505
  outputs=record_file_dropdown,
506
  )
507
  # Prepare files for chatbot
508
- parse_files.click(fn=prepare_file_for_chat, inputs=[record_list, record_file_dropdown, _state_user_token], outputs=[message_box, user_session_rag])
 
 
 
 
509
 
510
  with gr.Row():
511
  txt_input = gr.Textbox(
512
- show_label=False,
513
- placeholder="Type your question here...",
514
- lines=1
515
  )
516
  submit_btn = gr.Button("Submit", scale=1)
517
  refresh_btn = gr.Button("Refresh Chat", scale=1, variant="secondary")
@@ -523,20 +573,21 @@ with gr.Blocks() as main_demo:
523
 
524
  gr.Examples(examples=example_questions, inputs=[txt_input])
525
 
526
- txt_input.submit(fn=respond, inputs=[txt_input, chatbot, user_session_rag], outputs=[chatbot, txt_input])
527
- submit_btn.click(fn=respond, inputs=[txt_input, chatbot, user_session_rag], outputs=[chatbot, txt_input])
 
 
 
 
 
 
 
 
 
528
  refresh_btn.click(lambda: [], None, chatbot)
529
 
530
  app = gr.mount_gradio_app(app, main_demo, path="/gradio", auth_dependency=get_user)
531
 
532
 
533
- # def launch_gradio():
534
- # login_demo.launch(server_port=7860, host="0.0.0.0", share=True)
535
-
536
-
537
- import threading
538
-
539
  if __name__ == "__main__":
540
- # Launch Gradio with share=True in a separate thread
541
- # threading.Thread(target=launch_gradio).start()
542
  uvicorn.run(app, port=7860, host="0.0.0.0")
 
7
  Notes:
8
  1. register an application in Kadi (Setting->Applications)
9
  - Name: KadiOAuthTest
10
+ - Website URL: http://127.0.0.1:7860
11
+ - Redirect URIs: http://localhost:7860/auth
12
 
13
  And you will get Client ID and Client Secret, note them down and set in this file.
14
 
15
+ 2. Start this app, and open browser with address "http://localhost:7860/"
16
+ - if you are starting this app on Huggingface, use "start.py" instead.
17
  """
18
 
19
  import json
 
20
  import uvicorn
21
+ import gradio as gr
22
+ import kadi_apy
23
+ import pymupdf
24
+ import numpy as np
25
+ import faiss
26
+ import os
27
+ import tempfile
28
+ import pymupdf
29
  from fastapi import FastAPI, Depends
30
  from starlette.responses import RedirectResponse
31
  from starlette.middleware.sessions import SessionMiddleware
32
  from authlib.integrations.starlette_client import OAuth, OAuthError
33
  from fastapi import Request
 
 
34
  from kadi_apy import KadiManager
35
  from requests.compat import urljoin
36
  from typing import List, Tuple
 
37
  from sentence_transformers import SentenceTransformer
 
 
38
  from dotenv import load_dotenv
 
39
 
40
  # Kadi OAuth settings
41
  load_dotenv()
 
45
  huggingfacehub_api_token = os.environ["huggingfacehub_api_token"]
46
 
47
  from huggingface_hub import login
48
+
49
  login(token=huggingfacehub_api_token)
50
 
51
  # Set up OAuth
 
56
  instance = "my_instance" # "demo kit instance"
57
  host = "https://demo-kadi4mat.iam.kit.edu"
58
 
59
+ # Register oauth
60
  base_url = host
61
  oauth.register(
62
  name="kadi4mat",
 
73
 
74
  # Global LLM client
75
  from huggingface_hub import InferenceClient
76
+
77
  client = InferenceClient("meta-llama/Meta-Llama-3-8B-Instruct")
78
 
79
+ # Mixed-usage of huggingface client and local model for showing 2 possibilities
80
+ embeddings_client = InferenceClient(
81
+ model="sentence-transformers/all-mpnet-base-v2", token=huggingfacehub_api_token
82
+ )
83
+ embeddings_model = SentenceTransformer(
84
+ "sentence-transformers/all-mpnet-base-v2", trust_remote_code=True
85
+ )
86
 
 
 
 
87
 
88
  # Dependency to get the current user
89
  def get_user(request: Request):
90
+ """Validate and get user information."""
91
+
92
  if "user_access_token" in request.session:
93
  token = request.session["user_access_token"]
94
  else:
 
107
 
108
  @app.get("/")
109
  def public(request: Request, user=Depends(get_user)):
110
+ """Main extrance of app."""
111
+
112
  root_url = gr.route_utils.get_root_url(request, "/", None)
113
+ # print("root url", root_url)
114
  if user:
115
  return RedirectResponse(url=f"{root_url}/gradio/")
116
  else:
117
  return RedirectResponse(url=f"{root_url}/main/")
118
 
119
 
120
+ # Logout
121
  @app.route("/logout")
122
  async def logout(request: Request):
123
  request.session.pop("user", None)
 
127
  return RedirectResponse(url="/")
128
 
129
 
130
+ # Login
131
  @app.route("/login")
132
  async def login(request: Request):
133
  root_url = gr.route_utils.get_root_url(request, "/login", None)
134
  redirect_uri = request.url_for("auth") # f"{root_url}/auth"
135
+ redirect_uri = redirect_uri.replace(scheme="https") # required by Kadi
136
+ # print("-----------in login")
137
+ # print("root_urlt", root_url)
138
+ # print("redirect_uri", redirect_uri)
139
+ # print("request", request)
140
  return await oauth.kadi4mat.authorize_redirect(request, redirect_uri)
141
 
142
 
143
+ # Get auth
144
  @app.route("/auth")
145
  async def auth(request: Request):
146
  root_url = gr.route_utils.get_root_url(request, "/auth", None)
147
+ # print("*****+ in auth")
148
+ # print("root_urlt", root_url)
149
+ # print("request", request)
150
  try:
151
  access_token = await oauth.kadi4mat.authorize_access_token(request)
152
  request.session["user_access_token"] = access_token["access_token"]
 
159
 
160
 
161
  def greet(request: gr.Request):
162
+ """Show greeting message."""
163
+
164
  return f"Welcome to Kadichat, you're logged in as: {request.username}"
165
 
166
 
167
  def get_files_in_record(record_id, user_token, top_k=10):
168
+ """Get all file list within one record."""
169
 
170
  manager = KadiManager(instance=instance, host=host, pat=user_token)
171
 
 
210
 
211
 
212
  def get_all_records(user_token):
213
+ """Get all record list in Kadi."""
214
 
215
  if not user_token:
216
  return []
 
252
 
253
 
254
  def _init_user_token(request: gr.Request):
255
+ """Init user token."""
256
+
257
  user_token = request.request.session["user_access_token"]
258
  return user_token
259
 
260
 
261
+ # Landing page for login
262
  with gr.Blocks() as login_demo:
263
  gr.Markdown(
264
+ """<br/><br/><br/><br/><br/><br/><br/><br/>
265
  <center>
266
  <h1>Welcome to KadiChat!</h1>
267
  <br/><br/>
 
269
  <br/><br/>
270
  Chat with Record in Kadi.</center>
271
  """
272
+ )
273
  # Note: kadichat-logo is hosted on https://postimage.io/
274
 
275
  with gr.Row():
 
279
  btn = gr.Button("Sign in with Kadi (demo-instance)")
280
  with gr.Column():
281
  _btn_placeholder2 = gr.Button(visible=False)
282
+
283
  gr.Markdown(
284
  """<br/><br/><br/><br/>
285
  <center>
 
296
  """
297
  btn.click(None, js=_js_redirect)
298
 
 
 
 
299
 
300
+ # A simple RAG implementation
301
  class SimpleRAG:
302
  def __init__(self) -> None:
303
  self.documents = []
304
  self.embeddings_model = None
305
  self.embeddings = None
306
  self.index = None
307
+ # self.load_pdf("Brandt et al_2024_Kadi_info_page.pdf")
308
+ # self.build_vector_db()
309
 
310
  def load_pdf(self, file_path: str) -> None:
311
  """Extracts text from a PDF file and stores it in the property documents by page."""
312
+
313
  doc = pymupdf.open(file_path)
314
  self.documents = []
315
  for page_num in range(len(doc)):
316
  page = doc[page_num]
317
  text = page.get_text()
318
  self.documents.append({"page": page_num + 1, "content": text})
319
+ # print("PDF processed successfully!")
 
320
 
321
  def build_vector_db(self) -> None:
322
  """Builds a vector database using the content of the PDF."""
323
  if self.embeddings_model is None:
324
+ self.embeddings_model = SentenceTransformer(
325
+ "sentence-transformers/all-mpnet-base-v2", trust_remote_code=True
326
+ ) # jinaai/jina-embeddings-v2-base-de?
327
+
328
+ # Use local model
329
+ # print("now doing embedding")
330
+ # print("len of documents", len(self.documents))
331
+ # embedding_responses = embeddings_client.post(json={"inputs":[doc["content"] for doc in self.documents]}, task="feature-extraction")
332
+ # self.embeddings = np.array(json.loads(embedding_responses.decode()))
333
+ self.embeddings = self.embeddings_model.encode(
334
+ [doc["content"] for doc in self.documents], show_progress_bar=True
335
+ )
336
  self.index = faiss.IndexFlatL2(self.embeddings.shape[1])
337
  self.index.add(np.array(self.embeddings))
338
  print("Vector database built successfully!")
339
 
340
  def search_documents(self, query: str, k: int = 4) -> List[str]:
341
  """Searches for relevant documents using vector similarity."""
342
+
343
+ # Use embeddings_client
344
  # query_embedding = self.embeddings_model.encode([query], show_progress_bar=False)
345
+ embedding_responses = embeddings_client.post(
346
+ json={"inputs": [query]}, task="feature-extraction"
347
+ )
348
  query_embedding = json.loads(embedding_responses.decode())
349
  D, I = self.index.search(np.array(query_embedding), k)
350
  results = [self.documents[i]["content"] for i in I[0]]
351
  return results if results else ["No relevant documents found."]
352
 
353
+
354
  def chunk_text(text, chunk_size=2048, overlap_size=256, separators=["\n\n", "\n"]):
355
  """Chunk text into pieces of specified size with overlap, considering separators."""
356
+
357
  # Split the text by the separators
358
  for sep in separators:
359
  text = text.replace(sep, "\n")
360
+
361
  chunks = []
362
  start = 0
363
+
364
  while start < len(text):
365
  # Determine the end of the chunk, accounting for overlap and the chunk size
366
  end = min(len(text), start + chunk_size)
367
+
368
  # Find a natural break point at the newline to avoid cutting words
369
  if end < len(text):
370
+ while end > start and text[end] != "\n":
371
  end -= 1
372
+
373
  chunk = text[start:end].strip() # Strip trailing whitespace
374
  chunks.append(chunk)
375
+
376
  # Move the start position forward by the overlap size
377
  start += chunk_size - overlap_size
378
+
379
  return chunks
380
+
381
+
382
  def load_and_chunk_pdf(file_path):
383
  """Extracts text from a PDF file and stores it in the property documents by chunks."""
384
+
385
  with pymupdf.open(file_path) as pdf:
386
  text = ""
387
  for page in pdf:
 
391
  documents = []
392
  for chunk in chunks:
393
  documents.append({"content": chunk, "metadata": pdf.metadata})
394
+
395
  return documents
396
 
397
+
398
+ def load_pdf(file_path):
399
  """Extracts text from a PDF file and stores it in the property documents by page."""
400
+
401
  doc = pymupdf.open(file_path)
402
  documents = []
403
  for page_num in range(len(doc)):
 
406
  documents.append({"page": page_num + 1, "content": text})
407
  print("PDF processed successfully!")
408
  return documents
409
+
410
+
411
  def prepare_file_for_chat(record_id, file_names, token, progress=gr.Progress()):
412
+ """Parse file and prepare RAG."""
413
+
414
  if not file_names:
415
  raise gr.Error("No file selected")
416
  progress(0, desc="Starting")
417
+ # Create connection to kadi
418
  manager = KadiManager(instance=instance, host=host, pat=token)
419
  record = manager.record(identifier=record_id)
420
  progress(0.2, desc="Loading files...")
 
441
  progress(1, desc="ready to chat")
442
  return "ready to chat", user_rag
443
 
444
+
445
  def preprocess_response(response: str) -> str:
446
  """Preprocesses the response to make it more polished."""
447
+
448
+ # Placeholder for preprocessing
449
+
450
  # response = response.strip()
451
  # response = response.replace("\n\n", "\n")
452
  # response = response.replace(" ,", ",")
 
458
 
459
 
460
  def respond(message: str, history: List[Tuple[str, str]], user_session_rag):
461
+ """Get respond from LLMs."""
462
+
463
  # message is the current input query from user
464
  # RAG
465
  retrieved_docs = user_session_rag.search_documents(message)
466
  context = "\n".join(retrieved_docs)
467
+ system_message = "You are an assistant to help user to answer question related to Kadi based on Relevant documents.\nRelevant documents: {}".format(
468
+ context
469
+ )
470
  messages = [{"role": "assistant", "content": system_message}]
471
 
472
  # Add history for conversational chat, TODO
 
478
 
479
  messages.append({"role": "user", "content": f"\nQuestion: {message}"})
480
 
481
+ # print("-----------------")
482
+ # print(messages)
483
+ # print("-----------------")
484
  # Get anwser from LLM
485
+ response = client.chat_completion(
486
+ messages, max_tokens=2048, temperature=0.0
487
+ ) # , top_p=0.9)
488
+ response_content = "".join(
489
+ [
490
+ choice.message["content"]
491
+ for choice in response.choices
492
+ if "content" in choice.message
493
+ ]
494
+ )
495
+
496
  # Process response
497
  polished_response = preprocess_response(response_content)
498
 
 
509
  # State for storing user token
510
  _state_user_token = gr.State([])
511
 
512
+ # State for user rag
513
+ user_session_rag = gr.State("placeholder")
514
+
 
515
  with gr.Row():
516
  with gr.Column(scale=7):
517
  m = gr.Markdown("Welcome to Chatbot!")
 
542
 
543
  parse_files = gr.Button("Parse files")
544
  # message_box = gr.Markdown("")
545
+ message_box = gr.Textbox(
546
+ label="", value="progress bar", interactive=False
547
+ )
548
  # Interactions
549
  # Update file list after selecting record
550
  record_list.select(
 
553
  outputs=record_file_dropdown,
554
  )
555
  # Prepare files for chatbot
556
+ parse_files.click(
557
+ fn=prepare_file_for_chat,
558
+ inputs=[record_list, record_file_dropdown, _state_user_token],
559
+ outputs=[message_box, user_session_rag],
560
+ )
561
 
562
  with gr.Row():
563
  txt_input = gr.Textbox(
564
+ show_label=False, placeholder="Type your question here...", lines=1
 
 
565
  )
566
  submit_btn = gr.Button("Submit", scale=1)
567
  refresh_btn = gr.Button("Refresh Chat", scale=1, variant="secondary")
 
573
 
574
  gr.Examples(examples=example_questions, inputs=[txt_input])
575
 
576
+ # Actions
577
+ txt_input.submit(
578
+ fn=respond,
579
+ inputs=[txt_input, chatbot, user_session_rag],
580
+ outputs=[chatbot, txt_input],
581
+ )
582
+ submit_btn.click(
583
+ fn=respond,
584
+ inputs=[txt_input, chatbot, user_session_rag],
585
+ outputs=[chatbot, txt_input],
586
+ )
587
  refresh_btn.click(lambda: [], None, chatbot)
588
 
589
  app = gr.mount_gradio_app(app, main_demo, path="/gradio", auth_dependency=get_user)
590
 
591
 
 
 
 
 
 
 
592
  if __name__ == "__main__":
 
 
593
  uvicorn.run(app, port=7860, host="0.0.0.0")
start.py CHANGED
@@ -1,4 +1,4 @@
1
  import subprocess
2
 
3
- subprocess.run("kadi-apy config create", shell=True)
4
  subprocess.run("uvicorn app:app --host 0.0.0.0 --port 7860", shell=True)
 
1
  import subprocess
2
 
3
+ subprocess.run("kadi-apy config create", shell=True) # check kadi
4
  subprocess.run("uvicorn app:app --host 0.0.0.0 --port 7860", shell=True)