from pydantic import BaseModel
from fastapi import FastAPI
from sqlalchemy import create_engine
import pymysql
from vppll_m_rpp import vLLMWrapper
import uvicorn
import time
import gradio as gradio
from drug_judge import model
app = FastAPI()
class MySQL:
def __init__(self):
self.host = "172.29.105.97"
self.port = 8090
self.user = "algorithm"
self.password = "123456"
self.database = 'algorithmdb'
self.charset = 'utf8mb4'
def select(self, sql):
# 连接数据库
self.conn = pymysql.connect(
host=self.host,
port=self.port,
user=self.user,
password=self.password,
database=self.database,
charset=self.charset,
cursorclass=pymysql.cursors.DictCursor
)
# 创建游标
self.cursor = self.conn.cursor()
self.cursor.execute(sql)
results = self.cursor.fetchall()
# 关闭游标和连接
self.cursor.close()
self.conn.close()
return results
def insert(self):
self.conn = create_engine(f'mysql+pymysql://{self.user}:{self.password}@{self.host}/test')
return self.conn
mysql_conn = MySQL()
drug_specific_issues = [
'为我简单讲解该药品',
'该药的功效和作用',
'该药的用法用量',
'该药吃了会有什么不良反应',
'服用该药的禁忌症',
'服用该药后能喝酒吗',
'什么情况下不能服用该药',
'儿童用药有哪些注意事项',
'老人用药有哪些注意事项',
'该药孕妇能使用吗',
'该药不适宜人群',
'该药的适用人群',
'该药是饭前服药还是饭后服药',
'服用该药后需要注意什么',
'使用该药有什么后遗症吗',
'该药能长期吃吗',
'长期服用该药要注意什么',
'能否将该药碾碎后服用',
'该药可以空腹服用吗',
'服用该药后有什么忌口吗',
'该药吃多久会有效果',
'该药的主要成分是什么',
'该药不能和什么药一起吃',
'该药能和什么药一起吃',
'该药能和降压药一起服用吗?',
'该药应该如何保存',
'吃了柚子能使用该药吗',
'该药漏服了一次怎么办',
'备孕时可以服用该药吗',
'哺乳期能不能使用该药',
'该药有激素吗',
'该药可否用饮料送服',
'使用该药对肝脏有伤害吗',
'使用该药后会犯困吗',
'用药后会对体检指标有影响吗',
'忘记吃药了,应当如何补救',
'什么是处方药和非处方药',
'如何识别非处方药',
'经期可以吃吗',
'吃这个药能开车吗',
'吃这个药会犯困吗',
'这个药副作用大不大',
'这个药可以空腹吃吗',
'进口的和国产的哪个好',
'哪个牌子的药好一点',
'哪种用量效果好',
'喝完酒多长时间能吃XXX',
'这个药和XXX(另一种药),哪个治疗XXX的效果好',
]
drug_common_issues = [
'处方药和非处方药有什么区别',
'怎样识别非处方药',
'进口药和国产药哪个更好',
'中药和西药可以同时使用吗',
'不同品牌的同种药品可以混着吃吗',
'药品的品牌之间有什么区别',
'药品的颜色、形状改变还能用吗',
'抗生素会不会产生耐药性',
'能否用保健品代替药品',
'如何辨别假药',
'药品误服了怎么办',
'药品的剂型如何选择',
'药品的耐受性是什么意思',
'能否将药品溶解在饮料中服用',
'如何查询药品的真伪',
'药品的批准文号是什么意思',
'药品价格越高越好吗',
'药品的依赖性有哪些表现?',
'喝牛奶对服药有影响吗',
'喝茶对服药有影响吗',
'症状消失马上可以停药吗',
'家庭常备药如何储存',
'使用药物时加大药量,病会好的更快吗',
'服药后可以马上运动吗',
'服用该药是否影响消化系统',
]
options = ["不良反应","适应症","注意事项","用法用量","禁忌","药品服用方法","食用方法","贮藏","药品服用频次","包装规格","药品单次用量","生产厂家","是否医保","医保甲乙类别","上市许可持有人","药品类型","包装单位","成分", "其他"]
#xuanxiang_prompt = f""" 请从列表中选出和问题语义最接近的一个选项,只能从列表范围内选择并且只能选择一个,并输出元素值,问题:请问999感冒灵吃的时候需要注意什么?。列表:["不良反应(副作用)", "用法用量", "疗效与禁忌", "注意事项"] """
"""
请从列表中选出和问题语义最接近的多个选项,只能从列表范围内选择,并输出元素值,问题:{questions}。选项列表:{options}
"""
# option_judge_prompt = """ 请从列表中选出和问题语义最接近的一个选项,只能从列表范围内选择并且只能选择一个,并输出元素值,问题:{questions}。选项列表:{options} """
option_judge_prompt = """
任务:多项选择题
输入示例:龙胆泻肝丸的主要成分和不良反应是什么?
输出示例:成分,不良反应
请从列表中选出和问题语义最接近的选项,只能从列表范围内选择,可以选择多个,多个选项值之间用","逗号分割。
问题:清眩片的包装规格,生产厂家,使用方法是什么?
选项列表:["不良反应","适应症","注意事项","用法用量","禁忌","药品服用方法","食用方法","贮藏","药品服用频次","包装规格","药品单次用量","生产厂家","是否医保","医保甲乙类别","上市许可持有人","药品类型","包装单位","成分"]
"""
specific_issues_prompt = "“{drug_name}”该药品的{option_llm_res}为: {mysql_aswer}"
common_issues_prompt = "你是一名医疗助手,给出对该药关于“{questions}”问题的解答。回复时要简洁有情感。"
# get_drug_name_prompt = """{questions}请提取出上述这句话中的药品名实体(上述句子的子串),只返回药品名(上述句子的子串)即可,输出必须是上述句子的子串。如果没有,输出无"""
# get_drug_name_prompt = """
# 您是一位专业的药剂师,擅长识别和提取文本中的药品名称。请仔细阅读以下文本,并准确找出文本中的一个药品名称,忽略任何前缀或无关的词汇。药品名称应该以纯净的形式出现,不包含品牌、剂量、形式或其他无关信息的修饰。
# ---
# {questions}
# ---
# 请列出一个识别到的药品名称,并确保它们没有前缀或后缀。如果没有,输出无。
# """
get_drug_name_prompt = """
任务:药名提取
输入示例:当归补血丸,他达拉非片怎么服用?
输出示例:当归补血丸,他达拉非片
输入示例:小儿清肺化痰口服液和少林风湿跌打膏的包装规格?
输出示例:小儿清肺化痰口服液,少林风湿跌打膏
输入示例:今天的天气怎么样?
输出示例:无
说明:请仔细阅读以下句子,并从中识别出所有的药名。如果有多个药名,请使用中文逗号将它们连接起来。注意,只提取药名,不要包括其他无关的词汇。如果没有药名实体,则输出“无”。
{questions}
"""
pretty_prompt = """
您是一位专业的医疗顾问,您的任务是根据用户提供的问题和数据库查询结果,提供一个清晰、专业、准确且友好的回复。以下是用户的问题和相关的药品信息:
---
用户问题:{questions}
药品信息:{mysql_json}
---
请根据以上信息,撰写一段简洁明了的建议。确保您的回答既专业又易于理解,在回答的时候一定要加上商品名称和生产厂家信息。
"""
is_medical_question_prompt = """
您是一位专业的医疗咨询助手,任务是判断提出的问题是否与药物或疾病相关。请仔细阅读每个问题,并根据以下准则进行判断:
- 如果问题是询问药物信息、使用方法、副作用或与药物直接相关的内容,请回答“是”。
- 如果问题是询问疾病的症状、原因、治疗方法或与疾病直接相关的内容,请回答“是”。
- 如果问题不符合上述任何一种情况,即与药物和疾病都不相关,请回答“否”。
---
用户问题:{questions},请回答。
---
"""
class drug_instructions_que(BaseModel):
drug_name: str = ""
drug_questions: str = ""
class drug_instructions_que2(BaseModel):
question: str = ""
def specific_issues_res2(drug_name, questions, field_name, query_sql_flag, history):
# option_llm_res, his = model.chat(option_judge_prompt.format(questions=questions, options=options), history=None)
result = ""
if len(field_name) == 1:
option_llm_res = field_name[0]
if option_llm_res in options and query_sql_flag and drug_name != "":
if option_llm_res in ["药品服用方法","食用方法","用法用量","药品服用频次","药品单次用量"]:
sql = f"select 商品名称, 生产厂家, 包装规格, {option_llm_res},药品服用方法, 药品服用频次, 药品单次用量, 药品单次用量单位, 用法用量, 食用方法 from company_other_db_company_heath_data_20240608 where 通用名 like '%{drug_name}%' and 商品类型='中西成药' "
else:
sql = f"select 商品名称, 生产厂家, 包装规格, {option_llm_res} from company_other_db_company_heath_data_20240608 where 通用名 like '%{drug_name}%' and 商品类型='中西成药' "
# AND 商品类型='中西成药'
print(f"specific_issues_res2-->(field_name) == 1 {sql}")
target_content = mysql_conn.select(sql)
print(f"target_content[0] = \n{target_content}")
# 对查询结果需要做判断,如果是空,如果是1,如果是多个,都分别怎么处理
if target_content is None or len(target_content) == 0:
print("MySQL查询内容为空")
a, history = model.chat(questions, history=history, system="你是阿里巴巴医疗助手,由阿里巴巴医学数据科技有限公司开发,你现在是一名医学助手角色,只能回答医学问题,如果不是医学问题,会拒绝回答")
result = {"answer": a,
"reference": "LLM",
"detail": "",
"type": "文本"}
if len(target_content) == 1:
print("mysql查询内容1条")
pretty_prompt_format = pretty_prompt.format(questions=questions,
mysql_json=target_content[0])
a, his = model.chat(pretty_prompt_format, history=history)
reference = f"本答案来源于{target_content[0]['生产厂家']}的{drug_name}药品说明书"
result = {"answer": a,
"reference": reference,
"detail": "",
"type": "文本"}
if len(target_content) > 1:
print("mysql查询内容很多")
pretty_prompt_format = pretty_prompt.format(questions=questions,mysql_json=target_content[0])
a, his = model.chat(pretty_prompt_format, history=history)
reference = f"本答案来源于{target_content[0]['生产厂家']}的{drug_name}药品说明书"
result = {"answer": a,
"reference": reference,
"detail": "",
"type": "文本"}
return result
elif len(field_name) > 1:
target_content = []
for option_llm_res in field_name:
if option_llm_res in options and query_sql_flag and drug_name != "":
if option_llm_res in ["药品服用方法","食用方法","用法用量","药品服用频次","药品单次用量"]:
sql = f"select 商品名称, 生产厂家, 包装规格, {option_llm_res},药品服用方法, 药品服用频次, 药品单次用量, 药品单次用量单位, 用法用量, 食用方法 from company_other_db_company_heath_data_20240608 where 通用名 like '%{drug_name}%' and 商品类型='中西成药' "
else:
sql = f"select 商品名称, 生产厂家, 包装规格, {option_llm_res} from company_other_db_company_heath_data_20240608 where 通用名 like '%{drug_name}%' and 商品类型='中西成药' "
print(f"specific_issues_res2-->(field_name) > 1 {sql}")
# AND 商品类型='中西成药'
target_content1 = mysql_conn.select(sql)
if len(target_content1) > 0:
target_content.append(target_content1[0])
if target_content is None or len(target_content) == 0:
print("MySQL查询内容为空")
a, history = model.chat(questions, history=history, system="你是阿里巴巴医疗助手,由阿里巴巴医学数据科技有限公司开发,你现在是一名医学助手角色,只能回答医学问题,如果不是医学问题,会拒绝回答")
result = {"answer": a,
"reference": "LLM",
"detail": "",
"type": "文本"}
if len(target_content) == 1:
print("mysql查询内容1条")
pretty_prompt_format = pretty_prompt.format(questions=questions,
mysql_json=target_content[0])
a, his = model.chat(pretty_prompt_format, history=history)
reference = f"本答案来源于{target_content[0]['生产厂家']}的{drug_name}药品说明书"
result = {"answer": a,
"reference": reference,
"detail": "",
"type": "文本"}
if len(target_content) > 1:
print("mysql查询内容很多")
pretty_prompt_format = pretty_prompt.format(questions=questions,mysql_json=target_content[0])
a, his = model.chat(pretty_prompt_format, history=history)
reference = f"本答案来源于{target_content[0]['生产厂家']}的{drug_name}药品说明书"
result = {"answer": a,
"reference": reference,
"detail": "",
"type": "文本"}
return result
else:
llm_prompt = common_issues_prompt.format(drug_name=drug_name, questions=questions)
llm_res, his = model.chat(llm_prompt, history=history, system="你是阿里巴巴医疗助手,由阿里巴巴医学数据科技有限公司开发,你现在是一名医学助手角色,只能回答医学问题,如果不是医学问题,会拒绝回答")
result += llm_res
response = {"answer": result,
"reference": "LLM",
"detail": "",
"type": "文本"}
return response
# return result + "【LLM生成,仅供参考】"
"""
"""
def specific_issues_res2_multi_drug(drug_name, questions, field_name, query_sql_flag, history):
# option_llm_res, his = model.chat(option_judge_prompt.format(questions=questions, options=options), history=None)
result = ""
option_llm_res = field_name
if option_llm_res in options and query_sql_flag and drug_name != "":
if option_llm_res in ["药品服用方法","食用方法","用法用量","药品服用频次","药品单次用量"]:
sql = f"select 商品名称, 生产厂家, 包装规格, {option_llm_res},药品服用方法, 药品服用频次, 药品单次用量, 药品单次用量单位, 用法用量, 食用方法, 适应症, 不良反应, 禁忌, 药物相互作用, 注意事项 from company_other_db_company_heath_data_20240608 where 通用名 like '%{drug_name}%' and 商品类型='中西成药' "
else:
sql = f"select 商品名称, 生产厂家, 包装规格, 适应症, 不良反应, 禁忌, 药物相互作用, 注意事项, {option_llm_res} from company_other_db_company_heath_data_20240608 where 通用名 like '%{drug_name}%' and 商品类型='中西成药' "
# AND 商品类型='中西成药'
target_content = mysql_conn.select(sql)
print(f"target_content = \n{target_content}")
# 对查询结果需要做判断,如果是空,如果是1,如果是多个,都分别怎么处理
if target_content is None or len(target_content) == 0:
print("MySQL查询内容为空")
result, history = model.chat(questions, history=history, system="你是阿里巴巴医疗助手,由阿里巴巴医学数据科技有限公司开发,你现在是一名医学助手角色,只能回答医学问题,如果不是医学问题,会拒绝回答")
elif len(target_content) == 1:
print("mysql查询内容1条")
pretty_prompt_format = pretty_prompt.format(questions=questions,
mysql_json=target_content[0])
result, his = model.chat(pretty_prompt_format, history=history)
elif len(target_content) > 1:
print("mysql查询内容很多")
pretty_prompt_format = pretty_prompt.format(questions=questions,mysql_json=target_content[0])
result, his = model.chat(pretty_prompt_format, history=history)
return result
else:
llm_prompt = common_issues_prompt.format(drug_name=drug_name, questions=questions)
llm_res, his = model.chat(llm_prompt, history=history, system="你是阿里巴巴医疗助手,由阿里巴巴医学数据科技有限公司开发,你现在是一名医学助手角色,只能回答医学问题,如果不是医学问题,则会拒绝回答")
result = llm_res
return result
def common_issues_res(drug_name, questions):
llm_prompt = common_issues_prompt.format(drug_name=drug_name, questions=questions)
llm_res, his = model.chat(llm_prompt, history=None)
# return llm_res + "【LLM生成,仅供参考】"
return llm_res
def get_field_list(field_name):
lis = []
for i in options:
if i in field_name:
lis.append(i)
return lis
def extract__drug_questions(drug_questions):
query_sql_flag = True
field_name = "其他"
drug_name = "无"
fields = []
get_drug_name_prompt_format = get_drug_name_prompt.format(questions=drug_questions)
option_judge_prompt_format = option_judge_prompt.format(questions=drug_questions, options=options)
drug_name, his = model.chat(get_drug_name_prompt_format, history=None)
print(f"extract__drug_questions--> 药品名={drug_name}")
if ":" in drug_name:
drug_name = drug_name.split(":")[-1]
if len(drug_name) >20:
drug_name = "无"
if "," in drug_name:
item = drug_name.split(",")
for i in item:
if i.strip() not in drug_questions:
query_sql_flag = False
drug_name = "无"
if query_sql_flag and drug_name != "无":
# 判定多个字段的方法
field_name, his = model.chat(option_judge_prompt_format, history=None)
fields = get_field_list(field_name)
print(f"extract__drug_questions--> 字段名={fields}")
# 对字段需要做控制,如果不在字段中,就不查询
for field in fields:
if field.strip() not in options or field == "其他":
query_sql_flag = False
return drug_name.strip(), fields, query_sql_flag
def query_mysql_by_drug_name_and_field_name(drug_name, field_name):
sql = f"select 商品名称, 生产厂家, 包装规格, {field_name} from company_other_db_company_heath_data_20240608 where 通用名 like '%{drug_name}%' and 商品类型='中西成药' "
print(f"sql: {sql}")
target_content = mysql_conn.select(sql)
return target_content[0]
def is_other(questions):
# is_other_prompt = f"""你现在是一个判断机器,只能输出两种回复,是或者否。不要输出除了这两个字之外的任何字。判断以下用户的问题是否属于医学问题和是打招呼你好这种词汇,如果是回答是,否则回答否,回答的答案只能是["是", "否"]这个列表中的一个,问题为:{questions},你只能回复是或者否,不要输出超过2个汉字的回复"""
is_other_prompt = f"""你现在是阿里巴巴的问药小助手,由阿里巴巴医学数据科技有限公司开发。现在给你一个问题如下:
{questions}
如果这个问题是医学相关问题回复1
如果是问你角色和打招呼等这些初次见面的问题,请回复2
如果这个问题是其他问题请回复3
"""
res, his = model.chat(is_other_prompt, history=None, system="你是阿里巴巴医疗助手,由阿里巴巴医学数据科技有限公司开发,你现在是一名医学助手角色,只能回答医学问题,如果不是医学问题,请拒绝回答,可以回复我只能对有关药物和健康疾病的询问提供答案,其他问题超出了我的回答能力了哦。来委婉的拒绝。")
return res
@app.post("/wenyao")
def wenyao(req: drug_instructions_que2):
param = req.model_dump()
drug_questions = param.get('question')
history = None
# 切分流程 其他意图
print(f"drug_questions={drug_questions}, is_other={is_other(drug_questions)}")
is_other_res = is_other(drug_questions)
if is_other_res == 3 or "3" in is_other_res:
print("3333333333333333333333333333333")
response = {"answer": "我只能对有关药物和健康疾病的询问提供答案,其他问题超出了我的回答能力了哦。",
"reference": "LLM",
"detail": "",
"type": "文本"}
return response
# return "我只能对有关药物和健康疾病的询问提供答案,其他问题超出了我的回答能力了哦。"
elif is_other_res == 2 or "2" in is_other_res:
print("222222222222222222222222222222222")
a, his = model.chat(drug_questions, history=None,system="你是阿里巴巴医疗助手,由阿里巴巴医学数据科技有限公司开发,你现在是一名医学角色,只能回答医学问题,如果不是医学问题,请拒绝回答,可以回复我只能对有关药物和健康疾病的询问提供答案,其他问题超出了我的回答能力了哦。来委婉的拒绝。。")
response = {"answer": a,
"reference": "",
"detail": "",
"type": "文本"}
return response
elif is_other_res == 1 or "1" in is_other_res:
print("111111111111111111111111111111111111")
# 解析出query中的药品名和字段, 如果药品名都没有解析出来,字段也没有解析的必要了
drug_name, field_name, query_sql_flag = extract__drug_questions(drug_questions)
print(f"药品名= {drug_name},字段 = {field_name},query_sql_flag = {query_sql_flag}")
# 这里需要走分支,如果是多个病,
if "," in drug_name:
drug_list = drug_name.split(",")
response = ""
for drug_name in drug_list:
response = specific_issues_res2_multi_drug(drug_name.strip(), drug_questions, field_name, query_sql_flag, history=history)
response += f"\n\n{response}"
return response
elif "," not in drug_name:
response = specific_issues_res2(drug_name.strip(), drug_questions, field_name, query_sql_flag, history=history)
return response
# else:
# print("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee")
# response, his = model.chat(drug_questions, history=None, system="你是阿里巴巴医疗助手,由阿里巴巴医学数据科技有限公司开发,你现在是一名医学助手角色,应该热情回复用户问题。")
# return response
# # for i in range(len(response)):
# # time.sleep(0.05)
# # yield response[: i + 1]
def multi_chat_gr(drug_questions, history):
# 切分流程 其他意图
print(f"drug_questions={drug_questions}, is_other={is_other(drug_questions)}")
is_other_res = is_other(drug_questions)
if is_other_res == 3 or "3" in is_other_res:
print("3333333333333333333333333333333")
response = "我只能对有关药物和健康疾病的询问提供答案,其他问题超出了我的回答能力了哦。"
for i in range(len(response)):
time.sleep(0.05)
yield response[: i + 1]
# return "我只能对有关药物和健康疾病的询问提供答案,其他问题超出了我的回答能力了哦。"
if is_other_res == 2 or "2" in is_other_res:
print("222222222222222222222222222222222")
response, his = model.chat(drug_questions, history=None,system="你是阿里巴巴医疗助手,由阿里巴巴医学数据科技有限公司开发,你现在是一名医学角色,只能回答医学问题,如果不是医学问题,会拒绝回答,可以回复我只能对有关药物和健康疾病的询问提供答案,其他问题超出了我的回答能力了哦。来委婉的拒绝。。")
for i in range(len(response)):
time.sleep(0.05)
yield response[: i + 1]
if is_other_res == 1 or "1" in is_other_res:
print("111111111111111111111111111111111111")
# 解析出query中的药品名和字段, 如果药品名都没有解析出来,字段也没有解析的必要了
drug_name, field_name, query_sql_flag = extract__drug_questions(drug_questions)
print(f"药品名= {drug_name},字段 = {field_name},query_sql_flag = {query_sql_flag}")
response = specific_issues_res2(drug_name, drug_questions, field_name, query_sql_flag, history=history)
for i in range(len(response)):
time.sleep(0.05)
yield response[: i + 1]
# else:
# print("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee")
# response, his = model.chat(drug_questions, history=None, system="你是阿里巴巴医疗助手,由阿里巴巴医学数据科技有限公司开发,你现在是一名医学助手角色,应该热情回复用户问题。")
# return response
# # for i in range(len(response)):
# # time.sleep(0.05)
# # yield response[: i + 1]
"""
状态码整理
"""
if __name__ == "__main__":
# gr_instance = gradio.ChatInterface(fn=multi_chat_gr,
# title="这是一个阿里巴巴打造的医疗对话机器人,欢迎您的使用!结果仅供参考,不构成严谨的医疗建议。",
# chatbot=gradio.Chatbot(height=700, label="阿里巴巴AI医生", show_copy_button=True,
# avatar_images=[
# "/home/wangyp/Big_Model/LLaMA-Factory-main-old/user.jpg",
# "/home/wangyp/Big_Model/LLaMA-Factory-main-old/doctor.jpg"],
# render_markdown=True),
# textbox=gradio.Textbox(placeholder="请在这里输入您的问题", container=False,
# scale=7)
#
# )
# gr_instance.launch(share=True, server_name='0.0.0.0', server_port=6062)
import uvicorn
uvicorn.run("w_main:app", host="0.0.0.0", port=6062)