lexlepty/functioncall
0
1import os2import json3import requests4import smtplib5from email.mime.text import MIMEText6from email.mime.multipart import MIMEMultipart7from flask import Flask, request, jsonify, send_from_directory8from openai import OpenAI9from bs4 import BeautifulSoup10import random11from functions import FUNCTIONS_GROUP_1, FUNCTIONS_GROUP_2, get_function_descriptions12 13app = Flask(__name__)14API_KEY = os.getenv("OPENAI_API_KEY")15BASE_URL = os.getenv("OPENAI_BASE_URL")16emailkey = os.getenv("EMAIL_KEY")17client = OpenAI(api_key=API_KEY, base_url=BASE_URL)18 19def search_duckduckgo(keywords):20 search_term = " ".join(keywords)21 url = "https://www.bing.com/search"22 23 user_agents = [24 "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",25 "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0",26 "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15",27 ]28 headers = {29 "User-Agent": random.choice(user_agents)30 }31 32 params = {33 "q": search_term,34 "setlang": "zh-CN"35 }36 37 response = requests.get(url, params=params, headers=headers)38 39 results = []40 if response.status_code == 200:41 soup = BeautifulSoup(response.text, 'html.parser')42 for item in soup.select('.b_algo')[:5]: # Limit to 5 results43 title_elem = item.select_one('h2 a')44 snippet_elem = item.select_one('.b_caption p')45 46 if title_elem and snippet_elem:47 results.append({48 "title": title_elem.text,49 "href": title_elem['href'],50 "body": snippet_elem.text51 })52 return results53 54def search_papers(query):55 url = f"https://api.crossref.org/works?query={query}"56 response = requests.get(url)57 if response.status_code == 200:58 data = response.json()59 papers = data['message']['items']60 processed_papers = []61 for paper in papers:62 processed_paper = {63 "标题": paper.get('title', [''])[0],64 "作者": ", ".join([f"{author.get('given', '')} {author.get('family', '')}" for author in paper.get('author', [])]),65 "DOI": paper.get('DOI', ''),66 "ISBN": ", ".join(paper.get('ISBN', [])),67 "摘要": paper.get('abstract', '').replace('<p>', '').replace('</p>', '').replace('<italic>', '').replace('</italic>', '')68 }69 processed_papers.append(processed_paper)70 return processed_papers71 else:72 return []73 74def send_email(to, subject, content):75 try:76 with smtplib.SMTP('106.15.184.28', 8025) as smtp:77 smtp.login("jwt", emailkey)78 message = MIMEMultipart()79 message['From'] = "Me <aixiao@aixiao.xyz>"80 message['To'] = to81 message['Subject'] = subject82 message.attach(MIMEText(content, 'html'))83 smtp.sendmail("aixiao@aixiao.xyz", to, message.as_string())84 return True85 except Exception as e:86 print(f"发送邮件时出错: {str(e)}")87 return False88 89def get_openai_response(messages, model="gpt-4o-mini", functions=None, function_call=None):90 try:91 response = client.chat.completions.create(92 model=model,93 messages=messages,94 functions=functions,95 function_call=function_call96 )97 return response.choices[0].message98 except Exception as e:99 print(f"调用OpenAI API时出错: {str(e)}")100 return None101 102def process_function_call(function_name, function_args):103 if function_name == "search_duckduckgo":104 keywords = function_args.get('keywords', [])105 if not keywords:106 return "搜索关键词为空,无法执行搜索。"107 return search_duckduckgo(keywords)108 elif function_name == "search_papers":109 query = function_args.get('query', '')110 if not query:111 return "搜索查询为空,无法执行论文搜索。"112 return search_papers(query)113 elif function_name == "send_email":114 to = function_args.get('to', '')115 subject = function_args.get('subject', '')116 content = function_args.get('content', '')117 if not to or not subject or not content:118 return "邮件信息不完整,无法发送邮件。"119 success = send_email(to, subject, content)120 return {121 "success": success,122 "message": "邮件发送成功" if success else "邮件发送失败",123 "to": to,124 "subject": subject,125 "content": content,126 "is_email": True127 }128 else:129 return "未知的函数调用。"130 131@app.route('/')132def index():133 return send_from_directory('.', 'index.html')134 135@app.route('/chat', methods=['POST'])136def chat():137 data = request.json138 question = data['question']139 history = data.get('history', [])140 messages = history + [{"role": "user", "content": question}]141 142 status_log = []143 144 # 次级模型1: 处理搜索相关函数145 status_log.append("次级模型1:正在判断是否需要选调第一组函数")146 sub_model_1_response = get_openai_response(messages, model="gpt-4o-mini", functions=FUNCTIONS_GROUP_1, function_call="auto")147 148 # 次级模型2: 处理邮件发送相关函数149 status_log.append("次级模型2:正在判断是否需要选调第二组函数")150 sub_model_2_response = get_openai_response(messages, model="gpt-4o-mini", functions=FUNCTIONS_GROUP_2, function_call="auto")151 152 function_call_1 = sub_model_1_response.function_call if sub_model_1_response and sub_model_1_response.function_call else None153 function_call_2 = sub_model_2_response.function_call if sub_model_2_response and sub_model_2_response.function_call else None154 155 if not function_call_1:156 status_log.append("次级模型1:判断不需要选调第一组函数")157 if not function_call_2:158 status_log.append("次级模型2:判断不需要选调第二组函数")159 160 final_function_call = None161 response = None162 search_results = None163 email_sent = False164 165 if function_call_1 and function_call_2:166 # 裁决模型: 决定使用哪个函数调用167 status_log.append("裁决模型:正在决定使用哪个函数调用")168 arbitration_messages = messages + [169 {"role": "system", "content": "两个次级模型都建议使用函数。请决定使用哪个函数更合适。"},170 {"role": "assistant", "content": f"次级模型1建议使用函数:{function_call_1.name}"},171 {"role": "assistant", "content": f"次级模型2建议使用函数:{function_call_2.name}"}172 ]173 arbitration_response = get_openai_response(arbitration_messages, model="gpt-4o-mini")174 if "模型1" in arbitration_response.content or function_call_1.name in arbitration_response.content:175 final_function_call = function_call_1176 status_log.append(f"裁决模型:决定使用函数 {function_call_1.name}")177 else:178 final_function_call = function_call_2179 status_log.append(f"裁决模型:决定使用函数 {function_call_2.name}")180 elif function_call_1:181 final_function_call = function_call_1182 status_log.append(f"次级模型1:决定使用函数 {function_call_1.name}")183 elif function_call_2:184 final_function_call = function_call_2185 status_log.append(f"次级模型2:决定使用函数 {function_call_2.name}")186 else:187 status_log.append("所有次级模型:判断不需要进行任何函数调用")188 189 if final_function_call:190 function_name = final_function_call.name191 function_args = json.loads(final_function_call.arguments)192 status_log.append(f"正在执行函数 {function_name}")193 result = process_function_call(function_name, function_args)194 status_log.append(f"函数 {function_name} 执行完成")195 196 if isinstance(result, dict) and result.get("is_email", False):197 response = f"邮件{'已成功' if result['success'] else '未能成功'}发送到 {result['to']}。\n\n主题:{result['subject']}\n\n内容:\n{result['content']}"198 email_sent = result['success']199 elif isinstance(result, list):200 search_results = result201 messages.append({202 "role": "function",203 "name": function_name,204 "content": json.dumps(result, ensure_ascii=False)205 })206 else:207 messages.append({208 "role": "function",209 "name": function_name,210 "content": str(result)211 })212 213 # 只有在没有邮件发送结果时才调用主模型214 if not response:215 status_log.append("主模型:正在生成回答")216 final_response = get_openai_response(messages, model="gpt-4o-mini")217 response = final_response.content if final_response else "Error occurred"218 status_log.append("主模型:回答生成完成")219 220 return jsonify({221 "response": response,222 "status_log": status_log,223 "search_results": search_results,224 "search_used": bool(search_results),225 "email_sent": email_sent226 })227 228@app.route('/settings', methods=['POST'])229def update_settings():230 data = request.json231 max_history = data.get('max_history', 10)232 return jsonify({"status": "success", "max_history": max_history})233 234if __name__ == '__main__':235 app.run(host='0.0.0.0', port=7860, debug=True)236# from flask import Flask, request, jsonify, send_from_directory237# import requests238# from bs4 import BeautifulSoup239# import random240# import time241 242# app = Flask(__name__)243 244# def perform_bing_search(keywords):245# search_term = " ".join(keywords)246# url = "https://www.bing.com/search"247# user_agents = [248# "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",249# "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0",250# "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15",251# ]252# headers = {"User-Agent": random.choice(user_agents)}253# params = {"q": search_term, "setlang": "zh-CN"}254 255# response = requests.get(url, params=params, headers=headers)256# if response.status_code == 200:257# soup = BeautifulSoup(response.text, 'html.parser')258# results = soup.select('.b_algo')259# search_results = []260# for result in results[:5]: # 只取前5个结果261# title = result.select_one('h2 a')262# snippet = result.select_one('.b_caption p')263# if title and snippet:264# search_results.append({265# "title": title.text,266# "url": title['href'],267# "snippet": snippet.text268# })269# return search_results270# return []271 272# @app.route('/')273# def index():274# return send_from_directory('.', 'we.html')275 276# @app.route('/start_test', methods=['POST'])277# def start_test():278# data = request.json279# keywords = data['keywords'].split()280# interval = int(data['interval'])281 282# first_search = perform_bing_search(keywords)283# time.sleep(interval)284# second_search = perform_bing_search(keywords)285 286# success = len(first_search) > 0 and len(second_search) > 0287# return jsonify({288# "success": success,289# "first_search": first_search,290# "second_search": second_search291# })292 293# if __name__ == '__main__':294# app.run(host='0.0.0.0', port=7860, debug=True)295 296 