当Ollama遇上划词翻译:我的Windows本地AI服务搭建日记
🚀 实现Windows本地大模型翻译服务 - 基于Ollama+Flask的划词翻译实践
- 🛠️ 步骤概要
- 1️⃣ python 环境准备
- 2️⃣ Ollama 安装
- 3️⃣ 一个 Flask 服务
- 4️⃣ Windows 服务化封装
- 5️⃣ 测试本地接口
- 6️⃣ 配置划词翻译自定义翻译源
- 7️⃣ 效果展示
- 8️⃣ debug 历程
- 💡 技术亮点
🛠️ 步骤概要
参考 API 文档:
- Ollama API
- 划词翻译自定义翻译源
1️⃣ python 环境准备
# 虚拟环境
conda create -n ollama_trans
conda activate ollama_trans
pip install flask flask-cors pywin32 requests waitress
# 请确保完成 pywin32_postinstall.py 的安装步骤。:
python path\to\your\envs\ollama_trans\Scripts\pywin32_postinstall.py -install
2️⃣ Ollama 安装
安装 Ollama 最好提前设置安装路径和模型下载路径,否则它都一股脑干到 C 盘。可以参考前一篇博客 《本地投喂deepseek》:
- 设置模型保存路径:新增环境变量
OLLAMA_MODELS
,值为目标地址,似乎要 重启电脑生效 - 指定安装目录:OllamaSetup.exe /DIR=“D:\some\location”
- ollama默认在 11434 端口提供 REST API,比如通过 curl 发送请求到
/api/generate
来生成文本:
curl http://localhost:11434/api/generate -d "{\"model\": \"deepseek-r1:14b\", \"prompt\": \"Why is the sky blue?\", \"stream\": false}"
- 我们的目的就是用 flask 写一个服务器适配 Ollama 和划词翻译的 API
3️⃣ 一个 Flask 服务
遇事不决问 DS
# translation_service.py
import re
import win32serviceutil
import win32service
import win32event
import servicemanager
import socket
from flask import Flask, request, jsonify
from flask_cors import CORS
from waitress import serve
import requests
import logging
import sys
import osapp = Flask(__name__)
CORS(app)# 获取当前脚本所在的目录
current_directory = os.path.dirname(os.path.abspath(__file__))
# 定义日志文件名
log_file_path = os.path.join(current_directory, 'flask_svc.log')
# 配置日志记录器
logging.basicConfig(level=logging.INFO,format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',datefmt='%a, %d %b %Y %H:%M:%S',filename=log_file_path,filemode='a' # 使用 'a' 表示追加模式,'w' 表示覆盖模式
)
logger = logging.getLogger(__name__)# 选择ollama的模型
MODEL_NAME = {"qwen": "qwen2.5:7b-instruct-q8_0","llama": "llama3.2:3b","deepseek": "deepseek-r1:14b" # 其实 deepseek-r1 擅长推理,并不适合翻译,有点慢
}# 语言映射
LANGUAGE_MAP = {"中文(简体)": "中文","英语": "英文","日语": "日文"
}def clean_response(text):"""清除<think>标签内容"""# 过滤DeepSeek思考过程的正则表达式THINK_PATTERN = re.compile(r'<think>.*?</think>', re.DOTALL)return THINK_PATTERN.sub('', text).strip()def build_prompt(text, source, target):source_lang = LANGUAGE_MAP.get(source, source)target_lang = LANGUAGE_MAP.get(target, target)return f"作为专业翻译官,请将以下{source_lang}内容精准翻译为{target_lang},仅输出译文:\n{text}"@app.route('/translate', methods=['POST'])
def translate():try:data = request.jsonlogger.info(f"收到请求: {data}")# 提取必要参数model_name = data['name'].lower()text = data["text"]dest_langs = data["destination"]source_lang = data.get("source") or "auto"if source_lang == dest_langs[0] and len(dest_langs) > 1:target_lang = dest_langs[1]else:target_lang = dest_langs[0]response = requests.post("http://localhost:11434/api/generate",json={"model": MODEL_NAME.get(model_name, model_name),"prompt": build_prompt(text, source_lang, target_lang),"stream": False,"options": {"temperature": 0.3}})# 处理翻译结果raw_response = response.json()["response"]translated_text = clean_response(raw_response)return jsonify({"text": text,"from": source_lang,"to": target_lang,"result": [translated_text]})except Exception as e:logger.error(f"翻译失败: {str(e)}")return jsonify({"error": str(e)}), 500class TranslationService(win32serviceutil.ServiceFramework):_svc_name_ = "LocalOllamaTranslationService" # 服务名称(唯一)_svc_display_name_ = "Ollama本地翻译服务"_svc_description_ = "为划词翻译提供基于Ollama中运行的大模型的本地翻译服务" # 服务描述logger.info(f"svc_name: {_svc_name_}, model_name: {MODEL_NAME}")def __init__(self, args):win32serviceutil.ServiceFramework.__init__(self, args)self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)socket.setdefaulttimeout(60)def SvcStop(self):self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)logger.info("Stopping Ollama Translation Service...")win32event.SetEvent(self.hWaitStop)servicemanager.LogInfoMsg("服务正在停止...")logger.info("Service stopped successfully.")def SvcDoRun(self):logger.info("Starting Ollama Translation Service...")try:self.main()logger.info("Service started successfully.")except Exception as e:logger.error(f"Failed to start service: {str(e)}")self.ReportServiceStatus(win32service.SERVICE_STOPPED)def main(self):serve(app, host='127.0.0.1', port=5000)if __name__ == '__main__':if len(sys.argv) == 1:servicemanager.Initialize()servicemanager.PrepareToHostSingle(TranslationService)servicemanager.StartServiceCtrlDispatcher()else:win32serviceutil.HandleCommandLine(TranslationService)
4️⃣ Windows 服务化封装
以下脚本都需要以管理员身份运行
- 启动服务脚本
install_service.bat
:: install_service.bat
@echo off
# 这里的 python 解释器要填虚拟环境那个,否则找不到包
set PYTHON_PATH=path\to\your\envs\ollama_trans\python.exe
set SCRIPT_PATH=%~dp0translation_service.py%PYTHON_PATH% %SCRIPT_PATH% --startup=auto install
# 这里的服务名称 LocalOllamaTranslationService 要跟上面程序里面的一致,是唯一的
net start LocalOllamaTranslationService
- 关闭服务脚本
uninstall_service.bat
:: uninstall_service.bat
@echo off
net stop LocalOllamaTranslationService
set PYTHON_PATH=path\to\your\envs\ollama_trans\python.exe
set SCRIPT_PATH=%~dp0translation_service.py%PYTHON_PATH% %SCRIPT_PATH% remove
最终的文件结构:
├── translation_service.py # 主服务程序
├── install_service.bat # 服务安装脚本
├── uninstall_service.bat # 服务卸载脚本
└── flask_svc.log # python 日志
5️⃣ 测试本地接口
现在我们请求的是 flask 服务的端口,我这里指定了模型名称是 qwen
,ollama 中也下载了 qwen2.5:7b-instruct-q8_0
curl -X POST http://localhost:5000/translate -H "Content-Type: application/json" -d "{\"name\": \"qwen\",\"text\": \"人工智能的发展前景\", \"destination\": [\"中文(简体)\", \"英语\"], \"source\": \"中文(简体)\"}"
返回:
{"from":"\u4e2d\u6587(\u7b80\u4f53)","result":["The Prospects for the Development of Artificial Intelligence"],"text":"\u4eba\u5de5\u667a\u80fd\u7684\u53d1\u5c55\u524d\u666f","to":"\u82f1\u8bed"}
6️⃣ 配置划词翻译自定义翻译源
插件设置
自定义翻译源
-
接口地址:http://localhost:5000/translate
-
翻译源名称:qwen,然后回车
-
测试
根据上面的程序逻辑,翻译源名称最好跟 ollama 下载的模型名称一致
7️⃣ 效果展示
8️⃣ debug 历程
- 日志的重要性
- 一开始 deepseek 生成的 py 程序都没写日志,启动服务一直失败,报错:
pywintypes.error: (1063, 'StartServiceCtrlDispatcher', '服务进程无法连接到服务控制器上。')
,然后又那这些报错去问它,给了一堆方案都没解决问题 😄 - 写了 logger 才发现问题所在:
- 一开始 deepseek 生成的 py 程序都没写日志,启动服务一直失败,报错:
Sat, 15 Feb 2025 21:19:16 wasyncore.py[line:449] INFO Serving on http://127.0.0.1:5001
Sat, 15 Feb 2025 21:22:47 app.py[line:875] ERROR Exception on /translate [POST]
Traceback (most recent call last):File "D:\dev\miniconda\miniconda3\envs\flask\Lib\site-packages\flask\app.py", line 1511, in wsgi_appresponse = self.full_dispatch_request()File "D:\dev\miniconda\miniconda3\envs\flask\Lib\site-packages\flask\app.py", line 919, in full_dispatch_requestrv = self.handle_user_exception(e)File "D:\dev\miniconda\miniconda3\envs\flask\Lib\site-packages\flask_cors\extension.py", line 165, in wrapped_functionreturn cors_after_request(app.make_response(f(*args, **kwargs)))~^^^^^^^^^^^^^^^^^File "D:\dev\miniconda\miniconda3\envs\flask\Lib\site-packages\flask\app.py", line 917, in full_dispatch_requestrv = self.dispatch_request()File "D:\dev\miniconda\miniconda3\envs\flask\Lib\site-packages\flask\app.py", line 902, in dispatch_requestreturn self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
TypeError: TranslationService.translate() missing 1 required positional argument: 'self'
- 服务启停
- cmd 中的双引号是需要用反斜杠
\
转义的,在 powershell 中不需要 - debug 过程中需要起了又删掉
LocalOllamaTranslationService
服务: sc queryex LocalOllamaTranslationService
得到 PIDtaskkill /f /pid <PID>
强行停止sc delete LocalOllamaTranslationService
删掉这个服务 ID 后才能再启动程序,否则会报错服务已存在- 或者以管理员身份打开 cmd 或者 VS Code,执行:
python translation_service.py stop
停止服务python translation_service.py remove
删除服务python translation_service.py install
安装服务python translation_service.py start
启动服务
- cmd 中的双引号是需要用反斜杠
💡 技术亮点
-
完全离线: 从模型推理到翻译服务全程本地运行
-
隐私保护: 敏感文本无需离开本地设备
-
低延迟: 省去网络传输耗时,平均响应<500ms
-
可扩展架构: 轻松切换不同大语言模型
相关文章:

当Ollama遇上划词翻译:我的Windows本地AI服务搭建日记
🚀 实现Windows本地大模型翻译服务 - 基于OllamaFlask的划词翻译实践 🛠️ 步骤概要1️⃣ python 环境准备2️⃣ Ollama 安装3️⃣ 一个 Flask 服务4️⃣ Windows 服务化封装5️⃣ 测试本地接口6️⃣ 配置划词翻译自定义翻译源7️⃣ 效果展示8️⃣ debug…...
Linux上Elasticsearch 集群部署指南
Es 集群部署 Es 集群部署 Es 集群部署 准备好三台服务器。示例使用:110.0.5.141/142/143 1、es用户和用户组创建,使用root账号 groupadd esuseradd -g es es2、将es安装包和ik分词器上传到:/home/es/目录下(任意目录都行&#…...

字节Trae使用感想(后端)
前言 昨天分享了字节哥的Trae从0到1创作模式构建一个vue前端项目,今天又来试试她的后端项目能力。不是我舔,不得不说确实不错。可惜现在曾经没有好好学习,进不了字节。既然进不了字节,那我就用字节哥的产品吧。 后面有惊喜…...

国产编辑器EverEdit - 二进制模式下观察Window/Linux/MacOs换行符差异
1 换行符格式 1.1 应用场景 稍微了解计算机历史的人都知道, 计算机3大操作系统: Windows、Linux/Unix、MacOS,这3大系统对文本换行的定义各不相同,且互不相让,导致在文件的兼容性方面存在一些问题,比如它们…...

文心一言4月起全面免费,6月底开源新模型:AI竞争进入新阶段?
名人说:莫听穿林打叶声,何妨吟啸且徐行。—— 苏轼 Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 目录 一、文心一言免费化的背后:AI成本与应用的双重驱动1️⃣成本下降,推动文心一言普及2…...

解锁机器学习算法 | 线性回归:机器学习的基石
在机器学习的众多算法中,线性回归宛如一块基石,看似质朴无华,却稳稳支撑起诸多复杂模型的架构。它是我们初涉机器学习领域时便会邂逅的算法之一,其原理与应用广泛渗透于各个领域。无论是预测房价走势、剖析股票市场波动࿰…...
如何使用Three.js制作3D月球与星空效果
目录 1. 基本设置2. 创建星空效果3. 创建月球模型4. 添加中文3D文字5. 光照与相机配置6. 动画与控制7. 响应式布局8. 结语 在本文中,我们将一起学习如何利用Three.js实现一个3D月球与星空的效果,并添加一些有趣的元素,比如中文3D文字和互动功…...
SQL语句语法
SQL数据库的结构为 库database 表table 段segment 行row 列column 或field SQL 语句主要分为以下几类: 数据定义语言(DDL):用于定义数据库对象,如数据库、表、视图、索引等。数据操作语言(DML)&…...
github上文件过大无法推送问题
GitHub 对文件大小有限制,超过 100 MB 的文件无法直接推送到仓库中。 解决思路: 使用 Git Large File Storage (Git LFS) 来管理大文件不上传对应的大文件 使用Git LFS: 1. 安装 Git LFS 首先,你需要安装 Git LFS。可以按照以…...
微信小程序的请求函数封装(ts版本,uniapp开发)
主要封装函数代码: interface HttpOptions {url: string;method?: string;headers?: { [key: string]: string };data?: any; }class Http {private timeout: number;private baseUrl: string;public constructor() { this.timeout 60 * 1000;this.baseUrl ht…...

Visual Studio Code支持WSL,直接修改linux/ubuntu中的文件
步骤1 开始通过 WSL 使用 VS Code | Microsoft Learn 点击远程开发扩展包。 步骤2 Remote Development - Visual Studio Marketplace 点击install, 允许打开Visual Studio Code。 步骤3 共有4项,一齐安装。 步骤4 在WSL Linux(Ubuntu)中…...

openAI最新o1模型 推理能力上表现出色 准确性方面提升 API如何接入?
OpenAI o1模型在回答问题前会进行深入思考,并生成一条内部推理链,使其在尝试解决问题时可以识别并纠正错误,将复杂的步骤分解为更简单的部分,并在当前方法无效时尝试不同的途径。据悉,o1不仅数学水平与美国奥林匹克竞赛…...

GC 基础入门
什么是GC(Garbage Collection)? 内存管理方式通常分为两种: 手动内存管理(Manual Memory Management)自动内存管理(Garbage Collection, GC) 手动内存管理 手动内存管理是指开发…...
Go语言协程Goroutine高级用法(一)
什么协程 在Go语言中,协程就是一种轻量的线程,是并发编程的单元,由Go来管理,所以在GO层面的协程会更加的轻量、高效、开销更小,并且更容易实现并发编程。 轻量级线程 Go语言中协程(线程)与传…...

DeepSeek处理自有业务的案例:让AI给你写一份小众编辑器(EverEdit)的语法着色文件
1 DeepSeek处理自有业务的案例:让AI给你写一份小众编辑器(EverEdit)的语法着色文件 1.1 背景 AI能力再强,如果不能在企业的自有业务上产生助益,那基本也是一无是处。将企业的自有业务上传到线上训练,那是脑子进水的做法ÿ…...

【鸿蒙HarmonyOS Next实战开发】lottie动画库
简介 lottie是一个适用于OpenHarmony和HarmonyOS的动画库,它可以解析Adobe After Effects软件通过Bodymovin插件导出的json格式的动画,并在移动设备上进行本地渲染。 下载安裝 ohpm install ohos/lottieOpenHarmony ohpm 环境配置等更多内容,…...

PAT乙级真题 — 1084 外观数列(java)
外观数列是指具有以下特点的整数序列: d, d1, d111, d113, d11231, d112213111, ...它从不等于 1 的数字 d 开始,序列的第 n1 项是对第 n 项的描述。比如第 2 项表示第 1 项有 1 个 d,所以就是 d1;第 2 项是 1 个 d(对…...

从 ClickHouse 到 Apache Doris:在网易云音乐日增万亿日志数据场景下的落地
导读:日志数据已成为企业洞察系统状态、监控网络安全及分析业务动态的宝贵资源。网易云音乐引入 Apache Doris 作为日志库新方案,替换了 ClickHouse。解决了 ClickHouse 运维复杂、不支持倒排索引的问题。目前已经稳定运行 3 个季度,规模达到…...

STM32——HAL库开发笔记19(串口中断接收实验)(参考来源:b站铁头山羊)
本实验,我们以中断的方式使得串口发送数据控制LED的闪烁速度,发送1,慢闪;发送2,速度正常;发送3,快闪。 一、电路连接图 二、实现思路&CubeMx配置 1、实现控制LED的闪烁速度 uint32_t bli…...
清影2.0(AI视频生成)技术浅析(二):自然语言处理
清影2.0(AI视频生成)中的自然语言处理(NLP)技术是其核心组件之一,负责将用户输入的自然语言文本转化为机器可以理解的语义表示,从而指导后续的视频生成过程。 一、基本原理 1. 目标 清影2.0的NLP技术旨在将用户输入的自然语言文本转化为机器可以理解的语义表示,从而指…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...

龙虎榜——20250610
上证指数放量收阴线,个股多数下跌,盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型,指数短线有调整的需求,大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的:御银股份、雄帝科技 驱动…...
云计算——弹性云计算器(ECS)
弹性云服务器:ECS 概述 云计算重构了ICT系统,云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台,包含如下主要概念。 ECS(Elastic Cloud Server):即弹性云服务器,是云计算…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...
在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module
1、为什么要修改 CONNECT 报文? 多租户隔离:自动为接入设备追加租户前缀,后端按 ClientID 拆分队列。零代码鉴权:将入站用户名替换为 OAuth Access-Token,后端 Broker 统一校验。灰度发布:根据 IP/地理位写…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...

第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词
Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵,其中每行,每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid,其中有多少个 3 3 的 “幻方” 子矩阵&am…...

网络编程(UDP编程)
思维导图 UDP基础编程(单播) 1.流程图 服务器:短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...
稳定币的深度剖析与展望
一、引言 在当今数字化浪潮席卷全球的时代,加密货币作为一种新兴的金融现象,正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而,加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下,稳定…...