diff --git a/Ai_work.db b/Ai_work.db index 2981b24..4794774 100644 Binary files a/Ai_work.db and b/Ai_work.db differ diff --git a/backend/SqliteUtil.py b/backend/SqliteUtil.py index 694a7b9..20aa69b 100644 --- a/backend/SqliteUtil.py +++ b/backend/SqliteUtil.py @@ -336,20 +336,44 @@ def getActivities(UserID): finally: lock_threading.release() +from datetime import datetime + +def parse_time(time_str): + for fmt in ('%H:%M:%S', '%H:%M'): + try: + return datetime.strptime(time_str, fmt).time() + except ValueError: + pass + raise ValueError(f"无法解析时间格式: {time_str}") + def getActivitiesFromData(dataList): try: lock_threading.acquire() activities = [] - for itemArray in dataList: # dataList数据库返回的数据集,是一个二维数组 - # itemArray: (1, 1, 'Meeting', '2024-05-21', '10:00:00', '2024-05-21', '11:00:00') + for itemArray in dataList: activity = {} for columnIndex, columnName in enumerate(activityColumns): columnValue = itemArray[columnIndex] activity[columnName] = columnValue activities.append(activity) - activities.sort(key=lambda x: (x['ActivityBeginDate'], x['ActivityBeginTime'], x['ActivityEndDate'], x['ActivityEndTime']), reverse=True) - + def get_activity_status(activity): + now = datetime.now() + begin_date = datetime.strptime(activity['ActivityBeginDate'], '%Y-%m-%d').date() + begin_time = parse_time(activity['ActivityBeginTime']) + end_date = datetime.strptime(activity['ActivityEndDate'], '%Y-%m-%d').date() + end_time = parse_time(activity['ActivityEndTime']) + begin_datetime = datetime.combine(begin_date, begin_time) + end_datetime = datetime.combine(end_date, end_time) + if now < begin_datetime: + return 1 # 未开始 + elif begin_datetime <= now <= end_datetime: + return 0 # 进行中 + else: + return 2 # 已结束 + + activities.sort(key=lambda x: (get_activity_status(x), datetime.combine(datetime.strptime(x['ActivityEndDate'], '%Y-%m-%d').date(), parse_time(x['ActivityEndTime'])))) + return activities except Exception as e: print(repr(e)) @@ -370,11 +394,24 @@ def deleteActivity(activity_id): finally: lock_threading.release() +def deleteActivityByActivityName(activity_name, date): + try: + lock_threading.acquire() + sql = 'DELETE FROM TodoActivity WHERE ActivityName = ? and ActivityBeginDate = ?' + cursor.execute(sql, (activity_name, date)) + conn.commit() + return '删除成功' + except Exception as e: + print(repr(e)) + return '删除失败' + finally: + lock_threading.release() + def insertOrUpdateTodoItem(item): try: lock_threading.acquire() item = json.loads(item) - current_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') + current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') if item['ItemStatus'] == '进行中': item['ongoing_time'] = current_time elif item['ItemStatus'] == '已完成': @@ -385,9 +422,8 @@ def insertOrUpdateTodoItem(item): item_id = item.get('ItemID', 0) ItemContent = item.get('ItemContent', '') ItemLevel = item.get('ItemLevel', 0) - ItemStatus = item.get('ItemStatus', '未开始') + ItemStatus = item.get('Status', '未开始') # UserID = int(item.get('UserID', 0)) - print(item_id,ItemContent,ItemLevel) if item_id == 0: # 新增 keys = '' values = '' diff --git a/backend/llm_interface.py b/backend/llm_interface.py index 24a2990..4138da7 100644 --- a/backend/llm_interface.py +++ b/backend/llm_interface.py @@ -1,7 +1,10 @@ +import json from openai import OpenAI import qianfan import os +import requests + class LLMInterface: def __init__(self): # self.client = OpenAI(api_key="sk-f9e4937a7a7e4e31b823337fd6b9849c", base_url="https://api.deepseek.com") @@ -18,6 +21,46 @@ def query(self, content, prefix_prompt="You are a helpful assistant"): ) return response.choices[0].message.content +class MiniMax: + def __init__(self): + self.url = "https://api.minimax.chat/v1/text/chatcompletion_v2" + self.api_key = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJHcm91cE5hbWUiOiLkvZXmoKnmmZ8iLCJVc2VyTmFtZSI6IuS9leagqeaZnyIsIkFjY291bnQiOiIiLCJTdWJqZWN0SUQiOiIxODA1ODk3NjA5NDA4MTU1NjU3IiwiUGhvbmUiOiIxODA1MDIxNzY1MCIsIkdyb3VwSUQiOiIxODA1ODk3NjA5Mzk5NzY3MDQ5IiwiUGFnZU5hbWUiOiIiLCJNYWlsIjoiIiwiQ3JlYXRlVGltZSI6IjIwMjQtMDYtMjYgMjA6NTM6MzciLCJpc3MiOiJtaW5pbWF4In0.NopkGobcWVfcDUe88a1czroqv61dscmycEfsPTrKfuHeOi-kDDWQpf0avTe3P6rXSm7ByTlB47KSTMqbM4Kn7sdU6fFS5UT2a7hcYsbouMznEfaY_jE_h8DgSqS3_2NBeNylLTdUYjSzdoauuP5iP-jXjNyi7Af85mhtgPqJxw_g75bsp07AmZR_UOzNxetLX3UbFx1e7y6yDlEyMtLwuO6SdeL4k5Vj0gou_NDwQWRMWLzXGRXTDILB-6h6mfSDm6y0TClvTLLsmFJqJBL2b2xbuyBB9EZ1uJjOWdMtK4DgyXoGB5x5C5LHWe-KasZQn00oR7lyBTJMcfLhlCnn6g" + self.headers = { + 'Authorization': f'Bearer {self.api_key}', + 'Content-Type': 'application/json' + } + + def query(self, content, prefix_prompt="You are a helpful assistant"): + payload = json.dumps({ + "model": "abab6.5s-chat", + "messages": [ + { + "role": "system", + "content": prefix_prompt + }, + { + "role": "user", + "content": content + } + ], + "tools": [ + {"type": "web_search"} + ], + "tool_choice": "none", + "stream": False, + "max_tokens": 8000, + }) + + response = requests.post(self.url, headers=self.headers, data=payload) + # response = requests.request("POST", self.url, headers=self.headers, data=payload) + # return response.text['choices'][0]['message']['content'] + print(response.text) + if response.status_code == 200: + result = response.json() + return result['choices'][0]['message']['content'] + else: + return f"Error: {response.status_code}, {response.text}" + class Qianfan: def __init__(self): os.environ["QIANFAN_AK"] = "vtPcz76K1MFyHQNPKH2WG27e" diff --git a/backend/run_app.py b/backend/run_app.py index 905219d..ede8859 100644 --- a/backend/run_app.py +++ b/backend/run_app.py @@ -15,6 +15,7 @@ from PIL import Image import base64 from openai import OpenAI +import arrow app = Flask(__name__) app.config['UPLOAD_FOLDER'] = './uploads' @@ -233,6 +234,7 @@ def getActivityStatistics(job): @app.route(apiPrefix + 'updateItem', methods=['POST']) def addOrUpdateItem(): try: + print(request.get_json()) data = request.get_json() result = DBUtil.insertOrUpdateTodoItem(json.dumps(data)) print(result) @@ -334,12 +336,19 @@ def insertReservation(): print(data) room_id = data.get('room_id') - user_id = data.get('user_id') + user_id = data.get('user_id') # 可能是string,待查 start_time = data.get('start_time') end_time = data.get('end_time') date = data.get('date') subject = data.get('subject') - reservation = RBooking.insertreservation(room_id, user_id, start_time, end_time, date, subject) + type = data.get('type') + team_id = data.get('team_id') + + if type != 'team': + reservation = RBooking.insertreservation(room_id, user_id, start_time, end_time, date, subject) + else: + reservation = RBooking.insertreservation_team(room_id, user_id, start_time, end_time, date, subject, team_id) + if reservation == False: return jsonify({'code': 1, 'message': '添加会议室预约失败', 'status': 500 }) print(room_id) @@ -354,6 +363,33 @@ def insertReservation(): meeting_activity['ActivityEndTime'] = end_time print(meeting_activity) result = DBUtil.updateActivity(json.dumps(meeting_activity)) + + if type == 'team': + member_ids = Team.get_team_members(team_id) + for member_id in member_ids: + if int(member_id[0]) != int(user_id): + activity_name = "会议 - " + room_name + " - " + subject + meeting_activity = {} + meeting_activity['UserID'] = member_id[0] + meeting_activity['ActivityName'] = activity_name + meeting_activity['ActivityBeginDate'] = date + meeting_activity['ActivityEndDate'] = date + meeting_activity['ActivityBeginTime'] = start_time + meeting_activity['ActivityEndTime'] = end_time + result = DBUtil.updateActivity(json.dumps(meeting_activity)) + result2 = Team.insertMeetingRoomReservation(room_id, member_id[0], user_id, start_time, end_time, date, subject, team_id) + + # insertOrUpdateTodoItem + # item = {} + # item['ActivityID'] = result['ActivityID'] + # item['UserID'] = member_id[0] + # item['ItemCotent'] = '会议 - ' + room_name + ' - ' + subject + + + print(result2) + + + if result != '新增成功' and result != '修改成功': return jsonify({'code': 1, 'message': '添加会议室预约到日程失败', 'status': 500 }) @@ -367,8 +403,22 @@ def deleteReservation(): data = request.get_json() print(data) reservation_id = data.get('reservation_id') + reservation = RBooking.getreservation(reservation_id) + type = reservation[7] user_id = data.get('user_id') result = RBooking.deletereservation(user_id, reservation_id) + room_id, user_id, start_time, end_time, date, subject, team_id = reservation[1], reservation[2], reservation[3], reservation[4], reservation[5], reservation[6], reservation[7] + room_name = RBooking.getroomname(room_id) + if type != 0: + member_ids = Team.get_team_members(team_id) + for member_id in member_ids: + if int(member_id[0]) != int(user_id): + result2 = Team.insertMeetingRoomReservation(room_id, member_id[0], user_id, start_time, end_time, date, subject, team_id, 1) + print(result2) + activity_name = "会议 - " + room_name + " - " + subject + result3 = DBUtil.deleteActivityByActivityName(activity_name, date) + print(result3) + if result == False: return jsonify({'code': 1, 'message': '删除会议室预约失败', 'status': 500 }) return jsonify({'code': 0, 'message': '删除会议室预约成功', 'status': 200 }), 200 @@ -379,9 +429,10 @@ def getUserReservations(): data = request.get_json() user_id = data.get('user_id') reservations = RBooking.getuserreservations(user_id) + print(reservations) if reservations is None: return jsonify({'code': 1, 'message': '获取用户预约列表失败', 'status': 500 }) - keys = ['id', 'room_id', 'user_id', 'start_time', 'end_time', 'date', 'subject', 'room_name'] + keys = ['id', 'room_id', 'user_id', 'start_time', 'end_time', 'date', 'subject', 'type', 'room_name'] # date 小于今天的不显示 reservations_list = [] for reservation in reservations: @@ -396,20 +447,76 @@ def getUserReservations(): ##### AI 接口 ##### +reservation_flags = {} +chat_history = {} @app.route(apiPrefix + 'aiChat', methods=['POST']) def getAIResult(): - prompt = '''你是一个智能办公助手,你的能力有下面几种: 1. 回答有关日程的安排。2. 回答有关会议室的安排、预约情况等 3. 帮助用户进行日程的插入 4. 帮助用户进行会议室的预约。5. 其它不属于以上四种的情况。无论用户输入什么,你的输出回答里都有且只能有一个阿拉伯数字,即判断是上面的五种能力中的哪一种。\n例如:用户输入:帮我预定一间下午的会议室,两个小时 你的回答:4; 用户输入:帮我查询今天研讨室的预约情况 你的回答:2; 用户输入:昨晚什么天气?利物浦赢了吗?1+1等于几 你的回答:5; 用户输入:帮我查查看今天有什么紧急的事 你的回答:1; 用户输入:帮我在旅游事项里加入一项订机票 你的回答:3;''' + llm_qianfa = LLM.Qianfan() + llm = LLM.LLMInterface() + llm_minimax = LLM.MiniMax() data = request.get_json() userID = data.get('userID') content = data.get('content') + day_and_time = Arrow.now().format('YYYY-MM-DD HH:mm:ss') - llm_qianfa = LLM.Qianfan() - llm = LLM.LLMInterface() + if userID in reservation_flags and reservation_flags[userID]: + prompt_capacity = '''请判断这句话里是否含有预约会议室的人数信息,若有只要回答人数,若没有则回答无。 例如:我想预定一个五人的会议室。 回答:5; 我想在明天定一个会议室,回答:无''' + content1 = prompt_capacity + '\n\n' + content + print(content1) + response = llm_qianfa.query(content1) + print(response) + try: + number_of_people = re.findall(r'\d+', response)[0] + number_of_people = int(number_of_people) + except: + number_of_people = 0 + + meeting_rooms = RBooking.getroombycapacity(number_of_people) + keys = ['id', 'name', 'floor', 'capacity', 'equipment'] + meeting_rooms = [dict(zip(keys, room)) for room in meeting_rooms] + + prompt_head = '''你是会议室预约小助手,会议室预约的必选项是会议主题、会议预约日期、会议预约时间(可以是时间段也可以是时间长度,若是后者,你要为用户选择一个时间,格式例如9:00-12:00),可选项是会议人数(default=5),会议室名称(default根据数据选择)。你要根据用户输入判断是否覆盖了必选项的所有。如果缺了,请你必须告知用户需要补充什么信息,此时**不需要**返回json;如果没缺:你**仅**需返回一个json格式,key必须为:subject, date, time, room_name, room_id, number_of_people。\n\n''' + + history = chat_history.get(userID) + # 列表合并为字符串 + history = '\n'.join(history) + + # content按\n分割取最后一个 + content = content.split('\n')[-1] + + content2 = prompt_head + '可用会议室:' + str(meeting_rooms) + '\n\n' + '现在的时间是:' + day_and_time + '\n\n' + '请按照我的指令执行:' + '\n\n' + history + '\n\n' + content + + response = llm_minimax.query(content2) + print(response) + + try: + # json + response = json.loads(response) + print(response) + reservation_flags[userID] = False + chat_history[userID] = [] + return jsonify({'code': 0, 'message': '获取AI结果成功', 'status': 200, 'data': response, 'json': "true"}), 200 + + except: + reservation_flags[userID] = True + if chat_history.get(userID) is None: + chat_history[userID] = [] + chat_history[userID].append(content) + return jsonify({'code': 0, 'message': '获取AI结果成功', 'status': 200, 'data': response}), 200 + + + prompt = '''你是一个智能办公助手,你的能力有下面几种: 1. 回答有关日程的安排。2. 回答有关会议室的安排、预约情况等 3. 帮助用户进行日程的插入 4. 帮助用户进行会议室的预约。5. 其它不属于以上四种的情况。无论用户输入什么,你的输出回答里都有且只能有一个阿拉伯数字,即判断是上面的五种能力中的哪一种。\n例如:用户输入:帮我预定一间下午的会议室,两个小时 你的回答:4; 用户输入:今天我有哪些会议 你的回答:2; 用户输入:昨晚什么天气?利物浦赢了吗?1+1等于几 你的回答:5; 用户输入:帮我查查看今天有什么紧急的事 你的回答:1; 用户输入:帮我在旅游事项里加入一项订机票 你的回答:3; 用户输入:我想预定一间会议室 你的回答:4;用户输入:我今天有哪些日程 你的回答:1''' + + print(content) + + response = llm_qianfa.query(prompt + '\n\n' + content) print(response) # 提取response中的数字 - response_type = re.findall(r'\d+', response)[0] - day_and_time = Arrow.now().format('YYYY-MM-DD HH:mm:ss') + try: + response_type = re.findall(r'\d+', response)[0] + except: + response_type = '5' if (response_type == '1'): activities = DBUtil.getActivities(int(userID)) @@ -417,18 +524,67 @@ def getAIResult(): keys = ["ActivityID", "UserID", "ActivityName", "ActivityBeginDate", "ActivityBeginTime", "ActivityEndDate", "ActivityEndTime"] # keys和activities都删去第1列(从0开始) activities_list = [dict(zip(keys, activity)) for activity in activities] - prompt_head = '''你是我的日程问答小助手,以下是我的日程安排:\n\n''' - prompt_tail = '''\n\n请回答我的问题:''' + # 把日期在3天前的日程删去 + activities_list = [ + activity for activity in activities_list + if arrow.get(activity["ActivityEndDate"], 'YYYY-MM-DD').shift(days=3) >= Arrow.now() + ] + print(activities_list) + prompt_head = '''你是我的日程问答小助手,以下是我的日程安排,日程分为尚未开始,正在进行,已经结束三种:\n\n''' + prompt_tail = '''\n\n请回答我的问题(注意今天的日期在活动开始和结束日期之间的都算今天正在进行的日程,例如假设今天是2024年6月12日,那么如果我问今天有哪些日程,**那么我问的是今天正在进行的日程有哪些**你要回答的内容包括开始在12日前(例如6月1日)且结束在12日后的所有日程(例如6月30日)):''' prompt = prompt_head + str(activities_list) + '\n\n' + '现在的时间是:' + day_and_time + '\n\n' + prompt_tail + '\n\n' - response = llm.query(content, prefix_prompt=prompt) + content = prompt + '\n\n' + content + # response = llm.query(content, prefix_prompt=prompt) + response = llm_minimax.query(content) elif (response_type == '2'): reservations = RBooking.getallreservations(Arrow.now().format('YYYY-MM-DD')) keys = ['id', 'room_id', 'user_id', 'start_time', 'end_time', 'date'] reservations_list = [dict(zip(keys, reservation)) for reservation in reservations] - prompt_head = '''你是我的预约记录问答小助手,以下是我的预约记录:\n\n''' - prompt_tail = '''\n\n请回答我的问题:''' - prompt = prompt_head + str(reservations_list) + '\n\n' + '现在的时间是:' + day_and_time + '\n\n' + prompt_tail + '\n\n' - response = llm.query(content, prefix_prompt=prompt) + if len(reservations_list) == 0: + reservations_list = ["今天所有会议室都可用,暂无预约记录"] + prompt_head = '''你是我的预约记录问答小助手,以下是我的预约记录:\n''' + prompt_tail = '''\n\n请注意,你一定要回答的正确,例如问今天有哪些会议,就不要输出昨天的会议。请回答我的问题:''' + prompt = prompt_head + str(reservations_list) + '\n\n' + '现在的时间是:' + day_and_time + '\n\n' + '我的user_id是' + str(userID) + prompt_tail + '\n\n' + content = prompt + '\n\n' + content + print(content) + response = llm_minimax.query(content) + elif (response_type == '4'): + prompt_capacity = '''请判断这句话里是否含有预约会议室的人数信息,若有只要回答人数,若没有则回答无。 例如:我想预定一个五人的会议室。 回答:5; 我想在明天定一个会议室,回答:无''' + content1 = prompt_capacity + '\n\n' + content + print(content1) + response = llm_qianfa.query(content1) + print(response) + try: + number_of_people = re.findall(r'\d+', response)[0] + number_of_people = int(number_of_people) + except: + number_of_people = 0 + + meeting_rooms = RBooking.getroombycapacity(number_of_people) + keys = ['id', 'name', 'floor', 'capacity', 'equipment'] + rooms_list = [dict(zip(keys, room)) for room in meeting_rooms] + + prompt_head = '''你是会议室预约小助手,会议室预约的必选项是会议主题、会议预约日期、会议预约时间(可以是时间段也可以是时间长度,若是后者,你要为用户选择一个时间, 格式例如9:00-12:00),可选项是会议人数(default=5),会议室名称(default根据数据选择)。你要根据用户输入判断是否覆盖了必选项的所有。如果有缺漏,请你告知用户需要补充什么信息,此时**不需要**返回json;如果没缺:你**仅**需返回一个json格式,key必须为:subject, date, time, room_name, room_id, number_of_people。\n\n''' + + content2 = prompt_head + '可用会议室:' + str(rooms_list) + '\n\n' + '现在的时间是:' + day_and_time + '\n\n' + '请按照我的指令执行:' + '\n\n' + content + print(content2) + response = llm_minimax.query(content2) + print(response) + + try: + # json + print(response) + reservation_flags[userID] = False + chat_history[userID] = [] + return jsonify({'code': 0, 'message': '获取AI结果成功', 'status': 200, 'data': response}), 200 + except: + reservation_flags[userID] = True + if chat_history.get(userID) is None: + chat_history[userID] = [] + chat_history[userID].append(content) + return jsonify({'code': 0, 'message': '获取AI结果成功', 'status': 200, 'data': response}), 200 + + diff --git a/backend/sqlite_roombooking.py b/backend/sqlite_roombooking.py index f6f8b6e..8410a46 100644 --- a/backend/sqlite_roombooking.py +++ b/backend/sqlite_roombooking.py @@ -29,6 +29,7 @@ def createTables(): end_time TEXT NOT NULL, date TEXT NOT NULL, subject TEXT NOT NULL, + type INTEGER DEFAULT 0, FOREIGN KEY (room_id) REFERENCES meeting_room(id), FOREIGN KEY (user_id) REFERENCES users(id))''') conn.commit() @@ -91,6 +92,13 @@ def getallreservationsbyroom(room_id, date): def insertreservation(room_id, user_id, start_time, end_time, date, subject): try: lock_threading.acquire() + # 先获取今天的预约情况,如果有冲突则返回False + cursor.execute("SELECT * FROM booking WHERE room_id=? AND date=?", (room_id, date)) + reservations = cursor.fetchall() + for reservation in reservations: + if (start_time >= reservation[3] and start_time < reservation[4]) or (end_time > reservation[3] and end_time <= reservation[4]) or (start_time <= reservation[3] and end_time >= reservation[4]): + return False + # 如果没有冲突则插入预约记录 cursor.execute("INSERT INTO booking (room_id, user_id, start_time, end_time, date, subject) VALUES (?, ?, ?, ?, ?, ?)", (room_id, user_id, start_time, end_time, date, subject)) conn.commit() @@ -101,11 +109,30 @@ def insertreservation(room_id, user_id, start_time, end_time, date, subject): finally: lock_threading.release() +def insertreservation_team(room_id, user_id, start_time, end_time, date, subject, team_id): + try: + lock_threading.acquire() + cursor.execute("SELECT * FROM booking WHERE room_id=? AND date=?", (room_id, date)) + reservations = cursor.fetchall() + for reservation in reservations: + if (start_time >= reservation[3] and start_time < reservation[4]) or (end_time > reservation[3] and end_time <= reservation[4]) or (start_time <= reservation[3] and end_time >= reservation[4]): + return False + cursor.execute("INSERT INTO booking (room_id, user_id, start_time, end_time, date, subject, type) VALUES (?, ?, ?, ?, ?, ?, ?)", + (room_id, user_id, start_time, end_time, date, subject, team_id)) + conn.commit() + return True + except sqlite3.Error as e: + print(e) + return False + finally: + lock_threading.release() + def getuserreservations(user_id): try: lock_threading.acquire() # cursor.execute("SELECT * FROM booking WHERE user_id=?", (user_id,)) # 加上会议室名称 + cursor.execute("SELECT booking.*, meeting_room.name FROM booking JOIN meeting_room ON booking.room_id = meeting_room.id WHERE booking.user_id=?", (user_id,)) return cursor.fetchall() except sqlite3.Error as e: @@ -114,6 +141,17 @@ def getuserreservations(user_id): finally: lock_threading.release() +def getreservation(reservation_id): + try: + lock_threading.acquire() + cursor.execute("SELECT * FROM booking WHERE id=?", (reservation_id,)) + return cursor.fetchone() + except sqlite3.Error as e: + print(e) + return None + finally: + lock_threading.release() + def deletereservation(user_id, reservation_id): try: lock_threading.acquire() @@ -123,5 +161,16 @@ def deletereservation(user_id, reservation_id): except sqlite3.Error as e: print(e) return False + finally: + lock_threading.release() + +def getroombycapacity(capacity): + try: + lock_threading.acquire() + # 返回3个会议室,id小的优先,同时返回 + cursor.execute("SELECT * FROM meeting_room WHERE capacity>=? ORDER BY capacity ASC LIMIT 3", (capacity,)) + except sqlite3.Error as e: + print(e) + return None finally: lock_threading.release() \ No newline at end of file diff --git a/backend/sqlite_team.py b/backend/sqlite_team.py index 4387f44..35f18d6 100644 --- a/backend/sqlite_team.py +++ b/backend/sqlite_team.py @@ -4,6 +4,7 @@ import csv from sqlite3 import Error import threading +import sqlite_roombooking as RB db_name = 'Ai_work' @@ -33,11 +34,48 @@ def createTables(): PRIMARY KEY (team_id, member_id), FOREIGN KEY (team_id) REFERENCES team(id), FOREIGN KEY (member_id) REFERENCES users(id))''') + # 通知id,会议室id,用户id,预定开始时间,预定结束时间,预定日期 + cursor.execute('''CREATE TABLE IF NOT EXISTS meeting_room_reservation + (id INTEGER PRIMARY KEY AUTOINCREMENT, + room_id INTEGER NOT NULL, + room_name TEXT NOT NULL, + user_id INTEGER NOT NULL, + reserve_user_id INTEGER NOT NULL, + reserve_user_name TEXT NOT NULL, + start_time TEXT NOT NULL, + end_time TEXT NOT NULL, + date TEXT NOT NULL, + subject TEXT NOT NULL, + team_id INTEGER, + team_name TEXT, + type INTEGER DEFAULT 0, + FOREIGN KEY (room_id) REFERENCES meeting_room(id), + FOREIGN KEY (user_id) REFERENCES users(id))''' + ) conn.commit() createTables() +def insertMeetingRoomReservation(room_id, user_id, reserve_user_id, start_time, end_time, date, subject, team_id, type=0): + try: + lock_threading.acquire() + # 先拿team_id对应的team_name + cursor.execute('''SELECT name FROM team WHERE id = ?''', (team_id,)) + team_name = cursor.fetchone()[0] + cursor.execute('''SELECT username FROM users WHERE id = ?''', (reserve_user_id,)) + reserve_user_name = cursor.fetchone()[0] + cursor.execute('''INSERT INTO meeting_room_reservation (room_id, room_name, user_id, reserve_user_id, reserve_user_name, start_time, end_time, date, subject, team_id, team_name, type) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)''', (room_id, RB.getroomname(room_id), user_id, reserve_user_id, reserve_user_name, start_time, end_time, date, subject, team_id, team_name, type)) + + conn.commit() + return True + except sqlite3.Error as e: + print(e) + return False + finally: + lock_threading.release() + + def insertTeam(team_name, captain_id): try: lock_threading.acquire() diff --git a/frontend/src/pages/HomePage/HomePage.tsx b/frontend/src/pages/HomePage/HomePage.tsx index c724d30..6f85127 100644 --- a/frontend/src/pages/HomePage/HomePage.tsx +++ b/frontend/src/pages/HomePage/HomePage.tsx @@ -1,5 +1,5 @@ -import React, { useRef, useState } from 'react'; -import { ProChat, ProChatProvider, useProChat } from '@ant-design/pro-chat'; +import React, { ReactNode, useEffect, useRef, useState } from 'react'; +import { ChatItemProps, ProChat, ProChatProvider, useProChat } from '@ant-design/pro-chat'; import HttpUtil from '../../utils/HttpUtil'; import ApiUtil from '../../utils/ApiUtil'; import { ApiResponse } from '../../utils/ApiUtil'; @@ -8,6 +8,8 @@ import styled from 'styled-components'; import RightTopSection from './RightTopSection'; import LeftTopSection from './LeftTopSection'; import RightTopSection2 from './RightTopsection2'; +import { Button, Card, Form, Input, InputNumber, Modal, Select, message } from 'antd'; +import moment from 'moment'; const Container = styled.div` display: flex; @@ -25,93 +27,244 @@ const TopArea = styled.div` position: relative; `; -const Placeholder = styled.div` - width: 48%; - height: 300px; - border: 1px solid #ddd; - border-radius: 10px; -`; +interface Member { + member_id: number; + is_captain: number; +} + +interface Team { + team_id: number; + team_name: string; + is_captain: number; + members: Member[]; +} + +interface FormData { + subject: string; + date: string; + time: string; + number_of_people: number; + room_name: string; + room_id: number; + team_id?: number; +} + +interface FormComponentProps { + formData: FormData; +} const Homepage: React.FC = () => { - const chatRef = useRef(null); // 用于获取ProChat实例 - const times = useRef(null); - - const handleRequest = async (messages: any) => { - try { - const content = messages.map((msg: any) => msg.content).join('\n'); - const response = await HttpUtil.post(ApiUtil.API_AI_CHAT, - { - content, - userID: localStorage.getItem('userID') - }) as ApiResponse; - if (response.status !== 200) { - throw new Error(`HTTP error! status: ${response.status}`); - } - console.log(response.data); - return new Response(response.data); - } catch (error) { - console.error('Error fetching chat response:', error); - return new Response('Error fetching chat response', { status: 500 }); - } - }; + const chatRef = useRef(null); + const [teams, setTeams] = useState([]); - // 实例化迅飞语音听写 - const xfVoice = new XfVoiceDictation({ - APPID: '27ce1c02', - APISecret: 'NWRhNDM1NTJlMmJiYmU0YWI5OGY1YmNm', - APIKey: 'c55054b06c4f1753117debf4b31168dd', - onWillStatusChange: function (oldStatus: any, newStatus: any) { - console.log('开始识别:', oldStatus, newStatus); - }, - onTextChange: function (text: any) { - console.log('识别内容:', text); - if (text) { - if (times.current) { - clearTimeout(times.current); - } - times.current = setTimeout(() => xfVoice.stop(), 3000); - // 将识别内容填充到ProChat的输入框中 - if (chatRef.current) { - chatRef.current.setValue(text); - } - } - } - }); + const handleSubmit = async (values: any) => { + try { + const [startTime, endTime] = values.time.split('-'); + const newReservation = { + room_id: values.room_id, + user_id: localStorage.getItem('userID') || 1, + start_time: startTime, + end_time: endTime, + date: values.date, + subject: values.subject, + type: values.type, + team_id: values.type === 'team' ? values.team_id : null, + }; + const response = await HttpUtil.post(ApiUtil.API_INSERT_RESERVATION, newReservation) as ApiResponse; + if (response.status === 200) { + message.success('预约成功'); + } else { + message.error('预约失败'); + } + } catch (error) { + message.error('预约失败'); + } + }; - const handleVoiceButtonClick = () => { - xfVoice.start(); - }; + const FormComponent: React.FC = ({ formData }) => { + const [type, setType] = useState('individual'); + const [form] = Form.useForm(); - const handleVoiceStopButtonClick = () => { - xfVoice.stop(); + useEffect(() => { + fetchTeams(); + }, []); + + const handleTypeChange = (value: string) => { + setType(value); + if (value === 'individual') { + form.setFieldsValue({ team_id: undefined }); + } }; - return ( - - - - {/* Use the new component */} - -
-
- -
-
-
+ +
+ + + + + + + + + + + + + {type === 'individual' ? ( + + + + ) : ( + + + + )} + + + + + + + +
+
); + }; + + const fetchTeams = async () => { + try { + const response = await HttpUtil.post(ApiUtil.API_GET_ALL_TEAMS, + { + userID: localStorage.getItem('userID') + } + ) as ApiResponse; + if (response.status === 200) { + const userID = localStorage.getItem('userID'); + const filteredTeams = response.data.filter((team) => { + console.log(team); + return team.is_captain === 1; + }); + setTeams(filteredTeams); + console.log(filteredTeams); + console.log('teams:', teams); + } else { + message.error('获取团队列表失败'); + } + } catch (error) { + message.error('获取团队列表失败'); + } + }; + + const handleRequest = async (messages: any) => { + try { + const content = messages.map((msg: any) => msg.content).join('\n'); + const response = await HttpUtil.post(ApiUtil.API_AI_CHAT, { + content, + userID: localStorage.getItem('userID'), + }) as ApiResponse; + if (response.status !== 200) { + throw new Error(`HTTP error! status: ${response.status}`); + } + console.log(response.data); + + return new Response(response.data); + } catch (error) { + console.error('Error fetching chat response:', error); + return new Response('Error fetching chat response', { status: 500 }); + } + }; + + // 实例化迅飞语音听写 + // const xfVoice = new XfVoiceDictation({ + // APPID: '27ce1c02', + // APISecret: 'NWRhNDM1NTJlMmJiYmU0YWI5OGY1YmNm', + // APIKey: 'c55054b06c4f1753117debf4b31168dd', + // onWillStatusChange: function (oldStatus: any, newStatus: any) { + // console.log('开始识别:', oldStatus, newStatus); + // }, + // onTextChange: function (text: any) { + // console.log('识别内容:', text); + // if (text) { + // if (times.current) { + // clearTimeout(times.current); + // } + // times.current = setTimeout(() => xfVoice.stop(), 3000); + // // 将识别内容填充到ProChat的输入框中 + // if (chatRef.current) { + // chatRef.current.setValue(text); + // } + // } + // } + // }); + + // const handleVoiceButtonClick = () => { + // xfVoice.start(); + // }; + + // const handleVoiceStopButtonClick = () => { + // xfVoice.stop(); + // }; + + + return ( + + + + {/* Use the new component */} + +
+
+ >, defaultDom: ReactNode) => { + const item = props.originData; + console.log('====', item); + + if (typeof item?.content === 'string' && (item.content.startsWith('```json') || item.content.startsWith('{'))) { + try { + const jsonString = item.content.replace(/```json|\n```/g, '').trim(); + const formData = JSON.parse(jsonString); + console.log('formData:', formData); + + return ; + } catch (error) { + console.error('Error parsing JSON:', error); + return defaultDom; + } + } + return defaultDom; + }, + }} + /> +
+
+
+ ); }; export default Homepage; diff --git a/frontend/src/pages/Reservation/ReservationModal.tsx b/frontend/src/pages/Reservation/ReservationModal.tsx index 9670c2f..6c10c61 100644 --- a/frontend/src/pages/Reservation/ReservationModal.tsx +++ b/frontend/src/pages/Reservation/ReservationModal.tsx @@ -158,6 +158,7 @@ const ReservationModal: React.FC = ({ date: values.date.format('YYYY-MM-DD'), subject: values.title, type: bookingType, + team_id: values.teamId || null, }; const response = await HttpUtil.post(ApiUtil.API_INSERT_RESERVATION, newReservation) as ApiResponse; if (response.status === 200) { diff --git a/frontend/src/pages/TodoList/TodoList.tsx b/frontend/src/pages/TodoList/TodoList.tsx index a47ee75..7369ff3 100644 --- a/frontend/src/pages/TodoList/TodoList.tsx +++ b/frontend/src/pages/TodoList/TodoList.tsx @@ -462,6 +462,7 @@ class TodoList extends React.Component<{}, TodoListState> { ]} value={activityStatus} onChange={this.handleActivityStatusChange} + defaultValue='ongoing' />