From 2e5d60a2390fd409980b124a9848a567b043a96c Mon Sep 17 00:00:00 2001 From: shishengliang Date: Wed, 23 Sep 2026 14:16:36 +0800 Subject: [PATCH] chore(deploy): configure DeepSeek runtime injection for Portainer --- .DS_Store | Bin 8196 -> 0 bytes .dockerignore | 6 ++++++ .gitignore | 6 ++++++ docker-compose.yml | 2 ++ docs/.DS_Store | Bin 8196 -> 0 bytes docs/portainer-deepseek.md | 38 +++++++++++++++++++++++++++++++++++++ docs/superpowers/.DS_Store | Bin 10244 -> 0 bytes 7 files changed, 52 insertions(+) delete mode 100644 .DS_Store delete mode 100644 docs/.DS_Store create mode 100644 docs/portainer-deepseek.md delete mode 100644 docs/superpowers/.DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index eec867796ed82c702bb07018cb7c042e6172c0bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8196 zcmeHMTWl0n7(U;$&>1?=0a{tG1DkG%fGw03Xt^cZn{q2fwx!#0S$20uIxw9nJG0wj zscB4n0nzxR@fLaV7I{!n;)^DVqK}Fu7~=y*qrPZ@FDeiIGiMfhfy4)66z3#!{`23? zng5^fKeK0+F^0ChwwAF7V@#yWqe?k-w`iW;yJj>YkdzVy`LoQ3Gn_H)4DlCcScifz z17QZj41^g7GZ1Fr-;e=%XM0V&&3m6~!#>PFn1TOg2E6?tN|#6D0iEE~-#V!Cj{roy zBY@v%tat;W(SXJSI>9MvsDZl@<*o>h7~t+Cj|O(}fKG7A-5G+z2ZEImoKWDePV+~7 zbA~vlVIO87%)rbHc;!>dG-k6bb0(kPGsC9gxD5?oLMSPnHM>kK6U)Vei9vfL;ilcZ z)0WQd_qZP0HZ#R>Iu{E3brjD6ImVJtcfM6S7bEk!LdU8Cb zQ)uVkBT5p*c)lveBh4w7=c;|l{(=2+N?A~#8}A-=4cl_|={bjJN~v%t!0lPv+LO~g zeP7l#^Fx-CQs!sVW;So8UA@&b6UIY2$ts*|&Nj_GwqtnH^e0_?)b(^TRLKFy&bjUW zWJ!bO=T=JI(f8^!sZr27Xlkc&T5yog&0Dmrc13+-^Okt$_O1smS19urER?I{0m`K1 z8V?$Ju0QQ$bxSj>BfTSr<_`8149CcrdXJSJ(xv&RlP*_87B9KGT2;BhO^2dsGM_Py z=MDFS5)(y#ji_29AJFKYx@^r`MH7|tG!L!5T&+>}dz$u~PQ4a5tW@undmIX0RMOmV zwcH^093u!wio+#M@_Mz`OlNdcQZ&9!i@ZtgEAaeF%1$oaDp#q=tUWYDAvzM5wW{sv zA#d4TX~*pz)-CUrE^*y`q#JMs(>c9+gdiB)(GHUOkCfz|Q>SLQwy&gY?55qxPGAft@hDE=G|u30JcZ}+0$#*fyoxvQCeGt+yoXEp1fSw_T*bHe4&UQv z{Ek0xU6>^-5+cH4p+=|^>V?%pv(O@J5;hCFg>E4!q=ln`EsXL2gkq^3{p?@bXl?NZWbah%w8%MeN^;nRw)atW3?g`i!v)dNnOJZ}-n>PkLR3lvc4?eg<}=mR9i24IB}M$ZP=1A7Wk0ZA z*mXkrJS;>6_n?8W-G*)0?V~$^UK~OShmnDXAy}|+oN#^;<9HYoc!W^?7~%X0Jc(!U zES@8*zl4|Z3SPtOg!FfC0q^1ie29zqIKceZg!rFuZ5oQZiumOezfMMRA(698+d4wB zBI>7_-%(r%k0#=s|2uF0{r`@NISeMuK$wB489-@AqN9yux7+i)vv!oO!*qGgvzy@5 wccE^|hXCSl{9#DrD4BXb@qkWnN)l@S_=f=h2l-$4sU5!m!}q_B&^xpH6HA9^ZvX%Q diff --git a/.dockerignore b/.dockerignore index 983485f..ff67260 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,9 +1,15 @@ node_modules dist .env +.env.* +!.env.example .git .codex outputs reports data/geo data/vehicle-heatmap/source.csv + +# Local machine metadata and runtime logs +.DS_Store +*.log diff --git a/.gitignore b/.gitignore index 7071147..36c51ee 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,10 @@ node_modules dist .env +.env.* +!.env.example .worktrees + +# Local machine metadata and runtime logs +.DS_Store +*.log diff --git a/docker-compose.yml b/docker-compose.yml index 6f235dc..516ce2f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,6 +5,8 @@ services: image: harbor.lnh2e.com/lingniu-v1/ln-bi:main-1.0.0 network_mode: host environment: + # Runtime only: set this variable in Portainer Stack environment variables. + DEEPSEEK_API_KEY: "${DEEPSEEK_API_KEY:-}" DB_HOST: "rm-bp179zbv481rnw3e2no.mysql.rds.aliyuncs.com" DB_PORT: "3306" DB_USER: "oneos_db_prod" diff --git a/docs/.DS_Store b/docs/.DS_Store deleted file mode 100644 index 894578ac335e82154852446654c6d960af3d5d38..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8196 zcmeHMU2GIp6u#fI&>1?=0a{tG1DkG%fGw03X!%RFe+m>RvMt?~pJjJvqyy8LvNO9| zEH#aZFZ^hH()bs7@-OnBqQnj7ELY1YcAhJTrF|q|i5FAkIzhJ@?#u z&b{}XIp4iKTgDhV^4e;~B8)MSsz;SdYHm}!d9U75gkYqcC`g~N92;deD>9vWVF^7D zdLZ;b=z-7!p$G0p573+K6>*w(pU;ME=z-7!|4R>e_d}GbN8ZZEE@kLRtBYnH6G% zSSjvL4BN$on|AX~M>@CHr+f1QS=-EySWZfrn@yY9yqR|OcGFB4kLfg4FQ&y zH+Rcaa>%iBZl}Lk(xCOZl#+M!-8wC56!b1y+NqvmDx|Y>7A&b>*4W&-Dc-$x$0L`j zl)3Zf%Qf;4`PFibM-4qUn0B(dr5V(ss8OlMA~RtprC zs}IV34jC^hX)d@@Zj$?sP(VnE!$(@=wQ9ea&giD3XndbGd4oDo;Qp7C9zM8Pu2GX& zdt`)6bR<63u6C*iyluCq9k+K>x4a`=kSz&gs2H3drC@+i2APq%`g+b!&!e z`;+92opq`@=q=Z-X}%4MA`7e3gxW7EUy3P3F|2|?AfV66u^`4upC%Sx!Mm}Kbl&kD z9g8<{PNGLoWzDRMZD$7weBYDo&M3=5uwWe)z`}L6I zFqF+T_M5y1m!qDb$+7VPw6J%N54Kne$ufrb%SuyK^4{x~M^I41D~ z#r!FX`ls;>p2rJ#ks|+9yoT5DCf=gBe;?=Z0Y1hjxPZ?B1bj#F|0}LeiRm4sXyz1u zOdr#QM9wm8>kvtl5OK5eUCEX4Q$@V|zkB-M|L@APhldJ15PIOwcmU;HiLMS>Yr4D3 z%eA9a4^s7tCpXEduR@KVjuZ9MaiZ7%VMzTbiF!KmfKGBsBUJwL9|G?DAKu~nAHM(h H-249z(Q=1o diff --git a/docs/portainer-deepseek.md b/docs/portainer-deepseek.md new file mode 100644 index 0000000..6227547 --- /dev/null +++ b/docs/portainer-deepseek.md @@ -0,0 +1,38 @@ +# Portainer 部署资产 AI 问数 + +DeepSeek Key 由 Node 服务端在运行时读取,变量名为 `DEEPSEEK_API_KEY`。模型固定为 `deepseek-flash`,接口为 `https://api.deepseek.com/chat/completions`,部署节点需要能够访问该 HTTPS 地址。 + +## Stack 配置 + +仓库的 `docker-compose.yml` 已包含: + +```yaml +services: + ln-bi: + environment: + DEEPSEEK_API_KEY: "${DEEPSEEK_API_KEY:-}" +``` + +1. 等待当前分支的 Woodpecker 构建与镜像推送成功。本次版本 1.1.17 对应镜像 `harbor.lnh2e.com/lingniu-v1/ln-bi:feature-asset-statistics-1.1.17`。 +2. Portainer → Stacks → 现有 `ln-bi` Stack。确认 Compose 的 `image` 使用上述镜像,且保留现有数据库、认证、网络和端口配置。 +3. 在 **Environment variables** 中新增名称 `DEEPSEEK_API_KEY`,值粘贴实际 API Key。Compose 必须包含上面的变量引用,才能将 Stack 变量传入容器。 +4. 点击 **Update the stack** 并重新部署,确保拉取新镜像。Git 管理的 Stack 需要从仓库拉取新版 Compose;Web Editor 管理的 Stack 则直接更新编辑器内容。 +5. 登录应用,在资产管理中打开「AI 问数」,查询“当前库存按区域统计”验证。 + +后续更换 Key 只需更新 Stack 环境变量并重新部署/创建容器,无需重新构建镜像。仅重启旧容器不会刷新其环境变量。未配置 Key 时 AI 问数返回配置提示,其他资产功能可继续使用。 + +## 检查是否注入 + +在 Portainer 中打开正在运行的应用容器 Console,执行: + +```sh +node -e 'console.log(process.env.DEEPSEEK_API_KEY ? "已配置" : "未配置")' +``` + +该命令只检查是否存在,不打印 Key;实际有效性由问数请求验证。Swarm 部署请进入对应任务容器检查。 + +Key 不使用 `VITE_` 前缀,不写入前端代码、Dockerfile、构建参数或 Git。`.env` 与本机日志已排除出 Git 和 Docker 构建上下文。现有应用端口保持 8111,无需为 DeepSeek 新增监听端口。 + +仓库 Compose 采用显式 `environment` 引用,可用于 Docker Standalone 与 Swarm;不依赖仅 Standalone 支持的 `env_file: stack.env`。 + +参考:[Portainer 创建 Stack 与环境变量](https://docs.portainer.io/sts/user/docker/stacks/add)、[更新现有 Stack](https://docs.portainer.io/user/docker/stacks/edit)。 diff --git a/docs/superpowers/.DS_Store b/docs/superpowers/.DS_Store deleted file mode 100644 index 5115dd2fcf9c16235253b2aa2a53c261b73cc794..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10244 zcmeHMU2GIp6u#fIr89J(1GG}G1Dh^Hz!pjiwEQL8Kjpv3wsc#5mff9^4oqjt&Td;Q zHI0ccAR3=E{zabri#(_(@kJ9w(MLrSjPU`ZQC~E{7nKLk+&f!ni-{(Z0GUbdJ@?#u z&b{}X`OciZcNt@7%^Ry3i!jDyDn8Xzs&4Z5<9?a;NI{Q32-0WFOAmX4Y1>UtlMOpU z4}=~FJrH^z^g!r=+rtBtv;9Xd6Ev(t4}=~FJuu+`|N9W3;?r0_#|7n|4yyPOfM_vw z^M~4W4&XYGfW`tkE+|)}ImPJ#fhvL{2823|M|^Rjv4D;XD%2T-IzzBBf)fh(>ZBLp z;tVlC!#eap=z-}T@WZBr4Kkahm^118em*^DTVAfd{%c4@#U(RJIYS*~CiCW-9tu^hu4ZgumH;c?x#7?2fN zNorN2qmApDY9oznR*%(2M%Opg*GASft{WRu`|{IO|6i9XNG z=GypV35(_zQd-_K_n0)PHDtEa)Lz9D^PrraJ%90%Wpxcrn_?YXcRqBfT$?j@o?5B) zkuRN`^{{1TdsAMcG+7L{ebMntbs_ZzgQovz`pV#wM#nuk_js@LfI{E@b-NwpCuEZ6T>yF4;p z)>1-nrCP6c9VHMbnkRZ1)wO!Jol2Xwq8VbHW_5$!GbH@4Xxl~SX0=jJWZZ!PGSO2+ zUyI(RAM}^qk@9k#gQnwe>7p2WfX4c~{#4fN93~J3JK9FQ{FPF_uhd~!IhPNTH+I$N zdaplSi(zmZ7FI1N*W-G(tbHLTHO+E{ECN2gR)K#xT6i_l*b32%erSpYcXTvXFF1vg zo6Z_oJKMnyu`C;9r`faY410%NV4twB*mvw_c9s1BUEfWE~!&WNGa)vHXKx;C)emmjx^4TN6Kt1f^YE&uyk~x7>55frnm4yhz);|}0M#1< zfTMm=tZ>wGR7^qaB_4-nG`lHW%n{j-TCFsYjxLcYT(pvaUACOq?b-~% zR@beRDKs^Svubriqe20w6$NZv6R{ACx^a_2p{NxH?4lU4j5F2M?Hx4DMNR&{aDJIx zVL!3o*fqlWY|KLy?n6DHyA@loi{m?vZX84shmeMW0XT4RjF5f;V|Wzfc#LrV1R?z? zJdNk@JYFEQzk*ls8s5O0g!T7u9`EBLe2feDG(i2gg!x}^bqbDm77#2bexHovp?KD@ zUFR_M`p7R~9;HZ=W$vN`Ibl(lAj1S1CdgZxAa4w|FhSBU#4thL