使用python接入腾讯云DeepSeek

本文主要从提供SSE方式接入DeepSeek,并通过fastapi websocket对外提供接入方法。
参考文档:
腾讯云大模型:https://cloud.tencent.com/document/product/1759/109380
fastAPI官网:https://fastapi.tiangolo.com/

WebSocketManager

提供WebsocketManager对websocket连接实例进行管理,代码片段如下:

from fastapi import WebSocket


class WsManager:
    """
    websocket manager
    """
    connectors: dict[str, WebSocket] = {}

    @staticmethod
    def get_connector(connector_id: str) -> WebSocket | None:
        """
        获取连接实例
        :param connector_id:
        :return:
        """
        connector = WsManager.connectors.get(connector_id)
        return connector

    @staticmethod
    def add_connector(connector_id: str, connector: WebSocket):
        """
        添加websocket客户端
        :param connector_id: 客户端ID
        :param connector: 客户端连接实例
        :return:
        """
        WsManager.connectors[connector_id] = connector

    @staticmethod
    def remove_connector(connector_id: str):
        """
        移除websocket连接
        :param connector_id: 连接ID
        :return:
        """
        try:
            del WsManager.connectors[connector_id]
        except Exception:
            pass

    @staticmethod
    async def send_message(connector_id: str, message: str):
        connector = WsManager.connectors.get(connector_id)
        if connector is None:
            return
        try:
            await connector.send_text(message)
        except Exception as e:
            print('消息发送失败')

    @staticmethod
    async def send_message_json(connector_id: str, message: dict):
        connector = WsManager.connectors.get(connector_id)
        if connector is None:
            return
        try:
            await connector.send_json(message)
        except Exception as e:
            print('消息发送失败')

接入DeepSeek

import uuid
import os
import requests
import json

from src.core.WsManager import WsManager
from .session import get_session

TCLOUD_URL = 'lke.tencentcloudapi.com'
TCLOUD_DeepSeek_SSE_URL = "https://wss.lke.cloud.tencent.com/v1/qbot/chat/sse"

SECRET_ID = "XXXXXXXXXXXXXXXXXXXX"
SECRET_KEY = "XXXXXXXXXXXXXXXXXXXXX"
REGION = "ap-guangzhou"
TYPE = 5


def get_session():
    """
    生成一个 UUID
    :return session id 字符串
    """
    new_uuid = uuid.uuid4()
    # 将 UUID 转换为字符串
    session_id = str(new_uuid)
    return session_id


def _resolve_message(message: str, prev_message: str):
    """
    处理消息
    :param message:
    :param prev_message:
    :return:
    """
    if prev_message == '':
        return None
    if prev_message.startswith("event:"):
        # 生成消息
        message = message.replace("data:", '').strip()
        try:
            message_json = json.loads(message)
            message_type = message_json.get('type')
            payload = message_json.get('payload')
            if message_type == 'token_stat':
                # token统计事件
                return None
            elif message_type == 'thought':
                # 思考事件
                return None
            elif message_type == 'error':
                # 错误事件
                return None
            elif message_type == 'reference':
                # 参考来源事件
                return None
            content = payload.get('content')
            record_id = payload.get('record_id')
            request_id = payload.get('request_id')
            session_id = payload.get('session_id')
            trace_id = payload.get('trace_id')
            message_id = payload.get('message_id')
            return {
                'type': message_type,
                'data': {
                    'content': content,
                    'record_id': record_id,
                    'request_id': request_id,
                    'session_id': session_id,
                    'trace_id': trace_id,
                    'message_id': message_id,
                }
            }
        except Exception as e:
            print(e)
    else:
        return None


async def get_q_a_result(visitor_id: str, question: str):
    """
    获取问答结果
    :param visitor_id: 访客ID
    :param question: 问题内容
    :return: 回答内容
    """
    session_id = get_session()
    req_data = {
        "content": f"{question}",
        "bot_app_key": "XXXXXXXX",  # 可以获取方式见下图
        "visitor_biz_id": visitor_id,
        "session_id": session_id,
        "streaming_throttle": 100
    }
    res = requests.post(TCLOUD_DeepSeek_SSE_URL, data=json.dumps(req_data),
                        stream=True, headers={"Accept": "text/event-stream"})
    prev_message: str = ''  # 上一条消息
    if res.status_code == 200:
        for line in res.iter_lines():
            if line:
                data = line.decode('utf-8')
                message = _resolve_message(data, prev_message)
                if message:
                    await WsManager.send_message_json(visitor_id, message)
                prev_message = data
    else:
        print('Failed to get data. Status code: {response.status_code}')
    # 关闭websocket连接
    connector = WsManager.get_connector(visitor_id)
    if connector:
        await connector.close()
        WsManager.remove_connector(visitor_id)

  1. 进入控制台
    在这里插入图片描述2. 创建应用,并点击调用
    在这里插入图片描述

通过fastapi 以websocket方式对外提供接口

这个接口是,前台连接websocket后,后台直接根据连接参数,开始调用问答,问答结束后自动关闭websocket连接

import asyncio

from fastapi import APIRouter, WebSocket, WebSocketDisconnect, BackgroundTasks
from fastapi.responses import JSONResponse

from src.core.WsManager import WsManager
from src.utils.tcloudLLM import get_example_recommend
from src.utils.session import get_visitor_id

router = APIRouter(prefix="/api/tcloud", tags=['腾信云大模型接口'])


@router.websocket("/ws/{compound_name}")
async def get_exercises_ws(compound_name: str, websocket: WebSocket, background_tasks: BackgroundTasks):
    await websocket.accept()
    visitor_id = get_visitor_id()
    WsManager.add_connector(visitor_id, websocket)
    # 本来使用BackgroundTask去做后台任务,结果不知道什么原因,调用不起来,然后换成asyncio处理
    asyncio.create_task(get_example_recommend(visitor_id, compound_name))  # 创建对应问答任务
    try:
        while True:
            data = await websocket.receive_text()
            await websocket.send_text(f"Message text was: {data}")
    except WebSocketDisconnect:
        WsManager.remove_connector(visitor_id)
    except Exception:
        WsManager.remove_connector(visitor_id)

如果需要进行多轮问答,提供为多次问答设置相关的 request_id 参数进行消息串联。

### 如何在腾讯云服务器部署 DeepSeek R1 模型 #### 准备工作 为了成功部署 DeepSeek-R1 模型,需先完成腾讯云账号的创建并进入 Cloud Studio 环境。Cloud Studio 提供了一个集成开发环境(IDE),允许用户在线编写、编译以及执行代码而无需安装任何软件[^2]。 #### 配置云端环境 一旦登录到 Cloud Studio 平台,在启动项目之前要确保选择了具备 GPU 支持的工作空间配置选项。这一步骤至关重要因为 DeepSeek-R1 的训练和推理过程依赖于强大的计算能力来加速处理速度。对于腾讯云 Cloud Studio 所提供的免费 GPU 资源(16G 显存、32G 内存、8 核 CPU),可以选择适合模型大小的资源配置进行部署[^1]。 #### 获取 DeepSeek-R1 模型文件 获取预训练好的 DeepSeek-R1 模型权重和其他必要的脚本文件是下一步的关键操作。这些资源通常可以从官方 GitHub 仓库或者其他公开渠道下载获得。如果选择的是特定版本比如 `r1:14b` 模型,则应特别注意确认所使用的参数设置与该版本相匹配。 #### 安装依赖库 通过命令行工具安装 Python 及其相关机器学习框架如 PyTorch 或 TensorFlow 是必不可少的操作之一。此外还需要根据具体需求安装其他辅助性的Python包以支持整个项目的正常运作。可以使用 pip 工具来进行批量安装: ```bash pip install torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu113/ ``` 以上命令假设正在使用 CUDA 版本为 cu113 的 PyTorch 库作为例子[^3]。 #### 编写加载和服务化逻辑 最后一步涉及到了解如何将已经准备完毕的 DeepSeek-R1 模型转化为可调用的服务接口。一般情况下会采用 Flask 或 FastAPI 这样的轻量级 Web 框架构建 RESTful API 来实现这一点。下面是一个简单的基于Flask的应用程序实例用于提供预测服务: ```python from flask import Flask, request, jsonify import torch from transformers import AutoModelForCausalLM, AutoTokenizer app = Flask(__name__) model_name_or_path = "path_to_your_model" tokenizer = AutoTokenizer.from_pretrained(model_name_or_path) model = AutoModelForCausalLM.from_pretrained(model_name_or_path) @app.route('/predict', methods=['POST']) def predict(): input_text = request.json.get('text') inputs = tokenizer(input_text, return_tensors="pt").to("cuda") outputs = model.generate(**inputs) result = tokenizer.decode(outputs[0], skip_special_tokens=True) return jsonify({"result": result}) if __name__ == '__main__': app.run(host='0.0.0.0', port=5000) ``` 这段代码展示了怎样接收 HTTP POST 请求中的文本数据并通过已加载的 DeepSeek-R1 模型对其进行编码转换得到最终的结果返回给客户端应用程序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值