10.9.26.75 updated ui, data, features, and backend
Browse filesui
+ added new page for summary generation and allows user to select specific
articles from the database for summary generation
+ updated app.py to include new page
data
+ created four local dataset for testing summary generation prompts
features
+ pulled features, application, cloud_db, chains from main branch (studies demo)
+ added generate summary prompt function to features.py
+ created hand_chains.py for manually creating summary prompt chains
(may be removed later)
+ removed cloud_textract since it was no longer used
+
env settings
+ updated requirements.txt to exclude unused packages
+ updated the backend_update.ipynb for the latest procedure plus all the
new function/class creation and experimentation.
On branch summary
Changes to be committed:
new file: .data/chain.json
new file: .data/instruction_agg_performance.json
new file: .data/overview_chains.json
new file: .data/summary_prompts.json
modified: README.md
modified: app.py
modified: application.py
modified: backend_update.ipynb
modified: chains.py
modified: cloud_db.py
deleted: cloud_textract.py
modified: features.py
new file: hand_chains.py
modified: requirements.txt
new file: ui_studies.py
modified: ui_summary.py
- .data/chain.json +0 -0
- .data/instruction_agg_performance.json +1 -0
- .data/overview_chains.json +1 -0
- .data/summary_prompts.json +0 -0
- README.md +9 -22
- app.py +2 -2
- application.py +1 -0
- backend_update.ipynb +0 -0
- chains.py +31 -33
- cloud_db.py +6 -2
- cloud_textract.py +0 -227
- features.py +76 -15
- hand_chains.py +44 -0
- requirements.txt +6 -9
- ui_studies.py +44 -0
- ui_summary.py +61 -23
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
[{"name":"clin-perfFUtable-FIN","inputs":"Change in Probing Depth\nFFI\nGlobal Rating of Change\nGood to Excellent Odom Score\nGrip Strength\nIncision Length\nJOA\nKaplan-Meier\nLikert\nMcCormick Grade\nNDI\nNeer's Grade\nPatient Improvement\nPSS\nPinch Strength\nPocket Depth\nROM\nStride Length\nSWMT\nTime to Fusion\nVAS Change\nVAS Score\nWalking Velocity\nNew Clinical Symptoms","chain":["Report ALL of the information of the above text by performing the following tasks.\n\nPerform the following tasks:\n1) REPORT each table with the SAME columns as listed.\n\n\nFor Each Table\n1) Report EACH \"table heading\".\n2) Identify if the Table has Groups or NO groups. \n A) If the Table has \"Group\", Report each Group Name as written in the text. \n B) If the Table has No Group, \n 1. Add a Column 0 named: \"Group\". Column 0 will precede Column 1.\n 2. Report: \"No Group\" for each row.\n\n3) Identify if the Table has a \"Preoperative Value (Units)\" or NO \"Preoperative Value (Units)\" Heading. \n A) If the Table has \"Preoperative Value (Units)\", Report each Preoperative Value as written in the text. \n B) If the Table has NO \"Preoperative Value (Units)\" Heading. \n 1. Add a Column 3a named: \"Group\". Column 3a will follow the \"Outcome\" Column\n 2. Report: \"Not Reported\" for each row.\n\n\n4) Report the corresponding Outcome, Values, and Study N for each \"Clinical Outcome\" Table.\n A) Report each VALUE to only One Decimal Point.\n\n5) IF the table is Vertical, Transpose each VERTICAL table to a HORIZONTAL table.\n\n\n\nOverall rules:\n1) Do not exclude any Groups. \n2) Do not exclude any Tables. \n3) Do not exclude any Outcomes.\n4) Do not exclude any Values."],"assessment":"clinical"},{"name":"rad-perfFUtable-FIN","inputs":"Adjacent Segment ROM\nCarpal Height Ratio\nCervical Lordosis Profeta Method\nChange in Disc Height\nChange in Segmental Lordosis Angle\nCoronal Vertical Axis\nDeltoid Tuberosity Index\nDisc Height\nEngh grading scale\nFatty Atrophy\nForaminal Area Height\nFusion Assessment\nFusion Events-simplified 2\nParallel Pitch Lines\nScrew Placement Accuracy\nSegmental Lordosis Angle","chain":["Report ALL of the information of the above text by performing the following tasks.\n\nPerform the following tasks:\n1) REPORT each table with the SAME columns as listed.\n\n\nFor Each Table\n1) Report EACH \"table heading\".\n2) Identify if the Table has Groups or NO groups. \n A) If the Table has \"Group\", Report each Group Name as written in the text. \n B) If the Table has No Group, \n 1. Add a Column 0 named: \"Group\". Column 0 will precede Column 1.\n 2. Report: \"No Group\" for each row.\n\n3) Identify if the Table has a \"Preoperative Value (Units)\" or NO \"Preoperative Value (Units)\" Heading. \n A) If the Table has \"Preoperative Value (Units)\", Report each Preoperative Value as written in the text. \n B) If the Table has NO \"Preoperative Value (Units)\" Heading. \n 1. Add a Column 3a named: \"Group\". Column 3a will follow the \"Outcome\" Column\n 2. Report: \"Not Reported\" for each row.\n\n\n4) Report the corresponding Outcome, Values, and Study N for each \"Radiologic Outcome\" Table.\n A) Report each VALUE to only One Decimal Point.\n\n5) IF the table is Vertical, Transpose each VERTICAL table to a HORIZONTAL table.\n\n\n\nOverall rules:\n1) Do not exclude any Groups. \n2) Do not exclude any Tables. \n3) Do not exclude any Outcomes.\n4) Do not exclude any Values."],"assessment":"radiologic"},{"name":"saf-Futable-FIN","inputs":"abb Nonunion-NG\nGeneric Combo-NG\nMerged Revision\/Reoperation-NG\nSubsidence-NG","chain":["From the above text, extract information to complete the following sections sequentially to create a TABLE. \nCreate ONE table with the following Heading and Columns.\n\nPerform the following tasks\n1) Create the following \"table heading\" as described. \n2) Create the following columns.\n3) Populate each column as described. \n\n\n\n\n\n1) Combine the above Tables. \n2) Create one Table Heading--\"Safety Outcome Summary\"\n\n3) Report EACH Column heading. Only report what is inside of quotes. Remove the Quotation marks and the terms \"Column\" and \"Heading\". \n NOTE: Report ALL the Column Headings in ONE ROW.\n A) REPLACE the first column heading as: \"Adverse Events\".\n B) Report the second column heading as: \"Event N\".\n C) Report the third column heading as: \"Study N\".\n D) Report the fourth column heading as: \"Event %\".\n 1. Report the Event % Value to One Decimal Point.\n Note: Do Not Report any Levels N column or values.\n\n4) Report the corresponding data for each Column Values for each \"Safety Outcome\" Table.\n A) Report all the Adverse Events in the First Column.\n B) Report all the Event N Values in the SAME Column.\n Note: For Duplicate adverse events chose the Highest Event N. Only report one Event N per Adverse Event.\n C) Report all the Study N Values in the SAME Column.\n D) Report all the Event % Values in the SAME Column.\n Note: For Duplicate adverse events chose the Highest Event %. Only report one Event % per Adverse Event.\n\n\n5) IF the table is Vertical, Transpose each VERTICAL table to a HORIZONTAL table."],"assessment":"safety"},{"name":"oth-perfFUtable-FIN","inputs":"Blood Loss\nHospital Charge\nLength of Hospital Stay\nNeed for ICU\nOperation Time\nTransfusion Rate\nTime to Readmission","chain":["Report ALL of the information of the above text by performing the following tasks.\n\nPerform the following tasks:\n1) REPORT each table with the SAME columns as listed.\n\n\nFor Each Table\n1) Report EACH \"table heading\".\n2) Identify if the Table has Groups or NO groups. \n A) If the Table has \"Group\", Report each Group Name as written in the text. \n B) If the Table has No Group, \n 1. Add a Column 0 named: \"Group\". Column 0 will precede Column 1.\n 2. Report: \"No Group\" for each row.\n\n3) Identify if the Table has NO \"Preoperative Value (Units)\" Heading. \n A) If the Table has NO \"Preoperative Value (Units)\" Heading:\n 1. INSERT a column named: \"Group\". The \"Group\" Column will follow the \"Outcome\" Column.\n 2. Report: \"Not Reported\" for each row.\n\n\n4) Report the corresponding Outcome, Values, and Study N for each \"Other Outcome\" Table.\n A) Report each VALUE to only One Decimal Point.\n\n5) IF the table is Vertical, Transpose each VERTICAL table to a HORIZONTAL table.\n\n\n\nOverall rules:\n1) Do not exclude any Groups. \n2) Do not exclude any Tables. \n3) Do not exclude any Outcomes.\n4) Do not exclude any Values."],"assessment":"other"}]
|
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
{"studyN-H1-spine-FIN": ["Study-FIN", "FU-FIN", "Number of Patients-Spine-FIN", "Preliminary Data"], "Summary Device-Spine-FIN": ["Study-FIN", "Device-Spine-FIN", "Preliminary Data"], "Summary Age-FIN": ["Study-FIN", "Age-FIN", "Preliminary Data"], "sup-V-spine-FIN": ["SupFix-Spine-FIN", "sup-H1-spine", "Number of Patients-Spine-FIN", "Study-FIN", "sup-H2-spine", "studyN-H1-spine", "Preliminary Data", "sup-H3-spine", "sup-H4-spine"], "bone-V-spine-FIN": ["Bone Graft-FIN", "bone-H1-spine", "Number of Patients-Spine-FIN", "Study-FIN", "bone-H2-spine", "studyN-H1-spine", "Preliminary Data", "bone-H3-spine", "bone-H4-spine"], "app-V-spine-FIN": ["Approach-FIN", "Number of Patients-Spine-FIN", "app-H1-spine", "Study-FIN", "studyN-H1-spine", "app-H2-spine", "Preliminary Data", "app-H3-spine", "app-H4-spine"], "pro-V-spine-FIN": ["Procedure-Spine-FIN", "Number of Patients-Spine-FIN", "pro-H1-spine", "Study-FIN", "studyN-H1-spine", "pro-H2-spine", "Preliminary Data", "pro-H3-spine", "pro-H4-spine"], "type-V-spine-FIN": ["Number of Patients-Spine-FIN", "type-H1-spine", "Study-FIN", "studyN-H1-spine", "type-H2-spine", "Preliminary Data", "type-H3-spine", "type-H4-spine"], "ind-V-spine-FIN": ["Indication Categories-Spine-FIN", "Number of Patients-Spine-FIN", "ind-H1-spine", "Study-FIN", "studyN-H1-spine", "ind-H2-spine", "Preliminary Data", "ind-H3-spine", "ind-H4-spine"], "gen-V-spine-FIN": ["Number of Patients-Spine-FIN", "Gender-FIN", "studyN-H1-spine", "gen-H1-spine", "Study-FIN", "gen-H2-spine", "Preliminary Data", "gen-H3-spine"], "ske-V-spine-FIN": ["DAskemat-FIN", "Number of Patients-Spine-FIN", "ske-H1-spine", "Study-FIN", "studyN-H1-spine", "ske-H2-spine", "Preliminary Data", "ske-H3-spine", "ske-H4-spine"], "loco-V-spine-FIN": ["Location-Spine-FIN", "loco-H1-spine", "loco-H2-spine", "Number of Patients-Spine-FIN", "Study-FIN", "", "loco-H3-spine", "studyN-H1-spine", "Preliminary Data", "loco-H4-spine"], "studyN-H1-extremity-FIN": ["Study-FIN", "FU-FIN", "Number of Patients-Extremity-FIN", "Preliminary Data"], "Summary Device-extremity-FIN": ["Study-FIN", "Device-Extremity-FIN", "Preliminary Data"], "bone-V-extremity-FIN": ["Bone Graft-FIN", "bone-H1-extremity", "Number of Patients-Extremity-FIN", "Study-FIN", "bone-H2-extremity", "studyN-H1-extremity", "Preliminary Data", "bone-H3-extremity", "bone-H4-extremity"], "app-V-extremity-FIN": ["Approach-FIN", "Number of Patients-Extremity-FIN", "app-H1-extremity", "Study-FIN", "studyN-H1-extremity", "app-H2-extremity", "Preliminary Data", "app-H3-extremity", "app-H4-extremity"], "pro-V-extremity-FIN": ["Procedure-Extremity-FIN", "Number of Patients-Extremity-FIN", "pro-H1-extremity", "Study-FIN", "studyN-H1-extremity", "pro-H2-extremity", "Preliminary Data", "pro-H3-extremity", "pro-H4-extremity"], "type-V-extremity-FIN": ["Number of Patients-Extremity-FIN", "type-H1-extremity", "Study-FIN", "studyN-H1-extremity", "type-H2-extremity", "Preliminary Data", "type-H3-extremity", "type-H4-extremity"], "ind-V-extremity-FIN": ["Indication Categories-Extremity-FIN", "Number of Patients-Extremity-FIN", "ind-H1-extremity", "Study-FIN", "studyN-H1-extremity", "ind-H2-extremity", "Preliminary Data", "ind-H3-extremity", "ind-H4-extremity"], "gen-V-extremity-FIN": ["Number of Patients-Extremity-FIN", "Gender-FIN", "studyN-H1-extremity", "gen-H1-extremity", "Study-FIN", "gen-H2-extremity", "Preliminary Data", "gen-H3-extremity"], "ske-V-extremity-FIN": ["DAskemat-FIN", "Number of Patients-Extremity-FIN", "ske-H1-extremity", "Study-FIN", "studyN-H1-extremity", "ske-H2-extremity", "Preliminary Data", "ske-H3-extremity", "ske-H4-extremity"], "loco-V-extremity-FIN": ["Location-Extremity-FIN", "", "loco-H1-extremity", "Number of Patients-Extremity-FIN", "Study-FIN", "loco-H3-extremity", "loco-H2-extremity", "studyN-H1-extremity", "Preliminary Data", "loco-H4-extremity"], "DAproc-H0-spine-FIN": ["DAprocedure-Spine-FIN"], "DAproc-V-spine-FIN": ["Study-FIN", "Daproc-H1-spine", "Preliminary Data", "DAproc-H2-spine", "DAproc-H3-spine"], "DAproc-H0-extremity-FIN": ["DAprocedure-Extremity-FIN"], "DAproc-V-extremity-FIN": ["Study-FIN", "Daproc-H1-extremity", "Preliminary Data", "DAproc-H2-extremity", "DAproc-H3-extremity"], "DAdatcoll-H0-spine-FIN": ["DAdatcoll-FIN"], "DAdatcoll-V-spine-FIN": ["Number of Patients-Spine-FIN", "studyN-H1-spine", "DAdatcoll-FIN", "DAdatcoll-H1-spine", "Study-FIN", "DAdatcoll-H2-spine", "Preliminary Data", "DAdatcoll-H3-spine"], "DAdatsor-H0-spine-FIN": ["DAdatsource-FIN"], "DAdatsor-V-spine-FIN": ["Number of Patients-Spine-FIN", "studyN-H1-spine", "DAdatsource-FIN", "DAdatsor-H1-spine", "Study-FIN", "DAdatsor-H2-spine", "Preliminary Data", "DAdatsor-H3-spine"], "DAperf-H0-spine-FIN": ["DAperf-FIN"], "DAperf-V-spine-FIN": ["Number of Patients-Spine-FIN", "studyN-H1-spine", "DAperf-FIN", "DAperf-H1-spine", "Study-FIN", "DAperf-H2-spine", "Preliminary Data", "DAperf-H3-spine"], "DAsaf-H0-spine-FIN": ["DAsaf-FIN"], "DAsaf-V-spine-FIN": ["Number of Patients-Spine-FIN", "studyN-H1-spine", "DAsaf-FIN", "DAsaf-H1-spine", "Study-FIN", "DAsaf-H2-spine", "Preliminary Data", "DAsaf-H3-spine"], "DAsufFU-H0-spine-FIN": ["DAsufFU-FIN"], "DAsufFU-V-spine-FIN": ["Number of Patients-Spine-FIN", "studyN-H1-spine", "DAsufFU-FIN", "DAsufFU-H1-spine", "Study-FIN", "DAsufFU-H2-spine", "Preliminary Data", "DAsufFU-H3-spine"], "DAdatcoll-H0-extremity-FIN": ["DAdatcoll-FIN"], "DAdatcoll-V-extremity-FIN": ["Number of Patients-Extremity-FIN", "studyN-H1-extremity", "DAdatcoll-FIN", "DAdatcoll-H1-extremity", "Study-FIN", "DAdatcoll-H2-extremity", "Preliminary Data", "DAdatcoll-H3-extremity"], "DAdatsor-H0-extremity-FIN": ["DAdatsource-FIN"], "DAdatsor-V-extremity-FIN": ["Number of Patients-Extremity-FIN", "studyN-H1-extremity", "DAdatsource-FIN", "DAdatsor-H1-extremity", "Study-FIN", "DAdatsor-H2-extremity", "Preliminary Data", "DAdatsor-H3-extremity"], "DAperf-H0-extremity-FIN": ["DAperf-FIN"], "DAperf-V-extremity-FIN": ["Number of Patients-Extremity-FIN", "studyN-H1-extremity", "DAperf-FIN", "DAperf-H1-extremity", "Study-FIN", "DAperf-H2-extremity", "Preliminary Data", "DAperf-H3-extremity"], "DAsaf-H0-extremity-FIN": ["DAsaf-FIN"], "DAsaf-V-extremity-FIN": ["Number of Patients-Extremity-FIN", "studyN-H1-extremity", "DAsaf-FIN", "DAsaf-H1-extremity", "Study-FIN", "DAsaf-H2-extremity", "Preliminary Data", "DAsaf-H3-extremity"], "DAsufFU-H0-extremity-FIN": ["DAsufFU-FIN"], "DAsufFU-V-extremity-FIN": ["Number of Patients-Extremity-FIN", "studyN-H1-extremity", "DAsufFU-FIN", "DAsufFU-H1-extremity", "Study-FIN", "DAsufFU-H2-extremity", "Preliminary Data", "DAsufFU-H3-extremity"]}
|
|
The diff for this file is too large to render.
See raw diff
|
|
|
|
@@ -1,5 +1,5 @@
|
|
| 1 |
---
|
| 2 |
-
title: AMRA
|
| 3 |
emoji: 👀
|
| 4 |
colorFrom: blue
|
| 5 |
colorTo: cyan
|
|
@@ -9,42 +9,29 @@ app_file: app.py
|
|
| 9 |
pinned: false
|
| 10 |
---
|
| 11 |
|
| 12 |
-
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
| 13 |
-
|
| 14 |
## AMRA Studies demo
|
|
|
|
| 15 |
AMRA Studies demo contains the functionality to utilize LLM and cofounder heuristic knowledge to process one
|
| 16 |
or multiple studies and return the results in a structured format.
|
| 17 |
|
| 18 |
-
It was deployed in huggingface spaces and can be accessed through here: https://amra-ai.com
|
| 19 |
|
| 20 |
### Introduction
|
|
|
|
| 21 |
In medical device industry, process of clinical studies is a crucial step to get validation of the product.
|
| 22 |
The process is very time consuming and requires a lot of manual work. The goal of this project is to automate
|
| 23 |
the process of clinical studies by utilizing LLM and cofounder heuristic knowledge.
|
| 24 |
|
| 25 |
### To host the demo locally
|
|
|
|
| 26 |
1. Clone the repo
|
| 27 |
2. Install the requirements
|
| 28 |
-
```
|
| 29 |
-
pip install -r requirements.txt
|
| 30 |
-
```
|
| 31 |
-
3. Run the app.py file
|
| 32 |
-
```
|
| 33 |
-
python app.py
|
| 34 |
-
```
|
| 35 |
-
|
| 36 |
-
### To use the demo
|
| 37 |
-
1. Log into https://amra-ai.com
|
| 38 |
-
2. Select the studies from the sidebar
|
| 39 |
-
3. Upload the study file
|
| 40 |
-
4. Click on the "Add" button
|
| 41 |
-
|
| 42 |
-
### Demo
|
| 43 |
-
|
| 44 |
-
<iframe src="https://amra-ai-studies.hf.space"><iframe>
|
| 45 |
|
|
|
|
| 46 |
|
| 47 |
### Limitations and bias
|
|
|
|
| 48 |
Currently the demo is only validated for the studies in the following anatomical regions:
|
|
|
|
| 49 |
+ Spine
|
| 50 |
-
+ Extremity
|
|
|
|
| 1 |
---
|
| 2 |
+
title: AMRA Summary demo
|
| 3 |
emoji: 👀
|
| 4 |
colorFrom: blue
|
| 5 |
colorTo: cyan
|
|
|
|
| 9 |
pinned: false
|
| 10 |
---
|
| 11 |
|
|
|
|
|
|
|
| 12 |
## AMRA Studies demo
|
| 13 |
+
|
| 14 |
AMRA Studies demo contains the functionality to utilize LLM and cofounder heuristic knowledge to process one
|
| 15 |
or multiple studies and return the results in a structured format.
|
| 16 |
|
| 17 |
+
It was deployed in huggingface spaces and can be accessed through here: [AMRA-AI](https://amra-ai.com)
|
| 18 |
|
| 19 |
### Introduction
|
| 20 |
+
|
| 21 |
In medical device industry, process of clinical studies is a crucial step to get validation of the product.
|
| 22 |
The process is very time consuming and requires a lot of manual work. The goal of this project is to automate
|
| 23 |
the process of clinical studies by utilizing LLM and cofounder heuristic knowledge.
|
| 24 |
|
| 25 |
### To host the demo locally
|
| 26 |
+
|
| 27 |
1. Clone the repo
|
| 28 |
2. Install the requirements
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
|
| 30 |
+
To access the demo, please visit: [AMRA-AI Studies](https://amra-ai-studies.hf.space)
|
| 31 |
|
| 32 |
### Limitations and bias
|
| 33 |
+
|
| 34 |
Currently the demo is only validated for the studies in the following anatomical regions:
|
| 35 |
+
|
| 36 |
+ Spine
|
| 37 |
+
+ Extremity
|
|
@@ -14,8 +14,8 @@ examples = []
|
|
| 14 |
|
| 15 |
def create_demo():
|
| 16 |
return gr.TabbedInterface(
|
| 17 |
-
[summary_page(),articles_page()],
|
| 18 |
-
["Summary","Articles"],
|
| 19 |
theme = gr.themes.Soft(primary_hue="sky",secondary_hue="orange"),
|
| 20 |
title="AMRA AI Medi Reader",
|
| 21 |
css = "footer {visibility: hidden}",
|
|
|
|
| 14 |
|
| 15 |
def create_demo():
|
| 16 |
return gr.TabbedInterface(
|
| 17 |
+
[summary_page(),articles_page(),preference_page()],
|
| 18 |
+
["Summary","Articles","User Preferences"],
|
| 19 |
theme = gr.themes.Soft(primary_hue="sky",secondary_hue="orange"),
|
| 20 |
title="AMRA AI Medi Reader",
|
| 21 |
css = "footer {visibility: hidden}",
|
|
@@ -90,6 +90,7 @@ app_data = {
|
|
| 90 |
"terms":[],
|
| 91 |
"summary":{},
|
| 92 |
"user":{
|
|
|
|
| 93 |
"performance outcome #1":{"assessment_step":"Clinical"},
|
| 94 |
"performance outcome #2":{"assessment_step":"Clinical"},
|
| 95 |
"safety outcome #1":{},
|
|
|
|
| 90 |
"terms":[],
|
| 91 |
"summary":{},
|
| 92 |
"user":{
|
| 93 |
+
"summary":{"articles":[]},
|
| 94 |
"performance outcome #1":{"assessment_step":"Clinical"},
|
| 95 |
"performance outcome #2":{"assessment_step":"Clinical"},
|
| 96 |
"safety outcome #1":{},
|
|
The diff for this file is too large to render.
See raw diff
|
|
|
|
@@ -2,43 +2,49 @@ import asyncio
|
|
| 2 |
import openai
|
| 3 |
|
| 4 |
from langchain.chat_models import ChatOpenAI
|
|
|
|
| 5 |
from langchain.prompts.chat import ChatPromptTemplate
|
| 6 |
-
from langchain.schema import BaseOutputParser
|
| 7 |
from application import *
|
| 8 |
|
| 9 |
-
from utility import read_pdf,
|
| 10 |
|
| 11 |
-
|
| 12 |
-
|
|
|
|
|
|
|
| 13 |
|
|
|
|
| 14 |
|
| 15 |
-
def parse(self, text: str, **kwargs):
|
| 16 |
-
"""Parse the output of an LLM call."""
|
| 17 |
-
if kwargs:
|
| 18 |
-
print(kwargs)
|
| 19 |
-
return text.strip().split(", ")
|
| 20 |
|
| 21 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
async def async_generate(article,name,chain,replacement_term=None):
|
| 23 |
if replacement_term:
|
| 24 |
-
|
| 25 |
else:
|
| 26 |
-
|
| 27 |
-
|
|
|
|
|
|
|
| 28 |
|
| 29 |
-
@
|
|
|
|
| 30 |
async def execute_concurrent(article,prompts):
|
| 31 |
-
|
| 32 |
-
temperature=0.0,
|
| 33 |
-
model_name="gpt-3.5-turbo-16k",
|
| 34 |
-
openai_api_key=openai.api_key)
|
| 35 |
tasks = []
|
| 36 |
|
| 37 |
prompt_type = article["logic"]
|
| 38 |
prompt_list = list(prompts.keys())
|
| 39 |
-
print(prompt_list)
|
| 40 |
|
| 41 |
-
|
| 42 |
while prompt_list:
|
| 43 |
name = prompt_list.pop(0)
|
| 44 |
p = prompts[name]
|
|
@@ -46,16 +52,14 @@ async def execute_concurrent(article,prompts):
|
|
| 46 |
missing_inputs = [s for s in p["input_list"] if s not in article]
|
| 47 |
for x in missing_inputs:
|
| 48 |
await execute_concurrent(article,{x:app_data["prompts"][x]})
|
| 49 |
-
|
| 50 |
-
# if any([s not in article for s in p["input_list"]]):
|
| 51 |
-
# # prompt_list.append(name)
|
| 52 |
-
# print("skip",name,"due to missing input",p["input_list"])
|
| 53 |
-
# continue
|
| 54 |
|
| 55 |
print("executing",p["assessment_step"],name)
|
| 56 |
input_text = "".join([article[s] for s in p["input_list"]])
|
| 57 |
-
|
|
|
|
|
|
|
| 58 |
chat_prompt = ChatPromptTemplate.from_messages([
|
|
|
|
| 59 |
("human",input_text),
|
| 60 |
("system",p[prompt_type]),
|
| 61 |
])
|
|
@@ -90,16 +94,10 @@ if __name__ == "__main__":
|
|
| 90 |
sample_content,_ = read_pdf(sample_artice)
|
| 91 |
|
| 92 |
llm = ChatOpenAI(temperature=0.0,model_name="gpt-3.5-turbo-16k")
|
| 93 |
-
# with open(".prompts/other/Need for ICU.txt") as f:
|
| 94 |
-
# prompt = f.read()
|
| 95 |
-
# name = "Need for ICU"
|
| 96 |
with open(".prompts/other/Operation Time.txt") as f:
|
| 97 |
prompt = f.read()
|
| 98 |
name = "Operation Time"
|
| 99 |
-
|
| 100 |
-
# prompt = f.read()
|
| 101 |
-
# name = "Blood Loss"
|
| 102 |
-
|
| 103 |
post_prompt_maping = {}
|
| 104 |
post_replace_term = lambda res,map=post_prompt_maping:replace_term(res,map=map)
|
| 105 |
|
|
|
|
| 2 |
import openai
|
| 3 |
|
| 4 |
from langchain.chat_models import ChatOpenAI
|
| 5 |
+
from langchain.chat_models.openai import _create_retry_decorator
|
| 6 |
from langchain.prompts.chat import ChatPromptTemplate
|
| 7 |
+
# from langchain.schema import BaseOutputParser
|
| 8 |
from application import *
|
| 9 |
|
| 10 |
+
from utility import read_pdf,aterminal_print
|
| 11 |
|
| 12 |
+
llm = ChatOpenAI(
|
| 13 |
+
temperature=0.0,
|
| 14 |
+
model_name="gpt-3.5-turbo-16k",
|
| 15 |
+
openai_api_key=openai.api_key)
|
| 16 |
|
| 17 |
+
retry_decorator = _create_retry_decorator(llm)
|
| 18 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
|
| 20 |
+
# class Replacement(BaseOutputParser):
|
| 21 |
+
# """Parse the output of an LLM call to a comma-separated list."""
|
| 22 |
+
# def parse(self, text: str, **kwargs):
|
| 23 |
+
# """Parse the output of an LLM call."""
|
| 24 |
+
# if kwargs:
|
| 25 |
+
# print(kwargs)
|
| 26 |
+
# return text.strip().split(", ")
|
| 27 |
+
|
| 28 |
+
@aterminal_print # need to review this.
|
| 29 |
async def async_generate(article,name,chain,replacement_term=None):
|
| 30 |
if replacement_term:
|
| 31 |
+
res = await chain.ainvoke({"term":replacement_term})
|
| 32 |
else:
|
| 33 |
+
res = await chain.ainvoke({"term":""})
|
| 34 |
+
|
| 35 |
+
print("completed",name)
|
| 36 |
+
article[name] = res.content
|
| 37 |
|
| 38 |
+
@aterminal_print # need to review this.
|
| 39 |
+
@retry_decorator
|
| 40 |
async def execute_concurrent(article,prompts):
|
| 41 |
+
|
|
|
|
|
|
|
|
|
|
| 42 |
tasks = []
|
| 43 |
|
| 44 |
prompt_type = article["logic"]
|
| 45 |
prompt_list = list(prompts.keys())
|
|
|
|
| 46 |
|
| 47 |
+
i = 0
|
| 48 |
while prompt_list:
|
| 49 |
name = prompt_list.pop(0)
|
| 50 |
p = prompts[name]
|
|
|
|
| 52 |
missing_inputs = [s for s in p["input_list"] if s not in article]
|
| 53 |
for x in missing_inputs:
|
| 54 |
await execute_concurrent(article,{x:app_data["prompts"][x]})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 55 |
|
| 56 |
print("executing",p["assessment_step"],name)
|
| 57 |
input_text = "".join([article[s] for s in p["input_list"]])
|
| 58 |
+
# with open(f".outputs/{i}_{name}.txt","w+") as f:
|
| 59 |
+
# f.write(input_text)
|
| 60 |
+
# f.write(p[prompt_type])
|
| 61 |
chat_prompt = ChatPromptTemplate.from_messages([
|
| 62 |
+
("system","You are a helpful AI that can answer questions about clinical trail and operation studies."),
|
| 63 |
("human",input_text),
|
| 64 |
("system",p[prompt_type]),
|
| 65 |
])
|
|
|
|
| 94 |
sample_content,_ = read_pdf(sample_artice)
|
| 95 |
|
| 96 |
llm = ChatOpenAI(temperature=0.0,model_name="gpt-3.5-turbo-16k")
|
|
|
|
|
|
|
|
|
|
| 97 |
with open(".prompts/other/Operation Time.txt") as f:
|
| 98 |
prompt = f.read()
|
| 99 |
name = "Operation Time"
|
| 100 |
+
|
|
|
|
|
|
|
|
|
|
| 101 |
post_prompt_maping = {}
|
| 102 |
post_replace_term = lambda res,map=post_prompt_maping:replace_term(res,map=map)
|
| 103 |
|
|
@@ -17,8 +17,12 @@ dynamodb data operations
|
|
| 17 |
# get the list of articles from articles table in dynamodb
|
| 18 |
@terminal_print
|
| 19 |
def get_table(table_name:str):
|
| 20 |
-
result = db_client.scan(TableName = table_name)
|
| 21 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
|
| 23 |
# add a new article to table articles in dynamodb, return error if failed
|
| 24 |
def post_item(table_name:str,item:dict):
|
|
|
|
| 17 |
# get the list of articles from articles table in dynamodb
|
| 18 |
@terminal_print
|
| 19 |
def get_table(table_name:str):
|
| 20 |
+
result = db_client.scan(TableName = table_name)
|
| 21 |
+
items = result["Items"]
|
| 22 |
+
while "LastEvaluatedKey" in result:
|
| 23 |
+
result = db_client.scan(TableName = table_name,ExclusiveStartKey = result["LastEvaluatedKey"])
|
| 24 |
+
items.extend(result["Items"])
|
| 25 |
+
return [db_map_to_py_dict(r) for r in items]
|
| 26 |
|
| 27 |
# add a new article to table articles in dynamodb, return error if failed
|
| 28 |
def post_item(table_name:str,item:dict):
|
|
@@ -1,227 +0,0 @@
|
|
| 1 |
-
import boto3
|
| 2 |
-
|
| 3 |
-
from utility import terminal_print, create_md_table
|
| 4 |
-
from application import aws_access_key_id, aws_secret_access_key, default_s3_bucket
|
| 5 |
-
|
| 6 |
-
textract = boto3.client(
|
| 7 |
-
'textract',
|
| 8 |
-
aws_access_key_id=aws_access_key_id,
|
| 9 |
-
aws_secret_access_key=aws_secret_access_key,
|
| 10 |
-
region_name='us-east-1')
|
| 11 |
-
|
| 12 |
-
@terminal_print
|
| 13 |
-
def textract_get_tables(res_tables,textract=textract):
|
| 14 |
-
'''
|
| 15 |
-
This function is used to get the tables from the textract output
|
| 16 |
-
|
| 17 |
-
Parameters:
|
| 18 |
-
res_tables: the output from the textract.get_document_analysis function
|
| 19 |
-
textract: the boto3 client for textract
|
| 20 |
-
|
| 21 |
-
Returns:
|
| 22 |
-
result: the cascaded output with blocks from the textract.get_document_analysis function
|
| 23 |
-
'''
|
| 24 |
-
job_id = res_tables["JobId"]
|
| 25 |
-
temp = result = res_tables.copy()
|
| 26 |
-
|
| 27 |
-
while "NextToken" in temp:
|
| 28 |
-
temp = textract.get_document_analysis(JobId=job_id,NextToken=temp["NextToken"])
|
| 29 |
-
result["Blocks"].extend(temp["Blocks"])
|
| 30 |
-
|
| 31 |
-
return result
|
| 32 |
-
|
| 33 |
-
@terminal_print
|
| 34 |
-
def textract_get_text(res_text,textract=textract):
|
| 35 |
-
'''
|
| 36 |
-
This function is used to get the text from the textract output
|
| 37 |
-
|
| 38 |
-
Parameters:
|
| 39 |
-
res_text: the output from the textract.get_document_text_detection function
|
| 40 |
-
textract: the boto3 client for textract
|
| 41 |
-
|
| 42 |
-
Returns:
|
| 43 |
-
result: the cascaded output with blocks from the textract.get_document_text_detection function
|
| 44 |
-
'''
|
| 45 |
-
job_id = res_text["JobId"]
|
| 46 |
-
temp = result = res_text.copy()
|
| 47 |
-
|
| 48 |
-
while "NextToken" in temp:
|
| 49 |
-
temp = textract.get_document_text_detection(JobId=job_id,NextToken=temp["NextToken"])
|
| 50 |
-
result["Blocks"].extend(temp["Blocks"])
|
| 51 |
-
|
| 52 |
-
return result
|
| 53 |
-
|
| 54 |
-
@terminal_print
|
| 55 |
-
def get_article_tables(file_name:str,bucket:str,delay:int=5):
|
| 56 |
-
'''
|
| 57 |
-
This function is used to get the tables from the textract output
|
| 58 |
-
|
| 59 |
-
Parameters:
|
| 60 |
-
file_name: the name of the file in the bucket
|
| 61 |
-
bucket: the name of the bucket
|
| 62 |
-
delay: the delay time for the textract.get_document_analysis function
|
| 63 |
-
|
| 64 |
-
Returns:
|
| 65 |
-
res_tables: the output from the textract.get_document_analysis function with initial blocks
|
| 66 |
-
'''
|
| 67 |
-
import time
|
| 68 |
-
# need to use async method to process the files
|
| 69 |
-
job_tables = textract.start_document_analysis(
|
| 70 |
-
DocumentLocation={
|
| 71 |
-
"S3Object":{
|
| 72 |
-
"Bucket":bucket,
|
| 73 |
-
"Name": file_name
|
| 74 |
-
}
|
| 75 |
-
},
|
| 76 |
-
FeatureTypes=["TABLES"]
|
| 77 |
-
)
|
| 78 |
-
|
| 79 |
-
table_job_id = job_tables["JobId"]
|
| 80 |
-
res_tables = {"JobStatus":"IN_PROGRESS"}
|
| 81 |
-
|
| 82 |
-
while res_tables["JobStatus"] == "IN_PROGRESS":
|
| 83 |
-
time.sleep(delay)
|
| 84 |
-
res_tables = textract.get_document_analysis(JobId=table_job_id)
|
| 85 |
-
|
| 86 |
-
res_tables["JobId"] = table_job_id
|
| 87 |
-
|
| 88 |
-
return res_tables
|
| 89 |
-
|
| 90 |
-
@terminal_print
|
| 91 |
-
def get_article_text(file_name:str,bucket:str,delay:int=5):
|
| 92 |
-
'''
|
| 93 |
-
This function is used to get the text from the textract output
|
| 94 |
-
|
| 95 |
-
Parameters:
|
| 96 |
-
file_name: the name of the file in the bucket
|
| 97 |
-
bucket: the name of the bucket
|
| 98 |
-
delay: the delay time for the textract.get_document_text_detection function
|
| 99 |
-
|
| 100 |
-
Returns:
|
| 101 |
-
res_text: the output from the textract.get_document_text_detection function with initial blocks
|
| 102 |
-
'''
|
| 103 |
-
import time
|
| 104 |
-
job_text = textract.start_document_text_detection(
|
| 105 |
-
DocumentLocation={
|
| 106 |
-
"S3Object":{
|
| 107 |
-
"Bucket":bucket,
|
| 108 |
-
"Name": file_name
|
| 109 |
-
}
|
| 110 |
-
}
|
| 111 |
-
)
|
| 112 |
-
|
| 113 |
-
text_job_id = job_text["JobId"]
|
| 114 |
-
res_text = {"JobStatus":"IN_PROGRESS"}
|
| 115 |
-
|
| 116 |
-
while res_text["JobStatus"] == "IN_PROGRESS":
|
| 117 |
-
time.sleep(delay)
|
| 118 |
-
if res_text["JobStatus"] == "IN_PROGRESS":
|
| 119 |
-
res_text = textract.get_document_text_detection(JobId=text_job_id)
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
res_text["JobId"] = text_job_id
|
| 123 |
-
|
| 124 |
-
return res_text
|
| 125 |
-
|
| 126 |
-
@terminal_print
|
| 127 |
-
def construct_tables(tables):
|
| 128 |
-
'''
|
| 129 |
-
This function is used to construct the tables from the textract output
|
| 130 |
-
|
| 131 |
-
Parameters:
|
| 132 |
-
tables: the output from the textract.get_document_analysis function
|
| 133 |
-
|
| 134 |
-
Returns:
|
| 135 |
-
table_blocks: the list of tables with the blocks
|
| 136 |
-
blocks_dict: the dictionary of blocks with the block id as the key
|
| 137 |
-
'''
|
| 138 |
-
blocks = tables["Blocks"]
|
| 139 |
-
|
| 140 |
-
blocks_dict = {}
|
| 141 |
-
table_blocks = []
|
| 142 |
-
|
| 143 |
-
for b in blocks:
|
| 144 |
-
|
| 145 |
-
blocks_dict[b["Id"]] = b
|
| 146 |
-
|
| 147 |
-
if b["BlockType"] == "TABLE":
|
| 148 |
-
temp = {
|
| 149 |
-
"id":b["Id"],
|
| 150 |
-
"relationship":b["Relationships"],
|
| 151 |
-
"confidence":b["Confidence"],
|
| 152 |
-
"page":b["Page"],
|
| 153 |
-
"map":{}
|
| 154 |
-
}
|
| 155 |
-
table_blocks.append(temp)
|
| 156 |
-
|
| 157 |
-
for t in table_blocks:
|
| 158 |
-
for e in t["relationship"]:
|
| 159 |
-
t["map"].update({id:{"Type":e["Type"]} for id in e["Ids"]})
|
| 160 |
-
|
| 161 |
-
for id in t["map"]:
|
| 162 |
-
component = blocks_dict[id]
|
| 163 |
-
if component["BlockType"] not in t:
|
| 164 |
-
t[component["BlockType"]] = []
|
| 165 |
-
t[component["BlockType"]].append(component)
|
| 166 |
-
|
| 167 |
-
# table_blocks.append(t)
|
| 168 |
-
|
| 169 |
-
return table_blocks, blocks_dict
|
| 170 |
-
|
| 171 |
-
# Transfer the table blocks from aws textract into a table
|
| 172 |
-
@terminal_print
|
| 173 |
-
def textract_output_to_table(table,blocks_dict):
|
| 174 |
-
'''
|
| 175 |
-
This function is used to transfer the table blocks from aws textract into a table
|
| 176 |
-
|
| 177 |
-
Parameters:
|
| 178 |
-
table: the table block from the textract output
|
| 179 |
-
blocks_dict: the dictionary of blocks with the block id as the key
|
| 180 |
-
|
| 181 |
-
Returns:
|
| 182 |
-
array: the table array with the text from the table blocks
|
| 183 |
-
'''
|
| 184 |
-
array = [[]]
|
| 185 |
-
cur_row = 1
|
| 186 |
-
for c in table["CELL"]:
|
| 187 |
-
r_id = c["RowIndex"]
|
| 188 |
-
|
| 189 |
-
if r_id > cur_row:
|
| 190 |
-
array.append([])
|
| 191 |
-
cur_row = r_id
|
| 192 |
-
if "Relationships" in c:
|
| 193 |
-
words = [blocks_dict[i]["Text"] for i in c["Relationships"][0]["Ids"] if blocks_dict[i]["BlockType"] == "WORD"]
|
| 194 |
-
else:
|
| 195 |
-
words =[""]
|
| 196 |
-
# print(c["RowIndex"],c["ColumnIndex"]," ".join(words))
|
| 197 |
-
array[-1].append(" ".join(words))
|
| 198 |
-
|
| 199 |
-
return array
|
| 200 |
-
|
| 201 |
-
@terminal_print
|
| 202 |
-
def get_tables(filename:str,bucket:str=default_s3_bucket):
|
| 203 |
-
'''
|
| 204 |
-
This function is used to get the tables from the textract output
|
| 205 |
-
|
| 206 |
-
Parameters:
|
| 207 |
-
filename: the name of the file in the bucket
|
| 208 |
-
bucket: the name of the bucket
|
| 209 |
-
|
| 210 |
-
Returns:
|
| 211 |
-
md_tables: the list of tables in markdown format
|
| 212 |
-
'''
|
| 213 |
-
tables_temp = get_article_tables(file_name=filename,bucket=bucket)
|
| 214 |
-
|
| 215 |
-
tables = textract_get_tables(tables_temp)
|
| 216 |
-
table_blocks,block_dict = construct_tables(tables)
|
| 217 |
-
|
| 218 |
-
md_tables = []
|
| 219 |
-
for table in table_blocks:
|
| 220 |
-
table_array = textract_output_to_table(table,block_dict)
|
| 221 |
-
md_tables.append(create_md_table(table_array))
|
| 222 |
-
|
| 223 |
-
return md_tables
|
| 224 |
-
|
| 225 |
-
|
| 226 |
-
|
| 227 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -13,11 +13,8 @@ from langchain.chains import LLMChain
|
|
| 13 |
from chains import *
|
| 14 |
from cloud_db import *
|
| 15 |
from cloud_storage import *
|
| 16 |
-
from cloud_textract import *
|
| 17 |
from supplier import *
|
| 18 |
from utility import list_dict_to_dict
|
| 19 |
-
from application import *
|
| 20 |
-
# from features_beta import *
|
| 21 |
|
| 22 |
# get prompts, terms, outputs from the cloud
|
| 23 |
@terminal_print
|
|
@@ -38,6 +35,9 @@ def init_app_data():
|
|
| 38 |
app_data["terms"] = get_table("terms")
|
| 39 |
app_data["articles"] = list_dict_to_dict(get_table("articles"),key="name")
|
| 40 |
app_data["summary"] = list_dict_to_dict(get_table("summary"),key="term")
|
|
|
|
|
|
|
|
|
|
| 41 |
|
| 42 |
@terminal_print
|
| 43 |
def get_existing_article(
|
|
@@ -61,6 +61,12 @@ def get_existing_article(
|
|
| 61 |
|
| 62 |
return create_overview(article), create_detail_views(article)
|
| 63 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 64 |
@terminal_print
|
| 65 |
def process_study( # need revision
|
| 66 |
domain,
|
|
@@ -69,10 +75,7 @@ def process_study( # need revision
|
|
| 69 |
):
|
| 70 |
|
| 71 |
if study_file_obj:
|
| 72 |
-
|
| 73 |
-
article = add_article(domain,study_file_obj[0])
|
| 74 |
-
else:
|
| 75 |
-
article = add_article(domain,study_file_obj)
|
| 76 |
elif study_content:
|
| 77 |
article = add_article(domain,study_content,file_object=False)
|
| 78 |
else:
|
|
@@ -83,9 +86,13 @@ def process_study( # need revision
|
|
| 83 |
|
| 84 |
# perform pathway logic and content extraction
|
| 85 |
process_prompts(article=article)
|
|
|
|
|
|
|
|
|
|
| 86 |
|
| 87 |
# set the current article to the completed article object
|
| 88 |
app_data["current_article"] = article
|
|
|
|
| 89 |
|
| 90 |
# update the article to the cloud
|
| 91 |
try:
|
|
@@ -100,6 +107,29 @@ def process_study( # need revision
|
|
| 100 |
|
| 101 |
return overview, detail_views
|
| 102 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 103 |
@terminal_print
|
| 104 |
def update_article_segment(article):
|
| 105 |
# get the key content between article objective and discussion
|
|
@@ -121,8 +151,7 @@ def update_article_segment(article):
|
|
| 121 |
"Material and Methods": materials_and_methods,
|
| 122 |
"Results": results,
|
| 123 |
"Meta Content": meta_content,
|
| 124 |
-
"tables":
|
| 125 |
-
|
| 126 |
})
|
| 127 |
|
| 128 |
# add the key content as an aggregation of the other sections
|
|
@@ -146,13 +175,13 @@ def update_article_segment(article):
|
|
| 146 |
tasks.append(get_segments(article,article_prompts))
|
| 147 |
asyncio.gather(*tasks,return_exceptions=True)
|
| 148 |
|
| 149 |
-
@
|
| 150 |
async def gen_segment(article,name,chain):
|
| 151 |
|
| 152 |
resp = await chain.ainvoke({"term":""})
|
| 153 |
article[name] = resp.content #["content"]
|
| 154 |
|
| 155 |
-
@
|
| 156 |
async def get_segments(article,prompts):
|
| 157 |
llm = ChatOpenAI(
|
| 158 |
temperature=0.0,
|
|
@@ -341,7 +370,12 @@ def add_article(domain,file,add_to_s3=True, add_to_local=True, file_object=True)
|
|
| 341 |
else:
|
| 342 |
# extract the content from the pdf file
|
| 343 |
content, _ = read_pdf(file)
|
| 344 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 345 |
|
| 346 |
# upload the article to s3
|
| 347 |
pdf_obj = open(file.name, 'rb')
|
|
@@ -467,7 +501,8 @@ def select_overview_prompts(article):
|
|
| 467 |
if validate_term(article,t,"overview"):
|
| 468 |
# add the prompts to the memory
|
| 469 |
valid_prompts.update(t["prompts_list"])
|
| 470 |
-
|
|
|
|
| 471 |
|
| 472 |
return {p:app_data["prompts"][p] for p in valid_prompts}
|
| 473 |
|
|
@@ -494,8 +529,8 @@ def select_performance_prompts(article,performance_assessment):
|
|
| 494 |
else:
|
| 495 |
valid_prompts[p]["term"].update({t["term"]:t})
|
| 496 |
if performance_assessment not in article["extraction"]:
|
| 497 |
-
article["extraction"][performance_assessment] =
|
| 498 |
-
article["extraction"][performance_assessment].
|
| 499 |
|
| 500 |
return valid_prompts
|
| 501 |
|
|
@@ -625,6 +660,32 @@ def run_executor(article,prompt):
|
|
| 625 |
case "f_summary_term":
|
| 626 |
f_summary_term(article,prompt)
|
| 627 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 628 |
|
| 629 |
def add_inst(instructions,prompt):
|
| 630 |
return instructions + prompt
|
|
|
|
| 13 |
from chains import *
|
| 14 |
from cloud_db import *
|
| 15 |
from cloud_storage import *
|
|
|
|
| 16 |
from supplier import *
|
| 17 |
from utility import list_dict_to_dict
|
|
|
|
|
|
|
| 18 |
|
| 19 |
# get prompts, terms, outputs from the cloud
|
| 20 |
@terminal_print
|
|
|
|
| 35 |
app_data["terms"] = get_table("terms")
|
| 36 |
app_data["articles"] = list_dict_to_dict(get_table("articles"),key="name")
|
| 37 |
app_data["summary"] = list_dict_to_dict(get_table("summary"),key="term")
|
| 38 |
+
with open(".data/instruction_agg_performance.json","r") as f:
|
| 39 |
+
prompts_agg_json = json.load(f)
|
| 40 |
+
app_data["prompts_agg"] = list_dict_to_dict(prompts_agg_json,key="assessment")
|
| 41 |
|
| 42 |
@terminal_print
|
| 43 |
def get_existing_article(
|
|
|
|
| 61 |
|
| 62 |
return create_overview(article), create_detail_views(article)
|
| 63 |
|
| 64 |
+
@terminal_print
|
| 65 |
+
def generate_summary():
|
| 66 |
+
articles = app_data["user"]["summary"]["articles"]
|
| 67 |
+
|
| 68 |
+
pass
|
| 69 |
+
|
| 70 |
@terminal_print
|
| 71 |
def process_study( # need revision
|
| 72 |
domain,
|
|
|
|
| 75 |
):
|
| 76 |
|
| 77 |
if study_file_obj:
|
| 78 |
+
article = add_article(domain,study_file_obj)
|
|
|
|
|
|
|
|
|
|
| 79 |
elif study_content:
|
| 80 |
article = add_article(domain,study_content,file_object=False)
|
| 81 |
else:
|
|
|
|
| 86 |
|
| 87 |
# perform pathway logic and content extraction
|
| 88 |
process_prompts(article=article)
|
| 89 |
+
|
| 90 |
+
# perform a post process for perfFUTables
|
| 91 |
+
post_process(article)
|
| 92 |
|
| 93 |
# set the current article to the completed article object
|
| 94 |
app_data["current_article"] = article
|
| 95 |
+
app_data["articles"][article["name"]] = article
|
| 96 |
|
| 97 |
# update the article to the cloud
|
| 98 |
try:
|
|
|
|
| 107 |
|
| 108 |
return overview, detail_views
|
| 109 |
|
| 110 |
+
@terminal_print
|
| 111 |
+
def process_studies(
|
| 112 |
+
domain,
|
| 113 |
+
file_objs):
|
| 114 |
+
|
| 115 |
+
for file_obj in file_objs:
|
| 116 |
+
process_study(domain,file_obj,None)
|
| 117 |
+
return gr.update(value=create_md_tables(app_data["articles"]))
|
| 118 |
+
|
| 119 |
+
@terminal_print
|
| 120 |
+
def create_md_tables(articles):
|
| 121 |
+
'''
|
| 122 |
+
create markdown tables for the articles.
|
| 123 |
+
'''
|
| 124 |
+
md_text = ""
|
| 125 |
+
md_text += "| Article Name | Authors | Domain | Upload Time |\n| --- | --- | --- | --- |\n"
|
| 126 |
+
|
| 127 |
+
for name, article in articles.items():
|
| 128 |
+
md_table = f"| {name} | {article['Authors']} |{article['domain']} | {article['upload_time']} | \n"
|
| 129 |
+
md_text += md_table
|
| 130 |
+
|
| 131 |
+
return md_text
|
| 132 |
+
|
| 133 |
@terminal_print
|
| 134 |
def update_article_segment(article):
|
| 135 |
# get the key content between article objective and discussion
|
|
|
|
| 151 |
"Material and Methods": materials_and_methods,
|
| 152 |
"Results": results,
|
| 153 |
"Meta Content": meta_content,
|
| 154 |
+
"tables": ""
|
|
|
|
| 155 |
})
|
| 156 |
|
| 157 |
# add the key content as an aggregation of the other sections
|
|
|
|
| 175 |
tasks.append(get_segments(article,article_prompts))
|
| 176 |
asyncio.gather(*tasks,return_exceptions=True)
|
| 177 |
|
| 178 |
+
@aterminal_print # need to review this.
|
| 179 |
async def gen_segment(article,name,chain):
|
| 180 |
|
| 181 |
resp = await chain.ainvoke({"term":""})
|
| 182 |
article[name] = resp.content #["content"]
|
| 183 |
|
| 184 |
+
@aterminal_print # need to review this.
|
| 185 |
async def get_segments(article,prompts):
|
| 186 |
llm = ChatOpenAI(
|
| 187 |
temperature=0.0,
|
|
|
|
| 370 |
else:
|
| 371 |
# extract the content from the pdf file
|
| 372 |
content, _ = read_pdf(file)
|
| 373 |
+
if "\\" in file.name:
|
| 374 |
+
filename = file.name.split("\\")[-1]
|
| 375 |
+
elif "/" in file.name:
|
| 376 |
+
filename = file.name.split("/")[-1]
|
| 377 |
+
else:
|
| 378 |
+
filename = file.name
|
| 379 |
|
| 380 |
# upload the article to s3
|
| 381 |
pdf_obj = open(file.name, 'rb')
|
|
|
|
| 501 |
if validate_term(article,t,"overview"):
|
| 502 |
# add the prompts to the memory
|
| 503 |
valid_prompts.update(t["prompts_list"])
|
| 504 |
+
sorted_prompts = sorted(valid_prompts,key=lambda x:app_data["prompts"][x]["section_sequence"])
|
| 505 |
+
article["extraction"]["overview"] = sorted_prompts
|
| 506 |
|
| 507 |
return {p:app_data["prompts"][p] for p in valid_prompts}
|
| 508 |
|
|
|
|
| 529 |
else:
|
| 530 |
valid_prompts[p]["term"].update({t["term"]:t})
|
| 531 |
if performance_assessment not in article["extraction"]:
|
| 532 |
+
article["extraction"][performance_assessment] = set()
|
| 533 |
+
article["extraction"][performance_assessment].add(prompt["prompt_name"])
|
| 534 |
|
| 535 |
return valid_prompts
|
| 536 |
|
|
|
|
| 660 |
case "f_summary_term":
|
| 661 |
f_summary_term(article,prompt)
|
| 662 |
|
| 663 |
+
@retry_decorator
|
| 664 |
+
@terminal_print
|
| 665 |
+
def post_process(article):
|
| 666 |
+
post_inputs = {}
|
| 667 |
+
for assessment,segements in article["extraction"].items():
|
| 668 |
+
if assessment == "overview":
|
| 669 |
+
continue
|
| 670 |
+
post_inputs[assessment] = "\n".join([article[s] for s in segements])
|
| 671 |
+
|
| 672 |
+
template = ChatPromptTemplate.from_messages([
|
| 673 |
+
("human","{text}"),
|
| 674 |
+
("system","From the text above {instruction}"),
|
| 675 |
+
])
|
| 676 |
+
|
| 677 |
+
llm = ChatOpenAI(
|
| 678 |
+
temperature=0.0,
|
| 679 |
+
model_name="gpt-3.5-turbo-16k",
|
| 680 |
+
openai_api_key=openai.api_key)
|
| 681 |
+
|
| 682 |
+
chain = template | llm
|
| 683 |
+
|
| 684 |
+
for assessment,post_input in post_inputs.items():
|
| 685 |
+
instruction_agg = app_data["prompts_agg"][assessment]
|
| 686 |
+
article[instruction_agg["name"]] = chain.invoke({"text":post_input,"instruction":instruction_agg["chain"][0]}).content
|
| 687 |
+
article["extraction"][assessment].add(instruction_agg["name"])
|
| 688 |
+
|
| 689 |
|
| 690 |
def add_inst(instructions,prompt):
|
| 691 |
return instructions + prompt
|
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import asyncio
|
| 2 |
+
import json
|
| 3 |
+
|
| 4 |
+
from collections import deque
|
| 5 |
+
from application import app_data
|
| 6 |
+
from langchain.prompts import ChatPromptTemplate
|
| 7 |
+
from chains import llm, retry_decorator
|
| 8 |
+
from utility import list_dict_to_dict
|
| 9 |
+
from pydantic import BaseModel, Field
|
| 10 |
+
from typing import List, Dict, Optional
|
| 11 |
+
|
| 12 |
+
# manual create chain objects
|
| 13 |
+
with open(".data/summary_prompts.json","r") as f:
|
| 14 |
+
overview_summary = json.load(f)
|
| 15 |
+
overview_summary = list_dict_to_dict(overview_summary,"name")
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
class Instruction(BaseModel):
|
| 19 |
+
name: str
|
| 20 |
+
inputs: List[str]
|
| 21 |
+
instruction: str
|
| 22 |
+
|
| 23 |
+
def execute_chain(instruction,articles): # target shall be the object of the summary instruction
|
| 24 |
+
# a recursive function to generate the chain object for llm execution
|
| 25 |
+
# it will recursively create the chain object for each prompt required from article object
|
| 26 |
+
if all([instruction.name in article for article in articles]):
|
| 27 |
+
return
|
| 28 |
+
|
| 29 |
+
for i in instruction.inputs:
|
| 30 |
+
for article in articles:
|
| 31 |
+
if i not in article:
|
| 32 |
+
execute_chain(overview_summary[i],articles)
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def gen_node(name):
|
| 36 |
+
instruction = app_data["summary"][name]["instruction"]
|
| 37 |
+
|
| 38 |
+
prompt = ChatPromptTemplate.from_messages(
|
| 39 |
+
("system", "{content}"),
|
| 40 |
+
("system",f"{instruction}")
|
| 41 |
+
)
|
| 42 |
+
|
| 43 |
+
node = prompt | llm
|
| 44 |
+
return {name:node}
|
|
@@ -1,9 +1,6 @@
|
|
| 1 |
-
gradio
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
pdfminer.six
|
| 8 |
-
tiktoken
|
| 9 |
-
langchain
|
|
|
|
| 1 |
+
gradio==3.35.2
|
| 2 |
+
boto3==1.26.165
|
| 3 |
+
openai==0.27.8
|
| 4 |
+
pdfminer.six==20221105
|
| 5 |
+
tiktoken==0.4.0
|
| 6 |
+
langchain==0.0.338
|
|
|
|
|
|
|
|
|
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
|
| 3 |
+
from application import *
|
| 4 |
+
from features import init_app_data,process_studies,create_md_tables
|
| 5 |
+
from utility import terminal_print
|
| 6 |
+
|
| 7 |
+
def refresh():
|
| 8 |
+
init_app_data()
|
| 9 |
+
'''
|
| 10 |
+
refresh the literature report.
|
| 11 |
+
'''
|
| 12 |
+
return create_md_tables(app_data["articles"])
|
| 13 |
+
|
| 14 |
+
@terminal_print
|
| 15 |
+
def init_studies_page():
|
| 16 |
+
with gr.Blocks() as studies_page:
|
| 17 |
+
with gr.Row(equal_height=False):
|
| 18 |
+
with gr.Column():
|
| 19 |
+
gr.Markdown("## Clinical Studies")
|
| 20 |
+
domain = gr.Radio(label="Anatomical Region",choices=anatomic_domains,value=default_region)
|
| 21 |
+
upload_studies = gr.File(label="Upload clinical study reports",type="file",file_count="multiple")
|
| 22 |
+
btn_upload_studies = gr.Button(value="Upload",variant="primary")
|
| 23 |
+
with gr.Column():
|
| 24 |
+
gr.Markdown("## Article Lists")
|
| 25 |
+
btn_refresh = gr.Button(value="Refresh",variant="primary")
|
| 26 |
+
gr.HTML("<hr>")
|
| 27 |
+
article_list = gr.Markdown("")
|
| 28 |
+
|
| 29 |
+
btn_upload_studies.click(
|
| 30 |
+
process_studies,
|
| 31 |
+
inputs=[
|
| 32 |
+
domain,
|
| 33 |
+
upload_studies,
|
| 34 |
+
],
|
| 35 |
+
outputs=[
|
| 36 |
+
article_list,
|
| 37 |
+
],
|
| 38 |
+
)
|
| 39 |
+
|
| 40 |
+
btn_refresh.click(
|
| 41 |
+
fn=refresh,
|
| 42 |
+
outputs=[article_list]
|
| 43 |
+
)
|
| 44 |
+
return studies_page
|
|
@@ -1,36 +1,76 @@
|
|
| 1 |
import gradio as gr
|
| 2 |
-
import pandas as pd
|
| 3 |
|
| 4 |
from utility import *
|
| 5 |
from application import *
|
| 6 |
-
from features import init_app_data # , add_device, remove_device, get_device
|
| 7 |
-
# from features_beta import *
|
| 8 |
|
| 9 |
-
|
| 10 |
-
def refresh(selected_article):
|
| 11 |
init_app_data()
|
| 12 |
'''
|
| 13 |
refresh the literature report.
|
| 14 |
'''
|
| 15 |
-
return create_md_tables(app_data["articles"])
|
| 16 |
|
| 17 |
def articles_page():
|
| 18 |
|
| 19 |
with gr.Blocks() as tab_page:
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
gr.
|
| 24 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
return tab_page
|
| 26 |
|
| 27 |
-
def
|
| 28 |
with gr.Blocks() as tab_page:
|
| 29 |
render_custom_performance()
|
| 30 |
render_custom_safety()
|
| 31 |
|
| 32 |
return tab_page
|
| 33 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
def render_custom_performance():
|
| 35 |
with gr.Blocks():
|
| 36 |
render_performance_row("Performance Outcome #1",show_header=True)
|
|
@@ -75,17 +115,16 @@ def render_performance_row(row_name, show_header=False):
|
|
| 75 |
label="Units",
|
| 76 |
choices = defaults["units"])
|
| 77 |
|
| 78 |
-
assessment_step.change(fn=lambda value:
|
| 79 |
-
name.change(fn=lambda value:
|
| 80 |
-
replationship.change(fn=lambda value:
|
| 81 |
-
numeric_value.change(fn=lambda value:
|
| 82 |
-
unit.change(fn=lambda value:
|
| 83 |
|
| 84 |
def render_custom_safety():
|
| 85 |
with gr.Blocks():
|
| 86 |
render_safety_row("Safety Outcome #1",show_header=True)
|
| 87 |
-
render_safety_row("Safety Outcome #2")
|
| 88 |
-
|
| 89 |
|
| 90 |
def render_safety_row(row_name, show_header=False):
|
| 91 |
with gr.Row():
|
|
@@ -118,11 +157,10 @@ def render_safety_row(row_name, show_header=False):
|
|
| 118 |
value="%",
|
| 119 |
label="Units")
|
| 120 |
|
| 121 |
-
name.change(fn=lambda value:
|
| 122 |
-
numeric_value.change(fn=lambda value:
|
| 123 |
-
|
| 124 |
|
| 125 |
-
def
|
| 126 |
app_data["user"][setting.lower()][element] = value
|
| 127 |
print(app_data["user"])
|
| 128 |
if element == "assessment_step":
|
|
|
|
| 1 |
import gradio as gr
|
|
|
|
| 2 |
|
| 3 |
from utility import *
|
| 4 |
from application import *
|
| 5 |
+
from features import init_app_data, create_md_tables, generate_summary # , add_device, remove_device, get_device
|
|
|
|
| 6 |
|
| 7 |
+
def refresh():
|
|
|
|
| 8 |
init_app_data()
|
| 9 |
'''
|
| 10 |
refresh the literature report.
|
| 11 |
'''
|
| 12 |
+
return create_md_tables(app_data["articles"])
|
| 13 |
|
| 14 |
def articles_page():
|
| 15 |
|
| 16 |
with gr.Blocks() as tab_page:
|
| 17 |
+
gr.Markdown("## Article Lists")
|
| 18 |
+
btn_refresh = gr.Button(value="Refresh",variant="primary")
|
| 19 |
+
gr.HTML("<hr>")
|
| 20 |
+
article_list = gr.Markdown("")
|
| 21 |
+
|
| 22 |
+
btn_refresh.click(
|
| 23 |
+
fn=refresh,
|
| 24 |
+
outputs=[article_list]
|
| 25 |
+
)
|
| 26 |
return tab_page
|
| 27 |
|
| 28 |
+
def preference_page():
|
| 29 |
with gr.Blocks() as tab_page:
|
| 30 |
render_custom_performance()
|
| 31 |
render_custom_safety()
|
| 32 |
|
| 33 |
return tab_page
|
| 34 |
|
| 35 |
+
def summary_page():
|
| 36 |
+
# create a selection box for the user to select the articles
|
| 37 |
+
# that they want to include in the summary
|
| 38 |
+
with gr.Blocks() as tab_page:
|
| 39 |
+
gr.Markdown("## Summary")
|
| 40 |
+
gr.HTML("<hr>")
|
| 41 |
+
|
| 42 |
+
with gr.Row(equal_height=False):
|
| 43 |
+
with gr.Column():
|
| 44 |
+
article_selection = gr.Dropdown(
|
| 45 |
+
label="Select Articles",
|
| 46 |
+
choices=list(app_data["articles"].keys()),
|
| 47 |
+
info="Select the articles that you want to include in the summary.",
|
| 48 |
+
multiselect=True
|
| 49 |
+
)
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
with gr.Column():
|
| 53 |
+
gen_button = gr.Button(
|
| 54 |
+
label="Generate Summary",
|
| 55 |
+
variant="primary",
|
| 56 |
+
info="Click to generate the summary."
|
| 57 |
+
)
|
| 58 |
+
gr.HTML("<hr>")
|
| 59 |
+
summary = gr.Markdown("")
|
| 60 |
+
|
| 61 |
+
gen_button.click(
|
| 62 |
+
fn=generate_summary,
|
| 63 |
+
inputs=[article_selection],
|
| 64 |
+
outputs=[summary]
|
| 65 |
+
)
|
| 66 |
+
|
| 67 |
+
article_selection.change(
|
| 68 |
+
fn=lambda value: update_user_preference(value,"articles","summary"),
|
| 69 |
+
inputs=[article_selection]
|
| 70 |
+
)
|
| 71 |
+
|
| 72 |
+
return tab_page
|
| 73 |
+
|
| 74 |
def render_custom_performance():
|
| 75 |
with gr.Blocks():
|
| 76 |
render_performance_row("Performance Outcome #1",show_header=True)
|
|
|
|
| 115 |
label="Units",
|
| 116 |
choices = defaults["units"])
|
| 117 |
|
| 118 |
+
assessment_step.change(fn=lambda value: update_user_preference(value,"assessment_step",row_name),inputs=[assessment_step],outputs=[name])
|
| 119 |
+
name.change(fn=lambda value: update_user_preference(value,"name",row_name),inputs=[name])
|
| 120 |
+
replationship.change(fn=lambda value: update_user_preference(value,"relationship",row_name),inputs=[replationship])
|
| 121 |
+
numeric_value.change(fn=lambda value: update_user_preference(value,"numeric value",row_name),inputs=[numeric_value])
|
| 122 |
+
unit.change(fn=lambda value: update_user_preference(value,"unit",row_name),inputs=[unit])
|
| 123 |
|
| 124 |
def render_custom_safety():
|
| 125 |
with gr.Blocks():
|
| 126 |
render_safety_row("Safety Outcome #1",show_header=True)
|
| 127 |
+
render_safety_row("Safety Outcome #2")
|
|
|
|
| 128 |
|
| 129 |
def render_safety_row(row_name, show_header=False):
|
| 130 |
with gr.Row():
|
|
|
|
| 157 |
value="%",
|
| 158 |
label="Units")
|
| 159 |
|
| 160 |
+
name.change(fn=lambda value: update_user_preference(value,"name",row_name),inputs=[name])
|
| 161 |
+
numeric_value.change(fn=lambda value: update_user_preference(value,"numeric value",row_name),inputs=[numeric_value])
|
|
|
|
| 162 |
|
| 163 |
+
def update_user_preference(value,element,setting):
|
| 164 |
app_data["user"][setting.lower()][element] = value
|
| 165 |
print(app_data["user"])
|
| 166 |
if element == "assessment_step":
|