diff --git a/config.json b/config.json index e8724db..1214e07 100644 --- a/config.json +++ b/config.json @@ -22,6 +22,7 @@ "join": 10 }, "playSound": true, + "sound_synthesis_enabled": false, "visualization": false }, "items": [], diff --git a/core/content_db.py b/core/content_db.py index b109e84..313d2a6 100644 --- a/core/content_db.py +++ b/core/content_db.py @@ -50,7 +50,7 @@ class Content_Db: conn = sqlite3.connect("fay.db") cur = conn.cursor() try: - cur.execute("insert into T_Msg (type,way,content,createtime,username,uid) values (?,?,?,?,?,?)",(type,way,content,int(time.time()),username,uid)) + cur.execute("insert into T_Msg (type,way,content,createtime,username,uid) values (?,?,?,?,?,?)",(type, way, content, time.time(), username, uid)) conn.commit() except: util.log(1, "请检查参数是否有误") diff --git a/core/fay_core.py b/core/fay_core.py index bb5c963..4e4012e 100644 --- a/core/fay_core.py +++ b/core/fay_core.py @@ -65,7 +65,7 @@ modules = { } #大语言模型回复 -def handle_chat_message(msg, username='User'): +def handle_chat_message(msg, username='User', observation=''): text = '' textlist = [] try: @@ -81,7 +81,7 @@ def handle_chat_message(msg, username='User'): text = textlist[0]['text'] else: uid = member_db.new_instance().find_user(username) - text = selected_module.question(msg, uid) + text = selected_module.question(msg, uid, observation) util.printInfo(1, username, '自然语言处理完成. 耗时: {} ms'.format(math.floor((time.time() - tm) * 1000))) if text == '哎呀,你这么说我也不懂,详细点呗' or text == '': util.printInfo(1, username, '[!] 自然语言无语了!') @@ -161,9 +161,9 @@ class FeiFei: if wsa_server.get_instance().is_connected(username): content = {'Topic': 'Unreal', 'Data': {'Key': 'log', 'Value': "思考中..."}, 'Username' : username, 'robot': f'http://{cfg.fay_url}:5000/robot/Thinking.jpg'} wsa_server.get_instance().add_cmd(content) - text,textlist = handle_chat_message(interact.data["msg"], username) + text,textlist = handle_chat_message(interact.data["msg"], username, interact.data.get("observation", "")) - qa_service.QAService().record_qapair(interact.data["msg"], text)#沟通记录缓存到qa文件 + # qa_service.QAService().record_qapair(interact.data["msg"], text)#沟通记录缓存到qa文件 else: text = answer @@ -315,15 +315,16 @@ class FeiFei: def say(self, interact, text): try: result = None - audio_url = interact.data.get('audio')#透传的音频 - if audio_url is not None: - file_name = 'sample-' + str(int(time.time() * 1000)) + '.wav' - result = self.download_wav(audio_url, './samples/', file_name) - elif config_util.config["interact"]["playSound"] or wsa_server.get_instance().is_connected(interact.data.get("user")) or self.__is_send_remote_device_audio(interact):#tts - util.printInfo(1, interact.data.get('user'), '合成音频...') - tm = time.time() - result = self.sp.to_sample(text.replace("*", ""), self.__get_mood_voice()) - util.printInfo(1, interact.data.get('user'), '合成音频完成. 耗时: {} ms 文件:{}'.format(math.floor((time.time() - tm) * 1000), result)) + if config_util.config["interact"]["sound_synthesis_enabled"]: + audio_url = interact.data.get('audio')#透传的音频 + if audio_url is not None: + file_name = 'sample-' + str(int(time.time() * 1000)) + '.wav' + result = self.download_wav(audio_url, './samples/', file_name) + elif config_util.config["interact"]["playSound"] or wsa_server.get_instance().is_connected(interact.data.get("user")) or self.__is_send_remote_device_audio(interact):#tts + util.printInfo(1, interact.data.get('user'), '合成音频...') + tm = time.time() + result = self.sp.to_sample(text.replace("*", ""), self.__get_mood_voice()) + util.printInfo(1, interact.data.get('user'), '合成音频完成. 耗时: {} ms 文件:{}'.format(math.floor((time.time() - tm) * 1000), result)) if result is not None: MyThread(target=self.__process_output_audio, args=[result, interact, text]).start() diff --git a/gui/flask_server.py b/gui/flask_server.py index e4c38f5..f122f24 100644 --- a/gui/flask_server.py +++ b/gui/flask_server.py @@ -7,6 +7,7 @@ import re from flask import Flask, render_template, request, jsonify, Response, send_file from flask_cors import CORS import requests +import datetime import fay_booter @@ -82,8 +83,7 @@ def api_get_data(): voice_list = tts_voice.get_voice_list() send_voice_list = [] if config_util.tts_module == 'ali': - wsa_server.get_web_instance().add_cmd({ - "voiceList": [ + voice_list = [ {"id": "abin", "name": "阿斌"}, {"id": "zhixiaobai", "name": "知小白"}, {"id": "zhixiaoxia", "name": "知小夏"}, @@ -159,10 +159,12 @@ def api_get_data(): {"id": "laotie", "name": "老铁"}, {"id": "laomei", "name": "老妹"}, {"id": "aikan", "name": "艾侃"} - ] - }) + + ] + send_voice_list = {"voiceList": voice_list} + wsa_server.get_web_instance().add_cmd(send_voice_list) elif config_util.tts_module == 'volcano': - wsa_server.get_web_instance().add_cmd({ + voice_list = { "voiceList": [ {"id": "BV001_streaming", "name": "通用女声"}, {"id": "BV002_streaming", "name": "通用男声"}, @@ -171,7 +173,9 @@ def api_get_data(): {"id": "zh_male_wennuanahu_moon_bigtts", "name": "温暖阿虎/Alvin"}, {"id": "zh_female_wanwanxiaohe_moon_bigtts", "name": "湾湾小何"}, ] - }) + } + send_voice_list = {"voiceList": voice_list} + wsa_server.get_web_instance().add_cmd(send_voice_list) else: voice_list = tts_voice.get_voice_list() send_voice_list = [] @@ -181,10 +185,11 @@ def api_get_data(): wsa_server.get_web_instance().add_cmd({ "voiceList": send_voice_list }) + voice_list = send_voice_list wsa_server.get_web_instance().add_cmd({"deviceList": __get_device_list()}) if fay_booter.is_running(): wsa_server.get_web_instance().add_cmd({"liveState": 1}) - return json.dumps({'config': config_util.config, 'voice_list' : send_voice_list}) + return json.dumps({'config': config_util.config, 'voice_list' : voice_list}) @__app.route('/api/start-live', methods=['post']) @@ -227,7 +232,8 @@ def api_get_Msg(): relist = [] i = len(list)-1 while i >= 0: - relist.append(dict(type=list[i][0], way=list[i][1], content=list[i][2], createtime=list[i][3], timetext=list[i][4], username=list[i][5])) + timetext = datetime.datetime.fromtimestamp(list[i][3]).strftime('%Y-%m-%d %H:%M:%S.%f')[:-3] + relist.append(dict(type=list[i][0], way=list[i][1], content=list[i][2], createtime=list[i][3], timetext=timetext, username=list[i][5])) i -= 1 if fay_booter.is_running(): wsa_server.get_web_instance().add_cmd({"liveState": 1}) @@ -249,7 +255,8 @@ def api_send_v1_chat_completions(): username = 'User' model = data.get('model', 'fay') - interact = Interact("text", 1, {'user': username, 'msg': last_content}) + observation = data.get('observation', '') + interact = Interact("text", 1, {'user': username, 'msg': last_content, 'observation': observation}) util.printInfo(3, "文字沟通接口", '{}'.format(interact.data["msg"]), time.time()) text = fay_booter.feiFei.on_interact(interact) @@ -265,6 +272,12 @@ def api_get_Member_list(): return json.dumps({'list': list}) +@__app.route('/api/get_run_status', methods=['post']) +def api_get_run_status(): + status = fay_booter.is_running() + return json.dumps({'status': status}) + + def stream_response(text): def generate(): for chunk in text_chunks(text): diff --git a/gui/static/js/index.js b/gui/static/js/index.js index 852402b..eb9f7f9 100644 --- a/gui/static/js/index.js +++ b/gui/static/js/index.js @@ -83,6 +83,12 @@ class FayInterface { }); } + getRunStatus() { + return this.fetchData(`${this.baseApiUrl}/api/get_run_status`, { + method: 'POST' + }); + } + getMessageHistory(username) { return new Promise((resolve, reject) => { const url = `${this.baseApiUrl}/api/get-msg`; @@ -122,6 +128,19 @@ class FayInterface { }); } + getTime(){ + const date = new Date(); + const year = date.getFullYear(); + const month = (date.getMonth() + 1).toString().padStart(2, '0'); // 月份从0开始,需要+1 + const day = date.getDate().toString().padStart(2, '0'); + const hours = date.getHours().toString().padStart(2, '0'); + const minutes = date.getMinutes().toString().padStart(2, '0'); + const seconds = date.getSeconds().toString().padStart(2, '0'); + const milliseconds = date.getMilliseconds().toString().padStart(3, '0'); + const currentDateTimeWithMs = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}.${milliseconds}`; + return currentDateTimeWithMs + } + handleIncomingMessage(data) { const vueInstance = this.vueInstance; // console.log('Incoming message:', data); @@ -129,10 +148,8 @@ class FayInterface { vueInstance.liveState = data.liveState; if (data.liveState === 1) { vueInstance.configEditable = false; - vueInstance.sendSuccessMsg('已开启!'); } else if (data.liveState === 0) { vueInstance.configEditable = true; - vueInstance.sendSuccessMsg('已关闭!'); } } @@ -169,7 +186,7 @@ class FayInterface { username: data.panelReply.username, content: data.panelReply.content, type: data.panelReply.type, - time: new Date().toLocaleTimeString() + timetext: this.getTime() }); vueInstance.$nextTick(() => { const chatContainer = vueInstance.$el.querySelector('.chatmessage'); @@ -207,17 +224,31 @@ class FayInterface { chatMessages: {}, panelMsg: '', panelReply: '', - robot:'static/images/Normal.gif' + robot:'static/images/Normal.gif', + base_url: 'http://127.0.0.1:5000' }; }, created() { this.initFayService(); - this.loadUserList(); + // this.loadUserList(); }, methods: { initFayService() { - this.fayService = new FayInterface('ws://127.0.0.1:10003', 'http://127.0.0.1:5000', this); + this.fayService = new FayInterface('ws://127.0.0.1:10003', this.base_url, this); this.fayService.connectWebSocket(); + this.fayService.websocket.addEventListener('open', () => { + this.loadUserList(); + }); + this.fayService.getRunStatus().then((data) => { + if (data) { + if(data.status){ + this.liveState = 1; + }else{ + this.liveState = 0; + } + + } + }); }, sendMessage() { let _this = this; @@ -241,7 +272,7 @@ class FayInterface { document.querySelector('.chatmessage').scrollTop = height; }, 1000); _this.newMessage = ''; - let url = "http://127.0.0.1:5000/api/send"; + let url = `${this.base_url}/api/send`; let send_data = { "msg": text, "username": usernameToSend @@ -255,7 +286,6 @@ class FayInterface { xhr.onreadystatechange = async function () { if (!executed && xhr.status === 200) { executed = true; - // 成功处理逻辑(可以添加额外的回调操作) } }; }, @@ -283,11 +313,13 @@ class FayInterface { startLive() { this.liveState = 2 this.fayService.startLive().then(() => { + this.sendSuccessMsg('已开启!'); }); }, stopLive() { this.fayService.stopLive().then(() => { this.liveState = 3 + this.sendSuccessMsg('已关闭!'); }); }, diff --git a/gui/static/js/setting.js b/gui/static/js/setting.js index 638ddda..71719df 100644 --- a/gui/static/js/setting.js +++ b/gui/static/js/setting.js @@ -73,6 +73,13 @@ class FayInterface { }); } + getRunStatus() { + return this.fetchData(`${this.baseApiUrl}/api/get_run_status`, { + method: 'POST' + }); + } + + handleIncomingMessage(data) { const vueInstance = this.vueInstance; console.log('Incoming message:', data); @@ -80,10 +87,8 @@ class FayInterface { vueInstance.liveState = data.liveState; if (data.liveState === 1) { vueInstance.configEditable = false; - vueInstance.sendSuccessMsg('已开启!'); } else if (data.liveState === 0) { vueInstance.configEditable = true; - vueInstance.sendSuccessMsg('已关闭!'); } } @@ -132,6 +137,7 @@ new Vue({ visualization_detection_enabled: false, source_record_enabled: false, source_record_device: '', + sound_synthesis_enabled: true, attribute_name: "", attribute_gender: "", attribute_age: "", @@ -165,6 +171,7 @@ new Vue({ }], automatic_player_status: false, automatic_player_url: "", + host_url: "http://127.0.0.1:5000" }; }, created() { @@ -173,10 +180,22 @@ new Vue({ }, methods: { initFayService() { - this.fayService = new FayInterface('ws://127.0.0.1:10003', 'http://127.0.0.1:5000', this); + this.fayService = new FayInterface('ws://127.0.0.1:10003', this.host_url, this); this.fayService.connectWebSocket(); }, getData() { + this.fayService.getRunStatus().then((data) => { + if (data) { + if(data.status){ + this.liveState = 1; + this.configEditable = false; + }else{ + this.liveState = 0; + this.configEditable = true; + } + + } + }); this.fayService.getData().then((data) => { if (data) { this.voiceList = data.voice_list.map((voice) => ({ @@ -192,6 +211,7 @@ new Vue({ if (config.interact) { this.play_sound_enabled = config.interact.playSound; this.visualization_detection_enabled = config.interact.visualization; + this.sound_synthesis_enabled = config.interact.sound_synthesis_enabled; this.QnA = config.interact.QnA; } if (config.source && config.source.record) { @@ -224,7 +244,7 @@ new Vue({ } }, saveConfig() { - let url = "http://127.0.0.1:5000/api/submit"; + let url = `${this.host_url}/api/submit`; let send_data = { "config": { "source": { @@ -257,6 +277,7 @@ new Vue({ }, "interact": { "playSound": this.play_sound_enabled, + "sound_synthesis_enabled": this.sound_synthesis_enabled, "visualization": this.visualization_detection_enabled, "QnA": this.QnA, "maxInteractTime": this.interact_maxInteractTime, @@ -293,12 +314,14 @@ new Vue({ this.liveState = 2 this.fayService.startLive().then(() => { this.configEditable = false; + this.sendSuccessMsg('已开启!'); }); }, stopLive() { + this.liveState = 3 this.fayService.stopLive().then(() => { this.configEditable = true; - this.liveState = 3 + this.sendSuccessMsg('已关闭!'); }); }, sendSuccessMsg(message) { diff --git a/gui/templates/setting.html b/gui/templates/setting.html index 29c6735..549decf 100644 --- a/gui/templates/setting.html +++ b/gui/templates/setting.html @@ -29,7 +29,7 @@