Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

393 lignes
17 KiB

  1. import os
  2. import openai
  3. import pandas as pd
  4. from logger import logger
  5. from flask import Flask, request, make_response, redirect, jsonify, url_for
  6. from flask_cors import CORS, cross_origin
  7. from openai.embeddings_utils import get_embedding, cosine_similarity
  8. from scipy import spatial
  9. import tiktoken
  10. import redis
  11. from redis.commands.search.indexDefinition import (
  12. IndexDefinition,
  13. IndexType
  14. )
  15. from redis.commands.search.query import Query
  16. from redis.commands.search.field import (
  17. TextField,
  18. VectorField
  19. )
  20. app = Flask(__name__)
  21. cors = CORS(app, resources={r"/api/*": {"origins": "*"}})
  22. # openai.api_key = os.getenv("OPENAI_API_KEY")
  23. openai.api_key = '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'
  24. EMBEDDING_MODEL = "text-embedding-ada-002" # OpenAI's best embeddings as of Apr 2023
  25. GPT_MODEL = "gpt-3.5-turbo"
  26. def get_embed_array(strings):
  27. BATCH_SIZE = 1000 # you can submit up to 2048 embedding inputs per request
  28. embeddings = []
  29. for batch_start in range(0, len(strings), BATCH_SIZE):
  30. batch_end = batch_start + BATCH_SIZE
  31. batch = strings[batch_start:batch_end]
  32. print(f"Batch {batch_start} to {batch_end-1}")
  33. response = openai.Embedding.create(model=EMBEDDING_MODEL, input=batch)
  34. for i, be in enumerate(response["data"]):
  35. assert i == be["index"] # double check embeddings are in same order as input
  36. batch_embeddings = [e["embedding"] for e in response["data"]]
  37. embeddings.extend(batch_embeddings)
  38. df = pd.DataFrame({"text": strings, "embedding": embeddings})
  39. # res = search_reviews(df, '华大基因是什么', n=3)
  40. # print(res)
  41. return df
  42. class ChatCompletion:
  43. def __init__(self):
  44. self.role = {"role": "system", "content": "you are a useful assistant."}
  45. self.history = []
  46. self.embedding_strings = ['华大基因公司主营业务为通过基因检测、质谱检测、生物信息分析等多组学大数据技术手段,',
  47. '华大基因公司为科研机构、企事业单位、医疗机构、社会卫生组织等提供研究服务和精准医学检测综合解决方案。',
  48. '华大基因以推动生命科学研究进展、生命大数据应用和提高全球医疗健康水平为出发点,',
  49. '基于基因领域研究成果及精准检测技术在民生健康方面的应用,',
  50. '致力于加速科技创新,减少出生缺陷,加强肿瘤防控,抑制重大疾病对人类的危害,实现精准治愈感染,全面助力精准医学。',
  51. '以华大基因举例:作为中国基因行业的奠基者,秉承“基因科技造福人类”的愿景,通过20多年的人才积聚、科研积累和产业积淀,',
  52. '华大基因公司已建成覆盖全球百余个国家和全国所有省市自治区的营销服务网络,成为屈指可数的覆盖本行业全产业链、全应用领域的科技公司,立足技术先进、配置齐全和规模领先的多组学产出平台,已成为全球屈指可数的科学技术服务提供商和精准医疗服务运营商。',
  53. '2017年,华大基因于深圳证券交易所创业板上市',
  54. '在2016年的自然指数排名(Nature Index Annual Tables)中,华大名列亚太地区生命科学产业机构(life science - corporate)第一位,并连续七年蝉联该排名第一',
  55. '人类基因组计划:1999年9月1日,于英国茵格斯顿举行的第五次人类基因组测序战略会议上,华大基因创始人之一杨焕明提出,中国愿承担人类3号染色体短臂端粒一侧约30厘摩尔(相当于约3,000万个碱基对)区域的测序和分析任务,占整体人类基因组测序工作的1%,成为人类基因组计划成员当中唯一一个发展中国家',
  56. '水稻基因组计划:水稻(籼稻)基因组工作框架图:华大基因于2000年启动水稻基因组计划,希望通过测序找出水稻产量相关基因,并于2002年在《科学》期刊以封面文章发布首个水稻(籼稻))因组的工作框架序列图,文章先后被引用接近四千次。此次由中国科学家合作完成的水稻基因工作框架图,是继人类基因组之后完成测定的最大的基因组,也是当时测定的最大植物基因组。 水稻作为第一个完成基因组测序农作物,对解决全球粮食问题具有重要意义,建立了改善水稻品质、提高水稻产量的重要基础,并被当时《科学》杂志期刊编辑认为水稻基因组研究工作,对人类健康的重要性在接下来的二十年较人类基因组更大',
  57. '国际大熊猫基因组计划:从北京奥运会的吉祥物大熊猫“晶晶”抽取样本,利用短序列(short-reads)模式组装全球首个熊科动物、也是第二个肉食类动物的基因图谱,包含2.25千兆(Gb)个碱基对,并于2010年1月在《自然》科学期刊以封面文章发布。研究进一步支持大多数科学家所持的“大熊猫属于熊科动物”的观点,并为日后使用次世代基因测序技术,快速省时地组装大型真核生物(eukaryotic),如哺乳类动基因图谱奠定了基础。研究指出,相比于自然环境,人类活动对其造成的影响更为严重']
  58. self.df = get_embed_array(self.embedding_strings)
  59. chat = ChatCompletion()
  60. # search function
  61. def strings_ranked_by_relatedness(
  62. query: str,
  63. df: pd.DataFrame,
  64. relatedness_fn=lambda x, y: 1 - spatial.distance.cosine(x, y),
  65. top_n: int = 100
  66. ) -> tuple[list[str], list[float]]:
  67. """Returns a list of strings and relatednesses, sorted from most related to least."""
  68. query_embedding_response = openai.Embedding.create(
  69. model=EMBEDDING_MODEL,
  70. input=query,
  71. )
  72. query_embedding = query_embedding_response["data"][0]["embedding"]
  73. strings_and_relatednesses = [
  74. (row["text"], relatedness_fn(query_embedding, row["embedding"]))
  75. for i, row in df.iterrows()
  76. ]
  77. strings_and_relatednesses.sort(key=lambda x: x[1], reverse=True)
  78. strings, relatednesses = zip(*strings_and_relatednesses)
  79. return strings[:top_n], relatednesses[:top_n]
  80. def num_tokens(text: str, model: str = GPT_MODEL) -> int:
  81. """Return the number of tokens in a string."""
  82. encoding = tiktoken.encoding_for_model(model)
  83. return len(encoding.encode(text))
  84. def query_message(
  85. query: str,
  86. df: pd.DataFrame,
  87. model: str,
  88. token_budget: int
  89. ) -> str:
  90. """Return a message for GPT, with relevant source texts pulled from a dataframe."""
  91. strings, relatednesses = strings_ranked_by_relatedness(query, df)
  92. introduction = '你的身份是华大基因公司的工作人员,使用下面的文章来回答问题.如果没有找到答案, 写 "我没有找到答案.",如果我的问题中包含"你们",请将你视为华大公司的工作人员。'
  93. question = f"\n\nQuestion: {query}"
  94. message = introduction
  95. for string in strings:
  96. next_article = f'\n"""\n{string}\n"""'
  97. if (
  98. num_tokens(message + next_article + question, model=model)
  99. > token_budget
  100. ):
  101. break
  102. else:
  103. message += next_article
  104. return message + question
  105. @app.route(rule='/ask', methods=['post'])
  106. @cross_origin()
  107. def request_ask():
  108. req = request
  109. msg = request.json.get('msg1')
  110. data = {'msg': ask(query=msg, df=chat.df)}
  111. return data
  112. def ask(
  113. query: str,
  114. df: pd.DataFrame = chat.df,
  115. model: str = GPT_MODEL,
  116. token_budget: int = 4096 - 500,
  117. print_message: bool = False,
  118. ) -> str:
  119. """Answers a query using GPT and a dataframe of relevant texts and embeddings."""
  120. message = query_message(query, df, model=model, token_budget=token_budget)
  121. if print_message:
  122. print(message)
  123. messages = [
  124. {"role": "system", "content": "You answer questions about the 2022 Winter Olympics."},
  125. {"role": "user", "content": message},
  126. ]
  127. response = openai.ChatCompletion.create(
  128. model=model,
  129. messages=messages,
  130. temperature=0.8
  131. )
  132. response_message = response["choices"][0]["message"]["content"]
  133. print(response_message)
  134. return response_message
  135. @app.route(rule='/add_skill', methods=['post'])
  136. @cross_origin()
  137. def add_skill_request():
  138. req = request
  139. msg = request.json.get('msg')
  140. add_skill(msg)
  141. return '技能添加成功:{}'.format(msg)
  142. def add_skill(msg):
  143. # 将msg进行embedding,并添加到df中
  144. strings = [msg]
  145. df = get_embed_array(strings)
  146. concat_df = pd.concat([chat.df, df], sort=False)
  147. chat.df = concat_df
  148. # @app.route(rule='/init_skill', methods=['post'])
  149. # @cross_origin()
  150. # def add_skill_request():
  151. # req = request
  152. # msg = request.json.get('msg')
  153. # add_skill(msg)
  154. # return '技能添加成功:{}'.format(msg)
  155. #
  156. #
  157. # def init_skill(msg):
  158. # # 将msg进行embedding,并添加到df中
  159. # strings = [msg]
  160. # df = get_embed_array(strings)
  161. # concat_df = pd.concat([chat.df, df], sort=False)
  162. # chat.df = concat_df
  163. # def search_reviews(df, product_description, n=10, pprint=True):
  164. # embedding = openai.Embedding.create(input=[product_description], engine='text-embedding-ada-002')["data"][0]["embedding"]
  165. # df['similarities'] = df.embedding.apply(lambda x: cosine_similarity(x, embedding))
  166. # res = df.sort_values('similarities', ascending=False).head(n)
  167. # strings_and_relatednesses = [
  168. # (row["text"], relatedness_fn(query_embedding, row["embedding"]))
  169. # for i, row in df.iterrows()
  170. # ]
  171. # return res
  172. # 数据embedding
  173. # calculate embeddings
  174. # 此处设定助理身份
  175. def chat_completion(msg):
  176. role = {"role": "system", "content": "你是一个幽默段子手."}
  177. print("当前角色: {}".format(chat.role['content']))
  178. input_message = [
  179. chat.role
  180. # {"role": "assistant", "content": "好的,我明白了。如果您需要任何帮助或有任何问题,随时都可以叫我小智,我会尽力为您提供帮助。"},
  181. # {"role": "user", "content": "记住这家公司:歌尔股份有限公司于2001年06月25日在潍坊市工商行政管理局登记成立。法定代表人姜滨,注册资本约34.16亿元人民币。公司经营范围包括开发、制造、销售声学、光学、无线通信技术及相关产品;可穿戴智能设备销售;虚拟现实设备制造;智能无人飞行器制造及销售;智能机器人销售;移动终端设备制造等。我会以“你知道歌尔股份吗”或者“歌尔股份”来问你,你会回答上面的内容"},
  182. # {"role": "assistant", "content": "好的,如果您问我“你知道歌尔股份吗”或者“歌尔股份”,我会回答您:歌尔股份有限公司成立于2001年06月25日,注册资本约34.16亿元人民币。公司经营范围包括开发、制造、销售声学、光学、无线通信技术及相关产品;可穿戴智能设备销售;虚拟现实设备制造;智能无人飞行器制造及销售;智能机器人销售;移动终端设备制造等。"},
  183. # {"role": "assistant", "content": "好的,如果您问我“你知道缔智元吗”或者“缔智元”,我会回答您:缔智元是一家缔造数字人员工的科技企业,致力于综合图像识别、自然语言交互、知识图谱、超写实3D渲染、物联网等前沿技术,助力企业的数字化与智能化变革。\n\n如果您要我介绍一下您的公司,我可以使用上述信息,同时可以补充一些细节,例如缔智元的成立时间、总部所在地、业务范围等等。"},
  184. ]
  185. for m in chat.history:
  186. input_message.append(m['question'])
  187. input_message.append(m['answer'])
  188. input_message.append({"role": "user", "content": msg})
  189. print(input_message)
  190. completion = openai.ChatCompletion.create(
  191. model="gpt-3.5-turbo",
  192. # model="gpt-4",/
  193. messages=input_message,
  194. temperature=0.8,
  195. frequency_penalty=0,
  196. max_tokens=1024,
  197. presence_penalty=0,
  198. top_p=1
  199. )
  200. print(completion)
  201. print(completion.choices[0].message['content'])
  202. temp_completion = {'question': {"role": "user", "content": msg},
  203. 'answer': {"role": "assistant", "content": completion.choices[0].message['content']}}
  204. chat.history.append(temp_completion)
  205. if len(chat.history) > 5:
  206. chat.history.pop(0)
  207. print(chat.history)
  208. return completion.choices[0].message['content']
  209. def chat_completion_for_multi_turn(msg):
  210. role = {"role": "system", "content": "你是一个幽默段子手."}
  211. print("当前角色: {}".format(chat.role['content']))
  212. input_message = [
  213. chat.role
  214. ]
  215. for i in range(len(msg)):
  216. # 对i除以2取余数,如果是0,输入input_message.append({"role": "user", "content": msg[i]}),否则输入input_message.append({"role": "assistant", "content": msg[i]})
  217. if i % 2 == 0:
  218. input_message.append({"role": "user", "content": msg[i]})
  219. else:
  220. input_message.append({"role": "assistant", "content": msg[i]})
  221. print(input_message)
  222. completion = openai.ChatCompletion.create(
  223. model="gpt-3.5-turbo",
  224. # model="gpt-4",/
  225. messages=input_message,
  226. temperature=0.8,
  227. frequency_penalty=0,
  228. max_tokens=1024,
  229. presence_penalty=0,
  230. top_p=1,
  231. stream=True
  232. )
  233. for chunk in completion:
  234. res = chunk['choices'][0]['delta']
  235. print(res.get('content', ''))
  236. print(completion)
  237. print(completion.choices[0].message['content'])
  238. temp_completion = {'question': {"role": "user", "content": msg},
  239. 'answer': {"role": "assistant", "content": completion.choices[0].message['content']}}
  240. return completion.choices[0].message['content']
  241. def set_role(data):
  242. chat.role = {"role": "system", "content": data}
  243. return '更新完毕,现在助理的身份是:' + data
  244. @app.route(rule='/data', methods=['post'])
  245. def getjson():
  246. try:
  247. req = request
  248. msg = request.json.get('content')
  249. data = {'msg': chat_completion(msg)}
  250. return data
  251. except Exception as e:
  252. print("An exception occurred:", str(e))
  253. return {'msg': '真抱歉,我连接Chatgpt的好像出现问题了呀'}
  254. @app.route(rule='/chat_data', methods=['post'])
  255. @cross_origin()
  256. def chat_data():
  257. chat.role = {"role": "system", "content": '根据以下文章提出可能问到的10个问题,并给出对应的答案,回答的形式为"{问题}|{答案}",不要回复其他内容。'}
  258. try:
  259. req = request
  260. msg = []
  261. m = request.json.get('corpus')
  262. # 如果m不为空,就加入到msg中
  263. if m is not None:
  264. msg.append(m)
  265. data = {'msg': chat_completion_for_multi_turn(msg)}
  266. return data
  267. except Exception as e:
  268. print("An exception occurred:", str(e))
  269. return {'msg': '真抱歉,我连接Chatgpt的好像出现问题了呀'}
  270. # 写一个GET请求,方法名叫getPic,输入参数为prompts,调用openai的image创建并返回图片的url
  271. @app.route(rule='/getPic', methods=['get'])
  272. def getPic():
  273. try:
  274. req = request
  275. prompts = request.args['prompts']
  276. print(prompts)
  277. response = openai.Image.create(
  278. prompt=prompts,
  279. n=4,
  280. size="1024x1024"
  281. )
  282. print(response)
  283. return response
  284. except Exception as e:
  285. print("An exception occurred:", str(e))
  286. return {'msg': '真抱歉,我连接Chatgpt的好像出现问题了呀'}
  287. @app.route(rule='/wx_chat', methods=['get'])
  288. def wx_chat():
  289. req = request
  290. msg = request.args['question']
  291. is_contains = '@chat_fox' in msg
  292. if is_contains is False:
  293. # 如果问题没有@机器人,不做回答
  294. return ''
  295. print('msg=' + msg)
  296. logger.info('msg=' + msg)
  297. # 获取用户与对话,contents[0为用户,1为对话]
  298. contents = msg.split('\n')
  299. msg = contents[1]
  300. # 切分对话中的@机器人
  301. contents = msg.split('@chat_fox')
  302. msg = ''
  303. for word in contents:
  304. msg = msg + word.strip()
  305. # 如果包含更换助理的指令,返回设置助理
  306. is_contains = '\\assistant' in msg
  307. if is_contains is True:
  308. # 切割命令,并重新生成对话
  309. contents = msg.split('\\assistant')
  310. dialog = ''
  311. for word in contents:
  312. dialog = dialog + word.strip()
  313. return {
  314. 'data': {'id':'yinruoxi053115',
  315. 'content': set_role(dialog)
  316. },
  317. 'msg': 'ok',
  318. 'ret': 0}
  319. # 正常对话,调用openapi接口
  320. data = {
  321. 'data': {'id':'yinruoxi053115',
  322. 'content': chat_completion(msg)
  323. },
  324. 'msg': 'ok',
  325. 'ret': 0}
  326. return data
  327. if __name__ == '__main__':
  328. # ChatCompletion('你好,今天天怎么这么热')
  329. #ask('华大基因上市了没')
  330. print('hello')
  331. logger.info('hello')
  332. app.run(host='0.0.0.0', port=8081)