Spaces:
Sleeping
Sleeping
Commit
·
224e4de
1
Parent(s):
d005419
streamlit ui and ondemand integration
Browse files- app.py +80 -3
- prompts/prompts_manager.py +1 -1
- repository/intel_npu.py +1 -1
- repository/ondemand.py +39 -0
- repository/repository.py +20 -1
- repository/repository_abc.py +1 -1
- repository/testing_repo.py +31 -0
- utils/parsing_utils.py +3 -0
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 |
-
|
22 |
prompts_manager = PromptsManager()
|
23 |
-
user_prompt = input(f"
|
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
|
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,
|
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]
|