From 75a03ea6a21b9c21492797e41845cf01d7c1a894 Mon Sep 17 00:00:00 2001 From: Moujuruo <704353780@qq.com> Date: Thu, 27 Jun 2024 22:56:36 +0800 Subject: [PATCH] add new functions --- Ai_work.db | Bin 81920 -> 94208 bytes backend/SqliteUtil.py | 50 ++- backend/llm_interface.py | 43 +++ backend/run_app.py | 186 ++++++++++- backend/sqlite_roombooking.py | 49 +++ backend/sqlite_team.py | 38 +++ frontend/src/pages/HomePage/HomePage.tsx | 311 +++++++++++++----- .../pages/Reservation/ReservationModal.tsx | 1 + frontend/src/pages/TodoList/TodoList.tsx | 1 + 9 files changed, 578 insertions(+), 101 deletions(-) diff --git a/Ai_work.db b/Ai_work.db index 79acda05c500341f7b0181f0a9a6842a36e5cea7..4794774379f2357b920df6cce95d2bffa3f99aee 100644 GIT binary patch delta 5305 zcmcIoU2q#$72dn6pOsd-*LJYi^6yHD<2Z@&{^-XRP1D4q)(NRY6AzP+w2D(J#!_tu zM-3C0um<8L159YUrJB$HeFy^&jnc$4N=Q4MzQ7DH6lQqoLunaor%Y!|hhfMAFWmjn zYFAoil+arCSbKEtcg}atx#ym%#YOkxhwkS)TEIRG!&vlJ{)xP>O~k>zYe#1(^2$T!+7a-+_OC5%?2$7=9hT#oUE|W8Pa1akm(`iy^jy*-R!sGdG=Hn4h0b zFJw+;7EVp(XXfYJTLQ!(kgoS}dj6TIw8)E5J}$=bpqEI1^s)K*oC;-Vmwh<_2!5kdS4{s{OBn8yB#T~Pi^ zKP2Y_KL%1EHpEI2vGV4RKPncvK~8_OTD&ZwhqW88pkI~dARiwT<07BrdCQ|{d*p=S zWK2l%BNYu(l;!=H&oHK&kUu+PxuFJ_$@fi-PYO~MHC2@Td^NR(n8_6=(IJj?jO7L! zpw?1=!h*Jww!=ruBqkbrUKr6DutLmsoT?;WyjR&RDwsk_UZz2VFERDOL!9YLp#Bt z+(m_?C{z}hq7#oPtw&;V^%8rw%Lr)lDf?Ox{H{i2)zW zhJu71eS1mkV-<#hi;XDd8&TS4Rg&!qi<|bgSheaYxf@WzKD?Kbtc{ImIKO=_t+LX~ zjVOIhQ)*?jEnC$RQ2U7VmjjNY+K8c@W{;|R7E^r)oQIBK)R+^hWQRdwT zlrhgGg?Dc)y-R{c9LEOHtUd7LSwH1v6A5rm%1<79CgXTja1>Ib`%^n7QryJOU3*hp z*ilDm_DZFGFE|61FH!w?p$Ng3+kDsrM&AtdQS1JjWYT?wXs7RD6Udq5@ui*ZUUvI- z@V!>e8OO^Bx|`IKx7l5)r>1&UKwkBd+SO`qa#rD8ZG}gX#IN78GU;bez6iRTDo>e( zw64b%j(b5?dBo)z&SxfP(=$_HZuj^^>ao=RZM2``!kQH6X2RS=>fnSSJbeN^&&=gB z)0qWj5VRNm?gj72OD%0)_Rt}4Ue<$O&tu!gt+AV5t34Kui(1s{qzyYlr82iF%>H2E%2W#h_FP{WLloQa6G-mDL+EEnalQEG- z4G4!vF?bywU2f(lp!_AA#z08zBy6b9C*b$VDNo-6Dn{X z?tz;i&b-f*m>)4Gm~mz+L((hsE&3&tuY{oA;wVJKq_3ZT@KOaGtR5yryy7cLq35r z%moY=HjwC0m3Sd$nNs;gG!~CgCKG;G<;GWIASKRUff-Sms4@9FVG)jq zCQFo&$~4SJHKnl21Tsh|XRo$U5yD)nyn3}`EP|WQI7%b3g}&XY7}T*)1*7D*qOZ|N NmAdUt!AqLC{{fcb@xcH9 delta 465 zcmZp8z}nEjIzdW^p@o5gK?I0lKx(3n5fekp#)SF&jNF?9m;@wtGH~)oGxERVU(Vme ze}?}d|6KlP{&N1kn*|LV`6ox~$1?Iv-l?z7$H2|bEX|mdpP!wXmoBjRoxYfY1Q(Am z1OGgJ8@^|Jb$pV%8+ko>p7XTw2yYe?_|DB%z{ADB8913SP-1dKw4}AEk%5(gfsuic ziLQZ}u92yc5eiqqz`)Ab#LCDVp#mGKucKo4snGa$}wJG+^isw%d|b3g)xn3voA9r)AsWmj15doOjbZE&6qaN z;Z|pwzK)+UOoEFgih)0cPn!1x&k~+gu1j3AIaAr5vqS;a*|BV2E6V7_vHcw*qYC5X zeAeL2seGP{lRenxY*S$57GUh(&SSvn#Lwt5`690aZ$1+@10$!Qwz09iF~jsIea67) TXYCj{xD8Dd41qyr3JfLyZ_{= 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 6e84654..a08ae0a 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' />