修复并发问题,修复config不更新的问题

This commit is contained in:
Wenjie Zhang 2024-10-14 22:10:56 +08:00
parent 0ff38ffe8c
commit d18a0a1039
7 changed files with 112 additions and 61 deletions

View File

@ -24,5 +24,5 @@ logger = setup_logger("server:main")
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=5000)
uvicorn.run(app, host="0.0.0.0", port=5000, threads=10, workers=10)

View File

@ -16,7 +16,7 @@ async def route_index():
return {"message": "You Got It!"}
@base.get("/config")
async def get_config():
def get_config():
return startup.config
@base.post("/config")
@ -32,7 +32,7 @@ async def restart():
return {"message": "Restarted!"}
@base.get("/log")
async def get_log():
def get_log():
from src.utils.logging_config import LOG_FILE
from collections import deque

View File

@ -1,31 +1,41 @@
from fastapi import APIRouter, HTTPException, Request
from fastapi.responses import StreamingResponse
import time
import uuid
from fastapi import APIRouter, HTTPException, Request, Body
from fastapi.responses import StreamingResponse, Response
from concurrent.futures import ThreadPoolExecutor
import json
import asyncio
from src.core import HistoryManager
from src.core.startup import startup
from src.utils.logging_config import setup_logger
chat = APIRouter(prefix="/chat")
logger = setup_logger("server-chat")
# 创建线程池
executor = ThreadPoolExecutor()
refs_pool = {}
@chat.get("/")
async def chat_get():
return "Chat Get!"
@chat.post("/")
async def chat_post(request: Request):
request_data = await request.json()
query = request_data['query']
meta = request_data.get('meta')
history_manager = HistoryManager(request_data['history'])
def chat_post(
query: str = Body(...),
meta: dict = Body(None),
history: list = Body(...),
cur_res_id: str = Body(...)):
history_manager = HistoryManager(history)
new_query, refs = startup.retriever(query, history_manager.messages, meta)
refs_pool[cur_res_id] = refs
messages = history_manager.get_history_with_msg(new_query, max_rounds=meta.get('history_round'))
history_manager.add_user(query)
logger.debug(f"Web history: {history_manager.messages}")
async def generate_response():
def generate_response():
content = ""
for delta in startup.model.predict(messages, stream=True):
if not delta.content:
@ -36,20 +46,29 @@ async def chat_post(request: Request):
else:
content += delta.content
response_chunk = json.dumps({
"history": history_manager.update_ai(content),
logger.debug(f"Response: {content}")
_chunk = json.dumps({
"response": content,
"refs": refs # TODO: 优化 refs不需要每次都返回
}, ensure_ascii=False).encode('utf8') + b'\n'
yield response_chunk
"history": history_manager.update_ai(content),
}, ensure_ascii=False).encode('utf-8') + b"\n"
yield _chunk
return StreamingResponse(generate_response(), media_type='application/json')
@chat.post("/call")
async def call(request: Request):
request_data = await request.json()
query = request_data['query']
response = startup.model.predict(query)
async def call(query: str = Body(...), meta: dict = Body(None)):
async def predict_async(query):
loop = asyncio.get_event_loop()
return await loop.run_in_executor(executor, startup.model.predict, query)
response = await predict_async(query)
logger.debug({"query": query, "response": response.content})
return {"response": response.content}
return {"response": response.content}
@chat.get("/refs")
def get_refs(cur_res_id: str):
global refs_pool
refs = refs_pool.pop(cur_res_id, None)
return {"refs": refs}

View File

@ -1,7 +1,6 @@
import os
from typing import List, Optional
from fastapi import APIRouter, File, UploadFile, HTTPException, Depends, Body
from pydantic import BaseModel
from src.utils import setup_logger, hashstr
from src.core.startup import startup

View File

@ -16,10 +16,9 @@
</a-tooltip>
</div>
<div class="header__right">
<!-- <div class="nav-btn text metas">
<CompassFilled v-if="meta.use_web" />
<GoldenFilled v-if="meta.use_graph"/>
</div> -->
<div class="nav-btn text metas" v-if="meta.use_graph">
<GoldOutlined /> 图数据库
</div>
<a-dropdown v-if="meta.selectedKB !== null">
<a class="ant-dropdown-link nav-btn" @click.prevent>
<!-- <component :is="meta.selectedKB === null ? BookOutlined : BookFilled" /> -->
@ -147,6 +146,7 @@ import {
BookFilled,
CompassFilled,
GoldenFilled,
GoldOutlined,
SettingOutlined,
SettingFilled,
PlusCircleOutlined,
@ -282,7 +282,6 @@ const scrollToBottom = () => {
}, 10)
}
const generateRandomHash = (length) => {
let chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
let hash = '';
@ -314,14 +313,31 @@ const appendAiMessage = (message, refs=null) => {
const updateMessage = (text, id, refs, status) => {
const message = conv.value.messages.find((message) => message.id === id);
if (message) {
message.refs = refs;
message.status = status;
message.text = text;
message.model_name = refs.model_name
// text
if (text !== null && text !== undefined && text !== '') {
message.text = text;
}
// refs
if (refs !== null && refs !== undefined) {
message.refs = refs;
// refs model_name
if (refs.model_name !== null && refs.model_name !== undefined && refs.model_name !== '') {
message.model_name = refs.model_name;
}
}
// status
if (status !== null && status !== undefined && status !== '') {
message.status = status;
}
} else {
console.error('Message not found');
}
scrollToBottom();
};
@ -380,51 +396,74 @@ const fetchChatResponse = (user_input, cur_res_id) => {
body: JSON.stringify({
query: user_input,
history: conv.value.history,
meta: meta
meta: meta,
cur_res_id: cur_res_id,
}),
headers: {
'Content-Type': 'application/json'
}
}).then((response) => {
})
.then((response) => {
if (!response.body) throw new Error("ReadableStream not supported.");
const reader = response.body.getReader();
const decoder = new TextDecoder();
const decoder = new TextDecoder("utf-8");
let buffer = '';
//
const readChunk = () => {
return reader.read().then(({ done, value }) => {
if (done) {
//
updateStatus(cur_res_id, "finished");
fetchRefs(cur_res_id).then((data) => {
console.log(data)
updateMessage(null, cur_res_id, data, "finished");
updateStatus(cur_res_id, "finished");
})
isStreaming.value = false;
if (conv.value.messages.length === 2) { renameTitle(); }
return; //
return;
}
buffer += decoder.decode(value, { stream: true });
const messages = buffer.trim().split('\n');
messages.forEach((message) => {
try {
const data = JSON.parse(message);
updateMessage(data.response, cur_res_id, data.refs, "loading");
conv.value.history = data.history;
} catch (e) {
// console.error('JSON :', e);
}
});
buffer = ''; //
const chunk = decoder.decode(value, { stream: true });
buffer += chunk;
try {
const data = JSON.parse(chunk);
updateMessage(data.response, cur_res_id, data.refs, "loading");
console.debug(data.response)
conv.value.history = data.history;
} catch (e) {
// console.debug('JSON :', e, chunk);
}
return readChunk(); //
});
};
return readChunk();
isStreaming.value = false;
readChunk();
})
.catch((error) => {
console.error(error);
updateStatus(cur_res_id, "error");
isStreaming.value = false;
})
.finally(() => {
isStreaming.value = false;
});
}
const fetchRefs = (cur_res_id) => {
return new Promise((resolve, reject) => {
fetch(`/api/chat/refs?cur_res_id=${cur_res_id}`, {
method: "GET",
headers: {
"Content-Type": "application/json"
},
}).then(response => response.json())
.then(data => {
resolve(data.refs)
})
.catch((error) => {
reject(error)
})
})
}
// sendMessage

View File

@ -25,20 +25,13 @@
const fetchLogs = async () => {
state.fetching = true;
try {
//
error.value = '';
//
const response = await fetch('/api/log'); // API
const response = await fetch('/api/log');
if (!response.ok) {
throw new Error('Failed to fetch logs');
}
// JSON
const data = await response.json();
// logs
logs.value = data.log;
// DOM

View File

@ -50,6 +50,7 @@ const getRemoteDatabase = () => {
}
onMounted(() => {
getRemoteConfig()
getRemoteDatabase()
configStore.refreshConfig()
})