enricorampazzo commited on
Commit
224e4de
1 Parent(s): d005419

streamlit ui and ondemand integration

Browse files
app.py CHANGED
@@ -1,3 +1,5 @@
 
 
1
  from pathlib import Path
2
 
3
  from llm_manager.llm_parser import LlmParser
@@ -7,6 +9,9 @@ from repository.repository import get_repository
7
  from repository.repository_abc import ModelRoles, Model
8
  from form.form import build_form_data_from_answers, write_pdf_form
9
 
 
 
 
10
 
11
  def check_for_missing_answers(parsed_questions: dict[int, str]):
12
  return [k for k in parsed_questions if parsed_questions[k] is None]
@@ -18,10 +23,9 @@ def ask_again(missing_questions: list[int], user_questions: list[str], parsed_qu
18
  parsed_questions[id_] = new_answer
19
 
20
 
21
- if __name__ == '__main__':
22
  prompts_manager = PromptsManager()
23
- user_prompt = input(f"Please describe what you need to do. To get the best results "
24
- f"try to answer all the following questions:\n{'\n'.join(prompts_manager.questions)}\n\n>")
25
 
26
  repository = get_repository("intel_npu", Model("meta-llama/Meta-Llama-3-8B-Instruct",
27
  ModelRoles("system", "user", "assistant")),
@@ -40,3 +44,76 @@ if __name__ == '__main__':
40
 
41
  form_data = build_form_data_from_answers(answers, categories, f"{Path(__file__, "..", "signature.png")}")
42
  write_pdf_form(form_data, Path("signed_form1.pdf"))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import uuid
3
  from pathlib import Path
4
 
5
  from llm_manager.llm_parser import LlmParser
 
9
  from repository.repository_abc import ModelRoles, Model
10
  from form.form import build_form_data_from_answers, write_pdf_form
11
 
12
+ import streamlit as st
13
+
14
+ user_msg = "Please describe what you need to do. To get the best results try to answer all the following questions:"
15
 
16
  def check_for_missing_answers(parsed_questions: dict[int, str]):
17
  return [k for k in parsed_questions if parsed_questions[k] is None]
 
23
  parsed_questions[id_] = new_answer
24
 
25
 
26
+ def use_command_line():
27
  prompts_manager = PromptsManager()
28
+ user_prompt = input(f"{user_msg}\n{'\n'.join(prompts_manager.questions)}\n\n>")
 
29
 
30
  repository = get_repository("intel_npu", Model("meta-llama/Meta-Llama-3-8B-Instruct",
31
  ModelRoles("system", "user", "assistant")),
 
44
 
45
  form_data = build_form_data_from_answers(answers, categories, f"{Path(__file__, "..", "signature.png")}")
46
  write_pdf_form(form_data, Path("signed_form1.pdf"))
47
+
48
+
49
+ def update_answer (answers, missing_answer):
50
+ answers[missing_answer] = getattr(st.session_state, f"ma_{missing_answer}")
51
+
52
+
53
+ def use_streamlit():
54
+ pm = PromptsManager()
55
+ help_ = f"{user_msg}\n\n{'\n'.join(pm.questions)}"
56
+ repository = get_repository("ondemand", Model("ondemand-gpt-3.5-turbo", ModelRoles("system", "user", "assistant")))
57
+ if not st.session_state.get("step"):
58
+ with st.form("Please describe your request"):
59
+ user_input = st.text_area("Your input", height=700, label_visibility="hidden", placeholder=help_, help=help_)
60
+ signature = st.file_uploader("Your signature", key="file_upload")
61
+ st.session_state["signature"] = signature
62
+ st.session_state["session_id"] = str(uuid.uuid4())
63
+ button = st.form_submit_button()
64
+
65
+ if button:
66
+ llama3 = "meta-llama/Meta-Llama-3-8B-Instruct"
67
+ # repository = get_repository("intel_npu", Model(llama3,
68
+ # ModelRoles("system", "user", "assistant")),
69
+ # pm.system_prompt, Path("llm_log.txt"))
70
+ st.session_state["step"] = "parsing_answers"
71
+ if st.session_state.get("step") == "parsing_answers":
72
+ with st.status("initialising LLM"):
73
+ repository.init()
74
+ with st.status("waiting for LLM"):
75
+ repository.send_prompt(pm.ingest_user_answers(user_input))
76
+ answer = repository.send_prompt(pm.verify_user_input_prompt(user_input))
77
+ with st.status("Checking for missing answers"):
78
+ st.session_state["answers"] = LlmParser.parse_verification_prompt_answers(answer['content'])
79
+
80
+ st.session_state["missing_answers"] = check_for_missing_answers(st.session_state["answers"])
81
+ if not st.session_state.get("missing_answers"):
82
+ st.session_state["step"] = "check_category"
83
+ else:
84
+ st.session_state["step"] = "ask_again"
85
+
86
+ if st.session_state.get("step") == "ask_again":
87
+ with st.form("form1"):
88
+ for ma in st.session_state["missing_answers"]:
89
+ st.text_input(pm.questions[ma].lower(), key=ma)
90
+ submitted = st.form_submit_button("Submit answers")
91
+ if submitted:
92
+ st.session_state["step"] = "check_category"
93
+ for ma in st.session_state["missing_answers"]:
94
+ st.session_state["answers"][ma] = st.session_state[ma]
95
+
96
+ if st.session_state.get("step") == "check_category":
97
+ with st.status("finding the work categories applicable to your work"):
98
+ answer = repository.send_prompt(pm.get_work_category(st.session_state["answers"][1]))
99
+ categories = LlmParser.parse_get_categories_answer(answer['content'])
100
+
101
+ with st.status("categories found, creating PDF form"):
102
+
103
+ form_filename = f"{st.session_state["session_id"]}_form.pdf"
104
+ st.session_state["form_filename"] = form_filename
105
+ form_data = build_form_data_from_answers(st.session_state["answers"], categories,
106
+ st.session_state.get("signature"))
107
+ write_pdf_form(form_data, Path(form_filename))
108
+ st.session_state["step"] = "form_created"
109
+ if st.session_state.get("step") == "form_created":
110
+ with open(Path(st.session_state["form_filename"]), "rb") as form:
111
+ st.download_button("download form", form.read(), mime="application/pdf")
112
+ start_over_button = st.button("Start over")
113
+ if start_over_button:
114
+ del st.session_state["step"]
115
+ os.unlink(st.session_state["form_filename"])
116
+
117
+
118
+ use_streamlit()
119
+ #use_command_line()
prompts/prompts_manager.py CHANGED
@@ -22,7 +22,7 @@ class PromptsManager:
22
  self.verification_prompt: str = verification_prompt
23
 
24
  def verify_user_input_prompt(self, user_prompt) -> str:
25
- return (f"Using only this information \n {user_prompt} \n Answer the following questions, if the answer is not present just answer null. "
26
  f"Put each answer in a new line, keep the answer brief "
27
  f"and maintain the order in which the questions are asked. Do not add any preamble: "
28
  f"{self.verification_prompt}")
 
22
  self.verification_prompt: str = verification_prompt
23
 
24
  def verify_user_input_prompt(self, user_prompt) -> str:
25
+ return (f"Using only this information \n {user_prompt} \n answer the following questions, if the answer is not present or you are not sure about the answer just answer null. "
26
  f"Put each answer in a new line, keep the answer brief "
27
  f"and maintain the order in which the questions are asked. Do not add any preamble: "
28
  f"{self.verification_prompt}")
repository/intel_npu.py CHANGED
@@ -42,7 +42,7 @@ class IntelNpuRepository(Repository):
42
  input_ids = (self.tokenizer.apply_chat_template(self.get_message_history(), add_generation_prompt=True,
43
  return_tensors="pt")
44
  .to(self.model.device))
45
- outputs = self.model.generate(input_ids, eos_token_id=self.terminators, do_sample=True, max_new_tokens=2000)
46
  generated_token_array = outputs[0][len(input_ids[0]):]
47
  generated_tokens = "".join(self.tokenizer.batch_decode(generated_token_array, skip_special_tokens=True))
48
  answer = {"role": self.get_model_info().roles.ai_role, "content": generated_tokens}
 
42
  input_ids = (self.tokenizer.apply_chat_template(self.get_message_history(), add_generation_prompt=True,
43
  return_tensors="pt")
44
  .to(self.model.device))
45
+ outputs = self.model.generate(input_ids, eos_token_id=self.terminators, do_sample=True, max_new_tokens=2000, cache_position=None)
46
  generated_token_array = outputs[0][len(input_ids[0]):]
47
  generated_tokens = "".join(self.tokenizer.batch_decode(generated_token_array, skip_special_tokens=True))
48
  answer = {"role": self.get_model_info().roles.ai_role, "content": generated_tokens}
repository/ondemand.py ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from pathlib import Path
3
+
4
+ import requests
5
+
6
+ from repository.repository_abc import Repository, Model, ModelRoles
7
+
8
+
9
+ class OndemandRepository(Repository):
10
+ session_url = "https://api.on-demand.io/chat/v1/sessions"
11
+ def __init__(self, model_info: Model, system_message: str = None, log_to_file:Path=None):
12
+ self.model_info = model_info
13
+ self.system_message = system_message
14
+ self.log_to_file = log_to_file
15
+ self.session_id = None
16
+
17
+ def init(self):
18
+ if not self.session_id:
19
+ headers = {"apiKey": os.getenv("API_KEY")}
20
+ session_body = {"pluginIds": [], "externalUserId": "virtualDAM"}
21
+ response = requests.post(self.session_url, headers=headers, json=session_body)
22
+ response_data = response.json()
23
+ self.session_id = response_data["data"]["id"]
24
+
25
+ def get_model_roles(self) -> ModelRoles:
26
+ return self.model_info.roles
27
+
28
+ def get_model_info(self) -> Model:
29
+ return self.model_info
30
+
31
+ def send_prompt(self, prompt: str, add_to_history: bool = None) -> dict[str, str]:
32
+ headers = {"apiKey": os.getenv("API_KEY")}
33
+ body = {'endpointId': 'predefined-openai-gpt3.5turbo', 'query': prompt, 'pluginIds': [], 'responseMode': 'sync'}
34
+ url = f'https://api.on-demand.io/chat/v1/sessions/{self.session_id}/query'
35
+ response = requests.post(url, headers=headers, json=body)
36
+ return {"content": response.json()["data"]["answer"]}
37
+
38
+ def get_message_history(self) -> list[dict[str, str]]:
39
+ return []
repository/repository.py CHANGED
@@ -2,14 +2,33 @@ from pathlib import Path
2
 
3
  from repository.intel_npu import IntelNpuRepository
4
  from repository.ollama import OllamaRepository
 
5
  from repository.repository_abc import Model
 
6
 
7
 
8
  def get_repository(implementation: str, model: Model, system_msg: str = None, log_to_file: Path = None):
9
  known_implementations = ["ollama", "intel_npu"]
10
- if not implementation or implementation.lower() not in ["ollama", "intel_npu"]:
11
  raise ValueError(f"Unknown implementation {implementation}. Known implementations: {known_implementations}")
12
  if "ollama" == implementation:
13
  return OllamaRepository(model, system_msg)
14
  if "intel_npu" == implementation:
15
  return IntelNpuRepository(model, system_msg, log_to_file)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
  from repository.intel_npu import IntelNpuRepository
4
  from repository.ollama import OllamaRepository
5
+ from repository.ondemand import OndemandRepository
6
  from repository.repository_abc import Model
7
+ from repository.testing_repo import TestingRepository
8
 
9
 
10
  def get_repository(implementation: str, model: Model, system_msg: str = None, log_to_file: Path = None):
11
  known_implementations = ["ollama", "intel_npu"]
12
+ if not implementation or implementation.lower() not in ["ollama", "intel_npu", "testing", "ondemand"]:
13
  raise ValueError(f"Unknown implementation {implementation}. Known implementations: {known_implementations}")
14
  if "ollama" == implementation:
15
  return OllamaRepository(model, system_msg)
16
  if "intel_npu" == implementation:
17
  return IntelNpuRepository(model, system_msg, log_to_file)
18
+ if "ondemand" == implementation:
19
+ return OndemandRepository(model, system_msg, log_to_file)
20
+ if "testing" == implementation:
21
+ return TestingRepository(prompts_answers=[
22
+ {
23
+ "role": "assistant",
24
+ "content": "OK"
25
+ },
26
+ {
27
+ "role": "assistant",
28
+ "content": "What is my full name?\n\nnull\n\nWhat is the nature of the work I need to do?\n\nPest control\n\nIn which community is the work taking place?\n\nJBR\n\nIn which building?\n\nnull\n\nIn which unit/apartment number?\n\nnull\n\nAm I the owner or the tenant?\n\nTenant\n\nIn which date is the work taking place?\n\n12/09/2024\n\nIn which date will the work finish?\n\n12/09/2024\n\nWhat is my contact number?\n\nnull\n\nWhat is the name of the contracting company?\n\nnull\n\nWhat is the contact number of the contracting company?\n\nnull\n\nWhat is the email of the contracting company?\n\nnull\n\nWhat is my email?\n\nnull"
29
+ },
30
+ {
31
+ "role":"assistant",
32
+ "content":"pest_control"
33
+ }
34
+ ])
repository/repository_abc.py CHANGED
@@ -28,7 +28,7 @@ class Repository(abc.ABC):
28
  def send_prompt(self, prompt: str, add_to_history: bool) -> dict[str, str]:
29
  pass
30
 
31
- def set_message_for_role(self, message: str, role: str):
32
  self.get_message_history().append({"role": role, "content": message})
33
 
34
  def init(self):
 
28
  def send_prompt(self, prompt: str, add_to_history: bool) -> dict[str, str]:
29
  pass
30
 
31
+ def set_message_for_role(self, role: str, message: str):
32
  self.get_message_history().append({"role": role, "content": message})
33
 
34
  def init(self):
repository/testing_repo.py ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Tuple
2
+
3
+
4
+ from repository.repository_abc import Repository, Model, ModelRoles
5
+
6
+
7
+ class TestingRepository(Repository):
8
+
9
+ def __init__(self, prompts_answers: list[dict[str, str]], model_info:Model=None):
10
+ self.prompt_answers = prompts_answers
11
+ self.next_answer = iter(self.prompt_answers)
12
+ self.message_history = []
13
+ self.model_info = model_info or Model("fake_model",
14
+ ModelRoles("system", "user", "assistant"))
15
+ def init(self):
16
+ pass
17
+
18
+ def send_prompt(self, prompt: str, add_to_history: bool = True) -> dict[str, str]:
19
+ response = next(self.next_answer)
20
+ if add_to_history:
21
+ self.get_message_history().append(response)
22
+ return response
23
+
24
+ def get_message_history(self) -> list[dict[str, str]]:
25
+ return self.message_history
26
+
27
+ def get_model_info(self) -> Model:
28
+ return self.model_info
29
+
30
+ def get_model_roles(self) -> ModelRoles:
31
+ return self.model_info.roles
utils/parsing_utils.py CHANGED
@@ -15,3 +15,6 @@ def find_and_parse_date(llm_answer: str) -> str | None:
15
  def find_and_parse_phone_number(llm_answer: str):
16
  return _find_and_parse(llm_answer, parse_phone_number_regex)
17
 
 
 
 
 
15
  def find_and_parse_phone_number(llm_answer: str):
16
  return _find_and_parse(llm_answer, parse_phone_number_regex)
17
 
18
+
19
+ def check_for_missing_answers(parsed_questions: dict[int, str]):
20
+ return [k for k in parsed_questions if parsed_questions[k] is None]