Spaces:
Sleeping
Sleeping
ndis AI chatbot files
Browse files- __init__.py +0 -0
- app.py +128 -142
- data.json +298 -0
- requirements.txt +2 -6
- utils.py +171 -0
__init__.py
ADDED
File without changes
|
app.py
CHANGED
@@ -1,147 +1,133 @@
|
|
1 |
-
import
|
2 |
-
import
|
3 |
-
|
4 |
-
|
5 |
-
import
|
6 |
-
import panel as pn
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
async def random_url(_):
|
22 |
-
pet = random.choice(["cat", "dog"])
|
23 |
-
api_url = f"https://api.the{pet}api.com/v1/images/search"
|
24 |
-
async with aiohttp.ClientSession() as session:
|
25 |
-
async with session.get(api_url) as resp:
|
26 |
-
return (await resp.json())[0]["url"]
|
27 |
-
|
28 |
-
|
29 |
-
@pn.cache
|
30 |
-
def load_processor_model(
|
31 |
-
processor_name: str, model_name: str
|
32 |
-
) -> Tuple[CLIPProcessor, CLIPModel]:
|
33 |
-
processor = CLIPProcessor.from_pretrained(processor_name)
|
34 |
-
model = CLIPModel.from_pretrained(model_name)
|
35 |
-
return processor, model
|
36 |
-
|
37 |
-
|
38 |
-
async def open_image_url(image_url: str) -> Image:
|
39 |
-
async with aiohttp.ClientSession() as session:
|
40 |
-
async with session.get(image_url) as resp:
|
41 |
-
return Image.open(io.BytesIO(await resp.read()))
|
42 |
-
|
43 |
-
|
44 |
-
def get_similarity_scores(class_items: List[str], image: Image) -> List[float]:
|
45 |
-
processor, model = load_processor_model(
|
46 |
-
"openai/clip-vit-base-patch32", "openai/clip-vit-base-patch32"
|
47 |
-
)
|
48 |
-
inputs = processor(
|
49 |
-
text=class_items,
|
50 |
-
images=[image],
|
51 |
-
return_tensors="pt", # pytorch tensors
|
52 |
)
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
57 |
|
|
|
|
|
|
|
58 |
|
59 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
60 |
"""
|
61 |
-
|
62 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
63 |
"""
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
randomize_url = pn.widgets.Button(name="Randomize URL", align="end")
|
103 |
-
|
104 |
-
image_url = pn.widgets.TextInput(
|
105 |
-
name="Image URL to classify",
|
106 |
-
value=pn.bind(random_url, randomize_url),
|
107 |
-
)
|
108 |
-
class_names = pn.widgets.TextInput(
|
109 |
-
name="Comma separated class names",
|
110 |
-
placeholder="Enter possible class names, e.g. cat, dog",
|
111 |
-
value="cat, dog, parrot",
|
112 |
-
)
|
113 |
-
|
114 |
-
input_widgets = pn.Column(
|
115 |
-
"##### 😊 Click randomize or paste a URL to start classifying!",
|
116 |
-
pn.Row(image_url, randomize_url),
|
117 |
-
class_names,
|
118 |
-
)
|
119 |
-
|
120 |
-
# add interactivity
|
121 |
-
interactive_result = pn.panel(
|
122 |
-
pn.bind(process_inputs, image_url=image_url, class_names=class_names),
|
123 |
-
height=600,
|
124 |
-
)
|
125 |
-
|
126 |
-
# add footer
|
127 |
-
footer_row = pn.Row(pn.Spacer(), align="center")
|
128 |
-
for icon, url in ICON_URLS.items():
|
129 |
-
href_button = pn.widgets.Button(icon=icon, width=35, height=35)
|
130 |
-
href_button.js_on_click(code=f"window.open('{url}')")
|
131 |
-
footer_row.append(href_button)
|
132 |
-
footer_row.append(pn.Spacer())
|
133 |
-
|
134 |
-
# create dashboard
|
135 |
-
main = pn.WidgetBox(
|
136 |
-
input_widgets,
|
137 |
-
interactive_result,
|
138 |
-
footer_row,
|
139 |
-
)
|
140 |
-
|
141 |
-
title = "Panel Demo - Image Classification"
|
142 |
-
pn.template.BootstrapTemplate(
|
143 |
-
title=title,
|
144 |
-
main=main,
|
145 |
-
main_max_width="min(50%, 698px)",
|
146 |
-
header_background="#F08080",
|
147 |
-
).servable(title=title)
|
|
|
1 |
+
import os
|
2 |
+
import openai
|
3 |
+
import sys
|
4 |
+
sys.path.append('../..')
|
5 |
+
import utils
|
6 |
+
import panel as pn # GUI
|
7 |
+
pn.extension(template='bootstrap')
|
8 |
+
|
9 |
+
deployment_name = os.environ['DEPLOYMENT_ID']
|
10 |
+
|
11 |
+
def get_completion_from_messages(messages, engine=deployment_name, temperature=0, max_tokens=500):
|
12 |
+
openai.api_key = os.environ['API_KEY']
|
13 |
+
openai.api_base = os.environ['API_BASE']
|
14 |
+
openai.api_type = os.environ['API_TYPE']
|
15 |
+
openai.api_version = os.environ['API_VERSION']
|
16 |
+
response = openai.ChatCompletion.create(
|
17 |
+
engine=engine,
|
18 |
+
messages=messages,
|
19 |
+
temperature=temperature,
|
20 |
+
max_tokens=max_tokens,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
21 |
)
|
22 |
+
return response.choices[0].message["content"]
|
23 |
+
|
24 |
+
def get_moderation_from_input(user_input):
|
25 |
+
openai.api_key = os.environ['MOD_API_KEY']
|
26 |
+
openai.api_base = os.environ['MOD_API_BASE']
|
27 |
+
openai.api_type = "open_ai"
|
28 |
+
openai.api_version = None
|
29 |
+
response = openai.Moderation.create(input=user_input)
|
30 |
+
return response
|
31 |
+
|
32 |
+
def process_user_message(user_input, all_messages, debug=True):
|
33 |
+
delimiter = "```"
|
34 |
+
|
35 |
+
# Step 1: Check input to see if it flags the Moderation API or is a prompt injection
|
36 |
+
response = get_moderation_from_input(user_input)
|
37 |
+
moderation_output = response["results"][0]
|
38 |
|
39 |
+
if moderation_output["flagged"]:
|
40 |
+
print("Step 1: Input flagged by Moderation API.")
|
41 |
+
return "Sorry, we cannot process this request."
|
42 |
|
43 |
+
if debug: print("Step 1: Input passed moderation check.")
|
44 |
+
|
45 |
+
page_and_qm_response = utils.find_pages_and_qms_only(user_input)
|
46 |
+
#print(print(page_and_qm_response)
|
47 |
+
# Step 2: Extract the list of products
|
48 |
+
page_and_qm_list = utils.read_string_to_list(page_and_qm_response)
|
49 |
+
#print(page_and_qm_list)
|
50 |
+
|
51 |
+
if debug: print("Step 2: Extracted list of quality markers.")
|
52 |
+
|
53 |
+
# Step 3: If quality markers are found, look them up
|
54 |
+
qm_information = utils.generate_output_string(page_and_qm_list)
|
55 |
+
if debug: print("Step 3: Looked up quality marker information.")
|
56 |
+
|
57 |
+
# Step 4: Answer the user question
|
58 |
+
system_message = f"""
|
59 |
+
You are an experienced assistant in the domain of Behaviour Support Plans (BSPs). \
|
60 |
+
Respond in a friendly and helpful tone, with concise answers. \
|
61 |
+
Your response MUST be ONLY based on the relevant information provided to you.
|
62 |
+
Make sure to ask the user relevant follow-up questions.
|
63 |
"""
|
64 |
+
messages = [
|
65 |
+
{'role': 'system', 'content': system_message},
|
66 |
+
{'role': 'user', 'content': f"{delimiter}{user_input}{delimiter}"},
|
67 |
+
{'role': 'assistant', 'content': f"Relevant information:\n{qm_information}"}
|
68 |
+
]
|
69 |
+
|
70 |
+
final_response = get_completion_from_messages(all_messages + messages)
|
71 |
+
if debug:print("Step 4: Generated response to user question.")
|
72 |
+
all_messages = all_messages + messages[1:]
|
73 |
+
|
74 |
+
# Step 5: Put the answer through the Moderation API
|
75 |
+
response = get_moderation_from_input(final_response)
|
76 |
+
moderation_output = response["results"][0]
|
77 |
+
|
78 |
+
if moderation_output["flagged"]:
|
79 |
+
if debug: print("Step 5: Response flagged by Moderation API.")
|
80 |
+
return "Sorry, we cannot provide this information."
|
81 |
+
|
82 |
+
if debug: print("Step 5: Response passed moderation check.")
|
83 |
+
|
84 |
+
# Step 6: Ask the model if the response answers the initial user query well
|
85 |
+
user_message = f"""
|
86 |
+
Customer message: {delimiter}{user_input}{delimiter}
|
87 |
+
Agent response: {delimiter}{final_response}{delimiter}
|
88 |
+
|
89 |
+
Does the agent response sufficiently answer the customer question? \
|
90 |
+
Respond with a Y or N character, with no punctuation: \
|
91 |
+
Y - if the output sufficiently answers the question \
|
92 |
+
AND the response correctly uses the relevant information provided to the agent \
|
93 |
+
N - otherwise \
|
94 |
+
Output a single letter only.
|
95 |
"""
|
96 |
+
messages = [
|
97 |
+
{'role': 'system', 'content': system_message},
|
98 |
+
{'role': 'user', 'content': user_message}
|
99 |
+
]
|
100 |
+
evaluation_response = get_completion_from_messages(messages)
|
101 |
+
if debug: print("Step 6: Model evaluated the response.")
|
102 |
+
|
103 |
+
# Step 7: If yes, use this answer; if not, say that you will connect the user to a human
|
104 |
+
if "Y" in evaluation_response: # Using "in" instead of "==" to be safer for model output variation (e.g., "Y." or "Yes")
|
105 |
+
if debug: print("Step 7: Model approved the response.")
|
106 |
+
return final_response, all_messages
|
107 |
+
else:
|
108 |
+
if debug: print("Step 7: Model disapproved the response.")
|
109 |
+
neg_str = "I'm unable to provide the information you're looking for. Please try asking again."
|
110 |
+
return neg_str, all_messages
|
111 |
+
|
112 |
+
chat_box = pn.widgets.ChatBox(value=[
|
113 |
+
{"You": ""},
|
114 |
+
{"AI Assistant": "Greetings! Feel free to ask about the BSP summary document, such as pages, quality markers, AI models, and NLP topics."}
|
115 |
+
])
|
116 |
+
context = [{"role": "system", "content": "You are Service Assistant"}]
|
117 |
+
|
118 |
+
# Function that collects user and assistant messages over time
|
119 |
+
def collect_messages(event) -> None:
|
120 |
+
global context
|
121 |
+
user_input = event.new[-1]
|
122 |
+
user_message = user_input.get("You")
|
123 |
+
if user_message is None or user_message == "":
|
124 |
+
return
|
125 |
+
response, context = process_user_message(user_message, context, False)
|
126 |
+
context.append({"role": "assistant", "content": f"{response}"})
|
127 |
+
chat_box.append({"AI Assistant": response})
|
128 |
+
|
129 |
+
# Chat with the chatbot!
|
130 |
+
chat_box.param.watch(collect_messages, 'value')
|
131 |
+
|
132 |
+
dashboard = pn.Column(pn.pane.Markdown("# BSP Summary Document AI Assistant"), chat_box)
|
133 |
+
dashboard.servable()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
data.json
ADDED
@@ -0,0 +1,298 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"Q1": {
|
3 |
+
"page": "1",
|
4 |
+
"domain": "1",
|
5 |
+
"model_ids": [1, 2, 3, 4],
|
6 |
+
"topics": ["Age", "Gender", "Family History", "Diagnosed Disabilities", "Health Info", "Communication", "Likes", "Dislikes", "Sensory Experiences", "Goals & Aspirations"],
|
7 |
+
"text": "A summary description of the person who is the focus of the plan has been provided.",
|
8 |
+
"name": "Q1"
|
9 |
+
},
|
10 |
+
"Q2a": {
|
11 |
+
"page": "2",
|
12 |
+
"domain": "2",
|
13 |
+
"model_ids": [23, 31],
|
14 |
+
"topics": ["Person of Focus", "Exclusion Reason"],
|
15 |
+
"text": "The plan indicates that the person who is the focus of this plan was included in the assessment and data gathering processes OR an explanation has been provided as to why they were not included.",
|
16 |
+
"name": "Q2a"
|
17 |
+
},
|
18 |
+
"Q2b": {
|
19 |
+
"page": "2",
|
20 |
+
"domain": "2",
|
21 |
+
"model_ids": [5, 23, 25],
|
22 |
+
"topics": ["Stakeholder Interview", "File Review", "Observation / Communication", "Speak to Family", "Stakeholder Involvement", "Data Collectors", "Data Collected"],
|
23 |
+
"text": "The plan indicates that the focus person\u2019s family members, support staff, support providers and/or other professionals were included in the assessment and data gathering process.",
|
24 |
+
"name": "Q2b"
|
25 |
+
},
|
26 |
+
"Q2c": {
|
27 |
+
"page": "2",
|
28 |
+
"domain": "2",
|
29 |
+
"model_ids": [5, 7],
|
30 |
+
"topics": ["Stakeholder Interview", "File Review", "Observation / Communication", "Speak to Family", "Direct"],
|
31 |
+
"text": "The plan indicates that at least one direct data collection approach has been undertaken.",
|
32 |
+
"name": "Q2c"
|
33 |
+
},
|
34 |
+
"Q2d": {
|
35 |
+
"page": "2",
|
36 |
+
"domain": "2",
|
37 |
+
"model_ids": [6, 7],
|
38 |
+
"topics": ["Psychiatric Assessment", "Medical Assessment", "Speech and Language Assessment", "Indirect"],
|
39 |
+
"text": "The plan indicates that at least one indirect data collection approach has been undertaken.",
|
40 |
+
"name": "Q2d"
|
41 |
+
},
|
42 |
+
"Q3a": {
|
43 |
+
"page": "3",
|
44 |
+
"domain": "3",
|
45 |
+
"model_ids": [8],
|
46 |
+
"topics": ["Behaviour", "Glossary"],
|
47 |
+
"text": "All listed target behaviours are described in a way that would allow another person to act them out.",
|
48 |
+
"name": "Q3a"
|
49 |
+
},
|
50 |
+
"Q3b": {
|
51 |
+
"page": "3",
|
52 |
+
"domain": "3",
|
53 |
+
"model_ids": [8],
|
54 |
+
"topics": ["Frequency"],
|
55 |
+
"text": "Information has been provided about how often all the listed target behaviours occur (e.g., hourly, daily, weekly).",
|
56 |
+
"name": "Q3b"
|
57 |
+
},
|
58 |
+
"Q3c": {
|
59 |
+
"page": "3",
|
60 |
+
"domain": "3",
|
61 |
+
"model_ids": [8],
|
62 |
+
"topics": ["Duration"],
|
63 |
+
"text": "Information has been provided about how long all the listed target behaviours last for (e.g., seconds, minutes, hours, days).",
|
64 |
+
"name": "Q3c"
|
65 |
+
},
|
66 |
+
"Q3d": {
|
67 |
+
"page": "3",
|
68 |
+
"domain": "3",
|
69 |
+
"model_ids": [8],
|
70 |
+
"topics": ["Severity"],
|
71 |
+
"text": "Information has been provided about the severity of all the listed target behaviours (e.g., damage, disruption, injury, etc.).",
|
72 |
+
"name": "Q3d"
|
73 |
+
},
|
74 |
+
"Q3e": {
|
75 |
+
"page": "3",
|
76 |
+
"domain": "3",
|
77 |
+
"model_ids": [17],
|
78 |
+
"topics": ["Physical Signs", "Verbal Signs"],
|
79 |
+
"text": "All listed early warning signs are described in a way that is observable to others.",
|
80 |
+
"name": "Q3e"
|
81 |
+
},
|
82 |
+
"Q4a": {
|
83 |
+
"page": "3",
|
84 |
+
"domain": "4",
|
85 |
+
"model_ids": [9],
|
86 |
+
"topics": ["Triggers"],
|
87 |
+
"text": "The plan describes what is happening immediately before the target behaviour(s) are displayed, i.e., all identified triggers/antecedents are observable to others.",
|
88 |
+
"name": "Q4a"
|
89 |
+
},
|
90 |
+
"Q4b": {
|
91 |
+
"page": "3",
|
92 |
+
"domain": "4",
|
93 |
+
"model_ids": [9],
|
94 |
+
"topics": ["Consequences"],
|
95 |
+
"text": "The plan describes what happens immediately after the target behaviour(s) are displayed, i.e., all maintaining consequences are observable to others.",
|
96 |
+
"name": "Q4b"
|
97 |
+
},
|
98 |
+
"Q5b": {
|
99 |
+
"page": "3",
|
100 |
+
"domain": "5",
|
101 |
+
"model_ids": [12],
|
102 |
+
"topics": ["Background", "Contrubuting", "Sustaining", "Strength"],
|
103 |
+
"text": "The plan contains a formulation.",
|
104 |
+
"name": "Q5b"
|
105 |
+
},
|
106 |
+
"Q6b": {
|
107 |
+
"page": "4",
|
108 |
+
"domain": "6",
|
109 |
+
"model_ids": [15, 16],
|
110 |
+
"topics": ["Specific", "Measurable", "Achievable", "Relevant", "Timely", "Physical / Mental", "Relationships", "Personal Fulfillment", "Financial Stability", "Purpose / Impact"],
|
111 |
+
"text": "The plan contains at least one goal/objective that is related to the focus person\u2019s quality of life.",
|
112 |
+
"name": "Q6b"
|
113 |
+
},
|
114 |
+
"Q6c": {
|
115 |
+
"page": "4",
|
116 |
+
"domain": "6",
|
117 |
+
"model_ids": [15, 16],
|
118 |
+
"topics": ["Specific", "Measurable", "Achievable", "Relevant", "Timely", "Physical / Mental", "Relationships", "Personal Fulfillment", "Financial Stability", "Purpose / Impact"],
|
119 |
+
"text": "All goals are specific about who the goal/objective is for, what is to be achieved, when it will be achieved by.",
|
120 |
+
"name": "Q6c"
|
121 |
+
},
|
122 |
+
"Q7i": {
|
123 |
+
"page": "4",
|
124 |
+
"domain": "7",
|
125 |
+
"model_ids": [28],
|
126 |
+
"topics": ["Likes / Dislikes", "Interests", "Hobbies", "Relationships", "Employment", "Health", "Education"],
|
127 |
+
"text": "The plan specifies strategies that aim to enhance the focus person\u2019s quality of life and are not specifically related to the focus person\u2019s target behaviour(s).",
|
128 |
+
"name": "Q7i"
|
129 |
+
},
|
130 |
+
"Q7ii": {
|
131 |
+
"page": "4",
|
132 |
+
"domain": "7",
|
133 |
+
"model_ids": [14, 19],
|
134 |
+
"topics": ["Safety Strategy", "Setting Event Strategy", "Trigger Strategy", "Other Strategy"],
|
135 |
+
"text": "The plan specifies environmental strategies that address the identified setting events and/or triggers/antecedents.",
|
136 |
+
"name": "Q7ii"
|
137 |
+
},
|
138 |
+
"Q7iii": {
|
139 |
+
"page": "4",
|
140 |
+
"domain": "7",
|
141 |
+
"model_ids": [13, 19],
|
142 |
+
"topics": ["Replacement Behaviour", "Other Strategy"],
|
143 |
+
"text": "The plan specifies other strategies that will impact upon the focus person\u2019s target behaviour(s).",
|
144 |
+
"name": "Q7iii"
|
145 |
+
},
|
146 |
+
"Q7iv": {
|
147 |
+
"page": "4",
|
148 |
+
"domain": "7",
|
149 |
+
"model_ids": [27, 30],
|
150 |
+
"topics": ["Restrictive Intervention", "Physical Restraint", "Punitive Approaches"],
|
151 |
+
"text": "None of the proposed strategies reflect a restrictive practice (e.g., seclusion, restraint).",
|
152 |
+
"name": "Q7iv"
|
153 |
+
},
|
154 |
+
"Q7a": {
|
155 |
+
"page": "4",
|
156 |
+
"domain": "7",
|
157 |
+
"model_ids": [19, 14, 21, 29],
|
158 |
+
"topics": ["Safety Strategy", "Setting Event Strategy", "Trigger Strategy", "Other Strategy", "Privileges", "Breaks", "Verbal Praise", "Social Interaction", "Physical Rewards", "Attention", "When to Implement"],
|
159 |
+
"text": "All strategies are described in enough detail for someone to understand what needs to be done and when it needs to be implemented.",
|
160 |
+
"name": "Q7a"
|
161 |
+
},
|
162 |
+
"Q7b": {
|
163 |
+
"page": "4",
|
164 |
+
"domain": "7",
|
165 |
+
"model_ids": [13, 20, 21, 32],
|
166 |
+
"topics": ["Replacement Behaviour", "What", "How", "Who", "When", "Where", "Materials", "Privileges", "Breaks", "Verbal Praise", "Social Interaction", "Physical Rewards", "Attention", "Unneeded Teaching Reason"],
|
167 |
+
"text": "Does the plan propose to teach the person of focus alternative behaviours, functionally equivalent replacement behaviours and/or new skills?",
|
168 |
+
"name": "Q7b"
|
169 |
+
},
|
170 |
+
"Q8a": {
|
171 |
+
"page": "4",
|
172 |
+
"domain": "8",
|
173 |
+
"model_ids": [38],
|
174 |
+
"topics": ["Early Warning"],
|
175 |
+
"text": "A set of early warning signs for the target behaviour(s) are identified for the purposes of de-escalation.",
|
176 |
+
"name": "Q8a"
|
177 |
+
},
|
178 |
+
"Q8b": {
|
179 |
+
"page": "4",
|
180 |
+
"domain": "8",
|
181 |
+
"model_ids": [38],
|
182 |
+
"topics": ["Early Warning"],
|
183 |
+
"text": "At least one strategy relates to providing support to the person of focus when they start exhibiting the identified early warning signs.",
|
184 |
+
"name": "Q8b"
|
185 |
+
},
|
186 |
+
"Q8c": {
|
187 |
+
"page": "4",
|
188 |
+
"domain": "8",
|
189 |
+
"model_ids": [13],
|
190 |
+
"topics": ["Replacement Behaviour"],
|
191 |
+
"text": "At least one strategy relates to the person of focus being prompted to use an alternative response (e.g., a functionally equivalent behaviour, an alternative behaviour, moving onto another activity) when the target behaviour occurs.",
|
192 |
+
"name": "Q8c"
|
193 |
+
},
|
194 |
+
"Q8d": {
|
195 |
+
"page": "4",
|
196 |
+
"domain": "8",
|
197 |
+
"model_ids": [14],
|
198 |
+
"topics": ["Safety Strategy"],
|
199 |
+
"text": "At least one strategy relates to ensuring the safety of the person of focus and/or the people around them when the target behaviour(s) occur.",
|
200 |
+
"name": "Q8d"
|
201 |
+
},
|
202 |
+
"Q8e": {
|
203 |
+
"page": "4",
|
204 |
+
"domain": "8",
|
205 |
+
"model_ids": [18],
|
206 |
+
"topics": ["Debriefing Strategy"],
|
207 |
+
"text": "At least one strategy relates to debriefing with the person of focus and/or other relevant stakeholders at a designated time after the target behaviour(s) has subsided.",
|
208 |
+
"name": "Q8e"
|
209 |
+
},
|
210 |
+
"Q8f": {
|
211 |
+
"page": "4",
|
212 |
+
"domain": "8",
|
213 |
+
"model_ids": [27, 30],
|
214 |
+
"topics": ["Restrictive Intervention", "Physical Restraint", "Punitive Approaches"],
|
215 |
+
"text": "Restrictive interventions (e.g., seclusion, restraint) are not mentioned as a de-escalation strategy OR restrictive interventions are only discussed as a last resort strategy once all other de-escalation strategies have been implemented.",
|
216 |
+
"name": "Q8f"
|
217 |
+
},
|
218 |
+
"Q9a": {
|
219 |
+
"page": "5",
|
220 |
+
"domain": "9",
|
221 |
+
"model_ids": [5, 23, 25],
|
222 |
+
"topics": ["Stakeholder Interview", "Stakeholder Involvement", "Outcome Measurement Strategies"],
|
223 |
+
"text": "The plan describes at least one method of assessing the social validity of the proposed strategies (e.g., interview, rating scale).",
|
224 |
+
"name": "Q9a"
|
225 |
+
},
|
226 |
+
"Q9b": {
|
227 |
+
"page": "5",
|
228 |
+
"domain": "9",
|
229 |
+
"model_ids": [23, 31],
|
230 |
+
"topics": ["Person of Focus", "Exclusion Reason"],
|
231 |
+
"text": "The plan indicates that the focus person was consulted regarding the social validity of the proposed strategies OR an explanation has been provided around why they were not consulted.",
|
232 |
+
"name": "Q9b"
|
233 |
+
},
|
234 |
+
"Q9c": {
|
235 |
+
"page": "5",
|
236 |
+
"domain": "9",
|
237 |
+
"model_ids": [5, 23],
|
238 |
+
"topics": ["Stakeholder Interview", "Stakeholder Involvement", "Speak to Family"],
|
239 |
+
"text": "The plan indicates that the focus person\u2019s family members, support staff, support providers and/or other professionals were consulted regarding the social validity of the proposed strategies.",
|
240 |
+
"name": "Q9c"
|
241 |
+
},
|
242 |
+
"Q10a": {
|
243 |
+
"page": "5",
|
244 |
+
"domain": "10",
|
245 |
+
"model_ids": [24],
|
246 |
+
"topics": ["Implementors & Roles"],
|
247 |
+
"text": "At least one plan implementor and their role (e.g., parent, support staff) is identified in the plan.",
|
248 |
+
"name": "Q10a"
|
249 |
+
},
|
250 |
+
"Q10b": {
|
251 |
+
"page": "5",
|
252 |
+
"domain": "10",
|
253 |
+
"model_ids": [24],
|
254 |
+
"topics": ["Training Strategies"],
|
255 |
+
"text": "At least one strategy to train relevant plan implementors is proposed and indicates who will deliver the training.",
|
256 |
+
"name": "Q10b"
|
257 |
+
},
|
258 |
+
"Q10c": {
|
259 |
+
"page": "5",
|
260 |
+
"domain": "10",
|
261 |
+
"model_ids": [24],
|
262 |
+
"topics": ["Implementation Support"],
|
263 |
+
"text": "At least one strategy to support implementation in relevant settings (e.g., mentoring) is proposed and indicates who will deliver the strategy.",
|
264 |
+
"name": "Q10c"
|
265 |
+
},
|
266 |
+
"Q10d": {
|
267 |
+
"page": "5",
|
268 |
+
"domain": "10",
|
269 |
+
"model_ids": [24],
|
270 |
+
"topics": ["Communication Strategies"],
|
271 |
+
"text": "At least one strategy is proposed regarding how plan implementors will communicate with one another, relevant information about the plan and/or its implementation.",
|
272 |
+
"name": "Q10d"
|
273 |
+
},
|
274 |
+
"Q11a": {
|
275 |
+
"page": "5",
|
276 |
+
"domain": "11",
|
277 |
+
"model_ids": [25],
|
278 |
+
"topics": ["Outcome Measurement Strategies", "Data Collectors", "Data Collected"],
|
279 |
+
"text": "At least one outcome measurement strategy is proposed and indicates who will collect the data and what data will be collected.",
|
280 |
+
"name": "Q11a"
|
281 |
+
},
|
282 |
+
"Q11b": {
|
283 |
+
"page": "5",
|
284 |
+
"domain": "11",
|
285 |
+
"model_ids": [26],
|
286 |
+
"topics": ["Data Reviewer", "Reported To"],
|
287 |
+
"text": "The plan indicates who will review the data collected and who they will report the collated data to.",
|
288 |
+
"name": "Q11b"
|
289 |
+
},
|
290 |
+
"Q11c": {
|
291 |
+
"page": "5",
|
292 |
+
"domain": "11",
|
293 |
+
"model_ids": [26],
|
294 |
+
"topics": ["Review Meeting", "Review Timeframe"],
|
295 |
+
"text": "The plan provides a specific date or timeframe indicating when the plan will be reviewed.",
|
296 |
+
"name": "Q11c"
|
297 |
+
}
|
298 |
+
}
|
requirements.txt
CHANGED
@@ -1,6 +1,2 @@
|
|
1 |
-
|
2 |
-
|
3 |
-
transformers
|
4 |
-
numpy
|
5 |
-
torch
|
6 |
-
aiohttp
|
|
|
1 |
+
openai
|
2 |
+
panel
|
|
|
|
|
|
|
|
utils.py
ADDED
@@ -0,0 +1,171 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import json
|
3 |
+
import openai
|
4 |
+
from collections import defaultdict
|
5 |
+
|
6 |
+
deployment_name = "gpt-35-turbo"
|
7 |
+
|
8 |
+
data_file = 'data.json'
|
9 |
+
|
10 |
+
delimiter = "####"
|
11 |
+
|
12 |
+
def get_completion_from_messages(messages, engine=deployment_name, temperature=0, max_tokens=500):
|
13 |
+
openai.api_key = os.environ['API_KEY']
|
14 |
+
openai.api_base = os.environ['API_BASE']
|
15 |
+
openai.api_type = os.environ['API_TYPE']
|
16 |
+
openai.api_version = os.environ['API_VERSION']
|
17 |
+
response = openai.ChatCompletion.create(
|
18 |
+
engine=engine,
|
19 |
+
messages=messages,
|
20 |
+
temperature=temperature,
|
21 |
+
max_tokens=max_tokens,
|
22 |
+
)
|
23 |
+
return response.choices[0].message["content"]
|
24 |
+
|
25 |
+
def get_qms_and_pages():
|
26 |
+
qms = get_qms()
|
27 |
+
qms_by_page = defaultdict(list)
|
28 |
+
for qm_name, qm_info in qms.items():
|
29 |
+
page = qm_info.get('page')
|
30 |
+
if page:
|
31 |
+
qms_by_page[page].append(qm_name)
|
32 |
+
|
33 |
+
return dict(qms_by_page)
|
34 |
+
|
35 |
+
def get_qms():
|
36 |
+
with open(data_file, 'r') as file:
|
37 |
+
qms = json.load(file)
|
38 |
+
return qms
|
39 |
+
|
40 |
+
def find_pages_and_qms_only(user_input):
|
41 |
+
delimiter = "####"
|
42 |
+
example_string = """
|
43 |
+
Customer query: What topics are related to quality markers Q10c and Q5b? \
|
44 |
+
Your response: [{'page': '3', 'quality_marker': ['Q5b']}, {'page': '5', 'quality_marker': ['Q10c']}] \
|
45 |
+
Customer query: What topics are related to page 2? \
|
46 |
+
Your response: [{'page': '2', 'quality_marker': ['Q2a', 'Q2b', 'Q2c', 'Q2d']}]
|
47 |
+
"""
|
48 |
+
system_message = f"""
|
49 |
+
You will be provided with a customer query. \
|
50 |
+
The customer query will be delimited with {delimiter} characters. \
|
51 |
+
The customer is expected to query about some details related to pages or quality markers in Behaviour Support Plan (PBS) summary documents. \
|
52 |
+
For example, the customer may want to know which domains, models, topics, or descriptions are associated with a given page or quality marker. \
|
53 |
+
Your task is to output a python list of objects (dicts), where each object has the following keys: \
|
54 |
+
- 'page' \
|
55 |
+
- 'quality_marker' \
|
56 |
+
|
57 |
+
Rules: \
|
58 |
+
- 'page' value must be one of: 1, 2, 3, 4, 5. \
|
59 |
+
- 'quality_marker' value is a list of allowed quality markers \
|
60 |
+
- If a specific page number is mentioned, it must be associated with all the correct quality markers in the allowed quality markers list below. \
|
61 |
+
- If specific quality marker(s) are mentioned, the 'quality_marker' list in your response must only include the mentioned quality marker(s). \
|
62 |
+
- If no pages or quality markers are found, output an empty list. \
|
63 |
+
- Only output the list of objects (dicts), nothing else.
|
64 |
+
|
65 |
+
Allowed quality markers:
|
66 |
+
For page 1:
|
67 |
+
Q1
|
68 |
+
|
69 |
+
For page 2:
|
70 |
+
Q2a
|
71 |
+
Q2b
|
72 |
+
Q2c
|
73 |
+
Q2d
|
74 |
+
|
75 |
+
For page 3:
|
76 |
+
Q3a
|
77 |
+
Q3b
|
78 |
+
Q3c
|
79 |
+
Q3d
|
80 |
+
Q3e
|
81 |
+
Q4a
|
82 |
+
Q4b
|
83 |
+
Q5b
|
84 |
+
|
85 |
+
For page 4:
|
86 |
+
Q6b
|
87 |
+
Q6c
|
88 |
+
Q7i
|
89 |
+
Q7ii
|
90 |
+
Q7iii
|
91 |
+
Q7iv
|
92 |
+
Q7a
|
93 |
+
Q7b
|
94 |
+
Q8a
|
95 |
+
Q8b
|
96 |
+
Q8c
|
97 |
+
Q8d
|
98 |
+
Q8e
|
99 |
+
Q8f
|
100 |
+
|
101 |
+
For page 5:
|
102 |
+
Q9a
|
103 |
+
Q9b
|
104 |
+
Q9c
|
105 |
+
Q10a
|
106 |
+
Q10b
|
107 |
+
Q10c
|
108 |
+
Q10d
|
109 |
+
Q11a
|
110 |
+
Q11b
|
111 |
+
Q11c
|
112 |
+
|
113 |
+
Examples:
|
114 |
+
{example_string}
|
115 |
+
|
116 |
+
"""
|
117 |
+
|
118 |
+
messages = [
|
119 |
+
{'role':'system', 'content': system_message},
|
120 |
+
{'role':'user', 'content': f"{delimiter}{user_input}{delimiter}"},
|
121 |
+
]
|
122 |
+
return get_completion_from_messages(messages)
|
123 |
+
|
124 |
+
# qm look up (either by page or by qm within page)
|
125 |
+
def get_qm_by_name(name):
|
126 |
+
qms = get_qms()
|
127 |
+
return qms.get(name, None)
|
128 |
+
|
129 |
+
def get_qms_by_page(page):
|
130 |
+
qms = get_qms()
|
131 |
+
return [qm for qm in qms.values() if qm.get('page') == page]
|
132 |
+
|
133 |
+
def read_string_to_list(input_string):
|
134 |
+
if input_string is None:
|
135 |
+
return None
|
136 |
+
|
137 |
+
try:
|
138 |
+
input_string = input_string.replace("'", "\"") # Replace single quotes with double quotes for valid JSON
|
139 |
+
data = json.loads(input_string)
|
140 |
+
return data
|
141 |
+
except json.JSONDecodeError:
|
142 |
+
print("Error: Invalid JSON string")
|
143 |
+
return None
|
144 |
+
|
145 |
+
def generate_output_string(data_list):
|
146 |
+
output_string = ""
|
147 |
+
|
148 |
+
if data_list is None:
|
149 |
+
return output_string
|
150 |
+
|
151 |
+
for data in data_list:
|
152 |
+
try:
|
153 |
+
if "quality_marker" in data.keys():
|
154 |
+
qm_list = data["quality_marker"]
|
155 |
+
for qm_name in qm_list:
|
156 |
+
qm = get_qm_by_name(qm_name)
|
157 |
+
if qm:
|
158 |
+
output_string += json.dumps(qm, indent=4) + "\n"
|
159 |
+
else:
|
160 |
+
print(f"Error: Quality marker '{qm_name}' not found")
|
161 |
+
elif "page" in data:
|
162 |
+
page_no = data["page"]
|
163 |
+
page_qms = get_qms_by_page(page_no)
|
164 |
+
for qm in page_qms:
|
165 |
+
output_string += json.dumps(qm, indent=4) + "\n"
|
166 |
+
else:
|
167 |
+
print("Error: Invalid object format")
|
168 |
+
except Exception as e:
|
169 |
+
print(f"Error: {e}")
|
170 |
+
|
171 |
+
return output_string
|