record_with_prompt.py已经完成,能够在命令行界面输入病人描述,然后生成病历(json键值对形式),但是作为一个项目,还需要搭建前端和后端。我们后端选用的是Django,前端使用Vue,完成一个前后端分离的web应用,完成更多复杂的功能,并且将生成的病历信息存入数据库,给患者提供生成病历、查询病历的数据库操作,并且医生能够查看挂号患者的病历,填写诊断结果。
后端项目结构如下:
在urls.py配置相应路由,作为接口暴露给前端。
//case_history.urls.py中的路由配置
urlpatterns = [
path('admin/', admin.site.urls),
path('medic/', include('medic_app.urls')),
]
//medic_app.urls.py中的路由配置
urlpatterns = [
# 登录
path('login/', views.login, name='login'),
# 注册
path('register/', views.register, name='register'),
# 生成病历
path('generate/<int:p_id>/', views.generate, name='generate'),
# 查看病患病历
path('myCase/<int:p_id>/', views.myCase, name='myCase'),
# 医生诊断界面
path('diagnostic/<int:d_id>/', views.diagnostic, name='diagnostic'),
# 病历界面(通用)
path('case/<int:p_id>/<int:d_id>/', views.case, name='case'),
]
当后端Django项目启动后,前端往对应路由发送http请求,会发送到view.py中对应路由的函数进行处理,对应函数的return也是返回到对应的前端页面。
在views.py中完成对应逻辑的处理。
其中,对应病历生成的函数generate接收前端传来的message(患者自述),调用本地部署的大模型处理(具体处理方法见上一篇文章:[项目实训]大模型应用:病历自动生成 实现-CSDN博客)
并且利用Django自带的数据库框架,将生成的病历存入数据库中的record表中(这里的inference为调用大模型的方法)
def generate(request, p_id):
data = request.POST
print(data)
message = data['message']
doctor_id = data['doctor_id']
custom_settings = init_prompts()
my_record = inference(message, custom_settings)
client = MongoClient('mongodb://localhost:27017/')
db = client['medic_app']
collection = db['record']
record = {'p_id': p_id,
'd_id': doctor_id,
'name': my_record['姓名'],
'age' : my_record['年龄'],
'chief': my_record['主诉'],
'lastingTime': my_record['持续时间'],
'history': my_record['既往病史'],
'allergy': my_record['过敏药物']
}
collection.insert_one(record)
return JsonResponse({"message": my_record}, json_dumps_params={'ensure_ascii': False})
schema = {
'病历条目': ['姓名', '年龄', '主诉', '持续时间', '既往病史', '过敏药物']
}
IE_PATTERN = "{}\n\n提取上述句子中{}类型的实体,输出JSON格式,如果上述句子没有该信息,则用['无']来表示,多个值之间用','分隔。"
ie_examples = {
'病历1':
{
'sentence': '我叫傅一帆,今年38岁,我从昨天开始感觉头疼,并且伴有腹泻的症状。以前得过肠胃型感冒,对阿莫西林过敏',
'answers': {
'姓名': '傅一帆',
'年龄': '38岁',
'主诉': '头疼,腹泻',
'持续时间': '1天',
'既往病史': '肠胃型感冒',
'过敏药物': '阿莫西林',
}
},
'病历2':
{
'sentence': '我叫林凡,今年42岁,前天开始一直觉得肩膀酸痛,几十年前曾经得过肩周炎,但是已经痊愈,没有发现药物过敏',
'answers': {
'姓名': '林凡',
'年龄': '42岁',
'主诉': '肩膀酸痛',
'持续时间': '2天',
'既往病史': '肩周炎',
'过敏药物': '未提供',
}
},
'病历3':
{
'sentence': '我叫何清,今年13岁,这半个月一直觉得脚疼',
'answers': {
'姓名': '何清',
'年龄': '13岁',
'主诉': '脚疼',
'持续时间': '半个月',
'既往病史': '未提供',
'过敏药物': '未提供',
}
},
'病历4':
{
'sentence': '我叫林露,我觉得牙疼,去年因为口腔癌做过手术',
'answers': {
'姓名': '林露',
'年龄': '未提供',
'主诉': '牙疼',
'持续时间': '未提供',
'既往病史': '口腔癌',
'过敏药物': '未提供',
}
}
}
def init_prompts():
ie_prefix = [
(
"需要你协助完成病历信息抽取任务,当我给你一个病人自述时,帮我抽取出句子中的‘姓名、年龄、主诉、持续时间、既往病史、过敏药物’,并按照\
JSON的格式输出,如果缺少信息用['未提供']来表示,多个值之间用','分隔。持续时间要说明具体几天或几个月,只要输出json格式数据,不要输出\
多余信息",
'好的,我将只以json格式输出。'
)
]
properties_str = ', '.join(schema['病历条目'])
schema_str_list = f'“病历条目”({properties_str})'
for key, example in ie_examples.items():
sentence = example['sentence']
formatted_prompt = IE_PATTERN.format(sentence, schema_str_list)
answers_json = json.dumps(example['answers'], ensure_ascii=False)
ie_prefix.append((formatted_prompt, answers_json))
return {'ie_prefix': ie_prefix}
def format_output(response: str):
if '```json' in response:
# response = response.replace("\n","")
res = re.findall(r'```json((.|\n)*?)```', response)
if len(res) and res[0]:
response = res[0]
response = response[0]
response.replace('、', ',')
elif '{' in response:
res = re.findall(r'{((.|\n)*?)}', response)
if len(res) and res[0]:
response = res[0]
response = response[0]
response = '{' + response + '}'
response.replace('、', ',')
try:
return json.loads(response)
except:
return response
def inference(sentence, custom_settings: dict):
properties_str = ', '.join(schema['病历条目'])
schema_str_list = f'“病历条目”({properties_str})'
sentence_with_ie_prompt = IE_PATTERN.format(sentence, schema_str_list)
result, _ = (model.chat(tokenizer, sentence_with_ie_prompt, history=custom_settings['ie_prefix']))
result = format_output(result)
return result
其他还有登录注册、用户病历界面、医生查看病历界面、诊断界面等,这里不一一展示。
使用Postman测试,成功返回需要的json形式的病历数据键值对: