mistpe commited on
Commit
260484e
1 Parent(s): 9438612

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +204 -0
app.py ADDED
@@ -0,0 +1,204 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import json
3
+ import requests
4
+ import smtplib
5
+ from email.mime.text import MIMEText
6
+ from email.mime.multipart import MIMEMultipart
7
+ from flask import Flask, request, jsonify, send_from_directory
8
+ from openai import OpenAI
9
+ from duckduckgo_search import DDGS
10
+ from functions import FUNCTIONS_GROUP_1, FUNCTIONS_GROUP_2, get_function_descriptions
11
+
12
+ app = Flask(__name__)
13
+ API_KEY = os.getenv("OPENAI_API_KEY")
14
+ BASE_URL = os.getenv("OPENAI_BASE_URL")
15
+ emailkey = os.getenv("EMAIL_KEY")
16
+ client = OpenAI(api_key=API_KEY, base_url=BASE_URL)
17
+
18
+ def search_duckduckgo(keywords):
19
+ search_term = " ".join(keywords)
20
+ with DDGS() as ddgs:
21
+ return list(ddgs.text(keywords=search_term, region="cn-zh", safesearch="on", max_results=5))
22
+
23
+ def search_papers(query):
24
+ url = f"https://api.crossref.org/works?query={query}"
25
+ response = requests.get(url)
26
+ if response.status_code == 200:
27
+ data = response.json()
28
+ papers = data['message']['items']
29
+ processed_papers = []
30
+ for paper in papers:
31
+ processed_paper = {
32
+ "标题": paper.get('title', [''])[0],
33
+ "作者": ", ".join([f"{author.get('given', '')} {author.get('family', '')}" for author in paper.get('author', [])]),
34
+ "DOI": paper.get('DOI', ''),
35
+ "ISBN": ", ".join(paper.get('ISBN', [])),
36
+ "摘要": paper.get('abstract', '').replace('<p>', '').replace('</p>', '').replace('<italic>', '').replace('</italic>', '')
37
+ }
38
+ processed_papers.append(processed_paper)
39
+ return processed_papers
40
+ else:
41
+ return []
42
+
43
+ def send_email(to, subject, content):
44
+ try:
45
+ with smtplib.SMTP('106.15.184.28', 8025) as smtp:
46
+ smtp.login("jwt", emailkey)
47
+ message = MIMEMultipart()
48
+ message['From'] = "Me <[email protected]>"
49
+ message['To'] = to
50
+ message['Subject'] = subject
51
+ message.attach(MIMEText(content, 'html'))
52
+ smtp.sendmail("[email protected]", to, message.as_string())
53
+ return True
54
+ except Exception as e:
55
+ print(f"发送邮件时出错: {str(e)}")
56
+ return False
57
+
58
+ def get_openai_response(messages, model="gpt-4o-mini", functions=None, function_call=None):
59
+ try:
60
+ response = client.chat.completions.create(
61
+ model=model,
62
+ messages=messages,
63
+ functions=functions,
64
+ function_call=function_call
65
+ )
66
+ return response.choices[0].message
67
+ except Exception as e:
68
+ print(f"调用OpenAI API时出错: {str(e)}")
69
+ return None
70
+
71
+ def process_function_call(function_name, function_args):
72
+ if function_name == "search_duckduckgo":
73
+ keywords = function_args.get('keywords', [])
74
+ if not keywords:
75
+ return "搜索关键词为空,无法执行搜索。"
76
+ return search_duckduckgo(keywords)
77
+ elif function_name == "search_papers":
78
+ query = function_args.get('query', '')
79
+ if not query:
80
+ return "搜索查询为空,无法执行论文搜索。"
81
+ return search_papers(query)
82
+ elif function_name == "send_email":
83
+ to = function_args.get('to', '')
84
+ subject = function_args.get('subject', '')
85
+ content = function_args.get('content', '')
86
+ if not to or not subject or not content:
87
+ return "邮件信息不完整,无法发送邮件。"
88
+ success = send_email(to, subject, content)
89
+ return {
90
+ "success": success,
91
+ "message": "邮件发送成功" if success else "邮件发送失败",
92
+ "to": to,
93
+ "subject": subject,
94
+ "content": content,
95
+ "is_email": True
96
+ }
97
+ else:
98
+ return "未知的函数调用。"
99
+
100
+ @app.route('/')
101
+ def index():
102
+ return send_from_directory('.', 'index.html')
103
+
104
+ @app.route('/chat', methods=['POST'])
105
+ def chat():
106
+ data = request.json
107
+ question = data['question']
108
+ history = data.get('history', [])
109
+ messages = history + [{"role": "user", "content": question}]
110
+
111
+ status_log = []
112
+
113
+ # 次级模型1: 处理搜索相关函数
114
+ status_log.append("次级模型1:正在判断是否需要选调第一组函数")
115
+ sub_model_1_response = get_openai_response(messages, model="gpt-4o-mini", functions=FUNCTIONS_GROUP_1, function_call="auto")
116
+
117
+ # 次级模型2: 处理邮件发送相关函数
118
+ status_log.append("次级模型2:正在判断是否需要选调第二组函数")
119
+ sub_model_2_response = get_openai_response(messages, model="gpt-4o-mini", functions=FUNCTIONS_GROUP_2, function_call="auto")
120
+
121
+ function_call_1 = sub_model_1_response.function_call if sub_model_1_response and sub_model_1_response.function_call else None
122
+ function_call_2 = sub_model_2_response.function_call if sub_model_2_response and sub_model_2_response.function_call else None
123
+
124
+ if not function_call_1:
125
+ status_log.append("次级模型1:判断不需要选调第一组函数")
126
+ if not function_call_2:
127
+ status_log.append("次级模型2:判断不需要选调第二组函数")
128
+
129
+ final_function_call = None
130
+ response = None
131
+ search_results = None
132
+ email_sent = False
133
+
134
+ if function_call_1 and function_call_2:
135
+ # 裁决模型: 决定使用哪个函数调用
136
+ status_log.append("裁决模型:正在决定使用哪个函数调用")
137
+ arbitration_messages = messages + [
138
+ {"role": "system", "content": "两个次级模型都建议使用函数。请决定使用哪个函数更合适。"},
139
+ {"role": "assistant", "content": f"次级模型1建议使用函数:{function_call_1.name}"},
140
+ {"role": "assistant", "content": f"次级模型2建议使用函数:{function_call_2.name}"}
141
+ ]
142
+ arbitration_response = get_openai_response(arbitration_messages, model="gpt-4o-mini")
143
+ if "模型1" in arbitration_response.content or function_call_1.name in arbitration_response.content:
144
+ final_function_call = function_call_1
145
+ status_log.append(f"裁决模型:决定使用函数 {function_call_1.name}")
146
+ else:
147
+ final_function_call = function_call_2
148
+ status_log.append(f"裁决模型:决定使用函数 {function_call_2.name}")
149
+ elif function_call_1:
150
+ final_function_call = function_call_1
151
+ status_log.append(f"次级模型1:决定使用函数 {function_call_1.name}")
152
+ elif function_call_2:
153
+ final_function_call = function_call_2
154
+ status_log.append(f"次级模型2:决定使用函数 {function_call_2.name}")
155
+ else:
156
+ status_log.append("所有次级模型:判断不需要进行任何函数调用")
157
+
158
+ if final_function_call:
159
+ function_name = final_function_call.name
160
+ function_args = json.loads(final_function_call.arguments)
161
+ status_log.append(f"正在执行函数 {function_name}")
162
+ result = process_function_call(function_name, function_args)
163
+ status_log.append(f"函数 {function_name} 执行完成")
164
+
165
+ if isinstance(result, dict) and result.get("is_email", False):
166
+ response = f"邮件{'已成功' if result['success'] else '未能成功'}发送到 {result['to']}。\n\n主题:{result['subject']}\n\n内容:\n{result['content']}"
167
+ email_sent = result['success']
168
+ elif isinstance(result, list):
169
+ search_results = result
170
+ messages.append({
171
+ "role": "function",
172
+ "name": function_name,
173
+ "content": json.dumps(result, ensure_ascii=False)
174
+ })
175
+ else:
176
+ messages.append({
177
+ "role": "function",
178
+ "name": function_name,
179
+ "content": str(result)
180
+ })
181
+
182
+ # 只有在没有邮件发送结果时才调用主模型
183
+ if not response:
184
+ status_log.append("主模型:正在生成回答")
185
+ final_response = get_openai_response(messages, model="gpt-4o-mini")
186
+ response = final_response.content if final_response else "Error occurred"
187
+ status_log.append("主模型:回答生成完成")
188
+
189
+ return jsonify({
190
+ "response": response,
191
+ "status_log": status_log,
192
+ "search_results": search_results,
193
+ "search_used": bool(search_results),
194
+ "email_sent": email_sent
195
+ })
196
+
197
+ @app.route('/settings', methods=['POST'])
198
+ def update_settings():
199
+ data = request.json
200
+ max_history = data.get('max_history', 10)
201
+ return jsonify({"status": "success", "max_history": max_history})
202
+
203
+ if __name__ == '__main__':
204
+ app.run(host='0.0.0.0', port=7860, debug=True)