适配openai

openai 脚本

  • stream脚本
    import os
    from openai import OpenAIclient = OpenAI(base_url="http://127.0.0.1:9117/api/v1",api_key=os.environ["ACCESS_TOKEN"],
    )stream = client.chat.completions.create(model = "Qwen/Qwen2-7B-Instruct",messages = [{"role": "user","content": "介绍一下自己"}],stream=True,
    )
    for chunk in stream:print(chunk.choices[0].delta.content, end = "")
    
  • api脚本
    import os
    from openai import OpenAIclient = OpenAI(base_url="http://127.0.0.1:9117/api/v1",api_key=os.environ["ACCESS_TOKEN"],
    )response = client.chat.completions.create(model = "Qwen/Qwen2-7B-Instruct",messages = [{"role": "user","content": "介绍一下自己"}],stream=False,
    )
    print(response.choices[0].delta["content"])
    

api/v1/chat/completions实现

  • ChatController
    @RequestMapping("/api/v1/chat")
    public class ChatController {...@PostMapping("/completions")public Object send(@Valid @RequestBody ChatSendStreamReq req) {if (req.isStream()) {return chatService.sendStreamEmitter(req, AuthContextHolderHelper.getUid(), AuthContextHolderHelper.getUsername());}Object result = chatService.call(req, AuthContextHolderHelper.getUid(), AuthContextHolderHelper.getUsername());return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(result);}...
    }
    
  • WebClientConfig
    Configuration
    public class WebClientConfig {@Beanpublic WebClient webClient() throws SSLException {// 配置 SSLContext,信任所有证书SslContext sslContext = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build();HttpClient httpClient = HttpClient.create().secure(ssl -> ssl.sslContext(sslContext));return WebClient.builder().clientConnector(new ReactorClientHttpConnector(httpClient)).build();// return WebClient.builder().build();}
    }
    
  • ChatService
    @Service
    @Slf4j
    public class ChatServiceImpl implements ChatService {...@Overridepublic SseEmitter sendStreamEmitter(ChatSendStreamReq req, String uid, String username) {Map<String, String> headers = buildHeaders(uid, username);String traceId = MDC.get("trace-id");// 0 表示无限超时(直到前端断开)// 0 = 永不超时(不推荐),可以设一个合理值比如 30sSseEmitter emitter = new SseEmitter(1_000L);// 用来保存 WebClient 的订阅对象AtomicReference<Disposable> disposableRef = new AtomicReference<>();// 开新线程处理,避免阻塞Servlet请求线程Executors.newSingleThreadExecutor().submit(() -> {try {setTraceIdToMDC(traceId);log.debug("[sse] SseEmitter创建开始");String url = "https://localhost:8888/api/v1/chat/send_stream";WebClient.RequestHeadersSpec<?> requestSpec = webClient.post().uri(url).accept(MediaType.TEXT_EVENT_STREAM, MediaType.APPLICATION_NDJSON, MediaType.APPLICATION_JSON).body(BodyInserters.fromValue(req)).headers(httpHeaders -> {headers.forEach(httpHeaders::set);httpHeaders.set(HttpHeaders.ACCEPT_CHARSET, StandardCharsets.UTF_8.name());});// 订阅远端 SSE 流// 订阅远端 SSE 流Disposable disposable = requestSpec.retrieve().bodyToFlux(String.class).doOnNext(line -> {setTraceIdToMDC(traceId);try {log.debug("[sse] 收到数据: {}", line);emitter.send(SseEmitter.event().data(line));} catch (IOException e) {log.error("[sse] SSE发送失败: {}", e.getMessage());Disposable d = disposableRef.get();if (d != null && !d.isDisposed()) {d.dispose(); // <- 立即停止 WebClient 流log.info("[sse] WebClient 流已取消");}// emitter.complete();emitter.completeWithError(e);}}).doOnError(error -> {setTraceIdToMDC(traceId);log.error("[sse] 流式请求失败: {}", error.toString());Disposable d = disposableRef.get();if (d != null && !d.isDisposed()) {d.dispose(); // <- 立即停止 WebClient 流log.info("[sse] WebClient 流已取消 error");}// emitter.complete();emitter.completeWithError(error);}).doOnComplete(() -> {setTraceIdToMDC(traceId);log.info("[sse] 流式请求完成");emitter.complete();}).subscribe();disposableRef.set(disposable);} catch (Exception e) {log.error("[sse] 异常: {}", e.getMessage(), e);emitter.completeWithError(e);}});// 前端主动断开时的回调(相当于 onCancel)emitter.onCompletion(() -> {log.info("[sse] SSE完成/客户端断开");Disposable disposable = disposableRef.get();if (disposable != null && !disposable.isDisposed()) {disposable.dispose();log.info("[sse] WebClient 订阅已关闭");}});emitter.onTimeout(() -> {log.info("[sse] SSE超时");emitter.complete();});emitter.onError((ex) -> {log.error("[sse] SSE异常: {}", ex.getMessage());Disposable disposable = disposableRef.get();if (disposable != null && !disposable.isDisposed()) {disposable.dispose();log.info("[sse] WebClient 订阅已关闭(异常触发)");}});return emitter;}private void setTraceIdToMDC(String traceId) {if (StrUtil.isNotBlank(traceId)) {MDC.put("trace-id", traceId);}}....
    }
    

NGINX 配置

  • proxy_pass
    location = /api/v1/chat/completions {proxy_pass http://...;include proxy_ai.conf;
    }
    
  • proxy_ai.conf
    proxy_redirect off;
    proxy_cache off;
    proxy_buffering off;
    #AI不要加这个参数
    #proxy_set_header Connection 'keep-alive';
    proxy_max_temp_file_size 0;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header        X-Real-IP       $remote_addr;
    proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
    #proxy_set_header  X-Real-IP         $http_x_forwarded_for;
    #proxy_set_header X-Forwarded-For    $http_x_forwarded_for;
    client_max_body_size     2048M;
    client_body_buffer_size  128k;
    #proxy_connect_timeout    100;
    proxy_read_timeout       300;
    proxy_send_timeout       300;
    proxy_buffer_size        16k;
    proxy_buffers            16 128k;
    proxy_busy_buffers_size 256k;
    proxy_temp_file_write_size 256k;
    proxy_headers_hash_max_size 512;
    proxy_headers_hash_bucket_size 512;
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/94694.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/94694.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一天认识一个神经网络之--CNN卷积神经网络

CNN 是一种非常强大的深度学习模型&#xff0c;尤其擅长处理像图片这样的网格结构数据。你可以把它想象成一个系统&#xff0c;它能像我们的大脑一样&#xff0c;自动从图片中学习并识别出各种特征&#xff0c;比如边缘、角落、纹理&#xff0c;甚至是更复杂的物体部分&#xf…

13 SQL进阶-InnoDB引擎(8.23)

一、逻辑存储结构&#xff08;1&#xff09;表空间&#xff08;ibd文件&#xff09;&#xff1a;一个mysql实例可以对应多个表空间&#xff0c;用于存储记录、索引等数据。cd /var/lib/mysql&#xff08;2&#xff09;段&#xff0c;分为数据段&#xff08;leaf node segment&a…

MTK Linux DRM分析(二十四)- MTK mtk_drm_plane.c

一、代码分析 mtk_drm_plane.h 和 mtk_drm_plane.c 两个文件,并生成基于文本的函数调用图,我将首先解析文件中的主要函数及其功能,然后根据代码中的调用关系整理出调用图。由于文件内容较长,我会专注于关键函数及其相互调用关系,并以清晰的文本形式呈现。 文件分析 1. …

滚珠导轨如何赋能精密制造?

在智能制造发展的趋势下&#xff0c;新兴行业对高精度、高稳定性的运动控制需求激增。作为直线传动领域的“精密纽带”&#xff0c;滚珠导轨凭借低摩擦、长寿命、高刚性优势&#xff0c;广泛应用于精密传动领域&#xff0c;成为产业升级的关键。新能源汽车制造领域&#xff1a;…

医疗 AI 的 “破圈” 时刻:辅助诊断、药物研发、慢病管理,哪些场景已落地见效?

一、引言在科技迅猛发展的当下&#xff0c;医疗领域正经历着深刻变革&#xff0c;人工智能&#xff08;AI&#xff09;技术宛如一颗璀璨新星&#xff0c;强势 “破圈” 闯入&#xff0c;为医疗行业带来了前所未有的机遇与活力。从辅助医生精准诊断病情&#xff0c;到助力药企高…

【项目思维】编程思维学习路线(推荐)

本篇博客是一份系统性、分阶段的 编程思维学习路线图推荐&#xff0c;从零基础小白到系统架构级别&#xff0c;帮助你全面建立和提升编程思维能力。 &#x1f6a6; 阶段 0&#xff1a;思维准备&#xff08;理解编程是什么&#xff09; &#x1f3af; 学习目标&#xff1a; 理…

vue3+antd实现华为云OBS文件拖拽上传详解

1、文件上传核心流程 选择文件​​&#xff1a;用户通过拖拽或点击选择文件手动触发上传​​&#xff1a;点击"确定"按钮后开始上传&#xff08;阻止自动上传&#xff09;​​获取上传凭证​​&#xff1a;从后端获取华为云OBS的上传配置构建表单数据​​&#xff1…

Mac 开发环境与配置操作速查表

Mac 开发环境与配置操作速查表 安装和配置 nvm / Node 安装 Homebrew Homebrew 安装参考文章 如果没有VPN&#xff0c;不要使用此命令安装&#xff01; /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" brew --v…

【论文简读】MuGS

今天读一篇ICCV 2025的文章&#xff0c;关注的是Generalizable Gaussian Splatting&#xff0c;作者来自华中科技大学。 文章链接&#xff1a;arxiv 代码仓库&#xff1a;https://github.com/EuclidLou/MuGS&#xff08;摘要中的链接&#xff0c;但暂时404&#xff09; 文章目…

基于SpringBoot和百度人脸识别API开发的保安门禁系统

角色&#xff1a; 管理员、保安 技术&#xff1a; Spring Boot, MyBatis, MySQL, PageHelper, Bootstrap, jQuery, JavaScript, CSS3, HTML5, JSP, 百度人脸识别API 核心功能&#xff1a; 小区保安门禁系统是一个基于Spring Boot技术栈开发的综合性平台&#xff0c;旨在实现小区…

抖音电商首创最严珠宝玉石质检体系,推动行业规范与消费扩容

8月27日&#xff0c;“抖音电商开放日质检专场”活动在广州华林国际举行。活动上&#xff0c;抖音电商首次对外介绍了质检仓配一体化中心&#xff08;QIC&#xff09;的运作流程&#xff0c;并发布了服务升级计划。这一行业首创的“先鉴定后发货”模式&#xff0c;被认为推动了…

SpringBoot整合Spring WebFlux弃用自带的logback,使用log4j2,并启动异步日志处理

第一步&#xff1a;修改pom文件<!-- Spring Boot Starter WebFlux (排除默认日志) --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId><version>${spring-boot.vers…

理解虚拟 DOM:前端开发中的高效渲染利器

在前端开发中&#xff0c;我们经常听到 虚拟 DOM&#xff08;Virtual DOM&#xff09; 这个概念。它是 React、Vue 等框架的核心机制之一&#xff0c;用来提升性能和简化开发。那么&#xff0c;虚拟 DOM 到底是什么&#xff1f;为什么要用它&#xff1f;又是如何工作的呢&#…

GraphRAG数据可视化

GraphRAG数据可视化

vue/react项目如何跳转到一个已经写好的html页面

如果是一个你copy的别人的网站&#xff0c;某些页面是已经可以直接使用的&#xff0c;但是有些页面需要在vue/react项目中重新二次调整加工&#xff0c;这个时候&#xff0c;就需要将html文件和vue/react项目结合&#xff0c;当某些页面可以直接使用&#xff0c;就直接跳转到这…

MYSQL-表的约束(下)

目录 自增长 唯一键 外键 自增长 MySQL自增长&#xff08;Auto-Increment&#xff09; 是一种字段属性&#xff0c;用于为表中的记录自动生成唯一的连续整数&#xff0c;常作为主键或唯一标识字段使用&#xff0c;避免手动输入重复值。 核心特性 1. 自动赋值&#xff1a…

《UE5_C++多人TPS完整教程》学习笔记44 ——《P45 倾斜与侧向移动(Leaning And Strafing)》

本文为B站系列教学视频 《UE5_C多人TPS完整教程》 —— 《P45 倾斜与侧向移动&#xff08;Leaning And Strafing&#xff09;》 的学习笔记&#xff0c;该系列教学视频为计算机工程师、程序员、游戏开发者、作家&#xff08;Engineer, Programmer, Game Developer, Author&…

使用docker搭建嵌入式Linux开发环境

文章目录1、前言2、安装docker3、编写容器管理脚本4、创建容器1、前言 在日常开发全志、rk等不同平台时&#xff0c;大多数时候只有一个编译主机&#xff0c;但不同sdk所需要的编译环境可能不同。所以本文将记录使用docker为每个平台创建独立的开发环境。 2、安装docker # 1…

【开题答辩全过程】以基于Android的校园跳蚤市场交易系统的设计与实现为例,包含答辩的问题和答案

个人简介一名14年经验的资深毕设内行人&#xff0c;语言擅长Java、php、微信小程序、Python、Golang、安卓Android等开发项目包括大数据、深度学习、网站、小程序、安卓、算法。平常会做一些项目定制化开发、代码讲解、答辩教学、文档编写、也懂一些降重方面的技巧。感谢大家的…

【学习笔记】GB 42250-2022标准解析

随着数字化转型的加速推进和网络安全威胁的日益复杂化&#xff0c;网络安全专用产品作为保护关键信息基础设施的第一道防线&#xff0c;其安全性和可靠性受到国家的高度重视。GB 42250-2022《信息安全技术 网络安全专用产品安全技术要求》作为一项强制性国家标准&#xff0c;于…