大模型流式推理
目录http 流式推理直接返回http 流式推理ocr_stream_client.py# codingutf-8 import base64 import json import os import urllib.request import logging import logging.handlers from pathlib import Path from typing import Optional, List, Dict, Any, AsyncGenerator import requests LOG_DIR Path(__file__).resolve().parent / logs LOG_DIR.mkdir(exist_okTrue) base_url http://192.168.100.203:17890 # 统一使用第二个地址 # 主日志处理器geogebra_api.log main_handler logging.handlers.TimedRotatingFileHandler( filenameLOG_DIR / geogebra_api.log, whenmidnight, interval1, backupCount30, encodingutf-8 ) main_handler.setFormatter(logging.Formatter(%(asctime)s - %(name)s - %(levelname)s - %(message)s)) stream_handler logging.StreamHandler() stream_handler.setFormatter(logging.Formatter(%(asctime)s - %(name)s - %(levelname)s - %(message)s)) logging.basicConfig(levellogging.INFO, handlers[stream_handler, main_handler]) logger logging.getLogger(__name__) _MODEL_ID None def get_model_id() - str: 获取 vLLM 服务的模型 ID并缓存 global _MODEL_ID if _MODEL_ID is not None: return _MODEL_ID try: resp urllib.request.urlopen(f{base_url}/v1/models, timeout30) data json.loads(resp.read().decode(utf-8)) _MODEL_ID data[data][0][id] logger.info(f获取到模型 ID: {_MODEL_ID}) return _MODEL_ID except Exception as e: logger.error(f获取模型 ID 失败: {e}) # raise HTTPException(status_code500, detail无法获取 vLLM 模型 ID) model_id get_model_id() def _http_stream(url: str, payload: dict, timeout: int 300): 流式请求vLLM接口逐行返回SSE数据 data json.dumps(payload).encode(utf-8) req urllib.request.Request(url, datadata, headers{Content-Type: application/json}) with urllib.request.urlopen(req, timeouttimeout) as resp: for line in resp: line line.decode(utf-8).strip() if not line: continue if line.startswith(data: ): data_str line[6:] # 去掉 data: 前缀 if data_str [DONE]: break try: chunk json.loads(data_str) yield chunk except json.JSONDecodeError: continue prompt_file ocr_prompt.md with open(prompt_file, r, encodingutf-8) as f: system_prompt f.read() # 一行搞定包含所有换行 def encode_image_to_base64(image_path: str) - str: 将图片编码为 base64 with open(image_path, rb) as image_file: return base64.b64encode(image_file.read()).decode(utf-8) def ocr_image_processing(img_path: str, model_id: str, base_url: str, session_id: str, rep_id: str, timeout: int 300) - AsyncGenerator[str, None]: try: # 读取图片数据 with open(img_path, rb) as f: image_data f.read() # 获取图片文件名 image_filename os.path.basename(img_path) json_log_path image_filename[:-4] .json # 构建消息 ocr_messages [{role: user, content: [{type: text, text: 请识别图片中的文字和数学公式}, {type: image_url, image_url: {url: fdata:image/jpeg;base64,{base64.b64encode(image_data).decode(utf-8)}}}]}] full_ocr_messages [{role: system, content: system_prompt}] ocr_messages # 构建请求负载 ocr_payload {model: model_id, messages: full_ocr_messages, temperature: 0.1, max_tokens: 2048, stream: True} # 直接使用 requests 发送请求 response requests.post(f{base_url}/v1/chat/completions, jsonocr_payload, streamTrue, timeouttimeout) if response.status_code ! 200: error_msg fHTTP错误: {response.status_code} logger.error(error_msg) yield fdata: {json.dumps({type: ocr_error, error: error_msg, session_id: session_id, rep_id: rep_id},ensure_asciiFalse)}\n\n return ocr_full_content ocr_success False # 处理流式响应 for line in response.iter_lines(): if not line: continue line line.decode(utf-8).strip() if not line.startswith(data: ): continue data_str line[6:] # 去掉 data: 前缀 if data_str [DONE]: break try: chunk json.loads(data_str) choices chunk.get(choices, []) if not choices: continue delta choices[0].get(delta, {}) content delta.get(content, ) if content: ocr_full_content content print(content) yield fdata: {json.dumps({type: ocr_chunk, content: content, session_id: session_id, rep_id: rep_id},ensure_asciiFalse)}\n\n except json.JSONDecodeError: continue ocr_text ocr_full_content.strip() if ocr_text: ocr_success True logger.info(fOCR识别成功长度: {len(ocr_text)}) # 保存记录 record {session_id: session_id, image_filename: image_filename, ocr_text: ocr_text, success: ocr_success} with open(json_log_path, w, encodingutf-8) as f: json.dump(record, f, ensure_asciiFalse, indent2) logger.info(fOCR记录已保存: {json_log_path}) logger.info(fOCR识别文本内容:\n{ocr_text}) yield fdata: {json.dumps({type: ocr_done, content: ocr_text, session_id: session_id, rep_id: rep_id},ensure_asciiFalse)}\n\n else: logger.warning(OCR识别结果为空) yield fdata: {json.dumps({type: ocr_error, error: OCR识别结果为空, session_id: session_id, rep_id: rep_id},ensure_asciiFalse)}\n\n except FileNotFoundError: error_msg f图片文件不存在: {img_path} logger.error(error_msg) yield fdata: {json.dumps({type: ocr_error, error: error_msg, session_id: session_id, rep_id: rep_id},ensure_asciiFalse)}\n\n except Exception as e: error_msg fOCR处理异常: {str(e)} logger.error(error_msg) yield fdata: {json.dumps({type: ocr_error, error: error_msg, session_id: session_id, rep_id: rep_id},ensure_asciiFalse)}\n\n if __name__ __main__: # 配置日志 logging.basicConfig(levellogging.INFO) # 配置参数 img_path rC:\Users\ChanJing-01\Documents\math\07\hanshu.png session_id session_id rep_id rep_id # 模拟的http_stream_function实际使用时需要替换为真实的请求函数 def mock_http_stream_function(url, payload, timeout): # 模拟返回数据 yield {choices: [{delta: {content: 这是一个测试}}]} yield {choices: [{delta: {content: OCR识别结果}}]} # 调用函数 # for chunk in ocr_image_processing(img_pathimg_path, model_idmodel_id, base_urlbase_url, session_idsession_id, rep_idrep_id, http_stream_functionmock_http_stream_function): for chunk in ocr_image_processing(img_pathimg_path, model_idmodel_id, base_urlbase_url, session_idsession_id, rep_idrep_id): print(chunk)直接返回ocr_from_server.pyimport urllib from http.client import HTTPException from pathlib import Path import requests import json import base64 from typing import List, Dict, Any import time def encode_image_to_base64(image_path: str) - str: 将图片编码为 base64 with open(image_path, rb) as image_file: return base64.b64encode(image_file.read()).decode(utf-8) _MODEL_ID None def get_model_id() - str: 获取 vLLM 服务的模型 ID并缓存 global _MODEL_ID if _MODEL_ID is not None: return _MODEL_ID try: resp urllib.request.urlopen(f{BASE_URL}/v1/models, timeout30) data json.loads(resp.read().decode(utf-8)) _MODEL_ID data[data][0][id] print(f获取到模型 ID: {_MODEL_ID}) return _MODEL_ID except Exception as e: print(f获取模型 ID 失败: {e}) raise HTTPException(status_code500, detail无法获取 vLLM 模型 ID) def chat_with_images(text: str, image_paths: List[str], max_tokens: int 1024, temperature: float 0.7) - str: model_id get_model_id() # 构建 content 列表 content [] # 1. 添加文本内容 content.append({type: text, text: text}) for image_path in image_paths: # 如果是本地图片转换为 base64 if image_path.startswith((http://, https://)): # URL 图片 content.append({type: image_url, image_url: {url: image_path}}) else: # 本地图片 base64_image encode_image_to_base64(image_path) content.append({type: image_url, image_url: {url: fdata:image/jpeg;base64,{base64_image}}}) prompt_file ocr_prompt.md with open(prompt_file, r, encodingutf-8) as f: system_prompt f.read() # 一行搞定包含所有换行 payload { model: model_id, messages: [ {role: system, content: system_prompt}, {role: user, content: content}, ], temperature: 0.0, max_tokens: 4096, stream: True, } print(f Sending request with {len(image_paths)} images...) print(f Text: {text}) print(- * 80) full_response try: response requests.post(f{BASE_URL}/v1/chat/completions, jsonpayload, streamTrue, timeout300) if response.status_code ! 200: print(f❌ Error: {response.status_code}) print(response.text) return # 5. 处理流式响应 for line in response.iter_lines(): if line: line line.decode(utf-8) if line.startswith(data: ): data line[6:] # 去掉 data: 前缀 if data [DONE]: break try: chunk json.loads(data) choices chunk.get(choices, []) if choices: delta choices[0].get(delta, {}) content_delta delta.get(content, ) if content_delta: print(content_delta, end, flushTrue) full_response content_delta except json.JSONDecodeError: continue print(\n - * 80) return full_response except requests.exceptions.Timeout: print(❌ Request timeout) return except Exception as e: print(f❌ Error: {e}) return if __name__ __main__: BASE_URL http://192.168.100.203:17890 image_paths [rC:\Users\ChanJing-01\Documents\math\07\a12.jpg] image_paths [rC:\Users\ChanJing-01\Documents\math\07\hanshu.png] # response chat_with_images(text图中有两个矩形把几何图复现一下, image_paths[rC:\Users\ChanJing-01\Pictures\wav_sucai\ca1e63ed-1560-4ade-9e45-57aa500b7123.png]) response chat_with_images(text请识别图片中的文字和数学公式, image_pathsimage_paths) print(response)

相关新闻

告别论文难题:2026年亲测好用的AI论文写作平台大推荐

告别论文难题:2026年亲测好用的AI论文写作平台大推荐

在撰写期刊论文、毕业论文或职称论文的过程中,学术人员常常会遇到许多挑战。撰写一篇优质的论文,面对海量的文献资料,寻找相关的信息就像在沙滩上捡贝壳一样难;繁琐的格式要求经常让人感到无从下手,精力涣散&#xff1…

2026/7/24 11:59:00 阅读更多 →
不容错过!2026年7款AI论文平台实测,高效产出优质初稿

不容错过!2026年7款AI论文平台实测,高效产出优质初稿

到了2026年,越来越多的人开始尝试用AI写论文,特别是硕士和博士这种长篇学术作品。很多AI论文写作工具在处理这些复杂任务时,常常表现不好。比如,有的工具写出来的内容缺少深度,理论不够扎实;有的则逻辑很乱…

2026/7/24 11:59:00 阅读更多 →
单目视觉3D锥桶检测:UNet-RKNet架构与工程实践

单目视觉3D锥桶检测:UNet-RKNet架构与工程实践

1. 项目背景与核心挑战在自动驾驶环境感知领域,锥桶检测一直是个看似简单实则棘手的任务。传统方案通常依赖昂贵的激光雷达或多相机系统,而我们在实际工程中发现,许多商用车辆受限于成本只能搭载单目摄像头。这就引出一个关键问题&#xff1a…

2026/7/24 11:59:00 阅读更多 →

最新新闻

结合GEO优化,私有化AI部署提升搜索曝光率

结合GEO优化,私有化AI部署提升搜索曝光率

为何关注本地化与私有化部署在探讨武汉地区支持私有化部署的AI数字员工服务商有哪些这一议题时,企业的核心诉求往往聚焦于数据主权、响应速度以及深度业务整合能力。相较于通用的SaaS工具,私有化部署允许企业将AI系统直接搭建在自有服务器或指定的云端环…

2026/7/24 12:07:02 阅读更多 →
WhatsApp 发送频率控制的令牌桶算法实现

WhatsApp 发送频率控制的令牌桶算法实现

WhatsApp 发送频率控制的令牌桶算法实现 目录 为什么固定间隔的限速不够用令牌桶的核心思想基础实现:单线程令牌桶进阶:多节点独立桶 全局配额与调度器的集成生产环境的落地经验小结1. why 固定间隔的限速不够用 前面好几篇文章都提到过 time.sleep(8) …

2026/7/24 12:07:02 阅读更多 →
AI产品经理需掌握的通用能力

AI产品经理需掌握的通用能力

AI产品经理需掌握的通用能力 核心能力如下:这份图片笔记梳理了AI产品经理需要关注的核心框架。我为你整理了一份结构化的学习笔记,补充了一些关键细节和实战要点,希望能帮你建立更系统的认知。 🧭 理解AI技术的边界 作为AI产品经理…

2026/7/24 12:07:02 阅读更多 →
MacBook Pro启动禁止标志的排查与修复指南

MacBook Pro启动禁止标志的排查与修复指南

1. 问题现象与背景分析上周给2016款MacBook Pro升级到macOS Sequoia系统后,机器突然在重启时出现了一个带斜杠的圆圈禁止符号(俗称"禁止标志"),系统完全无法启动。这个标志对于老果粉来说应该不陌生——它通常意味着系统…

2026/7/24 12:07:02 阅读更多 →
基于AI与大数据的智能诗词问答系统设计与实践

基于AI与大数据的智能诗词问答系统设计与实践

1. 项目背景与核心价值 诗词作为中华文化瑰宝,其信息检索与问答一直存在两大痛点:一是传统检索方式依赖关键词匹配,难以理解用户意图;二是专业诗词数据库往往只提供原始文本,缺乏深度解析能力。这个项目正是为了解决这…

2026/7/24 12:07:02 阅读更多 →
电商企业选择BBWEYY、Codex+亚马逊AWS、比文云与Dreamweaver建站测评——基于商城、小程序、交易稳定与会员复购的评价,含零代码SAAS、AI编程、源码定制交付

电商企业选择BBWEYY、Codex+亚马逊AWS、比文云与Dreamweaver建站测评——基于商城、小程序、交易稳定与会员复购的评价,含零代码SAAS、AI编程、源码定制交付

电商企业选择BBWEYY、Codex+亚马逊AWS、比文云与Dreamweaver建站测评 ——基于商城、小程序、交易稳定与会员复购的评价 摘要 电商网站的核心是商品、营销、支付、订单、库存、物流、售后与会员的完整闭环。本文对BBWEYY、Codex+亚马逊AWS、比文云和D…

2026/7/24 12:06:02 阅读更多 →

日新闻

用Highcharts 创建可拖拽三维散点立方体3D图表

用Highcharts 创建可拖拽三维散点立方体3D图表

该案例基于Highcharts scatter3d 三维散点图实现空间立方体散点可视化,核心特色:三维 X/Y/Z 三轴空间,所有散点分布在 0~10 立方体空间内;散点使用径向渐变实现立体 3D 圆球质感;支持鼠标 / 触屏拖拽画布,…

2026/7/24 0:00:29 阅读更多 →
AppCertDlls:进程创建路径上的 DLL 入口

AppCertDlls:进程创建路径上的 DLL 入口

AppCertDlls:进程创建路径上的 DLL 入口 AppCertDlls 位于 HKLM\System\CurrentControlSet\Control\Session Manager\AppCertDlls。本文的程序功能是只读列出这个键在 64 位和 32 位注册表视图中的全部值,并显示每条值的来源、名称、类型和可安全显示的数…

2026/7/24 0:00:29 阅读更多 →
我的编程之路:第一篇博客

我的编程之路:第一篇博客

大家好,我是一名编程初学者,同时这也是我编程学习之路上的第一篇博客。在这里,我想要向大家介绍我的一些想法和规划。a.自我介绍我是一个刚刚接触编程的新手,目前在学习c语言,我对编程世界充满了强烈的好奇。当然&…

2026/7/24 0:00:29 阅读更多 →

周新闻

Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/24 3:59:20 阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/24 1:23:39 阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/23 17:49:47 阅读更多 →

月新闻