目录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)
企业数字化 ERP 产品动态
相关推荐
关于网络地址IP 子网掩码 网关 以及DNS服务器的学习和了解 我是在学习Linux的前期回顾了这个知识点,之前知道这些东西但是不知道这些都是如何区别的以及相关的作用,本人也是准备把学习Linux的过程记录一下,方便日后自己查看 也方便和我一样的学习者们一起共勉,有问题的话欢迎大家一起交流。… · 2026/9/21 12:08:58
AI算力网络架构详解:从GPU服务器到交换机、网卡与互联链路 在实际的AI集群建设中,GPU服务器只是计算节点,不能代表完整的算力网络。一个可用的AI算力网络,至少应该包含计算节点、交换层、服务器侧网络接口、光电互联链路、存储层和拓扑架构。1)计算节点:通常是GPU服务器&#x… · 2026/9/19 4:09:02
AM574x高速接口时序设计实战:从协议到PCB的嵌入式系统可靠性保障 1. 项目概述:为什么高速接口时序是嵌入式设计的“命门”?在嵌入式系统,尤其是工业控制、汽车电子和高端通信设备的设计中,处理器与外设之间的数据交换速度和可靠性是决定系统成败的关键。我们常常关注处理器的算力、内存大小&… · 2026/8/10 8:17:01
AI 辅助的 API 接口 Mock 数据生成:用 TaoToken 统一 Key 打通前端独立开发的数据引擎 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 19:17:30
学生党 vibe coding 实战:口述需求 + TaoToken 统一 Key 搞定前端作品集课设 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 19:17:30
网站单个页面做301怎么选?老手教你3个场景避坑指南 网站单个页面做301怎么选?老手教你3个场景避坑指南 域名解析改了服务器没动,或者服务器配置了Nginx但域名还是旧IP,这种“域名服务器搞不懂”的乱局,是每个独立站长都踩过的坑。很多时候,你只想把某个废弃的落地页彻底移除,或者合并两个内容… · 2026/9/27 19:17:24
AI开发工具全解析:从训练到部署,TaoToken统一Key打通工具链 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 19:17:24
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01