当前位置:   article > 正文

基于FastAPi的websocket 实现 一对一的客服demo

基于fastapi的websocket 实现 一对一的客服demo

环境

  • python3.7.6、fastapi、websockets9.1

功能说明

  • 模拟1对1的客服聊天
  • 客户id 聊天记录缓存,关闭窗口后,再次打开相同的客户id,之前聊天记录会再现
代码如下 解释就自己看吧
# -*- coding:utf-8 -*-
# @FileName  :demo.py
# @Time      :2021/7/26 18:09
# @Author    :Ranger
# @Info      :

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)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 客户端链接 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
客户端截图

image.png

服务端截图

image.png

如果对你帮助,希望点个赞,谢谢
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Guff_9hys/article/detail/863421
推荐阅读
相关标签
  

闽ICP备14008679号