环境
- python3.7.6、fastapi、websockets9.1
功能说明
- 模拟1对1的客服聊天
- 客户id 聊天记录缓存,关闭窗口后,再次打开相同的客户id,之前聊天记录会再现
代码如下 解释就自己看吧
import uvicorn
from fastapi import FastAPI
from starlette.websockets import WebSocket, WebSocketDisconnect
from fastapi.responses import HTMLResponse
from typing import List
from datetime import datetime
websocket_ip = 'localhost'
app = FastAPI()
class ChatText:
def __init__(self,
chat_src,
chat_text):
"""
:param chat_src: 0-客户端 1-服务端
:param chat_text:
"""
self.chat_src = chat_src
self.chat_text = chat_text
self.timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
class CustomerChatUtils:
def __init__(self,
client_id):
self.client_id = client_id
self.server_websocket = None
self.customer_websocket = None
self.active = False
self.timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
self.chat_message_list: List[ChatText] = []
class CustomerServiceUtils:
def __init__(self):
self.client_ids = []
self.customer_active_connections: List[WebSocket] = []
self.server_active_connections: List[WebSocket] = []
self.customer_chat_obj: List[CustomerChatUtils] = []
async def customer_connect(self, websocket: WebSocket):
await websocket.accept()
self.customer_active_connections.append(websocket)
async def server_connect(self, websocket: WebSocket):
await websocket.accept()
self.server_active_connections.append(websocket)
def customer_disconnect(self, websocket: WebSocket):
self.customer_active_connections.remove(websocket)
for item in self.customer_chat_obj:
if item.customer_websocket == websocket:
item.customer_websocket = None
item.active = False
def server_disconnect(self, websocket: WebSocket):
self.server_active_connections.remove(websocket)
for item in self.customer_chat_obj:
if item.server_websocket == websocket:
item.server_websocket = None
def get_customer_chat_obj(self, client_id) -> CustomerChatUtils:
"""获取历史聊天记录
:param client_id:
:return:
"""
current_chat_message = None
for chat_message in self.customer_chat_obj:
if chat_message.client_id == client_id:
current_chat_message = chat_message
break
if current_chat_message is None:
current_chat_message = CustomerChatUtils(client_id)
self.customer_chat_obj.append(current_chat_message)
return current_chat_message
customer_service_utils = CustomerServiceUtils()
@app.get("/chat/client/{client_id}")
async def chat_client(client_id: int):
html_content = f"""
<!DOCTYPE html>
<html>
<head>
<title>客户端</title>
</head>
<body>
<h1>客户端 Chat</h1>
<form action="" οnsubmit="sendMessage(event)">
<input type="text" id="messageText" autocomplete="off"/>
<button>Send</button>
</form>
<ul id='messages'>
</ul>
<script>
var ws = new WebSocket("ws://{websocket_ip}:8000/ws/customer/{client_id}");
""" + """
ws.onmessage = function(event) {
var messages = document.getElementById('messages')
var message = document.createElement('li')
var content = document.createTextNode(event.data)
message.appendChild(content)
messages.appendChild(message)
};
function sendMessage(event) {
var input = document.getElementById("messageText")
ws.send(input.value)
input.value = ''
event.preventDefault()
}
</script>
</body>
</html>
"""
return HTMLResponse(html_content)
@app.get("/chat/server/{client_id}")
async def chat_server(client_id: int):
html_content = f"""
<!DOCTYPE html>
<html>
<head>
<title>服务端</title>
</head>
<body>
<h1>服务端 Chat</h1>
<form action="" οnsubmit="sendMessage(event)">
<input type="text" id="messageText" autocomplete="off"/>
<button>Send</button>
</form>
<ul id='messages'>
</ul>
<script>
var ws = new WebSocket("ws://{websocket_ip}:8000/ws/server/{client_id}");
""" + """
ws.onmessage = function(event) {
var messages = document.getElementById('messages')
var message = document.createElement('li')
var content = document.createTextNode(event.data)
message.appendChild(content)
messages.appendChild(message)
};
function sendMessage(event) {
var input = document.getElementById("messageText")
ws.send(input.value)
input.value = ''
event.preventDefault()
}
</script>
</body>
</html>
"""
return HTMLResponse(html_content)
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
await websocket.accept()
while True:
data = await websocket.receive_text()
await websocket.send_text(f"Message text was: {data}")
@app.websocket("/ws/customer/{client_id}")
async def websocket_endpoint_customer(websocket: WebSocket, client_id: int):
await customer_service_utils.customer_connect(websocket)
try:
customer_chat_obj = customer_service_utils.get_customer_chat_obj(client_id)
customer_chat_obj.active = True
customer_chat_obj.customer_websocket = websocket
for chat_message in customer_chat_obj.chat_message_list:
if chat_message.chat_src == 0:
await websocket.send_text(f'我 {chat_message.timestamp}: {chat_message.chat_text}')
else:
await websocket.send_text(f'客服 {chat_message.timestamp}: {chat_message.chat_text}')
while True:
data = await websocket.receive_text()
print(f'客户端发送消息:{data}')
_chat_text = ChatText(0, data)
customer_chat_obj.chat_message_list.append(_chat_text)
await websocket.send_text(f"我 {_chat_text.timestamp}: {data}")
if customer_chat_obj.server_websocket is not None:
await customer_chat_obj.server_websocket.send_text(f"客户{client_id}-{_chat_text.timestamp}: {data}")
except WebSocketDisconnect:
customer_service_utils.customer_disconnect(websocket)
@app.websocket("/ws/server/{client_id}")
async def websocket_endpoint_server(websocket: WebSocket, client_id: int):
await customer_service_utils.server_connect(websocket)
try:
customer_chat_obj = customer_service_utils.get_customer_chat_obj(client_id)
if customer_chat_obj.active:
customer_chat_obj.server_websocket = websocket
for chat_message in customer_chat_obj.chat_message_list:
if chat_message.chat_src == 0:
await websocket.send_text(f'客户{client_id}-{chat_message.timestamp}: {chat_message.chat_text}')
else:
await websocket.send_text(f'我 {chat_message.timestamp}: {chat_message.chat_text}')
while True:
data = await websocket.receive_text()
print(f'服务端发送消息:{data}')
_chat_text = ChatText(1, data)
customer_chat_obj.chat_message_list.append(_chat_text)
await websocket.send_text(f"我 {_chat_text.timestamp}: {data}")
if customer_chat_obj.customer_websocket is not None:
await customer_chat_obj.customer_websocket.send_text(
f"客服:{_chat_text.timestamp}: {data}")
else:
await websocket.send_text("非法的client_id")
except WebSocketDisconnect:
customer_service_utils.server_disconnect(websocket)
uvicorn.run(app, host="0.0.0.0", port=8000)
- 客户端链接 http://localhost:8000/chat/client/{client_id}
- 比如client_id 为1: http://localhost:8000/chat/client/1
- 服务端链接 http://localhost:8000/chat/server/{client_id}
- 比如对接客户id为 1 的服务端链接 http://localhost:8000/chat/server/1
客户端截图
服务端截图
如果对你帮助,希望点个赞,谢谢
|