2024-10-26 11:34:55 +08:00
|
|
|
import importlib
|
|
|
|
import json
|
|
|
|
import time
|
|
|
|
import os
|
|
|
|
import pyaudio
|
|
|
|
import re
|
|
|
|
from flask import Flask, render_template, request, jsonify, Response, send_file
|
|
|
|
from flask_cors import CORS
|
|
|
|
import requests
|
2024-10-30 19:11:15 +08:00
|
|
|
import datetime
|
2024-11-27 17:29:51 +08:00
|
|
|
import pytz
|
2024-10-26 11:34:55 +08:00
|
|
|
|
|
|
|
import fay_booter
|
|
|
|
|
|
|
|
from tts import tts_voice
|
|
|
|
from gevent import pywsgi
|
|
|
|
from scheduler.thread_manager import MyThread
|
|
|
|
from utils import config_util, util
|
|
|
|
from core import wsa_server
|
|
|
|
from core import fay_core
|
|
|
|
from core import content_db
|
|
|
|
from core.interact import Interact
|
|
|
|
from core import member_db
|
|
|
|
import fay_booter
|
|
|
|
from flask_httpauth import HTTPBasicAuth
|
2024-12-10 16:23:32 +08:00
|
|
|
from flask import Flask, render_template, request, jsonify, Response, send_file
|
|
|
|
from flask_cors import CORS
|
|
|
|
from flask_socketio import SocketIO, emit
|
2024-11-06 18:42:52 +08:00
|
|
|
from core import qa_service
|
2024-10-26 11:34:55 +08:00
|
|
|
|
|
|
|
__app = Flask(__name__)
|
|
|
|
auth = HTTPBasicAuth()
|
|
|
|
CORS(__app, supports_credentials=True)
|
2024-12-10 16:23:32 +08:00
|
|
|
socketio = SocketIO(__app, async_mode='gevent', cors_allowed_origins="*")
|
2024-10-26 11:34:55 +08:00
|
|
|
def load_users():
|
2024-11-06 18:45:44 +08:00
|
|
|
try:
|
|
|
|
with open('verifier.json') as f:
|
|
|
|
users = json.load(f)
|
|
|
|
return users
|
|
|
|
except Exception as e:
|
|
|
|
print(f"Error loading users: {e}")
|
|
|
|
return {}
|
2024-10-26 11:34:55 +08:00
|
|
|
|
|
|
|
users = load_users()
|
|
|
|
|
|
|
|
@auth.verify_password
|
|
|
|
def verify_password(username, password):
|
|
|
|
if not users or config_util.start_mode == 'common':
|
|
|
|
return True
|
|
|
|
if username in users and users[username] == password:
|
|
|
|
return username
|
|
|
|
|
2024-11-20 23:44:47 +08:00
|
|
|
|
2024-10-26 11:34:55 +08:00
|
|
|
def __get_template():
|
2024-11-06 18:45:44 +08:00
|
|
|
try:
|
|
|
|
return render_template('index.html')
|
|
|
|
except Exception as e:
|
|
|
|
return f"Error rendering template: {e}", 500
|
2024-10-26 11:34:55 +08:00
|
|
|
|
|
|
|
def __get_device_list():
|
2024-11-06 18:45:44 +08:00
|
|
|
try:
|
|
|
|
if config_util.start_mode == 'common':
|
|
|
|
audio = pyaudio.PyAudio()
|
|
|
|
device_list = []
|
|
|
|
for i in range(audio.get_device_count()):
|
|
|
|
devInfo = audio.get_device_info_by_index(i)
|
|
|
|
if devInfo['hostApi'] == 0:
|
|
|
|
device_list.append(devInfo["name"])
|
|
|
|
return list(set(device_list))
|
|
|
|
else:
|
|
|
|
return []
|
|
|
|
except Exception as e:
|
|
|
|
print(f"Error getting device list: {e}")
|
2024-10-26 11:34:55 +08:00
|
|
|
return []
|
|
|
|
|
2024-11-20 23:44:47 +08:00
|
|
|
|
2024-10-26 11:34:55 +08:00
|
|
|
@__app.route('/api/submit', methods=['post'])
|
|
|
|
def api_submit():
|
|
|
|
data = request.values.get('data')
|
2024-11-06 18:45:44 +08:00
|
|
|
if not data:
|
|
|
|
return jsonify({'result': 'error', 'message': '未提供数据'})
|
|
|
|
try:
|
|
|
|
config_data = json.loads(data)
|
|
|
|
if 'config' not in config_data:
|
|
|
|
return jsonify({'result': 'error', 'message': '数据中缺少config'})
|
|
|
|
|
|
|
|
config_util.load_config()
|
|
|
|
existing_config = config_util.config
|
|
|
|
|
|
|
|
def merge_configs(existing, new):
|
|
|
|
for key, value in new.items():
|
|
|
|
if isinstance(value, dict) and key in existing:
|
|
|
|
if isinstance(existing[key], dict):
|
|
|
|
merge_configs(existing[key], value)
|
|
|
|
else:
|
|
|
|
existing[key] = value
|
|
|
|
else:
|
|
|
|
existing[key] = value
|
|
|
|
|
|
|
|
merge_configs(existing_config, config_data['config'])
|
|
|
|
|
|
|
|
config_util.save_config(existing_config)
|
2024-11-27 17:29:51 +08:00
|
|
|
config_util.load_config()
|
2024-11-06 18:45:44 +08:00
|
|
|
|
|
|
|
return jsonify({'result': 'successful'})
|
|
|
|
except json.JSONDecodeError:
|
|
|
|
return jsonify({'result': 'error', 'message': '无效的JSON数据'})
|
|
|
|
except Exception as e:
|
|
|
|
return jsonify({'result': 'error', 'message': f'保存配置时出错: {e}'}), 500
|
|
|
|
|
2024-10-26 11:34:55 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@__app.route('/api/get-data', methods=['post'])
|
|
|
|
def api_get_data():
|
2024-11-06 18:45:44 +08:00
|
|
|
# 获取配置和语音列表
|
|
|
|
try:
|
|
|
|
config_util.load_config()
|
2024-10-26 11:34:55 +08:00
|
|
|
voice_list = tts_voice.get_voice_list()
|
|
|
|
send_voice_list = []
|
2024-11-06 18:45:44 +08:00
|
|
|
if config_util.tts_module == 'ali':
|
|
|
|
voice_list = [
|
|
|
|
{"id": "abin", "name": "阿斌"},
|
|
|
|
{"id": "zhixiaobai", "name": "知小白"},
|
|
|
|
{"id": "zhixiaoxia", "name": "知小夏"},
|
|
|
|
{"id": "zhixiaomei", "name": "知小妹"},
|
|
|
|
{"id": "zhigui", "name": "知柜"},
|
|
|
|
{"id": "zhishuo", "name": "知硕"},
|
|
|
|
{"id": "aixia", "name": "艾夏"},
|
|
|
|
{"id": "zhifeng_emo", "name": "知锋_多情感"},
|
|
|
|
{"id": "zhibing_emo", "name": "知冰_多情感"},
|
|
|
|
{"id": "zhimiao_emo", "name": "知妙_多情感"},
|
|
|
|
{"id": "zhimi_emo", "name": "知米_多情感"},
|
|
|
|
{"id": "zhiyan_emo", "name": "知燕_多情感"},
|
|
|
|
{"id": "zhibei_emo", "name": "知贝_多情感"},
|
|
|
|
{"id": "zhitian_emo", "name": "知甜_多情感"},
|
|
|
|
{"id": "xiaoyun", "name": "小云"},
|
|
|
|
{"id": "xiaogang", "name": "小刚"},
|
|
|
|
{"id": "ruoxi", "name": "若兮"},
|
|
|
|
{"id": "siqi", "name": "思琪"},
|
|
|
|
{"id": "sijia", "name": "思佳"},
|
|
|
|
{"id": "sicheng", "name": "思诚"},
|
|
|
|
{"id": "aiqi", "name": "艾琪"},
|
|
|
|
{"id": "aijia", "name": "艾佳"},
|
|
|
|
{"id": "aicheng", "name": "艾诚"},
|
|
|
|
{"id": "aida", "name": "艾达"},
|
|
|
|
{"id": "ninger", "name": "宁儿"},
|
|
|
|
{"id": "ruilin", "name": "瑞琳"},
|
|
|
|
{"id": "siyue", "name": "思悦"},
|
|
|
|
{"id": "aiya", "name": "艾雅"},
|
|
|
|
{"id": "aimei", "name": "艾美"},
|
|
|
|
{"id": "aiyu", "name": "艾雨"},
|
|
|
|
{"id": "aiyue", "name": "艾悦"},
|
|
|
|
{"id": "aijing", "name": "艾婧"},
|
|
|
|
{"id": "xiaomei", "name": "小美"},
|
|
|
|
{"id": "aina", "name": "艾娜"},
|
|
|
|
{"id": "yina", "name": "伊娜"},
|
|
|
|
{"id": "sijing", "name": "思婧"},
|
|
|
|
{"id": "sitong", "name": "思彤"},
|
|
|
|
{"id": "xiaobei", "name": "小北"},
|
|
|
|
{"id": "aitong", "name": "艾彤"},
|
|
|
|
{"id": "aiwei", "name": "艾薇"},
|
|
|
|
{"id": "aibao", "name": "艾宝"},
|
|
|
|
{"id": "shanshan", "name": "姗姗"},
|
|
|
|
{"id": "chuangirl", "name": "小玥"},
|
|
|
|
{"id": "lydia", "name": "Lydia"},
|
|
|
|
{"id": "aishuo", "name": "艾硕"},
|
|
|
|
{"id": "qingqing", "name": "青青"},
|
|
|
|
{"id": "cuijie", "name": "翠姐"},
|
|
|
|
{"id": "xiaoze", "name": "小泽"},
|
|
|
|
{"id": "zhimao", "name": "知猫"},
|
|
|
|
{"id": "zhiyuan", "name": "知媛"},
|
|
|
|
{"id": "zhiya", "name": "知雅"},
|
|
|
|
{"id": "zhiyue", "name": "知悦"},
|
|
|
|
{"id": "zhida", "name": "知达"},
|
|
|
|
{"id": "zhistella", "name": "知莎"},
|
|
|
|
{"id": "kelly", "name": "Kelly"},
|
|
|
|
{"id": "jiajia", "name": "佳佳"},
|
|
|
|
{"id": "taozi", "name": "桃子"},
|
|
|
|
{"id": "guijie", "name": "柜姐"},
|
|
|
|
{"id": "stella", "name": "Stella"},
|
|
|
|
{"id": "stanley", "name": "Stanley"},
|
|
|
|
{"id": "kenny", "name": "Kenny"},
|
|
|
|
{"id": "rosa", "name": "Rosa"},
|
|
|
|
{"id": "mashu", "name": "马树"},
|
|
|
|
{"id": "xiaoxian", "name": "小仙"},
|
|
|
|
{"id": "yuer", "name": "悦儿"},
|
|
|
|
{"id": "maoxiaomei", "name": "猫小美"},
|
|
|
|
{"id": "aifei", "name": "艾飞"},
|
|
|
|
{"id": "yaqun", "name": "亚群"},
|
|
|
|
{"id": "qiaowei", "name": "巧薇"},
|
|
|
|
{"id": "dahu", "name": "大虎"},
|
|
|
|
{"id": "ailun", "name": "艾伦"},
|
|
|
|
{"id": "jielidou", "name": "杰力豆"},
|
|
|
|
{"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':
|
|
|
|
voice_list = [
|
|
|
|
{"id": "BV001_streaming", "name": "通用女声"},
|
|
|
|
{"id": "BV002_streaming", "name": "通用男声"},
|
|
|
|
{"id": "zh_male_jingqiangkanye_moon_bigtts", "name": "京腔侃爷/Harmony"},
|
|
|
|
{"id": "zh_female_shuangkuaisisi_moon_bigtts", "name": "爽快思思/Skye"},
|
|
|
|
{"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 = []
|
|
|
|
for voice in voice_list:
|
|
|
|
voice_data = voice.value
|
|
|
|
send_voice_list.append({"id": voice_data['name'], "name": voice_data['name']})
|
|
|
|
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': voice_list})
|
|
|
|
except Exception as e:
|
|
|
|
return jsonify({'result': 'error', 'message': f'获取数据时出错: {e}'}), 500
|
2024-10-26 11:34:55 +08:00
|
|
|
|
|
|
|
@__app.route('/api/start-live', methods=['post'])
|
|
|
|
def api_start_live():
|
2024-11-06 18:45:44 +08:00
|
|
|
# 启动
|
|
|
|
try:
|
|
|
|
fay_booter.start()
|
|
|
|
time.sleep(1)
|
|
|
|
wsa_server.get_web_instance().add_cmd({"liveState": 1})
|
|
|
|
return '{"result":"successful"}'
|
|
|
|
except Exception as e:
|
|
|
|
return jsonify({'result': 'error', 'message': f'启动时出错: {e}'}), 500
|
2024-10-26 11:34:55 +08:00
|
|
|
|
|
|
|
@__app.route('/api/stop-live', methods=['post'])
|
|
|
|
def api_stop_live():
|
2024-11-06 18:45:44 +08:00
|
|
|
# 停止
|
|
|
|
try:
|
|
|
|
fay_booter.stop()
|
|
|
|
time.sleep(1)
|
|
|
|
wsa_server.get_web_instance().add_cmd({"liveState": 0})
|
|
|
|
return '{"result":"successful"}'
|
|
|
|
except Exception as e:
|
|
|
|
return jsonify({'result': 'error', 'message': f'停止时出错: {e}'}), 500
|
2024-10-26 11:34:55 +08:00
|
|
|
|
|
|
|
@__app.route('/api/send', methods=['post'])
|
|
|
|
def api_send():
|
2024-11-06 18:45:44 +08:00
|
|
|
# 接收前端发送的消息
|
2024-10-26 11:34:55 +08:00
|
|
|
data = request.values.get('data')
|
2024-11-06 18:45:44 +08:00
|
|
|
if not data:
|
|
|
|
return jsonify({'result': 'error', 'message': '未提供数据'})
|
|
|
|
try:
|
|
|
|
info = json.loads(data)
|
|
|
|
username = info.get('username')
|
|
|
|
msg = info.get('msg')
|
|
|
|
if not username or not msg:
|
|
|
|
return jsonify({'result': 'error', 'message': '用户名和消息内容不能为空'})
|
|
|
|
interact = Interact("text", 1, {'user': username, 'msg': msg})
|
2024-11-20 23:44:47 +08:00
|
|
|
util.printInfo(1, username, '[文字发送按钮]{}'.format(interact.data["msg"]), time.time())
|
2024-11-06 18:45:44 +08:00
|
|
|
fay_booter.feiFei.on_interact(interact)
|
|
|
|
return '{"result":"successful"}'
|
|
|
|
except json.JSONDecodeError:
|
|
|
|
return jsonify({'result': 'error', 'message': '无效的JSON数据'})
|
|
|
|
except Exception as e:
|
|
|
|
return jsonify({'result': 'error', 'message': f'发送消息时出错: {e}'}), 500
|
2024-10-26 11:34:55 +08:00
|
|
|
|
2024-11-06 18:45:44 +08:00
|
|
|
# 获取指定用户的消息记录
|
2024-10-26 11:34:55 +08:00
|
|
|
@__app.route('/api/get-msg', methods=['post'])
|
|
|
|
def api_get_Msg():
|
2024-11-06 18:45:44 +08:00
|
|
|
try:
|
2024-11-20 23:44:47 +08:00
|
|
|
data = request.form.get('data')
|
|
|
|
if data is None:
|
|
|
|
data = request.get_json()
|
|
|
|
else:
|
|
|
|
data = json.loads(data)
|
2024-11-06 18:45:44 +08:00
|
|
|
uid = member_db.new_instance().find_user(data["username"])
|
|
|
|
contentdb = content_db.new_instance()
|
|
|
|
if uid == 0:
|
|
|
|
return json.dumps({'list': []})
|
|
|
|
else:
|
|
|
|
list = contentdb.get_list('all', 'desc', 1000, uid)
|
|
|
|
relist = []
|
|
|
|
i = len(list) - 1
|
|
|
|
while i >= 0:
|
2024-11-27 17:29:51 +08:00
|
|
|
timezone = pytz.timezone('Asia/Shanghai')
|
|
|
|
timetext = datetime.datetime.fromtimestamp(list[i][3], timezone).strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]
|
2024-11-06 18:45:44 +08:00
|
|
|
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], id=list[i][6], is_adopted=list[i][7]))
|
|
|
|
i -= 1
|
|
|
|
if fay_booter.is_running():
|
|
|
|
wsa_server.get_web_instance().add_cmd({"liveState": 1})
|
|
|
|
return json.dumps({'list': relist})
|
|
|
|
except json.JSONDecodeError:
|
|
|
|
return jsonify({'list': [], 'message': '无效的JSON数据'})
|
|
|
|
except Exception as e:
|
|
|
|
return jsonify({'list': [], 'message': f'获取消息时出错: {e}'}), 500
|
2024-10-26 11:34:55 +08:00
|
|
|
|
|
|
|
@__app.route('/v1/chat/completions', methods=['post'])
|
|
|
|
@__app.route('/api/send/v1/chat/completions', methods=['post'])
|
|
|
|
def api_send_v1_chat_completions():
|
2024-11-06 18:45:44 +08:00
|
|
|
# 处理聊天完成请求
|
|
|
|
data = request.get_json()
|
|
|
|
if not data:
|
|
|
|
return jsonify({'error': '未提供数据'})
|
|
|
|
try:
|
|
|
|
last_content = ""
|
|
|
|
if 'messages' in data and data['messages']:
|
|
|
|
last_message = data['messages'][-1]
|
|
|
|
username = last_message.get('role', 'User')
|
|
|
|
if username == 'user':
|
|
|
|
username = 'User'
|
|
|
|
last_content = last_message.get('content', 'No content provided')
|
|
|
|
else:
|
|
|
|
last_content = 'No messages found'
|
2024-10-26 11:34:55 +08:00
|
|
|
username = 'User'
|
|
|
|
|
2024-11-06 18:45:44 +08:00
|
|
|
model = data.get('model', 'fay')
|
|
|
|
observation = data.get('observation', '')
|
2024-11-27 17:29:51 +08:00
|
|
|
interact = Interact("text", 1, {'user': username, 'msg': last_content, 'observation': str(observation)})
|
2024-11-20 23:44:47 +08:00
|
|
|
util.printInfo(1, username, '[文字沟通接口]{}'.format(interact.data["msg"]), time.time())
|
2024-11-06 18:45:44 +08:00
|
|
|
text = fay_booter.feiFei.on_interact(interact)
|
2024-10-26 11:34:55 +08:00
|
|
|
|
2024-11-06 18:45:44 +08:00
|
|
|
if model == 'fay-streaming':
|
|
|
|
return stream_response(text)
|
|
|
|
else:
|
|
|
|
return non_streaming_response(last_content, text)
|
|
|
|
except Exception as e:
|
|
|
|
return jsonify({'error': f'处理请求时出错: {e}'}), 500
|
2024-10-26 11:34:55 +08:00
|
|
|
|
|
|
|
@__app.route('/api/get-member-list', methods=['post'])
|
|
|
|
def api_get_Member_list():
|
2024-11-06 18:45:44 +08:00
|
|
|
# 获取成员列表
|
|
|
|
try:
|
|
|
|
memberdb = member_db.new_instance()
|
|
|
|
list = memberdb.get_all_users()
|
|
|
|
return json.dumps({'list': list})
|
|
|
|
except Exception as e:
|
|
|
|
return jsonify({'list': [], 'message': f'获取成员列表时出错: {e}'}), 500
|
2024-10-26 11:34:55 +08:00
|
|
|
|
2024-10-30 19:11:15 +08:00
|
|
|
@__app.route('/api/get_run_status', methods=['post'])
|
|
|
|
def api_get_run_status():
|
2024-11-06 18:45:44 +08:00
|
|
|
# 获取运行状态
|
2024-11-06 18:34:56 +08:00
|
|
|
try:
|
2024-11-06 18:45:44 +08:00
|
|
|
status = fay_booter.is_running()
|
|
|
|
return json.dumps({'status': status})
|
2024-11-06 18:34:56 +08:00
|
|
|
except Exception as e:
|
2024-11-06 18:45:44 +08:00
|
|
|
return jsonify({'status': False, 'message': f'获取运行状态时出错: {e}'}), 500
|
2024-10-30 19:11:15 +08:00
|
|
|
|
2024-11-06 18:42:52 +08:00
|
|
|
@__app.route('/api/adopt_msg', methods=['POST'])
|
|
|
|
def adopt_msg():
|
2024-11-06 18:45:44 +08:00
|
|
|
# 采纳消息
|
2024-11-06 18:42:52 +08:00
|
|
|
data = request.get_json()
|
|
|
|
if not data:
|
|
|
|
return jsonify({'status':'error', 'msg': '未提供数据'})
|
|
|
|
|
|
|
|
id = data.get('id')
|
|
|
|
|
|
|
|
if not id:
|
|
|
|
return jsonify({'status':'error', 'msg': 'id不能为空'})
|
|
|
|
|
2024-11-06 18:45:44 +08:00
|
|
|
if config_util.config["interact"]["QnA"] == "":
|
|
|
|
return jsonify({'status':'error', 'msg': '请先设置Q&A文件'})
|
2024-11-06 18:34:56 +08:00
|
|
|
|
|
|
|
try:
|
2024-11-06 18:45:44 +08:00
|
|
|
info = content_db.new_instance().get_content_by_id(id)
|
|
|
|
content = info[3] if info else ''
|
|
|
|
if info is not None:
|
|
|
|
previous_info = content_db.new_instance().get_previous_user_message(id)
|
|
|
|
previous_content = previous_info[3] if previous_info else ''
|
|
|
|
result = content_db.new_instance().adopted_message(id)
|
|
|
|
if result:
|
|
|
|
qa_service.QAService().record_qapair(previous_content, content)
|
|
|
|
return jsonify({'status': 'success', 'msg': '采纳成功'})
|
|
|
|
else:
|
|
|
|
return jsonify({'status':'error', 'msg': '采纳失败'}), 500
|
2024-11-06 18:42:52 +08:00
|
|
|
else:
|
2024-11-06 18:45:44 +08:00
|
|
|
return jsonify({'status':'error', 'msg': '消息未找到'}), 404
|
|
|
|
except Exception as e:
|
|
|
|
return jsonify({'status':'error', 'msg': f'采纳消息时出错: {e}'}), 500
|
2024-11-06 18:42:52 +08:00
|
|
|
|
2024-10-26 11:34:55 +08:00
|
|
|
def stream_response(text):
|
2024-11-06 18:45:44 +08:00
|
|
|
# 处理流式响应
|
2024-10-26 11:34:55 +08:00
|
|
|
def generate():
|
|
|
|
for chunk in text_chunks(text):
|
|
|
|
message = {
|
|
|
|
"id": "chatcmpl-8jqorq6Fw1Vi5XoH7pddGGpQeuPe0",
|
|
|
|
"object": "chat.completion.chunk",
|
|
|
|
"created": int(time.time()),
|
|
|
|
"model": "fay-streaming",
|
|
|
|
"choices": [
|
|
|
|
{
|
|
|
|
"delta": {
|
|
|
|
"content": chunk
|
|
|
|
},
|
|
|
|
"index": 0,
|
|
|
|
"finish_reason": None
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
yield f"data: {json.dumps(message)}\n\n"
|
|
|
|
time.sleep(0.1)
|
|
|
|
yield 'data: [DONE]\n\n'
|
2024-11-20 23:44:47 +08:00
|
|
|
|
2024-10-26 11:34:55 +08:00
|
|
|
return Response(generate(), mimetype='text/event-stream')
|
|
|
|
|
|
|
|
def non_streaming_response(last_content, text):
|
2024-11-06 18:45:44 +08:00
|
|
|
# 处理非流式响应
|
2024-10-26 11:34:55 +08:00
|
|
|
return jsonify({
|
|
|
|
"id": "chatcmpl-8jqorq6Fw1Vi5XoH7pddGGpQeuPe0",
|
|
|
|
"object": "chat.completion",
|
|
|
|
"created": int(time.time()),
|
|
|
|
"model": "fay",
|
|
|
|
"choices": [
|
|
|
|
{
|
|
|
|
"index": 0,
|
|
|
|
"message": {
|
|
|
|
"role": "assistant",
|
|
|
|
"content": text
|
|
|
|
},
|
|
|
|
"logprobs": "",
|
|
|
|
"finish_reason": "stop"
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"usage": {
|
|
|
|
"prompt_tokens": len(last_content),
|
|
|
|
"completion_tokens": len(text),
|
|
|
|
"total_tokens": len(last_content) + len(text)
|
|
|
|
},
|
|
|
|
"system_fingerprint": "fp_04de91a479"
|
|
|
|
})
|
|
|
|
|
|
|
|
def text_chunks(text, chunk_size=20):
|
|
|
|
pattern = r'([^.!?;:,。!?]+[.!?;:,。!?]?)'
|
|
|
|
chunks = re.findall(pattern, text)
|
|
|
|
for chunk in chunks:
|
|
|
|
yield chunk
|
|
|
|
|
2024-12-10 16:23:32 +08:00
|
|
|
messages = []
|
|
|
|
|
|
|
|
@socketio.on('send_message')
|
|
|
|
def handle_send_message(data):
|
|
|
|
"""
|
|
|
|
处理来自客户端的消息。
|
|
|
|
data: {
|
|
|
|
'username': '用户或系统',
|
|
|
|
'message': '消息内容',
|
|
|
|
'type': 'user' 或 'system'
|
|
|
|
}
|
|
|
|
"""
|
|
|
|
timestamp = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
|
|
|
|
message = {
|
|
|
|
'id': len(messages) + 1,
|
|
|
|
'username': data.get('username', '用户'),
|
|
|
|
'content': data.get('message', ''),
|
|
|
|
'type': data.get('type', 'user'),
|
|
|
|
'timetext': timestamp,
|
|
|
|
'is_adopted': 1 # 根据需要调整
|
|
|
|
}
|
|
|
|
messages.append(message)
|
|
|
|
|
|
|
|
# 只保留最近的100条消息以防内存溢出
|
|
|
|
if len(messages) > 100:
|
|
|
|
messages.pop(0)
|
|
|
|
|
|
|
|
# 向所有客户端广播新消息
|
|
|
|
emit('receive_message', message, broadcast=True)
|
|
|
|
|
|
|
|
# 系统自动回复(可根据实际需求调整)
|
|
|
|
system_message_content = f"您说的是:{data.get('message', '')}"
|
|
|
|
system_message = {
|
|
|
|
'id': len(messages) + 1,
|
|
|
|
'username': '系统',
|
|
|
|
'content': system_message_content,
|
|
|
|
'type': 'system',
|
|
|
|
'timetext': time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()),
|
|
|
|
'is_adopted': 1
|
|
|
|
}
|
|
|
|
messages.append(system_message)
|
|
|
|
|
|
|
|
emit('receive_message', system_message, broadcast=True)
|
|
|
|
|
|
|
|
@socketio.on('connect')
|
|
|
|
def handle_connect():
|
|
|
|
print('客户端已连接')
|
|
|
|
# 发送最近三条消息给新连接的客户端
|
|
|
|
recent_messages = messages[-3:]
|
|
|
|
emit('load_messages', recent_messages)
|
|
|
|
|
|
|
|
@socketio.on('disconnect')
|
|
|
|
def handle_disconnect():
|
|
|
|
print('客户端已断开连接')
|
|
|
|
|
2024-10-26 11:34:55 +08:00
|
|
|
@__app.route('/', methods=['get'])
|
|
|
|
@auth.login_required
|
|
|
|
def home_get():
|
2024-11-06 18:45:44 +08:00
|
|
|
try:
|
|
|
|
return __get_template()
|
|
|
|
except Exception as e:
|
|
|
|
return f"Error loading home page: {e}", 500
|
2024-10-26 11:34:55 +08:00
|
|
|
|
|
|
|
@__app.route('/', methods=['post'])
|
|
|
|
@auth.login_required
|
|
|
|
def home_post():
|
2024-11-06 18:45:44 +08:00
|
|
|
try:
|
|
|
|
wsa_server.get_web_instance().add_cmd({"is_connect": wsa_server.get_instance().isConnect}) # TODO 不应放这里,同步数字人连接状态
|
|
|
|
return __get_template()
|
|
|
|
except Exception as e:
|
|
|
|
return f"Error processing request: {e}", 500
|
2024-10-26 11:34:55 +08:00
|
|
|
|
|
|
|
@__app.route('/setting', methods=['get'])
|
|
|
|
def setting():
|
2024-11-06 18:45:44 +08:00
|
|
|
try:
|
|
|
|
return render_template('setting.html')
|
|
|
|
except Exception as e:
|
|
|
|
return f"Error loading settings page: {e}", 500
|
2024-10-26 11:34:55 +08:00
|
|
|
|
2024-12-10 16:23:32 +08:00
|
|
|
|
|
|
|
@__app.route('/chat')
|
|
|
|
def chat():
|
|
|
|
return render_template('chat.html')
|
2024-11-06 18:45:44 +08:00
|
|
|
# 输出的音频http
|
2024-10-26 11:34:55 +08:00
|
|
|
@__app.route('/audio/<filename>')
|
|
|
|
def serve_audio(filename):
|
|
|
|
audio_file = os.path.join(os.getcwd(), "samples", filename)
|
2024-11-06 18:45:44 +08:00
|
|
|
if os.path.exists(audio_file):
|
|
|
|
return send_file(audio_file)
|
|
|
|
else:
|
|
|
|
return jsonify({'error': '文件未找到'}), 404
|
2024-10-26 11:34:55 +08:00
|
|
|
|
2024-11-06 18:45:44 +08:00
|
|
|
# 输出的表情gif
|
2024-10-26 11:34:55 +08:00
|
|
|
@__app.route('/robot/<filename>')
|
|
|
|
def serve_gif(filename):
|
|
|
|
gif_file = os.path.join(os.getcwd(), "gui", "robot", filename)
|
2024-11-06 18:45:44 +08:00
|
|
|
if os.path.exists(gif_file):
|
|
|
|
return send_file(gif_file)
|
|
|
|
else:
|
|
|
|
return jsonify({'error': '文件未找到'}), 404
|
2024-10-26 11:34:55 +08:00
|
|
|
|
|
|
|
def run():
|
|
|
|
server = pywsgi.WSGIServer(('0.0.0.0',5000), __app)
|
|
|
|
server.serve_forever()
|
|
|
|
|
|
|
|
def start():
|
|
|
|
MyThread(target=run).start()
|