From 841985c0d24c93d7895800ff2d5a463aa49cc35f Mon Sep 17 00:00:00 2001 From: kris Date: Mon, 23 Mar 2026 17:52:09 +0800 Subject: [PATCH] feat: expose storyforge through public cloud gateway --- README.md | 6 ++ deploy/STORYFORGE_TEST_HYZQ_GATEWAY.md | 37 +++++++ .../com.storyforge.cloud-bridge.plist.example | 40 +++++++ deploy/com.storyforge.web-v4.plist.example | 29 +++++ .../storyforge-test-hyzq-nginx.conf.fragment | 101 ++++++++++++++++++ web/storyforge-web-v4/README.md | 9 ++ web/storyforge-web-v4/assets/app.js | 17 ++- 7 files changed, 238 insertions(+), 1 deletion(-) create mode 100644 deploy/STORYFORGE_TEST_HYZQ_GATEWAY.md create mode 100644 deploy/com.storyforge.cloud-bridge.plist.example create mode 100644 deploy/com.storyforge.web-v4.plist.example create mode 100644 deploy/storyforge-test-hyzq-nginx.conf.fragment diff --git a/README.md b/README.md index 5b4ddea..bbdd42d 100644 --- a/README.md +++ b/README.md @@ -132,6 +132,7 @@ N8N_BASE_URL=http://127.0.0.1:5670 - `collector-service`:`http://127.0.0.1:8081` - `n8n`:`http://127.0.0.1:5670` - `cli-proxy-api`:`http://127.0.0.1:8317` +- 公网入口:`https://test.hyzq.net/storyforge/` 默认会创建最高权限账号: @@ -151,6 +152,11 @@ N8N_BASE_URL=http://127.0.0.1:5670 - 触发 `real_cut_pipeline` - 触发 `ai_video_pipeline` - 历史旧运行链已完成移除,当前运行时只保留 StoryForge 自身服务与外部执行引擎 +- 当前公网接入采用“云服务器 HTTPS 入口 + 本机桥接隧道 + 本机现网执行链”模式: + - `https://test.hyzq.net/storyforge/` 由云服务器 `nginx` 提供 HTTPS 入口 + - `/storyforge/` 静态页反向代理到本机 `Web V4` 静态服务 + - `/storyforge/v2/*`、`/storyforge/openapi.json`、`/storyforge/healthz` 反向代理到本机 `collector-service` + - `cutvideo / huobao / 本机模型 / NAS 录制` 继续由本机和局域网执行链提供 ## 说明 diff --git a/deploy/STORYFORGE_TEST_HYZQ_GATEWAY.md b/deploy/STORYFORGE_TEST_HYZQ_GATEWAY.md new file mode 100644 index 0000000..cb870f7 --- /dev/null +++ b/deploy/STORYFORGE_TEST_HYZQ_GATEWAY.md @@ -0,0 +1,37 @@ +# StoryForge `test.hyzq.net/storyforge` 公网入口 + +当前公网接入不是把执行链整体迁到云服务器,而是: + +1. 云服务器 `nginx` 提供 `https://test.hyzq.net/storyforge/` +2. 本机 `collector-service` 继续承接业务与局域网执行引擎 +3. 本机 `Web V4` 静态服务继续承接前端 +4. 本机通过 SSH 反向隧道把这两个入口桥接到云服务器 + +## 端口映射 + +- 云服务器 `127.0.0.1:18181` -> 本机 `127.0.0.1:8081` +- 云服务器 `127.0.0.1:18191` -> 本机 `127.0.0.1:3918` + +## 本机常驻服务 + +- `com.storyforge.collector` +- `com.storyforge.web-v4` +- `com.storyforge.cloud-bridge` + +## 云服务器 `nginx` 路由 + +- `/storyforge/` -> `127.0.0.1:18191` +- `/storyforge/v2/*` -> `127.0.0.1:18181` +- `/storyforge/openapi.json` -> `127.0.0.1:18181/openapi.json` +- `/storyforge/healthz` -> `127.0.0.1:18181/healthz` + +## 当前优点 + +- 不需要把 `cutvideo / huobao / NAS live-recorder / 本机模型` 全部搬上云 +- 公网入口统一 +- 本机现网能力不需要改造即可对外开放 + +## 当前限制 + +- 本机桥接断开时,公网入口不可用 +- 这是公网 staging / 私有运营入口,更接近“公网可访问的现网桥接”,不是最终完全云原生部署 diff --git a/deploy/com.storyforge.cloud-bridge.plist.example b/deploy/com.storyforge.cloud-bridge.plist.example new file mode 100644 index 0000000..164ae77 --- /dev/null +++ b/deploy/com.storyforge.cloud-bridge.plist.example @@ -0,0 +1,40 @@ + + + + + Label + com.storyforge.cloud-bridge + ProgramArguments + + /usr/bin/ssh + -N + -i + /Users/kris/.ssh/id_ed25519_kylin188 + -o + BatchMode=yes + -o + ExitOnForwardFailure=yes + -o + ServerAliveInterval=30 + -o + ServerAliveCountMax=3 + -o + StrictHostKeyChecking=no + -o + UserKnownHostsFile=/Users/kris/.ssh/known_hosts + -R + 127.0.0.1:18181:127.0.0.1:8081 + -R + 127.0.0.1:18191:127.0.0.1:3918 + ubuntu@111.231.132.51 + + RunAtLoad + + KeepAlive + + StandardOutPath + /Users/kris/code/StoryForge/data/collector/cloud-bridge.log + StandardErrorPath + /Users/kris/code/StoryForge/data/collector/cloud-bridge.log + + diff --git a/deploy/com.storyforge.web-v4.plist.example b/deploy/com.storyforge.web-v4.plist.example new file mode 100644 index 0000000..35d8416 --- /dev/null +++ b/deploy/com.storyforge.web-v4.plist.example @@ -0,0 +1,29 @@ + + + + + Label + com.storyforge.web-v4 + ProgramArguments + + /usr/bin/python3 + -m + http.server + 3918 + --bind + 127.0.0.1 + --directory + /Users/kris/code/StoryForge/web/storyforge-web-v4 + + WorkingDirectory + /Users/kris/code/StoryForge/web/storyforge-web-v4 + RunAtLoad + + KeepAlive + + StandardOutPath + /Users/kris/code/StoryForge/data/collector/web-v4.log + StandardErrorPath + /Users/kris/code/StoryForge/data/collector/web-v4.log + + diff --git a/deploy/storyforge-test-hyzq-nginx.conf.fragment b/deploy/storyforge-test-hyzq-nginx.conf.fragment new file mode 100644 index 0000000..554601a --- /dev/null +++ b/deploy/storyforge-test-hyzq-nginx.conf.fragment @@ -0,0 +1,101 @@ +location = /storyforge { + auth_basic off; + return 301 /storyforge/; +} + +location = /storyforge/healthz { + auth_basic off; + proxy_pass http://127.0.0.1:18181/healthz; + 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-Forwarded-Proto $scheme; +} + +location = /storyforge/openapi.json { + auth_basic off; + proxy_pass http://127.0.0.1:18181/openapi.json; + 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-Forwarded-Proto $scheme; +} + +location = /storyforge/api/v1/app/update/latest { + auth_basic off; + proxy_pass http://127.0.0.1:18181/api/v1/app/update/latest; + 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-Forwarded-Proto $scheme; +} + +location ^~ /storyforge/downloads/ { + auth_basic off; + proxy_pass http://127.0.0.1:18181/downloads/; + 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-Forwarded-Proto $scheme; + proxy_read_timeout 300s; + proxy_send_timeout 300s; +} + +location ^~ /storyforge/v2/ { + auth_basic off; + proxy_pass http://127.0.0.1:18181/v2/; + 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-Forwarded-Proto $scheme; + proxy_read_timeout 300s; + proxy_send_timeout 300s; + proxy_buffering off; +} + +location ^~ /storyforge/docs { + auth_basic off; + rewrite ^/storyforge(/docs.*)$ $1 break; + proxy_pass http://127.0.0.1:18181; + 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-Forwarded-Proto $scheme; + proxy_read_timeout 300s; + proxy_send_timeout 300s; + proxy_buffering off; +} + +location ^~ /storyforge/redoc { + auth_basic off; + rewrite ^/storyforge(/redoc.*)$ $1 break; + proxy_pass http://127.0.0.1:18181; + 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-Forwarded-Proto $scheme; + proxy_read_timeout 300s; + proxy_send_timeout 300s; + proxy_buffering off; +} + +location ^~ /storyforge/ { + auth_basic off; + rewrite ^/storyforge/?(.*)$ /$1 break; + proxy_pass http://127.0.0.1:18191; + 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-Forwarded-Proto $scheme; + proxy_read_timeout 300s; + proxy_send_timeout 300s; + proxy_buffering off; +} diff --git a/web/storyforge-web-v4/README.md b/web/storyforge-web-v4/README.md index 299a0d0..1fbb2fd 100644 --- a/web/storyforge-web-v4/README.md +++ b/web/storyforge-web-v4/README.md @@ -14,6 +14,7 @@ - 目录已经从 `output/ui/` 原型区独立出来,并接上了第一层真实业务接口 - 这里面向国内平台的 Web 承载,当前覆盖 `douyin`、`xiaohongshu`、`bilibili`、`kuaishou`、`wechat_video` - `YouTube` 目前明确不在本轮范围内 +- 已支持通过 `https://test.hyzq.net/storyforge/` 做公网访问 - 通用的项目、内容源、复盘、集成等流程可以正常使用 - 平台工作台和运行时数据目前只有 `douyin` 做到了完整实现,其余平台统一按 `待接入工作台` 处理 - 当前保留的核心页面结构: @@ -99,6 +100,14 @@ python3 -m http.server 3918 - `http://127.0.0.1:8081` +如果页面部署在: + +- `https://test.hyzq.net/storyforge/` + +前端会自动把默认后端切到同源的: + +- `https://test.hyzq.net/storyforge` + ## 后续建议 - 继续补多平台各自更深的专属采集与解析能力,而不只是一套统一抽象层 diff --git a/web/storyforge-web-v4/assets/app.js b/web/storyforge-web-v4/assets/app.js index 64828b0..29d0620 100644 --- a/web/storyforge-web-v4/assets/app.js +++ b/web/storyforge-web-v4/assets/app.js @@ -1,5 +1,20 @@ const STORAGE_KEY = "storyforge-web-v4-session"; -const DEFAULT_BACKEND_URL = "http://127.0.0.1:8081"; + +function detectDefaultBackendUrl() { + if (typeof window === "undefined") { + return "http://127.0.0.1:8081"; + } + const { origin, hostname, port, pathname } = window.location; + if (/^https?:/i.test(origin) && pathname.startsWith("/storyforge")) { + return `${origin}/storyforge`; + } + if ((hostname === "127.0.0.1" || hostname === "localhost") && port && port !== "8081") { + return "http://127.0.0.1:8081"; + } + return "http://127.0.0.1:8081"; +} + +const DEFAULT_BACKEND_URL = detectDefaultBackendUrl(); const navButtons = document.querySelectorAll("[data-screen-target]"); const screens = Array.from(document.querySelectorAll("[data-screen]"));