仓库初始化

This commit is contained in:
killua committed 2024-05-01 17:18:30 +08:00
commit 83cbe007ba
60 files changed
+5190

No files matched your search

+53
View File
@@ -0,0 +1,53 @@
from fastapi import FastAPI, Depends
from fastapi.middleware.cors import CORSMiddleware
from sqlalchemy import create_engine
from .models import Base
from .routes.character import router as character_router
from .routes.user import router as user_router
from .routes.session import router as session_router
from .routes.chat import router as chat_router
from .dependencies.logger import get_logger
from config import get_config
#----------------------获取日志------------------------
logger = get_logger()
logger.info("日志初始化完成")
#-----------------------------------------------------
#----------------------获取配置------------------------
Config = get_config()
logger.info("配置获取完成")
#-----------------------------------------------------
#--------------------初始化数据库-----------------------
engine = create_engine(Config.SQLALCHEMY_DATABASE_URI)
Base.metadata.create_all(bind=engine)
logger.info("数据库初始化完成")
#------------------------------------------------------
#--------------------创建FastAPI实例--------------------
app = FastAPI()
logger.info("FastAPI实例创建完成")
#------------------------------------------------------
#---------------------初始化路由------------------------
app.include_router(character_router)
app.include_router(user_router)
app.include_router(session_router)
app.include_router(chat_router)
logger.info("路由初始化完成")
#-------------------------------------------------------
#-------------------设置跨域中间件-----------------------
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # 允许所有源,也可以指定特定源
allow_credentials=True,
allow_methods=["*"], # 允许所有方法
allow_headers=["*"], # 允许所有头
)
#-------------------------------------------------------
+1
View File
@@ -0,0 +1 @@
from . import *
+89
View File
@@ -0,0 +1,89 @@
from ..schemas.character import *
from ..dependencies.logger import get_logger
from sqlalchemy.orm import Session
from ..models import Character
from datetime import datetime
from fastapi import HTTPException, status
#依赖注入获取logger
logger = get_logger()
#创建新角色
async def create_character_handler(character: CharacterCreateRequest, db: Session):
new_character = Character(voice_id=character.voice_id, avatar_id=character.avatar_id, background_ids=character.background_ids, name=character.name,
wakeup_words=character.wakeup_words, world_scenario = character.world_scenario, description=character.description, emojis=character.emojis, dialogues=character.dialogues)
try:
db.add(new_character)
db.commit()
db.refresh(new_character)
except Exception as e:
db.rollback()
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
character_create_data = CharacterCreateData(character_id=new_character.id, createdAt=datetime.now().isoformat())
return CharacterCreateResponse(status="success",message="创建角色成功",data=character_create_data)
#更新角色
async def update_character_handler(character_id: int, character: CharacterUpdateRequest, db: Session):
existing_character = db.query(Character).filter(Character.id == character_id).first()
if not existing_character:
return HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="角色不存在")
existing_character.voice_id = character.voice_id
existing_character.avatar_id = character.avatar_id
existing_character.background_ids = character.background_ids
existing_character.name = character.name
existing_character.wakeup_words = character.wakeup_words
existing_character.world_scenario = character.world_scenario
existing_character.description = character.description
existing_character.emojis = character.emojis
existing_character.dialogues = character.dialogues
try:
db.add(existing_character)
db.commit()
except Exception as e:
db.rollback()
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
character_update_data = CharacterUpdateData(updatedAt=datetime.now().isoformat())
return CharacterUpdateResponse(status="success",message="更新角色成功",data=character_update_data)
#查询角色
async def get_character_handler(character_id: int, db: Session):
try:
existing_character = db.query(Character).filter(Character.id == character_id).first()
except Exception as e:
db.rollback()
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
if not existing_character:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="角色不存在")
character_query_data = CharacterQueryData(voice_id=existing_character.voice_id,avatar_id=existing_character.avatar_id,background_ids=existing_character.background_ids,name=existing_character.name,
wakeup_words=existing_character.wakeup_words,world_scenario=existing_character.world_scenario,description=existing_character.description,emojis=existing_character.emojis,dialogues=existing_character.dialogues)
return CharacterQueryResponse(status="success",message="查询角色成功",data=character_query_data)
#删除角色
async def delete_character_handler(character_id: int, db: Session):
try:
existing_character = db.query(Character).filter(Character.id == character_id).first()
except Exception as e:
db.rollback()
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
if not existing_character:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="角色不存在")
try:
db.delete(existing_character)
db.commit()
except Exception as e:
db.rollback()
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
character_delete_data = CharacterDeleteData(id=character_id,deletedAt=datetime.now().isoformat())
return CharacterDeleteResponse(status="success",message="删除角色成功",data=character_delete_data)
+613
View File
@@ -0,0 +1,613 @@
from ..schemas.chat import *
from ..dependencies.logger import get_logger
from .controller_enum import *
from ..models import UserCharacter, Session, Character, User
from utils.audio_utils import VAD
from fastapi import WebSocket, HTTPException, status
from datetime import datetime
from utils.xf_asr_utils import generate_xf_asr_url
from config import get_config
import uuid
import json
import requests
import asyncio
# 依赖注入获取logger
logger = get_logger()
# --------------------初始化本地ASR-----------------------
from utils.stt.funasr_utils import FunAutoSpeechRecognizer
asr = FunAutoSpeechRecognizer()
logger.info("本地ASR初始化成功")
# -------------------------------------------------------
# --------------------初始化本地VITS----------------------
from utils.tts.vits_utils import TextToSpeech
tts = TextToSpeech(device='cpu')
logger.info("本地TTS初始化成功")
# -------------------------------------------------------
# 依赖注入获取Config
Config = get_config()
# ----------------------工具函数-------------------------
#获取session内容
def get_session_content(session_id,redis,db):
session_content_str = ""
if redis.exists(session_id):
session_content_str = redis.get(session_id)
else:
session_db = db.query(Session).filter(Session.id == session_id).first()
if not session_db:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Session not found")
session_content_str = session_db.content
return json.loads(session_content_str)
#解析大模型流式返回内容
def parseChunkDelta(chunk):
decoded_data = chunk.decode('utf-8')
parsed_data = json.loads(decoded_data[6:])
if 'delta' in parsed_data['choices'][0]:
delta_content = parsed_data['choices'][0]['delta']
return delta_content['content']
else:
return ""
#断句函数
def split_string_with_punctuation(current_sentence,text,is_first):
result = []
for char in text:
current_sentence += char
if is_first and char in ',.?!,。?!':
result.append(current_sentence)
current_sentence = ''
is_first = False
elif char in '。?!':
result.append(current_sentence)
current_sentence = ''
return result, current_sentence, is_first
#--------------------------------------------------------
# 创建新聊天
async def create_chat_handler(chat: ChatCreateRequest, db, redis):
# 创建新的UserCharacter记录
new_chat = UserCharacter(user_id=chat.user_id, character_id=chat.character_id)
try:
db.add(new_chat)
db.commit()
db.refresh(new_chat)
except Exception as e:
db.rollback()
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
# 查询所要创建聊天的角色信息,并创建SystemPrompt
db_character = db.query(Character).filter(Character.id == chat.character_id).first()
db_user = db.query(User).filter(User.id == chat.user_id).first()
system_prompt = f"""我们正在角色扮演对话游戏中,你需要始终保持角色扮演并待在角色设定的情景中,你扮演的角色信息如下:\n{"角色名称: " + db_character.name}。\n{"角色背景: " + db_character.description}\n{"角色所处环境: " + db_character.world_scenario}\n
{"角色的常用问候语: " + db_character.wakeup_words}。\n你需要用简单、通俗易懂的口语化方式进行对话,在没有经过允许的情况下,你需要保持上述角色,不得擅自跳出角色设定。\n 与你聊天的对象信息如下:{db_user.persona}"""
# 创建新的Session记录
session_id = str(uuid.uuid4())
user_id = chat.user_id
messages = json.dumps([{"role": "system", "content": system_prompt}], ensure_ascii=False)
tts_info = {
"language": 0,
"speaker_id":db_character.voice_id,
"noise_scale": 0.1,
"noise_scale_w":0.668,
"length_scale": 1.2
}
llm_info = {
"model": "abab5.5-chat",
"temperature": 1,
"top_p": 0.9,
}
# 将tts和llm信息转化为json字符串
tts_info_str = json.dumps(tts_info, ensure_ascii=False)
llm_info_str = json.dumps(llm_info, ensure_ascii=False)
user_info_str = db_user.persona
token = 0
content = {"user_id": user_id, "messages": messages, "user_info": user_info_str, "tts_info": tts_info_str,
"llm_info": llm_info_str, "token": token}
new_session = Session(id=session_id, user_character_id=new_chat.id, content=json.dumps(content, ensure_ascii=False),
last_activity=datetime.now(), is_permanent=False)
# 将Session记录存入
db.add(new_session)
db.commit()
db.refresh(new_session)
redis.set(session_id, json.dumps(content, ensure_ascii=False))
chat_create_data = ChatCreateData(user_character_id=new_chat.id, session_id=session_id, createdAt=datetime.now().isoformat())
return ChatCreateResponse(status="success", message="创建聊天成功", data=chat_create_data)
#删除聊天
async def delete_chat_handler(user_character_id, db, redis):
# 查询该聊天记录
user_character_record = db.query(UserCharacter).filter(UserCharacter.id == user_character_id).first()
if not user_character_record:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="UserCharacter not found")
session_record = db.query(Session).filter(Session.user_character_id == user_character_id).first()
try:
redis.delete(session_record.id)
except Exception as e:
logger.error(f"删除Redis中Session记录时发生错误: {str(e)}")
try:
db.delete(session_record)
db.delete(user_character_record)
db.commit()
except Exception as e:
db.rollback()
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
chat_delete_data = ChatDeleteData(deletedAt=datetime.now().isoformat())
return ChatDeleteResponse(status="success", message="删除聊天成功", data=chat_delete_data)
# 非流式聊天
async def non_streaming_chat_handler(chat: ChatNonStreamRequest, db, redis):
pass
#---------------------------------------单次流式聊天接口---------------------------------------------
#处理用户输入
async def sct_user_input_handler(ws,user_input_q,llm_input_q,future_session_id,future_response_type,user_input_finish_event):
logger.debug("用户输入处理函数启动")
is_future_done = False
try:
while not user_input_finish_event.is_set():
sct_data_json = json.loads(await ws.receive_text())
if not is_future_done:
future_session_id.set_result(sct_data_json['meta_info']['session_id'])
if sct_data_json['meta_info']['voice_synthesize']:
future_response_type.set_result(RESPONSE_AUDIO)
else:
future_response_type.set_result(RESPONSE_TEXT)
is_future_done = True
if sct_data_json['text']:
await llm_input_q.put(sct_data_json['text'])
if not user_input_finish_event.is_set():
user_input_finish_event.set()
break
if sct_data_json['meta_info']['is_end']:
await user_input_q.put(sct_data_json['audio'])
if not user_input_finish_event.is_set():
user_input_finish_event.set()
break
await user_input_q.put(sct_data_json['audio'])
except KeyError as ke:
if sct_data_json['state'] == 1 and sct_data_json['method'] == 'heartbeat':
logger.debug("收到心跳包")
#语音识别
async def sct_asr_handler(user_input_q,llm_input_q,user_input_finish_event):
logger.debug("语音识别函数启动")
current_message = ""
while not (user_input_finish_event.is_set() and user_input_q.empty()):
audio_data = await user_input_q.get()
asr_result = asr.streaming_recognize(audio_data)
current_message += ''.join(asr_result['text'])
asr_result = asr.streaming_recognize(b'',is_end=True)
current_message += ''.join(asr_result['text'])
await llm_input_q.put(current_message)
logger.debug(f"接收到用户消息: {current_message}")
#大模型调用
async def sct_llm_handler(session_id,llm_info,db,redis,llm_input_q,llm_response_q,llm_response_finish_event):
logger.debug("llm调用函数启动")
session_content = get_session_content(session_id,redis,db)
messages = json.loads(session_content["messages"])
current_message = await llm_input_q.get()
messages.append({'role': 'user', "content": current_message})
payload = json.dumps({
"model": llm_info["model"],
"stream": True,
"messages": messages,
"max_tokens": 10000,
"temperature": llm_info["temperature"],
"top_p": llm_info["top_p"]
})
headers = {
'Authorization': f"Bearer {Config.MINIMAX_LLM.API_KEY}",
'Content-Type': 'application/json'
}
response = requests.request("POST", Config.MINIMAX_LLM.URL, headers=headers, data=payload, stream=True)
if response.status_code == 200:
for chunk in response.iter_lines():
if chunk:
chunk_data = parseChunkDelta(chunk)
await llm_response_q.put(chunk_data)
llm_response_finish_event.set()
#大模型返回断句
async def sct_llm_response_handler(session_id,redis,db,llm_response_q,split_result_q,llm_response_finish_event):
logger.debug("llm返回处理函数启动")
llm_response = ""
current_sentence = ""
is_first = True
while not (llm_response_finish_event.is_set() and llm_response_q.empty()):
llm_chunk = await llm_response_q.get()
llm_response += llm_chunk
sentences, current_sentence, is_first = split_string_with_punctuation(current_sentence, llm_chunk, is_first)
for sentence in sentences:
await split_result_q.put(sentence)
session_content = get_session_content(session_id,redis,db)
messages = json.loads(session_content["messages"])
messages.append({'role': 'assistant', "content": llm_response})
session_content["messages"] = json.dumps(messages,ensure_ascii=False) #更新对话
redis.set(session_id,json.dumps(session_content,ensure_ascii=False)) #更新session
logger.debug(f"llm返回结果: {llm_response}")
#文本返回及语音合成
async def sct_response_handler(ws,tts_info,response_type,split_result_q,llm_response_finish_event,chat_finish_event):
logger.debug("返回处理函数启动")
while not (llm_response_finish_event.is_set() and split_result_q.empty()):
sentence = await split_result_q.get()
if response_type == RESPONSE_TEXT:
response_message = {"type": "text", "code":200, "msg": sentence}
await ws.send_text(json.dumps(response_message, ensure_ascii=False))
elif response_type == RESPONSE_AUDIO:
sr,audio = tts.synthesize(sentence, tts_info["speaker_id"], tts_info["language"], tts_info["noise_scale"], tts_info["noise_scale_w"], tts_info["length_scale"],return_bytes=True)
response_message = {"type": "text", "code":200, "msg": sentence}
await ws.send_bytes(audio)
await ws.send_text(json.dumps(response_message, ensure_ascii=False))
logger.debug(f"websocket返回: {sentence}")
chat_finish_event.set()
async def streaming_chat_temporary_handler(ws: WebSocket, db, redis):
logger.debug("streaming chat temporary websocket 连接建立")
user_input_q = asyncio.Queue() # 用于存储用户输入
llm_input_q = asyncio.Queue() # 用于存储llm输入
llm_response_q = asyncio.Queue() # 用于存储llm输出
split_result_q = asyncio.Queue() # 用于存储tts输出
user_input_finish_event = asyncio.Event()
llm_response_finish_event = asyncio.Event()
chat_finish_event = asyncio.Event()
future_session_id = asyncio.Future()
future_response_type = asyncio.Future()
asyncio.create_task(sct_user_input_handler(ws,user_input_q,llm_input_q,future_session_id,future_response_type,user_input_finish_event))
asyncio.create_task(sct_asr_handler(user_input_q,llm_input_q,user_input_finish_event))
session_id = await future_session_id #获取session_id
response_type = await future_response_type #获取返回类型
tts_info = json.loads(get_session_content(session_id,redis,db)["tts_info"])
llm_info = json.loads(get_session_content(session_id,redis,db)["llm_info"])
asyncio.create_task(sct_llm_handler(session_id,llm_info,db,redis,llm_input_q,llm_response_q,llm_response_finish_event))
asyncio.create_task(sct_llm_response_handler(session_id,redis,db,llm_response_q,split_result_q,llm_response_finish_event))
asyncio.create_task(sct_response_handler(ws,tts_info,response_type,split_result_q,llm_response_finish_event,chat_finish_event))
while not chat_finish_event.is_set():
await asyncio.sleep(1)
await ws.send_text(json.dumps({"type": "close", "code": 200, "msg": ""}, ensure_ascii=False))
await ws.close()
logger.debug("streaming chat temporary websocket 连接断开")
#---------------------------------------------------------------------------------------------------
# 持续流式聊天
async def streaming_chat_lasting_handler(ws, db, redis):
print("Websocket连接成功")
while True:
try:
print("等待接受")
data = await asyncio.wait_for(ws.receive_text(), timeout=60)
data_json = json.loads(data)
if data_json["is_close"]:
close_message = {"type": "close", "code": 200, "msg": ""}
await ws.send_text(json.dumps(close_message, ensure_ascii=False))
print("连接关闭")
await asyncio.sleep(0.5)
await ws.close()
return;
except asyncio.TimeoutError:
print("连接超时")
await ws.close()
return;
current_message = "" # 用于存储用户消息
response_type = RESPONSE_TEXT # 用于获取返回类型
session_id = ""
if Config.STRAM_CHAT.ASR == "LOCAL":
try:
while True:
if data_json["text"]: # 若文字输入不为空,则表示该输入为文字输入
if data_json["meta_info"]["voice_synthesize"]:
response_type = RESPONSE_AUDIO # 查看voice_synthesize判断返回类型
session_id = data_json["meta_info"]["session_id"]
current_message = data_json['text']
break
if not data_json['meta_info']['is_end']: # 还在发
asr_result = asr.streaming_recognize(data_json["audio"])
current_message += ''.join(asr_result['text'])
else: # 发完了
asr_result = asr.streaming_recognize(data_json["audio"], is_end=True)
session_id = data_json["meta_info"]["session_id"]
current_message += ''.join(asr_result['text'])
if data_json["meta_info"]["voice_synthesize"]:
response_type = RESPONSE_AUDIO # 查看voice_synthesize判断返回类型
break
data_json = json.loads(await ws.receive_text())
except Exception as e:
error_info = f"接收用户消息错误: {str(e)}"
error_message = {"type": "error", "code": "500", "msg": error_info}
logger.error(error_info)
await ws.send_text(json.dumps(error_message, ensure_ascii=False))
await ws.close()
return
elif Config.STRAM_CHAT.ASR == "REMOTE":
error_info = f"远程ASR服务暂未开通"
error_message = {"type": "error", "code": "500", "msg": error_info}
logger.error(error_info)
await ws.send_text(json.dumps(error_message, ensure_ascii=False))
await ws.close()
return
print(f"接收到用户消息: {current_message}")
# 查询Session记录
session_content_str = ""
if redis.exists(session_id):
session_content_str = redis.get(session_id)
else:
session_db = db.query(Session).filter(Session.id == session_id).first()
if not session_db:
error_info = f"未找到session记录: {str(e)}"
error_message = {"type": "error", "code": 500, "msg": error_info}
logger.error(error_info)
await ws.send_text(json.dumps(error_message, ensure_ascii=False))
await ws.close()
return
session_content_str = session_db.content
session_content = json.loads(session_content_str)
llm_info = json.loads(session_content["llm_info"])
tts_info = json.loads(session_content["tts_info"])
user_info = json.loads(session_content["user_info"])
messages = json.loads(session_content["messages"])
messages.append({'role': 'user', "content": current_message})
token_count = session_content["token"]
try:
payload = json.dumps({
"model": llm_info["model"],
"stream": True,
"messages": messages,
"tool_choice": "auto",
"max_tokens": 10000,
"temperature": llm_info["temperature"],
"top_p": llm_info["top_p"]
})
headers = {
'Authorization': f"Bearer {Config.MINIMAX_LLM.API_KEY}",
'Content-Type': 'application/json'
}
response = requests.request("POST", Config.MINIMAX_LLM.URL, headers=headers, data=payload, stream=True)
except Exception as e:
error_info = f"发送信息给大模型时发生错误: {str(e)}"
error_message = {"type": "error", "code": 500, "msg": error_info}
logger.error(error_info)
await ws.send_text(json.dumps(error_message, ensure_ascii=False))
await ws.close()
return
def split_string_with_punctuation(text):
punctuations = "!?。"
result = []
current_sentence = ""
for char in text:
current_sentence += char
if char in punctuations:
result.append(current_sentence)
current_sentence = ""
# 判断最后一个字符是否为标点符号
if current_sentence and current_sentence[-1] not in punctuations:
# 如果最后一段不以标点符号结尾,则加入拆分数组
result.append(current_sentence)
return result
llm_response = ""
response_buf = ""
try:
if Config.STRAM_CHAT.TTS == "LOCAL":
if response.status_code == 200:
for chunk in response.iter_lines():
if chunk:
if response_type == RESPONSE_AUDIO:
chunk_data = parseChunkDelta(chunk)
llm_response += chunk_data
response_buf += chunk_data
split_buf = split_string_with_punctuation(response_buf)
response_buf = ""
if len(split_buf) != 0:
for sentence in split_buf:
sr, audio = tts.synthesize(sentence, tts_info["language"], tts_info["speaker_id"], tts_info["noise_scale"], tts_info["noise_scale_w"], tts_info["length_scale"], return_bytes=True)
text_response = {"type": "text", "code": 200, "msg": sentence}
await ws.send_text(json.dumps(text_response, ensure_ascii=False)) # 返回文本数据
await ws.send_bytes(audio) # 返回音频二进制流数据
if response_type == RESPONSE_TEXT:
chunk_data = parseChunkDelta(chunk)
llm_response += chunk_data
text_response = {"type": "text", "code": 200, "msg": chunk_data}
await ws.send_text(json.dumps(text_response, ensure_ascii=False)) # 返回文本数据
elif Config.STRAM_CHAT.TTS == "REMOTE":
error_info = f"暂不支持远程音频合成"
error_message = {"type": "error", "code": 500, "msg": error_info}
logger.error(error_info)
await ws.send_text(json.dumps(error_message, ensure_ascii=False))
await ws.close()
return
end_response = {"type": "end", "code": 200, "msg": ""}
await ws.send_text(json.dumps(end_response, ensure_ascii=False)) # 单次返回结束
print(f"llm消息: {llm_response}")
except Exception as e:
error_info = f"音频合成与向前端返回时错误: {str(e)}"
error_message = {"type": "error", "code": 500, "msg": error_info}
logger.error(error_info)
await ws.send_text(json.dumps(error_message, ensure_ascii=False))
await ws.close()
return
try:
messages.append({'role': 'assistant', "content": llm_response})
token_count += len(llm_response)
session_content["messages"] = json.dumps(messages, ensure_ascii=False)
session_content["token"] = token_count
redis.set(session_id, json.dumps(session_content, ensure_ascii=False))
except Exception as e:
error_info = f"更新session时错误: {str(e)}"
error_message = {"type": "error", "code": 500, "msg": error_info}
logger.error(error_info)
await ws.send_text(json.dumps(error_message, ensure_ascii=False))
await ws.close()
return
print("处理完毕")
#--------------------------------语音通话接口--------------------------------------
#音频数据生产函数
async def voice_call_audio_producer(ws,audio_queue,future,shutdown_event):
logger.debug("音频数据生产函数启动")
is_future_done = False
while not shutdown_event.is_set():
voice_call_data_json = json.loads(await ws.receive_text())
if not is_future_done: #在第一次循环中读取session_id
future.set_result(voice_call_data_json['meta_info']['session_id'])
is_future_done = True
if voice_call_data_json["is_close"]:
shutdown_event.set()
break
else:
await audio_queue.put(voice_call_data_json["audio"]) #将音频数据存入audio_q
#音频数据消费函数
async def voice_call_audio_consumer(audio_q,asr_result_q,shutdown_event):
logger.debug("音频数据消费者函数启动")
vad = VAD()
current_message = ""
vad_count = 0
while not (shutdown_event.is_set() and audio_q.empty()):
audio_data = await audio_q.get()
if vad.is_speech(audio_data):
if vad_count > 0:
vad_count -= 1
asr_result = asr.streaming_recognize(audio_data)
current_message += ''.join(asr_result['text'])
else:
vad_count += 1
if vad_count >= 25: #连续25帧没有语音,则认为说完了
asr_result = asr.streaming_recognize(audio_data, is_end=True)
if current_message:
logger.debug(f"检测到静默,用户输入为:{current_message}")
await asr_result_q.put(current_message)
current_message = ""
vad_count = 0
#asr结果消费以及llm返回生产函数
async def voice_call_llm_handler(session_id,llm_info,redis,db,asr_result_q,llm_response_q,shutdown_event):
logger.debug("asr结果消费以及llm返回生产函数启动")
while not (shutdown_event.is_set() and asr_result_q.empty()):
session_content = get_session_content(session_id,redis,db)
messages = json.loads(session_content["messages"])
current_message = await asr_result_q.get()
messages.append({'role': 'user', "content": current_message})
payload = json.dumps({
"model": llm_info["model"],
"stream": True,
"messages": messages,
"max_tokens":10000,
"temperature": llm_info["temperature"],
"top_p": llm_info["top_p"]
})
headers = {
'Authorization': f"Bearer {Config.MINIMAX_LLM.API_KEY}",
'Content-Type': 'application/json'
}
response = requests.request("POST", Config.MINIMAX_LLM.URL, headers=headers, data=payload, stream=True)
if response.status_code == 200:
for chunk in response.iter_lines():
if chunk:
chunk_data =parseChunkDelta(chunk)
llm_frame = {'message':chunk_data,'is_end':False}
await llm_response_q.put(llm_frame)
llm_frame = {'message':"",'is_end':True}
await llm_response_q.put(llm_frame)
#llm结果返回函数
async def voice_call_llm_response_consumer(session_id,redis,db,llm_response_q,split_result_q,shutdown_event):
logger.debug("llm结果返回函数启动")
llm_response = ""
current_sentence = ""
is_first = True
while not (shutdown_event.is_set() and llm_response_q.empty()):
llm_frame = await llm_response_q.get()
llm_response += llm_frame['message']
sentences,current_sentence,is_first = split_string_with_punctuation(current_sentence,llm_frame['message'],is_first)
for sentence in sentences:
await split_result_q.put(sentence)
if llm_frame['is_end']:
is_first = True
session_content = get_session_content(session_id,redis,db)
messages = json.loads(session_content["messages"])
messages.append({'role': 'assistant', "content": llm_response})
session_content["messages"] = json.dumps(messages,ensure_ascii=False) #更新对话
redis.set(session_id,json.dumps(session_content,ensure_ascii=False)) #更新session
logger.debug(f"llm返回结果: {llm_response}")
llm_response = ""
current_sentence = ""
#语音合成及返回函数
async def voice_call_tts_handler(ws,tts_info,split_result_q,shutdown_event):
logger.debug("语音合成及返回函数启动")
while not (shutdown_event.is_set() and split_result_q.empty()):
sentence = await split_result_q.get()
sr,audio = tts.synthesize(sentence, tts_info["language"], tts_info["speaker_id"], tts_info["noise_scale"], tts_info["noise_scale_w"], tts_info["length_scale"], return_bytes=True)
text_response = {"type": "text", "code": 200, "msg": sentence}
await ws.send_bytes(audio) #返回音频二进制流数据
await ws.send_text(json.dumps(text_response, ensure_ascii=False)) #返回文本数据
logger.debug(f"websocket返回:{sentence}")
asyncio.sleep(0.5)
await ws.close()
async def voice_call_handler(ws, db, redis):
logger.debug("voice_call websocket 连接建立")
audio_q = asyncio.Queue()
asr_result_q = asyncio.Queue()
llm_response_q = asyncio.Queue()
split_result_q = asyncio.Queue()
shutdown_event = asyncio.Event()
future = asyncio.Future()
asyncio.create_task(voice_call_audio_producer(ws,audio_q,future,shutdown_event)) #创建音频数据生产者
asyncio.create_task(voice_call_audio_consumer(audio_q,asr_result_q,shutdown_event)) #创建音频数据消费者
#获取session内容
session_id = await future #获取session_id
tts_info = json.loads(get_session_content(session_id,redis,db)["tts_info"])
llm_info = json.loads(get_session_content(session_id,redis,db)["llm_info"])
asyncio.create_task(voice_call_llm_handler(session_id,llm_info,redis,db,asr_result_q,llm_response_q,shutdown_event)) #创建llm处理者
asyncio.create_task(voice_call_llm_response_consumer(session_id,redis,db,llm_response_q,split_result_q,shutdown_event)) #创建llm断句结果
asyncio.create_task(voice_call_tts_handler(ws,tts_info,split_result_q,shutdown_event)) #返回tts音频结果
while not shutdown_event.is_set():
await asyncio.sleep(5)
await ws.close()
logger.debug("voice_call websocket 连接断开")
#------------------------------------------------------------------------------------------
+13
View File
@@ -0,0 +1,13 @@
#聊天类型:文本、语音、不确定
CHAT_TEXT = 0
CHAT_AUDIO = 1
CHAT_UNCERTAIN = -1
#流式传输帧类型:第一帧、中间帧、最后帧
FIRST_FRAME = 1
CONTINUE_FRAME =2
LAST_FRAME =3
#响应类型:文本、语音
RESPONSE_TEXT = 0
RESPONSE_AUDIO = 1
+79
View File
@@ -0,0 +1,79 @@
from ..schemas.session import *
from ..dependencies.logger import get_logger
from fastapi import HTTPException, status
from ..models import Session
from ..models import UserCharacter
from datetime import datetime
import json
#依赖注入获取logger
logger = get_logger()
#获取SessionID
async def get_session_id_handler(user_id: int, character_id:int, db):
try:
user_character_record = db.query(UserCharacter).filter(UserCharacter.user_id == user_id, UserCharacter.character_id == character_id).first()
except Exception as e:
db.rollback()
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
if not user_character_record:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User Character not found")
try:
session_id = db.query(Session).filter(Session.user_character_id==user_character_record.id).first().id
except Exception as e:
db.rollback()
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
session_id_query_data = SessionIdQueryData(session_id=session_id)
return SessionIdQueryResponse(status="success",message="Session ID 获取成功",data=session_id_query_data)
#查询Session信息
async def get_session_handler(session_id: int, db, redis):
session_str = ""
if redis.exists(session_id):
session_str = redis.get(session_id)
else:
try:
session_str = db.query(Session).filter(Session.id == session_id).first().content
except Exception as e:
db.rollback()
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
redis.set(session_id, session_str)
if not session_str:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Session not found")
session = json.loads(session_str)
session_query_data = SessionQueryData(user_id=session["user_id"], messages=session["messages"],user_info=session["user_info"],tts_info=session["tts_info"],llm_info=session["llm_info"],token=session["token"])
return SessionQueryResponse(status="success",message="Session 查询成功",data=session_query_data)
#更新Sessino信息
async def update_session_handler(session_id, session_data:SessionUpdateRequest, db, redis):
existing_session = ""
if redis.exists(session_id):
existing_session = redis.get(session_id)
else:
existing_session = db.query(Session).filter(Session.id == session_id).first().content
if not existing_session:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Session not found")
#更新Session字段
session = json.loads(existing_session)
session["user_id"] = session_data.user_id
session["messages"] = session_data.messages
session["user_info"] = session_data.user_info
session["tts_info"] = session_data.tts_info
session["llm_info"] = session_data.llm_info
session["token"] = session_data.token
#存储Session
session_str = json.dumps(session,ensure_ascii=False)
redis.set(session_id, session_str)
try:
db.query(Session).filter(Session.id == session_id).update({"content": session_str})
db.commit()
except Exception as e:
db.rollback()
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
session_update_data = SessionUpdateData(updatedAt=datetime.now().isoformat())
return SessionUpdateResponse(status="success",message="Session 更新成功",data=session_update_data)
+159
View File
@@ -0,0 +1,159 @@
from ..schemas.user import *
from ..dependencies.logger import get_logger
from ..models import User, Hardware
from datetime import datetime
from sqlalchemy.orm import Session
from fastapi import HTTPException, status
#依赖注入获取logger
logger = get_logger()
#创建用户
async def create_user_handler(user:UserCrateRequest, db: Session):
new_user = User(created_at=datetime.now(), open_id=user.open_id, username=user.username, avatar_id=user.avatar_id, tags=user.tags, persona=user.persona)
try:
db.add(new_user)
db.commit()
db.refresh(new_user)
except Exception as e:
db.rollback()
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
user_create_data = UserCrateData(user_id=new_user.id, createdAt=new_user.created_at.isoformat())
return UserCrateResponse(status="success", message="创建用户成功", data=user_create_data)
#更新用户信息
async def update_user_handler(user_id:int, user:UserUpdateRequest, db: Session):
existing_user = db.query(User).filter(User.id == user_id).first()
if existing_user is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="用户不存在")
existing_user.open_id = user.open_id
existing_user.username = user.username
existing_user.avatar_id = user.avatar_id
existing_user.tags = user.tags
existing_user.persona = user.persona
try:
db.add(existing_user)
db.commit()
db.refresh(existing_user)
except Exception as e:
db.rollback()
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
user_update_data = UserUpdateData(updatedAt=datetime.now().isoformat())
return UserUpdateResponse(status="success", message="更新用户信息成功", data=user_update_data)
#查询用户信息
async def get_user_handler(user_id:int, db: Session):
try:
existing_user = db.query(User).filter(User.id == user_id).first()
except Exception as e:
db.rollback()
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
if existing_user is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="用户不存在")
user_query_data = UserQueryData(open_id=existing_user.open_id, username=existing_user.username, avatar_id=existing_user.avatar_id, tags=existing_user.tags, persona=existing_user.persona)
return UserQueryResponse(status="success", message="查询用户信息成功", data=user_query_data)
#删除用户
async def delete_user_handler(user_id:int, db: Session):
try:
existing_user = db.query(User).filter(User.id == user_id).first()
except Exception as e:
db.rollback()
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
if existing_user is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="用户不存在")
try:
db.delete(existing_user)
db.commit()
except Exception as e:
db.rollback()
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
user_delete_data = UserDeleteData(deletedAt=datetime.now().isoformat())
return UserDeleteResponse(status="success", message="删除用户成功", data=user_delete_data)
#绑定硬件
async def bind_hardware_handler(hardware, db: Session):
new_hardware = Hardware(mac=hardware.mac, user_id=hardware.user_id, firmware=hardware.firmware, model=hardware.model)
try:
db.add(new_hardware)
db.commit()
db.refresh(new_hardware)
except Exception as e:
db.rollback()
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
hardware_bind_data = HardwareBindData(hardware_id=new_hardware.id, bindedAt=datetime.now().isoformat())
return HardwareBindResponse(status="success", message="绑定硬件成功", data=hardware_bind_data)
#解绑硬件
async def unbind_hardware_handler(hardware_id:int, db: Session):
try:
existing_hardware = db.query(Hardware).filter(Hardware.id == hardware_id).first()
except Exception as e:
db.rollback()
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
if existing_hardware is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="硬件不存在")
try:
db.delete(existing_hardware)
db.commit()
except Exception as e:
db.rollback()
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
hardware_unbind_data = HardwareUnbindData(unbindedAt=datetime.now().isoformat())
return HardwareUnbindResponse(status="success", message="解绑硬件成功", data=hardware_unbind_data)
#硬件换绑
async def change_bind_hardware_handler(hardware_id, user, db):
try:
existing_hardware = db.query(Hardware).filter(Hardware.id == hardware_id).first()
if existing_hardware is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="硬件不存在")
existing_hardware.user_id = user.user_id
db.add(existing_hardware)
db.commit()
db.refresh(existing_hardware)
except Exception as e:
db.rollback()
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
hardware_change_bind_data = HardwareChangeBindData(bindChangedAt=datetime.now().isoformat())
return HardwareChangeBindResponse(status="success", message="硬件换绑成功", data=hardware_change_bind_data)
#硬件信息更新
async def update_hardware_handler(hardware_id, hardware, db):
try:
existing_hardware = db.query(Hardware).filter(Hardware.id == hardware_id).first()
if existing_hardware is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="硬件不存在")
existing_hardware.mac = hardware.mac
existing_hardware.firmware = hardware.firmware
existing_hardware.model = hardware.model
db.add(existing_hardware)
db.commit()
db.refresh(existing_hardware)
except Exception as e:
db.rollback()
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
hardware_update_data = HardwareUpdateData(updatedAt=datetime.now().isoformat())
return HardwareUpdateResponse(status="success", message="硬件信息更新成功", data=hardware_update_data)
#查询硬件
async def get_hardware_handler(hardware_id, db):
try:
existing_hardware = db.query(Hardware).filter(Hardware.id == hardware_id).first()
except Exception as e:
db.rollback()
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
if existing_hardware is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="硬件不存在")
hardware_query_data = HardwareQueryData(mac=existing_hardware.mac, user_id=existing_hardware.user_id, firmware=existing_hardware.firmware, model=existing_hardware.model)
return HardwareQueryResponse(status="success", message="查询硬件信息成功", data=hardware_query_data)
+1
View File
@@ -0,0 +1 @@
from . import *
+15
View File
@@ -0,0 +1,15 @@
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from config import get_config
Config = get_config()
LocalSession = sessionmaker(autocommit=False, autoflush=False, bind=create_engine(Config.SQLALCHEMY_DATABASE_URI))
#返回一个数据库连接
def get_db():
db = LocalSession()
try:
yield db
finally:
db.close()
+27
View File
@@ -0,0 +1,27 @@
import logging
from config import get_config
#获取配置信息
Config = get_config()
#日志类
class Logger:
def __init__(self):
self.logger = logging.getLogger(__name__)
self.logger.setLevel(Config.LOG_LEVEL)
self.logger.propagate = False
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
if not self.logger.handlers: # 检查是否已经有处理器
# 输出到控制台
console_handler = logging.StreamHandler()
console_handler.setFormatter(formatter)
self.logger.addHandler(console_handler)
# 输出到文件
file_handler = logging.FileHandler('app.log')
file_handler.setFormatter(formatter)
self.logger.addHandler(file_handler)
def get_logger():
return Logger().logger
+8
View File
@@ -0,0 +1,8 @@
import redis
from config import get_config
#获取配置信息
Config = get_config()
def get_redis():
return redis.Redis.from_url(Config.REDIS_URL)
View File
Whitespace-only changes.
+6
View File
@@ -0,0 +1,6 @@
from app import app
import uvicorn
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=7878)
+1
View File
@@ -0,0 +1 @@
from .models import *
+82
View File
@@ -0,0 +1,82 @@
from sqlalchemy import Column, Integer, String, JSON, Text, ForeignKey, DateTime, Boolean, CHAR
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
#角色表定义
class Character(Base):
__tablename__ = 'character'
id = Column(Integer, primary_key=True, autoincrement=True)
voice_id = Column(Integer, nullable=False)
avatar_id = Column(String(36), nullable=False)
background_ids = Column(String(255), nullable=False)
name = Column(String(36), nullable=False)
wakeup_words = Column(String(255), nullable=False)
world_scenario = Column(Text, nullable=False)
description = Column(Text, nullable=False)
emojis = Column(JSON, nullable=False)
dialogues = Column(Text, nullable=False)
def __repr__(self):
return f"<Character(id={self.id}, name={self.name}, avatar_id={self.avatar_id})>"
#用户表定义
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True, autoincrement=True)
created_at = Column(DateTime, nullable=True)
updated_at = Column(DateTime, nullable=True)
deleted_at = Column(DateTime, nullable=True)
open_id = Column(String(255), nullable=True)
username = Column(String(64), nullable=True)
avatar_id = Column(String(36), nullable=True)
tags = Column(JSON)
persona = Column(JSON)
def __repr__(self):
return f"<User(id={self.id}, tags={self.tags})>"
#硬件表定义
class Hardware(Base):
__tablename__ = 'hardware'
id = Column(Integer, primary_key=True, autoincrement=True)
user_id = Column(Integer, ForeignKey('user.id'))
mac = Column(String(17))
firmware = Column(String(16))
model = Column(String(36))
def __repr__(self):
return f"<Hardware( mac={self.mac})>"
#用户角色表定义
class UserCharacter(Base):
__tablename__ = 'user_character'
id = Column(Integer, primary_key=True, autoincrement=True)
user_id = Column(Integer, ForeignKey('user.id'))
character_id = Column(Integer, ForeignKey('character.id'))
persona = Column(JSON)
def __repr__(self):
return f"<UserCharacter(id={self.id}, user_id={self.user_id}, character_id={self.character_id})>"
#Session表定义
class Session(Base):
__tablename__ = 'session'
id = Column(CHAR(36), primary_key=True)
user_character_id = Column(Integer, ForeignKey('user_character.id'))
content = Column(Text)
last_activity = Column(DateTime())
is_permanent = Column(Boolean)
def __repr__(self):
return f"<Session(id={self.id}, user_character_id={self.user_character_id})>"
+1
View File
@@ -0,0 +1 @@
from . import *
+35
View File
@@ -0,0 +1,35 @@
from fastapi import APIRouter, HTTPException, status
from ..controllers.character import *
from fastapi import Depends
from sqlalchemy.orm import Session
from ..dependencies.database import get_db
router = APIRouter()
#角色创建接口
@router.post("/characters",response_model=CharacterCreateResponse)
async def create_character(character:CharacterCreateRequest, db: Session = Depends(get_db)):
response = await create_character_handler(character, db)
return response
#用户更新接口
@router.put("/characters/{character_id}",response_model=CharacterUpdateResponse)
async def update_character(character_id:int,character:CharacterUpdateRequest, db: Session = Depends(get_db)):
response = await update_character_handler(character_id, character, db)
return response
#角色删除接口
@router.delete("/characters/{character_id}", response_model=CharacterDeleteResponse)
async def delete_character(character_id: int, db: Session = Depends(get_db)):
response = await delete_character_handler(character_id, db)
return response
#角色查询接口
@router.get("/characters/{character_id}",response_model=CharacterQueryResponse)
async def get_character(character_id: int, db: Session = Depends(get_db)):
response = await get_character_handler(character_id, db)
return response
+48
View File
@@ -0,0 +1,48 @@
from fastapi import APIRouter, HTTPException, status, WebSocket
from ..controllers.chat import *
from fastapi import Depends
from ..dependencies.database import get_db
from ..dependencies.redis import get_redis
router = APIRouter()
#创建新聊天接口
@router.post("/chats", response_model=ChatCreateResponse)
async def create_chat(chat: ChatCreateRequest, db=Depends(get_db), redis=Depends(get_redis)):
response = await create_chat_handler(chat, db, redis)
return response
#删除聊天接口
@router.delete("/chats/{user_character_id}", response_model=ChatDeleteResponse)
async def delete_chat(user_character_id: int, db=Depends(get_db), redis=Depends(get_redis)):
response = await delete_chat_handler(user_character_id, db, redis)
return response
#非流式聊天
@router.post("/chats/non-streaming", response_model=ChatNonStreamResponse)
async def non_streaming_chat(chat: ChatNonStreamRequest,db=Depends(get_db), redis=Depends(get_redis)):
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN,detail="this api is not available")
response = await non_streaming_chat_handler(chat, db, redis)
return response
#流式聊天_单次
@router.websocket("/chat/streaming/temporary")
async def streaming_chat(ws: WebSocket,db=Depends(get_db), redis=Depends(get_redis)):
await ws.accept()
await streaming_chat_temporary_handler(ws,db,redis)
#流式聊天_持续
@router.websocket("/chat/streaming/lasting")
async def streaming_chat(ws: WebSocket,db=Depends(get_db), redis=Depends(get_redis)):
await ws.accept()
await streaming_chat_lasting_handler(ws,db,redis)
#语音通话
@router.websocket("/chat/voice_call")
async def voice_chat(ws: WebSocket,db=Depends(get_db), redis=Depends(get_redis)):
await ws.accept()
await voice_call_handler(ws,db,redis)
+29
View File
@@ -0,0 +1,29 @@
from fastapi import APIRouter, Query, HTTPException, status
from ..controllers.session import *
from fastapi import Depends
from ..dependencies.database import get_db
from ..dependencies.redis import get_redis
router = APIRouter()
#session_id查询接口
@router.get("/sessions", response_model=SessionIdQueryResponse)
async def get_session_id(user_id: int=Query(..., description="用户id"), character_id: int=Query(..., description="角色id"),db=Depends(get_db)):
response = await get_session_id_handler(user_id, character_id, db)
return response
#session查询接口
@router.get("/sessions/{session_id}", response_model=SessionQueryResponse)
async def get_session(session_id: str, db=Depends(get_db), redis=Depends(get_redis)):
response = await get_session_handler(session_id, db, redis)
return response
#session更新接口
@router.put("/sessions/{session_id}", response_model=SessionUpdateResponse)
async def update_session(session_id: str, session_data: SessionUpdateRequest, db=Depends(get_db), redis=Depends(get_redis)):
response = await update_session_handler(session_id, session_data, db, redis)
return response
+71
View File
@@ -0,0 +1,71 @@
from fastapi import APIRouter, HTTPException, status
from ..controllers.user import *
from fastapi import Depends
from sqlalchemy.orm import Session
from ..dependencies.database import get_db
router = APIRouter()
#角色创建接口
@router.post('/users', response_model=UserCrateResponse)
async def create_user(user: UserCrateRequest,db: Session = Depends(get_db)):
response = await create_user_handler(user,db)
return response
#角色更新接口
@router.put('/users/{user_id}', response_model=UserUpdateResponse)
async def update_user(user_id: int, user: UserUpdateRequest, db: Session = Depends(get_db)):
response = await update_user_handler(user_id, user, db)
return response
#角色删除接口
@router.delete('/users/{user_id}', response_model=UserDeleteResponse)
async def delete_user(user_id: int, db: Session = Depends(get_db)):
response = await delete_user_handler(user_id, db)
return response
#角色查询接口
@router.get('/users/{user_id}', response_model=UserQueryResponse)
async def get_user(user_id: int, db: Session = Depends(get_db)):
response = await get_user_handler(user_id, db)
return response
#硬件绑定接口
@router.post('/users/hardware',response_model=HardwareBindResponse)
async def bind_hardware(hardware: HardwareBindRequest, db: Session = Depends(get_db)):
response = await bind_hardware_handler(hardware, db)
return response
#硬件解绑接口
@router.delete('/users/hardware/{hardware_id}',response_model=HardwareUnbindResponse)
async def unbind_hardware(hardware_id: int, db: Session = Depends(get_db)):
response = await unbind_hardware_handler(hardware_id, db)
return response
#硬件换绑
@router.put('/users/hardware/{hardware_id}/bindchange',response_model=HardwareChangeBindResponse)
async def change_bind_hardware(hardware_id: int, user: HardwareChangeBindRequest, db: Session = Depends(get_db)):
response = await change_bind_hardware_handler(hardware_id, user, db)
return response
#硬件信息更新
@router.put('/users/hardware/{hardware_id}/info',response_model=HardwareUpdateResponse)
async def update_hardware_info(hardware_id: int, hardware: HardwareUpdateRequest, db: Session = Depends(get_db)):
response = await update_hardware_handler(hardware_id, hardware, db)
return response
#硬件查询
@router.get('/users/hardware/{hardware_id}',response_model=HardwareQueryResponse)
async def get_hardware(hardware_id: int, db: Session = Depends(get_db)):
response = await get_hardware_handler(hardware_id, db)
return response
+1
View File
@@ -0,0 +1 @@
from . import *
+6
View File
@@ -0,0 +1,6 @@
from pydantic import BaseModel
class BaseResponse(BaseModel):
status: str
message: str
data: dict
+79
View File
@@ -0,0 +1,79 @@
from pydantic import BaseModel
from typing import Optional
from .base import BaseResponse
#---------------------------角色创建-----------------------------
#角色创建请求类
class CharacterCreateRequest(BaseModel):
voice_id:int
avatar_id:str
background_ids:str
name:str
wakeup_words:str
world_scenario:str
description:str
emojis:str
dialogues:str
#角色创建返回类
class CharacterCreateData(BaseModel):
character_id:int
createdAt:str
#角色创建响应类
class CharacterCreateResponse(BaseResponse):
data: Optional[CharacterCreateData]
#----------------------------------------------------------------
#---------------------------角色更新------------------------------
#角色更新请求类
class CharacterUpdateRequest(BaseModel):
voice_id:int
avatar_id:str
background_ids:str
name:str
wakeup_words:str
world_scenario:str
description:str
emojis:str
dialogues:str
#角色更新返回类
class CharacterUpdateData(BaseModel):
updatedAt:str
#角色更新响应类
class CharacterUpdateResponse(BaseResponse):
data: Optional[CharacterUpdateData]
#------------------------------------------------------------------
#---------------------------角色查询--------------------------------
#角色查询返回类
class CharacterQueryData(BaseModel):
voice_id:int
avatar_id:str
background_ids:str
name:str
wakeup_words:str
world_scenario:str
description:str
emojis:str
dialogues:str
#角色查询响应类
class CharacterQueryResponse(BaseResponse):
data: Optional[CharacterQueryData]
#------------------------------------------------------------------
#---------------------------角色删除--------------------------------
#角色删除返回类
class CharacterDeleteData(BaseModel):
deletedAt:str
#角色删除响应类
class CharacterDeleteResponse(BaseResponse):
data: Optional[CharacterDeleteData]
#-------------------------------------------------------------------
+49
View File
@@ -0,0 +1,49 @@
from pydantic import BaseModel
from typing import Optional
from .base import BaseResponse
#--------------------------------新聊天创建--------------------------------
#创建新聊天请求类
class ChatCreateRequest(BaseModel):
user_id: int
character_id: int
#创建新聊天返回类
class ChatCreateData(BaseModel):
user_character_id: int
session_id: str
createdAt: str
#创建新聊天相应类
class ChatCreateResponse(BaseResponse):
data: Optional[ChatCreateData]
#--------------------------------------------------------------------------
#----------------------------------聊天删除--------------------------------
#删除聊天返回类
class ChatDeleteData(BaseModel):
deletedAt: str
#创建新聊天相应类
class ChatDeleteResponse(BaseResponse):
data: Optional[ChatDeleteData]
#--------------------------------------------------------------------------
#-----------------------------------非流式聊天------------------------------
#非流式聊天请求类
class ChatNonStreamRequest(BaseModel):
format: str
rate: int
session_id: str
speech:str
#非流式聊天返回类
class ChatNonStreamData(BaseModel):
audio_url: str
#非流式聊天相应类
class ChatNonStreamResponse(BaseResponse):
data: Optional[ChatNonStreamData]
#--------------------------------------------------------------------------
+58
View File
@@ -0,0 +1,58 @@
from pydantic import BaseModel
from typing import List
from typing import Optional
from .base import BaseResponse
#----------------------------Session_id查询------------------------------
#session_id查询请求类
class SessionIdQueryRequest(BaseModel):
user_id: int
character_id: int
#session_id查询返回类
class SessionIdQueryData(BaseModel):
session_id: str
#session_id查询响应类
class SessionIdQueryResponse(BaseResponse):
data: Optional[SessionIdQueryData]
#-------------------------------------------------------------------------
#----------------------------Session会话查询-------------------------------
#session会话查询请求类
class SessionQueryRequest(BaseModel):
user_id: int
class SessionQueryData(BaseModel):
user_id: int
messages: str
user_info: str
tts_info: str
llm_info: str
token: int
#session会话查询响应类
class SessionQueryResponse(BaseResponse):
data: Optional[SessionQueryData]
#-------------------------------------------------------------------------
#-------------------------------Session修改--------------------------------
#session修改请求类
class SessionUpdateRequest(BaseModel):
user_id: int
messages: str
user_info: str
tts_info: str
llm_info: str
token: int
#session修改返回类
class SessionUpdateData(BaseModel):
updatedAt:str
#session修改响应类
class SessionUpdateResponse(BaseResponse):
data: Optional[SessionUpdateData]
#--------------------------------------------------------------------------
+140
View File
@@ -0,0 +1,140 @@
from pydantic import BaseModel
from typing import Optional
from .base import BaseResponse
#---------------------------------用户创建----------------------------------
#用户创建请求类
class UserCrateRequest(BaseModel):
open_id: str
username: str
avatar_id: str
tags: str
persona: str
#用户创建返回类
class UserCrateData(BaseModel):
user_id : int
createdAt: str
#用户创建响应类
class UserCrateResponse(BaseResponse):
data: Optional[UserCrateData]
#---------------------------------------------------------------------------
#---------------------------------用户更新-----------------------------------
#用户更新请求类
class UserUpdateRequest(BaseModel):
open_id: str
username: str
avatar_id: str
tags: str
persona: str
#用户更新返回类
class UserUpdateData(BaseModel):
updatedAt: str
#用户更新响应类
class UserUpdateResponse(BaseResponse):
data: Optional[UserUpdateData]
#----------------------------------------------------------------------------
#---------------------------------用户查询------------------------------------
#用户查询返回类
class UserQueryData(BaseModel):
open_id: str
username: str
avatar_id: str
tags: str
persona: str
#用户查询响应类
class UserQueryResponse(BaseResponse):
data: Optional[UserQueryData]
#-----------------------------------------------------------------------------
#---------------------------------用户删除------------------------------------
#用户删除返回类
class UserDeleteData(BaseModel):
deletedAt: str
#用户删除响应类
class UserDeleteResponse(BaseResponse):
data: Optional[UserDeleteData]
#-----------------------------------------------------------------------------
#---------------------------------硬件绑定-------------------------------------
class HardwareBindRequest(BaseModel):
mac:str
user_id:int
firmware:str
model:str
class HardwareBindData(BaseModel):
hardware_id: int
bindedAt: str
class HardwareBindResponse(BaseResponse):
data: Optional[HardwareBindData]
#-----------------------------------------------------------------------------
#---------------------------------硬件解绑-------------------------------------
class HardwareUnbindData(BaseModel):
unbindedAt: str
class HardwareUnbindResponse(BaseResponse):
data: Optional[HardwareUnbindData]
#------------------------------------------------------------------------------
#---------------------------------硬件换绑--------------------------------------
class HardwareChangeBindRequest(BaseModel):
user_id:int
class HardwareChangeBindData(BaseModel):
bindChangedAt: str
class HardwareChangeBindResponse(BaseResponse):
data: Optional[HardwareChangeBindData]
#------------------------------------------------------------------------------
#-------------------------------硬件信息更新------------------------------------
class HardwareUpdateRequest(BaseModel):
mac:str
firmware:str
model:str
class HardwareUpdateData(BaseModel):
updatedAt: str
class HardwareUpdateResponse(BaseResponse):
data: Optional[HardwareUpdateData]
#------------------------------------------------------------------------------
#--------------------------------硬件查询---------------------------------------
class HardwareQueryData(BaseModel):
user_id:int
mac:str
firmware:str
model:str
class HardwareQueryResponse(BaseResponse):
data: Optional[HardwareQueryData]
#------------------------------------------------------------------------------