From 94d3b11921ce461e2a6ca76f96d168810d3d89d2 Mon Sep 17 00:00:00 2001 From: yumoqing Date: Thu, 17 Sep 2026 13:45:33 +0800 Subject: [PATCH] chore: commit pending local changes (2026-09-17 github sync) --- i18n/en/msg.txt | 58 ++ i18n/jp/msg.txt | 58 ++ i18n/ko/msg.txt | 58 ++ i18n/zh/msg.txt | 58 ++ scripts/add_home_i18n.py | 263 ++++++ scripts/check_i18n.py | 416 +++++++++ scripts/fix_i18n_w1.py | 64 ++ scripts/fix_i18n_w1_dspy.py | 74 ++ scripts/fix_i18n_w1_dyn.py | 190 ++++ scripts/gen_home_index.py | 306 +++++++ scripts/load_path.py | 3 + scripts/merge_i18n.py | 108 ++- scripts/verify_i18n_fix.py | 34 + wwwroot/home.css | 133 +++ wwwroot/i18n/en/i18n.json | 932 ++++++++++++++++++- wwwroot/i18n/jp/i18n.json | 821 ++++++++++++++++- wwwroot/i18n/ko/i18n.json | 821 ++++++++++++++++- wwwroot/i18n/zh/i18n.json | 913 ++++++++++++++++++- wwwroot/index.ui | 1719 ++++++++++++++++++++++++++++++++++- wwwroot/mine.ui | 2 +- wwwroot/todo_badge.js | 3 +- 21 files changed, 6982 insertions(+), 52 deletions(-) create mode 100644 scripts/add_home_i18n.py create mode 100644 scripts/check_i18n.py create mode 100644 scripts/fix_i18n_w1.py create mode 100644 scripts/fix_i18n_w1_dspy.py create mode 100644 scripts/fix_i18n_w1_dyn.py create mode 100644 scripts/gen_home_index.py create mode 100644 scripts/verify_i18n_fix.py create mode 100644 wwwroot/home.css diff --git a/i18n/en/msg.txt b/i18n/en/msg.txt index 4175916..37b1b56 100644 --- a/i18n/en/msg.txt +++ b/i18n/en/msg.txt @@ -57,3 +57,61 @@ API Key: API Key 我的工单: My Tickets 工单管理: Ticket Management 提交新工单: New Ticket +产线平台: Pipeline Platform +能力: Capabilities +流程: Workflow +登录 / 注册: Sign In / Up +AI 原生 · 产线操作系统: AI-Native · Pipeline Operating System +把业务装进产线: Put Business on Pipelines +让 Agent 自主运转: Let Agents Run It +产线平台是 Agent 驱动的企业智能产线操作系统:商机、投标、开发一键开工,大模型智能体自主推进任务,人类门禁把关质量,产出即产品、跑完即记账。: The Pipeline Platform is an agent-driven enterprise pipeline operating system: launch opportunity, bidding and development lines in one click, let LLM agents advance tasks autonomously, keep humans as quality gates — every output is a product and every run is billed. +查看平台能力: Explore Capabilities +功能模块: Modules +自主运转: Autonomous +语言国际化: Languages +商机挖掘: Opportunity Mining +投标生产: Bid Production +软件开发: Software Development +模型网关: Model Gateway +产品商品化: Productization +计费记账: Billing & Accounting +供销协同: Supply Chain +人机协同门禁: Human-in-the-Loop Gates +平台能力: Platform Capabilities +不是聊天机器人,是一条条能自主干活、能被审计、能直接计费的智能产线。: Not chatbots — intelligent pipelines that work autonomously, stay auditable and bill directly. +Agent 驱动产线引擎: Agent-Driven Pipeline Engine +会话式开工:一句话启动流程,Agent 自动拆解任务、调用大模型、产出交付件;LLM 三层容错兜底,产线不因单点模型故障停摆。: Start by chat: one sentence kicks off a flow; agents decompose tasks, call LLMs and produce deliverables. Three-layer LLM fault tolerance keeps pipelines running through single-model failures. +多供应商大模型统一接入:余额门禁、会话粘性轮询、故障自动路由、按调用出账,密钥不出进程。: Unified access to multi-vendor LLMs: balance gating, sticky session rotation, automatic failover routing and per-call billing — API keys never leave the process. +资源→产品→定价→折扣→订购→计费全链路;显示价按「真实定价×客户折扣」计算,跑产线即消费、即记账。: Full chain from resource to product, pricing, discount, subscription and billing; display price is the real price multiplied by the customer discount. Running a pipeline consumes and books in real time. +平台待办中枢: Platform Todo Hub +全局异步通知中枢:门禁、确认、上传等产线事件统一冒泡为人类待办,同一事项只发一次、处理完自动补位。: The global async notification hub: gates, confirmations and uploads bubble up as human todos — each item is issued once and auto-replenished when handled. +PM 审核、QC 质检、人工确认层层把关——机器的速度,人的判断,审计日志全程可追溯。: PM review, QC inspection and human confirmation at every layer — machine speed with human judgment, fully traceable in audit logs. +安全与多租户: Security & Multi-Tenancy +RBAC 细粒度路径权限、机构隔离、短令牌内部代理、登录审计与失败锁定。: Fine-grained RBAC path permissions, organization isolation, short-lived internal tokens, login audit and lockout. +国际化与双主题: i18n & Dual Themes +中 / 英 / 日 / 韩四语实时切换,明暗双主题一键换装,桌面与手机 H5 同构。: Live switching across Chinese, English, Japanese and Korean; light/dark themes in one click; same experience on desktop and mobile H5. +每条产线都是一个完整的业务闭环:从情报输入到可交付产出,全程 Agent 推进、人类门禁把关。: Every pipeline is a complete business loop: from intelligence input to shippable output, advanced by agents and gated by humans. +招标情报采集 → 商机研判 → 研发报告 → 人工确认,把市场信号变成可跟进的商机。: Tender intelligence collection → opportunity assessment → research reports → human confirmation: turn market signals into followable opportunities. +运行中: Live +标书智能编制:逐项应答评分标准、技术/商务分册生成、材料缺口清单、多轮 QC 门禁。: Intelligent bid document drafting: point-by-point scoring responses, technical/commercial volumes, material gap lists and multi-round QC gates. +SDLC 任务链:需求 → 设计 → 开发 → 测试 → 部署,PM 审核门控 + 交付件管理。: SDLC task chain: requirements → design → development → testing → deployment, with PM review gates and deliverable management. +面向 FOMS 的运维自动化:告警处置、巡检报告、变更编排。: Ops automation for FOMS: alert handling, inspection reports and change orchestration. +规划中: Planned +内容生产与投放自动化:素材生成、渠道分发、效果回收。: Content production and campaign automation: asset generation, channel distribution and performance feedback. +五步跑通一条产线: Five Steps to Run a Pipeline +订阅产线: Subscribe +在产品商城选购产线订阅,账号权益即时生效。: Buy a pipeline subscription in the product store; entitlements take effect instantly. +发起会话: Start a Session +进入产线工作台,用一句话下达任务。: Enter the pipeline workspace and issue a task in one sentence. +Agent 自主执行: Agents Execute +任务拆解、模型调用、交付件产出全程自动推进,可随时插话纠偏。: Task decomposition, model calls and deliverables advance automatically — jump in to steer at any time. +人类门禁: Human Gates +关键节点冒泡为平台待办,人看过正文再放行。: Key checkpoints bubble up as platform todos; humans review the content before release. +交付与记账: Deliver & Bill +产出归档、按量出账,消费明细随时可查。: Outputs are archived and billed by usage; consumption details available anytime. +准备好把业务装上产线了吗?: Ready to put your business on pipelines? +注册账号,订阅第一条产线,让 Agent 今天就开始干活。: Register, subscribe to your first pipeline, and let agents start working today. +立即注册: Register Now +© 2026 开元云(北京)科技有限公司: © 2026 Open Computing (Beijing) Technology Co., Ltd. +登录: Sign In +产线矩阵: Pipeline Matrix diff --git a/i18n/jp/msg.txt b/i18n/jp/msg.txt index 609672d..beeecac 100644 --- a/i18n/jp/msg.txt +++ b/i18n/jp/msg.txt @@ -36,3 +36,61 @@ API Key: API Key 我的工单: マイチケット 工单管理: チケット管理 提交新工单: 新規チケット +产线平台: パイプラインプラットフォーム +能力: 機能 +流程: フロー +登录 / 注册: ログイン / 新規登録 +AI 原生 · 产线操作系统: AIネイティブ・パイプラインOS +把业务装进产线: 業務をパイプラインへ +让 Agent 自主运转: エージェントに自律稼働させる +产线平台是 Agent 驱动的企业智能产线操作系统:商机、投标、开发一键开工,大模型智能体自主推进任务,人类门禁把关质量,产出即产品、跑完即记账。: パイプラインプラットフォームはエージェント駆動の企業向けインテリジェント・パイプラインOSです。商談・入札・開発をワンクリックで開始し、LLMエージェントがタスクを自律的に推進、人間ゲートが品質を管理。成果物はそのまま製品となり、実行と同時に課金・記帳されます。 +查看平台能力: プラットフォーム機能を見る +功能模块: 機能モジュール +自主运转: 自律稼働 +语言国际化: 言語対応 +商机挖掘: 商談発掘 +投标生产: 入札作成 +软件开发: ソフトウェア開発 +模型网关: モデルゲートウェイ +产品商品化: 製品商品化 +计费记账: 課金・記帳 +供销协同: 供給販売連携 +人机协同门禁: 人間協調ゲート +平台能力: プラットフォーム機能 +不是聊天机器人,是一条条能自主干活、能被审计、能直接计费的智能产线。: チャットボットではなく、自律的に動き、監査可能で、直接課金できるインテリジェント・パイプラインです。 +Agent 驱动产线引擎: エージェント駆動パイプラインエンジン +会话式开工:一句话启动流程,Agent 自动拆解任务、调用大模型、产出交付件;LLM 三层容错兜底,产线不因单点模型故障停摆。: 会話で開始:一言でフローを起動し、エージェントがタスクを自動分解、LLMを呼び出し、成果物を生成。LLM三重フォールトトレランスで単一モデル障害でもパイプラインは止まりません。 +多供应商大模型统一接入:余额门禁、会话粘性轮询、故障自动路由、按调用出账,密钥不出进程。: マルチベンダーLLMの統一接続:残高ゲート、セッション粘着ローテーション、障害時自動ルーティング、呼び出し単位課金。APIキーはプロセス外に出ません。 +资源→产品→定价→折扣→订购→计费全链路;显示价按「真实定价×客户折扣」计算,跑产线即消费、即记账。: リソース→製品→価格→割引→注文→課金の全チェーン。表示価格は「実価格×顧客割引」で計算し、パイプライン実行と同時に消費・記帳されます。 +平台待办中枢: プラットフォームToDoハブ +全局异步通知中枢:门禁、确认、上传等产线事件统一冒泡为人类待办,同一事项只发一次、处理完自动补位。: グローバル非同期通知ハブ:ゲート、確認、アップロードなどのイベントが人間のToDoとして統一バブル化。同一事項は一度だけ発行され、処理後は自動補充されます。 +PM 审核、QC 质检、人工确认层层把关——机器的速度,人的判断,审计日志全程可追溯。: PMレビュー、QC検査、人間確認の多層チェック——機械の速度と人間の判断、監査ログで全過程を追跡可能。 +安全与多租户: セキュリティとマルチテナント +RBAC 细粒度路径权限、机构隔离、短令牌内部代理、登录审计与失败锁定。: RBAC細粒度パス権限、組織分離、短命トークン内部プロキシ、ログイン監査と失敗ロックアウト。 +国际化与双主题: 国際化とデュアルテーマ +中 / 英 / 日 / 韩四语实时切换,明暗双主题一键换装,桌面与手机 H5 同构。: 中 / 英 / 日 / 韓の4言語をリアルタイム切替、明暗テーマをワンクリックで切替、デスクトップとモバイルH5で同一体験。 +每条产线都是一个完整的业务闭环:从情报输入到可交付产出,全程 Agent 推进、人类门禁把关。: 各パイプラインは完全な業務ループ:情報入力から納品可能な成果物まで、エージェントが推進し人間ゲートが管理します。 +招标情报采集 → 商机研判 → 研发报告 → 人工确认,把市场信号变成可跟进的商机。: 入札情報収集 → 商談評価 → 調査レポート → 人間確認。市場シグナルを追跡可能な商談に変えます。 +运行中: 稼働中 +标书智能编制:逐项应答评分标准、技术/商务分册生成、材料缺口清单、多轮 QC 门禁。: 入札書類のインテリジェント作成:評価基準への逐項回答、技術/商務分冊生成、資料不足リスト、複数ラウンドのQCゲート。 +SDLC 任务链:需求 → 设计 → 开发 → 测试 → 部署,PM 审核门控 + 交付件管理。: SDLCタスクチェーン:要件 → 設計 → 開発 → テスト → デプロイ、PMレビューゲート+成果物管理。 +面向 FOMS 的运维自动化:告警处置、巡检报告、变更编排。: FOMS向け運用自動化:アラート処理、点検レポート、変更オーケストレーション。 +规划中: 計画中 +内容生产与投放自动化:素材生成、渠道分发、效果回收。: コンテンツ制作と配信の自動化:素材生成、チャネル配信、効果回収。 +五步跑通一条产线: 5ステップでパイプラインを回す +订阅产线: パイプライン購読 +在产品商城选购产线订阅,账号权益即时生效。: 製品ストアでパイプライン購読を購入、アカウント権益は即時有効。 +发起会话: セッション開始 +进入产线工作台,用一句话下达任务。: パイプラインワークスペースに入り、一言でタスクを指示。 +Agent 自主执行: エージェント自律実行 +任务拆解、模型调用、交付件产出全程自动推进,可随时插话纠偏。: タスク分解、モデル呼び出し、成果物生成まで全自動で進行。いつでも割り込んで修正できます。 +人类门禁: 人間ゲート +关键节点冒泡为平台待办,人看过正文再放行。: 重要ノードがプラットフォームToDoとしてバブル化、人間が本文を確認して放行。 +交付与记账: 納品と記帳 +产出归档、按量出账,消费明细随时可查。: 成果物はアーカイブされ使用量に応じて課金、消費明細はいつでも照会可能。 +准备好把业务装上产线了吗?: 業務をパイプラインに乗せる準備はできましたか? +注册账号,订阅第一条产线,让 Agent 今天就开始干活。: アカウントを登録し、最初のパイプラインを購読して、今日からエージェントに働かせましょう。 +立即注册: 今すぐ登録 +© 2026 开元云(北京)科技有限公司: © 2026 開元雲(北京)科技有限公司 +登录: ログイン +产线矩阵: パイプラインマトリクス diff --git a/i18n/ko/msg.txt b/i18n/ko/msg.txt index a772b6a..3432977 100644 --- a/i18n/ko/msg.txt +++ b/i18n/ko/msg.txt @@ -36,3 +36,61 @@ API Key: API Key 我的工单: 내 티켓 工单管理: 티켓 관리 提交新工单: 새 티켓 +产线平台: 파이프라인 플랫폼 +能力: 기능 +流程: 워크플로 +登录 / 注册: 로그인 / 가입 +AI 原生 · 产线操作系统: AI 네이티브 · 파이프라인 운영체제 +把业务装进产线: 업무를 파이프라인에 싣다 +让 Agent 自主运转: 에이전트가 자율 가동 +产线平台是 Agent 驱动的企业智能产线操作系统:商机、投标、开发一键开工,大模型智能体自主推进任务,人类门禁把关质量,产出即产品、跑完即记账。: 파이프라인 플랫폼은 에이전트 기반 기업형 지능 파이프라인 운영체제입니다. 영업기회·입찰·개발을 원클릭으로 시작하고, LLM 에이전트가 작업을 자율 추진하며, 인간 게이트가 품질을 관리합니다. 산출물은 곧 제품이고, 실행 즉시 과금·기장됩니다. +查看平台能力: 플랫폼 기능 보기 +功能模块: 기능 모듈 +自主运转: 자율 가동 +语言国际化: 다국어 지원 +商机挖掘: 영업기회 발굴 +投标生产: 입찰서 생산 +软件开发: 소프트웨어 개발 +模型网关: 모델 게이트웨이 +产品商品化: 제품 상품화 +计费记账: 과금·기장 +供销协同: 공급·판매 연동 +人机协同门禁: 인간 협업 게이트 +平台能力: 플랫폼 기능 +不是聊天机器人,是一条条能自主干活、能被审计、能直接计费的智能产线。: 챗봇이 아니라, 자율적으로 일하고, 감사 가능하며, 직접 과금되는 지능형 파이프라인입니다. +Agent 驱动产线引擎: 에이전트 기반 파이프라인 엔진 +会话式开工:一句话启动流程,Agent 自动拆解任务、调用大模型、产出交付件;LLM 三层容错兜底,产线不因单点模型故障停摆。: 대화로 시작: 한 문장으로 플로를 가동하면 에이전트가 작업을 자동 분해하고 LLM을 호출해 산출물을 생성합니다. LLM 3중 장애 허용으로 단일 모델 장애에도 파이프라인은 멈추지 않습니다. +多供应商大模型统一接入:余额门禁、会话粘性轮询、故障自动路由、按调用出账,密钥不出进程。: 멀티 벤더 LLM 통합 접속: 잔액 게이트, 세션 고정 라운드로빈, 장애 자동 라우팅, 호출 단위 과금. API 키는 프로세스 밖으로 나가지 않습니다. +资源→产品→定价→折扣→订购→计费全链路;显示价按「真实定价×客户折扣」计算,跑产线即消费、即记账。: 리소스→제품→가격→할인→구독→과금 전체 체인. 표시 가격은 「실가격×고객 할인」으로 계산되며, 파이프라인 실행 즉시 소비·기장됩니다. +平台待办中枢: 플랫폼 할 일 허브 +全局异步通知中枢:门禁、确认、上传等产线事件统一冒泡为人类待办,同一事项只发一次、处理完自动补位。: 전역 비동기 알림 허브: 게이트·확인·업로드 등 이벤트가 인간 할 일로 통합 버블됩니다. 동일 사항은 한 번만 발행되고 처리 후 자동 보충됩니다. +PM 审核、QC 质检、人工确认层层把关——机器的速度,人的判断,审计日志全程可追溯。: PM 검토, QC 검사, 인간 확인의 다층 체크——기계의 속도와 인간의 판단, 감사 로그로 전 과정 추적 가능. +安全与多租户: 보안 및 멀티테넌시 +RBAC 细粒度路径权限、机构隔离、短令牌内部代理、登录审计与失败锁定。: RBAC 세분 경로 권한, 조직 격리, 단기 토큰 내부 프록시, 로그인 감사 및 실패 잠금. +国际化与双主题: 국제화 및 듀얼 테마 +中 / 英 / 日 / 韩四语实时切换,明暗双主题一键换装,桌面与手机 H5 同构。: 중 / 영 / 일 / 한 4개 언어 실시간 전환, 밝기/어둠 테마 원클릭 전환, 데스크톱과 모바일 H5 동일 경험. +每条产线都是一个完整的业务闭环:从情报输入到可交付产出,全程 Agent 推进、人类门禁把关。: 각 파이프라인은 완전한 업무 루프: 정보 입력부터 납품 가능한 산출물까지, 에이전트가 추진하고 인간 게이트가 관리합니다. +招标情报采集 → 商机研判 → 研发报告 → 人工确认,把市场信号变成可跟进的商机。: 입찰 정보 수집 → 영업기회 평가 → 조사 보고서 → 인간 확인. 시장 신호를 후속 조치 가능한 영업기회로 변환합니다. +运行中: 가동 중 +标书智能编制:逐项应答评分标准、技术/商务分册生成、材料缺口清单、多轮 QC 门禁。: 입찰서 지능 작성: 평가 기준 항목별 응답, 기술/상업 분책 생성, 자료 누락 목록, 다중 QC 게이트. +SDLC 任务链:需求 → 设计 → 开发 → 测试 → 部署,PM 审核门控 + 交付件管理。: SDLC 작업 체인: 요구 → 설계 → 개발 → 테스트 → 배포, PM 검토 게이트 + 산출물 관리. +面向 FOMS 的运维自动化:告警处置、巡检报告、变更编排。: FOMS 대상 운영 자동화: 알람 처리, 점검 보고서, 변경 오케스트레이션. +规划中: 계획 중 +内容生产与投放自动化:素材生成、渠道分发、效果回收。: 콘텐츠 제작·배포 자동화: 소재 생성, 채널 배포, 효과 회수. +五步跑通一条产线: 5단계로 파이프라인 가동 +订阅产线: 파이프라인 구독 +在产品商城选购产线订阅,账号权益即时生效。: 제품 스토어에서 파이프라인 구독 구매, 계정 권익 즉시 발효. +发起会话: 세션 시작 +进入产线工作台,用一句话下达任务。: 파이프라인 워크스페이스에 들어가 한 문장으로 작업을 지시하세요. +Agent 自主执行: 에이전트 자율 실행 +任务拆解、模型调用、交付件产出全程自动推进,可随时插话纠偏。: 작업 분해, 모델 호출, 산출물 생성까지 전 과정 자동 추진. 언제든 끼어들어 방향을 수정할 수 있습니다. +人类门禁: 인간 게이트 +关键节点冒泡为平台待办,人看过正文再放行。: 핵심 노드가 플랫폼 할 일로 버블되며, 사람이 본문을 확인 후 통과시킵니다. +交付与记账: 납품과 기장 +产出归档、按量出账,消费明细随时可查。: 산출물 아카이브, 사용량 기반 과금, 소비 명세 상시 조회 가능. +准备好把业务装上产线了吗?: 업무를 파이프라인에 실을 준비가 되셨나요? +注册账号,订阅第一条产线,让 Agent 今天就开始干活。: 계정을 가입하고 첫 파이프라인을 구독해, 오늘부터 에이전트에게 일을 시키세요. +立即注册: 지금 가입 +© 2026 开元云(北京)科技有限公司: © 2026 Kaiyuan Cloud (Beijing) Technology Co., Ltd. +登录: 로그인 +产线矩阵: 파이프라인 매트릭스 diff --git a/i18n/zh/msg.txt b/i18n/zh/msg.txt index 19aca56..7879a97 100644 --- a/i18n/zh/msg.txt +++ b/i18n/zh/msg.txt @@ -57,3 +57,61 @@ API Key: API Key 我的工单: 我的工单 工单管理: 工单管理 提交新工单: 提交新工单 +产线平台: 产线平台 +能力: 能力 +流程: 流程 +登录 / 注册: 登录 / 注册 +AI 原生 · 产线操作系统: AI 原生 · 产线操作系统 +把业务装进产线: 把业务装进产线 +让 Agent 自主运转: 让 Agent 自主运转 +产线平台是 Agent 驱动的企业智能产线操作系统:商机、投标、开发一键开工,大模型智能体自主推进任务,人类门禁把关质量,产出即产品、跑完即记账。: 产线平台是 Agent 驱动的企业智能产线操作系统:商机、投标、开发一键开工,大模型智能体自主推进任务,人类门禁把关质量,产出即产品、跑完即记账。 +查看平台能力: 查看平台能力 +功能模块: 功能模块 +自主运转: 自主运转 +语言国际化: 语言国际化 +商机挖掘: 商机挖掘 +投标生产: 投标生产 +软件开发: 软件开发 +模型网关: 模型网关 +产品商品化: 产品商品化 +计费记账: 计费记账 +供销协同: 供销协同 +人机协同门禁: 人机协同门禁 +平台能力: 平台能力 +不是聊天机器人,是一条条能自主干活、能被审计、能直接计费的智能产线。: 不是聊天机器人,是一条条能自主干活、能被审计、能直接计费的智能产线。 +Agent 驱动产线引擎: Agent 驱动产线引擎 +会话式开工:一句话启动流程,Agent 自动拆解任务、调用大模型、产出交付件;LLM 三层容错兜底,产线不因单点模型故障停摆。: 会话式开工:一句话启动流程,Agent 自动拆解任务、调用大模型、产出交付件;LLM 三层容错兜底,产线不因单点模型故障停摆。 +多供应商大模型统一接入:余额门禁、会话粘性轮询、故障自动路由、按调用出账,密钥不出进程。: 多供应商大模型统一接入:余额门禁、会话粘性轮询、故障自动路由、按调用出账,密钥不出进程。 +资源→产品→定价→折扣→订购→计费全链路;显示价按「真实定价×客户折扣」计算,跑产线即消费、即记账。: 资源→产品→定价→折扣→订购→计费全链路;显示价按「真实定价×客户折扣」计算,跑产线即消费、即记账。 +平台待办中枢: 平台待办中枢 +全局异步通知中枢:门禁、确认、上传等产线事件统一冒泡为人类待办,同一事项只发一次、处理完自动补位。: 全局异步通知中枢:门禁、确认、上传等产线事件统一冒泡为人类待办,同一事项只发一次、处理完自动补位。 +PM 审核、QC 质检、人工确认层层把关——机器的速度,人的判断,审计日志全程可追溯。: PM 审核、QC 质检、人工确认层层把关——机器的速度,人的判断,审计日志全程可追溯。 +安全与多租户: 安全与多租户 +RBAC 细粒度路径权限、机构隔离、短令牌内部代理、登录审计与失败锁定。: RBAC 细粒度路径权限、机构隔离、短令牌内部代理、登录审计与失败锁定。 +国际化与双主题: 国际化与双主题 +中 / 英 / 日 / 韩四语实时切换,明暗双主题一键换装,桌面与手机 H5 同构。: 中 / 英 / 日 / 韩四语实时切换,明暗双主题一键换装,桌面与手机 H5 同构。 +每条产线都是一个完整的业务闭环:从情报输入到可交付产出,全程 Agent 推进、人类门禁把关。: 每条产线都是一个完整的业务闭环:从情报输入到可交付产出,全程 Agent 推进、人类门禁把关。 +招标情报采集 → 商机研判 → 研发报告 → 人工确认,把市场信号变成可跟进的商机。: 招标情报采集 → 商机研判 → 研发报告 → 人工确认,把市场信号变成可跟进的商机。 +运行中: 运行中 +标书智能编制:逐项应答评分标准、技术/商务分册生成、材料缺口清单、多轮 QC 门禁。: 标书智能编制:逐项应答评分标准、技术/商务分册生成、材料缺口清单、多轮 QC 门禁。 +SDLC 任务链:需求 → 设计 → 开发 → 测试 → 部署,PM 审核门控 + 交付件管理。: SDLC 任务链:需求 → 设计 → 开发 → 测试 → 部署,PM 审核门控 + 交付件管理。 +面向 FOMS 的运维自动化:告警处置、巡检报告、变更编排。: 面向 FOMS 的运维自动化:告警处置、巡检报告、变更编排。 +规划中: 规划中 +内容生产与投放自动化:素材生成、渠道分发、效果回收。: 内容生产与投放自动化:素材生成、渠道分发、效果回收。 +五步跑通一条产线: 五步跑通一条产线 +订阅产线: 订阅产线 +在产品商城选购产线订阅,账号权益即时生效。: 在产品商城选购产线订阅,账号权益即时生效。 +发起会话: 发起会话 +进入产线工作台,用一句话下达任务。: 进入产线工作台,用一句话下达任务。 +Agent 自主执行: Agent 自主执行 +任务拆解、模型调用、交付件产出全程自动推进,可随时插话纠偏。: 任务拆解、模型调用、交付件产出全程自动推进,可随时插话纠偏。 +人类门禁: 人类门禁 +关键节点冒泡为平台待办,人看过正文再放行。: 关键节点冒泡为平台待办,人看过正文再放行。 +交付与记账: 交付与记账 +产出归档、按量出账,消费明细随时可查。: 产出归档、按量出账,消费明细随时可查。 +准备好把业务装上产线了吗?: 准备好把业务装上产线了吗? +注册账号,订阅第一条产线,让 Agent 今天就开始干活。: 注册账号,订阅第一条产线,让 Agent 今天就开始干活。 +立即注册: 立即注册 +© 2026 开元云(北京)科技有限公司: © 2026 开元云(北京)科技有限公司 +登录: 登录 +产线矩阵: 产线矩阵 diff --git a/scripts/add_home_i18n.py b/scripts/add_home_i18n.py new file mode 100644 index 0000000..4fa1d02 --- /dev/null +++ b/scripts/add_home_i18n.py @@ -0,0 +1,263 @@ +#!/usr/bin/env python3 +"""把主页词条追加进 i18n/{zh,en,jp,ko}/msg.txt(幂等:已存在的 key 跳过)。""" +import io, os + +ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + +T = { +'zh': { +"产线平台": "产线平台", +"能力": "能力", +"流程": "流程", +"登录 / 注册": "登录 / 注册", +"AI 原生 · 产线操作系统": "AI 原生 · 产线操作系统", +"把业务装进产线": "把业务装进产线", +"让 Agent 自主运转": "让 Agent 自主运转", +"产线平台是 Agent 驱动的企业智能产线操作系统:商机、投标、开发一键开工,大模型智能体自主推进任务,人类门禁把关质量,产出即产品、跑完即记账。": "产线平台是 Agent 驱动的企业智能产线操作系统:商机、投标、开发一键开工,大模型智能体自主推进任务,人类门禁把关质量,产出即产品、跑完即记账。", +"查看平台能力": "查看平台能力", +"功能模块": "功能模块", +"自主运转": "自主运转", +"语言国际化": "语言国际化", +"商机挖掘": "商机挖掘", +"投标生产": "投标生产", +"软件开发": "软件开发", +"模型网关": "模型网关", +"产品商品化": "产品商品化", +"计费记账": "计费记账", +"供销协同": "供销协同", +"人机协同门禁": "人机协同门禁", +"平台能力": "平台能力", +"不是聊天机器人,是一条条能自主干活、能被审计、能直接计费的智能产线。": "不是聊天机器人,是一条条能自主干活、能被审计、能直接计费的智能产线。", +"Agent 驱动产线引擎": "Agent 驱动产线引擎", +"会话式开工:一句话启动流程,Agent 自动拆解任务、调用大模型、产出交付件;LLM 三层容错兜底,产线不因单点模型故障停摆。": "会话式开工:一句话启动流程,Agent 自动拆解任务、调用大模型、产出交付件;LLM 三层容错兜底,产线不因单点模型故障停摆。", +"多供应商大模型统一接入:余额门禁、会话粘性轮询、故障自动路由、按调用出账,密钥不出进程。": "多供应商大模型统一接入:余额门禁、会话粘性轮询、故障自动路由、按调用出账,密钥不出进程。", +"资源→产品→定价→折扣→订购→计费全链路;显示价按「真实定价×客户折扣」计算,跑产线即消费、即记账。": "资源→产品→定价→折扣→订购→计费全链路;显示价按「真实定价×客户折扣」计算,跑产线即消费、即记账。", +"平台待办中枢": "平台待办中枢", +"全局异步通知中枢:门禁、确认、上传等产线事件统一冒泡为人类待办,同一事项只发一次、处理完自动补位。": "全局异步通知中枢:门禁、确认、上传等产线事件统一冒泡为人类待办,同一事项只发一次、处理完自动补位。", +"PM 审核、QC 质检、人工确认层层把关——机器的速度,人的判断,审计日志全程可追溯。": "PM 审核、QC 质检、人工确认层层把关——机器的速度,人的判断,审计日志全程可追溯。", +"安全与多租户": "安全与多租户", +"RBAC 细粒度路径权限、机构隔离、短令牌内部代理、登录审计与失败锁定。": "RBAC 细粒度路径权限、机构隔离、短令牌内部代理、登录审计与失败锁定。", +"国际化与双主题": "国际化与双主题", +"中 / 英 / 日 / 韩四语实时切换,明暗双主题一键换装,桌面与手机 H5 同构。": "中 / 英 / 日 / 韩四语实时切换,明暗双主题一键换装,桌面与手机 H5 同构。", +"每条产线都是一个完整的业务闭环:从情报输入到可交付产出,全程 Agent 推进、人类门禁把关。": "每条产线都是一个完整的业务闭环:从情报输入到可交付产出,全程 Agent 推进、人类门禁把关。", +"招标情报采集 → 商机研判 → 研发报告 → 人工确认,把市场信号变成可跟进的商机。": "招标情报采集 → 商机研判 → 研发报告 → 人工确认,把市场信号变成可跟进的商机。", +"运行中": "运行中", +"标书智能编制:逐项应答评分标准、技术/商务分册生成、材料缺口清单、多轮 QC 门禁。": "标书智能编制:逐项应答评分标准、技术/商务分册生成、材料缺口清单、多轮 QC 门禁。", +"SDLC 任务链:需求 → 设计 → 开发 → 测试 → 部署,PM 审核门控 + 交付件管理。": "SDLC 任务链:需求 → 设计 → 开发 → 测试 → 部署,PM 审核门控 + 交付件管理。", +"面向 FOMS 的运维自动化:告警处置、巡检报告、变更编排。": "面向 FOMS 的运维自动化:告警处置、巡检报告、变更编排。", +"规划中": "规划中", +"内容生产与投放自动化:素材生成、渠道分发、效果回收。": "内容生产与投放自动化:素材生成、渠道分发、效果回收。", +"五步跑通一条产线": "五步跑通一条产线", +"订阅产线": "订阅产线", +"在产品商城选购产线订阅,账号权益即时生效。": "在产品商城选购产线订阅,账号权益即时生效。", +"发起会话": "发起会话", +"进入产线工作台,用一句话下达任务。": "进入产线工作台,用一句话下达任务。", +"Agent 自主执行": "Agent 自主执行", +"任务拆解、模型调用、交付件产出全程自动推进,可随时插话纠偏。": "任务拆解、模型调用、交付件产出全程自动推进,可随时插话纠偏。", +"人类门禁": "人类门禁", +"关键节点冒泡为平台待办,人看过正文再放行。": "关键节点冒泡为平台待办,人看过正文再放行。", +"交付与记账": "交付与记账", +"产出归档、按量出账,消费明细随时可查。": "产出归档、按量出账,消费明细随时可查。", +"准备好把业务装上产线了吗?": "准备好把业务装上产线了吗?", +"注册账号,订阅第一条产线,让 Agent 今天就开始干活。": "注册账号,订阅第一条产线,让 Agent 今天就开始干活。", +"立即注册": "立即注册", +"© 2026 开元云(北京)科技有限公司": "© 2026 开元云(北京)科技有限公司", +"登录": "登录", +}, +'en': { +"产线平台": "Pipeline Platform", +"能力": "Capabilities", +"流程": "Workflow", +"登录 / 注册": "Sign In / Up", +"AI 原生 · 产线操作系统": "AI-Native · Pipeline Operating System", +"把业务装进产线": "Put Business on Pipelines", +"让 Agent 自主运转": "Let Agents Run It", +"产线平台是 Agent 驱动的企业智能产线操作系统:商机、投标、开发一键开工,大模型智能体自主推进任务,人类门禁把关质量,产出即产品、跑完即记账。": "The Pipeline Platform is an agent-driven enterprise pipeline operating system: launch opportunity, bidding and development lines in one click, let LLM agents advance tasks autonomously, keep humans as quality gates — every output is a product and every run is billed.", +"查看平台能力": "Explore Capabilities", +"功能模块": "Modules", +"自主运转": "Autonomous", +"语言国际化": "Languages", +"商机挖掘": "Opportunity Mining", +"投标生产": "Bid Production", +"软件开发": "Software Development", +"模型网关": "Model Gateway", +"产品商品化": "Productization", +"计费记账": "Billing & Accounting", +"供销协同": "Supply Chain", +"人机协同门禁": "Human-in-the-Loop Gates", +"平台能力": "Platform Capabilities", +"不是聊天机器人,是一条条能自主干活、能被审计、能直接计费的智能产线。": "Not chatbots — intelligent pipelines that work autonomously, stay auditable and bill directly.", +"Agent 驱动产线引擎": "Agent-Driven Pipeline Engine", +"会话式开工:一句话启动流程,Agent 自动拆解任务、调用大模型、产出交付件;LLM 三层容错兜底,产线不因单点模型故障停摆。": "Start by chat: one sentence kicks off a flow; agents decompose tasks, call LLMs and produce deliverables. Three-layer LLM fault tolerance keeps pipelines running through single-model failures.", +"多供应商大模型统一接入:余额门禁、会话粘性轮询、故障自动路由、按调用出账,密钥不出进程。": "Unified access to multi-vendor LLMs: balance gating, sticky session rotation, automatic failover routing and per-call billing — API keys never leave the process.", +"资源→产品→定价→折扣→订购→计费全链路;显示价按「真实定价×客户折扣」计算,跑产线即消费、即记账。": "Full chain from resource to product, pricing, discount, subscription and billing; display price = real price × customer discount. Running a pipeline consumes and books in real time.", +"平台待办中枢": "Platform Todo Hub", +"全局异步通知中枢:门禁、确认、上传等产线事件统一冒泡为人类待办,同一事项只发一次、处理完自动补位。": "The global async notification hub: gates, confirmations and uploads bubble up as human todos — each item is issued once and auto-replenished when handled.", +"PM 审核、QC 质检、人工确认层层把关——机器的速度,人的判断,审计日志全程可追溯。": "PM review, QC inspection and human confirmation at every layer — machine speed with human judgment, fully traceable in audit logs.", +"安全与多租户": "Security & Multi-Tenancy", +"RBAC 细粒度路径权限、机构隔离、短令牌内部代理、登录审计与失败锁定。": "Fine-grained RBAC path permissions, organization isolation, short-lived internal tokens, login audit and lockout.", +"国际化与双主题": "i18n & Dual Themes", +"中 / 英 / 日 / 韩四语实时切换,明暗双主题一键换装,桌面与手机 H5 同构。": "Live switching across Chinese, English, Japanese and Korean; light/dark themes in one click; same experience on desktop and mobile H5.", +"每条产线都是一个完整的业务闭环:从情报输入到可交付产出,全程 Agent 推进、人类门禁把关。": "Every pipeline is a complete business loop: from intelligence input to shippable output, advanced by agents and gated by humans.", +"招标情报采集 → 商机研判 → 研发报告 → 人工确认,把市场信号变成可跟进的商机。": "Tender intelligence collection → opportunity assessment → research reports → human confirmation: turn market signals into followable opportunities.", +"运行中": "Live", +"标书智能编制:逐项应答评分标准、技术/商务分册生成、材料缺口清单、多轮 QC 门禁。": "Intelligent bid document drafting: point-by-point scoring responses, technical/commercial volumes, material gap lists and multi-round QC gates.", +"SDLC 任务链:需求 → 设计 → 开发 → 测试 → 部署,PM 审核门控 + 交付件管理。": "SDLC task chain: requirements → design → development → testing → deployment, with PM review gates and deliverable management.", +"面向 FOMS 的运维自动化:告警处置、巡检报告、变更编排。": "Ops automation for FOMS: alert handling, inspection reports and change orchestration.", +"规划中": "Planned", +"内容生产与投放自动化:素材生成、渠道分发、效果回收。": "Content production and campaign automation: asset generation, channel distribution and performance feedback.", +"五步跑通一条产线": "Five Steps to Run a Pipeline", +"订阅产线": "Subscribe", +"在产品商城选购产线订阅,账号权益即时生效。": "Buy a pipeline subscription in the product store; entitlements take effect instantly.", +"发起会话": "Start a Session", +"进入产线工作台,用一句话下达任务。": "Enter the pipeline workspace and issue a task in one sentence.", +"Agent 自主执行": "Agents Execute", +"任务拆解、模型调用、交付件产出全程自动推进,可随时插话纠偏。": "Task decomposition, model calls and deliverables advance automatically — jump in to steer at any time.", +"人类门禁": "Human Gates", +"关键节点冒泡为平台待办,人看过正文再放行。": "Key checkpoints bubble up as platform todos; humans review the content before release.", +"交付与记账": "Deliver & Bill", +"产出归档、按量出账,消费明细随时可查。": "Outputs are archived and billed by usage; consumption details available anytime.", +"准备好把业务装上产线了吗?": "Ready to put your business on pipelines?", +"注册账号,订阅第一条产线,让 Agent 今天就开始干活。": "Register, subscribe to your first pipeline, and let agents start working today.", +"立即注册": "Register Now", +"© 2026 开元云(北京)科技有限公司": "© 2026 Open Computing (Beijing) Technology Co., Ltd.", +"登录": "Sign In", +}, +'jp': { +"产线平台": "パイプラインプラットフォーム", +"能力": "機能", +"流程": "フロー", +"登录 / 注册": "ログイン / 新規登録", +"AI 原生 · 产线操作系统": "AIネイティブ・パイプラインOS", +"把业务装进产线": "業務をパイプラインへ", +"让 Agent 自主运转": "エージェントに自律稼働させる", +"产线平台是 Agent 驱动的企业智能产线操作系统:商机、投标、开发一键开工,大模型智能体自主推进任务,人类门禁把关质量,产出即产品、跑完即记账。": "パイプラインプラットフォームはエージェント駆動の企業向けインテリジェント・パイプラインOSです。商談・入札・開発をワンクリックで開始し、LLMエージェントがタスクを自律的に推進、人間ゲートが品質を管理。成果物はそのまま製品となり、実行と同時に課金・記帳されます。", +"查看平台能力": "プラットフォーム機能を見る", +"功能模块": "機能モジュール", +"自主运转": "自律稼働", +"语言国际化": "言語対応", +"商机挖掘": "商談発掘", +"投标生产": "入札作成", +"软件开发": "ソフトウェア開発", +"模型网关": "モデルゲートウェイ", +"产品商品化": "製品商品化", +"计费记账": "課金・記帳", +"供销协同": "供給販売連携", +"人机协同门禁": "人間協調ゲート", +"平台能力": "プラットフォーム機能", +"不是聊天机器人,是一条条能自主干活、能被审计、能直接计费的智能产线。": "チャットボットではなく、自律的に動き、監査可能で、直接課金できるインテリジェント・パイプラインです。", +"Agent 驱动产线引擎": "エージェント駆動パイプラインエンジン", +"会话式开工:一句话启动流程,Agent 自动拆解任务、调用大模型、产出交付件;LLM 三层容错兜底,产线不因单点模型故障停摆。": "会話で開始:一言でフローを起動し、エージェントがタスクを自動分解、LLMを呼び出し、成果物を生成。LLM三重フォールトトレランスで単一モデル障害でもパイプラインは止まりません。", +"多供应商大模型统一接入:余额门禁、会话粘性轮询、故障自动路由、按调用出账,密钥不出进程。": "マルチベンダーLLMの統一接続:残高ゲート、セッション粘着ローテーション、障害時自動ルーティング、呼び出し単位課金。APIキーはプロセス外に出ません。", +"资源→产品→定价→折扣→订购→计费全链路;显示价按「真实定价×客户折扣」计算,跑产线即消费、即记账。": "リソース→製品→価格→割引→注文→課金の全チェーン。表示価格は「実価格×顧客割引」で計算し、パイプライン実行と同時に消費・記帳されます。", +"平台待办中枢": "プラットフォームToDoハブ", +"全局异步通知中枢:门禁、确认、上传等产线事件统一冒泡为人类待办,同一事项只发一次、处理完自动补位。": "グローバル非同期通知ハブ:ゲート、確認、アップロードなどのイベントが人間のToDoとして統一バブル化。同一事項は一度だけ発行され、処理後は自動補充されます。", +"PM 审核、QC 质检、人工确认层层把关——机器的速度,人的判断,审计日志全程可追溯。": "PMレビュー、QC検査、人間確認の多層チェック——機械の速度と人間の判断、監査ログで全過程を追跡可能。", +"安全与多租户": "セキュリティとマルチテナント", +"RBAC 细粒度路径权限、机构隔离、短令牌内部代理、登录审计与失败锁定。": "RBAC細粒度パス権限、組織分離、短命トークン内部プロキシ、ログイン監査と失敗ロックアウト。", +"国际化与双主题": "国際化とデュアルテーマ", +"中 / 英 / 日 / 韩四语实时切换,明暗双主题一键换装,桌面与手机 H5 同构。": "中 / 英 / 日 / 韓の4言語をリアルタイム切替、明暗テーマをワンクリックで切替、デスクトップとモバイルH5で同一体験。", +"每条产线都是一个完整的业务闭环:从情报输入到可交付产出,全程 Agent 推进、人类门禁把关。": "各パイプラインは完全な業務ループ:情報入力から納品可能な成果物まで、エージェントが推進し人間ゲートが管理します。", +"招标情报采集 → 商机研判 → 研发报告 → 人工确认,把市场信号变成可跟进的商机。": "入札情報収集 → 商談評価 → 調査レポート → 人間確認。市場シグナルを追跡可能な商談に変えます。", +"运行中": "稼働中", +"标书智能编制:逐项应答评分标准、技术/商务分册生成、材料缺口清单、多轮 QC 门禁。": "入札書類のインテリジェント作成:評価基準への逐項回答、技術/商務分冊生成、資料不足リスト、複数ラウンドのQCゲート。", +"SDLC 任务链:需求 → 设计 → 开发 → 测试 → 部署,PM 审核门控 + 交付件管理。": "SDLCタスクチェーン:要件 → 設計 → 開発 → テスト → デプロイ、PMレビューゲート+成果物管理。", +"面向 FOMS 的运维自动化:告警处置、巡检报告、变更编排。": "FOMS向け運用自動化:アラート処理、点検レポート、変更オーケストレーション。", +"规划中": "計画中", +"内容生产与投放自动化:素材生成、渠道分发、效果回收。": "コンテンツ制作と配信の自動化:素材生成、チャネル配信、効果回収。", +"五步跑通一条产线": "5ステップでパイプラインを回す", +"订阅产线": "パイプライン購読", +"在产品商城选购产线订阅,账号权益即时生效。": "製品ストアでパイプライン購読を購入、アカウント権益は即時有効。", +"发起会话": "セッション開始", +"进入产线工作台,用一句话下达任务。": "パイプラインワークスペースに入り、一言でタスクを指示。", +"Agent 自主执行": "エージェント自律実行", +"任务拆解、模型调用、交付件产出全程自动推进,可随时插话纠偏。": "タスク分解、モデル呼び出し、成果物生成まで全自動で進行。いつでも割り込んで修正できます。", +"人类门禁": "人間ゲート", +"关键节点冒泡为平台待办,人看过正文再放行。": "重要ノードがプラットフォームToDoとしてバブル化、人間が本文を確認して放行。", +"交付与记账": "納品と記帳", +"产出归档、按量出账,消费明细随时可查。": "成果物はアーカイブされ使用量に応じて課金、消費明細はいつでも照会可能。", +"准备好把业务装上产线了吗?": "業務をパイプラインに乗せる準備はできましたか?", +"注册账号,订阅第一条产线,让 Agent 今天就开始干活。": "アカウントを登録し、最初のパイプラインを購読して、今日からエージェントに働かせましょう。", +"立即注册": "今すぐ登録", +"© 2026 开元云(北京)科技有限公司": "© 2026 開元雲(北京)科技有限公司", +"登录": "ログイン", +}, +'ko': { +"产线平台": "파이프라인 플랫폼", +"能力": "기능", +"流程": "워크플로", +"登录 / 注册": "로그인 / 가입", +"AI 原生 · 产线操作系统": "AI 네이티브 · 파이프라인 운영체제", +"把业务装进产线": "업무를 파이프라인에 싣다", +"让 Agent 自主运转": "에이전트가 자율 가동", +"产线平台是 Agent 驱动的企业智能产线操作系统:商机、投标、开发一键开工,大模型智能体自主推进任务,人类门禁把关质量,产出即产品、跑完即记账。": "파이프라인 플랫폼은 에이전트 기반 기업형 지능 파이프라인 운영체제입니다. 영업기회·입찰·개발을 원클릭으로 시작하고, LLM 에이전트가 작업을 자율 추진하며, 인간 게이트가 품질을 관리합니다. 산출물은 곧 제품이고, 실행 즉시 과금·기장됩니다.", +"查看平台能力": "플랫폼 기능 보기", +"功能模块": "기능 모듈", +"自主运转": "자율 가동", +"语言国际化": "다국어 지원", +"商机挖掘": "영업기회 발굴", +"投标生产": "입찰서 생산", +"软件开发": "소프트웨어 개발", +"模型网关": "모델 게이트웨이", +"产品商品化": "제품 상품화", +"计费记账": "과금·기장", +"供销协同": "공급·판매 연동", +"人机协同门禁": "인간 협업 게이트", +"平台能力": "플랫폼 기능", +"不是聊天机器人,是一条条能自主干活、能被审计、能直接计费的智能产线。": "챗봇이 아니라, 자율적으로 일하고, 감사 가능하며, 직접 과금되는 지능형 파이프라인입니다.", +"Agent 驱动产线引擎": "에이전트 기반 파이프라인 엔진", +"会话式开工:一句话启动流程,Agent 自动拆解任务、调用大模型、产出交付件;LLM 三层容错兜底,产线不因单点模型故障停摆。": "대화로 시작: 한 문장으로 플로를 가동하면 에이전트가 작업을 자동 분해하고 LLM을 호출해 산출물을 생성합니다. LLM 3중 장애 허용으로 단일 모델 장애에도 파이프라인은 멈추지 않습니다.", +"多供应商大模型统一接入:余额门禁、会话粘性轮询、故障自动路由、按调用出账,密钥不出进程。": "멀티 벤더 LLM 통합 접속: 잔액 게이트, 세션 고정 라운드로빈, 장애 자동 라우팅, 호출 단위 과금. API 키는 프로세스 밖으로 나가지 않습니다.", +"资源→产品→定价→折扣→订购→计费全链路;显示价按「真实定价×客户折扣」计算,跑产线即消费、即记账。": "리소스→제품→가격→할인→구독→과금 전체 체인. 표시 가격은 「실가격×고객 할인」으로 계산되며, 파이프라인 실행 즉시 소비·기장됩니다.", +"平台待办中枢": "플랫폼 할 일 허브", +"全局异步通知中枢:门禁、确认、上传等产线事件统一冒泡为人类待办,同一事项只发一次、处理完自动补位。": "전역 비동기 알림 허브: 게이트·확인·업로드 등 이벤트가 인간 할 일로 통합 버블됩니다. 동일 사항은 한 번만 발행되고 처리 후 자동 보충됩니다.", +"PM 审核、QC 质检、人工确认层层把关——机器的速度,人的判断,审计日志全程可追溯。": "PM 검토, QC 검사, 인간 확인의 다층 체크——기계의 속도와 인간의 판단, 감사 로그로 전 과정 추적 가능.", +"安全与多租户": "보안 및 멀티테넌시", +"RBAC 细粒度路径权限、机构隔离、短令牌内部代理、登录审计与失败锁定。": "RBAC 세분 경로 권한, 조직 격리, 단기 토큰 내부 프록시, 로그인 감사 및 실패 잠금.", +"国际化与双主题": "국제화 및 듀얼 테마", +"中 / 英 / 日 / 韩四语实时切换,明暗双主题一键换装,桌面与手机 H5 同构。": "중 / 영 / 일 / 한 4개 언어 실시간 전환, 밝기/어둠 테마 원클릭 전환, 데스크톱과 모바일 H5 동일 경험.", +"每条产线都是一个完整的业务闭环:从情报输入到可交付产出,全程 Agent 推进、人类门禁把关。": "각 파이프라인은 완전한 업무 루프: 정보 입력부터 납품 가능한 산출물까지, 에이전트가 추진하고 인간 게이트가 관리합니다.", +"招标情报采集 → 商机研判 → 研发报告 → 人工确认,把市场信号变成可跟进的商机。": "입찰 정보 수집 → 영업기회 평가 → 조사 보고서 → 인간 확인. 시장 신호를 후속 조치 가능한 영업기회로 변환합니다.", +"运行中": "가동 중", +"标书智能编制:逐项应答评分标准、技术/商务分册生成、材料缺口清单、多轮 QC 门禁。": "입찰서 지능 작성: 평가 기준 항목별 응답, 기술/상업 분책 생성, 자료 누락 목록, 다중 QC 게이트.", +"SDLC 任务链:需求 → 设计 → 开发 → 测试 → 部署,PM 审核门控 + 交付件管理。": "SDLC 작업 체인: 요구 → 설계 → 개발 → 테스트 → 배포, PM 검토 게이트 + 산출물 관리.", +"面向 FOMS 的运维自动化:告警处置、巡检报告、变更编排。": "FOMS 대상 운영 자동화: 알람 처리, 점검 보고서, 변경 오케스트레이션.", +"规划中": "계획 중", +"内容生产与投放自动化:素材生成、渠道分发、效果回收。": "콘텐츠 제작·배포 자동화: 소재 생성, 채널 배포, 효과 회수.", +"五步跑通一条产线": "5단계로 파이프라인 가동", +"订阅产线": "파이프라인 구독", +"在产品商城选购产线订阅,账号权益即时生效。": "제품 스토어에서 파이프라인 구독 구매, 계정 권익 즉시 발효.", +"发起会话": "세션 시작", +"进入产线工作台,用一句话下达任务。": "파이프라인 워크스페이스에 들어가 한 문장으로 작업을 지시하세요.", +"Agent 自主执行": "에이전트 자율 실행", +"任务拆解、模型调用、交付件产出全程自动推进,可随时插话纠偏。": "작업 분해, 모델 호출, 산출물 생성까지 전 과정 자동 추진. 언제든 끼어들어 방향을 수정할 수 있습니다.", +"人类门禁": "인간 게이트", +"关键节点冒泡为平台待办,人看过正文再放行。": "핵심 노드가 플랫폼 할 일로 버블되며, 사람이 본문을 확인 후 통과시킵니다.", +"交付与记账": "납품과 기장", +"产出归档、按量出账,消费明细随时可查。": "산출물 아카이브, 사용량 기반 과금, 소비 명세 상시 조회 가능.", +"准备好把业务装上产线了吗?": "업무를 파이프라인에 실을 준비가 되셨나요?", +"注册账号,订阅第一条产线,让 Agent 今天就开始干活。": "계정을 가입하고 첫 파이프라인을 구독해, 오늘부터 에이전트에게 일을 시키세요.", +"立即注册": "지금 가입", +"© 2026 开元云(北京)科技有限公司": "© 2026 Kaiyuan Cloud (Beijing) Technology Co., Ltd.", +"登录": "로그인", +}, +} + +for lang, items in T.items(): + p = os.path.join(ROOT, 'i18n', lang, 'msg.txt') + existing = set() + with io.open(p, encoding='utf-8') as f: + for line in f: + line = line.strip() + if not line or line.startswith('#'): + continue + k = line.split('=', 1)[0] if '=' in line else line.split(':', 1)[0] + existing.add(k.strip()) + added = 0 + with io.open(p, 'a', encoding='utf-8') as f: + for k, v in items.items(): + if k in existing: + continue + f.write(f'{k}: {v}\n') + added += 1 + print(f'{lang}: +{added} keys (skip {len(items)-added})') diff --git a/scripts/check_i18n.py b/scripts/check_i18n.py new file mode 100644 index 0000000..ea8229f --- /dev/null +++ b/scripts/check_i18n.py @@ -0,0 +1,416 @@ +#!/usr/bin/env python3 +""" +check_i18n.py — 产线平台前端国际化(i18n)检查器 + +框架事实(bricks,决定各违规分类): + - TextBase(Text/Title*):只有 otext + i18n:true 才走翻译;裸 "text" 不翻译 → W1 + - Menu item label / Button label / Form field label / Tabular title / + PopupWindow title / UiCode data.text / placeholder / Message.message: + 组件自动 i18n._(),不需要改文件,只需要词条进字典 → 缺词条记 W2 + - 字典链:模块 i18n//msg.txt|i18n.json → scripts/merge_i18n.py → + wwwroot/i18n//i18n.json → /i18n_getmsgs 端点 → 前端 I18n.msgs + - msg.txt 以 '#' 开头的词条被 appPublic.i18n 解析器当注释丢弃 → W6 + - git-ignored 的 wwwroot/<列表名>/ 是 xls2ui 生成物,禁止直接修改(pre-commit 铁律) + → 生成物只收集 key,不报 W1(要改改 json/ 源 + 重新生成) + +违规分类: + W1 text/otext 硬编码中文且无 i18n 标记(git 跟踪的手写文件才报) + W2 自动翻译组件的中文 key 不在合并字典(en/jp/ko) + W3 手写 JS / dspy 内嵌 script 里硬编码中文提示(应 bricks.app.i18n._) + W4 模块有 UI 但缺 i18n 目录或缺语种 + W5 merge_i18n.py 自动发现覆盖检查(动态调用 discover_modules() 验证) + W6 msg.txt '#' 开头词条(静默丢弃) + W7 动态拼接中文(% / + / f-string)作为可见文本 → 需 otext+i18n 传参重构(仅报告) + +用法: + python3 scripts/check_i18n.py [--repos-dir ~/work/repos] [--json out.json] [-v] +退出码: 0=无违规, 1=有违规 +""" +import os, re, sys, json, subprocess, argparse +from collections import OrderedDict + +SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) +APP_DIR = os.path.dirname(SCRIPT_DIR) +LANGS = ['zh', 'en', 'jp', 'ko'] +CJK = re.compile(r'[\u4e00-\u9fff]') + +SKIP_PATH = [ + re.compile(r'/i18n/'), re.compile(r'/docs?/'), re.compile(r'\.md$'), + re.compile(r'node_modules'), re.compile(r'/\.git/'), re.compile(r'/py3/'), + re.compile(r'/dist/'), re.compile(r'\.bak/'), re.compile(r'\.bak$'), + re.compile(r'/wwwroot/bricks/'), # 框架软链 +] +AUTO_I18N_CTX = ('Menu', 'Button', 'Form', 'InlineForm', 'Tabular', 'PopupWindow', + 'Title', 'Title1', 'Title2', 'Title3', 'Title4', 'Error') + + +def skip(path): + return any(p.search(path) for p in SKIP_PATH) + + +def git_repo_root(path): + d = path if os.path.isdir(path) else os.path.dirname(path) + try: + return subprocess.run(['git', '-C', d, 'rev-parse', '--show-toplevel'], + capture_output=True, text=True, timeout=10).stdout.strip() + except Exception: + return None + + +_ignored_cache = {} +def git_ignored(path, repo): + key = (repo, path) + if key in _ignored_cache: + return _ignored_cache[key] + try: + r = subprocess.run(['git', '-C', repo, 'check-ignore', '-q', path], + capture_output=True, timeout=10) + v = (r.returncode == 0) + except Exception: + v = False + _ignored_cache[key] = v + return v + + +def load_modules(repos_dir): + mods = [] + build_sh = os.path.join(APP_DIR, 'build.sh') + if os.path.exists(build_sh): + content = open(build_sh, encoding='utf-8').read() + for m in re.finditer(r'^for mod in ([^;]+); do\s*$', content, re.M): + for name in m.group(1).split(): + if name not in mods: + mods.append(name) + for name in ['pipeline_core', 'pipeline_ops']: + if name not in mods: + mods.insert(0, name) + result = OrderedDict() + result['app'] = APP_DIR + for name in mods: + for cand in (os.path.join(repos_dir, name), os.path.join(APP_DIR, 'pkgs', name), + os.path.join(APP_DIR, name)): + if os.path.isdir(cand): + result[name] = cand + break + else: + result[name] = None + return result + + +def iter_files(root, exts): + for dirpath, dirnames, filenames in os.walk(root): + dirnames[:] = [d for d in dirnames + if d not in ('.git', 'py3', 'node_modules', 'dist', '__pycache__', 'i18n')] + for fn in filenames: + if fn.endswith(exts): + p = os.path.join(dirpath, fn) + if not skip(p): + yield p + + +def merged_dict(lang): + fp = os.path.join(APP_DIR, 'wwwroot', 'i18n', lang, 'i18n.json') + if os.path.exists(fp): + try: + return json.load(open(fp, encoding='utf-8')) + except Exception: + return {} + return {} + + +def in_code_data_array(raw, pos): + """判断位置是否处于 code 选项 data 数组的 {"value":..,"text":..} 上下文。""" + s = max(0, pos - 300) + ctx = raw[s:pos] + return '"value"' in ctx and ctx.rfind('"data"') >= 0 or \ + re.search(r'\{\s*"value"\s*:[^}]*$', ctx) is not None + + +def scan_ui(path, keys, viol, tracked): + raw = open(path, encoding='utf-8', errors='replace').read() + repo = git_repo_root(path) + ign = repo and git_ignored(path, repo) + for m in re.finditer(r'"(label|title|text|otext|placeholder|message|description)"\s*:\s*"([^"]*)"', raw): + field, val = m.group(1), m.group(2) + if not CJK.search(val) or val.startswith('{{'): + continue + s = max(0, m.start() - 400); e = min(len(raw), m.end() + 400) + ctx = raw[s:e] + has_i18n = re.search(r'"i18n"\s*:\s*true', ctx) is not None + has_otext = '"otext"' in ctx + if field == 'otext': + if has_i18n: + keys.add(val) + else: + viol.append((path, m.start(), 'W1', 'otext 无 i18n:true', val, ign)) + elif field == 'text': + if has_i18n or has_otext: + keys.add(val) + elif in_code_data_array(raw, m.start()): + keys.add(val) # UiCode/Tabular 渲染 code 值自动 i18n._ (input.js:1232) + else: + # Text 裸 text 不翻译 + if ign: + keys.add(val) # 生成物:改 json 源+重新生成,这里只收 key + else: + viol.append((path, m.start(), 'W1', 'text 硬编码中文(应 otext+i18n:true)', val, ign)) + else: + keys.add(val) # label/title/placeholder/message/description 组件自动翻译 + # 内嵌 script 里的中文提示 + for m in re.finditer(r'(show_message|show_error|bricks\.Message|bricks\.Error)\s*\(\s*\{[^}]{0,200}?(title|message)\s*:\s*[\'"]([^\'"]*)[\'"]', raw): + val = m.group(3) + if CJK.search(val): + keys.add(val) # Message.message 自动 i18n(message.js:25),title 走 PopupWindow 自动 i18n + # 动态拼接 + for m in re.finditer(r'"text"\s*:\s*("[^"]*"\s*[%+][^,}]*)', raw): + seg = m.group(1) + if CJK.search(seg) and '{{' not in seg: + viol.append((path, m.start(), 'W7', '动态拼接中文文本(需 otext+参数重构)', seg[:60], ign)) + + +DSPY_UI_KEYS = re.compile(r"['\"](label|title|otext|placeholder|message|description)['\"]\s*:\s*(['\"])([^'\"]*)\2") +DSPY_TEXT = re.compile(r"['\"]text['\"]\s*:\s*(?:(['\"])([^'\"]*)\1|(\(?\s*['\"][^'\"]*['\"]\s*[%+][^)\n]*\)?))") + +def scan_dspy(path, keys, viol): + raw = open(path, encoding='utf-8', errors='replace').read() + if 'widgettype' not in raw and 'mdtext' not in raw: + return + repo = git_repo_root(path) + ign = repo and git_ignored(path, repo) + for m in DSPY_UI_KEYS.finditer(raw): + field, val = m.group(1), m.group(3) + if not CJK.search(val) or val.startswith('{{'): + continue + s = max(0, m.start() - 500); e = min(len(raw), m.end() + 500) + ctx = raw[s:e] + has_i18n = re.search(r"['\"]i18n['\"]\s*:\s*True", ctx) is not None + if field == 'otext': + if has_i18n: + keys.add(val) + else: + viol.append((path, m.start(), 'W1', 'dspy otext 无 i18n:True', val, ign)) + else: + keys.add(val) + for m in DSPY_TEXT.finditer(raw): + if m.group(2) is not None: + val = m.group(2) + if not CJK.search(val): + continue + s = max(0, m.start() - 500); e = min(len(raw), m.end() + 500) + ctx = raw[s:e] + if re.search(r"['\"]i18n['\"]\s*:\s*True", ctx) or "'otext'" in ctx or '"otext"' in ctx \ + or in_code_data_array(raw, m.start()): + keys.add(val) + elif ign: + keys.add(val) + else: + viol.append((path, m.start(), 'W1', 'dspy text 硬编码中文(应 otext+i18n:True)', val, ign)) + else: + seg = m.group(3) or '' + if CJK.search(seg): + viol.append((path, m.start(), 'W7', 'dspy 动态拼接中文文本', seg[:60], ign)) + for m in re.finditer(r"(?:show_message|show_error)\s*\(\s*\{[^}]{0,200}?(?:title|message)['\"]?\s*[:=]\s*['\"]([^'\"]*)['\"]", raw): + val = m.group(1) + if CJK.search(val): + keys.add(val) + + +def strip_js_comments(raw): + """粗剥离 // 与 /* */ 注释(不处理字符串内含 // 的极端情形,够用)。""" + out = [] + i, n = 0, len(raw) + in_s = None + while i < n: + c = raw[i] + if in_s: + out.append(c) + if c == '\\' and i + 1 < n: + out.append(raw[i+1]); i += 2; continue + if c == in_s: + in_s = None + i += 1; continue + if c in ('"', "'", '`'): + in_s = c; out.append(c); i += 1; continue + if c == '/' and i + 1 < n and raw[i+1] == '/': + while i < n and raw[i] != '\n': + i += 1 + continue + if c == '/' and i + 1 < n and raw[i+1] == '*': + i += 2 + while i + 1 < n and not (raw[i] == '*' and raw[i+1] == '/'): + i += 1 + i += 2 + continue + out.append(c); i += 1 + return ''.join(out) + + +def scan_js(path, keys, viol): + raw = open(path, encoding='utf-8', errors='replace').read() + code = strip_js_comments(raw) + repo = git_repo_root(path) + ign = repo and git_ignored(path, repo) + # i18n-aware 文件:定义了 _t()/i18n._ 辅助函数,对象字面量里的中文是「词条 key」 + # 而非硬编码显示文本(如 showcase.js MEDIA_LABEL_KEYS,经 mediaLabel→_t 翻译) + has_i18n_helper = bool(re.search(r'function\s+_t\s*\(|(?:var|const|let)\s+_t\s*=|i18n\._', code)) + # 所有含中文的字符串字面量:不在 i18n._() 内、不在 Message/show_message 上下文 → W3 + for m in re.finditer(r"(['\"])([^'\"\n]*[\u4e00-\u9fff][^'\"\n]*)\1", code): + val = m.group(2) + pre = code[max(0, m.start() - 80):m.start()] + if 'i18n._' in pre[-30:] or re.search(r'(?:^|[^.\w])_t\(\s*$', pre): + keys.add(val) + continue + ctx = code[max(0, m.start() - 200):m.end()] + if re.search(r'(show_message|show_error|bricks\.Message|bricks\.Error)\s*\(\s*\{[^}]*$', ctx): + keys.add(val) # Message title/message 自动翻译 + continue + if re.search(r'(title|message|label)\s*:\s*$', pre): + keys.add(val) # 组件 option 自动翻译 + continue + if has_i18n_helper and re.search(r'[\w\'\"]+\s*:\s*$', pre): + keys.add(val) # i18n-aware 文件的对象字面量中文值 = 词条 key + continue + viol.append((path, m.start(), 'W3', 'js 硬编码中文(应 bricks.app.i18n._ 或组件词条)', val, ign)) + + +def check_infra(modules, merge_py): + issues = [] + # W5 动态验证:直接调用 merge_i18n.discover_modules(),模块的 i18n 目录 + # 能被自动发现即通过(2026-09-14:merge 已重写为自动发现,旧版按源码文本 + # 扫描 MODULES 清单会把所有模块误报为漏) + discovered = set() + try: + import importlib.util + spec = importlib.util.spec_from_file_location('merge_i18n_mod', merge_py) + if spec is not None and spec.loader is not None: + mmod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mmod) + discovered = {n for n, _ in mmod.discover_modules()} + else: + print(f'!! merge_i18n.py 无法加载: {merge_py}', file=sys.stderr) + except Exception as e: + print(f'!! 无法调用 merge_i18n.discover_modules(): {e}', file=sys.stderr) + for name, path in modules.items(): + if path is None or not os.path.isdir(path): + continue + ui_files = list(iter_files(path, ('.ui',))) + has_ui = bool(ui_files) + if not has_ui: + n = 0 + for f in iter_files(path, ('.dspy',)): + raw = open(f, encoding='utf-8', errors='replace').read(4000) + if 'widgettype' in raw: + has_ui = True + break + n += 1 + if n > 300: + break + i18n_dir = os.path.join(path, 'i18n') + if has_ui: + if not os.path.isdir(i18n_dir): + issues.append((name, 'W4', '有 UI 文件但无 i18n/ 目录')) + else: + missing = [l for l in LANGS + if not os.path.exists(os.path.join(i18n_dir, l, 'msg.txt')) + and not os.path.exists(os.path.join(i18n_dir, l, 'i18n.json'))] + if missing: + issues.append((name, 'W4', 'i18n 缺语种: ' + ','.join(missing))) + if name != 'app' and name not in discovered: + issues.append((name, 'W5', 'i18n/ 未被 merge_i18n.discover_modules() 发现')) + for lang in LANGS: + fp = os.path.join(path, 'i18n', lang, 'msg.txt') + if os.path.exists(fp): + for i, line in enumerate(open(fp, encoding='utf-8', errors='replace'), 1): + ls = line.strip() + if ls and ls.startswith('#') and (':' in ls or '=' in ls): + issues.append((name, 'W6', f'i18n/{lang}/msg.txt:{i} #词条被丢弃: {ls[:50]}')) + return issues + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument('--repos-dir', default=os.path.expanduser('~/work/repos')) + ap.add_argument('--json', default=None) + ap.add_argument('-v', '--verbose', action='store_true') + args = ap.parse_args() + + modules = load_modules(args.repos_dir) + dicts = {l: merged_dict(l) for l in LANGS} + all_keys = {} + violations = [] + per_mod = OrderedDict() + + for name, path in modules.items(): + if path is None or not os.path.isdir(path): + per_mod[name] = {'status': 'missing'} + continue + keys, viols = set(), [] + roots = [path] + for f in iter_files(path, ('.ui',)): + scan_ui(f, keys, viols, None) + for f in iter_files(path, ('.dspy',)): + scan_dspy(f, keys, viols) + wr = os.path.join(path, 'wwwroot') + if os.path.isdir(wr): + for f in iter_files(wr, ('.js',)): + scan_js(f, keys, viols) + for k in keys: + all_keys.setdefault(k, set()).add(name) + violations.extend(viols) + per_mod[name] = {'keys': len(keys), 'violations': len(viols)} + + missing_dict = {} + for key, mods in sorted(all_keys.items()): + for lang in ('en', 'jp', 'ko'): + if key not in dicts[lang]: + missing_dict.setdefault(lang, []).append({'key': key, 'modules': sorted(mods)}) + + infra = check_infra(modules, os.path.join(APP_DIR, 'scripts', 'merge_i18n.py')) + + cnt = {} + for v in violations: + cnt[v[2]] = cnt.get(v[2], 0) + 1 + w4 = [i for i in infra if i[1] == 'W4'] + w5 = [i for i in infra if i[1] == 'W5'] + w6 = [i for i in infra if i[1] == 'W6'] + + print('=' * 62) + print('产线平台 i18n 检查报告') + print('=' * 62) + print(f"模块数: {len([1 for p in modules.values() if p])}") + print(f"抽取可见中文 key(去重): {len(all_keys)}") + print(f"W1 硬编码未标i18n: {cnt.get('W1',0)} W3 js硬编码: {cnt.get('W3',0)} W7 动态拼接: {cnt.get('W7',0)}") + print(f"W2 字典缺失: en={len(missing_dict.get('en',[]))} jp={len(missing_dict.get('jp',[]))} ko={len(missing_dict.get('ko',[]))}") + print(f"W4 缺i18n目录/语种: {len(w4)} W5 merge漏模块: {len(w5)} W6 #词条: {len(w6)}") + if w5: + print(f" W5 漏: {[i[0] for i in w5]}") + if w4: + print(f" W4: {[(i[0], i[2][:30]) for i in w4]}") + print('-' * 62) + for name, st in per_mod.items(): + if 'keys' in st: + flag = ' <-- !' if st['violations'] else '' + print(f" {name:24s} keys={st['keys']:4d} viol={st['violations']:3d}{flag}") + if args.verbose: + print('-' * 62) + for v in violations: + tag = ' [git-ignored]' if v[5] else '' + print(f" [{v[2]}] {v[0]}@{v[1]}{tag}: {v[3]} | {v[4][:60]}") + if args.json: + json.dump({ + 'summary': {'keys': len(all_keys), 'viol': cnt, + 'W2': {l: len(missing_dict.get(l, [])) for l in ('en','jp','ko')}, + 'W4': len(w4), 'W5': len(w5), 'W6': len(w6)}, + 'violations': [{'file': v[0], 'pos': v[1], 'code': v[2], 'why': v[3], + 'text': v[4], 'git_ignored': bool(v[5])} for v in violations], + 'missing_dict': missing_dict, + 'keys': {k: sorted(v) for k, v in sorted(all_keys.items())}, + 'infra': [{'module': i[0], 'code': i[1], 'detail': i[2]} for i in infra], + }, open(args.json, 'w', encoding='utf-8'), ensure_ascii=False, indent=1) + print(f'JSON 报告: {args.json}') + total = sum(cnt.values()) + sum(len(v) for v in missing_dict.values()) + len(infra) + return 1 if total else 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/scripts/fix_i18n_w1.py b/scripts/fix_i18n_w1.py new file mode 100644 index 0000000..cf0d8e4 --- /dev/null +++ b/scripts/fix_i18n_w1.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 +""" +fix_i18n_w1.py — 批量修复 W1:给硬编码中文 text 加 otext+i18n 标记 +基于 check_i18n.py --json 报告的 violations(W1 且 git_ignored=False), +按 pos 从后往前精准插入,保持文件其余部分逐字节不变。 + +.ui: "text": "中文" → "otext": "中文", "text": "中文", "i18n": true +.dspy: 'text': '中文' → 'otext': '中文', 'text': '中文', 'i18n': True (引号风格跟随原文) +otext 无 i18n 的: "otext": "中文" → "otext": "中文", "i18n": true + +用法: python3 scripts/fix_i18n_w1.py /tmp/i18n.json [--dry-run] +""" +import json, re, sys +from collections import defaultdict + +def main(): + report = json.load(open(sys.argv[1], encoding='utf-8')) + dry = '--dry-run' in sys.argv + viols = [v for v in report['violations'] if v['code'] == 'W1' and not v['git_ignored']] + by_file = defaultdict(list) + for v in viols: + by_file[v['file']].append(v) + + total_fixed = 0 + errors = [] + for fp, vs in sorted(by_file.items()): + raw = open(fp, encoding='utf-8').read() + is_ui = fp.endswith('.ui') + q_t = 'true' if is_ui else 'True' + # 从后往前改,pos 不漂移 + for v in sorted(vs, key=lambda x: -x['pos']): + pos = v['pos'] + # 在 pos 处重新匹配完整 key-value 片段 + if v['why'].startswith('dspy otext') or v['why'].startswith('otext'): + m = re.compile(r'(["\'])otext\1\s*:\s*(["\'])(.*?)\2').match(raw, pos) + if not m: + errors.append((fp, pos, 'otext 片段定位失败')) + continue + if '"i18n"' in raw[m.end():m.end()+40] or "'i18n'" in raw[m.end():m.end()+40]: + continue # 已有 i18n 标记(可能重复报告) + ins = f', {m.group(1)}i18n{m.group(1)}: {q_t}' + raw = raw[:m.end()] + ins + raw[m.end():] + total_fixed += 1 + else: + m = re.compile(r'(["\'])text\1\s*:\s*(["\'])(.*?)\2').match(raw, pos) + if not m: + errors.append((fp, pos, 'text 片段定位失败')) + continue + q, val = m.group(1), m.group(3) + ins = f', {q}otext{q}: {q}{val}{q}, {q}i18n{q}: {q_t}' + # 在 "text": "val" 前插 otext,在其后插 i18n: + # 结果形如 "otext": "val", "text": "val", "i18n": true + new_seg = f'{q}otext{q}: {q}{val}{q}, {q}text{q}: {q}{val}{q}, {q}i18n{q}: {q_t}' + raw = raw[:m.start()] + new_seg + raw[m.end():] + total_fixed += 1 + if not dry: + open(fp, 'w', encoding='utf-8').write(raw) + + print(f'{"DRY-RUN " if dry else ""}fixed={total_fixed} files={len(by_file)} errors={len(errors)}') + for e in errors[:20]: + print(' ERR', e) + +if __name__ == '__main__': + main() diff --git a/scripts/fix_i18n_w1_dspy.py b/scripts/fix_i18n_w1_dspy.py new file mode 100644 index 0000000..86cbdb9 --- /dev/null +++ b/scripts/fix_i18n_w1_dspy.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python3 +""" +fix_i18n_w1_dspy.py — dspy 安全修复 W1(保守策略) +只处理纯字面量 "text": "中文"(match 后第一个非空白字符是 , 或 }), +跳过所有拼接(+)、多行隐式连接(后跟换行+字符串)、变量插值——那些记入 manual 清单。 + +替换: "text": "X" → "otext": "X", "text": "X", "i18n": True +引号风格跟随原文(' 或 ")。 +用法: python3 scripts/fix_i18n_w1_dspy.py /tmp/i18n.json [--dry-run] +""" +import json, re, sys +from collections import defaultdict + +TEXT_RE = re.compile(r'''(['"])text\1\s*:\s*(['"])((?:[^'"\\]|\\.)*)\2''') + +def safe_literal(raw, m): + """match 后第一个非空白字符必须是 , 或 }(排除拼接与多行隐式连接)""" + j = m.end() + while j < len(raw) and raw[j] in ' \t': + j += 1 + return j < len(raw) and raw[j] in ',}' + +def main(): + report = json.load(open(sys.argv[1], encoding='utf-8')) + dry = '--dry-run' in sys.argv + viols = [v for v in report['violations'] + if v['code'] == 'W1' and not v['git_ignored'] and v['file'].endswith('.dspy')] + by_file = defaultdict(list) + for v in viols: + by_file[v['file']].append(v) + + fixed = manual = 0 + manual_list = [] + for fp, vs in sorted(by_file.items()): + raw = open(fp, encoding='utf-8').read() + # 从后往前 + changed = False + for v in sorted(vs, key=lambda x: -x['pos']): + pos = v['pos'] + m = TEXT_RE.match(raw, pos) + if not m: + # otext 无 i18n 的情形 + mo = re.compile(r'''(['"])otext\1\s*:\s*(['"])((?:[^'"\\]|\\.)*)\2''').match(raw, pos) + if mo and not re.search(r"['\"]i18n['\"]\s*:\s*True", raw[mo.end():mo.end()+60]): + if safe_literal(raw, mo): + ins = f', {mo.group(1)}i18n{mo.group(1)}: True' + if not dry: + raw = raw[:mo.end()] + ins + raw[mo.end():] + fixed += 1; changed = True + else: + manual += 1; manual_list.append((fp, pos, 'otext动态', v['text'][:50])) + else: + manual += 1; manual_list.append((fp, pos, '无法定位', v['text'][:50])) + continue + val = m.group(3) + if not safe_literal(raw, m): + manual += 1 + manual_list.append((fp, pos, '拼接/多行串', val[:50])) + continue + q1, q2 = m.group(1), m.group(2) + seg = raw[m.start():m.end()] + new_seg = f'{q1}otext{q1}: {q2}{val}{q2}, {q1}text{q1}: {q2}{val}{q2}, {q1}i18n{q1}: True' + if not dry: + raw = raw[:m.start()] + new_seg + raw[m.end():] + fixed += 1; changed = True + if changed and not dry: + open(fp, 'w', encoding='utf-8').write(raw) + + print(f'{"DRY-RUN " if dry else ""}fixed={fixed} manual={manual} files={len(by_file)}') + for mm in manual_list[:40]: + print(' MANUAL', mm[0].split('/repos/')[-1], f'@{mm[1]}', mm[2], '|', mm[3]) + +if __name__ == '__main__': + main() diff --git a/scripts/fix_i18n_w1_dyn.py b/scripts/fix_i18n_w1_dyn.py new file mode 100644 index 0000000..8ff34ea --- /dev/null +++ b/scripts/fix_i18n_w1_dyn.py @@ -0,0 +1,190 @@ +#!/usr/bin/env python3 +""" +fix_i18n_w1_dyn.py — dspy 动态串 i18n 重构(AST 安全) +把 `"text": EXPR`(EXPR 含拼接/格式化)重构为: + "otext": TEMPLATE, "text": TEMPLATE, "i18n": True, "i18n_params": {p0:..,p1:..} +TEMPLATE 用 ${p0}/${p1} 占位;i18n_params 提供 JSON 可序列化的值。 +依赖框架 widget.js 的 i18n_params 支持(TextBase.set_attrs → i18n._(otext, params))。 + +只处理 ast 能解析的 Add 链 / Mod 格式化 / 纯常量(多行隐式拼接); +解析失败的记 manual,绝不破坏文件。 +用法: python3 scripts/fix_i18n_w1_dyn.py /tmp/i18n.json [--dry-run] +""" +import json, re, sys, ast +from collections import defaultdict + +PRINTF_SPEC = re.compile(r'%(?:\(\w+\))?[-+ #0]*\d*(?:\.\d+)?[hlL]?[diouxXeEfFgGcrsa%]') + + +def find_value_expr(raw, after_colon): + """从 after_colon("text": 之后)深度扫描出值表达式 [start,end)。""" + i = after_colon + n = len(raw) + while i < n and raw[i] in ' \t\r\n': + i += 1 + start = i + depth = 0 + in_s = None + while i < n: + c = raw[i] + if in_s: + if c == '\\': + i += 2; continue + if c == in_s: + in_s = None + i += 1; continue + if c in '"\'': + in_s = c; i += 1; continue + if c in '([{': + depth += 1; i += 1; continue + if c in ')]}': + if depth == 0: + return start, i # 闭合外层结构 = 值结束 + depth -= 1; i += 1; continue + if c == ',' and depth == 0: + return start, i + i += 1 + return start, n + + +def src_of(node, expr_src): + try: + return ast.get_source_segment(expr_src, node) + except Exception: + return None + + +def build_template_and_params(expr_src): + """返回 (template_str, params_dict_src, ok, reason)。params_dict_src 是 Python 源码片段。""" + expr_src = expr_src.strip() + try: + node = ast.parse(expr_src, mode='eval').body + except Exception as e: + return None, None, False, f'ast解析失败:{e}' + + # 纯常量字符串(含多行隐式拼接)→ 无参数 + if isinstance(node, ast.Constant) and isinstance(node.value, str): + return node.value, None, True, 'const' + + params = [] + # Mod 格式化: "FMT" % args + if isinstance(node, ast.BinOp) and isinstance(node.op, ast.Mod) \ + and isinstance(node.left, ast.Constant) and isinstance(node.left.value, str): + fmt = node.left.value + right = node.right + if isinstance(right, ast.Tuple): + arg_srcs = [src_of(e, expr_src) for e in right.elts] + else: + arg_srcs = [src_of(right, expr_src)] + if any(a is None for a in arg_srcs): + return None, None, False, 'mod参数源提取失败' + # 走 fmt,把 spec 换 ${pN} + out = [] + ai = 0 + last = 0 + for m in PRINTF_SPEC.finditer(fmt): + out.append(fmt[last:m.start()]) + spec = m.group(0) + if spec == '%%': + out.append('%') + else: + pname = f'p{ai}' + out.append('${' + pname + '}') + if ai >= len(arg_srcs): + return None, None, False, 'mod参数数不足' + # 每个参数用自身 spec 重新格式化,保证显示一致 + JSON 可序列化 + params.append((pname, f'str({spec!r} % ({arg_srcs[ai]},))' + if spec[-1] in 'diouxXeEfFgG' else + f'str({arg_srcs[ai]})')) + ai += 1 + last = m.end() + out.append(fmt[last:]) + template = ''.join(out) + if ai != len(arg_srcs): + return None, None, False, f'mod参数数不匹配 spec={ai} args={len(arg_srcs)}' + pd = '{' + ', '.join(f'"{k}": {v}' for k, v in params) + '}' if params else None + return template, pd, True, 'mod' + + # Add 拼接链 + parts = [] + def flatten(n): + if isinstance(n, ast.BinOp) and isinstance(n.op, ast.Add): + flatten(n.left); flatten(n.right) + else: + parts.append(n) + flatten(node) + template_pieces = [] + pi = 0 + has_dyn = False + for p in parts: + if isinstance(p, ast.Constant) and isinstance(p.value, str): + template_pieces.append(p.value) + else: + s = src_of(p, expr_src) + if s is None: + return None, None, False, 'add操作数源提取失败' + pname = f'p{pi}'; pi += 1 + template_pieces.append('${' + pname + '}') + params.append((pname, f'str({s})')) + has_dyn = True + if not has_dyn: + # 全是字符串常量拼接 → 合并 + return ''.join(template_pieces), None, True, 'const-concat' + template = ''.join(template_pieces) + pd = '{' + ', '.join(f'"{k}": {v}' for k, v in params) + '}' if params else None + return template, pd, True, 'add' + + +def main(): + report = json.load(open(sys.argv[1], encoding='utf-8')) + dry = '--dry-run' in sys.argv + viols = [v for v in report['violations'] + if v['code'] == 'W1' and not v['git_ignored'] and v['file'].endswith('.dspy')] + by_file = defaultdict(list) + for v in viols: + by_file[v['file']].append(v) + + fixed = manual = 0 + manual_list = [] + keys_added = [] + for fp, vs in sorted(by_file.items()): + raw = open(fp, encoding='utf-8').read() + changed = False + for v in sorted(vs, key=lambda x: -x['pos']): + pos = v['pos'] + mk = re.compile(r'''(['"])(text|otext)\1\s*:''').match(raw, pos) + if not mk: + manual += 1; manual_list.append((fp, pos, 'key定位失败', v['text'][:40])); continue + keyname = mk.group(2); q = mk.group(1) + vstart, vend = find_value_expr(raw, mk.end()) + expr_src = raw[vstart:vend] + tmpl, pd, ok, why = build_template_and_params(expr_src) + if not ok: + manual += 1; manual_list.append((fp, pos, why, expr_src[:50])); continue + # 转义模板里的双引号/反斜杠进 JSON 字符串 + tmpl_json = tmpl.replace('\\', '\\\\').replace('"', '\\"') + if keyname == 'otext' and pd is None and '不可退费' in tmpl: + # 仅缺 i18n:True + ins = f', {q}i18n{q}: True' + seg_new = raw[pos:vend] + ins + else: + params_part = f', {q}i18n_params{q}: {pd}' if pd else '' + seg_new = (f'{q}otext{q}: "{tmpl_json}", {q}text{q}: "{tmpl_json}", ' + f'{q}i18n{q}: True{params_part}') + if not dry: + raw = raw[:pos] + seg_new + raw[vend:] + keys_added.append(tmpl) + fixed += 1; changed = True + if changed and not dry: + open(fp, 'w', encoding='utf-8').write(raw) + + print(f'{"DRY-RUN " if dry else ""}fixed={fixed} manual={manual} files={len(by_file)}') + for mm in manual_list: + print(' MANUAL', mm[0].split('/repos/')[-1], f'@{mm[1]}', mm[2], '|', mm[3]) + if dry: + print('--- 模板预览(将进字典的key) ---') + for k in keys_added: + print(' ', k[:70]) + +if __name__ == '__main__': + main() diff --git a/scripts/gen_home_index.py b/scripts/gen_home_index.py new file mode 100644 index 0000000..b69d10b --- /dev/null +++ b/scripts/gen_home_index.py @@ -0,0 +1,306 @@ +#!/usr/bin/env python3 +"""生成产线平台新 index.ui:登录→工作台(原 index.ui 内容),未登录→后现代主页(bricks 声明式)。 +用法: python3 scripts/gen_home_index.py (在 pipeline-app 仓库根目录跑)""" +import json, os, io + +ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +IDX = os.path.join(ROOT, 'wwwroot', 'index.ui') + +with io.open(IDX, encoding='utf-8') as f: + old = f.read() + +# 幂等:已生成过则先还原工作区分支(用 git show HEAD 由调用方保证,这里检测标记) +assert '{% if get_user() %}' not in old, 'index.ui 已经是双分支版本,勿重复生成(用 git checkout 还原后重跑)' + +def T(s, css=None, **kw): + """TextBase 三件套:otext+text+i18n(W1 规范)""" + o = {'otext': s, 'text': s, 'i18n': True, 'halign': 'left'} + if css: + o['css'] = css + o.update(kw) + return {'widgettype': 'Text', 'options': o} + +def TN(s, css=None, **kw): + """不翻译的 Text(数字/英文装饰字)""" + o = {'text': s, 'halign': 'left'} + if css: + o['css'] = css + o.update(kw) + return {'widgettype': 'Text', 'options': o} + +def login_bind(): + return {'wid': 'self', 'event': 'click', 'actiontype': 'urlwidget', 'target': 'self', + 'options': {'url': "{{entire_url('/rbac/user/login.ui')}}"}} + +def scroll_script(anchor_id): + return ("var e=document.getElementById(%s);if(e){e.scrollIntoView({behavior:'smooth',block:'start'});}" + % json.dumps(anchor_id)) + +def btn(label, css, bind=None, script=None, small_id=None): + w = {'widgettype': 'Button', 'options': {'label': label, 'css': css}} + if small_id: + w['id'] = small_id + b = bind if bind is not None else { + 'wid': 'self', 'event': 'click', 'actiontype': 'script', 'target': 'self', 'script': script} + w['binds'] = [b] + return w + +THEME_SCRIPT = ("var h=document.documentElement;var t=h.getAttribute('data-theme')||'light';" + "var n=t=='light'?'dark':'light';h.setAttribute('data-theme',n);" + "try{localStorage.setItem('pipeline_ui_theme',n);}catch(e){}" + "if(window.applyPipelineTheme){window.applyPipelineTheme(n);}") + +# ---------- header ---------- +header = { + 'widgettype': 'HBox', + 'options': {'css': 'pl-header', 'width': '100%', 'padding': '0 clamp(20px,6vw,90px)', + 'alignItems': 'center', 'gap': '14px', 'cheight': 3.2}, + 'subwidgets': [ + {'widgettype': 'VBox', 'options': {'gap': '2px', 'alignItems': 'flex-start'}, + 'subwidgets': [T('产线平台', 'pl-logo'), TN('PIPELINE PLATFORM', 'pl-logo-sub')]}, + {'widgettype': 'Filler'}, + T('能力', 'pl-nav', mobile_hidden=True, binds=[ + {'wid': 'self', 'event': 'click', 'actiontype': 'script', 'target': 'self', + 'script': scroll_script('sec_caps')}]), + T('产线', 'pl-nav', mobile_hidden=True, binds=[ + {'wid': 'self', 'event': 'click', 'actiontype': 'script', 'target': 'self', + 'script': scroll_script('sec_pipes')}]), + T('流程', 'pl-nav', mobile_hidden=True, binds=[ + {'wid': 'self', 'event': 'click', 'actiontype': 'script', 'target': 'self', + 'script': scroll_script('sec_flow')}]), + btn('🌙', 'pl-btn-ghost theme-icon-btn', script=THEME_SCRIPT, small_id='theme_toggle_btn'), + {'widgettype': 'urlwidget', 'options': {'url': "{{entire_url('i18n/language.ui')}}"}}, + btn('登录 / 注册', 'pl-btn pl-btn-sm', bind=login_bind()), + ], +} + +# ---------- hero ---------- +hero = { + 'widgettype': 'VBox', + 'options': {'css': 'pl-hero', 'width': '100%'}, + 'subwidgets': [ + {'widgettype': 'VBox', 'options': {'css': 'pl-hero-deco'}, + 'subwidgets': [ + {'widgettype': 'VBox', 'options': {'css': 'pl-grid'}}, + {'widgettype': 'VBox', 'options': {'css': 'pl-orb pl-orb-1'}}, + {'widgettype': 'VBox', 'options': {'css': 'pl-orb pl-orb-2'}}, + {'widgettype': 'VBox', 'options': {'css': 'pl-orb pl-orb-3'}}, + {'widgettype': 'VBox', 'options': {'css': 'pl-noise'}}, + ]}, + {'widgettype': 'VBox', + 'options': {'css': 'pl-hero-content', 'width': '100%', 'gap': '22px', 'alignItems': 'flex-start'}, + 'subwidgets': [ + T('AI 原生 · 产线操作系统', 'pl-badge pl-rise pl-d1'), + T('把业务装进产线', 'pl-h1 pl-stroke pl-rise pl-d2'), + T('让 Agent 自主运转', 'pl-h1 pl-grad pl-rise pl-d2'), + T('产线平台是 Agent 驱动的企业智能产线操作系统:商机、投标、开发一键开工,' + '大模型智能体自主推进任务,人类门禁把关质量,产出即产品、跑完即记账。', + 'pl-sub pl-rise pl-d3', wrap=True), + {'widgettype': 'HBox', + 'options': {'gap': '14px', 'flexWrap': 'wrap', 'alignItems': 'center'}, + 'subwidgets': [ + btn('登录 / 注册', 'pl-btn pl-rise pl-d4', bind=login_bind()), + btn('查看平台能力', 'pl-btn-ghost pl-rise pl-d4', script=scroll_script('sec_caps')), + ]}, + {'widgettype': 'HBox', + 'options': {'css': 'pl-rise pl-d5', 'gap': '40px', 'flexWrap': 'wrap', + 'padding': '18px 0 0 0', 'alignItems': 'flex-start'}, + 'subwidgets': [ + {'widgettype': 'VBox', 'options': {'gap': '2px'}, + 'subwidgets': [TN('5', 'pl-stat-n'), T('产线矩阵', 'pl-stat-t')]}, + {'widgettype': 'VBox', 'options': {'gap': '2px'}, + 'subwidgets': [TN('30+', 'pl-stat-n'), T('功能模块', 'pl-stat-t')]}, + {'widgettype': 'VBox', 'options': {'gap': '2px'}, + 'subwidgets': [TN('24×7', 'pl-stat-n'), T('自主运转', 'pl-stat-t')]}, + {'widgettype': 'VBox', 'options': {'gap': '2px'}, + 'subwidgets': [TN('4', 'pl-stat-n'), T('语言国际化', 'pl-stat-t')]}, + ]}, + ]}, + ], +} + +# ---------- marquee ---------- +mq_items = ['商机挖掘', '投标生产', '软件开发', '模型网关', '产品商品化', + '计费记账', '供销协同', '知识库', '人机协同门禁'] +def mq_track(): + return {'widgettype': 'HBox', 'options': {'css': 'pl-mq-track'}, + 'subwidgets': [T(x, 'pl-mq-item') for x in mq_items * 2]} +marquee = {'widgettype': 'HBox', 'options': {'css': 'pl-marquee', 'width': '100%'}, + 'subwidgets': [mq_track()]} + +# ---------- capabilities (bento) ---------- +def card(icon, title, desc, tag, lg=False, flex='1 1 260px'): + css = 'pl-card pl-card-lg' if lg else 'pl-card' + subs = [] + if tag: + subs.append(TN(tag, 'pl-card-tag')) + subs.append(TN(icon, 'pl-card-icon')) + subs.append(T(title, 'pl-card-t')) + subs.append(T(desc, 'pl-card-d', wrap=True)) + return {'widgettype': 'VBox', + 'options': {'css': css, 'flex': flex, 'gap': '10px', 'alignItems': 'flex-start'}, + 'subwidgets': subs} + +caps = { + 'id': 'sec_caps', + 'widgettype': 'VBox', + 'options': {'css': 'pl-sec', 'width': '100%', 'gap': '18px', 'alignItems': 'flex-start'}, + 'subwidgets': [ + TN('CAPABILITIES', 'pl-kicker'), + T('平台能力', 'pl-h2'), + T('不是聊天机器人,是一条条能自主干活、能被审计、能直接计费的智能产线。', 'pl-sec-sub', wrap=True), + {'widgettype': 'HBox', + 'options': {'width': '100%', 'flexWrap': 'wrap', 'gap': '16px', 'padding': '18px 0 0 0', + 'alignItems': 'stretch'}, + 'subwidgets': [ + card('🤖', 'Agent 驱动产线引擎', + '会话式开工:一句话启动流程,Agent 自动拆解任务、调用大模型、产出交付件;' + 'LLM 三层容错兜底,产线不因单点模型故障停摆。', 'CORE', lg=True, flex='2 2 540px'), + card('🛰', '模型网关', + '多供应商大模型统一接入:余额门禁、会话粘性轮询、故障自动路由、按调用出账,密钥不出进程。', 'GATEWAY'), + card('🛒', '产品商品化', + '资源→产品→定价→折扣→订购→计费全链路;显示价按「真实定价×客户折扣」计算,跑产线即消费、即记账。', 'COMMERCE'), + card('🔔', '平台待办中枢', + '全局异步通知中枢:门禁、确认、上传等产线事件统一冒泡为人类待办,同一事项只发一次、处理完自动补位。', 'HUMAN LOOP'), + card('🛡', '人机协同门禁', + 'PM 审核、QC 质检、人工确认层层把关——机器的速度,人的判断,审计日志全程可追溯。', 'GATE'), + card('🔐', '安全与多租户', + 'RBAC 细粒度路径权限、机构隔离、短令牌内部代理、登录审计与失败锁定。', 'SECURITY'), + card('🌐', '国际化与双主题', + '中 / 英 / 日 / 韩四语实时切换,明暗双主题一键换装,桌面与手机 H5 同构。', 'I18N'), + ]}, + ], +} + +# ---------- pipelines ---------- +def pipe(no, name, desc, live): + tag = T('运行中' if live else '规划中', 'pl-tag ' + ('pl-tag-live' if live else 'pl-tag-soon')) + return {'widgettype': 'HBox', + 'options': {'css': 'pl-step', 'width': '100%', 'gap': '20px', 'alignItems': 'center', + 'flexWrap': 'wrap'}, + 'subwidgets': [ + TN(no, 'pl-step-n'), + {'widgettype': 'VBox', + 'options': {'css': 'filler', 'flex': '1 1 320px', 'gap': '4px', 'minWidth': '240px'}, + 'subwidgets': [T(name, 'pl-step-t'), T(desc, 'pl-step-d', wrap=True)]}, + tag, + ]} + +pipes = { + 'id': 'sec_pipes', + 'widgettype': 'VBox', + 'options': {'css': 'pl-sec', 'width': '100%', 'gap': '16px', 'alignItems': 'flex-start'}, + 'subwidgets': [ + TN('PIPELINES', 'pl-kicker'), + T('产线矩阵', 'pl-h2'), + T('每条产线都是一个完整的业务闭环:从情报输入到可交付产出,全程 Agent 推进、人类门禁把关。', 'pl-sec-sub', wrap=True), + {'widgettype': 'VBox', + 'options': {'width': '100%', 'gap': '12px', 'padding': '18px 0 0 0'}, + 'subwidgets': [ + pipe('01', '商机产线', '招标情报采集 → 商机研判 → 研发报告 → 人工确认,把市场信号变成可跟进的商机。', True), + pipe('02', '投标产线', '标书智能编制:逐项应答评分标准、技术/商务分册生成、材料缺口清单、多轮 QC 门禁。', True), + pipe('03', '开发产线', 'SDLC 任务链:需求 → 设计 → 开发 → 测试 → 部署,PM 审核门控 + 交付件管理。', True), + pipe('04', '运维产线', '面向 FOMS 的运维自动化:告警处置、巡检报告、变更编排。', False), + pipe('05', '营销产线', '内容生产与投放自动化:素材生成、渠道分发、效果回收。', False), + ]}, + ], +} + +# ---------- flow ---------- +def step(no, title, desc): + return {'widgettype': 'VBox', + 'options': {'css': 'pl-card', 'flex': '1 1 190px', 'gap': '8px', 'alignItems': 'flex-start', + 'minHeight': '170px'}, + 'subwidgets': [TN(no, 'pl-step-n'), T(title, 'pl-card-t'), T(desc, 'pl-card-d', wrap=True)]} + +flow = { + 'id': 'sec_flow', + 'widgettype': 'VBox', + 'options': {'css': 'pl-sec', 'width': '100%', 'gap': '16px', 'alignItems': 'flex-start'}, + 'subwidgets': [ + TN('HOW IT WORKS', 'pl-kicker'), + T('五步跑通一条产线', 'pl-h2'), + {'widgettype': 'HBox', + 'options': {'width': '100%', 'flexWrap': 'wrap', 'gap': '14px', 'padding': '18px 0 0 0', + 'alignItems': 'stretch'}, + 'subwidgets': [ + step('01', '订阅产线', '在产品商城选购产线订阅,账号权益即时生效。'), + step('02', '发起会话', '进入产线工作台,用一句话下达任务。'), + step('03', 'Agent 自主执行', '任务拆解、模型调用、交付件产出全程自动推进,可随时插话纠偏。'), + step('04', '人类门禁', '关键节点冒泡为平台待办,人看过正文再放行。'), + step('05', '交付与记账', '产出归档、按量出账,消费明细随时可查。'), + ]}, + ], +} + +# ---------- CTA + footer ---------- +cta = { + 'widgettype': 'VBox', + 'options': {'css': 'pl-cta', 'width': 'auto', 'gap': '16px', 'alignItems': 'center'}, + 'subwidgets': [ + T('准备好把业务装上产线了吗?', 'pl-cta-t'), + T('注册账号,订阅第一条产线,让 Agent 今天就开始干活。', 'pl-cta-d'), + btn('立即注册', 'pl-btn', bind=login_bind()), + ], +} +footer = { + 'widgettype': 'HBox', + 'options': {'css': 'pl-footer', 'width': '100%', 'justifyContent': 'space-between', + 'alignItems': 'center', 'flexWrap': 'wrap', 'gap': '8px'}, + 'subwidgets': [ + T('© 2026 开元云(北京)科技有限公司', 'pl-footer-t'), + TN('PIPELINE PLATFORM · BUILT WITH BRICKS', 'pl-footer-t'), + ], +} + +landing = { + 'id': 'app', + 'widgettype': 'VBox', + 'options': {'css': 'pl-page', 'width': '100%', 'height': '100%', 'padding': '0', + 'overflow': 'hidden'}, + 'subwidgets': [ + {'widgettype': 'VBox', + 'options': {'css': 'pl-scroll', 'width': '100%', 'flex': '1 1 auto', 'minHeight': '0', + 'overflowY': 'auto', 'alignItems': 'flex-start'}, + 'subwidgets': [header, hero, marquee, caps, pipes, flow, cta, footer]}, + ], + # 注册成功(register.dspy dispatch user_logined)后整页刷新 → 服务端渲染工作台分支。 + # 密码登录(up_login.dspy manual)走自身的 dismissed→in-place 渲染 /index.ui,不经此事件,无双重刷新。 + 'binds': [ + {'wid': 'app', 'event': 'user_logined', 'actiontype': 'script', 'target': 'self', + 'script': 'window.location.reload();'}, + ], +} + +landing_txt = json.dumps(landing, ensure_ascii=False, indent=1) +# 防 .ui 内嵌