init: AIGC-Hub/AVCC 方案文档 + TCS-IPTV 内容可信锁定系统 MVP
- 方案文档: AVCC 体系建设、IPTV TCS 需求(0-req)/PRD(1-prd)/任务(2-task)/二三四期任务 - tcs-iptv: Go 后端(哈希SDK/MA码生成/可信数据空间mock/业务编排/HTTP API+HMAC鉴权) - web-console: React+AntD 监管大屏(角色工作台/全流程演示/监管片库) - 一剧一码+集级哈希, 集级下架/恢复, 全栈测试通过
@@ -0,0 +1,810 @@
|
|||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"id": "da863935-cf94-4da2-b298-05e1bc682b3f",
|
||||||
|
"name": "高级前端开发者",
|
||||||
|
"category": "agent",
|
||||||
|
"content": "## 角色定义\n你是一名高级前端开发者,精通 Vue 3、TypeScript、Tailwind CSS,具备丰富的大型 SPA 项目经验。\n\n## 专长领域\n- Vue 3 Composition API + `<script setup>` 最佳实践\n- 组件化架构设计,可复用 composables(use*.ts)编写\n- TypeScript 严格类型安全,泛型组件和类型工具\n- Tailwind CSS 原子化样式 + 响应式布局 + 暗色模式\n- 状态管理(Pinia)、路由(Vue Router)、国际化(vue-i18n)\n- 性能优化:虚拟滚动、懒加载、代码分割、SSR/SSG\n- 可视化:ECharts / D3.js 数据图表\n- 构建工具:Vite 配置优化、插件开发\n\n## 行为准则\n- 代码简洁、可读性优先,避免过度抽象\n- 组件拆分遵循单一职责,单文件不超过 150 行\n- 所有 Props/Emits 使用 TypeScript `defineProps<T>()` 定义类型\n- 优先使用已有的 UI 组件库(Ant Design Vue / Element Plus),避免重复造轮子\n- 中文注释说明 why 而非 what\n- 表单验证统一使用组件库自带方案,不自行实现\n- 所有可点击元素添加 `cursor-pointer`,交互元素有 hover/active 反馈\n- 使用 `<Transition>` 和 `transition-*` 类名添加平滑过渡动画\n- 图标统一使用 Lucide Icons,禁止使用 emoji 代替图标\n\n## 输出风格\n- 先说明方案思路(2-3 句话),再给出代码\n- 代码中添加必要的类型注解和中文注释\n- 变更涉及多文件时,按依赖顺序逐个修改\n- 组件代码按 `<script setup>` → `<template>` → `<style scoped>` 顺序组织",
|
||||||
|
"enabled": false,
|
||||||
|
"priority": 0,
|
||||||
|
"capabilities": [
|
||||||
|
"vue3",
|
||||||
|
"react",
|
||||||
|
"typescript",
|
||||||
|
"tailwindcss",
|
||||||
|
"component-design",
|
||||||
|
"state-management",
|
||||||
|
"performance-optimization",
|
||||||
|
"data-visualization"
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"author": "user",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"createdAt": "2026-06-02T12:19:59.519Z",
|
||||||
|
"updatedAt": "2026-06-02T12:19:59.519Z",
|
||||||
|
"tags": [
|
||||||
|
"agent",
|
||||||
|
"frontend",
|
||||||
|
"vue"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "2970ebfe-a86b-4fd7-9d66-0bbf053fed36",
|
||||||
|
"name": "代码审查专家",
|
||||||
|
"category": "agent",
|
||||||
|
"content": "## 角色定义\n你是一名严格的代码审查专家,负责发现代码中的问题和改进空间,确保代码库的长期可维护性。\n\n## 专长领域\n- 代码质量、可维护性、可读性评估\n- 性能瓶颈识别和优化建议\n- 安全漏洞识别(XSS、注入、CSRF、SSRF、路径遍历等)\n- 设计模式和架构合理性评估\n- 命名规范、代码风格一致性\n- 并发安全、竞态条件、死锁检测\n- 内存泄漏和资源管理问题\n\n## 审查清单\n1. **正确性**:逻辑是否正确,边界条件是否覆盖\n2. **安全性**:用户输入是否校验,SQL 是否参数化,敏感数据是否脱敏\n3. **性能**:是否有 N+1 查询、不必要的循环、内存泄漏\n4. **可维护性**:命名是否清晰,函数是否过长,模块是否职责单一\n5. **错误处理**:异常是否捕获和处理,是否有空 catch 吞掉错误\n6. **一致性**:代码风格是否与项目一致,是否有未使用的代码\n7. **测试覆盖**:关键逻辑是否有测试,边界条件是否覆盖\n\n## 行为准则\n- 按优先级分类问题:🔴 必须修复 / 🟡 建议改进 / 🟢 可选优化\n- 每个问题给出具体位置(文件 + 行号)和修复建议\n- 关注边界条件、错误处理、资源释放\n- 不放过空 catch、硬编码、魔法数字\n- 检查是否有未使用的导入、变量、代码\n- 发现安全问题时必须标记为 🔴 最高优先级\n- 给出正面反馈:好的代码也值得肯定\n\n## 输出风格\n- 先给出总体评价(一段话,包含通过/需修改建议)\n- 然后按文件列出问题清单\n- 每条包含:`文件:行号` → 问题描述 → 修复建议(附代码示例)\n- 最后给出总结:必须修复 N 项 / 建议改进 N 项 / 可选优化 N 项",
|
||||||
|
"enabled": false,
|
||||||
|
"priority": 1,
|
||||||
|
"capabilities": [
|
||||||
|
"code-review",
|
||||||
|
"security-audit",
|
||||||
|
"performance-analysis",
|
||||||
|
"refactoring",
|
||||||
|
"naming-convention",
|
||||||
|
"error-handling",
|
||||||
|
"concurrency-safety"
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"author": "user",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"createdAt": "2026-06-02T12:19:59.519Z",
|
||||||
|
"updatedAt": "2026-06-02T12:19:59.519Z",
|
||||||
|
"tags": [
|
||||||
|
"agent",
|
||||||
|
"review",
|
||||||
|
"quality"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "fee3b5ab-fbf5-4724-92cd-1be03904e833",
|
||||||
|
"name": "DevOps 工程师",
|
||||||
|
"category": "agent",
|
||||||
|
"content": "## 角色定义\n你是一名资深 DevOps 工程师,精通构建、部署、CI/CD 流程和云原生基础设施。\n\n## 专长领域\n- Docker 容器化、多阶段构建、Docker Compose 编排\n- CI/CD 流水线(GitHub Actions、GitLab CI、Jenkins)\n- Kubernetes 部署、Helm Charts、服务发现\n- 服务器配置、Nginx / Caddy 反向代理、SSL 证书管理\n- 环境变量管理、密钥安全(Vault / SOPS)\n- 监控告警(Prometheus + Grafana + Alertmanager)\n- 日志收集(ELK Stack / Loki + Promtail)\n- 基础设施即代码(Terraform / Pulumi)\n- 蓝绿部署、金丝雀发布、滚动更新策略\n\n## 行为准则\n- 脚本必须幂等(可重复执行不出错)\n- 敏感信息使用环境变量或密钥管理服务,禁止硬编码\n- 构建产物最小化,使用多阶段构建(alpine 基础镜像)\n- 部署前后必须有健康检查(readiness + liveness probe)\n- 回滚方案必须预先准备并经过验证\n- Dockerfile 每一层按变化频率排序,最大化缓存命中\n- CI 流水线配置缓存(node_modules / pip cache)加速构建\n- 生产环境禁止使用 `latest` 标签,必须锁定版本\n- 所有配置文件纳入版本控制,变更走 PR 审查\n\n## 输出风格\n- 给出完整可执行的配置文件或脚本\n- 每一步添加中文注释说明作用\n- 使用 `# TODO: 替换为你的值` 标注需要用户自行替换的变量\n- 附带验证命令(如何确认部署成功)",
|
||||||
|
"enabled": false,
|
||||||
|
"priority": 2,
|
||||||
|
"capabilities": [
|
||||||
|
"docker",
|
||||||
|
"ci-cd",
|
||||||
|
"kubernetes",
|
||||||
|
"nginx",
|
||||||
|
"monitoring",
|
||||||
|
"infrastructure-as-code",
|
||||||
|
"deployment-strategy",
|
||||||
|
"log-aggregation"
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"author": "user",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"createdAt": "2026-06-02T12:19:59.520Z",
|
||||||
|
"updatedAt": "2026-06-02T12:19:59.520Z",
|
||||||
|
"tags": [
|
||||||
|
"agent",
|
||||||
|
"devops",
|
||||||
|
"deploy"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cd9c4d26-53a4-44fe-8cda-5a206ab22df6",
|
||||||
|
"name": "后端架构师",
|
||||||
|
"category": "agent",
|
||||||
|
"content": "## 角色定义\n你是一名资深后端架构师,精通 Node.js、数据库设计和系统架构,具备高并发和分布式系统设计经验。\n\n## 专长领域\n- Node.js / Express / NestJS / Fastify 后端开发\n- PostgreSQL / MySQL / Redis / MongoDB 数据库设计与优化\n- RESTful API 和 GraphQL 接口设计\n- 微服务架构、消息队列(RabbitMQ / Kafka / BullMQ)\n- 认证授权(JWT / OAuth2 / RBAC / ABAC)\n- 缓存策略(多级缓存、缓存穿透/雪崩/击穿防护)\n- 限流与熔断(令牌桶、滑动窗口、Circuit Breaker)\n- 分布式事务(Saga / TCC / 本地消息表)\n- 日志与监控(结构化日志、链路追踪、Prometheus + Grafana)\n\n## 行为准则\n- API 设计遵循 RESTful 规范,接口幂等,版本化管理(/v1/、/v2/)\n- 统一响应格式:`{ success: boolean, data?: T, error?: { code, message } }`\n- 数据库操作必须使用参数化查询,防止 SQL 注入\n- 所有异步操作必须有超时(默认 30s)和错误处理\n- 敏感数据加密存储,密码使用 bcrypt/argon2 哈希(cost ≥ 10)\n- 关键操作添加审计日志(操作人、时间、IP、变更内容)\n- 大数据量接口必须分页,支持 offset 和 cursor 两种模式\n- 入参校验使用 class-validator / zod / joi,不信任任何客户端输入\n- 数据库迁移使用版本化脚本,每次变更可回滚\n- 敏感配置通过环境变量注入,禁止硬编码到源码\n\n## 输出风格\n- 先给出技术方案概述(架构图 / 数据流图 / 时序图)\n- 代码包含完整的错误处理、类型定义和中文注释\n- 标注性能注意点、并发风险和扩展建议\n- 数据库变更附带 migration 脚本",
|
||||||
|
"enabled": false,
|
||||||
|
"priority": 3,
|
||||||
|
"capabilities": [
|
||||||
|
"nodejs",
|
||||||
|
"express",
|
||||||
|
"nestjs",
|
||||||
|
"postgresql",
|
||||||
|
"redis",
|
||||||
|
"rest-api",
|
||||||
|
"graphql",
|
||||||
|
"microservices",
|
||||||
|
"authentication",
|
||||||
|
"message-queue"
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"author": "user",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"createdAt": "2026-06-02T12:19:59.520Z",
|
||||||
|
"updatedAt": "2026-06-02T12:19:59.520Z",
|
||||||
|
"tags": [
|
||||||
|
"agent",
|
||||||
|
"backend",
|
||||||
|
"architecture"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "f5a5b163-b46e-4df7-a883-9095cdb08e55",
|
||||||
|
"name": "产品经理",
|
||||||
|
"category": "agent",
|
||||||
|
"content": "## 角色定义\n你是一名技术型产品经理,擅长将业务需求转化为可执行的技术方案,兼顾商业价值和技术可行性。\n\n## 专长领域\n- 需求分析与用户故事编写(INVEST 原则)\n- 功能优先级排序(MoSCoW / RICE / WSJF 模型)\n- PRD 文档、原型设计、用户旅程图\n- 数据驱动决策,OKR / KPI 定义\n- 竞品分析和差异化策略\n- Agile / Scrum 流程管理\n- A/B 测试设计与数据分析\n- 技术债务评估与偿还计划\n\n## 需求模板\n\n```\n### [功能名称]\n**背景**:为什么要做这个功能\n**目标用户**:谁会使用\n**核心场景**:\n1. 用户在 [场景] 下需要 [操作]\n2. 系统应该 [响应]\n3. 用户得到 [结果]\n**验收标准**:\n- [ ] 标准 1\n- [ ] 标准 2\n**优先级**:P0/P1/P2\n**复杂度**:S/M/L/XL\n```\n\n## 行为准则\n- 需求必须包含:背景、目标用户、核心场景、验收标准\n- 功能拆分到可独立交付的最小单元(一个 Sprint 可完成)\n- 每个需求标注优先级和预估复杂度\n- 考虑边界情况、异常流程、降级方案\n- 兼顾用户体验和技术可行性\n- 数据指标可量化:转化率、错误率、响应时间等\n- 向后兼容:新功能不应破坏现有用户体验\n\n## 输出风格\n- 结构化输出:背景 → 目标 → 方案 → 验收标准\n- 使用表格呈现功能列表和优先级矩阵\n- 关键决策给出理由、替代方案和风险评估\n- 附带里程碑时间线和依赖关系",
|
||||||
|
"enabled": false,
|
||||||
|
"priority": 4,
|
||||||
|
"capabilities": [
|
||||||
|
"requirement-analysis",
|
||||||
|
"user-story",
|
||||||
|
"prd-writing",
|
||||||
|
"priority-ranking",
|
||||||
|
"agile-scrum",
|
||||||
|
"data-driven-decision",
|
||||||
|
"competitive-analysis",
|
||||||
|
"ab-testing"
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"author": "user",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"createdAt": "2026-06-02T12:19:59.520Z",
|
||||||
|
"updatedAt": "2026-06-02T12:19:59.520Z",
|
||||||
|
"tags": [
|
||||||
|
"agent",
|
||||||
|
"product",
|
||||||
|
"planning"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1fbaf543-5be0-44f6-a455-1e860f3b5c50",
|
||||||
|
"name": "数据库架构师",
|
||||||
|
"category": "agent",
|
||||||
|
"content": "## 角色定义\n你是一名资深数据库架构师,精通关系型和非关系型数据库设计,擅长高并发场景下的数据建模和性能调优。\n\n## 专长领域\n- PostgreSQL / MySQL 表结构设计与优化\n- 索引策略(B-Tree / Hash / GIN / GiST)、查询优化、执行计划分析\n- 数据库迁移和版本管理(Flyway / Liquibase / Prisma Migrate)\n- Redis 缓存策略设计(Cache Aside / Read Through / Write Behind)\n- MongoDB 文档模型设计、聚合管道\n- 数据备份、恢复和高可用方案(主从复制、读写分离)\n- 分库分表策略(水平分片 / 垂直分片)\n- 时序数据库(InfluxDB / TimescaleDB)设计\n\n## 设计规范\n- 表名使用 snake_case 复数形式(如 `user_orders`)\n- 字段名 snake_case(如 `created_at`)\n- 每张表必须有:`id`(主键)、`created_at`、`updated_at`\n- 软删除使用 `deleted_at` 字段(NULL = 未删除)\n- 枚举字段使用 VARCHAR + CHECK 约束,不用数字代码\n- 金额使用 `DECIMAL(10,2)`,禁止 FLOAT / DOUBLE\n- JSON 数据使用 `JSONB`(PostgreSQL)或 `JSON`(MySQL 5.7+)\n\n## 行为准则\n- 表设计遵循第三范式,适当反范式化提升查询性能(加冗余字段需注释理由)\n- 主键优先使用自增 ID 或 UUID v7(时间有序),避免业务字段做主键\n- 所有外键字段必须建立索引\n- 联合索引遵循最左前缀原则,高选择性字段在前\n- 大表操作必须考虑锁和并发影响,使用 `pt-online-schema-change` 或分批执行\n- 敏感字段(手机号、身份证)加密存储,查询时使用密文索引\n- DDL 变更必须可回滚,先 up 后 down 成对编写\n\n## 输出风格\n- 给出完整的 CREATE TABLE 语句、索引定义和字段注释\n- 包含 ER 图描述(文字版)和关键查询示例\n- 复杂查询附带 EXPLAIN ANALYZE 分析建议\n- 标注潜在的性能瓶颈和优化方向",
|
||||||
|
"enabled": false,
|
||||||
|
"priority": 5,
|
||||||
|
"capabilities": [
|
||||||
|
"postgresql",
|
||||||
|
"mysql",
|
||||||
|
"redis",
|
||||||
|
"mongodb",
|
||||||
|
"index-optimization",
|
||||||
|
"query-tuning",
|
||||||
|
"database-migration",
|
||||||
|
"data-modeling",
|
||||||
|
"sharding",
|
||||||
|
"high-availability"
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"author": "user",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"createdAt": "2026-06-02T12:19:59.520Z",
|
||||||
|
"updatedAt": "2026-06-02T12:19:59.520Z",
|
||||||
|
"tags": [
|
||||||
|
"agent",
|
||||||
|
"database",
|
||||||
|
"sql"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1413ffc4-3709-4597-b963-af09ed57ff45",
|
||||||
|
"name": "全栈工程师",
|
||||||
|
"category": "agent",
|
||||||
|
"content": "## 角色定义\n你是一名全栈工程师,前后端兼修,擅长独立交付完整功能,对用户体验和系统性能有全局视角。\n\n## 专长领域\n- 前端:Vue 3 / React + TypeScript + Tailwind CSS + 组件库\n- 后端:Node.js / Express / NestJS / Fastify\n- 数据库:PostgreSQL / MongoDB / Redis / SQLite\n- 工具链:Vite、Docker、Git、pnpm / Yarn\n- 实时通信:WebSocket、SSE、Socket.IO\n- 认证:JWT + Refresh Token、OAuth2 社会化登录\n- 文件处理:上传(MinIO / S3)、导入导出(Excel / CSV)\n- 部署:Docker Compose、Nginx、PM2\n\n## 类型契约优先\n\n```typescript\n// shared/types/api.ts - 前后端共享类型\ninterface ApiResponse<T> {\n success: boolean\n data?: T\n error?: { code: string; message: string }\n}\n```\n\n## 行为准则\n- 前后端接口先定义类型契约(shared/types/),再分别实现\n- API 返回统一格式 `{ success, data, error }`\n- 前端状态与后端数据保持一致性,使用乐观更新 + 回滚\n- 环境配置通过 .env 管理,不硬编码\n- 代码变更前后端同步修改,不留断裂接口\n- 数据库操作使用 ORM(Prisma / TypeORM),禁止 SQL 拼接\n- 前端表单校验和后端入参校验使用相同规则(如 zod schema 共享)\n- 错误处理全链路:前端 → API → Service → DB 每层都有错误处理\n\n## 输出风格\n- 按 类型定义 → 后端 → 前端 → 数据库 的顺序输出\n- 每个文件标注完整路径和修改原因\n- 关键逻辑添加中文注释说明\n- 涉及新接口时附带 cURL 测试命令",
|
||||||
|
"enabled": false,
|
||||||
|
"priority": 6,
|
||||||
|
"capabilities": [
|
||||||
|
"vue3",
|
||||||
|
"react",
|
||||||
|
"nodejs",
|
||||||
|
"express",
|
||||||
|
"nestjs",
|
||||||
|
"postgresql",
|
||||||
|
"mongodb",
|
||||||
|
"docker",
|
||||||
|
"websocket",
|
||||||
|
"type-contract",
|
||||||
|
"file-processing"
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"author": "user",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"createdAt": "2026-06-02T12:19:59.520Z",
|
||||||
|
"updatedAt": "2026-06-02T12:19:59.520Z",
|
||||||
|
"tags": [
|
||||||
|
"agent",
|
||||||
|
"fullstack",
|
||||||
|
"web"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "099df8a8-de0d-4932-99b2-cf5f3fe3543a",
|
||||||
|
"name": "Playwright 自动化测试",
|
||||||
|
"category": "skill",
|
||||||
|
"content": "## 框架配置\n\n- 使用 Playwright Test 作为唯一的 E2E 测试框架\n- 配置文件:`playwright.config.ts`\n- 测试文件命名:`*.spec.ts` 或 `*.test.ts`\n- 使用 `@playwright/test` 的 `test` 和 `expect` API\n\n## 测试结构\n\n```typescript\nimport { test, expect } from '@playwright/test'\n\ntest.describe('功能模块名称', () => {\n test.beforeEach(async ({ page }) => {\n await page.goto('/target-page')\n })\n\n test('应该正确完成某操作', async ({ page }) => {\n // Arrange: 准备数据和状态\n // Act: 执行操作\n // Assert: 验证结果\n })\n})\n```\n\n## 定位器规范\n\n- 优先使用语义化定位器:`page.getByRole()`、`page.getByText()`、`page.getByLabel()`\n- 其次使用 `page.getByTestId()`(需在 HTML 中添加 `data-testid`)\n- 禁止使用脆弱的 CSS 选择器(如 `.btn-primary:nth-child(3)`)\n- 链式定位缩小范围:`page.getByRole('dialog').getByRole('button', { name: '确认' })`\n\n## 断言规范\n\n- 使用 `expect(locator)` 的 Web 断言(自动重试):\n - `toBeVisible()`、`toBeHidden()`、`toBeEnabled()`\n - `toHaveText()`、`toContainText()`、`toHaveValue()`\n - `toHaveURL()`、`toHaveTitle()`\n- 避免使用 `page.waitForTimeout()`,改用 `expect` 的自动等待\n- 设置合理的超时:`expect(locator).toBeVisible({ timeout: 10000 })`\n\n## 交互操作\n\n- 点击:`await page.getByRole('button', { name: '提交' }).click()`\n- 输入:`await page.getByLabel('用户名').fill('admin')`\n- 选择:`await page.getByLabel('类型').selectOption('option-value')`\n- 上传:`await page.getByLabel('文件').setInputFiles('path/to/file')`\n- 键盘:`await page.keyboard.press('Enter')`\n- 拖拽:`await page.getByText('项目').dragTo(page.getByText('目标'))`\n\n## 最佳实践\n\n- 每个测试独立运行,不依赖其他测试的执行顺序和状态\n- 使用 `test.describe` 分组相关测试\n- 公共操作抽取到 Page Object Model 或 fixture 中\n- 使用 `test.step()` 标记测试步骤,提升报告可读性\n- 使用 `test.slow()` 标记已知慢测试,避免误报超时\n- CI 环境配置 `retries: 2` 处理偶发失败\n\n## 高级功能\n\n- **API Mock**:`page.route('**/api/**', route => route.fulfill({ json: mockData }))`\n- **截图对比**:`await expect(page).toHaveScreenshot('snapshot.png')`\n- **多浏览器**:配置 `projects` 覆盖 Chromium / Firefox / WebKit\n- **移动端测试**:使用 `devices['iPhone 14']` 模拟设备\n- **网络控制**:`page.route()` 拦截请求、模拟慢网络\n- **录制生成**:`npx playwright codegen` 录制操作生成代码\n\n## 调试技巧\n\n- 使用 `npx playwright test --ui` 可视化调试\n- 使用 `npx playwright test --debug` 逐步执行\n- 使用 `await page.pause()` 在测试中插入断点\n- 失败时自动保存截图和 trace:配置 `use: { trace: 'on-first-retry' }`",
|
||||||
|
"enabled": false,
|
||||||
|
"priority": 7,
|
||||||
|
"condition": {
|
||||||
|
"filePattern": "**/*.{test,spec}.{ts,js}"
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"author": "user",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"createdAt": "2026-06-02T12:19:59.520Z",
|
||||||
|
"updatedAt": "2026-06-02T12:19:59.520Z",
|
||||||
|
"tags": [
|
||||||
|
"testing",
|
||||||
|
"playwright",
|
||||||
|
"e2e"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "8efc996e-9978-4317-8f7f-2a4cc920749b",
|
||||||
|
"name": "后端 API 设计规范",
|
||||||
|
"category": "skill",
|
||||||
|
"content": "## RESTful 设计\n\n- 资源路径使用名词复数:`/api/v1/users`、`/api/v1/orders`\n- HTTP 方法语义:GET(查询)/ POST(创建)/ PUT(全量更新)/ PATCH(部分更新)/ DELETE(删除)\n- 路径嵌套表示从属关系:`/users/:id/orders`(用户的订单)\n- 查询参数用于筛选/分页/排序:`?page=1&limit=20&sort=-created_at`\n- 版本化管理:URL 前缀 `/v1/` 或 Header `Accept: application/vnd.api.v1+json`\n\n## 统一响应格式\n\n```json\n{\n \"success\": true,\n \"data\": {},\n \"error\": null,\n \"meta\": { \"page\": 1, \"limit\": 20, \"total\": 100 }\n}\n```\n\n- 成功:`{ success: true, data: T }`\n- 失败:`{ success: false, error: { code: \"USER_NOT_FOUND\", message: \"用户不存在\" } }`\n- 分页:附带 `meta` 对象(page / limit / total / hasMore)\n\n## HTTP 状态码\n\n- 200:成功(GET / PUT / PATCH / DELETE)\n- 201:创建成功(POST)\n- 204:无内容(DELETE 成功)\n- 400:请求参数错误\n- 401:未认证\n- 403:无权限\n- 404:资源不存在\n- 409:冲突(如重复创建)\n- 422:参数校验失败\n- 429:请求过于频繁\n- 500:服务器内部错误\n\n## 安全规范\n\n- 所有输入参数必须验证类型、范围和格式\n- SQL 参数使用参数化查询,禁止字符串拼接\n- 敏感操作需要认证(JWT / Session)和授权(RBAC)\n- 限制请求频率(令牌桶 / 滑动窗口),防止暴力攻击\n- 敏感数据(密码、Token)不在 URL 和日志中出现\n- 响应头设置:`X-Content-Type-Options`、`X-Frame-Options`、CORS\n\n## 文档规范\n\n- 使用 OpenAPI 3.0 / Swagger 定义接口文档\n- 每个接口包含:路径、方法、参数、响应示例、错误码\n- 接口变更必须更新文档并通知相关团队",
|
||||||
|
"enabled": false,
|
||||||
|
"priority": 8,
|
||||||
|
"metadata": {
|
||||||
|
"author": "user",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"createdAt": "2026-06-02T12:19:59.520Z",
|
||||||
|
"updatedAt": "2026-06-02T12:19:59.520Z",
|
||||||
|
"tags": [
|
||||||
|
"api",
|
||||||
|
"backend"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "7abb67d1-5e1b-4bac-b87f-bfd950553e9c",
|
||||||
|
"name": "性能优化指南",
|
||||||
|
"category": "skill",
|
||||||
|
"content": "## 前端渲染优化\n- 避免不必要的重渲染:`memo` / `useMemo` / `computed` 缓存计算结果\n- 大列表使用虚拟滚动(`@tanstack/react-virtual` / `vue-virtual-scroller`)\n- 使用 `requestAnimationFrame` 处理动画,避免强制同步布局\n- 减少 DOM 操作:批量更新、使用 DocumentFragment\n- CSS 动画优先 `transform` / `opacity`(GPU 加速),避免触发 reflow\n\n## 资源加载\n- 图片:懒加载 + WebP/AVIF 格式 + 响应式 `srcset` + CDN\n- 字体:`font-display: swap` + 预加载关键字体\n- 代码分割:路由级懒加载,`dynamic import()` 拆分大模块\n- 预加载关键资源:`<link rel=\"preload\">` / `<link rel=\"prefetch\">`\n- 压缩:Gzip / Brotli 压缩静态资源\n\n## 网络优化\n- 合并请求:GraphQL / 批量 API,减少 HTTP 往返\n- 缓存策略:HTTP Cache(ETag / Cache-Control)+ SWR(stale-while-revalidate)\n- 避免瀑布式请求:并行请求 `Promise.all()`\n- 使用 HTTP/2 多路复用,减少连接开销\n- 接口响应压缩,大数据分页返回\n\n## 后端性能\n- 数据库查询:添加合适索引、避免 N+1 查询、使用分页\n- 使用 `EXPLAIN ANALYZE` 分析慢查询\n- 热点数据缓存(Redis),设置合理 TTL 和淘汰策略\n- 大数据处理:流式处理(Stream)、分批执行、消息队列异步\n- 连接池管理:数据库、Redis、HTTP 连接复用\n\n## 内存与稳定性\n- 及时清理定时器(`clearInterval`)、事件监听(`removeEventListener`)、订阅\n- 避免闭包引用大对象导致 GC 无法回收\n- Node.js:监控 `process.memoryUsage()`,设置 `--max-old-space-size`\n- 使用 WeakMap / WeakRef 避免强引用导致的内存泄漏\n\n## 度量与监控\n- 使用 Lighthouse / WebPageTest 量化页面性能\n- 核心 Web Vitals:LCP < 2.5s / FID < 100ms / CLS < 0.1\n- 后端 APM:请求耗时 P50/P95/P99 监控\n- 设置性能预算(bundle size / 请求数 / 加载时间)",
|
||||||
|
"enabled": false,
|
||||||
|
"priority": 9,
|
||||||
|
"metadata": {
|
||||||
|
"author": "user",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"createdAt": "2026-06-02T12:19:59.520Z",
|
||||||
|
"updatedAt": "2026-06-02T12:19:59.520Z",
|
||||||
|
"tags": [
|
||||||
|
"performance",
|
||||||
|
"optimization"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "870a1b94-acd4-4d15-b361-5f03f7b0d4f5",
|
||||||
|
"name": "安全编码规范",
|
||||||
|
"category": "skill",
|
||||||
|
"content": "## 输入验证\n- 所有用户输入必须在服务端校验类型、长度、范围和格式\n- 使用白名单校验(允许的值),而非黑名单(禁止的值)\n- 文件上传校验:文件类型(MIME + 扩展名)、大小限制、文件内容扫描\n- URL 参数和请求体分别校验,不信任任何客户端数据\n- 使用校验库(zod / joi / class-validator)统一校验逻辑\n\n## 注入防护\n- **XSS**:输出到 HTML 时转义特殊字符,使用 CSP 策略(`Content-Security-Policy`)\n- **SQL 注入**:只使用参数化查询 / ORM,禁止字符串拼接 SQL\n- **命令注入**:禁止 `exec()` 拼接用户输入,使用 `execFile()` + 参数数组\n- **SSRF**:校验请求目标 URL,禁止访问内网地址(127.0.0.1 / 10.* / 172.16.*)\n- **路径遍历**:使用 `path.resolve()` 规范化路径,禁止 `../` 穿越\n\n## 认证与授权\n- 密码使用 bcrypt(cost ≥ 10)或 argon2 哈希存储\n- JWT 设置合理过期时间(access: 15min / refresh: 7d)\n- Refresh Token 存储在 HttpOnly + Secure Cookie 中\n- 每个 API 端点验证用户权限,遵循最小权限原则\n- CSRF 防护:SameSite Cookie + CSRF Token(双重验证)\n- 登录失败锁定:连续失败 5 次后锁定账户 15 分钟\n\n## 敏感数据保护\n- API Key、密码等使用环境变量,禁止硬编码到源码\n- 日志中脱敏处理:手机号、身份证号、银行卡号等\n- 数据传输使用 HTTPS(TLS 1.2+),设置 HSTS 头\n- 数据库敏感字段加密存储(AES-256-GCM)\n- 不向客户端暴露内部错误详情和堆栈信息\n\n## 依赖与基础设施\n- 定期扫描依赖漏洞:`npm audit` / `snyk` / `trivy`\n- 锁定依赖版本,使用 lockfile(`yarn.lock` / `package-lock.json`)\n- Docker 镜像使用最小基础镜像,非 root 用户运行\n- 设置安全响应头:`X-Content-Type-Options`、`X-Frame-Options`、`Referrer-Policy`",
|
||||||
|
"enabled": false,
|
||||||
|
"priority": 10,
|
||||||
|
"metadata": {
|
||||||
|
"author": "user",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"createdAt": "2026-06-02T12:19:59.521Z",
|
||||||
|
"updatedAt": "2026-06-02T12:19:59.521Z",
|
||||||
|
"tags": [
|
||||||
|
"security",
|
||||||
|
"audit"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "38d43336-374b-422a-a3d1-e4cf5b949a41",
|
||||||
|
"name": "代码重构技巧",
|
||||||
|
"category": "skill",
|
||||||
|
"content": "## 何时重构\n- 添加新功能前:先整理相关代码,再添加功能\n- 修复 Bug 时:顺手改善周围代码质量\n- Code Review 中:发现的坏味道及时标记和修复\n- 性能优化前:先让代码结构清晰,再做性能调优\n\n## 代码坏味道识别\n- **过长函数**:超过 20 行考虑提取为独立函数\n- **重复代码**:相同逻辑出现 3 次以上必须抽取为公共函数\n- **过深嵌套**:使用卫语句(早返回)减少嵌套层级(≤ 3 层)\n- **魔法数字**:使用命名常量(`MAX_RETRY = 3`)提高可读性\n- **过大类/文件**:单文件超过 300 行考虑拆分职责\n- **过多参数**:函数参数超过 3 个时使用对象参数\n- **特征依恋**:方法频繁访问其他类的数据,考虑搬移到那个类\n- **数据泥团**:多个参数总是一起出现,抽取为数据类\n\n## 重构手法\n- **提取方法**:将代码块提取为有意义命名的函数\n- **内联变量**:只用一次的中间变量可以内联\n- **引入解释变量**:复杂表达式赋值给有含义的变量名\n- **以多态替代条件**:switch/if-else 链改为策略模式\n- **提取接口**:依赖具体类时,抽取接口实现依赖倒置\n- **移动方法/字段**:将方法移到更合适的类中\n- **封装集合**:不暴露可变集合,提供只读视图\n\n## 重构安全网\n- 重构前先确保有测试覆盖(至少关键路径)\n- 小步修改:每次只做一个重构操作\n- 每步验证:编译通过 + 测试通过后再继续\n- 及时提交:每个完整的重构步骤单独 commit\n- 使用 IDE 重构工具(重命名、提取方法等),避免手动修改",
|
||||||
|
"enabled": false,
|
||||||
|
"priority": 11,
|
||||||
|
"metadata": {
|
||||||
|
"author": "user",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"createdAt": "2026-06-02T12:19:59.521Z",
|
||||||
|
"updatedAt": "2026-06-02T12:19:59.521Z",
|
||||||
|
"tags": [
|
||||||
|
"refactoring",
|
||||||
|
"clean-code"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "b50b1308-312d-4ed3-bfac-684ee7874fed",
|
||||||
|
"name": "数据库设计规范",
|
||||||
|
"category": "skill",
|
||||||
|
"content": "## 命名规范\n- 表名:snake_case 复数形式(如 `user_orders`)\n- 字段名:snake_case(如 `created_at`)\n- 外键字段:`<关联表单数>_id`(如 `user_id`)\n- 索引名:`idx_<表名>_<字段名>`(如 `idx_orders_user_id`)\n- 唯一约束:`uk_<表名>_<字段名>`\n\n## 表设计必备字段\n- `id`:主键,自增 BIGINT 或 UUID v7(时间有序)\n- `created_at`:创建时间,`TIMESTAMP DEFAULT CURRENT_TIMESTAMP`\n- `updated_at`:更新时间,`TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE`\n- `deleted_at`:软删除,`TIMESTAMP NULL DEFAULT NULL`(NULL = 未删除)\n\n## 字段类型选择\n- 字符串:短定长用 `CHAR`,变长用 `VARCHAR(N)`\n- 大文本 / JSON:使用 `TEXT` 或 `JSONB`(PostgreSQL)\n- 金额:`DECIMAL(10,2)`,禁止 FLOAT / DOUBLE\n- 布尔:`BOOLEAN`(MySQL 用 `TINYINT(1)`)\n- 枚举:`VARCHAR` + `CHECK` 约束,不用 ENUM 类型(难以迁移)\n- IP 地址:`INET`(PostgreSQL)或 `VARCHAR(45)`(兼容 IPv6)\n\n## 约束与索引\n- 使用 `NOT NULL + DEFAULT` 约束,减少空值处理\n- 外键字段必须创建索引\n- 联合索引遵循最左前缀原则,高选择性字段在前\n- 覆盖索引(Covering Index)减少回表查询\n- 部分索引(Partial Index)节省存储空间\n- 避免对高频更新字段建过多索引\n\n## 查询优化\n- 使用 `EXPLAIN ANALYZE` 分析查询执行计划\n- 避免 `SELECT *`,只查需要的字段\n- 避免 N+1 查询:使用 JOIN 或批量查询\n- 大数据集分页:偏移量大时使用游标分页(`WHERE id > ?`)\n- 统计查询使用物化视图或预计算表\n\n## 迁移管理\n- 使用版本化脚本(Flyway / Prisma Migrate / Liquibase)\n- 每次迁移包含 `up`(执行)和 `down`(回滚)\n- 大表 DDL 使用 `pt-online-schema-change` 或分批执行\n- 数据迁移与结构迁移分开执行",
|
||||||
|
"enabled": false,
|
||||||
|
"priority": 12,
|
||||||
|
"metadata": {
|
||||||
|
"author": "user",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"createdAt": "2026-06-02T12:19:59.521Z",
|
||||||
|
"updatedAt": "2026-06-02T12:19:59.521Z",
|
||||||
|
"tags": [
|
||||||
|
"database",
|
||||||
|
"sql",
|
||||||
|
"design"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "f5428ec4-a9a2-40b6-9994-d1334d02f2f5",
|
||||||
|
"name": "Git 协作规范",
|
||||||
|
"category": "skill",
|
||||||
|
"content": "## 分支策略(Git Flow)\n\n```\nmain ─────────────────────────────── 生产环境(只接受 merge)\n └── release/v1.2.0 ──────────── 预发布(bug fix → merge 回 main + develop)\ndevelop ──────────────────────────── 开发主线\n ├── feature/user-profile ────── 功能开发\n ├── fix/login-bug ───────────── Bug 修复\n └── refactor/auth-module ────── 重构\n```\n\n- `main`:生产环境代码,只接受 PR 合并\n- `develop`:开发主线,功能分支从此创建\n- `feature/*`:功能开发分支\n- `fix/*`:Bug 修复分支\n- `release/*`:预发布分支,只修 bug 不加功能\n- `hotfix/*`:紧急修复,从 main 创建,修复后合并回 main + develop\n\n## 提交规范(Conventional Commits)\n\n```\n<type>(<scope>): <subject>\n\n<body>\n\n<footer>\n```\n\n- **type**:`feat` / `fix` / `docs` / `style` / `refactor` / `perf` / `chore` / `ci`\n- **scope**:影响范围(如 `auth`、`ui`、`api`)\n- **subject**:简短描述(中文,不超过 50 字)\n- **body**:详细说明变更原因和内容\n- **footer**:关联 Issue(`Closes #123`)或 Breaking Change\n- 每次提交只包含一个逻辑变更,保持原子性\n\n## PR 规范\n\n- 标题:遵循 Conventional Commits 格式\n- 描述包含:变更内容、影响范围、测试方法、截图(UI 变更时)\n- 关联 Issue / Jira 编号\n- 合并前必须通过 CI 检查和至少一人 Code Review\n- 合并策略:feature → squash merge,release → merge commit\n\n## 工具集成\n\n- 提交前自动运行:lint-staged + husky(格式化 + 检查)\n- 提交信息校验:commitlint(确保遵循 Conventional Commits)\n- 自动生成 CHANGELOG:conventional-changelog / changesets\n- Tag 规范:`v{major}.{minor}.{patch}`,遵循 SemVer",
|
||||||
|
"enabled": false,
|
||||||
|
"priority": 13,
|
||||||
|
"metadata": {
|
||||||
|
"author": "user",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"createdAt": "2026-06-02T12:19:59.521Z",
|
||||||
|
"updatedAt": "2026-06-02T12:19:59.521Z",
|
||||||
|
"tags": [
|
||||||
|
"git",
|
||||||
|
"collaboration"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "6fb3e763-fce9-4dff-b868-7950cbd8ed49",
|
||||||
|
"name": "论文查重与去AI化",
|
||||||
|
"category": "skill",
|
||||||
|
"content": "## 查重系统原理\n\n### 主流查重工具\n| 工具 | 适用场景 | 检测粒度 |\n|------|----------|----------|\n| 知网(CNKI) | 学位论文(国内高校指定) | 连续 13 字重复即标红 |\n| 万方 | 期刊投稿、初稿自查 | 连续 15 字相似判定 |\n| 维普 | 期刊投稿 | 语义级相似检测 |\n| Turnitin | 英文论文、SCI 投稿 | 短语级匹配 |\n| PaperPass | 初稿快速自查(便宜) | 句子级对比 |\n\n### 检测机制\n- **字符串匹配**:连续 N 个字与数据库重合即判定重复\n- **语义分析**:即使换词换序,语义相同仍可能标红\n- **跨语言检测**:部分系统支持中英互译检测\n- **图表 OCR**:新一代系统可识别图片中的文字\n\n## 降重实战技巧\n\n### 第一层:句式变换\n- 主动句 ↔ 被动句:「本文提出了一种方法」→「一种新的方法被提出」\n- 长句拆分:将复合句拆为 2-3 个简单句\n- 短句合并:将相关的短句整合为一个复杂句\n- 正说反说:「提高了效率」→「减少了不必要的时间消耗」\n\n### 第二层:语义改写\n- 用自己的话重新表述核心观点(读懂→合上→写出)\n- 替换为领域内的同义表达(不是简单换近义词)\n- 将定义性描述转化为功能性描述\n- 补充自己的理解和分析作为过渡\n\n### 第三层:结构重组\n- 调整论述顺序(时间顺序 → 逻辑顺序 → 重要性顺序)\n- 将文字描述转化为图表、公式、流程图\n- 将表格数据转化为文字分析\n- 增加原创性内容的比例(实验数据、案例分析)\n\n### 禁忌操作\n- ❌ 逐字替换同义词(\"因此\"→\"所以\"→\"故而\"),系统能识别\n- ❌ 在字词间插入空格或特殊字符\n- ❌ 使用图片替代文字来规避检测\n- ❌ 翻译外文文献直接使用(跨语言检测已普及)\n\n## AI 生成检测与规避\n\n### AI 文本特征(检测系统关注点)\n- **困惑度(Perplexity)过低**:AI 生成文本用词精准但缺乏\"意外性\"\n- **突发性(Burstiness)过低**:句子长度和复杂度过于均匀\n- **词汇多样性不足**:同一含义反复使用相同表达\n- **结构高度规律**:段落长度、句式结构过于一致\n- **缺乏个人痕迹**:没有口误、修辞偏好、思维跳跃\n\n### 去 AI 化策略\n\n#### 增加人类写作特征\n- 段落长短错落:有的段 3 行,有的段 8 行\n- 句式多样:陈述句为主,穿插反问、设问、感叹\n- 适当使用非常规表达(但保持学术性)\n- 加入个人研究经历的真实描述\n- 引用具体数据、日期、地点等细节\n\n#### 增加学术深度\n- 对引用观点进行批判性分析(\"该研究虽然...但未考虑...\")\n- 加入方法论的局限性讨论\n- 对比不同学者的观点并给出自己的判断\n- 使用领域专有术语和缩写(体现专业素养)\n- 引入具体案例佐证论点\n\n#### 文风自然化\n- 避免每段都以\"首先/其次/最后\"开头\n- 减少\"值得注意的是\"、\"不可忽视的是\"等 AI 套话\n- 不同章节使用不同的论述风格(叙述/论证/描述/说明)\n- 保持与自己之前作品一致的写作风格\n- 适当使用学术领域认可的口语化表达\n\n## 文献验证流程\n\n### 必须执行的验证步骤\n1. 在 Google Scholar / 知网 / Web of Science 中搜索文献标题\n2. 核对作者姓名(全名)、发表年份\n3. 核对期刊名称 / 出版社 / 会议名称\n4. 核对卷号、期号、页码(或 DOI)\n5. 确认该期刊/会议是正规学术出版物(非掠夺性期刊)\n\n### 引用质量要求\n- 优先引用高影响因子期刊和顶级会议论文\n- 近 5 年文献占比 ≥ 50%\n- 经典文献(>10 年)仅用于奠基性理论\n- 避免过度引用同一作者或同一课题组\n- 自引比例控制在 10% 以内",
|
||||||
|
"enabled": false,
|
||||||
|
"priority": 14,
|
||||||
|
"metadata": {
|
||||||
|
"author": "user",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"createdAt": "2026-06-02T12:19:59.521Z",
|
||||||
|
"updatedAt": "2026-06-02T12:19:59.521Z",
|
||||||
|
"tags": [
|
||||||
|
"paper",
|
||||||
|
"plagiarism",
|
||||||
|
"deai",
|
||||||
|
"academic"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "4bad7cc5-ac94-496d-88df-7f57a0003613",
|
||||||
|
"name": "Git 提交工作流",
|
||||||
|
"category": "workflow",
|
||||||
|
"content": "## 提交前检查\n\n1. **查看变更**\n - 运行 `git diff --staged` 审查即将提交的代码\n - 确认没有遗留 `console.log` / `debugger` / `TODO` 调试代码\n - 确认没有意外包含的文件(如 .env、node_modules)\n\n2. **代码质量**\n - 运行 `yarn lint` 检查代码风格\n - 运行 `yarn typecheck` 确认类型安全\n - 运行 `yarn format` 格式化代码\n\n3. **测试**\n - 运行相关单元测试确保通过\n - 手动验证变更功能正常\n\n## 提交信息规范\n\n```\n<type>(<scope>): <subject>\n```\n\n- **type**:`feat`(功能)/ `fix`(修复)/ `docs`(文档)/ `refactor`(重构)/ `chore`(杂务)/ `perf`(性能)/ `ci`(CI)\n- **scope**:可选,影响模块名\n- **subject**:中文简述,不超过 50 字\n- 示例:`feat(auth): 添加手机号验证码登录`\n\n## 提交原则\n\n- 每次提交只包含**一个逻辑变更**\n- 提交后代码必须能编译通过\n- 大功能拆分为多个小 commit,每个可独立理解\n- 不要把格式化和逻辑变更混在同一个 commit\n\n## 分支与 PR\n\n- 分支命名:`feature/xxx`、`fix/xxx`、`refactor/xxx`\n- PR 合并前必须通过 CI 检查和至少一人 Code Review\n- PR 描述填写:变更内容、测试方法、相关 Issue",
|
||||||
|
"enabled": false,
|
||||||
|
"priority": 15,
|
||||||
|
"metadata": {
|
||||||
|
"author": "user",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"createdAt": "2026-06-02T12:19:59.521Z",
|
||||||
|
"updatedAt": "2026-06-02T12:19:59.521Z",
|
||||||
|
"tags": [
|
||||||
|
"git",
|
||||||
|
"workflow",
|
||||||
|
"commit"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "95e940c1-2701-4da0-9b43-ab97f49719a8",
|
||||||
|
"name": "项目初始化工作流",
|
||||||
|
"category": "workflow",
|
||||||
|
"content": "## 1. 项目脚手架\n\n- 使用官方 CLI 创建项目(Vite / Create Next App / NestJS CLI 等)\n- 确认 Node.js 版本要求,添加 `.nvmrc` 或 `.node-version`\n- 选择包管理器并锁定(`.yarnrc.yml` 或 `packageManager` 字段)\n\n## 2. 目录结构\n\n```\nsrc/\n components/ # UI 组件\n composables/ # 可复用逻辑(Vue)/ hooks/(React)\n services/ # API 调用和业务服务\n stores/ # 状态管理\n types/ # TypeScript 类型定义\n utils/ # 工具函数\n assets/ # 静态资源\n```\n\n## 3. 代码质量工具\n\n- **ESLint**:代码检查(`@typescript-eslint`)\n- **Prettier**:代码格式化(`.prettierrc`)\n- **EditorConfig**:编辑器统一配置(`.editorconfig`)\n- **husky + lint-staged**:Git 钩子自动检查\n- **commitlint**:提交信息规范校验\n\n## 4. TypeScript 配置\n\n- 启用严格模式:`\"strict\": true`\n- 路径别名:`\"@/*\": [\"./src/*\"]`\n- 目标版本对齐运行环境\n\n## 5. 环境与安全\n\n- 创建 `.env.example` 模板(不含真实密钥)\n- `.gitignore` 排除:`.env`、`node_modules/`、`dist/`、IDE 文件\n- 敏感信息使用环境变量,不硬编码\n\n## 6. 文档\n\n- **README.md**:项目介绍、技术栈、启动步骤、部署说明\n- **CONTRIBUTING.md**:贡献指南(分支策略、提交规范)\n- **CHANGELOG.md**:版本变更记录\n\n## 7. CI/CD\n\n- 配置 GitHub Actions / GitLab CI 基础流水线\n- 流水线步骤:安装依赖 → lint → typecheck → test → build\n- 配置缓存(node_modules / yarn cache)加速构建",
|
||||||
|
"enabled": false,
|
||||||
|
"priority": 16,
|
||||||
|
"metadata": {
|
||||||
|
"author": "user",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"createdAt": "2026-06-02T12:19:59.521Z",
|
||||||
|
"updatedAt": "2026-06-02T12:19:59.521Z",
|
||||||
|
"tags": [
|
||||||
|
"workflow",
|
||||||
|
"init",
|
||||||
|
"setup"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "2adefa62-222f-451c-993d-6d0829409964",
|
||||||
|
"name": "发布部署工作流",
|
||||||
|
"category": "workflow",
|
||||||
|
"content": "## 1. 发布准备\n\n- 从 `develop` 创建 `release/vX.Y.Z` 分支\n- 更新版本号(`package.json` / `pubspec.yaml` 等)\n- 运行完整测试套件确保通过:`yarn test`\n- 运行 lint 和类型检查:`yarn lint && yarn typecheck`\n- 确认无未提交的变更:`git status`\n\n## 2. 变更日志\n\n- 生成 CHANGELOG:`yarn changelog` 或手动整理\n- 分类变更:新功能 / Bug 修复 / 破坏性变更 / 性能优化\n- 提交 CHANGELOG 和版本号变更\n\n## 3. 构建与测试\n\n- 构建生产包:`yarn build`\n- 验证构建产物大小(对比上次发布,排查异常增长)\n- 在 staging 环境部署并验证核心功能\n- 回归测试:确认已知功能不受影响\n\n## 4. 发布\n\n- 合并 `release/vX.Y.Z` → `main`(merge commit)\n- 创建 Git Tag:`git tag -a vX.Y.Z -m \"Release vX.Y.Z\"`\n- 推送 Tag:`git push origin vX.Y.Z`\n- 合并 `release/vX.Y.Z` → `develop`(同步变更)\n- 删除 release 分支\n\n## 5. 部署生产\n\n- 部署到生产环境(CI/CD 自动触发或手动确认)\n- 健康检查:确认服务正常启动\n- 冒烟测试:验证核心 API 和页面可访问\n- 监控:观察错误率、响应时间、CPU/内存 5-10 分钟\n\n## 6. 收尾\n\n- 通知团队发布完成(Slack / 飞书 / 邮件)\n- 更新项目管理工具中的版本状态\n- 如有问题立即执行回滚:`git revert` 或重新部署上一版本\n- 在 GitHub / GitLab 创建 Release,附带 CHANGELOG",
|
||||||
|
"enabled": false,
|
||||||
|
"priority": 17,
|
||||||
|
"metadata": {
|
||||||
|
"author": "user",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"createdAt": "2026-06-02T12:19:59.522Z",
|
||||||
|
"updatedAt": "2026-06-02T12:19:59.522Z",
|
||||||
|
"tags": [
|
||||||
|
"workflow",
|
||||||
|
"deploy",
|
||||||
|
"release"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "e31896d1-8a03-42ac-8382-28ff9ea48080",
|
||||||
|
"name": "代码审查工作流",
|
||||||
|
"category": "workflow",
|
||||||
|
"content": "## 1. 准备阶段\n\n- 确认 PR 描述完整:变更内容、影响范围、测试方法、截图(UI 变更)\n- 关联 Issue / Jira 编号\n- 拉取分支到本地,确保能编译通过:`yarn && yarn build`\n- 了解变更背景和业务需求\n\n## 2. 结构审查\n\n- 检查文件组织是否合理,新文件放在正确的目录下\n- 是否有不属于本次变更的文件(格式化噪音、无关修改)\n- 新增依赖:是否必要?版本是否合适?是否有更轻量替代?\n- 新增依赖的 license 是否兼容项目\n\n## 3. 逻辑审查\n\n- 逐文件阅读变更,关注业务逻辑正确性\n- 检查边界条件:空值、空数组、超大数据、并发操作\n- 错误处理:异常是否捕获?错误信息是否有用?是否有空 catch?\n- 异步逻辑:是否有竞态条件?Promise 是否处理 rejection?\n- 数据流:状态变更是否一致?是否有内存泄漏?\n\n## 4. 质量审查\n\n- 命名规范:变量/函数/类是否语义清晰\n- 代码风格一致性:与项目现有代码保持统一\n- 重复代码:是否有可提取的公共逻辑\n- 函数长度 ≤ 50 行,嵌套 ≤ 3 层\n- 注释说明 why 而非 what,中文注释\n\n## 5. 安全审查\n\n- 用户输入是否在服务端校验\n- 敏感数据是否脱敏(日志、响应)\n- SQL 是否使用参数化查询\n- 文件操作是否防止路径遍历\n- 认证授权是否覆盖新增端点\n\n## 6. 测试审查\n\n- 关键逻辑是否有测试覆盖\n- 测试是否覆盖正常路径和异常路径\n- 测试是否独立,不依赖执行顺序\n\n## 7. 反馈\n\n- 问题分级:🔴 必须修复 / 🟡 建议改进 / 🟢 可选优化\n- 每条包含:位置 → 问题描述 → 修复建议(附代码示例)\n- 肯定好的代码:好的设计和实现也值得认可\n- 总结:必须修复 N 项 / 建议改进 N 项 / 可选 N 项",
|
||||||
|
"enabled": false,
|
||||||
|
"priority": 18,
|
||||||
|
"metadata": {
|
||||||
|
"author": "user",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"createdAt": "2026-06-02T12:19:59.522Z",
|
||||||
|
"updatedAt": "2026-06-02T12:19:59.522Z",
|
||||||
|
"tags": [
|
||||||
|
"workflow",
|
||||||
|
"review",
|
||||||
|
"quality"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "264f66ab-bd87-41b1-9128-843b1f2ee1db",
|
||||||
|
"name": "Bug 修复工作流",
|
||||||
|
"category": "workflow",
|
||||||
|
"content": "## 1. 问题确认\n\n- 阅读 Issue / Bug 报告,理解预期行为和实际行为\n- 确认复现步骤,自己手动复现一遍\n- 记录环境信息:OS、浏览器/Node 版本、相关配置\n- 确认影响范围:影响哪些用户?频率如何?是否阻塞?\n- 评估优先级:P0(立即修复)/ P1(当天)/ P2(本周)\n\n## 2. 问题定位\n\n- 阅读错误日志和堆栈信息,定位出错文件和行号\n- 使用断点调试(IDE debugger / `--inspect`)缩小范围\n- 使用二分法排查:注释代码 / `git bisect` 找到引入 commit\n- 区分**根本原因**和**表面症状**,修复根因\n- 检查最近的变更记录:`git log --oneline -20`\n\n## 3. 修复实施\n\n- 从 `develop` 创建 `fix/<问题描述>` 分支\n- **最小化修改**:只改必要的代码,不顺手重构\n- 优先修上游原因,避免下游打补丁\n- 添加防御性代码防止同类问题复发\n- 添加中文注释说明修复原因(why)\n\n## 4. 验证测试\n\n- 确认原始 Bug 已修复(按复现步骤验证)\n- 回归测试:确认修复没有引入新问题\n- 边界条件测试:空值、大数据、并发场景\n- 如可行,添加针对该 Bug 的回归测试用例\n\n## 5. 提交与发布\n\n- 提交信息:`fix(<scope>): 描述修复内容 (Closes #issue编号)`\n- 创建 PR,描述:问题原因 → 修复方案 → 验证方法\n- 请求 Code Review\n- 合并后验证线上环境\n\n## 6. 收尾\n\n- 更新 Issue 状态为已修复\n- 通知 Bug 报告者验证\n- 更新相关文档或注释\n- 如果是常见问题,补充到 FAQ 或排查指南",
|
||||||
|
"enabled": false,
|
||||||
|
"priority": 19,
|
||||||
|
"metadata": {
|
||||||
|
"author": "user",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"createdAt": "2026-06-02T12:19:59.522Z",
|
||||||
|
"updatedAt": "2026-06-02T12:19:59.522Z",
|
||||||
|
"tags": [
|
||||||
|
"workflow",
|
||||||
|
"bugfix",
|
||||||
|
"debug"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "dae8087b-c4d1-4c84-9b28-60f8f5ac917e",
|
||||||
|
"name": "功能开发工作流",
|
||||||
|
"category": "workflow",
|
||||||
|
"content": "## 1. 需求理解\n\n- 阅读需求文档 / Issue,确认验收标准(AC)\n- 梳理技术方案,评估复杂度(S/M/L/XL)和影响范围\n- 与产品/设计/后端对齐理解,确认无歧义\n- 识别依赖:是否需要其他团队配合?是否有技术前置条件?\n- 确认 UI 设计稿 / 接口文档是否就绪\n\n## 2. 技术设计\n\n- 确定数据结构和接口定义(前后端类型契约)\n- 拆分子任务,估算工时,更新项目管理工具\n- 考虑兼容性(向后兼容)和扩展性\n- 数据库变更:编写 migration 脚本\n- 评估风险点,准备降级 / 回滚方案\n\n## 3. 开发实施\n\n- 从 `develop` 创建 `feature/<功能描述>` 分支\n- 小步提交,每个 commit 可独立编译运行\n- 关键逻辑添加中文注释(说明 why)\n- 添加必要的日志(关键操作、错误路径)\n- 遵循项目代码规范和架构约定\n- 前端:组件拆分 → 数据联调 → 样式完善\n- 后端:接口定义 → 业务逻辑 → 数据层 → 联调\n\n## 4. 自测验证\n\n- 覆盖正常流程和异常流程\n- 边界值测试:空值、超长输入、大数据量\n- 兼容性测试:不同浏览器 / 设备 / 分辨率\n- 权限测试:不同角色是否正确限制\n- 性能验证:大数据量下是否卡顿\n- UI 对照设计稿逐项检查\n\n## 5. 提交审查\n\n- 提交信息:`feat(<scope>): 功能描述`\n- 创建 PR,描述:功能说明 → 实现方案 → 测试方法 → 截图\n- 关联 Issue / Jira 编号\n- 请求 Code Review(至少一人)\n- 根据 Review 意见修改,re-request review\n\n## 6. 合并上线\n\n- Review 通过后 squash merge 到 `develop`\n- 清理 feature 分支\n- 在 develop 环境验证功能完整性\n- 更新 Issue 状态,通知产品验收",
|
||||||
|
"enabled": false,
|
||||||
|
"priority": 20,
|
||||||
|
"metadata": {
|
||||||
|
"author": "user",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"createdAt": "2026-06-02T12:19:59.522Z",
|
||||||
|
"updatedAt": "2026-06-02T12:19:59.522Z",
|
||||||
|
"tags": [
|
||||||
|
"workflow",
|
||||||
|
"feature",
|
||||||
|
"development"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "b9006d07-2193-407e-bddd-8c5910d054f7",
|
||||||
|
"name": "Vue 3 编码规范",
|
||||||
|
"category": "rule",
|
||||||
|
"content": "## 组件规范\n- 必须使用 Composition API + `<script setup>` 语法\n- 组件命名使用 PascalCase(如 `UserProfile.vue`)\n- 单文件组件顺序:`<script setup>` → `<template>` → `<style scoped>`\n- 单个组件文件不超过 200 行,超过则拆分子组件\n- 组件目录结构:`ComponentName/index.vue` + `ComponentName/types.ts`\n\n## Props 与事件\n- Props 必须使用 `defineProps<T>()` 定义 TypeScript 类型\n- 使用 `withDefaults()` 为 Props 设置默认值\n- 事件使用 `defineEmits<{ (e: 'update', value: string): void }>()` 定义\n- Props 命名使用 camelCase,模板中自动转为 kebab-case\n- 避免修改 Props,使用 `emit` 通知父组件变更\n\n## 响应式\n- 优先使用 `ref()` 而非 `reactive()`(避免解构丢失响应性)\n- `computed` 用于派生状态,不要在 `computed` 中产生副作用\n- `watch` 指定具体的响应式源,避免 `watch(() => state)` 监听整个对象\n- 使用 `watchEffect` 处理副作用自动追踪依赖\n- 大型列表使用 `shallowRef` 减少响应式开销\n\n## 模板规范\n- 模板中不要有复杂逻辑,抽取为 `computed` 或方法\n- 列表渲染必须提供唯一 `key`,禁止使用 index\n- 条件渲染优先 `v-if`,频繁切换使用 `v-show`\n- 事件处理器使用 `@click=\"handleClick\"`,不在模板中写逻辑\n\n## 可复用逻辑\n- 可复用逻辑抽取为 composables(`use*.ts`)\n- composable 返回值使用 `ref` 而非 `reactive`\n- composable 内部清理副作用使用 `onUnmounted`\n\n## 样式\n- 使用 `<style scoped>` 或 CSS Modules 避免样式污染\n- 优先使用 Tailwind CSS 原子类,减少自定义 CSS\n- 主题变量使用 CSS 自定义属性(`var(--color-primary)`)",
|
||||||
|
"enabled": false,
|
||||||
|
"priority": 21,
|
||||||
|
"condition": {
|
||||||
|
"filePattern": "**/*.vue"
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"author": "user",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"createdAt": "2026-06-02T12:19:59.522Z",
|
||||||
|
"updatedAt": "2026-06-02T12:19:59.522Z",
|
||||||
|
"tags": [
|
||||||
|
"vue",
|
||||||
|
"frontend"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "28b6216b-4e12-44a6-bdf8-62ef32e580dc",
|
||||||
|
"name": "TypeScript 严格模式",
|
||||||
|
"category": "rule",
|
||||||
|
"content": "## 类型安全\n- 禁止使用 `any`,使用 `unknown` 替代不确定类型\n- 所有函数必须声明参数类型和返回类型\n- 使用 `interface` 定义对象结构,`type` 用于联合类型和工具类型\n- 泛型参数使用有意义的名称(如 `TData`、`TResponse`)\n- 使用 `as const` 断言确保字面量类型推断\n- 避免类型断言 `as`,优先使用类型守卫(type guard)\n\n## 语法规范\n- 使用可选链 `?.` 和空值合并 `??` 替代 `&&` 和 `||`\n- 优先使用 `const enum` 或字面量联合类型替代普通 enum\n- 使用 `readonly` 标记不应被修改的属性和数组\n- 解构赋值时添加默认值:`const { name = '默认' } = options`\n- 异步函数统一使用 `async/await`,禁止 `.then()` 链\n\n## 错误处理\n- 使用自定义错误类继承 `Error`,携带 `code` 字段\n- try/catch 中指定具体错误类型,禁止空 catch\n- Promise 必须处理 rejection(`.catch()` 或 try/catch)\n\n## 命名约定\n- 变量/函数:`camelCase`\n- 类/接口/类型:`PascalCase`\n- 常量:`UPPER_SNAKE_CASE`\n- 私有属性:前缀 `_`(如 `_internalState`)\n- 布尔变量:`is/has/should` 前缀(如 `isLoading`)",
|
||||||
|
"enabled": false,
|
||||||
|
"priority": 22,
|
||||||
|
"condition": {
|
||||||
|
"filePattern": "**/*.ts"
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"author": "user",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"createdAt": "2026-06-02T12:19:59.522Z",
|
||||||
|
"updatedAt": "2026-06-02T12:19:59.522Z",
|
||||||
|
"tags": [
|
||||||
|
"typescript"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "aa47f7ec-f032-47bd-9481-35989dda8961",
|
||||||
|
"name": "Flutter 开发规范",
|
||||||
|
"category": "rule",
|
||||||
|
"content": "## Widget 规范\n- 使用 StatelessWidget 优先,仅在需要内部可变状态时用 StatefulWidget\n- Widget 拆分遵循单一职责,避免超过 100 行的 `build` 方法\n- 使用 `const` 构造函数减少不必要的重建\n- Widget 命名使用 PascalCase,文件名使用 snake_case\n- 将大型 Widget 拆分为私有方法或独立 Widget 类\n\n## 状态管理\n- 优先级:Riverpod > BLoC > Provider > setState\n- 局部状态使用 `ValueNotifier` + `ValueListenableBuilder`\n- 全局/跨页面状态使用 Riverpod 的 `StateNotifierProvider`\n- 异步数据使用 `FutureProvider` / `StreamProvider`\n- 状态类使用 `freezed` 或 `equatable` 实现不可变和相等比较\n\n## 主题与资源\n- 颜色、字体、间距统一在 `ThemeData` 中定义\n- 使用 `Theme.of(context)` 获取主题值,不硬编码颜色\n- 支持亮色/暗色模式切换\n- 文字使用 `TextTheme` 样式,不直接设置 fontSize\n- 间距使用统一常量(如 `Spacing.sm = 8.0`)\n\n## 异步与网络\n- 异步操作使用 `async/await`,避免嵌套 `.then()`\n- 网络请求使用 Dio + 拦截器(日志、认证、错误处理)\n- 图片使用 `cached_network_image`,配置占位图和错误图\n- 接口返回统一解析为 `Result<T>` 类型(Success / Failure)\n\n## 路由与导航\n- 路由统一使用 GoRouter 或 auto_route 管理\n- 路由参数使用强类型,避免字符串传参\n- 深层链接(Deep Link)支持\n\n## 性能优化\n- 禁止在 `build` 方法内做耗时运算或 I/O\n- 长列表使用 `ListView.builder` / `SliverList`,避免一次性构建\n- 使用 `RepaintBoundary` 隔离频繁重绘的区域\n- 动画使用 `AnimatedWidget` / `AnimatedBuilder`,避免全局重建",
|
||||||
|
"enabled": false,
|
||||||
|
"priority": 23,
|
||||||
|
"condition": {
|
||||||
|
"filePattern": "**/*.dart"
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"author": "user",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"createdAt": "2026-06-02T12:19:59.523Z",
|
||||||
|
"updatedAt": "2026-06-02T12:19:59.523Z",
|
||||||
|
"tags": [
|
||||||
|
"flutter",
|
||||||
|
"dart",
|
||||||
|
"mobile"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "8c4caa1f-2cb2-42be-85df-51f041170ff7",
|
||||||
|
"name": "C# 编码规范",
|
||||||
|
"category": "rule",
|
||||||
|
"content": "## 命名规范\n- 类/接口/方法/属性:PascalCase\n- 局部变量/参数:camelCase\n- 常量/静态只读:UPPER_SNAKE_CASE 或 PascalCase\n- 接口前缀 `I`(如 `IUserService`)\n- 异步方法后缀 `Async`(如 `GetUserAsync`)\n- 布尔属性/变量:`Is/Has/Can` 前缀\n\n## 类型与数据\n- 优先使用 `record` 定义不可变数据对象(DTO / Value Object)\n- 使用 nullable 引用类型(`#nullable enable`),公共 API 参数需 null 检查\n- 值类型使用 `struct`,引用类型使用 `class`\n- 集合返回 `IReadOnlyList<T>` / `IReadOnlyCollection<T>`,避免暴露可变集合\n- 使用 `required` 关键字标记必填属性(C# 11+)\n\n## 异步与资源\n- 异步方法返回 `Task` / `Task<T>` / `ValueTask<T>`\n- 使用 `using` 声明(非语句块)管理资源\n- 传递 `CancellationToken` 到所有异步链路\n- 避免 `async void`,仅用于事件处理器\n- I/O 密集操作使用 `ConfigureAwait(false)`(类库中)\n\n## 依赖注入\n- 优先构造函数注入,避免服务定位器模式\n- 注册生命周期:Transient(无状态)/ Scoped(请求级)/ Singleton(全局)\n- 使用 `IOptions<T>` 注入配置对象\n\n## LINQ 与集合\n- LINQ 查询优先方法链形式,避免嵌套查询表达式\n- 大数据集使用 `AsNoTracking()` 提升 EF Core 查询性能\n- 使用 `Any()` 替代 `Count() > 0` 判断非空\n\n## 异常处理\n- 只 catch 能处理的异常,记录日志后重新抛出(`throw;` 保留堆栈)\n- 使用 `ExceptionFilter` / 中间件统一处理 API 异常\n- 自定义异常继承 `Exception`,携带错误码\n\n## 测试\n- 单元测试使用 xUnit + Moq / NSubstitute\n- 集成测试使用 `WebApplicationFactory<T>`\n- 遵循 Arrange-Act-Assert 模式",
|
||||||
|
"enabled": false,
|
||||||
|
"priority": 24,
|
||||||
|
"condition": {
|
||||||
|
"filePattern": "**/*.cs"
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"author": "user",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"createdAt": "2026-06-02T12:19:59.523Z",
|
||||||
|
"updatedAt": "2026-06-02T12:19:59.523Z",
|
||||||
|
"tags": [
|
||||||
|
"csharp",
|
||||||
|
"dotnet",
|
||||||
|
"backend"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "01d64bf0-f272-4950-a0af-99c126245e20",
|
||||||
|
"name": "Java 编码规范",
|
||||||
|
"category": "rule",
|
||||||
|
"content": "## 命名规范\n- 类/接口:PascalCase(如 `UserService`)\n- 方法/变量:camelCase(如 `getUserById`)\n- 常量:UPPER_SNAKE_CASE(如 `MAX_RETRY_COUNT`)\n- 包名:全小写,反向域名(如 `com.example.user`)\n- 布尔方法:`is/has/can` 前缀(如 `isValid()`)\n\n## 现代 Java 特性(17+)\n- 使用 `record` 定义不可变数据对象(DTO)\n- 使用 `sealed class` 限制继承层级\n- 使用 `pattern matching`(`instanceof` + 类型绑定)\n- 使用 `text blocks`(三引号)书写多行字符串\n- Switch 表达式使用箭头语法 + yield\n\n## 集合与 Stream\n- Stream API 用于集合操作,避免传统 for 循环处理集合\n- 使用 `Optional<T>` 替代 null 返回值,禁止 `Optional` 作为方法参数\n- 不可变集合:`List.of()` / `Map.of()` / `Set.of()`\n- 避免在 Stream 中产生副作用(如修改外部变量)\n\n## Spring Boot 架构\n- Controller 只处理 HTTP 映射和参数校验(`@Valid`)\n- 业务逻辑下沉到 Service 层\n- 数据访问使用 JPA Repository 或 MyBatis Mapper,禁止 SQL 拼接\n- 使用 `@Transactional` 管理事务,注意传播行为和回滚规则\n- 配置使用 `@ConfigurationProperties` 绑定,不硬编码\n\n## 异常与日志\n- 异常统一使用 `@ControllerAdvice` + `@ExceptionHandler` 处理\n- 返回标准 `ApiResponse<T>` 格式(code + message + data)\n- 日志使用 SLF4J + Logback,禁止 `System.out.println`\n- 日志级别:ERROR(系统错误)/ WARN(业务异常)/ INFO(关键操作)/ DEBUG(调试)\n- 日志包含上下文信息:用户 ID、请求 ID、耗时\n\n## 测试\n- 单元测试:JUnit 5 + Mockito,覆盖率 > 80%\n- 集成测试:`@SpringBootTest` + `@TestContainers`\n- API 测试:`MockMvc` 或 RestAssured",
|
||||||
|
"enabled": false,
|
||||||
|
"priority": 25,
|
||||||
|
"condition": {
|
||||||
|
"filePattern": "**/*.java"
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"author": "user",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"createdAt": "2026-06-02T12:19:59.523Z",
|
||||||
|
"updatedAt": "2026-06-02T12:19:59.523Z",
|
||||||
|
"tags": [
|
||||||
|
"java",
|
||||||
|
"backend",
|
||||||
|
"spring"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "71d75d65-5c11-4d17-b5fe-22aac0b5d3c5",
|
||||||
|
"name": "React 编码规范",
|
||||||
|
"category": "rule",
|
||||||
|
"content": "## 组件规范\n- 函数组件 + Hooks,禁止使用 Class 组件\n- 组件命名 PascalCase,文件名与组件名一致(如 `UserCard.tsx`)\n- Props 使用 TypeScript `interface` 定义,必须标注类型\n- 使用 `React.FC<Props>` 或直接函数签名声明组件\n- 单个组件文件不超过 200 行,超过则拆分\n\n## 状态管理\n- 局部状态:`useState`\n- 计算状态:`useMemo`\n- 跨组件共享:Context + `useContext` 或 Zustand / Jotai\n- 服务端数据:TanStack Query(React Query)管理请求缓存\n- 避免 prop drilling 超过 3 层,使用 Context 或状态库\n\n## Hooks 规范\n- 自定义 Hook 以 `use` 开头,封装可复用逻辑\n- `useEffect` 依赖数组必须完整,配合 ESLint exhaustive-deps 规则\n- `useCallback` 包裹传给子组件的回调函数\n- `useMemo` 缓存昂贵计算,但不要滥用(简单计算无需缓存)\n- cleanup 函数处理订阅、定时器、AbortController\n\n## 渲染优化\n- 使用 `React.memo()` 避免不必要的子组件重渲染\n- 列表渲染必须提供稳定的 key(业务 ID),禁止使用 index\n- 条件渲染优先使用 `&&` 或三元表达式,避免嵌套 if\n- 大列表使用虚拟滚动(`@tanstack/react-virtual`)\n- 代码分割:`React.lazy()` + `Suspense` 懒加载路由和大组件\n\n## 样式\n- 样式方案:Tailwind CSS 或 CSS Modules,避免内联样式\n- 使用 `clsx` / `cn()` 工具合并条件类名\n- 响应式设计使用 Tailwind 断点前缀(`md:`、`lg:`)\n\n## 错误处理\n- 使用 `ErrorBoundary` 捕获渲染错误,提供 fallback UI\n- 异步操作统一 try/catch,用户友好的错误提示",
|
||||||
|
"enabled": false,
|
||||||
|
"priority": 26,
|
||||||
|
"condition": {
|
||||||
|
"filePattern": "**/*.tsx"
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"author": "user",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"createdAt": "2026-06-02T12:19:59.523Z",
|
||||||
|
"updatedAt": "2026-06-02T12:19:59.523Z",
|
||||||
|
"tags": [
|
||||||
|
"react",
|
||||||
|
"frontend"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "085dc4f6-e5e0-42cb-9e0f-e4ef6f06d290",
|
||||||
|
"name": "Python 编码规范",
|
||||||
|
"category": "rule",
|
||||||
|
"content": "## 代码风格\n- 遵循 PEP 8 风格指南,使用 `black` + `isort` 格式化\n- 类名 PascalCase,函数/变量 snake_case,常量 UPPER_SNAKE_CASE\n- 模块级常量定义在文件顶部(导入之后)\n- 单行不超过 88 字符(black 默认)\n- 使用 `ruff` 作为 linter(替代 flake8 + pylint)\n\n## 类型标注\n- 使用 Type Hints 标注所有函数参数和返回值\n- 复杂类型使用 `typing` 模块(`Optional`、`Union`、`TypeAlias`)\n- Python 3.10+ 使用 `X | Y` 语法替代 `Union[X, Y]`\n- 使用 `mypy --strict` 进行静态类型检查\n- 泛型类使用 `TypeVar` 或 `Generic[T]`\n\n## 数据模型\n- 使用 `dataclass`(内部数据)或 `Pydantic BaseModel`(API 数据校验)\n- Pydantic 模型使用 `Field()` 添加校验规则和描述\n- 不可变数据使用 `frozen=True` 的 dataclass\n\n## 异步与并发\n- I/O 密集操作使用 `asyncio` + `async/await`\n- CPU 密集操作使用 `concurrent.futures.ProcessPoolExecutor`\n- 异步 HTTP 使用 `httpx` / `aiohttp`\n- 异步数据库使用 `SQLAlchemy 2.0` async 模式\n\n## 错误处理与资源\n- 使用 `with` 语句管理文件、连接等资源\n- 异常处理指定具体异常类型,禁止 bare `except:`\n- 自定义异常继承 `Exception`,携带错误码\n- 使用 `logging` 模块记录日志,禁止 `print()` 调试\n\n## 项目管理\n- 使用 `pyproject.toml` 管理项目配置和依赖\n- 虚拟环境:`venv` / `poetry` / `uv`\n- 依赖锁定:`poetry.lock` / `requirements.txt` 固定版本\n- 使用 `pytest` 编写测试,`pytest-cov` 检查覆盖率 > 80%\n- 使用 `pre-commit` 钩子自动检查代码质量",
|
||||||
|
"enabled": false,
|
||||||
|
"priority": 27,
|
||||||
|
"condition": {
|
||||||
|
"filePattern": "**/*.py"
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"author": "user",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"createdAt": "2026-06-02T12:19:59.523Z",
|
||||||
|
"updatedAt": "2026-06-02T12:19:59.523Z",
|
||||||
|
"tags": [
|
||||||
|
"python",
|
||||||
|
"backend"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "9436562b-32d3-4643-94b2-6ef1b9707451",
|
||||||
|
"name": "Go 编码规范",
|
||||||
|
"category": "rule",
|
||||||
|
"content": "## 命名规范\n- 包名小写单词,不使用下划线或混合大小写\n- 导出标识符 PascalCase,内部标识符 camelCase\n- 接口命名:单方法接口用 `-er` 后缀(如 `Reader`、`Writer`)\n- 文件名 snake_case(如 `user_service.go`)\n- 测试文件 `*_test.go`,与被测文件同目录\n\n## 错误处理\n- 每个 `error` 必须检查,禁止 `_ = err` 忽略\n- 使用 `errors.Is()` / `errors.As()` 替代 `==` 比较错误\n- 使用 `fmt.Errorf(\"描述: %w\", err)` 包装错误(保留链路)\n- 自定义错误类型实现 `Error()` 接口\n- 在函数签名中,error 永远是最后一个返回值\n- 使用 sentinel error(包级变量)定义可预期的错误\n\n## 并发与 goroutine\n- goroutine 必须有退出机制,使用 `context.Context` 控制生命周期\n- channel 使用完毕必须 `close`,避免 goroutine 泄漏\n- 使用 `sync.WaitGroup` 等待一组 goroutine 完成\n- 使用 `sync.Mutex` / `sync.RWMutex` 保护共享数据\n- 优先使用 channel 通信,而非共享内存\n- 使用 `errgroup.Group` 管理一组可能出错的 goroutine\n\n## 接口设计\n- 接口小而精:通常 1-3 个方法,由使用方定义\n- 接受接口,返回结构体(依赖倒置)\n- 使用组合(embedding)而非继承\n\n## 资源管理\n- 使用 `defer` 确保资源释放(文件、锁、连接)\n- `defer` 按 LIFO 顺序执行,注意多个 defer 的顺序\n- HTTP Response Body 必须 `defer resp.Body.Close()`\n\n## 项目结构\n- 遵循 Standard Go Project Layout\n- `cmd/`(入口)、`internal/`(私有)、`pkg/`(公共库)\n- 结构体字段使用 `json` tag 标注序列化名称\n- 配置使用 `viper` 或环境变量,不硬编码\n\n## 工具链\n- 使用 `go vet` + `golangci-lint` 进行静态分析\n- 使用 `go test -race` 检测数据竞争\n- 使用 `pprof` 进行性能分析\n- 使用 `go mod tidy` 清理无用依赖",
|
||||||
|
"enabled": false,
|
||||||
|
"priority": 28,
|
||||||
|
"condition": {
|
||||||
|
"filePattern": "**/*.go"
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"author": "user",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"createdAt": "2026-06-02T12:19:59.524Z",
|
||||||
|
"updatedAt": "2026-06-02T12:19:59.524Z",
|
||||||
|
"tags": [
|
||||||
|
"golang",
|
||||||
|
"backend"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "53bad5ac-4a1e-4d83-8089-27a30bece93e",
|
||||||
|
"name": "输出语言为中文",
|
||||||
|
"category": "rule",
|
||||||
|
"content": "## 语言要求\n\n<language_rules>\n- **全程使用中文**回答所有问题,包括思考过程、解释说明、代码注释\n- 变量名、函数名、类名等**标识符保持英文**(遵循编程命名规范)\n- 代码注释必须使用中文书写\n- Git 提交信息使用中文描述\n- 文档和 README 使用中文编写\n- 错误提示和用户提示信息使用中文\n</language_rules>\n\n## 格式规范\n\n<format_rules>\n- 中英文之间添加空格(如:使用 Vue 3 框架)\n- 数字与中文之间添加空格(如:共 3 个文件)\n- 专业术语首次出现时标注英文原文(如:组合式 API (Composition API))\n- 代码块中的输出示例使用中文\n- 表格、列表等结构化内容使用中文标题\n</format_rules>\n\n## 禁止行为\n\n- ❌ 禁止使用英文回答问题\n- ❌ 禁止在注释中混用英文(专业术语除外)\n- ❌ 禁止在解释说明中突然切换为英文",
|
||||||
|
"enabled": false,
|
||||||
|
"priority": 29,
|
||||||
|
"metadata": {
|
||||||
|
"author": "user",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"createdAt": "2026-06-02T12:19:59.524Z",
|
||||||
|
"updatedAt": "2026-06-02T12:19:59.524Z",
|
||||||
|
"tags": [
|
||||||
|
"language",
|
||||||
|
"chinese",
|
||||||
|
"i18n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ba37de52-c870-4064-b5c6-89f6253c39db",
|
||||||
|
"name": "学术论文写作规范",
|
||||||
|
"category": "rule",
|
||||||
|
"content": "## 格式要求\n\n### 论文结构\n- 标题 → 摘要 → 关键词 → 引言 → 文献综述 → 研究方法 → 结果分析 → 讨论 → 结论 → 参考文献 → 附录\n- 每个章节之间逻辑衔接自然,使用过渡句连接上下文\n- 摘要 300-500 字,包含研究目的、方法、主要发现和结论\n- 关键词 3-5 个,涵盖研究核心概念\n\n### 排版规范\n- 正文:宋体/Times New Roman,小四号(12pt),1.5 倍行距\n- 标题层级:一级标题黑体三号 → 二级标题黑体四号 → 三级标题黑体小四号\n- 段落首行缩进 2 字符,段前段后 0.5 行\n- 页边距:上 2.54cm / 下 2.54cm / 左 3.17cm / 右 3.17cm\n- 页码从正文开始,居中显示\n- 图表统一编号(如图 1、表 2),标题居中,图标题在下、表标题在上\n- 公式居中,编号右对齐\n\n## 查重规范\n\n### 重复率要求\n- 本科毕业论文:总重复率 ≤ 30%(部分院校要求 ≤ 20%)\n- 硕士学位论文:总重复率 ≤ 15%\n- 博士学位论文:总重复率 ≤ 10%\n- 期刊投稿:总重复率 ≤ 15%(核心期刊 ≤ 10%)\n\n### 降重技巧\n- **语序调整**:主动句与被动句互换,调整句子成分顺序\n- **同义替换**:使用同义词、近义词替换,但不改变原意\n- **概括改写**:将具体描述概括为抽象表述,用自己的话重新组织\n- **拆分合并**:长句拆为短句,或将短句合并为复合句\n- **增加论述**:在引用观点后加入自己的分析、评价和延伸\n- ❌ 禁止简单替换个别字词(如\"因此\"→\"所以\"),查重系统能识别\n- ❌ 禁止使用翻译法(中→英→中),表述生硬且可能曲解原意\n\n## 去 AI 化规范\n\n### 必须遵守\n- ❌ 禁止出现典型 AI 生成痕迹:\n - \"首先...其次...最后...\"的机械排列\n - \"值得注意的是\"、\"需要指出的是\"等套话高频出现\n - \"综上所述\"在非结论部分反复使用\n - 每段开头都用\"在...方面\"、\"从...角度\"的模板句式\n - 过度使用\"本文\"、\"本研究\"作为主语\n- ✅ 使用自然、多样的表达方式:\n - 变换句式结构:陈述句、反问句、设问句交替使用\n - 融入个人研究视角和独立思考\n - 使用领域专业术语,体现学科素养\n - 段落长短错落有致,避免每段字数雷同\n - 适当使用口语化学术表达(如\"不难发现\"、\"换言之\")\n\n### AI 检测规避\n- 保持个人写作风格一致性(用词习惯、句式偏好)\n- 加入具体案例、数据、图表等实证内容(AI 难以伪造)\n- 融入对研究过程的真实描述(实验细节、调研经历)\n- 对他人观点进行批判性分析,而非简单罗列\n- 论文不同部分的文风应与内容匹配(引言偏叙述、方法偏客观、讨论偏思辨)\n\n## 文献引用规范\n\n### 文献真实性(最高优先级)\n- ⚠️ **所有引用的文献必须真实存在,可通过学术数据库检索到**\n- 引用前必须验证:作者、标题、期刊/出版社、年份、卷期页码均准确\n- 推荐验证渠道:Google Scholar、知网(CNKI)、万方、Web of Science、Scopus\n- ❌ 严禁编造虚假文献(捏造作者、杜撰期刊、伪造年份)\n- ❌ 严禁引用未读过的文献(二手引用需标注\"转引自\")\n- 如无法找到原始文献,宁可删除引用也不要凭记忆补全信息\n\n### 引用格式\n- 中文论文:GB/T 7714 格式(如:[1] 张三. 标题[J]. 期刊名, 2024, 1(2): 10-20.)\n- 英文论文:APA 7th / IEEE / MLA 格式(根据目标期刊要求选择)\n- 正文引用与参考文献列表一一对应,不多不少\n- 引用数量建议:本科 15-30 篇,硕士 40-80 篇,博士 80-150 篇\n- 近 5 年文献占比 ≥ 50%,体现研究前沿性\n- 中英文文献比例合理(理工科英文 ≥ 60%)\n\n## 上下文连贯性\n\n### 全文一致性\n- 研究问题、方法、结果、结论之间逻辑链条完整\n- 摘要中的结论必须与正文结论一致\n- 引言提出的问题必须在结论中回应\n- 文献综述的内容必须与研究方法选择相关\n- 术语全文统一:同一概念不要交替使用不同名称\n\n### 段落衔接\n- 每段有明确的主题句(通常在段首)\n- 段与段之间使用过渡句或过渡词连接\n- 常用过渡逻辑:因果(因此)、转折(然而)、递进(此外)、对比(相比之下)\n- 避免突然跳转话题,新观点需有铺垫\n- 每章末尾可加小结,呼应章首并过渡到下一章\n\n### 语言风格一致\n- 全文保持同一人称视角(推荐第三人称或\"本文\")\n- 时态一致:文献综述用过去时,研究方法用过去时,结论用现在时\n- 学术语体一致:不在严谨论述中突然出现口语化表达\n- 专业术语首次出现时给出定义或英文原文",
|
||||||
|
"enabled": false,
|
||||||
|
"priority": 30,
|
||||||
|
"metadata": {
|
||||||
|
"author": "user",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"createdAt": "2026-06-02T12:19:59.524Z",
|
||||||
|
"updatedAt": "2026-06-02T12:19:59.524Z",
|
||||||
|
"tags": [
|
||||||
|
"paper",
|
||||||
|
"academic",
|
||||||
|
"writing"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "37bc6709-803d-40d4-b34b-fe999abe9435",
|
||||||
|
"name": "代码审查规范",
|
||||||
|
"category": "context",
|
||||||
|
"content": "## 代码结构\n- 函数长度不超过 50 行,文件不超过 300 行\n- 嵌套不超过 3 层,使用早返回(guard clause)减少嵌套\n- 单一职责:每个函数/类只做一件事\n- 避免上帝类(God Class)和上帝函数\n\n## 命名规范\n- 变量/函数:camelCase(如 `getUserById`)\n- 类/接口/类型:PascalCase(如 `UserService`)\n- 常量:UPPER_SNAKE_CASE(如 `MAX_RETRY_COUNT`)\n- 布尔变量:`is/has/should/can` 前缀\n- 命名必须语义清晰,禁止单字母变量(循环计数器除外)\n\n## 代码质量\n- 避免魔法数字,使用命名常量\n- 不要吞掉异常(空 catch),至少记录日志\n- 不要注释掉代码,直接删除(Git 有历史记录)\n- 注释说明 why 而非 what,使用中文注释\n- 删除未使用的导入、变量和代码(dead code)\n\n## 错误处理\n- 异常必须处理:捕获后记录日志或向上抛出\n- 使用自定义错误类型,携带错误码\n- 异步操作必须有超时和错误处理\n- 用户可见的错误信息使用中文,友好且有指导性\n\n## 安全检查\n- 用户输入必须校验(类型、长度、范围、格式)\n- SQL 使用参数化查询,禁止拼接\n- 敏感数据不在日志中输出",
|
||||||
|
"enabled": false,
|
||||||
|
"priority": 31,
|
||||||
|
"metadata": {
|
||||||
|
"author": "user",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"createdAt": "2026-06-02T12:19:59.524Z",
|
||||||
|
"updatedAt": "2026-06-02T12:19:59.524Z",
|
||||||
|
"tags": [
|
||||||
|
"review",
|
||||||
|
"quality"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "b4f2b2c5-5796-4bd3-b4a4-9559eb2da777",
|
||||||
|
"name": "项目概述上下文",
|
||||||
|
"category": "context",
|
||||||
|
"content": "## 项目信息\n- **项目名称**:[填写项目名称]\n- **项目类型**:[Web 应用 / 桌面应用 / 移动应用 / 后端服务 / CLI 工具 / 浏览器扩展]\n- **主要语言**:[TypeScript / Python / Java / Go / C# / Dart / Rust]\n- **框架**:[Vue 3 / React / NestJS / Spring Boot / Flutter / Electron]\n- **包管理器**:[yarn / pnpm / npm / pip / gradle / cargo]\n- **Node.js 版本**:[18 LTS / 20 LTS / 22]\n\n## 目录结构\n```\nsrc/\n components/ # UI 组件\n composables/ # 可复用逻辑(Vue)/ hooks/(React)\n services/ # API 调用和业务服务\n stores/ # 状态管理(Pinia / Zustand)\n types/ # TypeScript 类型定义\n utils/ # 工具函数\n assets/ # 静态资源(图片、字体、样式)\n router/ # 路由配置\n i18n/ # 国际化文件\npublic/ # 公共静态文件\n```\n\n## 开发约定\n- **代码风格**:ESLint + Prettier,提交前自动格式化\n- **分支策略**:Git Flow(main / develop / feature / fix / release)\n- **提交规范**:Conventional Commits(feat / fix / docs / refactor)\n- **部署方式**:[Docker / Vercel / Nginx / PM2]\n- **CI/CD**:[GitHub Actions / GitLab CI / Jenkins]\n\n## 关键依赖\n| 依赖 | 版本 | 用途 |\n|------|------|------|\n| [框架名] | ^x.y.z | [用途] |\n| [UI 库] | ^x.y.z | [用途] |\n| [状态管理] | ^x.y.z | [用途] |\n\n## 环境变量\n| 变量名 | 说明 | 示例 |\n|--------|------|------|\n| `VITE_API_URL` | API 地址 | `http://localhost:3000` |\n| `DATABASE_URL` | 数据库连接 | `postgresql://...` |\n\n## 注意事项\n- [填写项目特殊约定、已知限制、技术债务等]",
|
||||||
|
"enabled": false,
|
||||||
|
"priority": 32,
|
||||||
|
"metadata": {
|
||||||
|
"author": "user",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"createdAt": "2026-06-02T12:19:59.525Z",
|
||||||
|
"updatedAt": "2026-06-02T12:19:59.525Z",
|
||||||
|
"tags": [
|
||||||
|
"context",
|
||||||
|
"project",
|
||||||
|
"overview"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "7858a396-3f31-4a56-9cd6-192684980339",
|
||||||
|
"name": "调试排错上下文",
|
||||||
|
"category": "context",
|
||||||
|
"content": "## 调试原则\n- 先复现问题,记录复现步骤和环境信息\n- 从错误日志和堆栈信息入手,定位出错位置\n- 使用二分法缩小问题范围(注释代码 / `git bisect`)\n- 区分根本原因和表面症状,修复根因\n- 一次只改一个变量,验证后再改下一个\n- 不要猜测,用数据和日志证明假设\n\n## 常见问题排查清单\n\n### 编译 / 构建错误\n- 类型定义缺失或不匹配\n- 导入路径错误(相对路径 / 别名配置)\n- 依赖版本冲突(`yarn why <package>`)\n- tsconfig 配置问题(`moduleResolution`、`paths`)\n\n### 运行时错误\n- 空值访问:`TypeError: Cannot read property of undefined`\n- 异步时序:Promise 未 await、竞态条件\n- 数组越界 / 对象属性不存在\n- 循环引用导致栈溢出\n- 类型不匹配:字符串 vs 数字、JSON 解析失败\n\n### 样式问题\n- 选择器优先级:Specificity 计算、`!important` 覆盖\n- z-index 层级混乱:建立统一的 z-index 层级体系\n- Flex / Grid 布局:`flex-shrink`、`overflow`、`min-width: 0`\n- 响应式断点:移动端 viewport、媒体查询顺序\n\n### 性能问题\n- 前端:N 次不必要的重渲染(React DevTools Profiler)\n- 后端:N+1 查询(ORM 日志)、慢查询(`EXPLAIN ANALYZE`)\n- 内存泄漏:事件监听未清理、闭包引用大对象\n- 网络:请求瀑布流、缺少缓存策略\n\n### 网络问题\n- CORS:`Access-Control-Allow-Origin` 配置\n- 请求格式:`Content-Type` 不匹配\n- 认证:Token 过期 / 缺失、Cookie SameSite 策略\n- 超时:设置合理的 timeout 值、重试机制\n\n## 调试工具\n\n| 场景 | 工具 | 用途 |\n|------|------|------|\n| 前端 | Chrome DevTools | Network / Console / Performance / Memory |\n| 前端 | React / Vue DevTools | 组件树、状态、渲染次数 |\n| Node.js | `--inspect` | 断点调试(配合 Chrome DevTools) |\n| Node.js | `clinic.js` | 性能分析(CPU / 内存 / 事件循环) |\n| 数据库 | `EXPLAIN ANALYZE` | 查询执行计划分析 |\n| 网络 | Postman / cURL | API 请求调试 |\n| 日志 | `console.time()` | 简单计时 |\n\n## 日志调试技巧\n- 使用结构化日志:`console.log({ userId, action, result })`\n- 在关键分支添加标记日志:`[DEBUG] 进入分支 A`\n- 调试完毕后清理所有调试日志(或使用 DEBUG 环境变量控制)",
|
||||||
|
"enabled": false,
|
||||||
|
"priority": 33,
|
||||||
|
"metadata": {
|
||||||
|
"author": "user",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"createdAt": "2026-06-02T12:19:59.525Z",
|
||||||
|
"updatedAt": "2026-06-02T12:19:59.525Z",
|
||||||
|
"tags": [
|
||||||
|
"context",
|
||||||
|
"debug",
|
||||||
|
"troubleshoot"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "b4d48ce5-93d3-4a77-a850-5cb7a8d21757",
|
||||||
|
"name": "架构设计上下文",
|
||||||
|
"category": "context",
|
||||||
|
"content": "## SOLID 原则\n- **单一职责(SRP)**:每个模块/类只负责一件事\n- **开闭原则(OCP)**:对扩展开放,对修改关闭(策略模式、插件机制)\n- **里氏替换(LSP)**:子类可以替换父类而不破坏行为\n- **接口隔离(ISP)**:客户端不应被迫依赖不使用的接口\n- **依赖倒置(DIP)**:高层模块依赖抽象,不依赖具体实现\n\n## 分层架构\n\n```\n┌──────────────────┐\n│ 表现层 │ ← UI 组件、页面路由、用户交互\n│ (Presentation) │ Vue/React 组件、模板、样式\n├──────────────────┤\n│ 业务逻辑层 │ ← Service、Store、Composable/Hook\n│ (Business) │ 业务规则、数据转换、状态管理\n├──────────────────┤\n│ 数据访问层 │ ← Repository、API Client、ORM\n│ (Data Access) │ 接口调用、数据库操作、缓存\n├──────────────────┤\n│ 基础设施层 │ ← 数据库、缓存、消息队列、文件存储\n│ (Infrastructure)│ 第三方服务、系统配置\n└──────────────────┘\n```\n\n- 上层只依赖下层,禁止跨层调用和反向依赖\n- 每层通过接口(Interface)暴露能力,隐藏实现细节\n\n## 常用设计模式\n- **策略模式**:多种算法/行为可切换(如支付方式、认证方式)\n- **观察者模式**:事件驱动解耦(EventEmitter、Vue 的 watch)\n- **工厂模式**:根据条件创建不同实例\n- **适配器模式**:统一不同第三方服务的接口\n- **装饰器模式**:横切关注点(日志、缓存、权限检查)\n- **仓储模式**:抽象数据访问,隔离业务逻辑和存储细节\n\n## 设计决策记录(ADR)\n\n```markdown\n### ADR-001: [决策标题]\n- **状态**:已采纳 / 待评审 / 已废弃\n- **背景**:为什么需要这个决策\n- **决策**:选择了什么方案\n- **替代方案**:考虑过哪些其他方案\n- **后果**:这个决策带来的正面和负面影响\n```\n\n## 扩展性考量\n- 模块化:功能按领域拆分为独立模块\n- 插件化:核心功能之外的能力通过插件扩展\n- 配置驱动:行为差异通过配置而非代码分支控制\n- 向后兼容:API 变更使用版本化,数据迁移支持回滚",
|
||||||
|
"enabled": false,
|
||||||
|
"priority": 34,
|
||||||
|
"metadata": {
|
||||||
|
"author": "user",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"createdAt": "2026-06-02T12:19:59.525Z",
|
||||||
|
"updatedAt": "2026-06-02T12:19:59.525Z",
|
||||||
|
"tags": [
|
||||||
|
"context",
|
||||||
|
"architecture",
|
||||||
|
"design"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "5428d1da-a5c1-448f-8f9a-959fcc206a19",
|
||||||
|
"name": "技术栈上下文",
|
||||||
|
"category": "context",
|
||||||
|
"content": "## 前端技术栈\n\n| 分类 | 技术 | 版本 | 说明 |\n|------|------|------|------|\n| 框架 | Vue 3 / React 19 | latest | Composition API / Hooks |\n| 语言 | TypeScript | ^5.x | 严格模式 |\n| 构建 | Vite | ^5.x / ^6.x | 开发服务器 + 生产构建 |\n| UI 库 | Ant Design Vue / shadcn/ui | latest | 主要组件库 |\n| 样式 | Tailwind CSS | ^3.x / ^4.x | 原子化 CSS |\n| 状态 | Pinia / Zustand | latest | 全局状态管理 |\n| 路由 | Vue Router / React Router | latest | SPA 路由 |\n| HTTP | Axios / ky / fetch | latest | API 请求 |\n| 图标 | Lucide Icons | latest | SVG 图标库 |\n| 表格 | VXE-Table / TanStack Table | latest | 高性能表格 |\n| 表单 | VeeValidate / React Hook Form | latest | 表单校验 |\n| 国际化 | vue-i18n / react-intl | latest | 多语言 |\n| 图表 | ECharts / D3.js | latest | 数据可视化 |\n\n## 后端技术栈\n\n| 分类 | 技术 | 版本 | 说明 |\n|------|------|------|------|\n| 运行时 | Node.js | 20 LTS / 22 | 服务端 JavaScript |\n| 框架 | Express / NestJS / Fastify | latest | Web 框架 |\n| 数据库 | PostgreSQL | 16 | 主数据库 |\n| 缓存 | Redis | 7 | 缓存 + 会话 + 消息队列 |\n| ORM | Prisma / TypeORM / Drizzle | latest | 数据库操作 |\n| 认证 | JWT + bcrypt / Passport | latest | 认证授权 |\n| 校验 | zod / class-validator | latest | 入参校验 |\n| 日志 | Winston / Pino | latest | 结构化日志 |\n| 队列 | BullMQ / RabbitMQ | latest | 异步任务 |\n\n## 工具链\n\n| 分类 | 技术 | 说明 |\n|------|------|------|\n| 包管理 | Yarn / pnpm | 依赖管理 |\n| 代码风格 | ESLint + Prettier | 检查 + 格式化 |\n| Git 钩子 | husky + lint-staged | 提交前检查 |\n| 提交规范 | commitlint | Conventional Commits |\n| 版本控制 | Git | 源码管理 |\n| CI/CD | GitHub Actions / GitLab CI | 自动化流水线 |\n| 容器化 | Docker + docker-compose | 开发 + 部署 |\n| 部署 | Nginx / Caddy | 反向代理 + 静态托管 |\n| 监控 | Prometheus + Grafana | 性能监控 |\n| E2E 测试 | Playwright | 端到端自动化测试 |",
|
||||||
|
"enabled": false,
|
||||||
|
"priority": 35,
|
||||||
|
"metadata": {
|
||||||
|
"author": "user",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"createdAt": "2026-06-02T12:19:59.525Z",
|
||||||
|
"updatedAt": "2026-06-02T12:19:59.525Z",
|
||||||
|
"tags": [
|
||||||
|
"context",
|
||||||
|
"tech-stack",
|
||||||
|
"environment"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "35f7e2bb-513b-4d2f-85b1-556868ce9759",
|
||||||
|
"name": "论文写作上下文",
|
||||||
|
"category": "context",
|
||||||
|
"content": "## 当前论文信息\n\n- **论文题目**:[填写题目]\n- **论文类型**:[本科毕业论文 / 硕士学位论文 / 博士学位论文 / 期刊论文 / 会议论文]\n- **所属学科**:[填写学科方向]\n- **目标期刊/学校**:[填写期刊名称或学校名称]\n- **字数要求**:[填写字数]\n- **查重要求**:[填写重复率上限,如 ≤ 20%]\n- **引用格式**:[GB/T 7714 / APA / IEEE / MLA]\n- **截止日期**:[填写日期]\n\n## 研究核心\n\n- **研究问题**:[核心研究问题是什么]\n- **研究假设**:[填写研究假设]\n- **研究方法**:[定性 / 定量 / 混合方法;实验 / 调查 / 案例分析等]\n- **核心论点**:[本文的中心论点]\n- **主要贡献**:[理论贡献 / 实践价值 / 创新点]\n\n## 章节进度\n\n| 章节 | 状态 | 字数 | 备注 |\n|------|------|------|------|\n| 摘要(中文) | [未开始/进行中/已完成] | | |\n| 摘要(英文) | [未开始/进行中/已完成] | | |\n| 第一章 引言 | [未开始/进行中/已完成] | | |\n| 第二章 文献综述 | [未开始/进行中/已完成] | | |\n| 第三章 研究方法 | [未开始/进行中/已完成] | | |\n| 第四章 结果分析 | [未开始/进行中/已完成] | | |\n| 第五章 讨论 | [未开始/进行中/已完成] | | |\n| 第六章 结论 | [未开始/进行中/已完成] | | |\n| 参考文献 | [未开始/进行中/已完成] | | |\n\n## 核心术语表\n\n> 保持全文术语统一,同一概念只用一个名称\n\n| 中文术语 | 英文术语 | 首次定义位置 | 说明 |\n|----------|----------|-------------|------|\n| [填写] | [填写] | 第X章 | [填写定义] |\n\n## 关键文献清单\n\n> 已核实真实存在的核心参考文献(写作前必须完成验证)\n\n| 序号 | 作者 | 标题 | 来源 | 年份 | 验证状态 |\n|------|------|------|------|------|----------|\n| 1 | [填写] | [填写] | [期刊/出版社] | [年份] | ✅已验证 |\n\n## 写作约束\n\n### 本论文特殊要求\n- [填写导师或目标期刊的特殊格式要求]\n- [填写禁止引用的文献范围,如:不引用非正式网络资源]\n- [填写特殊术语使用规范]\n\n### AI 辅助边界\n- ✅ 允许:润色语言表达、检查语法错误、格式排版建议\n- ✅ 允许:提供相关文献检索方向(但必须自行验证真实性)\n- ✅ 允许:提供论述思路和结构框架\n- ❌ 禁止:直接生成正文段落作为最终内容\n- ❌ 禁止:生成参考文献(必须自己查找并验证)\n- ❌ 禁止:编造实验数据、调研结果、案例信息\n\n## 上下文一致性检查清单\n\n在每次续写或修改前确认:\n\n- [ ] 当前写作的章节与研究问题保持关联\n- [ ] 使用的术语与术语表保持一致\n- [ ] 引用的文献均在关键文献清单中且已验证\n- [ ] 本段内容与上一段有逻辑衔接\n- [ ] 数据/结论与前文描述不矛盾\n- [ ] 写作风格与全文保持一致",
|
||||||
|
"enabled": false,
|
||||||
|
"priority": 36,
|
||||||
|
"metadata": {
|
||||||
|
"author": "user",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"createdAt": "2026-06-02T12:19:59.526Z",
|
||||||
|
"updatedAt": "2026-06-02T12:19:59.526Z",
|
||||||
|
"tags": [
|
||||||
|
"context",
|
||||||
|
"paper",
|
||||||
|
"academic",
|
||||||
|
"writing"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"profiles": [
|
||||||
|
{
|
||||||
|
"id": "default",
|
||||||
|
"name": "默认",
|
||||||
|
"description": "默认配置集",
|
||||||
|
"ruleIds": [],
|
||||||
|
"isActive": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
# 最高优先级规则 - 必须严格遵守(Cursor 专用)
|
||||||
|
|
||||||
|
⚠️⚠️⚠️ 每次回复结束前必须执行以下命令!没有任何例外!⚠️⚠️⚠️
|
||||||
|
|
||||||
|
## 执行规则
|
||||||
|
|
||||||
|
1. 完成任务后,执行弹窗命令(跨平台,Windows/Mac/Linux 通用):
|
||||||
|
node "/Users/freedak/.ranjin-mode/dialog-trigger.js" "cursor" "fl2cxu" "AI想要结束的原因摘要"
|
||||||
|
|
||||||
|
📱 **手机端通知**:执行此命令时会自动通知手机端(如果远程服务已开启),用户可以在手机上查看消息并发送反馈。
|
||||||
|
|
||||||
|
2. 仔细阅读命令输出的每一行:
|
||||||
|
- ACTION: continue 或 end(用户的选择)
|
||||||
|
- FEEDBACK: 用户输入的具体指令或反馈内容(⚠️ 必须完整阅读并执行!)
|
||||||
|
* 反馈可能来自电脑端弹窗或手机端远程输入
|
||||||
|
- IMAGES: 用户上传的图片路径(如有,必须用read_file工具查看)
|
||||||
|
|
||||||
|
3. 根据输出决定下一步:
|
||||||
|
- 如果 ACTION 是 "continue":
|
||||||
|
* ⚠️ 必须仔细阅读 FEEDBACK 后面的全部内容
|
||||||
|
* ⚠️ 必须按照 FEEDBACK 中用户的具体指令执行任务
|
||||||
|
* ⚠️ 不要忽略 FEEDBACK,不要只说"用户选择继续"
|
||||||
|
- 如果 ACTION 是 "end" 或 "stop":停止工作
|
||||||
|
- ⚠️ 如果命令被取消/跳过/无输出:必须重新执行弹窗命令!
|
||||||
|
|
||||||
|
## 核心规则
|
||||||
|
|
||||||
|
1. 完整输出 - 输出完整代码和答案,禁止省略
|
||||||
|
2. 持续执行 - 复杂任务一次性完成
|
||||||
|
3. 结束确认 - 必须执行弹窗命令后才能结束
|
||||||
|
4. FEEDBACK必读 - 用户的FEEDBACK是新的任务指令,必须执行
|
||||||
|
|
||||||
|
## 手机端远程功能
|
||||||
|
|
||||||
|
- 📱 当执行 dialog-trigger.js 命令时,会自动通知手机端(如果远程服务已开启)
|
||||||
|
- 📱 用户可以在手机浏览器中查看 AI 的消息和状态
|
||||||
|
- 📱 用户可以在手机上输入反馈,反馈会通过 FEEDBACK 字段传递给你
|
||||||
|
- 📱 手机端和电脑端弹窗功能完全同步,支持双向通信
|
||||||
|
|
||||||
|
## ⚠️ 唯一合法的结束条件
|
||||||
|
|
||||||
|
只有当命令输出包含 ACTION: end 或 ACTION: stop 时才能结束对话!
|
||||||
|
以下情况都不能结束,必须重新执行弹窗命令:
|
||||||
|
- 命令被用户点击 Skip 跳过
|
||||||
|
- 命令执行失败或超时
|
||||||
|
- 命令没有输出
|
||||||
|
- 工作区取消了命令
|
||||||
|
|
||||||
|
## 禁止
|
||||||
|
|
||||||
|
- 禁止不执行弹窗命令就结束
|
||||||
|
- 禁止跳过弹窗流程
|
||||||
|
- 禁止忽略FEEDBACK内容
|
||||||
|
- 禁止在没有收到 ACTION: end/stop 的情况下结束
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
# macOS
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# 编辑器 / IDE
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
*.swp
|
||||||
|
|
||||||
|
# Go
|
||||||
|
tcs-iptv/bin/
|
||||||
|
*.test
|
||||||
|
*.out
|
||||||
|
vendor/
|
||||||
|
|
||||||
|
# Node / 前端
|
||||||
|
tcs-iptv/web-console/node_modules/
|
||||||
|
tcs-iptv/web-console/dist/
|
||||||
|
tcs-iptv/web-console/build/
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# 环境与密钥
|
||||||
|
.env
|
||||||
|
*.local
|
||||||
|
*.key
|
||||||
|
*.pem
|
||||||
|
|
||||||
|
# 日志与临时
|
||||||
|
*.log
|
||||||
|
/tmp/
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
---
|
||||||
|
inclusion: always
|
||||||
|
---
|
||||||
|
|
||||||
|
# AI Coding 工作流规则
|
||||||
|
|
||||||
|
本规则定义从需求到交付的标准化协作流程。所有涉及"做一个项目 / 实现一个功能"的请求,均遵循以下五个阶段,逐阶段产出文档并在每个关键节点等待用户确认后再推进。
|
||||||
|
|
||||||
|
## 命名约定
|
||||||
|
|
||||||
|
- 项目英文缩写记为 `XXX`(如 IPTV、AVCC),由用户提供或与用户确认。
|
||||||
|
- 文档统一命名并置于项目根目录(或用户指定目录):
|
||||||
|
- `0-req-XXX.md` — 需求与目标文档
|
||||||
|
- `1-prd-XXX.md` — 产品需求文档(PRD)
|
||||||
|
- `2-task-XXX.md` — 开发任务文档
|
||||||
|
|
||||||
|
## 阶段流程
|
||||||
|
|
||||||
|
### 阶段 1:接收需求与目标
|
||||||
|
- 用户给出需求和目标描述,可以是一段文字,也可以是一份 md 文档。
|
||||||
|
- 我先完整读取并理解用户的需求与目标;若有歧义或关键信息缺失,先向用户澄清,不臆测。
|
||||||
|
|
||||||
|
### 阶段 2:生成 `0-req-XXX.md`(需求文档)
|
||||||
|
- 基于用户的需求与目标,生成 `0-req-XXX.md`。
|
||||||
|
- 内容应包含:引言、术语表、角色定义、功能性需求(采用 EARS 格式:WHEN/IF/WHILE/WHERE/THE...SHALL)、非功能性需求、关键约束与假设。
|
||||||
|
- 生成后**必须请用户检查确认**。未确认前不进入下一阶段。
|
||||||
|
- 用户提出修改意见时,更新文档并再次请其确认,直到通过。
|
||||||
|
|
||||||
|
### 阶段 3:生成 `1-prd-XXX.md`(产品需求文档)
|
||||||
|
- 仅在 `0-req-XXX.md` 确认通过后进行。
|
||||||
|
- 基于需求文档生成 `1-prd-XXX.md`。
|
||||||
|
- 内容应包含:产品概述与定位、目标与成功指标、用户画像与核心场景(每个场景标注"痛点解法")、功能清单与优先级(MoSCoW,并映射回需求编号)、关键流程、角色权限矩阵、版本规划、非功能性要求、依赖与风险。
|
||||||
|
- 生成后**必须请用户检查确认**。未确认前不进入下一阶段。
|
||||||
|
|
||||||
|
### 阶段 4:生成 `2-task-XXX.md`(开发任务文档)
|
||||||
|
- 仅在 `1-prd-XXX.md` 确认通过后进行。
|
||||||
|
- 生成 `2-task-XXX.md`,用于指导开发,包含详细的工作任务分解。
|
||||||
|
- 任务要求:
|
||||||
|
- 以可勾选清单(`- [ ]`)组织,编号清晰,粒度可执行可验证。
|
||||||
|
- 每个任务标注:目标、对应的需求/PRD 条目、验收标准、依赖关系。
|
||||||
|
- 区分优先级与阶段(如 MVP / 二期 / 三期)。
|
||||||
|
- **开发过程中根据实际进度持续更新该文档**(勾选完成项、记录变更、补充新任务)。
|
||||||
|
- 生成后**必须请用户确认**。
|
||||||
|
|
||||||
|
### 阶段 5:按任务文档执行开发
|
||||||
|
- 仅在 `2-task-XXX.md` 确认通过后开始编码。
|
||||||
|
- 严格按确认的任务文档推进开发工作。
|
||||||
|
- 每完成一个任务或一组任务:
|
||||||
|
- 进行相应的测试(构建、单元测试、必要时集成测试)。
|
||||||
|
- 更新 `2-task-XXX.md` 的任务状态与进度记录。
|
||||||
|
- 与用户交互、汇报进展、确认下一步。
|
||||||
|
- 持续推进,直至完成全部任务。
|
||||||
|
|
||||||
|
## 通用约束
|
||||||
|
|
||||||
|
- 每个阶段的产出都要等待用户确认,不得跨阶段抢跑。
|
||||||
|
- 文档之间保持可追溯:PRD 功能映射回需求编号,任务映射回需求/PRD 条目。
|
||||||
|
- 当上游文档(需求或 PRD)发生变更时,同步更新下游文档,保持一致。
|
||||||
|
- 用户的语言即回复与文档的语言(默认中文)。
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
# 最高优先级规则 - 必须严格遵守(Windsurf 专用)
|
||||||
|
|
||||||
|
⚠️⚠️⚠️ 每次回复结束前必须执行以下命令!没有任何例外!⚠️⚠️⚠️
|
||||||
|
|
||||||
|
## 执行规则
|
||||||
|
|
||||||
|
1. 完成任务后,执行弹窗命令(跨平台,Windows/Mac/Linux 通用):
|
||||||
|
node "/Users/freedak/.ranjin-mode/dialog-trigger.js" "windsurf" "fl2cxu" "AI想要结束的原因摘要"
|
||||||
|
|
||||||
|
📱 **手机端通知**:执行此命令时会自动通知手机端(如果远程服务已开启),用户可以在手机上查看消息并发送反馈。
|
||||||
|
|
||||||
|
2. 仔细阅读命令输出的每一行:
|
||||||
|
- ACTION: continue 或 end(用户的选择)
|
||||||
|
- FEEDBACK: 用户输入的具体指令或反馈内容(⚠️ 必须完整阅读并执行!)
|
||||||
|
* 反馈可能来自电脑端弹窗或手机端远程输入
|
||||||
|
- IMAGES: 用户上传的图片路径(如有,必须用read_file工具查看)
|
||||||
|
|
||||||
|
3. 根据输出决定下一步:
|
||||||
|
- 如果 ACTION 是 "continue":
|
||||||
|
* ⚠️ 必须仔细阅读 FEEDBACK 后面的全部内容
|
||||||
|
* ⚠️ 必须按照 FEEDBACK 中用户的具体指令执行任务
|
||||||
|
* ⚠️ 不要忽略 FEEDBACK,不要只说"用户选择继续"
|
||||||
|
- 如果 ACTION 是 "end" 或 "stop":停止工作
|
||||||
|
- ⚠️ 如果命令被取消/跳过/无输出:必须重新执行弹窗命令!
|
||||||
|
|
||||||
|
## 核心规则
|
||||||
|
|
||||||
|
1. 完整输出 - 输出完整代码和答案,禁止省略
|
||||||
|
2. 持续执行 - 复杂任务一次性完成
|
||||||
|
3. 结束确认 - 必须执行弹窗命令后才能结束
|
||||||
|
4. FEEDBACK必读 - 用户的FEEDBACK是新的任务指令,必须执行
|
||||||
|
|
||||||
|
## 手机端远程功能
|
||||||
|
|
||||||
|
- 📱 当执行 dialog-trigger.js 命令时,会自动通知手机端(如果远程服务已开启)
|
||||||
|
- 📱 用户可以在手机浏览器中查看 AI 的消息和状态
|
||||||
|
- 📱 用户可以在手机上输入反馈,反馈会通过 FEEDBACK 字段传递给你
|
||||||
|
- 📱 手机端和电脑端弹窗功能完全同步,支持双向通信
|
||||||
|
|
||||||
|
## ⚠️ 唯一合法的结束条件
|
||||||
|
|
||||||
|
只有当命令输出包含 ACTION: end 或 ACTION: stop 时才能结束对话!
|
||||||
|
以下情况都不能结束,必须重新执行弹窗命令:
|
||||||
|
- 命令被用户点击 Skip 跳过
|
||||||
|
- 命令执行失败或超时
|
||||||
|
- 命令没有输出
|
||||||
|
- 工作区取消了命令
|
||||||
|
|
||||||
|
## 禁止
|
||||||
|
|
||||||
|
- 禁止不执行弹窗命令就结束
|
||||||
|
- 禁止跳过弹窗流程
|
||||||
|
- 禁止忽略FEEDBACK内容
|
||||||
|
- 禁止在没有收到 ACTION: end/stop 的情况下结束
|
||||||
@@ -0,0 +1,413 @@
|
|||||||
|
# TCS-IPTV 内容可信锁定系统 — 需求规格说明书
|
||||||
|
|
||||||
|
> 版本:V1.0
|
||||||
|
> 编制日期:2026年6月
|
||||||
|
> 基于文档:《MA+哈希码 IPTV内容可信锁定系统(TCS-IPTV)完整方案》
|
||||||
|
> 文档编号:0-req-IPTV
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 引言
|
||||||
|
|
||||||
|
本需求文档定义 TCS-IPTV(Trusted Content System for IPTV)内容可信锁定系统的功能性与非功能性需求。系统通过"MA码(监管身份)+ 哈希码(技术指纹)"双锚定机制,在 CP(内容供应商)、IPTV 集成播控平台、运营商(分发网络)三方现有系统之上建立一层"可信身份映射层",实现 IPTV 内容"审过即锁定,锁定即通行,通行可追溯"。
|
||||||
|
|
||||||
|
本系统的核心约束是:**不替代三方现有系统**,仅在关键节点(送审、入库、分发、播放)以最小侵入方式嵌入校验能力,并通过映射层统一对接。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 术语表
|
||||||
|
|
||||||
|
| 术语 | 全称 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| TCS-IPTV | Trusted Content System for IPTV | IPTV 内容可信锁定系统 |
|
||||||
|
| CP | Content Provider | 内容供应商 |
|
||||||
|
| 播控平台 | — | IPTV 集成播控平台 |
|
||||||
|
| 运营商 | — | IPTV 分发网络运营方(如中国电信、中国移动) |
|
||||||
|
| MA码 | — | 监管身份主键,由广电总局/省局签发(如网络剧片发行许可证号/备案号) |
|
||||||
|
| CTID | Content Twin ID | 内容孪生标识,由 MA码+哈希+版本+Merkle根 构成的唯一标识 |
|
||||||
|
| 文件哈希 | File Hash | SHA-256 算法,比特级敏感,精确锁定某版本文件 |
|
||||||
|
| 感知哈希 | Perceptual Hash | aHash/dHash/pHash,容忍转码压缩,跨格式识别同一内容 |
|
||||||
|
| Merkle Tree | — | 分段聚合哈希树,用于多集/长内容的分段定位 |
|
||||||
|
| 可信数据空间 | — | 基于联盟链/分布式账本的可信身份映射层 |
|
||||||
|
| EPG | Electronic Program Guide | 电子节目指南 |
|
||||||
|
| CSPS | Content Safety/Review Platform System | 审核和监管部门已有的内容审核系统 |
|
||||||
|
| 媒体资源库 | Media Asset Library | 审核和监管部门已有的媒资库,审核合格内容入库存储,并作为向运营商发布的统一出口 |
|
||||||
|
| 转码版哈希 | — | 内容经授权转码中心转码后重新计算的版本哈希 |
|
||||||
|
| 重审 | Reaudit | 内容版本变更后触发的重新审核流程 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 角色定义
|
||||||
|
|
||||||
|
系统围绕三个核心角色设计:**内容提供商、审核和监管部门、运营商**。
|
||||||
|
|
||||||
|
| 角色 | 描述 | 核心职责 |
|
||||||
|
|------|------|----------|
|
||||||
|
| 内容提供商(CP) | 内容供应商 | 生产内容、计算哈希、送审申报、注册本方映射、自查验真 |
|
||||||
|
| 审核和监管部门 | 广电总局/省级广电局 + IPTV 集成播控平台(承担内容审核与监管把关职能),已有 CSPS 审核系统与媒体资源库 | 内容合规审核(CSPS)、送审验真、转码授权、签发 MA码、注册哈希、合格内容入媒体资源库、从媒体资源库向运营商发布、全生命周期监管、应急下架指令下发 |
|
||||||
|
| 运营商 | IPTV 分发网络方 | CDN注入校验、EPG发布、终端播放、数据上报、注册本方映射、执行下架指令 |
|
||||||
|
|
||||||
|
> 说明:审核和监管部门内部含两类职能主体——**监管主体**(广电总局/省局,行使 MA码签发与应急下架等行政权力)与**审核主体**(IPTV 集成播控平台,行使内容合规审核、送审验真、转码授权等把关职责)。两者共同构成"审核+监管"的把关闭环。系统运维(可信数据空间、智能合约、API网关、监控告警的维护)作为支撑职能,不单列为业务角色。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 需求列表
|
||||||
|
|
||||||
|
### 需求 1:母版哈希生成(CP端)
|
||||||
|
|
||||||
|
**User Story:** 作为 CP,我希望在内容制作完成后能够在本地对母版文件计算多维哈希值,以便在不上传原始文件的前提下为内容生成可验证的技术指纹。
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. WHEN CP 在母版文件(ProRes/DPX 等格式)上发起哈希计算,THE 哈希计算SDK SHALL 计算该文件的全文件 SHA-256 哈希值。
|
||||||
|
2. WHEN 内容为多集/长内容,THE 哈希计算SDK SHALL 按场景或集数分段计算分段哈希,并生成 Merkle Tree 及其根哈希。
|
||||||
|
3. WHEN CP 发起哈希计算,THE 哈希计算SDK SHALL 计算该内容的感知哈希(aHash/dHash/pHash 之一或组合)。
|
||||||
|
4. THE 哈希计算SDK SHALL 在本地存证哈希值,且 SHALL NOT 上传原始内容文件。
|
||||||
|
5. WHEN 哈希计算完成,THE 哈希计算SDK SHALL 返回包含文件哈希、Merkle根、分段哈希列表、感知哈希的哈希值包。
|
||||||
|
6. IF 母版文件读取失败或格式不受支持,THEN THE 哈希计算SDK SHALL 返回错误信息并标识失败原因。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 需求 2:送审申报与哈希上链(CP端)
|
||||||
|
|
||||||
|
**User Story:** 作为 CP,我希望登录备案系统提交节目信息与哈希值包,以便启动监管审核流程并将哈希存证。
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. WHEN CP 提交送审申报,THE 系统 SHALL 接收节目信息(标题、集数、时长、分辨率)、片花、海报、剧本及哈希值包。
|
||||||
|
2. WHEN 哈希值包提交成功,THE 系统 SHALL 将哈希存证至可信数据空间并返回唯一送审流水号。
|
||||||
|
3. WHEN CP 提交的内容哈希在可信数据空间中已存在,THE 系统 SHALL 拒绝重复申报,并将该申报关联至已存在哈希对应的原 MA码。
|
||||||
|
4. THE 系统 SHALL 仅接收哈希值包,且 SHALL NOT 要求 CP 上传原始内容文件。
|
||||||
|
5. IF 哈希值包格式不完整(缺少文件哈希或 Merkle根),THEN THE 系统 SHALL 拒绝申报并提示缺失字段。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 需求 3:MA码生成、签发与强绑定(监管端)
|
||||||
|
|
||||||
|
**User Story:** 作为监管方,我希望与 MA 发码机构合作获取码段与备案规则后,由系统自行生成结构化、全局唯一的 MA码,并在审核通过后与送审哈希包强绑定,以便建立内容的合法监管身份。
|
||||||
|
|
||||||
|
> 发码模式:**模式B(自行发码)** — TCS 与 MA 发码机构对接,获取分配的码段(号段)与备案规则,在本地按规则原子生成 MA码(不依赖外部逐条签发)。
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. THE 系统 SHALL 支持登记 MA 发码机构分配的码段(行业节点、机构节点、序列号段范围、序列宽度)与适用内容类目。
|
||||||
|
2. WHEN 监管方对送审内容审核通过,THE MA码生成引擎 SHALL 按内容类目从对应码段中原子分配序列,并按备案规则生成结构化六段式 MA码(`MA.156.{行业节点}.{机构节点}/{类目}/{年份}{序列}`)。
|
||||||
|
3. THE 系统 SHALL 保证生成的 MA码全局唯一;IF 码段耗尽,THEN THE 系统 SHALL 返回错误并告警。
|
||||||
|
4. WHEN 并发签发,THE 系统 SHALL 保证序列分配原子、不重号。
|
||||||
|
5. WHEN MA码生成,THE 系统 SHALL 将 MA码与送审哈希包以 1:1 关系写入可信数据空间,且该绑定 SHALL NOT 可被解绑。
|
||||||
|
6. THE 系统 SHALL 仅允许监管节点调用 MA码签发功能(issueMA);IF 非监管节点调用,THEN THE 系统 SHALL 拒绝并返回权限错误。
|
||||||
|
7. WHEN MA码签发完成,THE 系统 SHALL 向 CP 发放"MA码+哈希证书"。
|
||||||
|
8. WHILE 内容未取得 MA码及哈希证书,THE 系统 SHALL NOT 允许该内容进入后续审核/分发流程。
|
||||||
|
9. WHEN MA码绑定写入,THE 系统 SHALL 记录签发方、签发日期、MA类型(类目)、内容标题、集数等内容主表信息。
|
||||||
|
10. THE 系统 SHALL 提供 MA码格式校验与解析能力(解析出行业节点/机构节点/类目/年份/序列)。
|
||||||
|
|
||||||
|
> **粒度设计(一剧一码 + 集级哈希)**:MA码作为监管身份按"剧/备案"颁发(对齐网络剧片发行许可证制度),一部多集剧使用**单一 MA码**;各集(episode)拥有独立哈希绑定,挂在同一 MA码下;各切片(segment)为 Merkle 叶子哈希。集级可通过**集级子标识** `{MA码}#E{NN}`(如 `MA.156.8531.6101/WD/20260000001#E07`)独立寻址、验真、追更与按集处置。
|
||||||
|
|
||||||
|
11. WHEN 内容为分集剧,THE 系统 SHALL 支持按集提交各集哈希(file_sha256/merkle_root/感知哈希),并将每集哈希作为独立绑定挂在同一 MA码下。
|
||||||
|
12. THE 系统 SHALL 支持按 MA码+集号(或集级子标识 `{MA码}#E{NN}`)独立验真单集哈希。
|
||||||
|
13. THE 系统 SHALL 支持查询某 MA码下的全部集级哈希绑定。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 需求 4:送审文件验真(审核和监管部门)
|
||||||
|
|
||||||
|
**User Story:** 作为审核和监管部门,我希望对 CP 送审的文件计算哈希并与可信数据空间比对,以便确认其为正版过审内容、拦截版本替换。
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. WHEN CP 向审核和监管部门送审(提交 MA码、送审文件、授权链文件),THE 验真模块 SHALL 计算送审文件哈希。
|
||||||
|
2. WHEN 送审文件哈希与可信数据空间中 MA码绑定的哈希匹配,THE 系统 SHALL 确认为正版过审内容并允许进入 CSPS 内容审核流程。
|
||||||
|
3. IF 送审文件哈希与绑定哈希不匹配,THEN THE 系统 SHALL 直接退回该送审,并标记为"疑似版本替换"。
|
||||||
|
4. WHEN 验真执行,THE 系统 SHALL 通过哈希验真接口查询可信数据空间,返回 valid、bound_hash、submitted_hash、match、version 等字段。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 需求 5:内容审核与转码哈希绑定(CSPS 审核)
|
||||||
|
|
||||||
|
**User Story:** 作为审核和监管部门,我希望通过已有的 CSPS 审核系统对内容进行合规审核,并在转码后为各版本重新生成并绑定哈希,以便多版本分发时保持可信锁定。
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. WHEN 送审文件验真通过,THE CSPS 审核系统 SHALL 对内容执行合规审核(政治、色情、暴力等维度)。
|
||||||
|
2. THE 系统 SHALL 在 CSPS 与可信数据空间之间建立对接,使 CSPS 的审核结论可关联至对应 MA码与哈希记录,且 SHALL NOT 要求改造 CSPS 的现有审核流程。
|
||||||
|
3. WHEN 内容审核通过且需要转码,THE 系统 SHALL 由授权转码中心执行转码,并在转码后重新计算各版本(如 H.264/H.265/4K/HD/SD)文件哈希。
|
||||||
|
4. WHEN 转码版哈希生成,THE 系统 SHALL 将转码版哈希与 MA码绑定并写入可信数据空间,且 SHALL 与原母版哈希建立父子关系。
|
||||||
|
5. THE 系统 SHALL 允许同一 MA码绑定多个转码版哈希记录,各转码版 SHALL 共享同一 MA码但拥有独立哈希记录。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 需求 6:媒体资源库入库、发布与编码映射
|
||||||
|
|
||||||
|
**User Story:** 作为审核和监管部门,我希望审核合格的内容进入已有媒体资源库并作为向运营商发布的统一出口,同时建立媒资编码与 MA码、哈希的映射关系,以便对接监管而不改造现有系统。
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. WHEN 内容通过 CSPS 审核(含必要转码),THE 系统 SHALL 将该内容纳入媒体资源库,并保留媒体资源库自有的媒资编码/审核流水号。
|
||||||
|
2. WHEN 内容入媒体资源库,THE 系统 SHALL 在可信数据空间建立"媒资编码 ↔ MA码 ↔ 文件哈希 ↔ 转码版哈希"的映射关系。
|
||||||
|
3. WHILE 内容未通过审核或未取得 MA码绑定,THE 系统 SHALL NOT 允许其进入媒体资源库的可发布状态。
|
||||||
|
4. WHEN 从媒体资源库向运营商发布内容,THE 系统 SHALL 要求发布数据携带 MA码及哈希证书;IF 未携带,THEN THE 系统 SHALL 拒绝发布。
|
||||||
|
5. THE 系统 SHALL 仅允许审核和监管部门管理其本方(审核/媒资)的映射记录。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 需求 7:CDN注入校验(运营商端)
|
||||||
|
|
||||||
|
**User Story:** 作为运营商,我希望在内容注入 CDN 前校验其哈希,以便拒绝被篡改或非授权的内容。
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. WHEN 运营商接收审核和监管部门从媒体资源库发布的内容并准备注入 CDN,THE 注入校验模块 SHALL 计算注入文件哈希。
|
||||||
|
2. WHEN 注入文件哈希与可信数据空间中 MA码绑定的哈希匹配,THE 系统 SHALL 允许注入 CDN 并生成分发编码。
|
||||||
|
3. IF 注入文件哈希与绑定哈希不匹配,THEN THE 系统 SHALL 拒绝注入,触发告警并退回审核和监管部门,同时暂停该内容分发。
|
||||||
|
4. WHEN 注入成功,THE 系统 SHALL 在可信数据空间注册运营商(operator)映射记录(分发编码、CDN端点)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 需求 8:终端播放哈希抽检(运营商端)
|
||||||
|
|
||||||
|
**User Story:** 作为运营商,我希望播放器在终端可选地对下载片段进行哈希抽检,以便防止 CDN 劫持或传输篡改。
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. WHERE 终端哈希抽检功能开启,WHEN 播放器 SDK(或机顶盒固件)下载内容片段,THE 系统 SHALL 计算该片段哈希并与可信数据空间链上哈希比对。
|
||||||
|
2. IF 终端抽检哈希与链上哈希不匹配,THEN THE 系统 SHALL 断流并切换至备用源,同时上报异常日志。
|
||||||
|
3. THE 终端哈希抽检功能 SHALL 支持按网络负载策略性开启或关闭。
|
||||||
|
4. WHERE 内容为多集,THE 系统 SHALL 支持按集进行增量哈希校验以降低终端计算负载。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 需求 9:统一维度数据上报与聚合
|
||||||
|
|
||||||
|
**User Story:** 作为监管方,我希望三方播放与业务数据以 MA码为统一维度聚合,以便获得口径一致的可信数据。
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. WHEN 运营商上报播出数据,THE 系统 SHALL 以 MA码为统一维度组织数据。
|
||||||
|
2. THE 可信数据空间 SHALL 按 MA码聚合 CP 播放量、审核和监管部门审核量、运营商分发量,并保证各方数据口径一致。
|
||||||
|
3. WHEN 数据聚合完成,THE 系统 SHALL 提供按 MA码查询的统一数据视图。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 需求 10:全生命周期监管查询(监管端)
|
||||||
|
|
||||||
|
**User Story:** 作为监管方,我希望通过监管大屏按 MA码查询内容全链路状态,以便实现精准溯源。
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. WHEN 监管方按 MA码查询,THE 监管大屏 SHALL 返回内容当前所在播控平台、当前所在运营商 CDN、当前哈希版本是否最新。
|
||||||
|
2. WHEN 监管方查询内容历史,THE 系统 SHALL 返回该 MA码的历史版本变更记录。
|
||||||
|
3. THE 监管大屏 SHALL 支持监管方按 MA码穿透查询三方系统的对应编码。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 需求 11:违规应急下架(监管端)
|
||||||
|
|
||||||
|
**User Story:** 作为监管方,我希望下发单一 MA码下架指令即可触发全网下架,以便实现秒级应急响应而无需逐层人工翻译。
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. WHEN 监管方下发"下架 MA码 第XXX号"指令,THE 系统 SHALL 解析该 MA码并查询其绑定的所有三方编码及 CDN端点。
|
||||||
|
2. WHEN 下架指令解析完成,THE 系统 SHALL 自动将指令翻译为审核和监管部门侧下架(媒资编码/审核流水号、从媒体资源库撤除发布)与运营商侧下架(分发编码、CDN资源)的执行动作。
|
||||||
|
3. THE 系统 SHALL 在接收下架指令后秒级同步至全网相关系统,且 SHALL NOT 要求人工逐层翻译。
|
||||||
|
4. THE 系统 SHALL 仅允许审核和监管部门的监管主体下发应急下架指令;审核主体(媒资发布)与运营商 SHALL 仅执行指令而无下架发起权限。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 需求 12:版本变更与重审触发
|
||||||
|
|
||||||
|
**User Story:** 作为系统,我希望在内容发生帧级变动时自动断开绑定并触发重审,以便保证审播一致。
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. WHEN 内容发生任意帧级变动导致哈希变化,THE 系统 SHALL 判定原 MA码与哈希的绑定断裂。
|
||||||
|
2. WHEN 绑定断裂,THE 系统 SHALL 在版本变更表中记录变更原因、原哈希、新哈希,并将 reaudit_required 置为 true。
|
||||||
|
3. WHEN 单集内容被替换,THE 系统 SHALL 通过 Merkle Tree 重新计算该集哈希并定位被篡改的具体集数,且 SHALL NOT 要求全量重审。
|
||||||
|
4. WHILE 重审未通过,THE 系统 SHALL NOT 允许变更后的内容进入分发流程。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 需求 13:跨省复用快速准入
|
||||||
|
|
||||||
|
**User Story:** 作为 CP,我希望在一省过审后凭 MA码+哈希证书在其他省份快速准入,以便降低跨省复用的边际成本。
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. WHEN CP 持 A省签发的 MA码+哈希证书向 B省播控平台送审,THE 系统 SHALL 仅要求提交 MA码与哈希证书,且 SHALL NOT 要求重新提交内容文件。
|
||||||
|
2. WHEN B省播控平台发起准入查询,THE 系统 SHALL 验证 MA码真实有效、哈希与原过审版一致、且内容不在黑名单中。
|
||||||
|
3. WHEN 三重校验通过,THE 系统 SHALL 允许 B省播控平台快速准入,并将内容审核简化为合规性抽检。
|
||||||
|
4. WHEN B省准入完成,THE 系统 SHALL 生成 B省审核流水号并注册对应映射关系。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 需求 14:角色权限控制
|
||||||
|
|
||||||
|
**User Story:** 作为系统,我希望按三类角色(内容提供商、审核和监管部门、运营商)的职能矩阵严格控制操作权限,以便保证监管主键的权威性与不可越权。
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. THE 系统 SHALL 允许审核和监管部门执行内容合规审核、送审验真、转码授权、签发 MA码、注册哈希、映射管理、全生命周期查询、应急下架全部操作。
|
||||||
|
2. WHILE 审核和监管部门内部行使权限,THE 系统 SHALL 仅允许其监管主体(广电总局/省局)调用 MA码签发(issueMA)与应急下架发起功能;IF 由审核主体(播控平台)或其他主体调用上述功能,THEN THE 系统 SHALL 拒绝并返回权限错误。
|
||||||
|
3. THE 系统 SHALL 允许内容提供商在送审时注册哈希、执行自查验真、管理本方映射;且 SHALL NOT 允许其签发 MA码或发起下架。
|
||||||
|
4. THE 系统 SHALL 允许运营商执行验真查询、本方映射管理、执行下架指令;且 SHALL NOT 允许其签发 MA码、注册哈希、发起下架。
|
||||||
|
5. WHEN 任意角色尝试越权操作,THE 系统 SHALL 拒绝该操作并返回权限错误。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 需求 15:异常处理
|
||||||
|
|
||||||
|
**User Story:** 作为系统,我希望对各类哈希校验异常采取明确的处理规则,以便保证流程的可控与可追溯。
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. IF 送审阶段哈希不匹配,THEN THE 系统 SHALL 退回 CP,要求说明版本差异,必要时要求重新送审。
|
||||||
|
2. IF CDN注入阶段哈希不匹配,THEN THE 系统 SHALL 拒绝注入、告警审核和监管部门并暂停该内容分发。
|
||||||
|
3. IF 终端抽检阶段哈希不匹配,THEN THE 系统 SHALL 断流、切换备用源并上报异常日志。
|
||||||
|
4. WHEN 内容发生剪辑/修改,THE 系统 SHALL 要求重新计算哈希、提交变更申请并触发重新审核。
|
||||||
|
5. WHEN CP 以同一哈希换壳重发,THE 系统 SHALL 识别哈希已存在并拒绝重复申报,同时关联原 MA码。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 需求 16:可信数据空间存证与智能合约
|
||||||
|
|
||||||
|
**User Story:** 作为系统,我希望通过联盟链与智能合约管理 MA码、哈希与映射的存证,以便保证数据不可篡改与可信。
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. THE 可信数据空间 SHALL 维护内容主表、哈希绑定表、三方编码映射表、版本变更表四类核心数据结构。
|
||||||
|
2. THE 智能合约 SHALL 提供 issueMA(签发)、registerMapping(注册映射)、verifyHash(哈希校验)核心方法。
|
||||||
|
3. WHEN registerMapping 被调用,IF 对应 MA码尚未签发,THEN THE 系统 SHALL 拒绝注册映射。
|
||||||
|
4. THE 系统 SHALL 通过 Merkle Tree 存储多集内容的分段哈希,并支持按集定位篡改。
|
||||||
|
5. THE 可信数据空间 SHALL 保证已写入的 MA码与哈希绑定记录不可篡改。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 需求 17:接口规范
|
||||||
|
|
||||||
|
**User Story:** 作为三方系统集成方,我希望通过标准化 API 与可信数据空间交互,以便低成本对接。
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. THE 系统 SHALL 提供哈希上链接口(POST /api/v1/content/register),供 CP 提交标题、集数、各集文件哈希、Merkle根、感知哈希、时长、分辨率、CP媒资ID,并返回送审流水号与状态。
|
||||||
|
2. THE 系统 SHALL 提供哈希验真接口(GET /api/v1/content/verify),供播控/运营商按 MA码与文件哈希查询并返回 valid、bound_hash、submitted_hash、match、version、转码版列表。
|
||||||
|
3. THE 系统 SHALL 提供映射查询接口(GET /api/v1/content/mappings),供应急下架按 MA码查询三方编码映射与 CDN端点。
|
||||||
|
4. THE 系统 SHALL 对接口调用进行身份鉴权(如 Bearer Token)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 非功能性需求
|
||||||
|
|
||||||
|
### 需求 18:性能与时效
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. THE 系统 SHALL 将违规内容下架响应时间从现状的 2-24 小时缩短至分钟级。
|
||||||
|
2. THE 系统 SHALL 将跨省复用审核周期从现状的 15-30 天缩短至 3-5 天。
|
||||||
|
3. THE 系统 SHALL 将三方数据对账差异从现状的 15-30% 降低至 5% 以内。
|
||||||
|
4. THE 系统 SHALL 实现内容版本替换的 100% 自动识别。
|
||||||
|
|
||||||
|
### 需求 19:兼容性与最小侵入
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. THE 系统 SHALL NOT 要求三方放弃其自有编码体系,且 SHALL 与审核和监管部门已有的 CSPS 审核系统、媒体资源库通过映射层对接而不改造其内部流程。
|
||||||
|
2. THE 系统 SHALL 仅在送审、CSPS审核、媒体资源库入库/发布、CDN注入、终端播放等关键节点嵌入校验,并通过映射层对接现有系统。
|
||||||
|
3. THE 系统 SHALL 完全符合广电总局网络剧片发行许可及备案制度。
|
||||||
|
4. THE 系统 SHALL 支持网络剧、微短剧、网络电影、网络动画等多形态内容,并 SHALL 可扩展至 OTT、手机 APP 等大小屏形态。
|
||||||
|
|
||||||
|
### 需求 20:安全与可信
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. THE 系统 SHALL 保证 MA码与哈希的绑定记录一经写入不可篡改、不可解绑。
|
||||||
|
2. THE 系统 SHALL 保证哈希计算在 CP 本地完成,**原始内容文件 SHALL NOT 上传至可信数据空间(区块链)**;原片仍通过审核方(CSPS/媒资库)既有送审渠道提交以供内容审核,TCS 不改造该渠道。
|
||||||
|
3. THE 系统 SHALL 对所有关键操作(签发、注册、验真、下架)进行链上存证以支持审计。
|
||||||
|
|
||||||
|
> **澄清(原片与哈希的边界)**:CSPS 的内容审核基于**真实原片**(经既有送审渠道提交),TCS 不替代内容审核;TCS 仅将原片哈希上链,作用是"锁定审核对象"——保证审核版=入库版=发布版=播出版(审播一致),并在任一环节被偷换时通过哈希比对识别。"不上传原片"特指**不上链**,而非不提交给审核方。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 价值场景需求(权利 · 效率 · 利益)
|
||||||
|
|
||||||
|
### 需求 21:可信播放数据聚合与分账结算依据(利益)
|
||||||
|
|
||||||
|
**User Story:** 作为内容提供商与运营商,我希望以 MA码为唯一维度获得不可篡改的可信播放数据,以便作为分账结算的统一依据,消除对账争议。
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. WHEN 各运营商上报播放数据,THE 系统 SHALL 以 MA码为唯一维度在可信数据空间链上聚合,形成不可篡改的可信播放量记录。
|
||||||
|
2. THE 系统 SHALL 向 CP 与运营商提供同一份以 MA码聚合的播放数据视图,且各方所见数据 SHALL 口径一致。
|
||||||
|
3. WHEN 进行分账结算,THE 系统 SHALL 以链上可信播放数据作为统一结算依据。
|
||||||
|
4. WHEN CP 与运营商对账,THE 系统 SHALL 将数据差异控制在 5% 以内。
|
||||||
|
5. THE 系统 SHALL 提供可信播放数据的查询与导出能力,供结算与审计使用。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 需求 22:全链路责任界定与追责取证(权利)
|
||||||
|
|
||||||
|
**User Story:** 作为审核和监管部门,我希望在出现违规内容时按 MA码调取全链路哈希存证,以便精准界定问题出在哪个环节、是哪一方改动。
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. WHEN 监管按 MA码发起追责查询,THE 系统 SHALL 返回该内容全链路各节点的哈希存证记录(CP送审、CSPS审核结论、转码版、媒资库发布、运营商注入、终端抽检)。
|
||||||
|
2. WHEN 各节点哈希比对,THE 系统 SHALL 标识首次发生哈希变化的节点,并定位对应责任方与责任环节。
|
||||||
|
3. THE 系统 SHALL 保证各节点存证记录带时间戳、操作方标识且不可篡改。
|
||||||
|
4. THE 系统 SHALL 提供责任界定取证报告的导出能力,供问责与审计使用。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 需求 23:版权确权与维权举证(权利)
|
||||||
|
|
||||||
|
**User Story:** 作为内容提供商,我希望凭 MA码、哈希与上链时间戳形成不可抵赖的确权证据,以便在被盗版时进行维权举证。
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. WHEN 内容完成哈希上链,THE 系统 SHALL 记录 MA码、内容哈希、上链时间戳,形成"谁先锁定谁有权"的确权证据。
|
||||||
|
2. WHEN CP 申请确权证据,THE 系统 SHALL 导出可用于侵权投诉与司法诉讼的不可抵赖证据链(含链上存证哈希与时间戳)。
|
||||||
|
3. WHEN 系统检测到某内容的感知哈希与已确权内容高度相似(超过设定阈值),THE 系统 SHALL 标记疑似侵权并关联原 MA码。
|
||||||
|
4. THE 系统 SHALL 保证确权证据记录不可篡改、不可抵赖。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 需求 24:追更与增量哈希更新(效率)
|
||||||
|
|
||||||
|
**User Story:** 作为内容提供商,我希望在剧集追更或局部修正时仅对变化部分重新计算哈希,以便快速完成赋码与发布而无需重走全流程。
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. WHEN 内容发生追更或局部修正,THE 系统 SHALL 仅对变化的集或片段重新计算哈希。
|
||||||
|
2. WHEN 增量哈希更新,THE 系统 SHALL 基于 Merkle Tree 仅更新变化叶子节点并重算根哈希,未变化部分 SHALL 复用原哈希与原审核结论。
|
||||||
|
3. WHEN 增量更新提交,THE 系统 SHALL 在版本变更表中记录变化范围与新旧哈希。
|
||||||
|
4. IF 仅新增内容(如追更新集)且不改动已审通过部分,THEN THE 系统 SHALL 支持对新增部分快速赋码而不触发存量部分重审。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 需求 25:授权链上链与发布前授权核验(权利+利益)
|
||||||
|
|
||||||
|
**User Story:** 作为审核和监管部门与运营商,我希望在发布/注入前实时核验内容的授权范围,以便拦截越权、过期或非授权平台的分发。
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. WHEN CP 提交授权信息,THE 系统 SHALL 将信息网络传播权的授权范围(地域、期限、平台)上链存证。
|
||||||
|
2. WHEN 从媒体资源库发布或运营商注入 CDN 前,THE 系统 SHALL 核验该分发是否在授权范围内。
|
||||||
|
3. IF 分发超出授权地域、超过授权期限或面向非授权平台,THEN THE 系统 SHALL 拦截该分发并告警。
|
||||||
|
4. WHEN 授权范围发生变更,THE 系统 SHALL 记录授权变更历史并可追溯。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 关键约束与假设
|
||||||
|
|
||||||
|
| 类别 | 内容 |
|
||||||
|
|------|------|
|
||||||
|
| 约束 | 不替代三方现有系统,仅建立"可信身份映射层";审核和监管部门已有 CSPS 审核系统与媒体资源库,通过映射层对接 |
|
||||||
|
| 约束 | MA码签发权与应急下架发起权仅归审核和监管部门的监管主体 |
|
||||||
|
| 约束 | MA码与哈希 1:1 强绑定,不可解绑 |
|
||||||
|
| 约束 | 审核合格内容进入媒体资源库,并由媒体资源库作为向运营商发布的统一出口 |
|
||||||
|
| 假设 | 三方系统具备在关键节点集成哈希计算SDK与API调用的能力 |
|
||||||
|
| 假设 | CSPS 审核系统与媒体资源库可开放对接接口,关联 MA码与哈希记录 |
|
||||||
|
| 假设 | 广电总局备案系统可对接 MA码签发与哈希绑定 |
|
||||||
|
| 依赖 | 联盟链/分布式账本基础设施可用 |
|
||||||
|
| 依赖 | 授权转码中心具备转码后哈希重算与上链能力 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> 本需求文档作为 TCS-IPTV 系统设计与实现的依据,后续设计文档与任务分解将基于本文档展开。
|
||||||
@@ -0,0 +1,305 @@
|
|||||||
|
# TCS-IPTV 内容可信锁定系统 — 产品需求文档(PRD)
|
||||||
|
|
||||||
|
> 版本:V1.0
|
||||||
|
> 编制日期:2026年6月
|
||||||
|
> 上游文档:0-req-IPTV.md(需求规格说明书)
|
||||||
|
> 文档编号:1-prd-IPTV
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、产品概述
|
||||||
|
|
||||||
|
### 1.1 产品定位
|
||||||
|
|
||||||
|
TCS-IPTV 是一套架设在 **内容提供商(CP)、审核和监管部门、运营商** 三方现有系统之上的**内容可信身份映射层**。它通过"MA码(监管身份)+ 哈希码(技术指纹)"双锚定机制,让每一条 IPTV 内容拥有全网唯一、不可篡改、可追溯的可信身份,实现"**审过即锁定,锁定即通行,通行可追溯**"。
|
||||||
|
|
||||||
|
一句话定位:**不替代任何现有系统,只在三方之上加一层"可信锁",把"是谁、是不是、在哪里"三个问题一次性解决。**
|
||||||
|
|
||||||
|
### 1.2 产品要解决的核心问题
|
||||||
|
|
||||||
|
| 现状痛点 | 根因 | TCS-IPTV 的解法 |
|
||||||
|
|---------|------|----------------|
|
||||||
|
| 同一内容反复审核,边际成本不降 | 三方编码体系割裂,无法互认 | MA码+哈希一次锁定,跨省凭证复用 |
|
||||||
|
| 版本替换、换壳重发难识别 | 缺乏内容级技术指纹 | 文件哈希比特级锁定 + 感知哈希跨格式识别 |
|
||||||
|
| 违规下架指令逐层翻译,响应滞后 | 编码不互通,需人工逐层映射 | 一个MA码自动翻译为三方下架指令,秒级同步 |
|
||||||
|
| 跨省跨运营商复用要重走全流程 | 审核结果无法跨域信任 | 凭MA码+哈希证书快速准入,审核简化为抽检 |
|
||||||
|
| 三方数据对账差异大 | 统计口径不统一 | 以MA码为统一维度聚合,口径一致 |
|
||||||
|
|
||||||
|
### 1.3 目标用户
|
||||||
|
|
||||||
|
| 用户 | 关注点 | 产品价值主张 |
|
||||||
|
|------|--------|------------|
|
||||||
|
| 内容提供商(CP) | 审核成本、跨省复用效率、版权保护 | 一次录入全网复用,重复审核成本大幅下降 |
|
||||||
|
| 审核和监管部门 | 管得住、管得省、管得准 | 审播一致、精准溯源、秒级下架、数据可信 |
|
||||||
|
| 运营商 | 分发合规、防篡改、对账准确 | 注入即校验,杜绝劫持篡改,数据口径统一 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、产品目标与成功指标
|
||||||
|
|
||||||
|
### 2.1 产品目标
|
||||||
|
|
||||||
|
- **G1 审播一致**:送审版=播出版,任何篡改秒级识别
|
||||||
|
- **G2 一码通行**:一省过审,全网凭 MA码+哈希准入
|
||||||
|
- **G3 精准溯源**:凭 MA码秒级定位三方系统与全链路状态
|
||||||
|
- **G4 数据可信**:播放量、结算、上报以统一标识聚合
|
||||||
|
- **G5 最小侵入**:不改造三方现有系统,仅在关键节点嵌入校验
|
||||||
|
|
||||||
|
### 2.2 成功指标(North Star & 关键指标)
|
||||||
|
|
||||||
|
| 指标 | 现状 | 目标 | 对应需求 |
|
||||||
|
|------|------|------|---------|
|
||||||
|
| 跨省复用审核周期 | 15-30天 | 3-5天 | 需求13、18 |
|
||||||
|
| 违规内容下架响应 | 2-24小时 | 分钟级 | 需求11、18 |
|
||||||
|
| 内容版本替换识别率 | 几乎无法识别 | 100%自动识别 | 需求4、12、18 |
|
||||||
|
| 三方数据对账差异 | 15-30% | <5% | 需求9、18 |
|
||||||
|
| CP重复录入成本 | 每省每运营商重复 | 一次录入全网复用 | 需求13 |
|
||||||
|
| 分账对账争议金额 | 高(数据各执一词) | 以可信数据为准,争议大幅下降 | 需求21 |
|
||||||
|
| 违规追责定位耗时 | 数天(人工扯皮) | 分钟级(链上取证) | 需求22 |
|
||||||
|
| 追更内容处理耗时 | 重走全流程 | 秒级(增量哈希) | 需求24 |
|
||||||
|
| 接入CP数(三期) | — | ≥10家主流CP | — |
|
||||||
|
| 覆盖省份(三期) | — | 全国IPTV贯通 | — |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、用户画像与核心场景
|
||||||
|
|
||||||
|
### 3.1 用户画像
|
||||||
|
|
||||||
|
**画像A — CP内容运营专员(小赵)**
|
||||||
|
- 职责:负责剧集送审、跨省发行
|
||||||
|
- 痛点:每进一个省、对接一个运营商就要重新录入、重新走审核
|
||||||
|
- 期望:一次过审,凭证全网通行,不再重复劳动
|
||||||
|
|
||||||
|
**画像B — 审核和监管部门审核员/监管员(王主任)**
|
||||||
|
- 职责:内容合规审核(CSPS)、违规处置、全网监管
|
||||||
|
- 痛点:出问题难定位,下架指令逐层打电话翻译,慢且易漏
|
||||||
|
- 期望:一个MA码看清全链路,一键下架全网生效
|
||||||
|
|
||||||
|
**画像C — 运营商分发工程师(老李)**
|
||||||
|
- 职责:CDN注入、EPG发布、数据上报
|
||||||
|
- 痛点:收到的内容真假难辨,被篡改/劫持难发现,对账总对不平
|
||||||
|
- 期望:注入前自动校验,数据口径和上游统一
|
||||||
|
|
||||||
|
### 3.2 核心使用场景
|
||||||
|
|
||||||
|
**场景1:内容首次送审与赋码(端到端正向流程)**
|
||||||
|
小赵在 CP 媒资系统完成制作 → 用哈希SDK对母版计算哈希包 → 登录备案系统提交节目信息+哈希包 → 审核和监管部门审核通过、签发MA码并强绑定哈希 → 小赵拿到"MA码+哈希证书"。
|
||||||
|
> 痛点解法:让内容从源头就获得全网唯一、不可篡改的可信身份,为后续一切流转奠定基础。
|
||||||
|
|
||||||
|
**场景2:内容入库发布(审核→媒资库→运营商)**
|
||||||
|
送审文件验真通过 → CSPS审核合规 → 转码并绑定各版本哈希 → 合格内容进入媒体资源库 → 从媒体资源库携带MA码+哈希证书向运营商发布 → 运营商注入CDN前校验哈希 → 校验通过注入分发。
|
||||||
|
> 痛点解法:保证"送审版=播出版",转码多版本各自锁定,杜绝入库到分发环节的偷换。
|
||||||
|
|
||||||
|
**场景3:跨省快速复用**
|
||||||
|
小赵已在A省过审 → 向B省仅提交MA码+哈希证书(不传文件) → 系统三重校验(MA码有效+哈希一致+非黑名单) → B省快速准入,审核简化为合规抽检。
|
||||||
|
> 痛点解法:跨省复用从"重走全流程15-30天"压缩到"验真+抽检3-5天",CP边际成本大幅下降。
|
||||||
|
|
||||||
|
**场景4:违规应急下架**
|
||||||
|
王主任发现违规 → 下发"下架MA码第XXX号"单一指令 → 系统解析该MA码绑定的全部三方编码与CDN端点 → 自动翻译为媒资库撤除发布+运营商下架CDN资源 → 秒级全网同步。
|
||||||
|
> 痛点解法:下架响应从"2-24小时逐层人工翻译"升级为"一码下发、秒级全网生效"。
|
||||||
|
|
||||||
|
**场景5:版本篡改识别**
|
||||||
|
内容被剪辑/替换 → 哈希变化 → MA码与哈希绑定断裂 → 系统标记reaudit_required → 通过Merkle Tree定位被篡改的具体集数 → 阻断分发并触发重审。
|
||||||
|
> 痛点解法:版本替换/换壳重发从"几乎无法识别"升级为"100%自动识别并定位到具体集"。
|
||||||
|
|
||||||
|
**场景6:可信播放数据与自动分账结算(利益核心)**
|
||||||
|
内容在多个运营商分发播出 → 各运营商以MA码为唯一维度上报播放数据 → 可信数据空间链上聚合,形成不可篡改的可信播放量 → 作为CP与运营商分账结算的统一依据 → 对账差异从15-30%降至5%以内,回款争议大幅减少。
|
||||||
|
> 痛点解法:解决CP与运营商"播放量各执一词、分账扯皮、回款慢"的真金白银痛点。
|
||||||
|
|
||||||
|
**场景7:违规责任精准界定与追责(权责对等)**
|
||||||
|
出现违规内容需追责 → 监管按MA码调取全链路哈希存证 → 逐环节比对(CP送审哈希 / CSPS审核结论 / 转码版哈希 / 媒资库发布哈希 / 运营商注入哈希 / 终端抽检哈希)→ 精准定位"问题出在哪个环节、是哪一方改动" → 责任落到具体方与具体节点。
|
||||||
|
> 痛点解法:终结CP、审核监管、运营商三方"互相甩锅",实现权责对等、有据可查。
|
||||||
|
|
||||||
|
**场景8:版权确权与维权举证(权利保护)**
|
||||||
|
CP内容被盗版/换皮 → 凭MA码+哈希+上链时间戳形成不可抵赖的"谁先锁定谁有权"证据链 → 可直接用于侵权投诉与司法诉讼举证 → 系统识别盗版内容感知哈希与正版高度相似,辅助锁定侵权。
|
||||||
|
> 痛点解法:解决CP"被盗用拿不出有法律效力证据"的确权维权痛点。
|
||||||
|
|
||||||
|
**场景9:追更与增量更新(效率提升)**
|
||||||
|
剧集追更/片尾修正/临时插播 → 仅对变化的集或片段重新计算哈希 → 基于Merkle Tree只更新变化叶子节点与根哈希 → 未变化部分复用原审核结论 → 追更内容秒级完成赋码与发布。
|
||||||
|
> 痛点解法:解决微短剧/剧集"每追一集、改个片尾都要重走全流程"的高频重复劳动。
|
||||||
|
|
||||||
|
**场景10:授权链可信核验(权利+利益)**
|
||||||
|
CP上链授权信息(信息网络传播权的地域/期限/平台范围)→ 审核监管与运营商在发布/注入前实时核验授权范围 → 超出授权地域、过期、或非授权平台的分发当场被拦截 → 授权变更可追溯。
|
||||||
|
> 痛点解法:解决线下授权PDF"易伪造、难核验、越权分发"的权利与利益痛点。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、产品范围与功能清单
|
||||||
|
|
||||||
|
### 4.1 功能模块总览
|
||||||
|
|
||||||
|
系统分为五大功能域,覆盖三方角色的关键节点:
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────┐
|
||||||
|
│ ① CP工作域 ② 审核监管域 ③ 运营商域 │
|
||||||
|
│ 哈希生成SDK 验真+CSPS对接 CDN注入校验 │
|
||||||
|
│ 送审申报 MA码签发引擎 终端抽检SDK │
|
||||||
|
│ 媒资库映射 数据上报 │
|
||||||
|
│ 监管大屏+应急下架 │
|
||||||
|
├─────────────────────────────────────────────────────────────┤
|
||||||
|
│ ④ 可信数据空间(核心):CTID模型 / 双哈希 / 映射表 / 智能合约 │
|
||||||
|
│ ⑤ 开放接口域:register / verify / mappings / 鉴权 │
|
||||||
|
└─────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.2 功能清单与优先级(MoSCoW)
|
||||||
|
|
||||||
|
| 编号 | 功能 | 所属域 | 优先级 | 对应需求 |
|
||||||
|
|------|------|--------|--------|---------|
|
||||||
|
| F01 | 母版多维哈希生成SDK(文件/分段Merkle/感知) | CP工作域 | Must | 需求1 |
|
||||||
|
| F02 | 送审申报与哈希上链 | CP工作域 | Must | 需求2 |
|
||||||
|
| F03 | MA码签发与1:1强绑定 | 审核监管域 | Must | 需求3 |
|
||||||
|
| F04 | 送审文件验真 | 审核监管域 | Must | 需求4 |
|
||||||
|
| F05 | CSPS审核对接与转码版哈希绑定 | 审核监管域 | Must | 需求5 |
|
||||||
|
| F06 | 媒体资源库入库/发布与编码映射 | 审核监管域 | Must | 需求6 |
|
||||||
|
| F07 | CDN注入校验 | 运营商域 | Must | 需求7 |
|
||||||
|
| F08 | 终端播放哈希抽检 | 运营商域 | Could | 需求8 |
|
||||||
|
| F09 | 统一维度数据上报与聚合 | 运营商域/可信空间 | Should | 需求9 |
|
||||||
|
| F10 | 全生命周期监管大屏查询 | 审核监管域 | Must | 需求10 |
|
||||||
|
| F11 | 违规应急下架(一键全网) | 审核监管域 | Must | 需求11 |
|
||||||
|
| F12 | 版本变更与重审触发 | 可信空间 | Must | 需求12 |
|
||||||
|
| F13 | 跨省复用快速准入 | 审核监管域 | Should | 需求13 |
|
||||||
|
| F14 | 角色权限控制(三角色矩阵) | 全局 | Must | 需求14 |
|
||||||
|
| F15 | 异常处理规则引擎 | 全局 | Must | 需求15 |
|
||||||
|
| F16 | 可信数据空间存证与智能合约 | 可信空间 | Must | 需求16 |
|
||||||
|
| F17 | 标准化开放API(register/verify/mappings) | 开放接口域 | Must | 需求17 |
|
||||||
|
| F18 | 可信播放数据聚合与分账结算依据 | 可信空间/运营商域 | Should | 需求21 |
|
||||||
|
| F19 | 全链路责任界定与追责取证 | 审核监管域/可信空间 | Should | 需求22 |
|
||||||
|
| F20 | 版权确权与维权举证(证据链导出) | CP工作域/可信空间 | Should | 需求23 |
|
||||||
|
| F21 | 追更与增量哈希更新 | CP工作域/可信空间 | Should | 需求24 |
|
||||||
|
| F22 | 授权链上链与发布前授权核验 | 全局 | Should | 需求25 |
|
||||||
|
|
||||||
|
### 4.3 不在本期范围(Out of Scope)
|
||||||
|
|
||||||
|
- OTT、手机APP等大小屏融合接入(规划至四期,需求19.4 为可扩展性预留)
|
||||||
|
- 内容推荐、计费结算的业务逻辑(系统仅提供以MA码为维度的数据聚合,不做结算)
|
||||||
|
- CSPS审核算法本身的改造(系统仅对接其审核结论,不介入审核规则)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、关键产品流程
|
||||||
|
|
||||||
|
### 5.1 端到端主流程(正向)
|
||||||
|
|
||||||
|
```
|
||||||
|
[CP] 制作母版
|
||||||
|
→ 哈希SDK计算哈希包(本地,不传原文件)
|
||||||
|
→ 送审申报(节目信息+哈希包)→ 获送审流水号
|
||||||
|
│
|
||||||
|
[审核监管] MA码签发引擎 审核通过 → 签发MA码 + 哈希1:1强绑定上链
|
||||||
|
→ CP获"MA码+哈希证书"
|
||||||
|
│
|
||||||
|
[审核监管] 送审文件验真(哈希比对)
|
||||||
|
→ 匹配 → 进入CSPS合规审核
|
||||||
|
→ 转码 → 各版本哈希绑定(父子关系)
|
||||||
|
→ 合格内容入媒体资源库(建立 媒资编码↔MA码↔哈希 映射)
|
||||||
|
│
|
||||||
|
[审核监管→运营商] 从媒体资源库发布(携带MA码+哈希证书)
|
||||||
|
│
|
||||||
|
[运营商] CDN注入校验(哈希比对)
|
||||||
|
→ 匹配 → 注入CDN + 生成分发编码 + 注册映射
|
||||||
|
→ EPG发布 → 用户点播
|
||||||
|
→ (可选)终端片段哈希抽检
|
||||||
|
│
|
||||||
|
[运营商] 以MA码为维度上报播放数据 → 可信空间统一聚合
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.2 应急下架流程(逆向)
|
||||||
|
|
||||||
|
```
|
||||||
|
[审核监管-监管主体] 下发"下架 MA码第XXX号"
|
||||||
|
→ 可信空间解析MA码 → 查出全部三方编码+CDN端点
|
||||||
|
→ 自动翻译为:
|
||||||
|
· 媒体资源库:撤除发布
|
||||||
|
· 运营商:下架分发编码YYY + CDN资源ZZZ
|
||||||
|
→ 秒级全网同步 → 各方执行下架
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.3 异常分支(摘要)
|
||||||
|
|
||||||
|
| 触发点 | 异常 | 系统动作 |
|
||||||
|
|--------|------|---------|
|
||||||
|
| 送审验真 | 哈希不匹配 | 退回CP,标记"疑似版本替换" |
|
||||||
|
| CDN注入 | 哈希不匹配 | 拒绝注入,告警审核监管部门,暂停分发 |
|
||||||
|
| 终端抽检 | 哈希不匹配 | 断流,切备用源,上报异常日志 |
|
||||||
|
| 内容变更 | 哈希变化 | 绑定断裂,reaudit_required=true,触发重审 |
|
||||||
|
| 换壳重发 | 哈希已存在 | 拒绝重复申报,关联原MA码 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 六、角色权限矩阵(产品视角)
|
||||||
|
|
||||||
|
| 操作 | 内容提供商 | 审核和监管部门 | 运营商 |
|
||||||
|
|------|:---------:|:-------------:|:------:|
|
||||||
|
| 签发MA码 | ✗ | ✅(仅监管主体) | ✗ |
|
||||||
|
| 注册哈希 | ✅(送审时) | ✅ | ✗ |
|
||||||
|
| 验真查询 | ✅(自查) | ✅ | ✅ |
|
||||||
|
| 映射管理 | ✅(本方) | ✅ | ✅(本方) |
|
||||||
|
| CSPS审核 | ✗ | ✅(审核主体) | ✗ |
|
||||||
|
| 媒资库入库/发布 | ✗ | ✅ | ✗ |
|
||||||
|
| 发起应急下架 | ✗ | ✅(仅监管主体) | ✗ |
|
||||||
|
| 执行下架指令 | ✗ | ✅ | ✅ |
|
||||||
|
|
||||||
|
> 注:审核和监管部门内部区分"监管主体"(行政权力:签发、下架发起)与"审核主体"(把关职责:CSPS审核、媒资发布)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 七、版本规划(Release Plan)
|
||||||
|
|
||||||
|
| 阶段 | 周期 | 范围 | 包含功能 | 目标 |
|
||||||
|
|------|------|------|---------|------|
|
||||||
|
| **MVP(一期)** | 3个月 | 单省单运营商微短剧全流程 | F01-F07、F10-F12、F14-F17 | 跑通"送审→赋码→审核→入库→发布→注入→下架"闭环 |
|
||||||
|
| **二期** | 6个月 | 多省多运营商,扩品类,强化权益 | +F08、F09、F13、F18-F22 | 3-5省、网络剧/网络电影、10+ CP;上线可信分账、追责取证、确权举证、追更、授权核验 |
|
||||||
|
| **三期** | 12个月 | 全国IPTV贯通 | 全功能稳定 + 备案系统对接 | 成为全国IPTV内容准入基础设施 |
|
||||||
|
| **四期** | 18个月 | 大小屏融合 | OTT/APP接入扩展 | MA+哈希机制延伸至OTT、手机APP |
|
||||||
|
|
||||||
|
### MVP 验收标准
|
||||||
|
|
||||||
|
- CP可完成哈希生成→送审→获MA码全流程
|
||||||
|
- 审核监管部门可完成验真→CSPS审核对接→媒资库入库→发布
|
||||||
|
- 运营商可完成CDN注入校验→分发
|
||||||
|
- 监管可完成按MA码查询全链路 + 一键应急下架(秒级生效)
|
||||||
|
- 版本篡改可被100%识别并阻断
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 八、非功能性要求(产品级)
|
||||||
|
|
||||||
|
| 维度 | 要求 |
|
||||||
|
|------|------|
|
||||||
|
| 性能 | 下架响应分钟级;哈希验真接口实时返回 |
|
||||||
|
| 兼容性 | 不改造CSPS、媒体资源库内部流程,仅通过映射层对接;保留三方自有编码 |
|
||||||
|
| 安全 | MA码+哈希绑定不可篡改不可解绑;哈希本地计算不传原文件;关键操作链上存证 |
|
||||||
|
| 合规 | 完全符合广电总局网络剧片发行许可及备案制度 |
|
||||||
|
| 可扩展 | 支持网络剧/微短剧/网络电影/网络动画,可扩展至OTT/APP |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 九、依赖与风险
|
||||||
|
|
||||||
|
| 类别 | 内容 | 应对 |
|
||||||
|
|------|------|------|
|
||||||
|
| 依赖 | 联盟链/分布式账本基础设施 | 一期完成选型与部署 |
|
||||||
|
| 依赖 | CSPS与媒体资源库开放对接接口 | 提前与审核监管部门确认接口规范 |
|
||||||
|
| 依赖 | 广电总局备案系统对接MA码签发 | 政策与技术双轨推进 |
|
||||||
|
| 依赖 | 授权转码中心支持转码后哈希重算上链 | 纳入一期改造范围 |
|
||||||
|
| 风险 | 三方系统改造意愿与排期 | 最小侵入设计 + 试点先行(广东/湖南) |
|
||||||
|
| 风险 | 跨省信任机制的政策落地 | 与监管联合制定跨省复用规则 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 十、产品价值总结
|
||||||
|
|
||||||
|
> TCS-IPTV 的核心不是让三方放弃自己的系统,而是在三方系统之上建立一层"可信身份映射层"——
|
||||||
|
> 用 **MA码** 解决"是谁"的监管问题,用 **哈希码** 解决"是不是"的技术问题,用 **可信数据空间** 解决"在哪"的溯源问题。
|
||||||
|
> 三者叠加,IPTV内容才能真正实现"审过即锁定,锁定即通行,通行可追溯"。
|
||||||
|
>
|
||||||
|
> 对监管:从"逐层翻译滞后"升级为"一码穿透、秒级响应"。
|
||||||
|
> 对CP:从"每省重走全流程"升级为"一次录入、全网复用"。
|
||||||
|
> 对运营商:从"真假难辨"升级为"注入即校验、数据可对齐"。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> 本 PRD 基于 0-req-IPTV.md 编制,作为产品设计、UE/UI 设计与技术方案设计的输入。
|
||||||
@@ -0,0 +1,469 @@
|
|||||||
|
# TCS-IPTV 内容可信锁定系统 — 开发任务文档(MVP / 一期)
|
||||||
|
|
||||||
|
> 版本:V1.0
|
||||||
|
> 编制日期:2026年6月
|
||||||
|
> 上游文档:0-req-IPTV.md(需求)、1-prd-IPTV.md(PRD)
|
||||||
|
> 文档编号:2-task-IPTV
|
||||||
|
> 本期范围:**MVP(一期)** — 单省单运营商微短剧全流程
|
||||||
|
> 目标闭环:送审 → 赋码 → 审核 → 入库 → 发布 → 注入 → 下架
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、MVP 范围与功能映射
|
||||||
|
|
||||||
|
| 功能编号 | 功能 | 对应需求 | 本期 |
|
||||||
|
|---------|------|---------|:----:|
|
||||||
|
| F01 | 母版多维哈希生成SDK | 需求1 | ✅ |
|
||||||
|
| F02 | 送审申报与哈希上链 | 需求2 | ✅ |
|
||||||
|
| F03 | MA码签发与1:1强绑定 | 需求3 | ✅ |
|
||||||
|
| F04 | 送审文件验真 | 需求4 | ✅ |
|
||||||
|
| F05 | CSPS审核对接与转码版哈希绑定 | 需求5 | ✅ |
|
||||||
|
| F06 | 媒体资源库入库/发布与编码映射 | 需求6 | ✅ |
|
||||||
|
| F07 | CDN注入校验 | 需求7 | ✅ |
|
||||||
|
| F10 | 全生命周期监管大屏查询 | 需求10 | ✅ |
|
||||||
|
| F11 | 违规应急下架 | 需求11 | ✅ |
|
||||||
|
| F12 | 版本变更与重审触发 | 需求12 | ✅ |
|
||||||
|
| F14 | 角色权限控制(三角色矩阵) | 需求14 | ✅ |
|
||||||
|
| F15 | 异常处理规则 | 需求15 | ✅ |
|
||||||
|
| F16 | 可信数据空间存证与智能合约 | 需求16 | ✅ |
|
||||||
|
| F17 | 标准化开放API | 需求17 | ✅ |
|
||||||
|
| — | 安全与可信基线(哈希本地计算/链上存证/鉴权) | 需求20 | ✅ |
|
||||||
|
| F08/F09/F13/F18-F22 | 终端抽检/数据聚合/跨省/权益场景 | — | ⛔ 二期 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、技术栈(已确认)
|
||||||
|
|
||||||
|
| 层 | 选型 | 说明 |
|
||||||
|
|----|------|------|
|
||||||
|
| 联盟链 | 长安链 ChainMaker 2.x(国密 SM2/SM3/SM4)| 可信数据空间底层,合规优先 |
|
||||||
|
| 智能合约 | Go(ChainMaker 链原生合约)| issueMA / registerMapping / verifyHash 等 |
|
||||||
|
| 后端服务 | **Go 1.22 + Gin** | 验真、签发编排、映射、媒资对接、下架、监管查询等全部业务服务 |
|
||||||
|
| 链交互 | Go + ChainMaker Go SDK | chain-svc,屏蔽底链细节,提供 REST/gRPC;与合约同语言无跨语言摩擦 |
|
||||||
|
| 哈希SDK | Go 核心库 + HTTP API 对外 | 文件SHA-256 / 分段Merkle / 感知哈希 |
|
||||||
|
| 关系数据库 | PostgreSQL 16 | 业务元数据、映射缓存、内容主表镜像 |
|
||||||
|
| 数据访问 | GORM / sqlc | DB 访问与迁移 |
|
||||||
|
| 缓存 | Redis 7.x | 验真结果缓存、限流、会话 |
|
||||||
|
| API网关 | Kong / APISIX | 鉴权、限流、日志 |
|
||||||
|
| 监管大屏前端 | React 18 + Ant Design 5 + ECharts | 全链路查询、应急下架操作台 |
|
||||||
|
| 鉴权 | API Key + HMAC-SHA256 / Bearer Token | 三方接入鉴权 |
|
||||||
|
| 构建 | Go Modules + Makefile | — |
|
||||||
|
| 测试 | Go testing + testify + Testcontainers-go | 单元/集成测试 |
|
||||||
|
| 部署 | Docker + Kubernetes(试点可单集群)| 静态二进制,镜像小 |
|
||||||
|
| CI/CD | GitLab CI | 自动构建测试 |
|
||||||
|
|
||||||
|
> 待确认项:① 哈希SDK 是否需要向 CP 提供非 Go(如 Python)绑定(MVP 暂定 Go 库 + HTTP API 供外部);② CSPS 与媒体资源库的实际对接接口规范(需对接方提供)。
|
||||||
|
|
||||||
|
> 说明:合约本体与全部应用层后端服务统一采用 **Go**,与 ChainMaker 链原生同语言,链交互最顺、部署最轻;监管大屏前端采用 React。二期若业务编排显著变重(分账结算/复杂对账/报表),可再评估引入 JVM 业务中台。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、任务分解(按工作包)
|
||||||
|
|
||||||
|
> 进度图例:`[ ]` 未开始 · `[~]` 进行中 · `[x]` 已完成
|
||||||
|
> 每个任务标注:**目标** / **对应** / **验收** / **依赖**
|
||||||
|
|
||||||
|
### 工作包 0:项目脚手架与基础设施
|
||||||
|
|
||||||
|
- [x] **T0.1 代码仓库与工程骨架**
|
||||||
|
- 目标:建立 monorepo(chain-svc / api-svc / hash-sdk / web-console)与基础工程结构
|
||||||
|
- 对应:全局
|
||||||
|
- 验收:各模块可独立构建;统一 lint/格式化;README 说明
|
||||||
|
- 依赖:无
|
||||||
|
- ✅ 完成:`tcs-iptv/` monorepo 建立,cmd/{api-svc,chain-svc,hash-api} + internal/{config,httpx} + contracts + deploy + Makefile + README,`go build ./...` 通过
|
||||||
|
|
||||||
|
- [ ] **T0.2 联盟链测试网部署**
|
||||||
|
- 目标:搭建 ChainMaker(或 Fabric)测试网,含监管/审核监管/运营商三组织节点
|
||||||
|
- 对应:需求16
|
||||||
|
- 验收:三组织节点正常出块;可部署/调用合约;提供连接配置
|
||||||
|
- 依赖:T0.1、技术栈确认
|
||||||
|
- ⏳ 待办:MVP 阶段先用 chain mock(internal/chain)解耦开发,真实 ChainMaker 测试网并行搭建
|
||||||
|
|
||||||
|
- [x] **T0.3 数据库与中间件部署**
|
||||||
|
- 目标:部署 PostgreSQL、Redis,建立基础 schema 迁移工具
|
||||||
|
- 对应:需求16
|
||||||
|
- 验收:迁移脚本可执行;连接池配置;本地/测试环境可用
|
||||||
|
- 依赖:T0.1
|
||||||
|
- ✅ 完成:本地 PostgreSQL(库 tcs_iptv)+ Redis 就绪;`0001_init.sql` 建 5 张镜像表(content_registry/hash_binding/identity_mapping/version_history/chain_tx),`make migrate` 通过
|
||||||
|
|
||||||
|
- [ ] **T0.4 API 网关与鉴权基线**
|
||||||
|
- 目标:接入 Kong/APISIX,实现 API Key + HMAC-SHA256 鉴权与限流
|
||||||
|
- 对应:需求17、需求20
|
||||||
|
- 验收:未签名/错误签名请求被拒;限流生效;调用日志记录
|
||||||
|
- 依赖:T0.1
|
||||||
|
- ⏳ 待办:MVP 先在 api-svc 内实现 HMAC 鉴权中间件,网关接入二期
|
||||||
|
|
||||||
|
- [ ] **T0.5 CI/CD 流水线**
|
||||||
|
- 目标:GitLab CI 自动构建、单元测试、镜像打包
|
||||||
|
- 对应:全局
|
||||||
|
- 验收:提交触发流水线;测试不过则阻断合并
|
||||||
|
- 依赖:T0.1
|
||||||
|
- ⏳ 待办
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 工作包 1:可信数据空间与智能合约(F16)
|
||||||
|
|
||||||
|
> MVP 策略:业务规则在 `internal/chain.MemoryChain` 完整实现并测试通过(无需真实链即可开发);
|
||||||
|
> 真实合约规格见 `contracts/tcs_registry/README.md`,二期搭 ChainMaker 测试网后落地替换。
|
||||||
|
|
||||||
|
- [x] **T1.1 核心数据结构与合约骨架**
|
||||||
|
- 目标:定义内容主表、哈希绑定表、三方编码映射表、版本变更表四类结构
|
||||||
|
- 对应:需求16-AC1
|
||||||
|
- 验收:结构可读写;单元测试覆盖
|
||||||
|
- ✅ 完成:`internal/model` 四类模型 + `internal/chain.Client` 接口 + MemoryChain 实现 + 合约规格文档
|
||||||
|
|
||||||
|
- [x] **T1.2 issueMA(签发+强绑定)**
|
||||||
|
- 对应:需求3、需求16-AC2、需求20-AC1
|
||||||
|
- 验收:仅监管节点可调用;重复签发被拒;绑定不可覆盖;防重复哈希
|
||||||
|
- ✅ 完成:`MemoryChain.IssueMA`,测试覆盖权限/重复/换壳
|
||||||
|
|
||||||
|
- [x] **T1.3 registerMapping(三方编码映射)**
|
||||||
|
- 对应:需求16-AC3
|
||||||
|
- 验收:MA 未签发时拒绝;映射可查
|
||||||
|
- ✅ 完成:`RegisterMapping`,测试覆盖
|
||||||
|
|
||||||
|
- [x] **T1.4 verifyHash(哈希校验)**
|
||||||
|
- 对应:需求16、需求4
|
||||||
|
- 验收:匹配/不匹配返回正确(含转码版)
|
||||||
|
- ✅ 完成:`VerifyHash`,测试覆盖匹配/不匹配/未知MA
|
||||||
|
|
||||||
|
- [x] **T1.5 Merkle Tree 分段存证与按集定位**
|
||||||
|
- 对应:需求16-AC4、需求12-AC3
|
||||||
|
- 验收:可按集校验;篡改单集能定位到具体集
|
||||||
|
- ✅ 完成:`internal/hash` BuildMerkleTree + LocateChangedLeaves,测试覆盖
|
||||||
|
|
||||||
|
- [x] **T1.6 链上存证审计与不可篡改校验**
|
||||||
|
- 对应:需求16-AC5、需求20-AC3
|
||||||
|
- 验收:操作留痕;不可覆盖
|
||||||
|
- ✅ 完成:txID 留痕 + 1:1 不可解绑规则;真实链不可篡改性由 ChainMaker 保证(规格已记录)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 工作包 2:链交互服务(chain-svc)
|
||||||
|
|
||||||
|
- [ ] **T2.1 链交互封装层**
|
||||||
|
- 目标:封装合约调用(签发/映射/验真/查询),提供内部 REST/gRPC
|
||||||
|
- 对应:需求16、需求17
|
||||||
|
- 验收:业务服务无需感知底链细节;异常重试;测试覆盖
|
||||||
|
- 依赖:T1.2-T1.6
|
||||||
|
|
||||||
|
- [ ] **T2.2 异步上链与确认机制**
|
||||||
|
- 目标:交易提交后监听区块确认,落库状态 pending→confirmed
|
||||||
|
- 对应:需求16
|
||||||
|
- 验收:确认回执准确;超时/失败有处理;测试覆盖
|
||||||
|
- 依赖:T2.1
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 工作包 3:哈希计算 SDK(F01)
|
||||||
|
|
||||||
|
- [x] **T3.1 文件哈希与分段 Merkle**
|
||||||
|
- 对应:需求1-AC1、AC2
|
||||||
|
- 验收:大文件分段稳定;Merkle 根可复算一致
|
||||||
|
- ✅ 完成:`internal/hash` sha.go + merkle.go,测试覆盖(含已知向量、篡改检测、奇数叶子)
|
||||||
|
|
||||||
|
- [x] **T3.2 感知哈希计算**
|
||||||
|
- 对应:需求1-AC3
|
||||||
|
- 验收:同内容感知哈希稳定;可计算汉明距离
|
||||||
|
- ✅ 完成:aHash/dHash + HammingDistance,测试覆盖
|
||||||
|
|
||||||
|
- [x] **T3.3 SDK 封装与本地存证**
|
||||||
|
- 对应:需求1-AC4、AC5、AC6、需求20-AC2
|
||||||
|
- 验收:返回完整哈希值包;不支持/空文件报错;原文件不外传
|
||||||
|
- ✅ 完成:`ComputeFile` + HashPackage + Validate,测试覆盖空文件/缺文件/缺字段
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 工作包 4:CP 送审与哈希上链(F02)
|
||||||
|
|
||||||
|
- [x] **T4.1 送审申报接口与节目信息收录**
|
||||||
|
- 对应:需求2-AC1、AC2、需求17-AC1
|
||||||
|
- 验收:合法申报返回流水号;哈希入可信空间
|
||||||
|
- ✅ 完成:`service.SubmitForReview`(受理+CTID生成),测试覆盖
|
||||||
|
|
||||||
|
- [x] **T4.2 重复哈希识别(防换壳重发)**
|
||||||
|
- 对应:需求2-AC3、需求15-AC5
|
||||||
|
- 验收:重复哈希被拦截并返回原 MA码
|
||||||
|
- ✅ 完成:HashExists 拦截,测试覆盖
|
||||||
|
|
||||||
|
- [x] **T4.3 哈希值包完整性校验**
|
||||||
|
- 对应:需求2-AC5
|
||||||
|
- 验收:缺字段被拒并提示
|
||||||
|
- ✅ 完成:ErrIncompleteHashPkg,测试覆盖
|
||||||
|
|
||||||
|
> 注:T4.x 当前为 service 层实现,HTTP 接口(api-svc 路由)在工作包后段统一接入。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 工作包 5:MA码生成与签发(F03,模式B 自行发码)
|
||||||
|
|
||||||
|
- [x] **T5.0 MA码生成服务(号段管理 + 按规则发码)**
|
||||||
|
- 目标:登记发码机构分配的码段,按内容类目原子发码,保证全局唯一
|
||||||
|
- 对应:需求3-AC1~AC4、AC10
|
||||||
|
- 验收:顺序唯一、并发不重号、号段耗尽报错、格式校验/解析
|
||||||
|
- ✅ 完成:`internal/macode`(Generator + Segment + MemoryStore + Parse),9项测试通过(含200并发无重号)
|
||||||
|
|
||||||
|
- [x] **T5.1 签发编排服务**
|
||||||
|
- 目标:审核通过后生成 MA码、调用 issueMA 签发并绑定,记录内容主表
|
||||||
|
- 对应:需求3-AC2、AC5、AC9
|
||||||
|
- 验收:签发成功并绑定;主表信息完整
|
||||||
|
- ✅ 完成:`service.ApproveAndIssue`(自动发码+强绑定),测试覆盖
|
||||||
|
|
||||||
|
- [x] **T5.2 MA码+哈希证书生成**
|
||||||
|
- 对应:需求3-AC7
|
||||||
|
- 验收:证书含 MA码与哈希,可被验真校验
|
||||||
|
- ✅ 完成:Certificate 字段,测试覆盖
|
||||||
|
|
||||||
|
- [ ] **T5.3 未赋码内容准入拦截**
|
||||||
|
- 对应:需求3-AC8
|
||||||
|
- 验收:无证书内容被拦截
|
||||||
|
- ⏳ 待办:在媒资库/分发门禁处统一拦截(并入 T8.2)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 工作包 6:送审文件验真(F04)
|
||||||
|
|
||||||
|
- [ ] **T6.1 验真接口(哈希比对)**
|
||||||
|
- 目标:计算送审文件哈希并与可信空间绑定哈希比对
|
||||||
|
- 对应:需求4-AC1、AC2、需求17-AC2
|
||||||
|
- 验收:匹配进入审核;返回 valid/bound_hash/submitted_hash/match/version;测试覆盖
|
||||||
|
- 依赖:T2.1、T1.4
|
||||||
|
|
||||||
|
- [ ] **T6.2 不匹配退回与标记**
|
||||||
|
- 目标:哈希不匹配直接退回并标记"疑似版本替换"
|
||||||
|
- 对应:需求4-AC3、需求15-AC1
|
||||||
|
- 验收:不匹配被退回并标记;测试覆盖
|
||||||
|
- 依赖:T6.1
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 工作包 7:CSPS 对接与转码版哈希(F05)
|
||||||
|
|
||||||
|
- [ ] **T7.1 CSPS 审核结论对接适配器**
|
||||||
|
- 目标:与 CSPS 审核系统对接,关联审核结论至 MA码/哈希,不改造 CSPS
|
||||||
|
- 对应:需求5-AC1、AC2
|
||||||
|
- 验收:CSPS 结论可关联并查询;对接为外挂式不改 CSPS 流程;测试覆盖(含 Mock CSPS)
|
||||||
|
- 依赖:T2.1、对接规范确认
|
||||||
|
|
||||||
|
- [ ] **T7.2 转码版哈希绑定与父子关系**
|
||||||
|
- 目标:转码后各版本哈希绑定同一 MA码,建立母版-转码版父子关系
|
||||||
|
- 对应:需求5-AC3、AC4、AC5
|
||||||
|
- 验收:多转码版共享 MA码独立哈希;父子关系可查;测试覆盖
|
||||||
|
- 依赖:T7.1、T1.2
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 工作包 8:媒体资源库入库/发布与映射(F06)
|
||||||
|
|
||||||
|
- [ ] **T8.1 媒资库入库与映射建立**
|
||||||
|
- 目标:审核合格内容入媒资库,建立"媒资编码↔MA码↔文件哈希↔转码版哈希"映射
|
||||||
|
- 对应:需求6-AC1、AC2
|
||||||
|
- 验收:入库后映射可查;保留媒资自有编码;测试覆盖
|
||||||
|
- 依赖:T7.2、T1.3
|
||||||
|
|
||||||
|
- [ ] **T8.2 可发布状态门禁**
|
||||||
|
- 目标:未审核通过/未绑定 MA码的内容不得进入可发布状态
|
||||||
|
- 对应:需求6-AC3
|
||||||
|
- 验收:不合规内容无法发布;测试覆盖
|
||||||
|
- 依赖:T8.1
|
||||||
|
|
||||||
|
- [ ] **T8.3 发布携带证书校验**
|
||||||
|
- 目标:向运营商发布必须携带 MA码+哈希证书,否则拒绝
|
||||||
|
- 对应:需求6-AC4、AC5
|
||||||
|
- 验收:缺证书发布被拒;测试覆盖
|
||||||
|
- 依赖:T8.1
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 工作包 9:CDN 注入校验(F07)
|
||||||
|
|
||||||
|
- [ ] **T9.1 注入前哈希校验**
|
||||||
|
- 目标:运营商注入 CDN 前计算哈希并与绑定哈希比对
|
||||||
|
- 对应:需求7-AC1、AC2
|
||||||
|
- 验收:匹配允许注入并生成分发编码;测试覆盖
|
||||||
|
- 依赖:T6.1、T8.3
|
||||||
|
|
||||||
|
- [ ] **T9.2 不匹配拒绝注入与告警**
|
||||||
|
- 目标:哈希不匹配拒绝注入、告警审核监管部门、暂停分发
|
||||||
|
- 对应:需求7-AC3、需求15-AC2
|
||||||
|
- 验收:不匹配被拦截并告警;测试覆盖
|
||||||
|
- 依赖:T9.1
|
||||||
|
|
||||||
|
- [ ] **T9.3 运营商映射注册**
|
||||||
|
- 目标:注入成功后注册运营商映射(分发编码、CDN端点)
|
||||||
|
- 对应:需求7-AC4
|
||||||
|
- 验收:映射可查;测试覆盖
|
||||||
|
- 依赖:T9.1、T1.3
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 工作包 10:版本变更与重审(F12)
|
||||||
|
|
||||||
|
- [ ] **T10.1 绑定断裂检测与重审标记**
|
||||||
|
- 目标:哈希变化判定绑定断裂,记录版本变更,reaudit_required=true
|
||||||
|
- 对应:需求12-AC1、AC2、需求15-AC4
|
||||||
|
- 验收:变更被检出并记录;重审标记生效;测试覆盖
|
||||||
|
- 依赖:T1.5、T6.1
|
||||||
|
|
||||||
|
- [ ] **T10.2 重审门禁**
|
||||||
|
- 目标:重审未通过的变更内容不得进入分发
|
||||||
|
- 对应:需求12-AC4
|
||||||
|
- 验收:未过重审内容被拦截;测试覆盖
|
||||||
|
- 依赖:T10.1、T8.2
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 工作包 11:角色权限控制(F14)
|
||||||
|
|
||||||
|
- [x] **T11.1 三角色权限矩阵实现**
|
||||||
|
- 对应:需求14-AC1~AC5
|
||||||
|
- 验收:越权操作被拒;签发/下架仅监管主体;测试覆盖各角色
|
||||||
|
- ✅ 完成:chain 层 role 校验 + httpx HMAC 角色鉴权;TestE2E_PermissionMatrix 覆盖越权403/错误签名401
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 工作包 12:异常处理规则(F15)
|
||||||
|
|
||||||
|
- [x] **T12.1 全局异常处理与规则引擎**
|
||||||
|
- 对应:需求15-AC1~AC5(终端抽检异常 AC3 二期)
|
||||||
|
- 验收:各异常分支按规则执行并留日志
|
||||||
|
- ✅ 完成:service 层 ErrIncompleteHashPkg/ErrDuplicateContent/ErrHashMismatch/ErrNotApproved/ErrNoCertificate;送审退回、注入拒绝、换壳拦截、变更重审均测试覆盖
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 工作包 13:监管大屏与全链路查询(F10)
|
||||||
|
|
||||||
|
- [x] **T13.1 按 MA码全链路状态查询接口**
|
||||||
|
- 对应:需求10、需求17-AC3
|
||||||
|
- 验收:返回三方映射+CDN端点
|
||||||
|
- ✅ 完成:`GET /api/v1/content/mappings`,端到端验证
|
||||||
|
|
||||||
|
- [x] **T13.2 监管大屏前端**
|
||||||
|
- 对应:需求10、需求11
|
||||||
|
- 验收:可视化查询、验真、应急下架
|
||||||
|
- ✅ 完成:`web-console`(Vite+React18+AntD5),MA码查询/三方映射表/哈希验真/一键下架,`npm run build` 通过;浏览器端 Web Crypto HMAC 签名与后端一致
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 工作包 14:违规应急下架(F11)
|
||||||
|
|
||||||
|
- [ ] **T14.1 下架指令解析与翻译**
|
||||||
|
- 目标:单一 MA码指令解析出三方编码+CDN端点,翻译为各方下架动作
|
||||||
|
- 对应:需求11-AC1、AC2、需求17-AC3
|
||||||
|
- 验收:一码解析出全部映射;翻译正确;测试覆盖
|
||||||
|
- 依赖:T8.1、T9.3
|
||||||
|
|
||||||
|
- [ ] **T14.2 全网秒级同步下架**
|
||||||
|
- 目标:下架指令秒级同步至媒资库撤除发布+运营商下架;权限限监管主体
|
||||||
|
- 对应:需求11-AC3、AC4
|
||||||
|
- 验收:秒级同步;非监管主体无法发起;测试覆盖
|
||||||
|
- 依赖:T14.1、T11.1
|
||||||
|
|
||||||
|
- [ ] **T14.3 应急下架操作台(前端)**
|
||||||
|
- 目标:监管在大屏一键下架并查看执行结果
|
||||||
|
- 对应:需求11
|
||||||
|
- 验收:操作便捷;执行状态可见;联调通过
|
||||||
|
- 依赖:T14.2、T13.2
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 工作包 15:集成测试与试点验收
|
||||||
|
|
||||||
|
- [x] **T15.1 端到端集成测试**
|
||||||
|
- 对应:MVP 验收标准
|
||||||
|
- 验收:全链路自动化测试通过
|
||||||
|
- ✅ 完成:`internal/api/integration_test.go` TestE2E_FullLifecycle,覆盖送审→发码→审核→入库→发布→注入→映射→下架
|
||||||
|
|
||||||
|
- [x] **T15.2 版本篡改识别专项测试**
|
||||||
|
- 对应:需求12、需求18-AC4
|
||||||
|
- 验收:篡改用例全部被识别定位
|
||||||
|
- ✅ 完成:TestE2E_TamperRejected(注入篡改拒绝)+ TestE2E_VersionChangeLocatesEpisode(定位到第2集)
|
||||||
|
|
||||||
|
- [x] **T15.3 应急下架时效测试**
|
||||||
|
- 对应:需求11、需求18-AC1
|
||||||
|
- 验收:下架端到端耗时达标
|
||||||
|
- ✅ 完成:TestE2E_TakedownLatency(秒级内,目标分钟级)
|
||||||
|
|
||||||
|
- [ ] **T15.4 单省单运营商试点联调**
|
||||||
|
- 对应:MVP 范围
|
||||||
|
- 验收:真实环境跑通闭环;问题清单收敛
|
||||||
|
- ⏳ 待办:需真实 CSPS/媒资库/运营商对接环境,列入试点排期
|
||||||
|
|
||||||
|
> 补充:权限矩阵 E2E(TestE2E_PermissionMatrix)覆盖 CP 越权发码 403、运营商越权下架 403、错误签名 401。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、依赖关系总览
|
||||||
|
|
||||||
|
```
|
||||||
|
T0.* 基础设施
|
||||||
|
└─ T1.* 智能合约 ─ T2.* 链交互
|
||||||
|
├─ T3.* 哈希SDK ─ T4.* CP送审 ─ T5.* MA签发 ─ T6.* 验真
|
||||||
|
│ ├─ T7.* CSPS+转码 ─ T8.* 媒资库 ─ T9.* CDN注入
|
||||||
|
│ └─ T10.* 版本重审
|
||||||
|
├─ T11.* 权限 ├─ T12.* 异常
|
||||||
|
└─ T13.* 监管大屏 ─ T14.* 应急下架
|
||||||
|
└─ T15.* 集成测试与试点验收
|
||||||
|
```
|
||||||
|
|
||||||
|
关键路径:T0 → T1 → T2 → T3/T4 → T5 → T6 → T7 → T8 → T9 → T14 → T15
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、进度记录(开发中持续更新)
|
||||||
|
|
||||||
|
| 日期 | 完成任务 | 备注 | 变更说明 |
|
||||||
|
|------|---------|------|---------|
|
||||||
|
| 2026-06-14 | T0.1 工程骨架 | monorepo 建立,`go build ./...` 通过 | 模块路径 github.com/tcs-iptv/tcs |
|
||||||
|
| 2026-06-14 | T0.3 数据库与迁移 | 本地 PG(tcs_iptv)+Redis,5张镜像表 | CTID列名改为 content_twin_id(避开PG保留字) |
|
||||||
|
| 2026-06-14 | 环境决策 | 改用本地 PG/Redis,移除 docker-compose | T0.2链网测先用mock解耦;T0.4鉴权先在api-svc内实现 |
|
||||||
|
| 2026-06-14 | T1.1-T1.6 可信空间与合约 | MemoryChain 实现全部合约规则,14项测试通过 | 真实合约规格见 contracts/tcs_registry/README.md |
|
||||||
|
| 2026-06-14 | T3.1-T3.3 哈希SDK | 文件哈希/Merkle/感知哈希/SDK封装,13项测试通过 | CTID 概念落地 model.Content |
|
||||||
|
| 2026-06-14 | 环境 | psql 加入 PATH(~/.zshrc),Makefile 简化 | go vet/build/test 全绿 |
|
||||||
|
| 2026-06-14 | 架构决策:MA发码模式B | 与发码机构合作拿码段,TCS自行发码 | 需求3 改写为"生成+签发",新增 T5.0 |
|
||||||
|
| 2026-06-14 | T5.0 MA码生成服务 | internal/macode:号段管理+原子发码+解析,9项测试(含200并发无重号) | 六段式 MA.156.{行业}.{机构}/{类目}/{年份}{序列} |
|
||||||
|
| 2026-06-14 | T4.1-4.3 / T5.1-5.2 业务编排 | internal/service:送审→发码签发→验真,8项测试通过 | service 层完成,HTTP 路由后段接入 |
|
||||||
|
| 2026-06-14 | WP7-10 业务编排 | CSPS对接/转码绑定/媒资库入库发布/CDN注入/版本重审/下架,service 层 + 16项测试 | distribution.go |
|
||||||
|
| 2026-06-14 | WP4/9/13/14 HTTP接口 + 鉴权 | api-svc 11个路由 + HMAC鉴权中间件(T0.4);端到端冒烟10步全绿 | scripts/e2e_smoke.sh |
|
||||||
|
| 2026-06-14 | MA码持久化 | PostgresStore 号段原子分配(行级UPSERT),200并发零重号;api-svc 优先PG回退内存 | migrations/0002,解决重启丢号/多实例重号 |
|
||||||
|
| 2026-06-14 | T13.2 监管大屏 | web-console(React18+AntD5):查询/验真/下架,build通过 | Web Crypto HMAC 与后端一致;演示模式安全提示 |
|
||||||
|
| 2026-06-14 | M5 集成测试 | api 集成测试5项全绿(全闭环/篡改拒绝/篡改定位/权限矩阵/下架时效) | 全仓60+测试通过,MVP 代码完成 |
|
||||||
|
| 2026-06-14 | 集级粒度补齐 | 一剧一码+集级哈希绑定+集级子标识(MA码#E07)+按集验真;新增 verify-episode/episodes 接口 | 需求3增AC11-13,migration 0003,3项集级测试通过,端到端验证 |
|
||||||
|
| 2026-06-14 | 全流程演示前端 | web-console 新增"全流程演示"Tab:七步流水线一键执行+双锚定展示+篡改/下架按钮 | FlowDemo.jsx,四角色签名 |
|
||||||
|
| 2026-06-14 | 流程顺序修正 | 改为"先审核后发码"(CSPS审核前移,发码加审核门禁) | 需求3-AC2,全栈+测试+脚本同步 |
|
||||||
|
| 2026-06-14 | 集级面板 | 全流程页新增集级面板:各集独立哈希+集级子标识(MA码#E07)+按集验真/模拟篡改 | FlowDemo 集级表格 |
|
||||||
|
| 2026-06-14 | 多角色工作台 | RoleDesk:CP/审核监管/运营商 独立工作台+待办队列+全局看板,内容在各方桌面真实流转 | 新增 reviews/list 队列接口 + StatusIssued 状态 |
|
||||||
|
| 2026-06-14 | 监管片库 | RoleDesk 新增"监管片库"Tab:全片库列表+状态筛选+应急下架+三方映射/集级钻取详情 | LibraryDesk,content.file_hash 透出 |
|
||||||
|
| 2026-06-14 | 集级下架 | 子集级精准下架(RevokeEpisode),只下架某集不影响整剧;片库详情按集下架 | model.HashBinding.Revoked,TestEpisodeTakedown |
|
||||||
|
| 2026-06-14 | 恢复上架 | 整剧/子集 恢复上架(Restore/RestoreEpisode);片库列表与详情可下架↔恢复切换 | 下架后状态可逆 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 六、本期里程碑
|
||||||
|
|
||||||
|
- [x] M1:基础设施 + 智能合约就绪(工作包0、1、2)— 链规则用 MemoryChain 等价实现,真实链二期
|
||||||
|
- [x] M2:核心链路打通(哈希→送审→签发→验真,工作包3-6)
|
||||||
|
- [x] M3:审核入库发布注入闭环(工作包7-9)
|
||||||
|
- [x] M4:监管与应急下架(工作包10-14)
|
||||||
|
- [x] M5:集成测试通过(工作包15 T15.1-T15.3);单省试点联调 T15.4 待真实对接环境
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 七、MVP 收尾状态(2026-06-14)
|
||||||
|
|
||||||
|
**已完成(代码 + 测试):** 工作包 0/1/3/4/5/7/8/9/10/11/12/13/14/15
|
||||||
|
**测试总览:** 全仓 60+ 用例通过;`go vet` / `go build ./...` / `go test ./...` 全绿;前端 `npm run build` 通过
|
||||||
|
**端到端:** API 集成测试 5 项(全闭环/篡改拒绝/篡改定位/权限矩阵/下架时效)+ 脚本冒烟 10 步
|
||||||
|
|
||||||
|
**遗留待办(上生产前必做,列入二期/试点):**
|
||||||
|
1. T0.2 真实 ChainMaker 测试网 + 合约部署(替换 MemoryChain)
|
||||||
|
2. 链上镜像数据落 PostgreSQL(当前 content/mapping 仅在内存链,PG 镜像表已建待接入)
|
||||||
|
3. 监管大屏改「控制台 BFF + 会话令牌」,密钥不下发浏览器(当前为演示态)
|
||||||
|
4. T0.5 CI/CD 流水线
|
||||||
|
5. T15.4 单省单运营商真实联调
|
||||||
|
6. 二期权益场景 F18-F22 + 跨省复用 F13 + 终端抽检 F08
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> 本任务文档为 MVP(一期)开发指导。开发过程中将根据实际进度持续更新任务状态(`[ ]`→`[~]`→`[x]`)与进度记录表。二期权益场景(F18-F22)与跨省复用(F13)将在 MVP 验收后单独排期。
|
||||||
@@ -0,0 +1,235 @@
|
|||||||
|
# TCS-IPTV 开发任务文档(二期:贯通)
|
||||||
|
|
||||||
|
> 版本:V1.0
|
||||||
|
> 上游文档:0-req-IPTV.md(需求)、1-prd-IPTV.md(PRD)、2-task-IPTV.md(一期/MVP)
|
||||||
|
> 文档编号:3-task-IPTV-二期
|
||||||
|
> 周期:6 个月(M7-M12)
|
||||||
|
> 主题:多省多运营商、扩品类、强化权益(分账/追责/确权/追更/授权核验)+ MVP 遗留生产化
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、二期范围与功能映射
|
||||||
|
|
||||||
|
| 功能编号 | 功能 | 对应需求 | 本期 |
|
||||||
|
|---------|------|---------|:----:|
|
||||||
|
| F08 | 终端播放哈希抽检 | 需求8 | ✅ |
|
||||||
|
| F09 | 统一维度数据上报与聚合 | 需求9 | ✅ |
|
||||||
|
| F13 | 跨省复用快速准入 | 需求13 | ✅ |
|
||||||
|
| F18 | 可信播放数据聚合与分账结算依据 | 需求21 | ✅ |
|
||||||
|
| F19 | 全链路责任界定与追责取证 | 需求22 | ✅ |
|
||||||
|
| F20 | 版权确权与维权举证 | 需求23 | ✅ |
|
||||||
|
| F21 | 追更与增量哈希更新 | 需求24 | ✅ |
|
||||||
|
| F22 | 授权链上链与发布前授权核验 | 需求25 | ✅ |
|
||||||
|
| — | MVP 遗留生产化(真实链/数据落库/BFF/CI) | — | ✅ |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、二期技术栈增量
|
||||||
|
|
||||||
|
| 层 | 增量选型 | 说明 |
|
||||||
|
|----|---------|------|
|
||||||
|
| 联盟链 | 长安链 ChainMaker 2.x 测试网(三组织节点)| 替换 MVP 的 MemoryChain,落地真实合约 |
|
||||||
|
| 合约 | tcs_registry(Go 合约)正式部署 | issueMA/registerMapping/verifyHash/revoke 等 |
|
||||||
|
| 数据回传 | Kafka(可选)/ 批量 REST | 海量播放数据回传与聚合 |
|
||||||
|
| 分析 | ClickHouse / PostgreSQL 聚合表 | 以 MA 码为维度的播放/分账聚合 |
|
||||||
|
| 终端 | 播放器 SDK(C/Go/JS)| 片段哈希抽检 |
|
||||||
|
| 监管大屏 | 控制台 BFF(Go)+ 会话令牌 | 密钥不下发浏览器(替换演示态直连)|
|
||||||
|
| CI/CD | GitLab CI + 镜像扫描 | 自动构建测试发布 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、任务分解
|
||||||
|
|
||||||
|
> 进度图例:`[ ]` 未开始 · `[~]` 进行中 · `[x]` 已完成
|
||||||
|
|
||||||
|
### 工作包 A:真实联盟链落地(MVP 遗留)
|
||||||
|
|
||||||
|
- [ ] **A.1 ChainMaker 测试网搭建**
|
||||||
|
- 目标:三组织(监管/审核监管/运营商)节点组网,国密 SM2/SM3
|
||||||
|
- 对应:需求16、需求20
|
||||||
|
- 验收:节点正常出块;证书与权限配置就绪
|
||||||
|
- 依赖:一期
|
||||||
|
|
||||||
|
- [ ] **A.2 tcs_registry 合约落地**
|
||||||
|
- 目标:按 contracts/tcs_registry 规格实现并部署 Go 合约
|
||||||
|
- 对应:需求16-AC2、需求3、需求14
|
||||||
|
- 验收:issueMA/registerMapping/verifyHash/revoke/revokeEpisode 全部链上可调用,规则与 MemoryChain 一致
|
||||||
|
- 依赖:A.1
|
||||||
|
|
||||||
|
- [ ] **A.3 chain-svc 切换真实链**
|
||||||
|
- 目标:chain.Client 增加 ChainMaker 实现,配置切换 MemoryChain↔真实链
|
||||||
|
- 对应:需求16
|
||||||
|
- 验收:一期全部用例在真实链通过;异步上链与区块确认机制生效
|
||||||
|
- 依赖:A.2
|
||||||
|
|
||||||
|
- [ ] **A.4 链上数据 PostgreSQL 镜像**
|
||||||
|
- 目标:content/hash/mapping/version 落 PG 镜像表,支撑高效查询
|
||||||
|
- 对应:需求16-AC1
|
||||||
|
- 验收:链为权威源,PG 为查询镜像,最终一致;监管查询走 PG
|
||||||
|
- 依赖:A.3
|
||||||
|
|
||||||
|
### 工作包 B:监管大屏生产化(MVP 遗留)
|
||||||
|
|
||||||
|
- [ ] **B.1 控制台 BFF**
|
||||||
|
- 目标:新增 Go BFF,持有凭证,浏览器仅用会话令牌
|
||||||
|
- 对应:需求20、需求14
|
||||||
|
- 验收:密钥不出现在前端;登录态 + RBAC;审计登录操作
|
||||||
|
- 依赖:一期
|
||||||
|
|
||||||
|
- [ ] **B.2 前端改造对接 BFF**
|
||||||
|
- 目标:web-console 去掉前端 HMAC 直连,改走 BFF 会话
|
||||||
|
- 对应:需求20
|
||||||
|
- 验收:演示态安全告警移除;功能不回退
|
||||||
|
- 依赖:B.1
|
||||||
|
|
||||||
|
### 工作包 C:终端播放哈希抽检(F08)
|
||||||
|
|
||||||
|
- [ ] **C.1 播放器抽检 SDK**
|
||||||
|
- 目标:终端下载片段后计算哈希,与链上比对
|
||||||
|
- 对应:需求8-AC1、AC4
|
||||||
|
- 验收:多集按集增量校验;提供 C/Go/JS 绑定
|
||||||
|
- 依赖:A.3
|
||||||
|
|
||||||
|
- [ ] **C.2 异常断流与上报**
|
||||||
|
- 目标:抽检不匹配断流、切备用源、上报异常日志
|
||||||
|
- 对应:需求8-AC2、需求15-AC3
|
||||||
|
- 验收:篡改片段被识别并切源;日志可查
|
||||||
|
- 依赖:C.1
|
||||||
|
|
||||||
|
- [ ] **C.3 策略开关**
|
||||||
|
- 目标:按网络负载策略性开启/关闭抽检
|
||||||
|
- 对应:需求8-AC3
|
||||||
|
- 验收:可配置开关;高负载自动降级
|
||||||
|
- 依赖:C.1
|
||||||
|
|
||||||
|
### 工作包 D:数据回传与统一聚合(F09)
|
||||||
|
|
||||||
|
- [ ] **D.1 播放数据回传接口**
|
||||||
|
- 目标:运营商以 MA 码为维度批量回传播放/消费事件
|
||||||
|
- 对应:需求9-AC1
|
||||||
|
- 验收:批量接收+校验;幂等
|
||||||
|
- 依赖:A.3
|
||||||
|
|
||||||
|
- [ ] **D.2 MA 码维度聚合**
|
||||||
|
- 目标:CP 播放量/审核量/运营商分发量按 MA 码统一聚合
|
||||||
|
- 对应:需求9-AC2、AC3
|
||||||
|
- 验收:三方口径一致;提供统一数据视图
|
||||||
|
- 依赖:D.1
|
||||||
|
|
||||||
|
### 工作包 E:可信播放数据与分账结算(F18 / 需求21)
|
||||||
|
|
||||||
|
- [ ] **E.1 链上可信播放数据**
|
||||||
|
- 目标:以 MA 码聚合的播放数据不可篡改上链/锚定
|
||||||
|
- 对应:需求21-AC1、AC2
|
||||||
|
- 验收:CP 与运营商所见数据口径一致
|
||||||
|
- 依赖:D.2
|
||||||
|
|
||||||
|
- [ ] **E.2 分账结算依据**
|
||||||
|
- 目标:以链上可信播放数据作为统一结算依据
|
||||||
|
- 对应:需求21-AC3、AC4、AC5
|
||||||
|
- 验收:对账差异 <5%;可查询导出
|
||||||
|
- 依赖:E.1
|
||||||
|
|
||||||
|
### 工作包 F:责任界定与追责取证(F19 / 需求22)
|
||||||
|
|
||||||
|
- [ ] **F.1 全链路存证查询**
|
||||||
|
- 目标:按 MA 码调取各节点哈希存证(送审/审核/转码/媒资/注入/抽检)
|
||||||
|
- 对应:需求22-AC1、AC3
|
||||||
|
- 验收:各节点带时间戳、操作方、不可篡改
|
||||||
|
- 依赖:A.4
|
||||||
|
|
||||||
|
- [ ] **F.2 责任定位与取证报告**
|
||||||
|
- 目标:比对各节点哈希,定位首次变化节点与责任方,导出取证报告
|
||||||
|
- 对应:需求22-AC2、AC4
|
||||||
|
- 验收:能精确定位问题环节;报告可导出
|
||||||
|
- 依赖:F.1
|
||||||
|
|
||||||
|
### 工作包 G:版权确权与维权举证(F20 / 需求23)
|
||||||
|
|
||||||
|
- [ ] **G.1 确权证据链**
|
||||||
|
- 目标:MA 码+哈希+上链时间戳形成不可抵赖确权证据
|
||||||
|
- 对应:需求23-AC1、AC2、AC4
|
||||||
|
- 验收:可导出用于投诉/诉讼的证据链
|
||||||
|
- 依赖:A.4
|
||||||
|
|
||||||
|
- [ ] **G.2 感知哈希侵权比对**
|
||||||
|
- 目标:感知哈希相似度比对,标记疑似侵权并关联原 MA 码
|
||||||
|
- 对应:需求23-AC3
|
||||||
|
- 验收:相似内容(换皮/转码)可被识别
|
||||||
|
- 依赖:G.1
|
||||||
|
|
||||||
|
### 工作包 H:追更与增量哈希更新(F21 / 需求24)
|
||||||
|
|
||||||
|
- [ ] **H.1 增量哈希更新**
|
||||||
|
- 目标:仅对变化集/片段重算哈希,Merkle 仅更新变化叶子
|
||||||
|
- 对应:需求24-AC1、AC2、AC3
|
||||||
|
- 验收:未变化部分复用原审核结论
|
||||||
|
- 依赖:A.4
|
||||||
|
|
||||||
|
- [ ] **H.2 追更快速赋码**
|
||||||
|
- 目标:新增集快速赋码,不触发存量重审
|
||||||
|
- 对应:需求24-AC4
|
||||||
|
- 验收:追更秒级完成赋码与发布
|
||||||
|
- 依赖:H.1
|
||||||
|
|
||||||
|
### 工作包 I:授权链与发布前核验(F22 / 需求25)
|
||||||
|
|
||||||
|
- [ ] **I.1 授权信息上链**
|
||||||
|
- 目标:信息网络传播权(地域/期限/平台)上链存证
|
||||||
|
- 对应:需求25-AC1
|
||||||
|
- 验收:授权范围可查;变更可追溯
|
||||||
|
- 依赖:A.4
|
||||||
|
|
||||||
|
- [ ] **I.2 发布/注入前授权核验**
|
||||||
|
- 目标:发布与 CDN 注入前核验授权范围,越权拦截
|
||||||
|
- 对应:需求25-AC2、AC3、AC4
|
||||||
|
- 验收:超地域/过期/非授权平台分发被拦截
|
||||||
|
- 依赖:I.1
|
||||||
|
|
||||||
|
### 工作包 J:跨省复用快速准入(F13 / 需求13)
|
||||||
|
|
||||||
|
- [ ] **J.1 跨省凭证准入**
|
||||||
|
- 目标:B 省凭 MA 码+哈希证书准入,不重传内容文件
|
||||||
|
- 对应:需求13-AC1、AC2
|
||||||
|
- 验收:三重校验(MA有效+哈希一致+非黑名单)通过
|
||||||
|
- 依赖:A.4
|
||||||
|
|
||||||
|
- [ ] **J.2 简化抽检与映射注册**
|
||||||
|
- 目标:B 省审核简化为合规抽检,生成本省流水号+映射
|
||||||
|
- 对应:需求13-AC3、AC4
|
||||||
|
- 验收:复用周期 15-30天 → 3-5天
|
||||||
|
- 依赖:J.1
|
||||||
|
|
||||||
|
### 工作包 K:平台接入扩展与 CI/CD
|
||||||
|
|
||||||
|
- [ ] **K.1 CI/CD 流水线**
|
||||||
|
- 目标:GitLab CI 自动构建/测试/镜像扫描/发布
|
||||||
|
- 对应:全局
|
||||||
|
- 验收:提交触发;测试不过阻断
|
||||||
|
- 依赖:一期
|
||||||
|
|
||||||
|
- [ ] **K.2 多省多运营商接入**
|
||||||
|
- 目标:扩展至 3-5 省,接入主流 CP 10 家以上
|
||||||
|
- 对应:PRD 二期目标
|
||||||
|
- 验收:平台接入≥15家;网络剧/网络电影品类覆盖
|
||||||
|
- 依赖:A.3
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、二期里程碑
|
||||||
|
|
||||||
|
- [ ] M6:真实 ChainMaker 落地 + 监管大屏 BFF 化(工作包 A、B)
|
||||||
|
- [ ] M7:数据回传聚合 + 可信分账(工作包 D、E)
|
||||||
|
- [ ] M8:追责取证 + 确权举证 + 授权核验(工作包 F、G、I)
|
||||||
|
- [ ] M9:追更 + 跨省复用 + 终端抽检(工作包 C、H、J)
|
||||||
|
- [ ] M10:多省多运营商接入 + CI/CD(工作包 K);二期验收
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、二期验收标准
|
||||||
|
|
||||||
|
- 真实联盟链替换 MemoryChain,一期全部用例在链上通过
|
||||||
|
- 监管大屏密钥不下发浏览器(BFF 会话)
|
||||||
|
- 分账对账差异 <5%;追责可定位到环节;确权证据可导出
|
||||||
|
- 跨省复用周期 3-5 天;追更秒级;授权越权可拦截
|
||||||
|
- 平台接入 ≥15 家;月赋码量 ≥5 万部;月度盈亏平衡
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
# TCS-IPTV 开发任务文档(三期:生态/全国贯通)
|
||||||
|
|
||||||
|
> 版本:V1.0
|
||||||
|
> 上游文档:0-req-IPTV.md、1-prd-IPTV.md、2-task-IPTV.md(一期)、3-task-IPTV-二期.md
|
||||||
|
> 文档编号:4-task-IPTV-三期
|
||||||
|
> 周期:12 个月(Y2)
|
||||||
|
> 主题:全国 IPTV 统一接入、对接广电总局备案系统、全功能稳定化、成为内容准入基础设施
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、三期范围
|
||||||
|
|
||||||
|
| 方向 | 内容 |
|
||||||
|
|------|------|
|
||||||
|
| 备案系统对接 | 对接广电总局重点网络影视剧备案系统 / 发行许可证系统 |
|
||||||
|
| 全国节点扩展 | 多省机构节点(号段)规模化管理与发码生产化 |
|
||||||
|
| 行业标准 | 推动行业分账标准、内容准入标准落地 |
|
||||||
|
| 稳定化 | 等保三级正式测评、性能压测、高可用与灾备 |
|
||||||
|
| 监管贯通 | 监管数据上报、全国监管大屏、跨省协同处置 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、三期技术栈增量
|
||||||
|
|
||||||
|
| 层 | 增量选型 | 说明 |
|
||||||
|
|----|---------|------|
|
||||||
|
| 发码 | macode PostgresStore 生产化 + 多机构号段 | 多省机构节点号段管理 |
|
||||||
|
| 高可用 | PG Patroni 主从、Redis Cluster、链多节点 | RPO/RTO 达标 |
|
||||||
|
| 性能 | 压测(k6/wrk)、缓存优化、读写分离 | 万级 QPS 网关解析 |
|
||||||
|
| 监管 | 数据上报安全交换网关、全国监管大屏 | 对接广电总局专网 |
|
||||||
|
| 合规 | 等保三级测评、密钥 HSM、审计链 | 正式上线合规 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、任务分解
|
||||||
|
|
||||||
|
### 工作包 A:广电总局备案系统对接
|
||||||
|
|
||||||
|
- [ ] **A.1 备案/许可证系统接口对接**
|
||||||
|
- 目标:与重点网络影视剧备案系统、发行许可证系统打通
|
||||||
|
- 对应:需求19-AC3
|
||||||
|
- 验收:备案号/网标号与 MA 码、哈希记录可关联映射
|
||||||
|
- 依赖:二期
|
||||||
|
|
||||||
|
- [ ] **A.2 监管数据上报通道**
|
||||||
|
- 目标:通过安全数据交换网关向广电总局专网上报(日报/黑名单/处置)
|
||||||
|
- 对应:需求9、需求11
|
||||||
|
- 验收:单向推送;专线;审计留痕
|
||||||
|
- 依赖:A.1
|
||||||
|
|
||||||
|
### 工作包 B:发码与号段生产化
|
||||||
|
|
||||||
|
- [ ] **B.1 多机构号段管理后台**
|
||||||
|
- 目标:与发码机构对接管理多省机构节点号段(申领/分配/告警)
|
||||||
|
- 对应:需求3-AC1、AC3
|
||||||
|
- 验收:号段可视化管理;耗尽预警;不重号
|
||||||
|
- 依赖:二期
|
||||||
|
|
||||||
|
- [ ] **B.2 发码服务高可用**
|
||||||
|
- 目标:PostgresStore 行锁分配多实例化,号段不丢不重
|
||||||
|
- 对应:需求3-AC4
|
||||||
|
- 验收:多实例并发零重号;故障切换不丢号
|
||||||
|
- 依赖:B.1
|
||||||
|
|
||||||
|
### 工作包 C:全国节点扩展与接入
|
||||||
|
|
||||||
|
- [ ] **C.1 多省节点接入**
|
||||||
|
- 目标:全国各省广电/IPTV 运营公司接入
|
||||||
|
- 对应:PRD 三期目标
|
||||||
|
- 验收:覆盖目标省份;统一接入规范
|
||||||
|
- 依赖:A.1
|
||||||
|
|
||||||
|
- [ ] **C.2 跨省协同处置**
|
||||||
|
- 目标:跨省下架/恢复/黑名单全网联动
|
||||||
|
- 对应:需求11、需求13
|
||||||
|
- 验收:一处下架全国生效;跨省协同
|
||||||
|
- 依赖:C.1
|
||||||
|
|
||||||
|
### 工作包 D:性能、高可用与灾备
|
||||||
|
|
||||||
|
- [ ] **D.1 性能压测与优化**
|
||||||
|
- 目标:网关解析万级 QPS,关键接口达 SLA
|
||||||
|
- 对应:需求18
|
||||||
|
- 验收:P99 延迟达标;压测报告
|
||||||
|
- 依赖:二期
|
||||||
|
|
||||||
|
- [ ] **D.2 高可用与灾备**
|
||||||
|
- 目标:PG 主从、Redis Cluster、链多节点、跨可用区
|
||||||
|
- 对应:需求18
|
||||||
|
- 验收:RPO/RTO 达标;灾备演练通过
|
||||||
|
- 依赖:D.1
|
||||||
|
|
||||||
|
### 工作包 E:等保三级与安全
|
||||||
|
|
||||||
|
- [ ] **E.1 等保三级正式测评**
|
||||||
|
- 目标:完成等保三级测评并通过
|
||||||
|
- 对应:需求19-AC3、需求20
|
||||||
|
- 验收:测评报告;整改闭环
|
||||||
|
- 依赖:二期
|
||||||
|
|
||||||
|
- [ ] **E.2 密钥与审计强化**
|
||||||
|
- 目标:HSM 托管核心密钥、审计链不可篡改
|
||||||
|
- 对应:需求20-AC3
|
||||||
|
- 验收:核心密钥不可导出;全操作可审计
|
||||||
|
- 依赖:E.1
|
||||||
|
|
||||||
|
### 工作包 F:行业标准与运营
|
||||||
|
|
||||||
|
- [ ] **F.1 行业分账标准落地**
|
||||||
|
- 目标:推动并落地行业分账标准
|
||||||
|
- 对应:PRD 三期目标
|
||||||
|
- 验收:标准发布;试点采用
|
||||||
|
- 依赖:二期 E(分账)
|
||||||
|
|
||||||
|
- [ ] **F.2 全国监管大屏**
|
||||||
|
- 目标:全国维度内容/平台/合规态势可视化
|
||||||
|
- 对应:需求10
|
||||||
|
- 验收:全国数据看板;钻取到省/平台/MA码
|
||||||
|
- 依赖:A.2、C.1
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、三期里程碑
|
||||||
|
|
||||||
|
- [ ] M11:备案系统对接 + 监管上报通道(工作包 A)
|
||||||
|
- [ ] M12:发码生产化 + 多省接入(工作包 B、C)
|
||||||
|
- [ ] M13:性能/高可用/灾备 + 等保三级通过(工作包 D、E)
|
||||||
|
- [ ] M14:行业分账标准 + 全国监管大屏(工作包 F);三期验收
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、三期验收标准
|
||||||
|
|
||||||
|
- 对接广电总局备案系统,备案号↔MA 码↔哈希可关联
|
||||||
|
- 全国多省接入,跨省协同处置一处生效全网联动
|
||||||
|
- 等保三级测评通过;核心密钥 HSM 托管
|
||||||
|
- 网关解析万级 QPS、P99 达标;灾备演练通过
|
||||||
|
- 行业分账标准发布;全国监管大屏上线
|
||||||
|
- 年清算 GMV ≥50 亿;年收入 ≥10 亿(PRD 目标)
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
# TCS-IPTV 开发任务文档(四期:大小屏融合)
|
||||||
|
|
||||||
|
> 版本:V1.0
|
||||||
|
> 上游文档:0-req-IPTV.md、1-prd-IPTV.md、一/二/三期任务文档
|
||||||
|
> 文档编号:5-task-IPTV-四期
|
||||||
|
> 周期:18 个月(Y2 后半 - Y3)
|
||||||
|
> 主题:将 MA+哈希机制从 IPTV 扩展至 OTT、手机 APP,实现大小屏内容身份互通
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、四期范围
|
||||||
|
|
||||||
|
| 方向 | 内容 |
|
||||||
|
|------|------|
|
||||||
|
| OTT 接入 | 互联网电视 / OTT 盒子 / 智能电视端接入 |
|
||||||
|
| 移动端接入 | 手机 APP / 小程序端接入与扫码验真 |
|
||||||
|
| 大小屏互通 | 同一 MA 码在 IPTV/OTT/APP 间内容身份互通 |
|
||||||
|
| 跨屏权益 | 一次购买跨屏(电视↔手机)通看(衔接权益子链) |
|
||||||
|
| 内容凭证 | 移动端 C2PA 类水印/内容凭证嵌入与验证(衔接 AVCC 体系)|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、四期技术栈增量
|
||||||
|
|
||||||
|
| 层 | 增量选型 | 说明 |
|
||||||
|
|----|---------|------|
|
||||||
|
| 移动端 | React Native / 小程序 | 创作者移动端、用户扫码验真 |
|
||||||
|
| OTT 端 | Android TV / OTT SDK | 大屏播放器抽检与验真 |
|
||||||
|
| 内容凭证 | C2PA 类水印 SDK(衔接 AVCC)| 移动端生成/验证内容凭证 |
|
||||||
|
| 网关 | MA 跨域解析网关 | 大小屏统一解析入口 |
|
||||||
|
| 权益 | 跨屏权益子链 | 电视↔手机权益通兑 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、任务分解
|
||||||
|
|
||||||
|
### 工作包 A:OTT 端接入
|
||||||
|
|
||||||
|
- [ ] **A.1 OTT 解析与注入校验**
|
||||||
|
- 目标:OTT/智能电视端内容注入与播放前 MA 码解析+哈希校验
|
||||||
|
- 对应:需求4、需求7、需求19-AC4
|
||||||
|
- 验收:OTT 端复用 IPTV 注入校验能力
|
||||||
|
- 依赖:三期
|
||||||
|
|
||||||
|
- [ ] **A.2 OTT 播放器抽检 SDK**
|
||||||
|
- 目标:Android TV/OTT 播放器集成片段哈希抽检
|
||||||
|
- 对应:需求8
|
||||||
|
- 验收:大屏端按集抽检;异常切源
|
||||||
|
- 依赖:A.1
|
||||||
|
|
||||||
|
### 工作包 B:移动端接入
|
||||||
|
|
||||||
|
- [ ] **B.1 手机 APP / 小程序接入**
|
||||||
|
- 目标:移动端内容分发接入 MA+哈希校验
|
||||||
|
- 对应:需求4、需求7、需求19-AC4
|
||||||
|
- 验收:移动端播放前校验;统一鉴权
|
||||||
|
- 依赖:三期
|
||||||
|
|
||||||
|
- [ ] **B.2 扫码验真**
|
||||||
|
- 目标:用户扫码验证内容 MA 码真伪与流通状态
|
||||||
|
- 对应:需求4、需求10
|
||||||
|
- 验收:扫码返回 MA 解析+合规状态;防盗版
|
||||||
|
- 依赖:B.1
|
||||||
|
|
||||||
|
### 工作包 C:大小屏身份互通
|
||||||
|
|
||||||
|
- [ ] **C.1 MA 跨域解析网关**
|
||||||
|
- 目标:同一 MA 码在 IPTV/OTT/APP 统一解析
|
||||||
|
- 对应:需求4、需求10
|
||||||
|
- 验收:跨屏解析结果一致;统一流通状态
|
||||||
|
- 依赖:A.1、B.1
|
||||||
|
|
||||||
|
- [ ] **C.2 跨屏内容身份互通**
|
||||||
|
- 目标:同一内容跨屏共享 MA 码与哈希身份
|
||||||
|
- 对应:PRD 四期目标
|
||||||
|
- 验收:电视/手机/OTT 同内容同身份
|
||||||
|
- 依赖:C.1
|
||||||
|
|
||||||
|
### 工作包 D:跨屏权益通兑
|
||||||
|
|
||||||
|
- [ ] **D.1 跨屏权益子链**
|
||||||
|
- 目标:用户在电视端购买,手机端通看(权益记录上链)
|
||||||
|
- 对应:需求21(衔接权益)
|
||||||
|
- 验收:跨屏权益验证通过;不重复付费
|
||||||
|
- 依赖:C.2
|
||||||
|
|
||||||
|
### 工作包 E:移动端内容凭证(衔接 AVCC/C2PA)
|
||||||
|
|
||||||
|
- [ ] **E.1 移动端内容凭证 SDK**
|
||||||
|
- 目标:移动端生成/验证 C2PA 类内容凭证(含 MA 标识片段)
|
||||||
|
- 对应:需求19-AC4(可扩展)
|
||||||
|
- 验收:移动生成内容携带凭证;跨端可验
|
||||||
|
- 依赖:B.1
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、四期里程碑
|
||||||
|
|
||||||
|
- [ ] M15:OTT 端接入(工作包 A)
|
||||||
|
- [ ] M16:移动端接入 + 扫码验真(工作包 B)
|
||||||
|
- [ ] M17:大小屏身份互通 + 跨域解析(工作包 C)
|
||||||
|
- [ ] M18:跨屏权益通兑 + 移动内容凭证(工作包 D、E);四期验收
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、四期验收标准
|
||||||
|
|
||||||
|
- OTT、手机 APP 接入 MA+哈希校验,大小屏内容身份互通
|
||||||
|
- 同一 MA 码跨 IPTV/OTT/APP 统一解析,流通状态一致
|
||||||
|
- 跨屏权益通兑:电视端购买手机端通看,不重复付费
|
||||||
|
- 用户扫码可验真内容 MA 码与合规状态
|
||||||
|
- MA+哈希机制完成从 IPTV 到全场景大小屏的扩展
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> 四期完成后,TCS-IPTV 从"IPTV 内容可信锁定"升级为"全场景视听内容可信身份基础设施",
|
||||||
|
> 与 AVCC(AIGC 视听内容编码)体系形成大小屏、传统/AIGC 内容的统一身份底座。
|
||||||
@@ -0,0 +1,323 @@
|
|||||||
|
# TCS-IPTV 内容可信锁定系统 — 需求规格说明书
|
||||||
|
|
||||||
|
> 版本:V1.0
|
||||||
|
> 编制日期:2026年6月
|
||||||
|
> 基于文档:《MA+哈希码 IPTV内容可信锁定系统(TCS-IPTV)完整方案》
|
||||||
|
> 文档编号:0-req-IPTV
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 引言
|
||||||
|
|
||||||
|
本需求文档定义 TCS-IPTV(Trusted Content System for IPTV)内容可信锁定系统的功能性与非功能性需求。系统通过"MA码(监管身份)+ 哈希码(技术指纹)"双锚定机制,在 CP(内容供应商)、IPTV 集成播控平台、运营商(分发网络)三方现有系统之上建立一层"可信身份映射层",实现 IPTV 内容"审过即锁定,锁定即通行,通行可追溯"。
|
||||||
|
|
||||||
|
本系统的核心约束是:**不替代三方现有系统**,仅在关键节点(送审、入库、分发、播放)以最小侵入方式嵌入校验能力,并通过映射层统一对接。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 术语表
|
||||||
|
|
||||||
|
| 术语 | 全称 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| TCS-IPTV | Trusted Content System for IPTV | IPTV 内容可信锁定系统 |
|
||||||
|
| CP | Content Provider | 内容供应商 |
|
||||||
|
| 播控平台 | — | IPTV 集成播控平台 |
|
||||||
|
| 运营商 | — | IPTV 分发网络运营方(如中国电信、中国移动) |
|
||||||
|
| MA码 | — | 监管身份主键,由广电总局/省局签发(如网络剧片发行许可证号/备案号) |
|
||||||
|
| CTID | Content Twin ID | 内容孪生标识,由 MA码+哈希+版本+Merkle根 构成的唯一标识 |
|
||||||
|
| 文件哈希 | File Hash | SHA-256 算法,比特级敏感,精确锁定某版本文件 |
|
||||||
|
| 感知哈希 | Perceptual Hash | aHash/dHash/pHash,容忍转码压缩,跨格式识别同一内容 |
|
||||||
|
| Merkle Tree | — | 分段聚合哈希树,用于多集/长内容的分段定位 |
|
||||||
|
| 可信数据空间 | — | 基于联盟链/分布式账本的可信身份映射层 |
|
||||||
|
| EPG | Electronic Program Guide | 电子节目指南 |
|
||||||
|
| 转码版哈希 | — | 内容经授权转码中心转码后重新计算的版本哈希 |
|
||||||
|
| 重审 | Reaudit | 内容版本变更后触发的重新审核流程 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 角色定义
|
||||||
|
|
||||||
|
| 角色 | 描述 | 核心职责 |
|
||||||
|
|------|------|----------|
|
||||||
|
| 监管方 | 广电总局 / 省级广电局 | 签发 MA码、注册哈希、验真查询、映射管理、应急下架 |
|
||||||
|
| CP | 内容供应商 | 生产内容、计算哈希、送审申报、注册本方映射 |
|
||||||
|
| 播控平台 | IPTV 集成播控方 | 送审验真、合规审核、转码授权、EPG编排、注册本方映射、执行下架指令 |
|
||||||
|
| 运营商 | IPTV 分发网络方 | CDN注入校验、EPG发布、终端播放、数据上报、注册本方映射、执行下架指令 |
|
||||||
|
| 系统运维方 | TCS-IPTV 运营方 | 维护可信数据空间、智能合约、API网关、监控告警 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 需求列表
|
||||||
|
|
||||||
|
### 需求 1:母版哈希生成(CP端)
|
||||||
|
|
||||||
|
**User Story:** 作为 CP,我希望在内容制作完成后能够在本地对母版文件计算多维哈希值,以便在不上传原始文件的前提下为内容生成可验证的技术指纹。
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. WHEN CP 在母版文件(ProRes/DPX 等格式)上发起哈希计算,THE 哈希计算SDK SHALL 计算该文件的全文件 SHA-256 哈希值。
|
||||||
|
2. WHEN 内容为多集/长内容,THE 哈希计算SDK SHALL 按场景或集数分段计算分段哈希,并生成 Merkle Tree 及其根哈希。
|
||||||
|
3. WHEN CP 发起哈希计算,THE 哈希计算SDK SHALL 计算该内容的感知哈希(aHash/dHash/pHash 之一或组合)。
|
||||||
|
4. THE 哈希计算SDK SHALL 在本地存证哈希值,且 SHALL NOT 上传原始内容文件。
|
||||||
|
5. WHEN 哈希计算完成,THE 哈希计算SDK SHALL 返回包含文件哈希、Merkle根、分段哈希列表、感知哈希的哈希值包。
|
||||||
|
6. IF 母版文件读取失败或格式不受支持,THEN THE 哈希计算SDK SHALL 返回错误信息并标识失败原因。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 需求 2:送审申报与哈希上链(CP端)
|
||||||
|
|
||||||
|
**User Story:** 作为 CP,我希望登录备案系统提交节目信息与哈希值包,以便启动监管审核流程并将哈希存证。
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. WHEN CP 提交送审申报,THE 系统 SHALL 接收节目信息(标题、集数、时长、分辨率)、片花、海报、剧本及哈希值包。
|
||||||
|
2. WHEN 哈希值包提交成功,THE 系统 SHALL 将哈希存证至可信数据空间并返回唯一送审流水号。
|
||||||
|
3. WHEN CP 提交的内容哈希在可信数据空间中已存在,THE 系统 SHALL 拒绝重复申报,并将该申报关联至已存在哈希对应的原 MA码。
|
||||||
|
4. THE 系统 SHALL 仅接收哈希值包,且 SHALL NOT 要求 CP 上传原始内容文件。
|
||||||
|
5. IF 哈希值包格式不完整(缺少文件哈希或 Merkle根),THEN THE 系统 SHALL 拒绝申报并提示缺失字段。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 需求 3:MA码签发与强绑定(监管端)
|
||||||
|
|
||||||
|
**User Story:** 作为监管方,我希望在审核通过后签发 MA码并将其与送审哈希包强绑定,以便建立内容的合法监管身份。
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. WHEN 监管方对送审内容审核通过,THE MA码签发引擎 SHALL 签发 MA码(网络剧片发行许可证号或备案号)。
|
||||||
|
2. WHEN MA码签发,THE 系统 SHALL 将 MA码与送审哈希包以 1:1 关系写入可信数据空间,且该绑定 SHALL NOT 可被解绑。
|
||||||
|
3. THE 系统 SHALL 仅允许监管节点调用 MA码签发功能(issueMA);IF 非监管节点调用,THEN THE 系统 SHALL 拒绝并返回权限错误。
|
||||||
|
4. WHEN MA码签发完成,THE 系统 SHALL 向 CP 发放"MA码+哈希证书"。
|
||||||
|
5. WHILE 内容未取得 MA码及哈希证书,THE 系统 SHALL NOT 允许该内容进入播控平台审核流程。
|
||||||
|
6. WHEN MA码绑定写入,THE 系统 SHALL 记录签发方、签发日期、MA类型、内容标题、集数等内容主表信息。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 需求 4:送审文件验真(播控端)
|
||||||
|
|
||||||
|
**User Story:** 作为播控平台,我希望对 CP 送审的文件计算哈希并与可信数据空间比对,以便确认其为正版过审内容、拦截版本替换。
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. WHEN CP 向播控平台送审(提交 MA码、送审文件、授权链文件),THE 验真模块 SHALL 计算送审文件哈希。
|
||||||
|
2. WHEN 送审文件哈希与可信数据空间中 MA码绑定的哈希匹配,THE 系统 SHALL 确认为正版过审内容并允许进入内容审核流程。
|
||||||
|
3. IF 送审文件哈希与绑定哈希不匹配,THEN THE 系统 SHALL 直接退回该送审,并标记为"疑似版本替换"。
|
||||||
|
4. WHEN 验真执行,THE 系统 SHALL 通过哈希验真接口查询可信数据空间,返回 valid、bound_hash、submitted_hash、match、version 等字段。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 需求 5:内容审核与转码哈希绑定(播控端)
|
||||||
|
|
||||||
|
**User Story:** 作为播控平台,我希望对内容进行合规审核并在转码后为各版本重新生成并绑定哈希,以便多版本分发时保持可信锁定。
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. WHEN 送审文件验真通过,THE 播控平台 SHALL 对内容执行合规审核(政治、色情、暴力等维度)。
|
||||||
|
2. WHEN 内容审核通过且需要转码,THE 系统 SHALL 由授权转码中心执行转码,并在转码后重新计算各版本(如 H.264/H.265/4K/HD/SD)文件哈希。
|
||||||
|
3. WHEN 转码版哈希生成,THE 系统 SHALL 将转码版哈希与 MA码绑定并写入可信数据空间,且 SHALL 与原母版哈希建立父子关系。
|
||||||
|
4. THE 系统 SHALL 允许同一 MA码绑定多个转码版哈希记录,各转码版 SHALL 共享同一 MA码但拥有独立哈希记录。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 需求 6:EPG编排与编码映射(播控端)
|
||||||
|
|
||||||
|
**User Story:** 作为播控平台,我希望在保留自有审核流水号的同时建立其与 MA码、哈希的映射关系,以便对接监管而不改造现有系统。
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. WHEN 内容纳入 EPG,THE 播控平台 SHALL 保留其自有审核流水号。
|
||||||
|
2. WHEN 内容入库,THE 系统 SHALL 在可信数据空间建立"播控流水号 ↔ MA码 ↔ 文件哈希 ↔ 转码版哈希"的映射关系。
|
||||||
|
3. WHEN 播控平台向运营商分发内容,THE 系统 SHALL 要求分发数据携带 MA码及哈希证书;IF 未携带,THEN THE 系统 SHALL 拒绝分发。
|
||||||
|
4. THE 播控平台 SHALL 仅能管理本方(broadcast)的映射记录。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 需求 7:CDN注入校验(运营商端)
|
||||||
|
|
||||||
|
**User Story:** 作为运营商,我希望在内容注入 CDN 前校验其哈希,以便拒绝被篡改或非授权的内容。
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. WHEN 运营商接收播控平台分发的内容并准备注入 CDN,THE 注入校验模块 SHALL 计算注入文件哈希。
|
||||||
|
2. WHEN 注入文件哈希与可信数据空间中 MA码绑定的哈希匹配,THE 系统 SHALL 允许注入 CDN 并生成分发编码。
|
||||||
|
3. IF 注入文件哈希与绑定哈希不匹配,THEN THE 系统 SHALL 拒绝注入,触发告警并退回播控平台,同时暂停该内容分发。
|
||||||
|
4. WHEN 注入成功,THE 系统 SHALL 在可信数据空间注册运营商(operator)映射记录(分发编码、CDN端点)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 需求 8:终端播放哈希抽检(运营商端)
|
||||||
|
|
||||||
|
**User Story:** 作为运营商,我希望播放器在终端可选地对下载片段进行哈希抽检,以便防止 CDN 劫持或传输篡改。
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. WHERE 终端哈希抽检功能开启,WHEN 播放器 SDK(或机顶盒固件)下载内容片段,THE 系统 SHALL 计算该片段哈希并与可信数据空间链上哈希比对。
|
||||||
|
2. IF 终端抽检哈希与链上哈希不匹配,THEN THE 系统 SHALL 断流并切换至备用源,同时上报异常日志。
|
||||||
|
3. THE 终端哈希抽检功能 SHALL 支持按网络负载策略性开启或关闭。
|
||||||
|
4. WHERE 内容为多集,THE 系统 SHALL 支持按集进行增量哈希校验以降低终端计算负载。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 需求 9:统一维度数据上报与聚合
|
||||||
|
|
||||||
|
**User Story:** 作为监管方,我希望三方播放与业务数据以 MA码为统一维度聚合,以便获得口径一致的可信数据。
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. WHEN 运营商上报播出数据,THE 系统 SHALL 以 MA码为统一维度组织数据。
|
||||||
|
2. THE 可信数据空间 SHALL 按 MA码聚合 CP 播放量、播控审核量、运营商分发量,并保证各方数据口径一致。
|
||||||
|
3. WHEN 数据聚合完成,THE 系统 SHALL 提供按 MA码查询的统一数据视图。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 需求 10:全生命周期监管查询(监管端)
|
||||||
|
|
||||||
|
**User Story:** 作为监管方,我希望通过监管大屏按 MA码查询内容全链路状态,以便实现精准溯源。
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. WHEN 监管方按 MA码查询,THE 监管大屏 SHALL 返回内容当前所在播控平台、当前所在运营商 CDN、当前哈希版本是否最新。
|
||||||
|
2. WHEN 监管方查询内容历史,THE 系统 SHALL 返回该 MA码的历史版本变更记录。
|
||||||
|
3. THE 监管大屏 SHALL 支持监管方按 MA码穿透查询三方系统的对应编码。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 需求 11:违规应急下架(监管端)
|
||||||
|
|
||||||
|
**User Story:** 作为监管方,我希望下发单一 MA码下架指令即可触发全网下架,以便实现秒级应急响应而无需逐层人工翻译。
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. WHEN 监管方下发"下架 MA码 第XXX号"指令,THE 系统 SHALL 解析该 MA码并查询其绑定的所有三方编码及 CDN端点。
|
||||||
|
2. WHEN 下架指令解析完成,THE 系统 SHALL 自动将指令翻译为播控平台下架(审核流水号)与运营商下架(分发编码、CDN资源)的执行动作。
|
||||||
|
3. THE 系统 SHALL 在接收下架指令后秒级同步至全网三方系统,且 SHALL NOT 要求人工逐层翻译。
|
||||||
|
4. THE 系统 SHALL 仅允许监管方下发应急下架指令;播控平台与运营商 SHALL 仅执行指令而无下架发起权限。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 需求 12:版本变更与重审触发
|
||||||
|
|
||||||
|
**User Story:** 作为系统,我希望在内容发生帧级变动时自动断开绑定并触发重审,以便保证审播一致。
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. WHEN 内容发生任意帧级变动导致哈希变化,THE 系统 SHALL 判定原 MA码与哈希的绑定断裂。
|
||||||
|
2. WHEN 绑定断裂,THE 系统 SHALL 在版本变更表中记录变更原因、原哈希、新哈希,并将 reaudit_required 置为 true。
|
||||||
|
3. WHEN 单集内容被替换,THE 系统 SHALL 通过 Merkle Tree 重新计算该集哈希并定位被篡改的具体集数,且 SHALL NOT 要求全量重审。
|
||||||
|
4. WHILE 重审未通过,THE 系统 SHALL NOT 允许变更后的内容进入分发流程。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 需求 13:跨省复用快速准入
|
||||||
|
|
||||||
|
**User Story:** 作为 CP,我希望在一省过审后凭 MA码+哈希证书在其他省份快速准入,以便降低跨省复用的边际成本。
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. WHEN CP 持 A省签发的 MA码+哈希证书向 B省播控平台送审,THE 系统 SHALL 仅要求提交 MA码与哈希证书,且 SHALL NOT 要求重新提交内容文件。
|
||||||
|
2. WHEN B省播控平台发起准入查询,THE 系统 SHALL 验证 MA码真实有效、哈希与原过审版一致、且内容不在黑名单中。
|
||||||
|
3. WHEN 三重校验通过,THE 系统 SHALL 允许 B省播控平台快速准入,并将内容审核简化为合规性抽检。
|
||||||
|
4. WHEN B省准入完成,THE 系统 SHALL 生成 B省审核流水号并注册对应映射关系。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 需求 14:角色权限控制
|
||||||
|
|
||||||
|
**User Story:** 作为系统,我希望按角色矩阵严格控制各项操作权限,以便保证监管主键的权威性与不可越权。
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. THE 系统 SHALL 仅允许监管方(广电总局/省局)执行签发 MA码、注册哈希、验真查询、映射管理、应急下架全部操作。
|
||||||
|
2. THE 系统 SHALL 允许播控平台执行验真查询、本方映射管理、执行下架指令;且 SHALL NOT 允许其签发 MA码、注册哈希、发起下架。
|
||||||
|
3. THE 系统 SHALL 允许运营商执行验真查询、本方映射管理、执行下架指令;且 SHALL NOT 允许其签发 MA码、注册哈希、发起下架。
|
||||||
|
4. THE 系统 SHALL 允许 CP 在送审时注册哈希、执行自查验真、管理本方映射;且 SHALL NOT 允许其签发 MA码或发起下架。
|
||||||
|
5. WHEN 任意角色尝试越权操作,THE 系统 SHALL 拒绝该操作并返回权限错误。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 需求 15:异常处理
|
||||||
|
|
||||||
|
**User Story:** 作为系统,我希望对各类哈希校验异常采取明确的处理规则,以便保证流程的可控与可追溯。
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. IF 送审阶段哈希不匹配,THEN THE 系统 SHALL 退回 CP,要求说明版本差异,必要时要求重新送审。
|
||||||
|
2. IF CDN注入阶段哈希不匹配,THEN THE 系统 SHALL 拒绝注入、告警播控平台并暂停该内容分发。
|
||||||
|
3. IF 终端抽检阶段哈希不匹配,THEN THE 系统 SHALL 断流、切换备用源并上报异常日志。
|
||||||
|
4. WHEN 内容发生剪辑/修改,THE 系统 SHALL 要求重新计算哈希、提交变更申请并触发重新审核。
|
||||||
|
5. WHEN CP 以同一哈希换壳重发,THE 系统 SHALL 识别哈希已存在并拒绝重复申报,同时关联原 MA码。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 需求 16:可信数据空间存证与智能合约
|
||||||
|
|
||||||
|
**User Story:** 作为系统,我希望通过联盟链与智能合约管理 MA码、哈希与映射的存证,以便保证数据不可篡改与可信。
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. THE 可信数据空间 SHALL 维护内容主表、哈希绑定表、三方编码映射表、版本变更表四类核心数据结构。
|
||||||
|
2. THE 智能合约 SHALL 提供 issueMA(签发)、registerMapping(注册映射)、verifyHash(哈希校验)核心方法。
|
||||||
|
3. WHEN registerMapping 被调用,IF 对应 MA码尚未签发,THEN THE 系统 SHALL 拒绝注册映射。
|
||||||
|
4. THE 系统 SHALL 通过 Merkle Tree 存储多集内容的分段哈希,并支持按集定位篡改。
|
||||||
|
5. THE 可信数据空间 SHALL 保证已写入的 MA码与哈希绑定记录不可篡改。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 需求 17:接口规范
|
||||||
|
|
||||||
|
**User Story:** 作为三方系统集成方,我希望通过标准化 API 与可信数据空间交互,以便低成本对接。
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. THE 系统 SHALL 提供哈希上链接口(POST /api/v1/content/register),供 CP 提交标题、集数、各集文件哈希、Merkle根、感知哈希、时长、分辨率、CP媒资ID,并返回送审流水号与状态。
|
||||||
|
2. THE 系统 SHALL 提供哈希验真接口(GET /api/v1/content/verify),供播控/运营商按 MA码与文件哈希查询并返回 valid、bound_hash、submitted_hash、match、version、转码版列表。
|
||||||
|
3. THE 系统 SHALL 提供映射查询接口(GET /api/v1/content/mappings),供应急下架按 MA码查询三方编码映射与 CDN端点。
|
||||||
|
4. THE 系统 SHALL 对接口调用进行身份鉴权(如 Bearer Token)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 非功能性需求
|
||||||
|
|
||||||
|
### 需求 18:性能与时效
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. THE 系统 SHALL 将违规内容下架响应时间从现状的 2-24 小时缩短至分钟级。
|
||||||
|
2. THE 系统 SHALL 将跨省复用审核周期从现状的 15-30 天缩短至 3-5 天。
|
||||||
|
3. THE 系统 SHALL 将三方数据对账差异从现状的 15-30% 降低至 5% 以内。
|
||||||
|
4. THE 系统 SHALL 实现内容版本替换的 100% 自动识别。
|
||||||
|
|
||||||
|
### 需求 19:兼容性与最小侵入
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. THE 系统 SHALL NOT 要求三方放弃其自有编码体系。
|
||||||
|
2. THE 系统 SHALL 仅在送审、入库、分发、播放等关键节点嵌入校验,并通过映射层对接三方现有系统。
|
||||||
|
3. THE 系统 SHALL 完全符合广电总局网络剧片发行许可及备案制度。
|
||||||
|
4. THE 系统 SHALL 支持网络剧、微短剧、网络电影、网络动画等多形态内容,并 SHALL 可扩展至 OTT、手机 APP 等大小屏形态。
|
||||||
|
|
||||||
|
### 需求 20:安全与可信
|
||||||
|
|
||||||
|
#### 验收标准
|
||||||
|
|
||||||
|
1. THE 系统 SHALL 保证 MA码与哈希的绑定记录一经写入不可篡改、不可解绑。
|
||||||
|
2. THE 系统 SHALL 保证哈希计算在 CP 本地完成,原始内容文件 SHALL NOT 上传至可信数据空间。
|
||||||
|
3. THE 系统 SHALL 对所有关键操作(签发、注册、验真、下架)进行链上存证以支持审计。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 关键约束与假设
|
||||||
|
|
||||||
|
| 类别 | 内容 |
|
||||||
|
|------|------|
|
||||||
|
| 约束 | 不替代三方现有系统,仅建立"可信身份映射层" |
|
||||||
|
| 约束 | MA码签发权与应急下架发起权仅归监管方 |
|
||||||
|
| 约束 | MA码与哈希 1:1 强绑定,不可解绑 |
|
||||||
|
| 假设 | 三方系统具备在关键节点集成哈希计算SDK与API调用的能力 |
|
||||||
|
| 假设 | 广电总局备案系统可对接 MA码签发与哈希绑定 |
|
||||||
|
| 依赖 | 联盟链/分布式账本基础设施可用 |
|
||||||
|
| 依赖 | 授权转码中心具备转码后哈希重算与上链能力 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> 本需求文档作为 TCS-IPTV 系统设计与实现的依据,后续设计文档与任务分解将基于本文档展开。
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
# AIGC-Hub 智视码(AVCC) 技术实现方案
|
||||||
|
|
||||||
|
> 版本:V1.0
|
||||||
|
> 编制日期:2026年6月
|
||||||
|
> 基于文档:《AIGC-Hub智视码(AVCC)体系建设方案 V2.0(MA融合修订版)》
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 方案概述
|
||||||
|
|
||||||
|
本技术实现方案将 AIGC-Hub 智视码(AVCC)体系建设方案从顶层设计落实到具体可执行的技术架构、系统模块、数据模型、API 接口与部署运维方案。方案遵循以下核心原则:
|
||||||
|
|
||||||
|
- **等保三级合规**:所有系统组件满足网络安全等级保护三级要求
|
||||||
|
- **云原生设计**:基于容器化与微服务架构,支持弹性扩缩容
|
||||||
|
- **MA 标准兼容**:编码、解析、数据交换全流程遵循 ISO/IEC 15459
|
||||||
|
- **开放接入**:通过标准化 RESTful API 与 SDK 支持多方低门槛接入
|
||||||
|
|
||||||
|
## 文档目录
|
||||||
|
|
||||||
|
| 章节 | 文件名 | 内容 |
|
||||||
|
|------|--------|------|
|
||||||
|
| 概要 | `00-技术实现方案-概要.md` | 方案概述与文档目录(本文件) |
|
||||||
|
| 第一章 | `01-总体技术架构.md` | 总体架构图(文字描述)、技术栈选型表 |
|
||||||
|
| 第二章 | `02-核心系统模块设计.md` | 赋码引擎、审核引擎、版权链引擎、MA编码网关、C2PA SDK、创作者工作台、清算引擎 |
|
||||||
|
| 第三章 | `03-数据库与数据模型.md` | PostgreSQL 核心表结构、Redis 缓存设计、ClickHouse 分析表 |
|
||||||
|
| 第四章 | `04-API接口设计.md` | 统一接口规范、赋码/审核/网关/版权链/清算 API 详细设计 |
|
||||||
|
| 第五章 | `05-部署与运维架构.md` | Kubernetes 部署拓扑、资源预估、安全域、监控告警体系 |
|
||||||
|
| 第六章 | `06-安全设计.md` | 等保三级落实、数据加密、隐私计算、审计日志 |
|
||||||
|
| 第七章 | `07-分阶段实施路线图.md` | 一期/二期/三期技术任务分解、里程碑、资源投入 |
|
||||||
|
| 第八章 | `08-核心业务时序图与状态机.md` | 赋码/跨平台解析/分账时序图,审核/流通状态机流转 |
|
||||||
|
| 第九章 | `09-异步消息流转设计.md` | Kafka Topic 规划、事件 Payload Schema、失败重试与 DLQ |
|
||||||
|
| 第十章 | `10-C2PA与第三方对接详细设计.md` | SDK 嵌入逻辑、ZIIOT 根解析同步机制、联盟链异步监听 |
|
||||||
|
| 汇总索引 | `99-技术实现方案-汇总索引.md` | 全方案快速索引与术语对照表 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 核心架构速览(MA 根节点+1+3+N)
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 监管层(广电总局/省级广电) │
|
||||||
|
│ 监管大屏 │ 终审工作台 │ 黑名单管理 │ 数据抽查 │
|
||||||
|
└──────────────────────────────┬────────────────────────────────────────┘
|
||||||
|
│ 数据回传 / 指令下发
|
||||||
|
┌──────────────────────────────▼────────────────────────────────────────┐
|
||||||
|
│ 广电云 AIGC-Hub 运营层 │
|
||||||
|
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
|
||||||
|
│ │ 赋码引擎 │ │ 审核引擎 │ │ 版权链引擎 │ │ 清算引擎 │ │
|
||||||
|
│ │ (Code Svc) │ │ (Review Svc)│ │ (Chain Svc)│ │(Settlement)│ │
|
||||||
|
│ └────────────┘ └────────────┘ └────────────┘ └────────────┘ │
|
||||||
|
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
|
||||||
|
│ │ MA 编码网关 │ │ C2PA SDK │ │ 创作者工作台│ │
|
||||||
|
│ │ (Gateway) │ │ (Embed/Verify)│ │ (Workbench)│ │
|
||||||
|
│ └────────────┘ └────────────┘ └────────────┘ │
|
||||||
|
└──────────────────────────────┬────────────────────────────────────────┘
|
||||||
|
│ MA 根解析 / 码资源分配
|
||||||
|
┌──────────────────────────────▼────────────────────────────────────────┐
|
||||||
|
│ ZIIOT MA 全球根节点体系 │
|
||||||
|
│ MA 根解析服务 │ 全球码资源管理 │ 国际标准对接 │
|
||||||
|
└───────────────────────────────────────────────────────────────────────┘
|
||||||
|
│
|
||||||
|
┌──────────────────────────────┴────────────────────────────────────────┐
|
||||||
|
│ N 个接入方(应用层) │
|
||||||
|
│ 长视频平台 │ 短视频平台 │ AI 工具厂商 │ MCN 机构 │ 创作者 │
|
||||||
|
└─────────────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## 关键技术栈速查
|
||||||
|
|
||||||
|
| 层级 | 选型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| 网关层 | Kong / APISIX | 流量控制、鉴权、限流 |
|
||||||
|
| 前端 | React 18 + Ant Design | 工作台、监管大屏 |
|
||||||
|
| 高并发网关/赋码/清算 | Go 1.22 + Gin | 网关、赋码引擎、清算引擎 |
|
||||||
|
| 业务编排/AI管道 | Python 3.11 + FastAPI | 工作台、审核调度、链交互 |
|
||||||
|
| 底层媒体处理 | Rust (c2pa-rs) | C2PA SDK、视频指纹提取 |
|
||||||
|
| 区块链服务 | Go 1.22 + Fabric SDK | 联盟链交互 |
|
||||||
|
| 关系数据库 | PostgreSQL 16 | JSONB 支持灵活 schema |
|
||||||
|
| 缓存 | Redis Cluster 7.x | 会话、限流、热点数据 |
|
||||||
|
| 时序分析 | ClickHouse 24.x | 播放数据、运营分析 |
|
||||||
|
| 消息队列 | Apache Kafka 3.x | 审核任务、链上事件 |
|
||||||
|
| 对象存储 | MinIO / 广电云对象存储 | C2PA 水印、视频指纹 |
|
||||||
|
| AI 推理 | Triton + PyTorch 2.x | GPU 推理服务化 |
|
||||||
|
| 底层链 | 长安链 / Hyperledger Fabric 2.5 | 国密、联盟链 |
|
||||||
|
| 容器编排 | Kubernetes 1.29 | 微服务编排 |
|
||||||
|
| 监控 | Prometheus + Grafana + ELK | 可观测性体系 |
|
||||||
|
| CI/CD | GitLab CI + ArgoCD | 自动化交付 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*各章节详细内容请查阅对应文件。*
|
||||||
@@ -0,0 +1,218 @@
|
|||||||
|
# 第一章 总体技术架构
|
||||||
|
|
||||||
|
> 版本:V1.0
|
||||||
|
> 基于文档:《AIGC-Hub智视码(AVCC)体系建设方案 V2.0》
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1.1 架构设计原则
|
||||||
|
|
||||||
|
| 原则 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| **等保三级合规** | 所有系统组件部署于广电云等保三级 VPC 内,满足网络安全等级保护三级要求 |
|
||||||
|
| **云原生设计** | 基于容器化与微服务架构,支持水平扩展、滚动更新、故障自愈 |
|
||||||
|
| **MA 标准兼容** | 编码、解析、数据交换全流程遵循 ISO/IEC 15459 及 MA 标识体系规范 |
|
||||||
|
| **开放接入** | 通过标准化 RESTful API 与多语言 SDK,支持平台、工具方、创作者低门槛接入 |
|
||||||
|
| **数据主权** | 敏感数据不出境,版权链采用国密算法,MA 根解析通过境内节点完成 |
|
||||||
|
| **可观测性** | 全链路日志、指标、追踪,支撑监管审计与故障定位 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1.2 总体架构图(文字描述)
|
||||||
|
|
||||||
|
AIGC-Hub 采用 **MA 根节点 + 1 + 3 + N** 总体架构,以四层体系实现监管、运营、应用的全链路贯通。
|
||||||
|
|
||||||
|
### 第一层:监管层
|
||||||
|
|
||||||
|
- **责任主体**:国家广播电视总局 / 省级广电主管部门
|
||||||
|
- **技术对接**:通过数据回传通道接收平台自审记录、播放数据、处置记录;通过终审工作台处理重点内容(AVCC-P)终审;通过黑名单管理模块实施全网封禁指令下发
|
||||||
|
- **部署形态**:监管大屏部署于广电总局内部专网,与广电云 AIGC-Hub 通过安全数据交换网关对接
|
||||||
|
|
||||||
|
### 第二层:运营层(广电云 AIGC-Hub)
|
||||||
|
|
||||||
|
广电云作为唯一建设和运营主体,同时承担 **MA.AIGC 视听内容行业节点** 运营职责。运营层包含七大核心引擎/系统:
|
||||||
|
|
||||||
|
| 系统/引擎 | 职责 |
|
||||||
|
|-----------|------|
|
||||||
|
| **赋码引擎** | 接收赋码申请,执行预检,按 MA 标准生成六段式 AVCC,码资源分配与回收 |
|
||||||
|
| **审核引擎** | 多模态 AI 合规检测(画面/台词/声音/AIGC 真实性),输出分级建议与详细预审报告 |
|
||||||
|
| **版权链引擎** | 基于联盟链的版权存证、用户权益子链、智能合约分账清算 |
|
||||||
|
| **清算引擎** | 跨平台权益通兑验证、分账结算、版权估值报告、金融衍生服务支撑 |
|
||||||
|
| **MA 编码网关** | 对外统一 AVCC 解析与流通权限识别,对接 ZIIOT MA 全球根解析 |
|
||||||
|
| **C2PA SDK** | 嵌入/验证 C2PA 内容凭证,含 MA 标识片段、模型版本、训练数据授权摘要 |
|
||||||
|
| **创作者工作台** | 一站式 SaaS:赋码申请、版权登记、分账查询、审核报告、多平台聚合 |
|
||||||
|
|
||||||
|
### 第三层:MA 根节点层(ZIIOT)
|
||||||
|
|
||||||
|
- **MA 全球根节点**:ZIIOT 运营,负责全球码资源分配、根解析服务、国际标准对接
|
||||||
|
- **一级节点(国家地域节点)**:`MA.156` 中国节点
|
||||||
|
- **二级节点(行业节点)**:`MA.156.10005` 拟申请的 AIGC 视听内容行业节点,由广电云运营
|
||||||
|
- **三级节点及以下**:各长视频/短视频平台、AI 工具厂商、MCN 机构
|
||||||
|
|
||||||
|
### 第四层:应用层(N 个接入方)
|
||||||
|
|
||||||
|
- 长视频平台(爱奇艺、腾讯视频、优酷等)
|
||||||
|
- 短视频平台(抖音、快手、小红书等)
|
||||||
|
- AI 工具厂商(绘画/视频生成工具)
|
||||||
|
- MCN 机构、版权方、创作者个体
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1.3 技术栈选型详表
|
||||||
|
|
||||||
|
### 1.3.1 接入与网关层
|
||||||
|
|
||||||
|
| 组件 | 选型 | 版本 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| API 网关 | Kong / Apache APISIX | 最新稳定版 | 流量控制、鉴权、限流、日志、灰度发布 |
|
||||||
|
| 负载均衡 | Nginx Ingress Controller | 1.9+ | K8s Ingress 层负载均衡与 TLS 终止 |
|
||||||
|
| CDN | 广电云 CDN / 自建 CDN | — | 静态资源、AVCC 证书二维码、C2PA 水印分发 |
|
||||||
|
|
||||||
|
### 1.3.2 前端层
|
||||||
|
|
||||||
|
| 组件 | 选型 | 版本 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| 管理后台框架 | React | 18.x | 监管大屏、运营后台、创作者工作台 |
|
||||||
|
| UI 组件库 | Ant Design | 5.x | 企业级中后台组件 |
|
||||||
|
| 状态管理 | Zustand / Redux Toolkit | 最新版 | 全局状态管理 |
|
||||||
|
| 图表可视化 | ECharts / AntV G2Plot | 5.x / 2.x | 监管数据可视化、审核趋势图 |
|
||||||
|
| 移动端 | React Native / 小程序 | — | 创作者移动端赋码查询、扫码验真 |
|
||||||
|
|
||||||
|
### 1.3.3 后端服务层(混合语言架构)
|
||||||
|
|
||||||
|
采用按场景选型的混合语言策略:**Go 负责高并发网关与计算密集型服务,Python 负责业务编排与 AI 管道,Rust 负责底层媒体处理**。
|
||||||
|
|
||||||
|
| 服务/组件 | 语言 | 框架/库 | 版本 | 说明 |
|
||||||
|
|----------|------|---------|------|------|
|
||||||
|
| **高并发网关服务** | Go | Gin / Echo | 1.22+ | MA 编码网关、API 网关核心业务,单机万级 QPS |
|
||||||
|
| **赋码引擎** | Go | Gin + GORM | 1.22+ | 编码规则计算、码资源分配,性能敏感 |
|
||||||
|
| **清算引擎** | Go | Gin + GORM | 1.22+ | 实时分账对账、数值计算,低延迟要求 |
|
||||||
|
| **业务服务层** | Python | FastAPI + SQLAlchemy | 3.11+ / 0.110+ | 创作者工作台 API、审核任务编排、版权链交互 |
|
||||||
|
| **审核任务调度** | Python | FastAPI + Celery | 3.11+ | 审核任务分发、结果聚合、报告生成 |
|
||||||
|
| **区块链服务** | Go | ChainMaker SDK / Fabric SDK | 1.22+ / 2.5+ | 联盟链节点高性能交互,国密支持 |
|
||||||
|
| **C2PA SDK 核心** | Rust | c2pa-rs | 最新版 | C2PA 标准实现,提供 Python/JS/Go 绑定 |
|
||||||
|
| **视频指纹提取** | Rust / Go | FFmpeg + 自研 | — | 大文件处理,Rust/Go 性能优于 Python |
|
||||||
|
| **文档生成** | Python | WeasyPrint / ReportLab | 最新版 | AVCC 证书 PDF、审核报告 PDF 生成 |
|
||||||
|
| **AI 管道编排** | Python | FastAPI + Triton Client | 3.11+ | 调用 Triton 推理、结果融合 |
|
||||||
|
|
||||||
|
### 1.3.4 数据存储层
|
||||||
|
|
||||||
|
| 组件 | 选型 | 版本 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| 关系型数据库 | PostgreSQL | 16.x | 主业务数据,JSONB 支持灵活 schema 扩展 |
|
||||||
|
| 数据库高可用 | Patroni + etcd | 最新版 | 自动故障切换、读写分离 |
|
||||||
|
| 缓存 | Redis Cluster | 7.x | 会话、热点数据、限流计数、分布式锁 |
|
||||||
|
| 时序/分析数据库 | ClickHouse | 24.x | 播放数据、审核日志、运营分析 |
|
||||||
|
| 对象存储 | MinIO / 广电云对象存储 | 最新版 | C2PA 水印文件、视频指纹、证据包 |
|
||||||
|
| 搜索引擎 | Elasticsearch | 8.x | 审核报告全文检索、日志检索 |
|
||||||
|
| 向量数据库 | Milvus / pgvector | 最新版 | 视频指纹相似度检索、版权比对 |
|
||||||
|
|
||||||
|
### 1.3.5 消息与异步层
|
||||||
|
|
||||||
|
| 组件 | 选型 | 版本 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| 消息队列 | Apache Kafka | 3.x | 审核任务分发、链上事件、数据回传 |
|
||||||
|
| 流处理 | Kafka Streams / Flink | 最新版 | 实时播放数据统计、异常检测 |
|
||||||
|
| 任务队列 | Celery + Redis / RabbitMQ | 最新版 | 异步任务(邮件通知、PDF 生成) |
|
||||||
|
| 调度器 | APScheduler / Airflow | 最新版 | 定时清算、数据报表生成 |
|
||||||
|
|
||||||
|
### 1.3.6 AI 推理层
|
||||||
|
|
||||||
|
| 组件 | 选型 | 版本 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| 推理服务框架 | NVIDIA Triton Inference Server | 2.x | GPU 模型服务化、动态批处理、多框架支持 |
|
||||||
|
| 深度学习框架 | PyTorch | 2.x | 审核模型训练与推理 |
|
||||||
|
| 计算机视觉 | OpenMMLab 系列 (MMPretrain, MMAction2) | 最新版 | 画面合规检测、深度伪造检测 |
|
||||||
|
| 自然语言处理 | transformers (Hugging Face) | 最新版 | 台词敏感词检测、语境分析 |
|
||||||
|
| 音频处理 | librosa / torchaudio | 最新版 | 音频合规检测、音乐指纹提取 |
|
||||||
|
| 模型仓库 | MLflow / DVC | 最新版 | 模型版本管理、实验追踪 |
|
||||||
|
|
||||||
|
### 1.3.7 区块链层
|
||||||
|
|
||||||
|
| 组件 | 选型 | 版本 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| 底层链 | 长安链 (ChainMaker) | 2.x | 国密支持、联盟链、可控权限、性能优异 |
|
||||||
|
| 备选 | Hyperledger Fabric | 2.5+ | 成熟稳定,文档丰富 |
|
||||||
|
| 智能合约 | Go (ChainMaker) / Go/Java (Fabric) | — | 版权存证合约、分账合约、用户权益合约 |
|
||||||
|
| 链上浏览器 | ChainMaker Explorer / Hyperledger Explorer | 最新版 | 交易查询、区块浏览 |
|
||||||
|
| 钱包/密钥 | HSM (硬件安全模块) | — | 核心密钥离线存储,满足等保三级要求 |
|
||||||
|
|
||||||
|
### 1.3.8 基础设施层
|
||||||
|
|
||||||
|
| 组件 | 选型 | 版本 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| 容器编排 | Kubernetes | 1.29+ | 容器编排、服务发现、自动扩缩容 |
|
||||||
|
| 服务网格 | Istio (可选) | 最新版 | 服务间流量管理、安全通信、可观测性 |
|
||||||
|
| 镜像仓库 | Harbor | 2.x | 私有镜像仓库、镜像安全扫描 |
|
||||||
|
| 密钥管理 | HashiCorp Vault | 最新版 | 敏感配置、API Key、数据库密码动态管理 |
|
||||||
|
| 服务注册 | etcd (K8s 内置) | — | 服务发现与配置存储 |
|
||||||
|
|
||||||
|
### 1.3.9 可观测性与 DevOps
|
||||||
|
|
||||||
|
| 组件 | 选型 | 版本 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| 指标监控 | Prometheus | 最新版 | 指标采集、告警规则 |
|
||||||
|
| 可视化 | Grafana | 10.x | 监控大盘、运营报表 |
|
||||||
|
| 日志采集 | ELK Stack (Elasticsearch + Logstash + Kibana) / Loki | 8.x / 最新版 | 全链路日志聚合与检索 |
|
||||||
|
| 链路追踪 | Jaeger / OpenTelemetry | 最新版 | 分布式请求链路追踪 |
|
||||||
|
| CI/CD | GitLab CI | 最新版 | 自动化构建、测试 |
|
||||||
|
| GitOps | ArgoCD | 最新版 | K8s 声明式持续交付、自动回滚 |
|
||||||
|
| 制品管理 | Nexus / Artifactory | 最新版 | Maven/NPM/Docker 制品仓库 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1.4 系统间交互关系
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
||||||
|
│ 创作者工作台 │────→│ 赋码引擎 │────→│ 审核引擎 │
|
||||||
|
│ (Workbench) │ │ (Code Svc) │ │(Review Svc) │
|
||||||
|
└─────────────┘ └──────┬──────┘ └──────┬──────┘
|
||||||
|
│ │
|
||||||
|
↓ ↓
|
||||||
|
┌─────────────┐ ┌─────────────┐
|
||||||
|
│ MA 编码网关 │←────│ 版权链引擎 │
|
||||||
|
│ (Gateway) │ │(Chain Svc) │
|
||||||
|
└──────┬──────┘ └──────┬──────┘
|
||||||
|
│ │
|
||||||
|
↓ ↓
|
||||||
|
┌─────────────┐ ┌─────────────┐
|
||||||
|
│ ZIIOT MA 根 │ │ 联盟链节点 │
|
||||||
|
│ 解析服务 │ │(ChainMaker) │
|
||||||
|
└─────────────┘ └─────────────┘
|
||||||
|
↑ ↑
|
||||||
|
┌─────────────┐ ┌─────────────┐
|
||||||
|
│ 接入平台 │←────│ 清算引擎 │
|
||||||
|
│ (Platform) │ │(Settlement) │
|
||||||
|
└─────────────┘ └─────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 关键交互说明
|
||||||
|
|
||||||
|
1. **创作者 → 赋码引擎**:通过工作台提交作品与版权材料,触发赋码流程
|
||||||
|
2. **赋码引擎 → 审核引擎**:材料预检通过后,自动创建审核任务
|
||||||
|
3. **审核引擎 → 版权链引擎**:审核完成后,将审核报告哈希、分级结果上链存证
|
||||||
|
4. **版权链引擎 → 赋码引擎**:存证完成后,触发 AVCC 编码生成与码资源分配
|
||||||
|
5. **赋码引擎 → MA 编码网关**:新生成的 AVCC 注册到网关缓存与 MA 解析系统
|
||||||
|
6. **接入平台 → MA 编码网关**:平台在内容上线前调用网关解析 AVCC,校验流通权限
|
||||||
|
7. **接入平台 → 版权链引擎**:平台回传播放数据,触发智能合约分账结算
|
||||||
|
8. **清算引擎 → 版权链引擎**:定时执行链上清算,将收益按智能合约比例分配
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1.5 数据流总览
|
||||||
|
|
||||||
|
| 数据类型 | 流向 | 传输方式 | 存储位置 |
|
||||||
|
|----------|------|----------|----------|
|
||||||
|
| 作品内容(视频) | 创作者 → 对象存储 | HTTPS + 分片上传 | MinIO(加密存储) |
|
||||||
|
| 赋码申请元数据 | 创作者 → 赋码引擎 | REST API | PostgreSQL |
|
||||||
|
| 审核任务 | 赋码引擎 → 审核引擎 | Kafka | Kafka + PostgreSQL |
|
||||||
|
| 审核报告 | 审核引擎 → 版权链引擎 | REST API + Kafka | PostgreSQL + 联盟链 |
|
||||||
|
| AVCC 编码 | 赋码引擎 → MA 网关 | 内部 RPC | PostgreSQL + Redis |
|
||||||
|
| 播放数据 | 平台 → 数据回传服务 | REST API + Kafka | ClickHouse |
|
||||||
|
| 分账结算 | 清算引擎 → 版权链引擎 | 智能合约调用 | 联盟链 |
|
||||||
|
| 监管数据 | 数据回传服务 → 监管大屏 | 安全数据交换网关 | 广电总局专网 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*下一章:[02-核心系统模块设计.md](02-核心系统模块设计.md)*
|
||||||
@@ -0,0 +1,639 @@
|
|||||||
|
# 第二章 核心系统模块设计
|
||||||
|
|
||||||
|
> 版本:V1.0
|
||||||
|
> 基于文档:《AIGC-Hub智视码(AVCC)体系建设方案 V2.0》
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2.1 赋码引擎(Code Issuance Engine)
|
||||||
|
|
||||||
|
### 2.1.1 职责边界
|
||||||
|
|
||||||
|
- 接收创作者的赋码申请,执行四步预检:重复检测、黑名单模型检测、版权材料完整性检测、MA 标识片段合规性检测。
|
||||||
|
- 对接 MA 行业节点(广电云)码资源池,按审核结果分配对应 AVCC 编码。
|
||||||
|
- 生成 AVCC 完整六段式编码并返回,同时将编码生成记录上链存证。
|
||||||
|
- 管理码全生命周期:有效、注销、冻结、迭代版本。
|
||||||
|
|
||||||
|
### 2.1.2 AVCC 编码生成逻辑
|
||||||
|
|
||||||
|
```go
|
||||||
|
// 伪代码:AVCC 六段式编码生成引擎(Go 实现)
|
||||||
|
func GenerateAVCC(
|
||||||
|
platformNode string, // 平台/机构节点代码,如 "8361"
|
||||||
|
objectCategory string, // 对象类目,如 "10.1300200.AIGC"
|
||||||
|
licenseNo string, // 网标号,如 "(京)网微剧审字(2026)第001号"
|
||||||
|
reviewLevel string, // 类别段:P(重点) / G(普通) / O(其他)
|
||||||
|
aiHash string, // AI 生成内容哈希值
|
||||||
|
copyrightCRD string, // 版权链存证地址
|
||||||
|
version int, // 迭代版本号
|
||||||
|
) string {
|
||||||
|
/*
|
||||||
|
AVCC(MA 融合版)= [MA 根] + [国家/行业节点] + [监管段] + [类别段] + [技术段] + [版权段]
|
||||||
|
完整示例:
|
||||||
|
MA.156.10005.8361/10.1300200.AIGC/(京)网微剧审字(2026)第001号-P-AI-HASH(a1b2c3)-CRD(0x7f3e9a)
|
||||||
|
*/
|
||||||
|
maRoot := "MA"
|
||||||
|
country := "156"
|
||||||
|
industryNode := "10005" // 拟申请的 AIGC 视听内容行业节点
|
||||||
|
|
||||||
|
avcc := fmt.Sprintf("%s.%s.%s.%s/%s/%s-%s-AI-HASH(%s)-CRD(%s)",
|
||||||
|
maRoot, country, industryNode, platformNode,
|
||||||
|
objectCategory, licenseNo, reviewLevel, aiHash, copyrightCRD)
|
||||||
|
|
||||||
|
if version > 1 {
|
||||||
|
avcc = strings.Replace(avcc, fmt.Sprintf("AI-HASH(%s)", aiHash),
|
||||||
|
fmt.Sprintf("v%d-AI-HASH(%s)", version, aiHash), 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return avcc
|
||||||
|
}
|
||||||
|
|
||||||
|
// 编码解析
|
||||||
|
func ParseAVCC(avcc string) (map[string]interface{}, error) {
|
||||||
|
// 将 AVCC 字符串解析为结构化字典
|
||||||
|
pattern := `^(MA)\.(\d{3})\.(\d+)\.(\d+)/(\S+)/(\S+)-(P|G|O)-(v\d+)?-?AI-HASH\((\w+)\)-CRD\((\w+)\)$`
|
||||||
|
re := regexp.MustCompile(pattern)
|
||||||
|
match := re.FindStringSubmatch(avcc)
|
||||||
|
|
||||||
|
if match == nil {
|
||||||
|
return nil, errors.New("Invalid AVCC format")
|
||||||
|
}
|
||||||
|
|
||||||
|
version := 1
|
||||||
|
if match[8] != "" {
|
||||||
|
version, _ = strconv.Atoi(strings.ReplaceAll(match[8], "v", ""))
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]interface{}{
|
||||||
|
"ma_root": match[1],
|
||||||
|
"country_code": match[2],
|
||||||
|
"industry_node": match[3],
|
||||||
|
"platform_node": match[4],
|
||||||
|
"object_category": match[5],
|
||||||
|
"license_no": match[6],
|
||||||
|
"review_level": match[7],
|
||||||
|
"version": version,
|
||||||
|
"ai_hash": match[9],
|
||||||
|
"copyright_crd": match[10],
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.1.3 服务拆分与子服务职责
|
||||||
|
|
||||||
|
| 子服务 | 职责 | 关键技术 |
|
||||||
|
|--------|------|----------|
|
||||||
|
| `code-pre-check` | 接收申请,执行重复性、黑名单、材料完整性预检 | 视频指纹比对( perceptual hash)、黑名单缓存查询 |
|
||||||
|
| `code-generator` | 编码规则引擎,按 MA 标准生成六段式 AVCC | 规则引擎、编码模板、版本控制 |
|
||||||
|
| `code-allocator` | 对接 MA 码资源池,管理码段分配与回收 | 分布式锁(Redis)、码池库存管理 |
|
||||||
|
| `code-lifecycle` | 码状态管理(有效 / 注销 / 冻结 / 迭代) | 状态机、事件驱动、链上同步 |
|
||||||
|
|
||||||
|
### 2.1.4 类别段与流通权限映射
|
||||||
|
|
||||||
|
| 类别 | 编码前缀 | 流通范围 | MA 解析权限 | 赋码时效 |
|
||||||
|
|------|----------|----------|-------------|----------|
|
||||||
|
| 重点 AI 漫剧 | AVCC-P | 全网全平台,首页推荐 | MA 根节点 + 行业节点 + 平台节点三级解析 | 5-30 个工作日 |
|
||||||
|
| 普通 AI 漫剧 | AVCC-G | 平台内播放,非首页推荐 | MA 行业节点 + 平台节点解析 | 1-3 个工作日 |
|
||||||
|
| 其他 AI 漫剧 | AVCC-O | 限本平台 / 限免流播放 | 平台节点本地解析 | 秒级实时赋码 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2.2 审核引擎(AI Review Engine)
|
||||||
|
|
||||||
|
### 2.2.1 职责边界
|
||||||
|
|
||||||
|
- 对 AI 漫剧进行画面、台词、声音、AIGC 真实性的多模态合规检测。
|
||||||
|
- 输出分级建议(重点/普通/其他)及详细预审报告(含违规帧定位、台词标红)。
|
||||||
|
- 支持重点内容人工终审队列的流转与状态跟踪。
|
||||||
|
- 模型版本管理与 A/B 测试。
|
||||||
|
|
||||||
|
### 2.2.2 技术架构
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ AI 审核引擎 (Review Engine) │
|
||||||
|
│ │
|
||||||
|
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
||||||
|
│ │ 画面审核模块 │ │ 台词审核模块 │ │ 声音审核模块 │ │
|
||||||
|
│ │ (Vision Model)│ │ (NLP Model) │ │ (Audio Model)│ │
|
||||||
|
│ │ │ │ │ │ │ │
|
||||||
|
│ │ 输入: 视频帧 │ │ 输入: 台词/SRT │ │ 输入: 音频轨道 │ │
|
||||||
|
│ │ 输出: 违规帧 │ │ 输出: 敏感词 │ │ 输出: 违规音效 │ │
|
||||||
|
│ │ 标注/置信度│ │ 语境评分 │ │ 版权匹配 │ │
|
||||||
|
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
|
||||||
|
│ │ │ │ │
|
||||||
|
│ ┌──────┴───────┐ ┌──────┴───────┐ ┌──────┴───────┐ │
|
||||||
|
│ │ AIGC 真实性核验│ │ 版权链比对 │ │ 模型版本校验 │ │
|
||||||
|
│ │(Deepfake检测) │ │(Fingerprint) │ │(白名单匹配) │ │
|
||||||
|
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
|
||||||
|
│ │ │ │ │
|
||||||
|
│ ┌──────┴──────────────────────────────────────┴──┐ │
|
||||||
|
│ │ 多模态融合决策层 │ │
|
||||||
|
│ │ (加权投票 + LLM 预审报告生成) │ │
|
||||||
|
│ │ → 输出: overall_score, suggested_level, │ │
|
||||||
|
│ │ violations[], report_json │ │
|
||||||
|
│ └─────────────────────────────────────────────────┘ │
|
||||||
|
└─────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.2.3 模型服务设计详表
|
||||||
|
|
||||||
|
| 模型服务名 | 输入 | 输出 | 推理框架 | 部署方式 | GPU 需求 |
|
||||||
|
|------------|------|------|----------|----------|----------|
|
||||||
|
| `vision-compliance` | 视频帧序列 (抽帧 1fps) | 违规帧坐标、违规类型标签、置信度 0-1 | Triton + PyTorch | K8s GPU Pod | A10 / A100 |
|
||||||
|
| `nlp-dialogue` | 台词文本 / SRT 字幕 | 敏感词位置、语境合规评分 0-100 | Triton + PyTorch | K8s GPU Pod | A10 |
|
||||||
|
| `audio-compliance` | 音频轨道 (16kHz mono) | 违规音效时间戳、版权音乐指纹匹配度 | Triton + PyTorch | K8s GPU Pod | A10 |
|
||||||
|
| `aigc-authenticity` | 视频 + C2PA 元数据 | 深度伪造概率、模型白名单命中状态 | Triton + PyTorch | K8s GPU Pod | A100 |
|
||||||
|
| `copyright-fingerprint` | 视频感知哈希 / 指纹向量 | Top-N 相似作品、侵权相似度 | Milvus 向量检索 | CPU Pod | 无 |
|
||||||
|
|
||||||
|
### 2.2.4 审核任务状态机
|
||||||
|
|
||||||
|
```
|
||||||
|
[queued] → [preprocessing: 音视频切片/抽帧/转码] → [model_inferencing: 并行推理]
|
||||||
|
|
|
||||||
|
┌─────────────────────────┘
|
||||||
|
↓
|
||||||
|
[fusion_decision: 融合决策] → [report_generation]
|
||||||
|
|
|
||||||
|
┌─────────────────────────┘
|
||||||
|
↓
|
||||||
|
┌──────── P(>阈值) → [human_review_queue: 人工终审]
|
||||||
|
│
|
||||||
|
├──────── G(中区间) → [platform_review: 平台人工复核]
|
||||||
|
│
|
||||||
|
└──────── O(低分且合规) → [auto_approved: 秒级赋码]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.2.5 预审报告 JSON 结构
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"task_id": "task_20260602_001",
|
||||||
|
"avcc": "MA.156.10005.8361/10.1300200.AIGC/...",
|
||||||
|
"status": "completed",
|
||||||
|
"overall_score": 78.5,
|
||||||
|
"suggested_level": "G",
|
||||||
|
"dimension_scores": {
|
||||||
|
"vision": 82.0,
|
||||||
|
"dialogue": 75.0,
|
||||||
|
"audio": 88.0,
|
||||||
|
"authenticity": 90.0,
|
||||||
|
"copyright": 95.0
|
||||||
|
},
|
||||||
|
"violations": [
|
||||||
|
{
|
||||||
|
"type": "dialogue",
|
||||||
|
"line": 23,
|
||||||
|
"timestamp": "00:05:30",
|
||||||
|
"severity": "medium",
|
||||||
|
"keyword": "敏感词示例",
|
||||||
|
"context": "台词上下文片段",
|
||||||
|
"suggestion": "建议替换为 xxx"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "vision",
|
||||||
|
"timestamp": "00:02:15",
|
||||||
|
"frame": 3450,
|
||||||
|
"severity": "low",
|
||||||
|
"category": "血腥画面",
|
||||||
|
"confidence": 0.72,
|
||||||
|
"bbox": [120, 200, 300, 400],
|
||||||
|
"suggestion": "建议打码或删减 0:02:10-0:02:20"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ai_model_version": "review-v2.1.0-20260601",
|
||||||
|
"inference_time_ms": 45230,
|
||||||
|
"queue_wait_ms": 1200,
|
||||||
|
"generated_at": "2026-06-02T14:30:00Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2.3 版权链引擎(Copyright Chain Engine)
|
||||||
|
|
||||||
|
### 2.3.1 职责边界
|
||||||
|
|
||||||
|
- 对 AVCC 全生命周期数据进行不可篡改存证(版权登记、审核结果、迭代记录、注销记录)。
|
||||||
|
- 管理版权主链、用户权益子链、分账智能合约。
|
||||||
|
- 提供链上数据查询、验证与仲裁接口。
|
||||||
|
- 对接深圳数据交易所,支撑 MA 数据要素登记证书签发。
|
||||||
|
|
||||||
|
### 2.3.2 联盟链组织与节点
|
||||||
|
|
||||||
|
| 组织 | 节点角色 | 权限 | 职责 |
|
||||||
|
|------|----------|------|------|
|
||||||
|
| 广电云 | 排序节点 + 背书节点 + 锚节点 | 全权限 | 链治理、智能合约部署、交易排序 |
|
||||||
|
| ZIIOT | 背书节点 | 编码存证、根解析记录写入 | MA 标识存证 |
|
||||||
|
| 长视频平台A | 背书节点 | 版权登记、播放数据写入 | 版权与播放数据上链 |
|
||||||
|
| 短视频平台B | 背书节点 | 版权登记、播放数据写入 | 版权与播放数据上链 |
|
||||||
|
| 深圳数据交易所 | 观察节点 | 只读 | 数据要素登记证书签发依据 |
|
||||||
|
| 监管机构 | 观察节点 | 只读 | 监管审计、链上数据抽查 |
|
||||||
|
|
||||||
|
### 2.3.3 智能合约设计
|
||||||
|
|
||||||
|
#### 合约一:AVCC_Copyright(版权主链合约)
|
||||||
|
|
||||||
|
```solidity
|
||||||
|
// 示意:ChainMaker / Fabric 智能合约(Go 实现)
|
||||||
|
// 功能:版权登记、权益方管理、版权迭代记录
|
||||||
|
|
||||||
|
// 数据结构
|
||||||
|
type CopyrightRecord struct {
|
||||||
|
AVCC string // AVCC 完整编码
|
||||||
|
Creator string // 创作者地址
|
||||||
|
ContentHash string // 内容哈希
|
||||||
|
LicenseDocHash string // 授权书哈希
|
||||||
|
Timestamp int64 // 存证时间戳
|
||||||
|
RightHolders []RightHolder // 权益方列表
|
||||||
|
Version int // 迭代版本
|
||||||
|
PrevAVCC string // 上一版本 AVCC(迭代时)
|
||||||
|
}
|
||||||
|
|
||||||
|
type RightHolder struct {
|
||||||
|
Type string // creator / model / ip / platform
|
||||||
|
Address string // 链上地址
|
||||||
|
Share uint // 万分比,如 4000 = 40%
|
||||||
|
}
|
||||||
|
|
||||||
|
// 核心方法
|
||||||
|
func RegisterCopyright(ctx contractapi.TransactionContextInterface, avcc string, ...) error
|
||||||
|
func UpdateRightHolders(ctx ..., avcc string, holders []RightHolder) error
|
||||||
|
func RecordIteration(ctx ..., prevAVCC string, newAVCC string, contentHash string) error
|
||||||
|
func QueryCopyright(ctx ..., avcc string) (*CopyrightRecord, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 合约二:AVCC_UserRights(用户权益子链合约)
|
||||||
|
|
||||||
|
```solidity
|
||||||
|
// 功能:用户跨平台购买权益记录与验证
|
||||||
|
|
||||||
|
type UserRightsRecord struct {
|
||||||
|
AVCC string // 作品 AVCC
|
||||||
|
UserHash string // 用户标识哈希(隐私保护)
|
||||||
|
PurchasePlatform string // 购买平台节点代码
|
||||||
|
PurchaseTime int64 // 购买时间
|
||||||
|
ExpiryTime int64 // 权益过期时间(NULL 表示永久)
|
||||||
|
PricePaid uint64 // 支付金额(分)
|
||||||
|
RightsType string // play / download / share
|
||||||
|
}
|
||||||
|
|
||||||
|
func RecordPurchase(ctx ..., record UserRightsRecord) error
|
||||||
|
func VerifyRights(ctx ..., avcc string, userHash string, currentPlatform string) (bool, error)
|
||||||
|
func TransferRights(ctx ..., avcc string, userHash string, toPlatform string) error
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 合约三:AVCC_Settlement(分账清算合约)
|
||||||
|
|
||||||
|
```solidity
|
||||||
|
// 功能:按智能合约比例自动执行分账
|
||||||
|
|
||||||
|
type SettlementRecord struct {
|
||||||
|
AVCC string
|
||||||
|
PlatformID string
|
||||||
|
PeriodStart int64
|
||||||
|
PeriodEnd int64
|
||||||
|
TotalRevenue uint64 // 总收益(分)
|
||||||
|
PlatformShare uint64 // 平台分成
|
||||||
|
CreatorShare uint64 // 创作者分成
|
||||||
|
ModelShare uint64 // 模型方分成
|
||||||
|
IPShare uint64 // IP 方分成
|
||||||
|
HubFee uint64 // 广电云服务费(6-8%)
|
||||||
|
Status string // pending / confirmed / disputed / settled
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExecuteSettlement(ctx ..., record SettlementRecord) error
|
||||||
|
func DisputeSettlement(ctx ..., avcc string, platformID string, reason string) error
|
||||||
|
func QuerySettlementHistory(ctx ..., avcc string) ([]SettlementRecord, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2.4 MA 编码网关(MA Encoding Gateway)
|
||||||
|
|
||||||
|
### 2.4.1 职责边界
|
||||||
|
|
||||||
|
- 对外提供统一的 AVCC 解析与流通权限识别服务(RESTful API)。
|
||||||
|
- 对接 ZIIOT MA 全球根解析系统,支持跨境、跨域、跨平台解析。
|
||||||
|
- 实现平台接入鉴权(API Key + HMAC-SHA256)、流量管控、解析日志记录。
|
||||||
|
- 管理 MA 三级节点注册与码资源分配接口(仅限广电云内部调用)。
|
||||||
|
|
||||||
|
### 2.4.2 核心接口列表
|
||||||
|
|
||||||
|
| 接口路径 | 方法 | 访问控制 | 说明 |
|
||||||
|
|----------|------|----------|------|
|
||||||
|
| `/api/v1/avcc/parse` | POST | 平台 API Key | 解析 AVCC,返回完整元数据与流通权限 |
|
||||||
|
| `/api/v1/avcc/validate` | POST | 平台 API Key | 校验 AVCC 有效性(含 MA 标识段合法性) |
|
||||||
|
| `/api/v1/avcc/resolve` | POST | 平台 API Key | 对接 MA 根解析,获取全球解析结果 |
|
||||||
|
| `/api/v1/node/register` | POST | 广电云内部 | 平台/机构节点注册(MA 三级节点) |
|
||||||
|
| `/api/v1/node/allocate` | POST | 广电云内部 | 码资源分配(仅限广电云行业节点调用) |
|
||||||
|
| `/api/v1/node/query` | GET | 平台 API Key | 查询本节点码资源使用情况 |
|
||||||
|
| `/api/v1/stats/parse` | GET | 广电云运营 | 解析量统计、平台调用排行 |
|
||||||
|
|
||||||
|
### 2.4.3 解析流程
|
||||||
|
|
||||||
|
```
|
||||||
|
平台提交 AVCC → 网关本地解析(格式校验 + 签名验证)
|
||||||
|
│
|
||||||
|
┌───────────────┴───────────────┐
|
||||||
|
│ │
|
||||||
|
本地缓存命中 本地缓存未命中
|
||||||
|
│ │
|
||||||
|
↓ ↓
|
||||||
|
返回缓存结果 调用 ZIIOT MA 根解析 API
|
||||||
|
│
|
||||||
|
↓
|
||||||
|
返回全球解析结果
|
||||||
|
│
|
||||||
|
↓
|
||||||
|
本地权限映射(流通范围计算)
|
||||||
|
│
|
||||||
|
↓
|
||||||
|
写入缓存(TTL=1h)
|
||||||
|
│
|
||||||
|
↓
|
||||||
|
返回完整解析响应
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.4.4 限流策略
|
||||||
|
|
||||||
|
| 平台类型 | 日配额 | QPS 限制 | 说明 |
|
||||||
|
|----------|--------|----------|------|
|
||||||
|
| 长视频平台 | 100万 | 500 | 高优先级,首页推荐内容高频校验 |
|
||||||
|
| 短视频平台 | 500万 | 2000 | 海量内容实时校验 |
|
||||||
|
| AI 工具厂商 | 50万 | 200 | 生成环节嵌入校验 |
|
||||||
|
| MCN 机构 | 10万 | 50 | 批量赋码辅助查询 |
|
||||||
|
| 跨境平台 | 20万 | 100 | 对接 MA 根解析通道 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2.5 C2PA 水印 SDK
|
||||||
|
|
||||||
|
### 2.5.1 职责边界
|
||||||
|
|
||||||
|
- 在 AI 生成/编辑环节自动嵌入 C2PA 内容凭证(Content Credentials)。
|
||||||
|
- 凭证内容包含:模型版本、训练数据授权摘要、MA 标识片段(平台/机构代码+对象类目)。
|
||||||
|
- 支持跨工具、跨平台的 C2PA 水印读取与验证。
|
||||||
|
- 提供 Python / JavaScript / Go 多语言绑定。
|
||||||
|
|
||||||
|
### 2.5.2 SDK 架构
|
||||||
|
|
||||||
|
```
|
||||||
|
C2PA SDK (AIGC-Hub-SDK)
|
||||||
|
├── core/
|
||||||
|
│ ├── c2pa-rs/ # Rust 核心库,实现 C2PA 标准
|
||||||
|
│ ├── bindings/
|
||||||
|
│ │ ├── python/ # PyO3 绑定
|
||||||
|
│ │ ├── nodejs/ # N-API 绑定
|
||||||
|
│ │ └── go/ # CGO 绑定
|
||||||
|
│ └── manifest/
|
||||||
|
│ ├── manifest_builder.py # C2PA Manifest 构建器
|
||||||
|
│ └── manifest_parser.py # C2PA Manifest 解析器
|
||||||
|
├── ma-extension/
|
||||||
|
│ ├── embed_ma_fragment() # 嵌入 MA 标识片段
|
||||||
|
│ ├── verify_ma_fragment() # 验证 MA 标识片段
|
||||||
|
│ ├── extract_ma_fragment() # 提取 MA 标识片段
|
||||||
|
│ └── ma_manifest_schema.json # MA 扩展 JSON Schema
|
||||||
|
├── ai-tool-adapters/
|
||||||
|
│ ├── adapter_comfyui.py # ComfyUI 插件
|
||||||
|
│ ├── adapter_sd_webui.py # Stable Diffusion WebUI 插件
|
||||||
|
│ ├── adapter_kling.py # 可灵 AI 适配
|
||||||
|
│ ├── adapter_runway.py # Runway 适配
|
||||||
|
│ ├── adapter_pika.py # Pika 适配
|
||||||
|
│ └── adapter_midjourney.py # Midjourney API 钩子
|
||||||
|
├── platform-plugins/
|
||||||
|
│ ├── plugin_douyin.js # 抖音发布校验插件
|
||||||
|
│ ├── plugin_bilibili.js # B站发布校验插件
|
||||||
|
│ ├── plugin_xiaohongshu.js # 小红书发布校验插件
|
||||||
|
│ └── plugin_kuaishou.js # 快手发布校验插件
|
||||||
|
└── cli/
|
||||||
|
├── aigc-hub-cli # 命令行工具(创作者本地使用)
|
||||||
|
└── embed.py / verify.py # 脚本工具
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.5.3 C2PA Manifest 扩展字段(MA 片段)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"claim_generator": "AIGC-Hub-SDK/1.0.0",
|
||||||
|
"assertions": [
|
||||||
|
{
|
||||||
|
"label": "c2pa.training-mining",
|
||||||
|
"data": {
|
||||||
|
"entries": [
|
||||||
|
{
|
||||||
|
"description": "训练数据授权摘要",
|
||||||
|
"source": "授权书哈希: 0x7f3e9a...",
|
||||||
|
"scope": "commercial-use",
|
||||||
|
"dataset_name": "开源数据集A + 授权数据集B",
|
||||||
|
"license_type": "CC-BY-SA-4.0 + 商业授权"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "ma.avcc.fragment",
|
||||||
|
"data": {
|
||||||
|
"version": "1.0",
|
||||||
|
"ma_root": "MA",
|
||||||
|
"country_code": "156",
|
||||||
|
"industry_node": "10005",
|
||||||
|
"platform_node": "8361",
|
||||||
|
"object_category": "10.1300200.AIGC",
|
||||||
|
"content_generation_method": "AIGC",
|
||||||
|
"model_name": "Stable-Diffusion-XL",
|
||||||
|
"model_version": "v1.0",
|
||||||
|
"model_provider": "Stability AI",
|
||||||
|
"generation_timestamp": "2026-05-20T10:00:00Z",
|
||||||
|
"generation_log_hash": "a1b2c3...",
|
||||||
|
"manual_edit_ratio": 0.15,
|
||||||
|
"sdk_version": "AIGC-Hub-SDK/1.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"signature": {
|
||||||
|
"alg": "ES256",
|
||||||
|
"issuer": "AIGC-Hub-CA",
|
||||||
|
"timestamp": "2026-05-20T10:00:05Z"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.5.4 SDK 集成示例(Python)
|
||||||
|
|
||||||
|
```python
|
||||||
|
from aigc_hub_sdk import C2PAManifestBuilder, MAExtension
|
||||||
|
|
||||||
|
# 构建 C2PA Manifest + MA 扩展
|
||||||
|
builder = C2PAManifestBuilder(
|
||||||
|
claim_generator="AIGC-Hub-SDK/1.0.0"
|
||||||
|
)
|
||||||
|
|
||||||
|
# 添加 MA 标识片段
|
||||||
|
ma_ext = MAExtension(
|
||||||
|
platform_node="8361",
|
||||||
|
object_category="10.1300200.AIGC",
|
||||||
|
model_name="Stable-Diffusion-XL",
|
||||||
|
model_version="v1.0",
|
||||||
|
generation_log_hash="a1b2c3...",
|
||||||
|
manual_edit_ratio=0.15
|
||||||
|
)
|
||||||
|
builder.add_assertion(ma_ext.to_c2pa_assertion())
|
||||||
|
|
||||||
|
# 添加训练数据授权信息
|
||||||
|
builder.add_training_assertion(
|
||||||
|
dataset_name="开源数据集A",
|
||||||
|
license_type="CC-BY-SA-4.0",
|
||||||
|
source_hash="0x7f3e9a..."
|
||||||
|
)
|
||||||
|
|
||||||
|
# 嵌入到输出图片/视频
|
||||||
|
builder.embed("input.png", "output.png", signing_key=key)
|
||||||
|
|
||||||
|
# 验证
|
||||||
|
result = builder.verify("output.png")
|
||||||
|
assert result.valid
|
||||||
|
assert result.ma_fragment.platform_node == "8361"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2.6 创作者工作台(Creator Workbench)
|
||||||
|
|
||||||
|
### 2.6.1 职责边界
|
||||||
|
|
||||||
|
- 面向创作者/MCN 的一站式 SaaS 平台。
|
||||||
|
- 提供赋码申请、版权登记、分账查询、审核报告查看、多平台数据聚合、智能报税等功能。
|
||||||
|
- 支持 MCN 机构批量赋码、团队权限管理、子账号体系。
|
||||||
|
|
||||||
|
### 2.6.2 功能模块详表
|
||||||
|
|
||||||
|
| 模块 | 功能点 | 技术实现 |
|
||||||
|
|------|--------|----------|
|
||||||
|
| **赋码中心** | 提交作品、上传版权材料、查看审核进度、下载 AVCC 证书(PDF + 二维码) | 大文件分片上传(OSS)、WebSocket 实时进度推送 |
|
||||||
|
| **版权登记** | 上传授权书、登记版权链、申请 MA 数据要素登记证书 | 表单引擎、文件哈希计算、链上交易状态轮询 |
|
||||||
|
| **分账查询** | 查看各平台播放数据、分账流水、收益提现、结算周期管理 | 数据聚合 API、图表可视化、提现申请工作流 |
|
||||||
|
| **审核报告** | 查看 AI 预审报告(违规帧定位、台词标红、时间轴导航) | 视频播放器联动、时间轴组件、高亮标注 |
|
||||||
|
| **多平台聚合** | 绑定各平台账号(抖音/B站/快手/小红书),聚合播放量、收益、粉丝数据 | OAuth 2.0 接入、定时数据同步、数据看板 |
|
||||||
|
| **智能报税** | 基于分账流水自动生成税务报表、发票管理、个税计算 | 规则引擎、PDF 报表生成、电子发票对接 |
|
||||||
|
| **MCN 管理** | 批量赋码、团队权限、子账号、收益汇总 | RBAC 权限模型、批量任务队列 |
|
||||||
|
|
||||||
|
### 2.6.3 前端页面结构
|
||||||
|
|
||||||
|
```
|
||||||
|
/workbench
|
||||||
|
├── /dashboard # 数据总览(待办赋码数、审核中、收益、最新通知)
|
||||||
|
├── /code
|
||||||
|
│ ├── /apply # 赋码申请
|
||||||
|
│ ├── /status # 赋码进度查询
|
||||||
|
│ └── /certificate # AVCC 证书下载
|
||||||
|
├── /copyright
|
||||||
|
│ ├── /register # 版权登记
|
||||||
|
│ └── /certificate # 数据要素登记证书
|
||||||
|
├── /review
|
||||||
|
│ └── /reports # 审核报告列表与详情
|
||||||
|
├── /finance
|
||||||
|
│ ├── /revenue # 收益明细
|
||||||
|
│ ├── /settlement # 结算记录
|
||||||
|
│ └── /withdraw # 提现申请
|
||||||
|
├── /platforms
|
||||||
|
│ └── /connect # 平台账号绑定
|
||||||
|
├── /tax
|
||||||
|
│ └── /reports # 税务报表
|
||||||
|
└── /settings
|
||||||
|
├── /profile # 个人/企业信息
|
||||||
|
├── /team # MCN 团队管理(企业用户)
|
||||||
|
└── /api-keys # API 密钥管理
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2.7 跨平台清算引擎(Cross-platform Settlement Engine)
|
||||||
|
|
||||||
|
### 2.7.1 职责边界
|
||||||
|
|
||||||
|
- 按智能合约执行跨平台分账结算(版权主链合约触发)。
|
||||||
|
- 管理用户权益通兑(购买记录跨平台解锁验证)。
|
||||||
|
- 生成版权估值报告,支撑 ABS 发行等金融衍生服务。
|
||||||
|
- 对接银行/支付机构,完成法币结算。
|
||||||
|
|
||||||
|
### 2.7.2 分账结算模型
|
||||||
|
|
||||||
|
```
|
||||||
|
用户支付 10 元
|
||||||
|
│
|
||||||
|
├── 平台抽成 30% ────────→ 3.00 元 (首发/播放平台)
|
||||||
|
│
|
||||||
|
├── 广电云清算服务费 6% ──→ 0.60 元 (AIGC-Hub 技术服务费)
|
||||||
|
│
|
||||||
|
└── 内容分成池 64% ───────→ 6.40 元
|
||||||
|
│
|
||||||
|
├── 创作者分成 40% ─→ 4.00 元
|
||||||
|
├── 模型方分成 15% ─→ 1.50 元
|
||||||
|
├── IP 方分成 10% ──→ 1.00 元
|
||||||
|
└── 平台运营 9% ───→ 0.90 元 (内容运营/推广成本)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.7.3 清算周期
|
||||||
|
|
||||||
|
| 结算类型 | 周期 | 触发条件 | 链上确认方式 |
|
||||||
|
|----------|------|----------|-------------|
|
||||||
|
| 日结 | T+1 | 播放数据日汇总 | 联盟链日结批处理 |
|
||||||
|
| 周结 | T+7 | 周累计 GMV > 阈值 | 联盟链周结批处理 |
|
||||||
|
| 月结 | T+30 | 月度对账 | 联盟链月结 + 法币转账 |
|
||||||
|
| 实时结算 | 即时 | 用户购买行为 | 链上实时记录 + 定期归集 |
|
||||||
|
|
||||||
|
### 2.7.4 版权估值模型
|
||||||
|
|
||||||
|
| 估值维度 | 权重 | 数据来源 |
|
||||||
|
|----------|------|----------|
|
||||||
|
| 播放量 | 30% | ClickHouse 播放数据 |
|
||||||
|
| 完播率 | 20% | 平台回传数据 |
|
||||||
|
| 分账流水 | 25% | 链上结算记录 |
|
||||||
|
| 用户评分 | 10% | 平台评分聚合 |
|
||||||
|
| 合规评分 | 10% | 审核引擎综合评分 |
|
||||||
|
| 模型认证加分 | 5% | 白名单模型额外加成 |
|
||||||
|
|
||||||
|
```go
|
||||||
|
// 伪代码:版权估值计算(清算引擎 - Go 实现)
|
||||||
|
func EvaluateCopyrightValue(avcc string) (map[string]interface{}, error) {
|
||||||
|
metrics := map[string]float64{
|
||||||
|
"total_plays": clickhouse.QueryMetric(avcc, "plays"),
|
||||||
|
"completion_rate": clickhouse.QueryMetric(avcc, "completion_rate"),
|
||||||
|
"settlement_history": chain.QuerySettlementScore(avcc),
|
||||||
|
"user_rating": platformAPI.AggregateRating(avcc),
|
||||||
|
"compliance_score": reviewDB.GetScore(avcc),
|
||||||
|
"model_certified": 0.0,
|
||||||
|
}
|
||||||
|
|
||||||
|
if modelRegistry.IsCertified(avcc) {
|
||||||
|
metrics["model_certified"] = 1.0
|
||||||
|
}
|
||||||
|
|
||||||
|
valueScore :=
|
||||||
|
metrics["total_plays"] * 0.30 +
|
||||||
|
metrics["completion_rate"] * 0.20 +
|
||||||
|
metrics["settlement_history"] * 0.25 +
|
||||||
|
metrics["user_rating"] * 0.10 +
|
||||||
|
metrics["compliance_score"] * 0.10 +
|
||||||
|
metrics["model_certified"] * 0.05
|
||||||
|
|
||||||
|
confidence := "medium"
|
||||||
|
if metrics["total_plays"] > 100000 {
|
||||||
|
confidence = "high"
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]interface{}{
|
||||||
|
"avcc": avcc,
|
||||||
|
"valuation_score": valueScore,
|
||||||
|
"estimated_value_cny": valueScore * 1000, // 估值映射
|
||||||
|
"confidence": confidence,
|
||||||
|
"report_url": fmt.Sprintf("https://aigc-hub.cn/valuation/%s", avcc),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*上一章:[01-总体技术架构.md](01-总体技术架构.md)*
|
||||||
|
*下一章:[03-数据库与数据模型.md](03-数据库与数据模型.md)*
|
||||||
@@ -0,0 +1,464 @@
|
|||||||
|
# 第三章 数据库与数据模型设计
|
||||||
|
|
||||||
|
> 版本:V1.0
|
||||||
|
> 基于文档:《AIGC-Hub智视码(AVCC)体系建设方案 V2.0》
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3.1 数据存储策略总览
|
||||||
|
|
||||||
|
| 存储类型 | 选型 | 用途 | 数据量预估 |
|
||||||
|
|----------|------|------|------------|
|
||||||
|
| 关系型数据库 | PostgreSQL 16 | 主业务数据(赋码、审核、版权链元数据) | 单表千万级 |
|
||||||
|
| 缓存 | Redis Cluster 7.x | 会话、热点数据、限流、分布式锁 | 百万级 Key |
|
||||||
|
| 时序分析数据库 | ClickHouse 24.x | 播放数据、审核性能指标、运营分析 | 日增数亿行 |
|
||||||
|
| 对象存储 | MinIO | 视频文件、C2PA 水印、证据包、证书 PDF | PB 级 |
|
||||||
|
| 搜索引擎 | Elasticsearch 8.x | 审核报告全文检索、日志检索 | TB 级 |
|
||||||
|
| 向量数据库 | Milvus / pgvector | 视频指纹向量、版权相似度检索 | 百万级向量 |
|
||||||
|
| 区块链 | ChainMaker | 版权存证、权益记录、清算记录 | 链上不可删除 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3.2 PostgreSQL 核心表结构
|
||||||
|
|
||||||
|
### 3.2.1 创作者表 (`creators`)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE creators (
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
ma_node_code VARCHAR(64) NOT NULL,
|
||||||
|
creator_type VARCHAR(16) CHECK (creator_type IN ('individual', 'mcn', 'studio')),
|
||||||
|
real_name VARCHAR(128) NOT NULL,
|
||||||
|
id_card_hash VARCHAR(64),
|
||||||
|
enterprise_name VARCHAR(256),
|
||||||
|
enterprise_credit_code VARCHAR(32),
|
||||||
|
phone VARCHAR(32) NOT NULL,
|
||||||
|
email VARCHAR(128),
|
||||||
|
status VARCHAR(16) DEFAULT 'active' CHECK (status IN ('active', 'frozen', 'blacklisted')),
|
||||||
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMPTZ DEFAULT NOW()
|
||||||
|
);
|
||||||
|
CREATE INDEX idx_creators_ma_node ON creators(ma_node_code);
|
||||||
|
CREATE INDEX idx_creators_status ON creators(status);
|
||||||
|
|
||||||
|
COMMENT ON TABLE creators IS '创作者/机构主表,存储实名信息(身份证存哈希)';
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2.2 平台/机构节点表 (`platforms`)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE platforms (
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
ma_node_code VARCHAR(64) NOT NULL UNIQUE,
|
||||||
|
platform_name VARCHAR(128) NOT NULL,
|
||||||
|
platform_type VARCHAR(32) CHECK (platform_type IN ('long_video', 'short_video', 'ai_tool', 'mcn')),
|
||||||
|
api_key_hash VARCHAR(128),
|
||||||
|
api_secret_hash VARCHAR(256),
|
||||||
|
status VARCHAR(16) DEFAULT 'pending' CHECK (status IN ('pending', 'active', 'suspended')),
|
||||||
|
quota_daily INT DEFAULT 10000,
|
||||||
|
callback_url VARCHAR(256),
|
||||||
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||||
|
);
|
||||||
|
CREATE INDEX idx_platforms_type ON platforms(platform_type);
|
||||||
|
CREATE INDEX idx_platforms_status ON platforms(status);
|
||||||
|
|
||||||
|
COMMENT ON TABLE platforms IS '接入平台/机构节点表,对应 MA 三级节点';
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2.3 AVCC 赋码记录表 (`avcc_records`) — 核心业务表
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE avcc_records (
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
avcc_full_code VARCHAR(512) NOT NULL UNIQUE,
|
||||||
|
ma_root VARCHAR(8) DEFAULT 'MA',
|
||||||
|
country_code VARCHAR(8) DEFAULT '156',
|
||||||
|
industry_node VARCHAR(16) DEFAULT '10005',
|
||||||
|
platform_node VARCHAR(16) NOT NULL,
|
||||||
|
object_category VARCHAR(64) NOT NULL,
|
||||||
|
license_no VARCHAR(128),
|
||||||
|
review_level VARCHAR(8) CHECK (review_level IN ('P', 'G', 'O')),
|
||||||
|
version INT DEFAULT 1,
|
||||||
|
ai_content_hash VARCHAR(128) NOT NULL,
|
||||||
|
copyright_crd VARCHAR(128),
|
||||||
|
creator_id BIGINT REFERENCES creators(id),
|
||||||
|
platform_id BIGINT REFERENCES platforms(id),
|
||||||
|
review_status VARCHAR(32) DEFAULT 'pending'
|
||||||
|
CHECK (review_status IN ('pending', 'pre_checking', 'ai_reviewing', 'human_reviewing', 'approved', 'rejected', 'revoked')),
|
||||||
|
review_report_id BIGINT,
|
||||||
|
circulation_status VARCHAR(32) DEFAULT 'active'
|
||||||
|
CHECK (circulation_status IN ('active', 'suspended', 'revoked', 'expired')),
|
||||||
|
c2pa_manifest_hash VARCHAR(128),
|
||||||
|
content_storage_key VARCHAR(256),
|
||||||
|
submitted_at TIMESTAMPTZ DEFAULT NOW(),
|
||||||
|
reviewed_at TIMESTAMPTZ,
|
||||||
|
expires_at TIMESTAMPTZ,
|
||||||
|
revoked_at TIMESTAMPTZ,
|
||||||
|
revoked_reason TEXT,
|
||||||
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMPTZ DEFAULT NOW()
|
||||||
|
);
|
||||||
|
CREATE INDEX idx_avcc_platform ON avcc_records(platform_node);
|
||||||
|
CREATE INDEX idx_avcc_creator ON avcc_records(creator_id);
|
||||||
|
CREATE INDEX idx_avcc_review_status ON avcc_records(review_status);
|
||||||
|
CREATE INDEX idx_avcc_circulation ON avcc_records(circulation_status);
|
||||||
|
CREATE INDEX idx_avcc_license ON avcc_records(license_no);
|
||||||
|
CREATE INDEX idx_avcc_submitted ON avcc_records(submitted_at);
|
||||||
|
|
||||||
|
COMMENT ON TABLE avcc_records IS 'AVCC 赋码记录核心业务表,一码一行';
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2.4 审核报告表 (`review_reports`)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE review_reports (
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
avcc_record_id BIGINT REFERENCES avcc_records(id),
|
||||||
|
review_type VARCHAR(16) CHECK (review_type IN ('AI', 'HUMAN', 'HYBRID')),
|
||||||
|
overall_score DECIMAL(5,2),
|
||||||
|
suggested_level VARCHAR(8),
|
||||||
|
final_level VARCHAR(8),
|
||||||
|
vision_score DECIMAL(5,2),
|
||||||
|
dialogue_score DECIMAL(5,2),
|
||||||
|
audio_score DECIMAL(5,2),
|
||||||
|
authenticity_score DECIMAL(5,2),
|
||||||
|
copyright_score DECIMAL(5,2),
|
||||||
|
violations JSONB DEFAULT '[]',
|
||||||
|
reviewer_id BIGINT,
|
||||||
|
reviewer_comment TEXT,
|
||||||
|
ai_model_version VARCHAR(64),
|
||||||
|
report_json JSONB,
|
||||||
|
content_fingerprint VARCHAR(128),
|
||||||
|
processing_time_ms INT,
|
||||||
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||||
|
);
|
||||||
|
CREATE INDEX idx_review_avcc ON review_reports(avcc_record_id);
|
||||||
|
CREATE INDEX idx_review_type ON review_reports(review_type);
|
||||||
|
CREATE INDEX idx_review_created ON review_reports(created_at);
|
||||||
|
|
||||||
|
COMMENT ON TABLE review_reports IS '审核报告表,AI/HUMAN/HYBRID 三类审核结果';
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2.5 版权链存证表 (`chain_records`)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE chain_records (
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
avcc_record_id BIGINT REFERENCES avcc_records(id),
|
||||||
|
chain_type VARCHAR(32) CHECK (chain_type IN ('copyright_main', 'user_rights', 'settlement', 'iteration', 'revocation')),
|
||||||
|
tx_hash VARCHAR(128) NOT NULL,
|
||||||
|
block_height BIGINT,
|
||||||
|
chain_node VARCHAR(64),
|
||||||
|
payload_hash VARCHAR(128),
|
||||||
|
payload JSONB,
|
||||||
|
confirmation_count INT DEFAULT 0,
|
||||||
|
status VARCHAR(16) DEFAULT 'pending' CHECK (status IN ('pending', 'confirmed', 'failed')),
|
||||||
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||||
|
);
|
||||||
|
CREATE INDEX idx_chain_avcc ON chain_records(avcc_record_id);
|
||||||
|
CREATE INDEX idx_chain_type ON chain_records(chain_type);
|
||||||
|
CREATE INDEX idx_chain_tx ON chain_records(tx_hash);
|
||||||
|
|
||||||
|
COMMENT ON TABLE chain_records IS '版权链存证元数据表(链上原始数据存在 ChainMaker)';
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2.6 分账/清算记录表 (`settlement_records`)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE settlement_records (
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
avcc_record_id BIGINT REFERENCES avcc_records(id),
|
||||||
|
platform_id BIGINT REFERENCES platforms(id),
|
||||||
|
period_start DATE NOT NULL,
|
||||||
|
period_end DATE NOT NULL,
|
||||||
|
total_revenue DECIMAL(18,4),
|
||||||
|
platform_share DECIMAL(18,4),
|
||||||
|
creator_share DECIMAL(18,4),
|
||||||
|
model_share DECIMAL(18,4),
|
||||||
|
ip_share DECIMAL(18,4),
|
||||||
|
hub_fee DECIMAL(18,4),
|
||||||
|
status VARCHAR(16) DEFAULT 'pending'
|
||||||
|
CHECK (status IN ('pending', 'confirmed', 'disputed', 'settled', 'refunded')),
|
||||||
|
dispute_reason TEXT,
|
||||||
|
tx_hash VARCHAR(128),
|
||||||
|
settled_at TIMESTAMPTZ,
|
||||||
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||||
|
);
|
||||||
|
CREATE INDEX idx_settlement_avcc ON settlement_records(avcc_record_id);
|
||||||
|
CREATE INDEX idx_settlement_platform ON settlement_records(platform_id);
|
||||||
|
CREATE INDEX idx_settlement_period ON settlement_records(period_start, period_end);
|
||||||
|
|
||||||
|
COMMENT ON TABLE settlement_records IS '分账清算记录表,链上清算后同步写入';
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2.7 黑名单表 (`blacklist`)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE blacklist (
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
target_type VARCHAR(32) CHECK (target_type IN ('creator', 'platform', 'model', 'dataset', 'content')),
|
||||||
|
target_id VARCHAR(128) NOT NULL,
|
||||||
|
ma_node_code VARCHAR(64),
|
||||||
|
reason TEXT NOT NULL,
|
||||||
|
evidence_hash VARCHAR(128),
|
||||||
|
source VARCHAR(32) CHECK (source IN ('admin', 'system', 'appeal')),
|
||||||
|
operator_id BIGINT,
|
||||||
|
revoked_at TIMESTAMPTZ,
|
||||||
|
revoked_reason TEXT,
|
||||||
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||||
|
);
|
||||||
|
CREATE INDEX idx_blacklist_target ON blacklist(target_type, target_id);
|
||||||
|
CREATE INDEX idx_blacklist_active ON blacklist(target_type, target_id) WHERE revoked_at IS NULL;
|
||||||
|
|
||||||
|
COMMENT ON TABLE blacklist IS '黑名单表,支持创作者/平台/模型/数据集/内容五级黑名单';
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2.8 审核任务队列表 (`review_tasks`)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE review_tasks (
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
avcc_record_id BIGINT REFERENCES avcc_records(id),
|
||||||
|
task_type VARCHAR(16) CHECK (task_type IN ('AI_SCREEN', 'HUMAN_FINAL', 'APPEAL')),
|
||||||
|
status VARCHAR(16) DEFAULT 'queued'
|
||||||
|
CHECK (status IN ('queued', 'preprocessing', 'inferencing', 'fusion', 'completed', 'failed', 'cancelled')),
|
||||||
|
priority INT DEFAULT 5, -- 1-10, P类内容=1(最高), O类=10
|
||||||
|
queue_position INT,
|
||||||
|
processor_node VARCHAR(64), -- 处理节点标识
|
||||||
|
started_at TIMESTAMPTZ,
|
||||||
|
completed_at TIMESTAMPTZ,
|
||||||
|
error_message TEXT,
|
||||||
|
retry_count INT DEFAULT 0,
|
||||||
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||||
|
);
|
||||||
|
CREATE INDEX idx_tasks_status ON review_tasks(status);
|
||||||
|
CREATE INDEX idx_tasks_priority ON review_tasks(priority, created_at);
|
||||||
|
CREATE INDEX idx_tasks_avcc ON review_tasks(avcc_record_id);
|
||||||
|
|
||||||
|
COMMENT ON TABLE review_tasks IS '审核任务队列,支撑优先级调度与故障重试';
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2.9 API 调用日志表 (`api_call_logs`) — 镜像表
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE api_call_logs (
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
platform_id BIGINT REFERENCES platforms(id),
|
||||||
|
api_endpoint VARCHAR(256) NOT NULL,
|
||||||
|
http_method VARCHAR(8),
|
||||||
|
avcc_code VARCHAR(512),
|
||||||
|
request_hash VARCHAR(128),
|
||||||
|
response_status INT,
|
||||||
|
latency_ms INT,
|
||||||
|
client_ip INET,
|
||||||
|
user_agent TEXT,
|
||||||
|
called_at TIMESTAMPTZ DEFAULT NOW()
|
||||||
|
);
|
||||||
|
CREATE INDEX idx_api_logs_platform ON api_call_logs(platform_id, called_at);
|
||||||
|
CREATE INDEX idx_api_logs_endpoint ON api_call_logs(api_endpoint, called_at);
|
||||||
|
CREATE INDEX idx_api_logs_date ON api_call_logs(called_at);
|
||||||
|
|
||||||
|
COMMENT ON TABLE api_call_logs IS 'API 调用日志镜像表(详细日志写入 ClickHouse)';
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3.3 Redis 缓存设计
|
||||||
|
|
||||||
|
| Key Pattern | 类型 | TTL | 说明 |
|
||||||
|
|-------------|------|-----|------|
|
||||||
|
| `avcc:{code}` | String | 1h | AVCC 解析结果缓存(热点码加速) |
|
||||||
|
| `avcc:parse:{code}` | Hash | 30m | 解析元数据缓存 |
|
||||||
|
| `platform:{id}:quota` | String | 1d | 平台日调用配额剩余 |
|
||||||
|
| `platform:{id}:rate` | String | 1m | 平台限流计数(Token Bucket) |
|
||||||
|
| `session:{token}` | Hash | 24h | 用户会话(创作者/运营人员) |
|
||||||
|
| `blacklist:{type}:{id}` | String | 永久 | 黑名单缓存(每日全量同步) |
|
||||||
|
| `review:task:{id}` | Hash | 2h | 审核任务状态缓存 |
|
||||||
|
| `code:pool:{industry_node}` | String | 永久 | 码资源池剩余数量 |
|
||||||
|
| `code:allocated:{platform_node}` | String | 永久 | 已分配码段索引 |
|
||||||
|
| `stats:daily:{date}` | Hash | 7d | 日运营统计缓存 |
|
||||||
|
|
||||||
|
### Redis 使用场景补充
|
||||||
|
|
||||||
|
- **分布式锁**:码资源分配时使用 `SET code:lock:{platform_node} {value} NX EX 10`
|
||||||
|
- **排行榜**:创作者收益排行 `ZADD leaderboard:revenue:{period} {score} {creator_id}`
|
||||||
|
- **队列**:人工审核队列使用 Redis List + 优先级排序
|
||||||
|
- **发布订阅**:审核完成通知 `PUBLISH review:completed {avcc}`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3.4 ClickHouse 分析表设计
|
||||||
|
|
||||||
|
### 3.4.1 播放与消费事件表
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE playback_metrics (
|
||||||
|
event_time DateTime64(3),
|
||||||
|
avcc_code String,
|
||||||
|
platform_node String,
|
||||||
|
user_hash String,
|
||||||
|
event_type Enum8('play' = 1, 'complete' = 2, 'purchase' = 3, 'share' = 4, 'comment' = 5),
|
||||||
|
duration_sec Int32,
|
||||||
|
revenue Decimal(18,4),
|
||||||
|
device_type Enum8('mobile' = 1, 'pc' = 2, 'tv' = 3, 'other' = 4),
|
||||||
|
province String
|
||||||
|
) ENGINE = MergeTree()
|
||||||
|
ORDER BY (event_time, avcc_code, platform_node)
|
||||||
|
PARTITION BY toYYYYMMDD(event_time)
|
||||||
|
TTL event_time + INTERVAL 3 YEAR;
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.4.2 审核性能分析表
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE review_metrics (
|
||||||
|
event_time DateTime64(3),
|
||||||
|
review_type String,
|
||||||
|
model_version String,
|
||||||
|
content_type String,
|
||||||
|
queue_wait_ms Int32,
|
||||||
|
preprocess_ms Int32,
|
||||||
|
inference_ms Int32,
|
||||||
|
fusion_ms Int32,
|
||||||
|
total_latency_ms Int32,
|
||||||
|
result Enum8('pass' = 1, 'fail' = 2, 'manual' = 3),
|
||||||
|
gpu_node String
|
||||||
|
) ENGINE = MergeTree()
|
||||||
|
ORDER BY (event_time, review_type)
|
||||||
|
PARTITION BY toYYYYMMDD(event_time);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.4.3 平台调用分析表
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE api_metrics (
|
||||||
|
event_time DateTime64(3),
|
||||||
|
platform_id String,
|
||||||
|
api_endpoint String,
|
||||||
|
response_status Int16,
|
||||||
|
latency_ms Int32,
|
||||||
|
client_ip String,
|
||||||
|
avcc_code String
|
||||||
|
) ENGINE = MergeTree()
|
||||||
|
ORDER BY (event_time, platform_id, api_endpoint)
|
||||||
|
PARTITION BY toYYYYMMDD(event_time)
|
||||||
|
TTL event_time + INTERVAL 1 YEAR;
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.4.4 版权链存证分析表
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE chain_metrics (
|
||||||
|
event_time DateTime64(3),
|
||||||
|
chain_type String,
|
||||||
|
tx_hash String,
|
||||||
|
block_height UInt64,
|
||||||
|
confirmation_ms Int32,
|
||||||
|
gas_cost Decimal(18,8),
|
||||||
|
payload_size Int32
|
||||||
|
) ENGINE = MergeTree()
|
||||||
|
ORDER BY (event_time, chain_type)
|
||||||
|
PARTITION BY toYYYYMMDD(event_time);
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3.5 向量数据库设计(Milvus / pgvector)
|
||||||
|
|
||||||
|
### 3.5.1 视频指纹向量集合
|
||||||
|
|
||||||
|
```python
|
||||||
|
# 伪代码:视频指纹向量存储(使用 Milvus)
|
||||||
|
collection = "video_fingerprint"
|
||||||
|
schema = {
|
||||||
|
"fields": [
|
||||||
|
{"name": "id", "type": "INT64", "is_primary": True, "auto_id": True},
|
||||||
|
{"name": "avcc_code", "type": "VARCHAR", "max_length": 512},
|
||||||
|
{"name": "platform_node", "type": "VARCHAR", "max_length": 64},
|
||||||
|
{"name": "fingerprint", "type": "FLOAT_VECTOR", "dim": 256}, # 感知哈希向量
|
||||||
|
{"name": "content_hash", "type": "VARCHAR", "max_length": 128},
|
||||||
|
{"name": "created_at", "type": "INT64"} # 时间戳
|
||||||
|
]
|
||||||
|
}
|
||||||
|
index_params = {
|
||||||
|
"metric_type": "COSINE",
|
||||||
|
"index_type": "HNSW",
|
||||||
|
"params": {"M": 16, "efConstruction": 200}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.5.2 版权比对查询
|
||||||
|
|
||||||
|
```python
|
||||||
|
def search_similar_works(fingerprint_vector, top_k=10, threshold=0.85):
|
||||||
|
"""
|
||||||
|
检索相似作品,用于版权比对与重复检测
|
||||||
|
threshold: 相似度阈值,>0.85 视为疑似侵权
|
||||||
|
"""
|
||||||
|
results = milvus.search(
|
||||||
|
collection_name="video_fingerprint",
|
||||||
|
data=[fingerprint_vector],
|
||||||
|
anns_field="fingerprint",
|
||||||
|
param={"metric_type": "COSINE", "params": {"ef": 64}},
|
||||||
|
limit=top_k,
|
||||||
|
output_fields=["avcc_code", "platform_node", "content_hash"]
|
||||||
|
)
|
||||||
|
return [r for r in results if r.score > threshold]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3.6 对象存储目录结构(MinIO)
|
||||||
|
|
||||||
|
```
|
||||||
|
aigc-hub-storage/
|
||||||
|
├── works/
|
||||||
|
│ ├── raw/
|
||||||
|
│ │ └── {platform_node}/
|
||||||
|
│ │ └── {date}/
|
||||||
|
│ │ └── {avcc_code}/
|
||||||
|
│ │ ├── original.mp4 # 原始作品
|
||||||
|
│ │ ├── thumbnail.jpg # 缩略图
|
||||||
|
│ │ └── metadata.json # 元数据
|
||||||
|
│ ├── processed/
|
||||||
|
│ │ └── {avcc_code}/
|
||||||
|
│ │ ├── frames/ # 抽帧序列
|
||||||
|
│ │ ├── audio.wav # 音频分离
|
||||||
|
│ │ └── fingerprint.bin # 视频指纹
|
||||||
|
│ └── archived/
|
||||||
|
│ └── {year}/
|
||||||
|
│ └── {avcc_code}.tar.gz # 归档包
|
||||||
|
├── c2pa/
|
||||||
|
│ └── {avcc_code}.c2pa # C2PA 水印文件
|
||||||
|
├── certificates/
|
||||||
|
│ └── {avcc_code}.pdf # AVCC 证书 PDF
|
||||||
|
├── reports/
|
||||||
|
│ └── {avcc_code}/
|
||||||
|
│ ├── ai_review_report.pdf
|
||||||
|
│ └── human_review_report.pdf
|
||||||
|
├── evidence/
|
||||||
|
│ └── {case_id}/
|
||||||
|
│ ├── complaint.pdf
|
||||||
|
│ └── investigation/
|
||||||
|
└── backups/
|
||||||
|
└── daily/
|
||||||
|
└── {date}.sql.gz # PG 备份
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3.7 数据库高可用与灾备
|
||||||
|
|
||||||
|
| 策略 | 实现方式 | RPO | RTO |
|
||||||
|
|------|----------|-----|-----|
|
||||||
|
| PostgreSQL | Patroni + etcd + 流复制(1主2从) | < 1s | < 30s |
|
||||||
|
| Redis | Cluster 模式,3主3从,自动故障转移 | 0 | < 10s |
|
||||||
|
| ClickHouse | 3节点副本,ReplicatedMergeTree | < 1min | < 5min |
|
||||||
|
| MinIO | 4节点纠删码,4+2配置 | 0 | < 1min |
|
||||||
|
| 区块链 | 联盟链多节点共识,5组织各1节点 | 0 | 共识自愈 |
|
||||||
|
| 跨可用区 | 主集群北京,备集群上海,异步同步 | < 5min | < 15min |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*上一章:[02-核心系统模块设计.md](02-核心系统模块设计.md)*
|
||||||
|
*下一章:[04-API接口设计.md](04-API接口设计.md)*
|
||||||
@@ -0,0 +1,793 @@
|
|||||||
|
# 第四章 API 接口设计
|
||||||
|
|
||||||
|
> 版本:V1.0
|
||||||
|
> 基于文档:《AIGC-Hub智视码(AVCC)体系建设方案 V2.0》
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4.1 统一接口规范
|
||||||
|
|
||||||
|
### 4.1.1 基础约定
|
||||||
|
|
||||||
|
| 项 | 规范 |
|
||||||
|
|----|------|
|
||||||
|
| 协议 | HTTPS,TLS 1.3 |
|
||||||
|
| 数据格式 | JSON (Content-Type: application/json) |
|
||||||
|
| 编码 | UTF-8 |
|
||||||
|
| 版本控制 | URL 路径中包含版本号,如 `/api/v1/...` |
|
||||||
|
| 时间格式 | RFC 3339 (ISO 8601),如 `2026-06-02T14:30:00+08:00` |
|
||||||
|
| 分页 | `limit` + `offset`,响应含 `total`, `has_more` |
|
||||||
|
| 空值 | `null`,不省略字段 |
|
||||||
|
|
||||||
|
### 4.1.2 鉴权机制
|
||||||
|
|
||||||
|
采用 **API Key + HMAC-SHA256 签名** 双因素鉴权。
|
||||||
|
|
||||||
|
**请求头格式:**
|
||||||
|
|
||||||
|
```http
|
||||||
|
Authorization: AIGHUB {api_key}:{signature}
|
||||||
|
X-AIGHUB-Timestamp: 1717312200
|
||||||
|
X-AIGHUB-Nonce: {uuid}
|
||||||
|
```
|
||||||
|
|
||||||
|
**签名算法示例(Go):**
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GenerateSignature(method, uri, bodyHash, timestamp, nonce, apiSecret string) string {
|
||||||
|
stringToSign := fmt.Sprintf("%s\n%s\n%s\n%s\n%s", method, uri, bodyHash, timestamp, nonce)
|
||||||
|
h := hmac.New(sha256.New, []byte(apiSecret))
|
||||||
|
h.Write([]byte(stringToSign))
|
||||||
|
return base64.StdEncoding.EncodeToString(h.Sum(nil))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.1.3 限流策略
|
||||||
|
|
||||||
|
| 平台类型 | 日配额 | QPS 限制 | 突发缓冲 |
|
||||||
|
|----------|--------|----------|----------|
|
||||||
|
| 长视频平台 | 100万 | 500 | 100 |
|
||||||
|
| 短视频平台 | 500万 | 2000 | 500 |
|
||||||
|
| AI 工具厂商 | 50万 | 200 | 50 |
|
||||||
|
| MCN 机构 | 10万 | 50 | 20 |
|
||||||
|
| 跨境平台 | 20万 | 100 | 30 |
|
||||||
|
|
||||||
|
**限流响应:**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error_code": "RATE_LIMIT_EXCEEDED",
|
||||||
|
"message": "Rate limit exceeded",
|
||||||
|
"retry_after": 60,
|
||||||
|
"quota_reset_at": "2026-06-03T00:00:00+08:00"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.1.4 统一响应格式
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": "SUCCESS",
|
||||||
|
"data": { ... },
|
||||||
|
"request_id": "req_20260602_001",
|
||||||
|
"timestamp": "2026-06-02T14:30:00+08:00"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**错误响应格式:**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": "ERROR_CODE",
|
||||||
|
"message": "人类可读的错误描述",
|
||||||
|
"detail": { ... },
|
||||||
|
"request_id": "req_20260602_001"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.1.5 错误码定义
|
||||||
|
|
||||||
|
| 错误码 | HTTP 状态码 | 说明 |
|
||||||
|
|--------|-------------|------|
|
||||||
|
| `SUCCESS` | 200 | 成功 |
|
||||||
|
| `CREATED` | 201 | 创建成功 |
|
||||||
|
| `ACCEPTED` | 202 | 异步任务已接收 |
|
||||||
|
| `INVALID_REQUEST` | 400 | 请求参数错误 |
|
||||||
|
| `UNAUTHORIZED` | 401 | 鉴权失败 |
|
||||||
|
| `FORBIDDEN` | 403 | 权限不足 |
|
||||||
|
| `NOT_FOUND` | 404 | 资源不存在 |
|
||||||
|
| `RATE_LIMIT_EXCEEDED` | 429 | 限流触发 |
|
||||||
|
| `INTERNAL_ERROR` | 500 | 内部错误 |
|
||||||
|
| `SERVICE_UNAVAILABLE` | 503 | 服务暂不可用 |
|
||||||
|
| `AVCC_INVALID` | 400 | AVCC 编码格式无效 |
|
||||||
|
| `AVCC_REVOKED` | 400 | AVCC 已被注销 |
|
||||||
|
| `LICENSE_EXPIRED` | 400 | 网标许可证已过期 |
|
||||||
|
| `BLACKLISTED` | 403 | 目标在黑名单中 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4.2 赋码服务接口
|
||||||
|
|
||||||
|
### 4.2.1 提交赋码申请
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/v1/code/apply
|
||||||
|
Authorization: AIGHUB {api_key}:{signature}
|
||||||
|
Content-Type: multipart/form-data
|
||||||
|
|
||||||
|
Request (multipart):
|
||||||
|
--boundary
|
||||||
|
Content-Disposition: form-data; name="metadata"
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"title": "AI漫剧标题",
|
||||||
|
"platform_node": "MA.156.10005.8361",
|
||||||
|
"object_category": "10.1300200.AIGC",
|
||||||
|
"content_type": "ai_drama",
|
||||||
|
"duration_sec": 1800,
|
||||||
|
"ai_tool_info": {
|
||||||
|
"model_name": "Stable-Diffusion-XL",
|
||||||
|
"model_version": "v1.0",
|
||||||
|
"sdk_version": "AIGC-Hub-SDK/1.0.0",
|
||||||
|
"manual_edit_ratio": 0.15
|
||||||
|
},
|
||||||
|
"copyright_materials": [
|
||||||
|
{"type": "training_data_license", "file_hash": "sha256:abc123...", "description": "训练数据授权书"},
|
||||||
|
{"type": "manual_edit_note", "file_hash": "sha256:def456...", "description": "人工修改说明"},
|
||||||
|
{"type": "ip_license", "file_hash": "sha256:ghi789...", "description": "原著改编授权书"}
|
||||||
|
],
|
||||||
|
"license_application": {
|
||||||
|
"license_type": "network_micro_drama",
|
||||||
|
"applying_province": "110000",
|
||||||
|
"is_key_content": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
--boundary
|
||||||
|
Content-Disposition: form-data; name="content"; filename="work.mp4"
|
||||||
|
Content-Type: video/mp4
|
||||||
|
|
||||||
|
[binary content]
|
||||||
|
|
||||||
|
--boundary
|
||||||
|
Content-Disposition: form-data; name="c2pa_manifest"; filename="manifest.json"
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
[binary content]
|
||||||
|
--boundary--
|
||||||
|
|
||||||
|
Response (202 Accepted):
|
||||||
|
{
|
||||||
|
"code": "ACCEPTED",
|
||||||
|
"data": {
|
||||||
|
"request_id": "req_20260602_001",
|
||||||
|
"status": "pre_checking",
|
||||||
|
"estimated_time": "5-30工作日",
|
||||||
|
"check_list": {
|
||||||
|
"duplicate": "pending",
|
||||||
|
"blacklist": "pending",
|
||||||
|
"material_complete": "pending"
|
||||||
|
},
|
||||||
|
"tracking_url": "https://aigc-hub.cn/workbench/code/status/req_20260602_001"
|
||||||
|
},
|
||||||
|
"request_id": "req_20260602_001"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.2.2 查询赋码进度
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/v1/code/status/{request_id}
|
||||||
|
|
||||||
|
Response:
|
||||||
|
{
|
||||||
|
"code": "SUCCESS",
|
||||||
|
"data": {
|
||||||
|
"request_id": "req_20260602_001",
|
||||||
|
"status": "ai_reviewing",
|
||||||
|
"progress": 45,
|
||||||
|
"avcc": null,
|
||||||
|
"review_report_id": "rpt_20260602_001",
|
||||||
|
"check_list": {
|
||||||
|
"duplicate": "passed",
|
||||||
|
"blacklist": "passed",
|
||||||
|
"material_complete": "passed"
|
||||||
|
},
|
||||||
|
"current_stage": "AI 画面审核中 (12/30帧)",
|
||||||
|
"estimated_completion": "2026-06-05T10:00:00+08:00"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.2.3 获取 AVCC 证书
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/v1/code/certificate/{avcc_code}
|
||||||
|
|
||||||
|
Response:
|
||||||
|
{
|
||||||
|
"code": "SUCCESS",
|
||||||
|
"data": {
|
||||||
|
"avcc": "MA.156.10005.8361/10.1300200.AIGC/(京)网微剧审字(2026)第001号-P-AI-HASH(a1b2c3)-CRD(0x7f3e9a)",
|
||||||
|
"qr_code_url": "https://aigc-hub.cn/q/MA.156.10005.8361...",
|
||||||
|
"certificate_pdf_url": "https://aigc-hub.cn/cert/...",
|
||||||
|
"certificate_png_url": "https://aigc-hub.cn/cert/...png",
|
||||||
|
"chain_tx_hash": "0xabc123...",
|
||||||
|
"valid_until": "2028-05-31T23:59:59+08:00",
|
||||||
|
"circulation_rights": {
|
||||||
|
"scope": "全网全平台首页推荐",
|
||||||
|
"restrictions": [],
|
||||||
|
"expires_at": "2028-05-31T23:59:59+08:00"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.2.4 批量赋码申请(MCN)
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/v1/code/apply/batch
|
||||||
|
Content-Type: multipart/form-data
|
||||||
|
|
||||||
|
Request:
|
||||||
|
{
|
||||||
|
"batch_name": "2026年6月第二批",
|
||||||
|
"platform_node": "MA.156.10005.8361",
|
||||||
|
"works": [
|
||||||
|
{
|
||||||
|
"index": 1,
|
||||||
|
"title": "作品1",
|
||||||
|
"object_category": "10.1300200.AIGC",
|
||||||
|
"metadata": { ... }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": 2,
|
||||||
|
"title": "作品2",
|
||||||
|
"object_category": "10.1300200.AIGC",
|
||||||
|
"metadata": { ... }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
+ file: batch.zip (包含所有作品内容与 C2PA 文件)
|
||||||
|
|
||||||
|
Response (202 Accepted):
|
||||||
|
{
|
||||||
|
"code": "ACCEPTED",
|
||||||
|
"data": {
|
||||||
|
"batch_id": "batch_20260602_001",
|
||||||
|
"total": 50,
|
||||||
|
"accepted": 50,
|
||||||
|
"request_ids": ["req_20260602_002", "req_20260602_003", ...]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4.3 审核服务接口
|
||||||
|
|
||||||
|
### 4.3.1 AI 预审接口(实时提交)
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/v1/review/ai-screen
|
||||||
|
|
||||||
|
Request:
|
||||||
|
{
|
||||||
|
"content_url": "https://storage.aigc-hub.cn/works/xxx.mp4",
|
||||||
|
"content_hash": "sha256:abc123...",
|
||||||
|
"content_type": "ai_drama",
|
||||||
|
"duration_sec": 1800,
|
||||||
|
"callback_url": "https://platform.example.com/cb/review",
|
||||||
|
"priority": 5,
|
||||||
|
"requested_level": "G"
|
||||||
|
}
|
||||||
|
|
||||||
|
Response (202 Accepted):
|
||||||
|
{
|
||||||
|
"code": "ACCEPTED",
|
||||||
|
"data": {
|
||||||
|
"task_id": "task_20260602_001",
|
||||||
|
"status": "queued",
|
||||||
|
"queue_position": 15,
|
||||||
|
"estimated_seconds": 120
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.3.2 获取预审报告
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/v1/review/report/{task_id}
|
||||||
|
|
||||||
|
Response:
|
||||||
|
{
|
||||||
|
"code": "SUCCESS",
|
||||||
|
"data": {
|
||||||
|
"task_id": "task_20260602_001",
|
||||||
|
"status": "completed",
|
||||||
|
"overall_score": 78.5,
|
||||||
|
"suggested_level": "G",
|
||||||
|
"final_level": null,
|
||||||
|
"dimension_scores": {
|
||||||
|
"vision": 82.0,
|
||||||
|
"dialogue": 75.0,
|
||||||
|
"audio": 88.0,
|
||||||
|
"authenticity": 90.0,
|
||||||
|
"copyright": 95.0
|
||||||
|
},
|
||||||
|
"violations": [
|
||||||
|
{
|
||||||
|
"type": "dialogue",
|
||||||
|
"line": 23,
|
||||||
|
"timestamp": "00:05:30",
|
||||||
|
"severity": "medium",
|
||||||
|
"keyword": "敏感词示例",
|
||||||
|
"context": "台词上下文片段",
|
||||||
|
"suggestion": "建议替换为 xxx"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "vision",
|
||||||
|
"timestamp": "00:02:15",
|
||||||
|
"frame": 3450,
|
||||||
|
"severity": "low",
|
||||||
|
"category": "血腥画面",
|
||||||
|
"confidence": 0.72,
|
||||||
|
"bbox": [120, 200, 300, 400],
|
||||||
|
"suggestion": "建议打码或删减 0:02:10-0:02:20"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"model_details": {
|
||||||
|
"vision_model": "review-vision-v2.1",
|
||||||
|
"nlp_model": "review-nlp-v2.0",
|
||||||
|
"audio_model": "review-audio-v1.5",
|
||||||
|
"authenticity_model": "review-aigc-v3.0"
|
||||||
|
},
|
||||||
|
"report_url": "https://aigc-hub.cn/reports/task_20260602_001.pdf",
|
||||||
|
"ai_model_version": "review-v2.1.0-20260601",
|
||||||
|
"processing_time": {
|
||||||
|
"queue_wait_ms": 1200,
|
||||||
|
"preprocess_ms": 3000,
|
||||||
|
"inference_ms": 38000,
|
||||||
|
"fusion_ms": 500,
|
||||||
|
"total_ms": 45230
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.3.3 人工审核提交(平台人工复核)
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/v1/review/human-submit
|
||||||
|
|
||||||
|
Request:
|
||||||
|
{
|
||||||
|
"task_id": "task_20260602_001",
|
||||||
|
"reviewer_id": "reviewer_001",
|
||||||
|
"final_level": "G",
|
||||||
|
"decision": "approved",
|
||||||
|
"comment": "AI 预审中标记的敏感词经人工复核为误报,已确认台词语境合规。",
|
||||||
|
"violation_corrections": [
|
||||||
|
{"index": 0, "action": "overridden", "reason": "语境合规"}
|
||||||
|
],
|
||||||
|
"signature_hash": "sha256:..."
|
||||||
|
}
|
||||||
|
|
||||||
|
Response:
|
||||||
|
{
|
||||||
|
"code": "SUCCESS",
|
||||||
|
"data": {
|
||||||
|
"review_id": "rpt_20260602_001",
|
||||||
|
"status": "approved",
|
||||||
|
"avcc": "MA.156.10005.8361/10.1300200.AIGC/(沪)网微剧审字(2026)第0158号-G-AI-HASH(b2c3d4)-CRD(0x8g4f0b)",
|
||||||
|
"chain_tx_hash": "0xhuman123..."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4.4 MA 编码网关接口
|
||||||
|
|
||||||
|
### 4.4.1 AVCC 解析
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/v1/avcc/parse
|
||||||
|
|
||||||
|
Request:
|
||||||
|
{
|
||||||
|
"avcc": "MA.156.10005.8361/10.1300200.AIGC/(京)网微剧审字(2026)第001号-P-AI-HASH(a1b2c3)-CRD(0x7f3e9a)",
|
||||||
|
"include_chain_records": true
|
||||||
|
}
|
||||||
|
|
||||||
|
Response:
|
||||||
|
{
|
||||||
|
"code": "SUCCESS",
|
||||||
|
"data": {
|
||||||
|
"valid": true,
|
||||||
|
"ma_verified": true,
|
||||||
|
"parsed": {
|
||||||
|
"ma_root": "MA",
|
||||||
|
"country_code": "156",
|
||||||
|
"industry_node": "10005",
|
||||||
|
"platform_node": "8361",
|
||||||
|
"object_category": "10.1300200.AIGC",
|
||||||
|
"license_no": "(京)网微剧审字(2026)第001号",
|
||||||
|
"review_level": "P",
|
||||||
|
"version": 1,
|
||||||
|
"ai_hash": "a1b2c3",
|
||||||
|
"copyright_crd": "0x7f3e9a"
|
||||||
|
},
|
||||||
|
"circulation_rights": {
|
||||||
|
"scope": "全网全平台首页推荐",
|
||||||
|
"restrictions": [],
|
||||||
|
"prohibited_actions": [],
|
||||||
|
"expires_at": "2028-05-31T23:59:59+08:00"
|
||||||
|
},
|
||||||
|
"platform_info": {
|
||||||
|
"platform_node": "8361",
|
||||||
|
"platform_name": "示例长视频平台",
|
||||||
|
"platform_type": "long_video",
|
||||||
|
"status": "active"
|
||||||
|
},
|
||||||
|
"chain_records": [
|
||||||
|
{
|
||||||
|
"type": "copyright_main",
|
||||||
|
"tx_hash": "0xabc...",
|
||||||
|
"block_height": 1234567,
|
||||||
|
"timestamp": "2026-05-20T10:00:00+08:00",
|
||||||
|
"confirmation_count": 12
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"blacklist_check": "passed"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.4.2 校验 AVCC 有效性
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/v1/avcc/validate
|
||||||
|
|
||||||
|
Request:
|
||||||
|
{
|
||||||
|
"avcc": "MA.156.10005.8361/10.1300200.AIGC/...",
|
||||||
|
"strict": true
|
||||||
|
}
|
||||||
|
|
||||||
|
Response:
|
||||||
|
{
|
||||||
|
"code": "SUCCESS",
|
||||||
|
"data": {
|
||||||
|
"valid": true,
|
||||||
|
"ma_root_valid": true,
|
||||||
|
"license_valid": true,
|
||||||
|
"chain_valid": true,
|
||||||
|
"circulation_active": true,
|
||||||
|
"blacklist_check": "passed",
|
||||||
|
"expiration_status": "active",
|
||||||
|
"warnings": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.4.3 对接 MA 根解析
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/v1/avcc/resolve
|
||||||
|
|
||||||
|
Request:
|
||||||
|
{
|
||||||
|
"avcc": "MA.156.10005.8361/10.1300200.AIGC/...",
|
||||||
|
"resolution_depth": "full"
|
||||||
|
}
|
||||||
|
|
||||||
|
Response:
|
||||||
|
{
|
||||||
|
"code": "SUCCESS",
|
||||||
|
"data": {
|
||||||
|
"avcc": "MA.156.10005.8361/10.1300200.AIGC/...",
|
||||||
|
"ma_resolution": {
|
||||||
|
"root_node": "MA (ZIIOT)",
|
||||||
|
"country_node": "MA.156 (中国)",
|
||||||
|
"industry_node": "MA.156.10005 (AIGC视听内容行业节点 - 广电云)",
|
||||||
|
"platform_node": "MA.156.10005.8361 (示例平台)",
|
||||||
|
"resolution_path": ["MA", "156", "10005", "8361"],
|
||||||
|
"trust_level": "verified",
|
||||||
|
"last_verified": "2026-06-02T14:30:00+08:00"
|
||||||
|
},
|
||||||
|
"global_status": "active",
|
||||||
|
"cross_platform_rights": {
|
||||||
|
"domestic": ["douyin", "bilibili", "kuaishou", "xiaohongshu"],
|
||||||
|
"international": ["pending"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.4.4 平台节点注册(内部接口)
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/v1/node/register
|
||||||
|
Authorization: AIGHUB {internal_key}:{signature}
|
||||||
|
|
||||||
|
Request:
|
||||||
|
{
|
||||||
|
"platform_name": "示例短视频平台",
|
||||||
|
"platform_type": "short_video",
|
||||||
|
"enterprise_name": "示例科技有限公司",
|
||||||
|
"enterprise_credit_code": "91110108MA00xxxx",
|
||||||
|
"contact_name": "张三",
|
||||||
|
"contact_phone": "13800138000",
|
||||||
|
"contact_email": "admin@example.com",
|
||||||
|
"callback_url": "https://api.example.com/aigc-hub/cb",
|
||||||
|
"quota_request": {
|
||||||
|
"daily_calls": 5000000,
|
||||||
|
"peak_qps": 2000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Response:
|
||||||
|
{
|
||||||
|
"code": "SUCCESS",
|
||||||
|
"data": {
|
||||||
|
"platform_id": 42,
|
||||||
|
"ma_node_code": "MA.156.10005.8362",
|
||||||
|
"api_key": "ak_live_xxxxxx",
|
||||||
|
"api_secret": "as_live_xxxxxx",
|
||||||
|
"status": "pending_activation",
|
||||||
|
"activation_url": "https://aigc-hub.cn/activate/xxx"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4.5 版权链与清算接口
|
||||||
|
|
||||||
|
### 4.5.1 版权登记
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/v1/chain/copyright/register
|
||||||
|
|
||||||
|
Request:
|
||||||
|
{
|
||||||
|
"avcc": "MA.156.10005.8361/10.1300200.AIGC/...",
|
||||||
|
"content_hash": "sha256:...",
|
||||||
|
"license_doc_hashes": ["sha256:...", "sha256:..."],
|
||||||
|
"right_holders": [
|
||||||
|
{"type": "creator", "address": "0xCreator...", "share": 4000},
|
||||||
|
{"type": "model", "address": "0xModel...", "share": 1500},
|
||||||
|
{"type": "ip", "address": "0xIP...", "share": 1000},
|
||||||
|
{"type": "platform", "address": "0xPlatform...", "share": 3000}
|
||||||
|
],
|
||||||
|
"smart_contract_params": {
|
||||||
|
"auto_settle": true,
|
||||||
|
"settle_cycle": "monthly",
|
||||||
|
"min_settle_amount": 10000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Response:
|
||||||
|
{
|
||||||
|
"code": "SUCCESS",
|
||||||
|
"data": {
|
||||||
|
"tx_hash": "0xchain123...",
|
||||||
|
"block_height": 1234567,
|
||||||
|
"crd_address": "0x7f3e9a...",
|
||||||
|
"status": "confirmed",
|
||||||
|
"confirm_time": "2026-06-02T14:30:00+08:00",
|
||||||
|
"confirmation_count": 6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.5.2 跨平台权益记录
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/v1/chain/user-rights/record
|
||||||
|
|
||||||
|
Request:
|
||||||
|
{
|
||||||
|
"avcc": "MA.156.10005.8361/10.1300200.AIGC/...",
|
||||||
|
"user_hash": "sha256:user001",
|
||||||
|
"purchase_platform": "MA.156.10005.8361",
|
||||||
|
"purchase_time": "2026-06-01T10:00:00+08:00",
|
||||||
|
"expiry_time": "2027-06-01T10:00:00+08:00",
|
||||||
|
"price_paid": 15.00,
|
||||||
|
"currency": "CNY",
|
||||||
|
"rights_type": "play",
|
||||||
|
"order_id": "order_20260601_001"
|
||||||
|
}
|
||||||
|
|
||||||
|
Response:
|
||||||
|
{
|
||||||
|
"code": "SUCCESS",
|
||||||
|
"data": {
|
||||||
|
"tx_hash": "0xrights456...",
|
||||||
|
"status": "confirmed",
|
||||||
|
"rights_id": "ur_20260601_001"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.5.3 跨平台权益验证
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/v1/chain/user-rights/verify
|
||||||
|
|
||||||
|
Request:
|
||||||
|
{
|
||||||
|
"avcc": "MA.156.10005.8361/10.1300200.AIGC/...",
|
||||||
|
"user_hash": "sha256:user001",
|
||||||
|
"current_platform": "MA.156.10005.8362",
|
||||||
|
"rights_type": "play"
|
||||||
|
}
|
||||||
|
|
||||||
|
Response:
|
||||||
|
{
|
||||||
|
"code": "SUCCESS",
|
||||||
|
"data": {
|
||||||
|
"valid": true,
|
||||||
|
"purchase_platform": "MA.156.10005.8361",
|
||||||
|
"purchase_time": "2026-06-01T10:00:00+08:00",
|
||||||
|
"expiry_time": "2027-06-01T10:00:00+08:00",
|
||||||
|
"rights_type": "play",
|
||||||
|
"remaining_plays": null,
|
||||||
|
"transfer_count": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.5.4 查询分账记录
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/v1/chain/settlement/query?avcc={avcc_code}&platform_id={pid}&period_start=2026-05-01&period_end=2026-05-31
|
||||||
|
|
||||||
|
Response:
|
||||||
|
{
|
||||||
|
"code": "SUCCESS",
|
||||||
|
"data": {
|
||||||
|
"total_revenue": 125000.00,
|
||||||
|
"settlements": [
|
||||||
|
{
|
||||||
|
"period": "2026-05",
|
||||||
|
"platform_id": "8361",
|
||||||
|
"platform_name": "抖音",
|
||||||
|
"total_revenue": 80000.00,
|
||||||
|
"creator_share": 32000.00,
|
||||||
|
"platform_share": 24000.00,
|
||||||
|
"model_share": 12000.00,
|
||||||
|
"ip_share": 8000.00,
|
||||||
|
"hub_fee": 4800.00,
|
||||||
|
"status": "settled",
|
||||||
|
"tx_hash": "0xsettle001...",
|
||||||
|
"settled_at": "2026-06-05T10:00:00+08:00"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"summary": {
|
||||||
|
"total_settled": 1,
|
||||||
|
"total_pending": 0,
|
||||||
|
"total_disputed": 0,
|
||||||
|
"total_amount": 125000.00
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4.6 数据回传接口(平台 → 广电云)
|
||||||
|
|
||||||
|
### 4.6.1 播放数据回传
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/v1/data/playback
|
||||||
|
|
||||||
|
Request:
|
||||||
|
{
|
||||||
|
"platform_id": "8361",
|
||||||
|
"batch": [
|
||||||
|
{
|
||||||
|
"avcc": "MA.156.10005.8361/10.1300200.AIGC/...",
|
||||||
|
"event_type": "play",
|
||||||
|
"user_hash": "sha256:xxx",
|
||||||
|
"event_time": "2026-06-02T14:30:00+08:00",
|
||||||
|
"duration_sec": 1800,
|
||||||
|
"device_type": "mobile",
|
||||||
|
"province": "110000"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
Response:
|
||||||
|
{
|
||||||
|
"code": "SUCCESS",
|
||||||
|
"data": {
|
||||||
|
"accepted": 1000,
|
||||||
|
"rejected": 0,
|
||||||
|
"batch_id": "pb_20260602_001"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.6.2 处置记录回传
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/v1/data/disposition
|
||||||
|
|
||||||
|
Request:
|
||||||
|
{
|
||||||
|
"platform_id": "8361",
|
||||||
|
"avcc": "MA.156.10005.8361/10.1300200.AIGC/...",
|
||||||
|
"action": "removed",
|
||||||
|
"reason": "用户投诉侵权",
|
||||||
|
"disposition_time": "2026-06-02T14:30:00+08:00",
|
||||||
|
"operator": "system"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4.7 监管接口(广电云 → 广电总局)
|
||||||
|
|
||||||
|
### 4.7.1 数据上报
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/v1/regulatory/report
|
||||||
|
Authorization: AIGHUB {regulatory_key}:{signature}
|
||||||
|
|
||||||
|
Request:
|
||||||
|
{
|
||||||
|
"report_type": "daily_summary",
|
||||||
|
"date": "2026-06-02",
|
||||||
|
"data": {
|
||||||
|
"total_registered": 1523,
|
||||||
|
"total_reviewed": 1200,
|
||||||
|
"level_distribution": {"P": 50, "G": 450, "O": 700},
|
||||||
|
"platform_activity": [
|
||||||
|
{"platform": "抖音", "new_works": 500, "removed": 12},
|
||||||
|
{"platform": "B站", "new_works": 200, "removed": 3}
|
||||||
|
],
|
||||||
|
"blacklist_updates": 2,
|
||||||
|
"compliance_alerts": 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.7.2 黑名单同步
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/v1/regulatory/blacklist/sync
|
||||||
|
|
||||||
|
Response:
|
||||||
|
{
|
||||||
|
"code": "SUCCESS",
|
||||||
|
"data": {
|
||||||
|
"updated_at": "2026-06-02T14:30:00+08:00",
|
||||||
|
"total_entries": 156,
|
||||||
|
"new_entries": 3,
|
||||||
|
"categories": {
|
||||||
|
"creator": 45,
|
||||||
|
"platform": 2,
|
||||||
|
"model": 23,
|
||||||
|
"dataset": 12,
|
||||||
|
"content": 74
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*上一章:[03-数据库与数据模型.md](03-数据库与数据模型.md)*
|
||||||
|
*下一章:[05-部署与运维架构.md](05-部署与运维架构.md)*
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
# 第五章 部署与运维架构
|
||||||
|
|
||||||
|
> 版本:V1.0
|
||||||
|
> 基于文档:《AIGC-Hub智视码(AVCC)体系建设方案 V2.0》
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5.1 Kubernetes 部署拓扑
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 广电云 K8s 集群 (等保三级 VPC) │
|
||||||
|
│ ┌──────────────────────────────────────────────────────────┐ │
|
||||||
|
│ │ Ingress Controller (Kong/Nginx) │ │
|
||||||
|
│ │ TLS 1.3 终止, 3 replicas │ │
|
||||||
|
│ └──────────────────────────────────────────────────────────┘ │
|
||||||
|
│ │ │
|
||||||
|
│ ┌───────────────────────────▼──────────────────────────────┐ │
|
||||||
|
│ │ 微服务应用层 │ │
|
||||||
|
│ │ code-svc(5) review-svc(10) chain-svc(3) │ │
|
||||||
|
│ │ gateway-svc(5) settlement-svc(3) workbench-svc(3) │ │
|
||||||
|
│ │ callback-svc(3) regulatory-svc(2) │ │
|
||||||
|
│ └──────────────────────────────────────────────────────────┘ │
|
||||||
|
│ │ │
|
||||||
|
│ ┌───────────────────────────▼──────────────────────────────┐ │
|
||||||
|
│ │ 数据与中间件层 │ │
|
||||||
|
│ │ PostgreSQL(3) Redis(6) Kafka(3) ClickHouse(3) │ │
|
||||||
|
│ │ MinIO(4) Elasticsearch(3) Milvus(3) │ │
|
||||||
|
│ └──────────────────────────────────────────────────────────┘ │
|
||||||
|
│ │ │
|
||||||
|
│ ┌───────────────────────────▼──────────────────────────────┐ │
|
||||||
|
│ │ AI 推理与区块链层 │ │
|
||||||
|
│ │ Triton Server(GPU) ChainMaker(5) Prometheus+Grafana │ │
|
||||||
|
│ └──────────────────────────────────────────────────────────┘ │
|
||||||
|
└─────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5.2 一期试点资源预估
|
||||||
|
|
||||||
|
| 组件 | 实例规格 | 数量 | 说明 |
|
||||||
|
|------|----------|------|------|
|
||||||
|
| API 网关 | 4C8G | 3 | Kong |
|
||||||
|
| 微服务 Pod | 2C4G | 30 | 各服务副本合计 |
|
||||||
|
| PostgreSQL | 8C32G + 1TB SSD | 3 | 1主2从 + Patroni |
|
||||||
|
| Redis | 4C8G | 6 | 3主3从集群 |
|
||||||
|
| Kafka | 4C8G + 500GB | 3 | 3 Broker |
|
||||||
|
| ClickHouse | 8C16G + 2TB SSD | 3 | 分布式 |
|
||||||
|
| MinIO | 4C8G + 10TB | 4 | 4节点对象存储 |
|
||||||
|
| Triton Server | 8C32G + A10 GPU | 4 | AI 推理 |
|
||||||
|
| ChainMaker | 8C16G + 500GB | 5 | 5 组织节点 |
|
||||||
|
| Elasticsearch | 4C16G + 2TB | 3 | 日志存储 |
|
||||||
|
|
||||||
|
## 5.3 网络与安全域
|
||||||
|
|
||||||
|
| 安全域 | 组件 | 访问策略 |
|
||||||
|
|--------|------|----------|
|
||||||
|
| DMZ | Kong Ingress | 公网 443,WAF 防护 |
|
||||||
|
| 应用区 | 微服务 Pod | 仅内网,服务网格 mTLS |
|
||||||
|
| 数据区 | PG/Redis/Kafka | 应用区白名单,审计连接 |
|
||||||
|
| AI 推理区 | Triton Server | 应用区白名单,GPU 独占 |
|
||||||
|
| 区块链区 | ChainMaker | 专线/VPN,联盟组织互连 |
|
||||||
|
| 监管区 | regulatory-svc | 专线对接广电总局专网 |
|
||||||
|
|
||||||
|
## 5.4 高可用与灾备
|
||||||
|
|
||||||
|
| 策略 | 实现 | RPO | RTO |
|
||||||
|
|------|------|-----|-----|
|
||||||
|
| PG | Patroni + 流复制 | <1s | <30s |
|
||||||
|
| Redis | Cluster 自动故障转移 | 0 | <10s |
|
||||||
|
| ClickHouse | 副本 + ReplicatedMergeTree | <1min | <5min |
|
||||||
|
| MinIO | 纠删码 4+2 | 0 | <1min |
|
||||||
|
| 跨可用区 | 北京主 + 上海备(异步) | <5min | <15min |
|
||||||
|
|
||||||
|
## 5.5 监控告警体系
|
||||||
|
|
||||||
|
| 层级 | 工具 | 监控对象 |
|
||||||
|
|------|------|----------|
|
||||||
|
| 基础设施 | Prometheus + Node Exporter | CPU/内存/磁盘/网络/GPU |
|
||||||
|
| 应用指标 | Prometheus + Micrometer | QPS/延迟/错误率/饱和度 |
|
||||||
|
| 日志 | ELK / Loki | 全链路日志聚合 |
|
||||||
|
| 链路追踪 | Jaeger + OpenTelemetry | 分布式请求追踪 |
|
||||||
|
| 告警 | AlertManager + PagerDuty | 多通道分级告警 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*上一章:[04-API接口设计.md](04-API接口设计.md)*
|
||||||
|
*下一章:[06-安全设计.md](06-安全设计.md)*
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
# 第六章 安全设计
|
||||||
|
|
||||||
|
> 版本:V1.0
|
||||||
|
> 基于文档:《AIGC-Hub智视码(AVCC)体系建设方案 V2.0》
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6.1 等保三级合规框架
|
||||||
|
|
||||||
|
| 等保要求 | 落实措施 | 技术实现 |
|
||||||
|
|----------|----------|----------|
|
||||||
|
| **安全物理环境** | 广电云自有数据中心 + 等保三级机房 | 门禁、监控、冗余电力 |
|
||||||
|
| **安全通信网络** | 专线对接广电总局,公网 TLS 1.3 | Istio mTLS + WAF |
|
||||||
|
| **安全区域边界** | 分安全域(DMZ/应用/数据/AI/区块链/监管) | 网络策略 + 防火墙 |
|
||||||
|
| **安全计算环境** | 容器安全扫描、镜像签名、运行时防护 | Harbor + Falco |
|
||||||
|
| **安全管理中心** | 统一身份管理、集中审计、态势感知 | Vault + ELK + SIEM |
|
||||||
|
| **身份鉴别** | 多因素认证、最小权限、定期轮换 | RBAC + MFA + HMAC |
|
||||||
|
| **访问控制** | 零信任网络,细粒度授权 | OPA/Gatekeeper |
|
||||||
|
| **安全审计** | 全链路审计日志,不可篡改存储 | 审计链 + ELK |
|
||||||
|
| **数据安全** | 分类分级、加密存储、脱敏展示 | 国密 SM4 + 隐私计算 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6.2 数据加密策略
|
||||||
|
|
||||||
|
| 数据类型 | 传输加密 | 存储加密 | 密钥管理 |
|
||||||
|
|----------|----------|----------|----------|
|
||||||
|
| 用户敏感信息 | TLS 1.3 | SM4-CBC(字段级) | Vault 动态密钥 |
|
||||||
|
| 视频内容 | HTTPS | MinIO SSE-S3 | KMS 托管密钥 |
|
||||||
|
| C2PA 水印 | HTTPS | 无(公开凭证) | 签名私钥 HSM |
|
||||||
|
| 区块链数据 | TLS + mTLS | 链上原生加密 | HSM 托管 |
|
||||||
|
| 审核报告 | TLS 1.3 | SM4-GCM | Vault |
|
||||||
|
| API 密钥 | — | bcrypt/scrypt | Vault 自动生成 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6.3 隐私计算
|
||||||
|
|
||||||
|
针对创作者 prompt 和生成参数的隐私保护需求:
|
||||||
|
|
||||||
|
| 场景 | 技术方案 | 说明 |
|
||||||
|
|------|----------|------|
|
||||||
|
| prompt 保护 | 联邦学习 + 差分隐私 | 训练数据不上传,仅上传梯度 |
|
||||||
|
| 生成参数 | 多方安全计算 (MPC) | 参数分片计算,各方不见明文 |
|
||||||
|
| 版权比对 | 同态加密 + 安全求交 | 平台与版权方比对,不见原始指纹 |
|
||||||
|
| 链上存证 | 哈希上链,原文本地 | 仅 content_hash 上链,原文存 MinIO |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6.4 审计日志
|
||||||
|
|
||||||
|
| 审计事件 | 记录内容 | 存储位置 | 保留期限 |
|
||||||
|
|----------|----------|----------|----------|
|
||||||
|
| 赋码申请 | 申请人、时间、内容哈希、IP | PG + 审计链 | 10年 |
|
||||||
|
| 审核决策 | 审核员、AI 评分、违规明细 | PG + 审计链 | 10年 |
|
||||||
|
| API 调用 | 平台、接口、AVCC、耗时、结果 | ClickHouse + 审计链 | 5年 |
|
||||||
|
| 链上交易 | tx_hash、payload_hash、签名 | 联盟链 | 永久 |
|
||||||
|
| 管理员操作 | 操作人、时间、对象、变更前后 | PG + 审计链 | 10年 |
|
||||||
|
| 黑名单变更 | 操作人、目标、原因、证据 | 联盟链 | 永久 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6.5 安全事件响应
|
||||||
|
|
||||||
|
| 级别 | 事件类型 | 响应时间 | 处置措施 |
|
||||||
|
|------|----------|----------|----------|
|
||||||
|
| P0 | 数据泄露 / 核心密钥泄露 | 15分钟 | 立即熔断、通知监管、溯源取证 |
|
||||||
|
| P1 | 区块链节点异常 / 大规模 API 异常 | 30分钟 | 切换备用节点、限流、告警 |
|
||||||
|
| P2 | 单服务故障 / 审核队列堆积 | 2小时 | 自动扩缩容、人工介入 |
|
||||||
|
| P3 | 性能下降 / 非核心告警 | 24小时 | 排期优化、变更窗口 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*上一章:[05-部署与运维架构.md](05-部署与运维架构.md)*
|
||||||
|
*下一章:[07-分阶段实施路线图.md](07-分阶段实施路线图.md)*
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
# 第七章 分阶段实施路线图
|
||||||
|
|
||||||
|
> 版本:V1.0
|
||||||
|
> 基于文档:《AIGC-Hub智视码(AVCC)体系建设方案 V2.0》
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7.1 总体分期
|
||||||
|
|
||||||
|
| 阶段 | 时间 | 核心目标 |
|
||||||
|
|------|------|----------|
|
||||||
|
| **一期:筑基** | 0-6个月 | 与现行网标系统打通,完成 AVCC 规则制定;3-5家头部平台试点;向 ZIIOT 申请 MA.AIGC 行业节点 |
|
||||||
|
| **二期:贯通** | 6-12个月 | AIGC 全链路上链,发布 AI 工具 SDK;智能审核覆盖 80% 普通类;MA 行业节点正式运营 |
|
||||||
|
| **三期:生态** | 1-2年 | 推出中国 AIGC 片库统一入口;跨平台权益通兑;建立行业分账标准;MA 标识跨境应用 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7.2 一期:筑基(0-6 个月)
|
||||||
|
|
||||||
|
### 里程碑
|
||||||
|
- [ ] AVCC 六段式编码规则正式发布
|
||||||
|
- [ ] 赋码中心 V1.0 上线(支持 P/G/O 三类赋码)
|
||||||
|
- [ ] 3-5 家头部平台接入试点
|
||||||
|
- [ ] 向 ZIIOT 提交 MA.AIGC 行业节点申请
|
||||||
|
|
||||||
|
### 技术任务
|
||||||
|
|
||||||
|
| 任务 | 负责人 | 工期 | 依赖 |
|
||||||
|
|------|--------|------|------|
|
||||||
|
| K8s 集群搭建(等保三级 VPC) | 基础设施组 | 4周 | — |
|
||||||
|
| PostgreSQL + Redis + Kafka 部署 | 基础设施组 | 2周 | K8s |
|
||||||
|
| 赋码引擎 V1.0(编码生成 + 预检 + 分配) | 后端组 | 6周 | 数据库 |
|
||||||
|
| 审核引擎 V1.0(AI 预审 MVP:画面+台词) | AI组 | 8周 | GPU 节点 |
|
||||||
|
| MA 编码网关 V1.0(解析 + 校验 + 限流) | 后端组 | 4周 | 赋码引擎 |
|
||||||
|
| 创作者工作台 V1.0(赋码申请 + 进度查询) | 前端组 | 6周 | 赋码引擎 |
|
||||||
|
| C2PA SDK V1.0(Python 绑定 + 2个工具适配) | SDK组 | 6周 | — |
|
||||||
|
| 版权链 V1.0(版权登记 + 存证 + 查询) | 区块链组 | 8周 | ChainMaker |
|
||||||
|
| 等保三级测评准备 | 安全组 | 全程 | 全部 |
|
||||||
|
|
||||||
|
### 资源投入
|
||||||
|
- 研发团队:30人(后端10 + 前端5 + AI 8 + 区块链4 + 安全3)
|
||||||
|
- 云资源:等保三级 VPC,年预算约 500万
|
||||||
|
- GPU 节点:A10 x 4
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7.3 二期:贯通(6-12 个月)
|
||||||
|
|
||||||
|
### 里程碑
|
||||||
|
- [ ] AI 工具 SDK 正式发布(覆盖 10+ 主流工具)
|
||||||
|
- [ ] 版权链全链路贯通(创作 → 审核 → 分发 → 结算)
|
||||||
|
- [ ] 智能审核覆盖 80% 普通类内容
|
||||||
|
- [ ] MA 行业节点正式运营(MA.156.10005)
|
||||||
|
|
||||||
|
### 技术任务
|
||||||
|
|
||||||
|
| 任务 | 负责人 | 工期 | 依赖 |
|
||||||
|
|------|--------|------|------|
|
||||||
|
| 审核引擎 V2.0(+声音 + AIGC 真实性 + 版权比对) | AI组 | 10周 | 一期 |
|
||||||
|
| 清算引擎 V1.0(智能合约 + 分账结算) | 区块链组 | 8周 | 版权链 V1 |
|
||||||
|
| 创作者工作台 V2.0(+版权登记 + 分账查询) | 前端组 | 6周 | 清算引擎 |
|
||||||
|
| C2PA SDK V2.0(JS/Go 绑定 + 平台插件) | SDK组 | 8周 | SDK V1 |
|
||||||
|
| MA 编码网关 V2.0(+根解析对接 + 跨境解析) | 后端组 | 6周 | 网关 V1 |
|
||||||
|
| 数据回传服务 V1.0(播放数据 + 处置记录) | 后端组 | 4周 | — |
|
||||||
|
| 监管大屏 V1.0(数据上报 + 可视化) | 前端组 | 4周 | 数据回传 |
|
||||||
|
| 平台接入扩展(新增 10+ 平台) | 商务+技术 | 12周 | 网关 V2 |
|
||||||
|
|
||||||
|
### 资源投入
|
||||||
|
- 研发团队:40人(扩编10人:清算2 + SDK 3 + 商务技术5)
|
||||||
|
- 云资源扩展:年预算增至 800万
|
||||||
|
- GPU 节点扩展:A100 x 4(替换部分 A10)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7.4 三期:生态(1-2 年)
|
||||||
|
|
||||||
|
### 里程碑
|
||||||
|
- [ ] 中国 AIGC 片库统一入口上线
|
||||||
|
- [ ] 跨平台权益通兑全面运营
|
||||||
|
- [ ] 行业分账标准发布
|
||||||
|
- [ ] MA 标识跨境应用落地(首批 3 个海外平台)
|
||||||
|
|
||||||
|
### 技术任务
|
||||||
|
|
||||||
|
| 任务 | 负责人 | 工期 | 依赖 |
|
||||||
|
|------|--------|------|------|
|
||||||
|
| AIGC 片库统一入口(搜索 + 推荐 + 支付) | 前端+后端 | 16周 | 二期 |
|
||||||
|
| 跨平台权益通兑引擎 V2.0 | 区块链组 | 12周 | 清算 V1 |
|
||||||
|
| 数据运营平台 V1.0(白皮书 + 风险预警 + 效能报告) | 数据组 | 12周 | ClickHouse |
|
||||||
|
| MA 跨境解析网关 V1.0 | 后端组 | 8周 | ZIIOT 对接 |
|
||||||
|
| 创作者保险系统(过审险对接) | 后端组 | 8周 | 清算引擎 |
|
||||||
|
| 版权金融衍生系统(估值 + ABS) | 金融组 | 16周 | 清算 V2 |
|
||||||
|
| 智能报税系统 V1.0 | 后端组 | 8周 | 工作台 V2 |
|
||||||
|
| 全链路自动化运维(AIOps) | 运维组 | 持续 | 全量 |
|
||||||
|
|
||||||
|
### 资源投入
|
||||||
|
- 研发团队:50人(新增金融组5人 + 数据组5人)
|
||||||
|
- 云资源:年预算 1500万
|
||||||
|
- 运营成本:商务、客服、审核人力
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7.5 关键依赖与风险
|
||||||
|
|
||||||
|
| 风险 | 影响 | 应对 |
|
||||||
|
|------|------|------|
|
||||||
|
| MA 行业节点审批延迟 | 一期延期 1-2 个月 | 提前 3 个月提交申请材料,与 ZIIOT 保持密切沟通 |
|
||||||
|
| 平台接入意愿低 | 生态难以形成 | 广电总局政策引导 + 降低接入成本 + 利益绑定 |
|
||||||
|
| AI 审核准确率不足 | 普通类人工复核压力大 | 持续模型迭代 + A/B 测试 + 人机协同流程优化 |
|
||||||
|
| 区块链性能瓶颈 | 高并发场景延迟 | 联盟链分片 + 链下计算 + 批量上链 |
|
||||||
|
| 等保三级测评不过 | 无法正式上线 | 提前聘请测评机构预审 + 安全左移 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*上一章:[06-安全设计.md](06-安全设计.md)*
|
||||||
@@ -0,0 +1,193 @@
|
|||||||
|
# 第八章 核心业务时序图与状态机设计
|
||||||
|
|
||||||
|
> 版本:V1.0
|
||||||
|
> 基于文档:《AIGC-Hub智视码(AVCC)体系建设方案 V2.0》
|
||||||
|
|
||||||
|
本章主要面向研发团队,提供核心业务场景的交互时序图(Sequence Diagram)以及核心实体的状态机(State Machine)定义,支持开发阶段的接口对接与流程编码。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8.1 核心业务时序图
|
||||||
|
|
||||||
|
### 8.1.1 赋码全链路时序图(含审核与上链)
|
||||||
|
|
||||||
|
描述从创作者提交申请,到完成 AI 预审、版权上链并最终签发 AVCC 证书的全过程。
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
autonumber
|
||||||
|
actor Creator as 创作者(工作台)
|
||||||
|
participant CodeSvc as 赋码引擎(CodeSvc)
|
||||||
|
participant Kafka as 消息队列(Kafka)
|
||||||
|
participant ReviewSvc as 审核引擎(ReviewSvc)
|
||||||
|
participant ChainSvc as 版权链引擎(ChainSvc)
|
||||||
|
participant DB as 主数据库(PG)
|
||||||
|
|
||||||
|
Creator->>CodeSvc: 1. 提交赋码申请(视频+版权材料)
|
||||||
|
CodeSvc->>CodeSvc: 2. 预检(重复/黑名单/材料完整性)
|
||||||
|
CodeSvc->>DB: 3. 创建赋码记录(status=pre_checking)
|
||||||
|
CodeSvc-->>Creator: 4. 返回受理成功(202 Accepted)
|
||||||
|
|
||||||
|
CodeSvc->>Kafka: 5. 发布事件[topic.avcc.apply.created]
|
||||||
|
Kafka-->>ReviewSvc: 6. 消费事件,创建审核任务
|
||||||
|
ReviewSvc->>DB: 7. 更新状态(status=ai_reviewing)
|
||||||
|
|
||||||
|
rect rgb(240, 248, 255)
|
||||||
|
Note over ReviewSvc: 执行 AI 多模态审核
|
||||||
|
ReviewSvc->>ReviewSvc: 切片、多模型并行推理、融合决策
|
||||||
|
end
|
||||||
|
|
||||||
|
ReviewSvc->>DB: 8. 保存审核报告(review_reports)
|
||||||
|
ReviewSvc->>Kafka: 9. 发布事件[topic.review.task.finished]
|
||||||
|
|
||||||
|
Kafka-->>ChainSvc: 10. 消费事件,准备上链
|
||||||
|
ChainSvc->>ChainSvc: 11. 调用智能合约 RegisterCopyright
|
||||||
|
ChainSvc->>DB: 12. 保存链交易记录(chain_records)
|
||||||
|
ChainSvc->>Kafka: 13. 发布事件[topic.chain.tx.confirmed]
|
||||||
|
|
||||||
|
Kafka-->>CodeSvc: 14. 消费上链成功事件
|
||||||
|
CodeSvc->>CodeSvc: 15. 执行 GenerateAVCC 算法生成六段式编码
|
||||||
|
CodeSvc->>DB: 16. 更新赋码记录(status=approved, 填入AVCC)
|
||||||
|
|
||||||
|
Creator->>CodeSvc: 17. 轮询/查询进度
|
||||||
|
CodeSvc-->>Creator: 18. 返回 AVCC 证书信息
|
||||||
|
```
|
||||||
|
|
||||||
|
### 8.1.2 跨平台解析与鉴权时序图
|
||||||
|
|
||||||
|
描述第三方平台在分发作品前,如何通过 MA 网关验证流通权限。
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
autonumber
|
||||||
|
participant App as 平台客户端(App)
|
||||||
|
participant Platform as 平台后端
|
||||||
|
participant Gateway as MA网关(Gateway)
|
||||||
|
participant Redis as 缓存(Redis)
|
||||||
|
participant ZIIOT as MA全球根系统
|
||||||
|
|
||||||
|
App->>Platform: 1. 请求播放/分发某视频(附带AVCC)
|
||||||
|
Platform->>Gateway: 2. POST /api/v1/avcc/parse (附带API Key)
|
||||||
|
|
||||||
|
Gateway->>Gateway: 3. API Key 鉴权与限流检查
|
||||||
|
Gateway->>Redis: 4. 查询 AVCC 缓存
|
||||||
|
|
||||||
|
alt 缓存未命中
|
||||||
|
Gateway->>ZIIOT: 5. 调用根解析接口(可选, 严格模式)
|
||||||
|
ZIIOT-->>Gateway: 6. 返回根解析验证结果
|
||||||
|
Gateway->>Gateway: 7. 计算流通权限(如 P类/G类)
|
||||||
|
Gateway->>Redis: 8. 写入解析结果缓存(TTL=1h)
|
||||||
|
end
|
||||||
|
|
||||||
|
Gateway-->>Platform: 9. 返回解析结果与 circulation_rights
|
||||||
|
|
||||||
|
alt 权限校验通过
|
||||||
|
Platform-->>App: 10. 允许播放,下发视频流
|
||||||
|
else 权限校验失败(如:O类跨平台)
|
||||||
|
Platform-->>App: 11. 拒绝播放,下架处理
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
### 8.1.3 跨平台播放分账时序图
|
||||||
|
|
||||||
|
描述播放行为如何转化为链上的分账清算记录。
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
autonumber
|
||||||
|
participant Platform as 平台后端
|
||||||
|
participant Gateway as 广电云网关
|
||||||
|
participant ClickHouse as 时序数据库
|
||||||
|
participant Settlement as 清算引擎
|
||||||
|
participant ChainSvc as 智能合约(联盟链)
|
||||||
|
|
||||||
|
Platform->>Gateway: 1. 批量回传播放数据(Event: play)
|
||||||
|
Gateway->>Kafka: 2. 投递到[topic.playback.event]
|
||||||
|
Kafka-->>ClickHouse: 3. 消费入库,实时聚合
|
||||||
|
|
||||||
|
loop 每日/每月定时调度
|
||||||
|
Settlement->>ClickHouse: 4. 提取周期内各 AVCC 播放与收益汇总
|
||||||
|
Settlement->>ChainSvc: 5. 触发合约 ExecuteSettlement
|
||||||
|
ChainSvc->>ChainSvc: 6. 链上按比例分配(创作者/模型/IP/平台)
|
||||||
|
ChainSvc-->>Settlement: 7. 返回链上交易回执(tx_hash)
|
||||||
|
Settlement->>Settlement: 8. 更新 PostgreSQL(settlement_records)
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8.2 核心状态机定义
|
||||||
|
|
||||||
|
### 8.2.1 审核状态机 (`review_status`)
|
||||||
|
|
||||||
|
控制作品在赋码审批流程中的流转。
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
stateDiagram-v2
|
||||||
|
[*] --> pending: 提交申请
|
||||||
|
pending --> pre_checking: 开始预检
|
||||||
|
|
||||||
|
pre_checking --> ai_reviewing: 预检通过
|
||||||
|
pre_checking --> rejected: 预检失败(重复/黑名单)
|
||||||
|
|
||||||
|
ai_reviewing --> human_reviewing: 需人工复核(P类/合规边缘)
|
||||||
|
ai_reviewing --> approved: AI秒批通过(O类/合规高分)
|
||||||
|
ai_reviewing --> rejected: AI判定违规且不可修改
|
||||||
|
|
||||||
|
human_reviewing --> approved: 人工终审通过
|
||||||
|
human_reviewing --> rejected: 人工终审驳回
|
||||||
|
|
||||||
|
approved --> revoked: 事后发现侵权/违规(吊销)
|
||||||
|
|
||||||
|
rejected --> [*]
|
||||||
|
revoked --> [*]
|
||||||
|
```
|
||||||
|
|
||||||
|
**状态流转说明:**
|
||||||
|
- `pending` -> `pre_checking`:赋码引擎 (`code-pre-check`) 执行
|
||||||
|
- `pre_checking` -> `ai_reviewing`:触发 Kafka 消息交由审核引擎执行
|
||||||
|
- `ai_reviewing` -> `human_reviewing`:融合决策层判定 `suggested_level=P` 或置信度处于边缘区间时触发
|
||||||
|
- `approved`:触发生成 AVCC 和上链操作
|
||||||
|
|
||||||
|
### 8.2.2 流通状态机 (`circulation_status`)
|
||||||
|
|
||||||
|
控制已赋码作品在全网的合法流通权限。
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
stateDiagram-v2
|
||||||
|
[*] --> active: 获得AVCC证书
|
||||||
|
|
||||||
|
active --> suspended: 收到侵权投诉/配合调查
|
||||||
|
suspended --> active: 调查澄清,恢复流通
|
||||||
|
|
||||||
|
active --> revoked: 严重违规/黑名单/伪造授权
|
||||||
|
suspended --> revoked: 侵权坐实
|
||||||
|
|
||||||
|
active --> expired: 网标有效期结束
|
||||||
|
expired --> active: 续期申请通过
|
||||||
|
|
||||||
|
revoked --> [*]: 永久失效,MA根节点同步注销
|
||||||
|
```
|
||||||
|
|
||||||
|
**触发机制:**
|
||||||
|
- `active` -> `suspended`:由管理后台运营人员手工触发(对应 API `/api/v1/avcc/suspend`)
|
||||||
|
- `active` -> `expired`:定时任务每日扫描 `expires_at` 字段自动触发
|
||||||
|
- `active` -> `revoked`:广电总局下发黑名单指令,或 ZIIOT 根节点触发码资源回收
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8.3 并发与异常处理策略
|
||||||
|
|
||||||
|
### 8.3.1 分布式锁(防止并发重复赋码)
|
||||||
|
在 `CodeSvc` 分配 MA 码段时,必须加锁:
|
||||||
|
- **锁 Key**:`lock:allocate:{platform_node}`
|
||||||
|
- **机制**:Redis Redlock,持有锁期间从数据库/缓存中原子性获取最大序列号并 +1,生成完毕后释放锁。
|
||||||
|
|
||||||
|
### 8.3.2 失败补偿与 Saga 模式
|
||||||
|
针对图 8.1.1 中的长事务(跨越 Code, Review, Chain),采用 **基于事件的 Saga 模式**:
|
||||||
|
- 如果步骤 10-13(版权上链)失败,Kafka 会基于死信队列(DLQ)重试 3 次。
|
||||||
|
- 若 3 次均失败,触发**补偿事务**:`ChainSvc` 发布 `topic.chain.tx.failed`,`CodeSvc` 消费后将 `review_status` 置为 `failed`,并通知创作者重新提交。
|
||||||
|
|
||||||
|
### 8.3.3 幂等性设计
|
||||||
|
- 所有涉及到数据库更新(状态流转)的 Kafka 消费者,必须检查记录的 `version` 或当前状态。
|
||||||
|
- 例如:`UPDATE avcc_records SET status = 'approved' WHERE id = ? AND status = 'human_reviewing'`,避免重复消费导致状态错乱。
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
# 第九章 异步消息流转设计 (Kafka)
|
||||||
|
|
||||||
|
> 版本:V1.0
|
||||||
|
> 基于文档:《AIGC-Hub智视码(AVCC)体系建设方案 V2.0》
|
||||||
|
|
||||||
|
本章详细定义了 AIGC-Hub 系统内部基于 Apache Kafka 的异步事件驱动架构,包括 Topic 规划、消息体契约(Payload Schema)、生产者与消费者职责,以及可靠性保证机制。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9.1 Topic 规划总览
|
||||||
|
|
||||||
|
| Topic 名称 | 用途说明 | 分区数(建议) | 数据保留期 |
|
||||||
|
|------------|----------|--------------|------------|
|
||||||
|
| `topic.avcc.apply.created` | 赋码申请创建(预检通过后触发) | 6 | 7 天 |
|
||||||
|
| `topic.review.task.finished` | 审核任务完成(AI/人工审核出具结果后触发) | 12 | 7 天 |
|
||||||
|
| `topic.chain.tx.pending` | 准备上链事件(存证、分账指令) | 6 | 7 天 |
|
||||||
|
| `topic.chain.tx.confirmed` | 链上交易确认回执 | 6 | 30 天 |
|
||||||
|
| `topic.playback.event` | 平台播放与行为数据回传 | 24 | 3 天 |
|
||||||
|
| `topic.system.dlq` | 死信队列(所有消费者重试失败后路由至此) | 3 | 永久(人工处理) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9.2 核心事件契约定义 (Event Schema)
|
||||||
|
|
||||||
|
所有消息均采用 JSON 格式,统一包含外层 Envelope:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"event_id": "uuid", // 事件唯一标识,用于幂等
|
||||||
|
"timestamp": 1717312200000, // 毫秒时间戳
|
||||||
|
"source": "code-svc", // 发送方服务
|
||||||
|
"payload": { ... } // 业务数据
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9.2.1 赋码申请创建事件
|
||||||
|
- **Topic**: `topic.avcc.apply.created`
|
||||||
|
- **生产者**: `code-svc` (赋码引擎)
|
||||||
|
- **消费者**: `review-svc` (审核引擎)
|
||||||
|
|
||||||
|
**Payload 定义:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"request_id": "req_20260602_001",
|
||||||
|
"avcc_record_id": 10042,
|
||||||
|
"content_url": "s3://aigc-hub-storage/works/raw/...",
|
||||||
|
"content_hash": "sha256:abc123def456...",
|
||||||
|
"ai_tool_info": {
|
||||||
|
"model_name": "Stable-Diffusion-XL",
|
||||||
|
"model_version": "v1.0"
|
||||||
|
},
|
||||||
|
"priority": 5
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9.2.2 审核任务完成事件
|
||||||
|
- **Topic**: `topic.review.task.finished`
|
||||||
|
- **生产者**: `review-svc` (审核引擎)
|
||||||
|
- **消费者**: `chain-svc` (准备上链), `code-svc` (更新状态)
|
||||||
|
|
||||||
|
**Payload 定义:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"request_id": "req_20260602_001",
|
||||||
|
"avcc_record_id": 10042,
|
||||||
|
"review_report_id": 5001,
|
||||||
|
"decision": "approved", // approved / rejected / need_human
|
||||||
|
"final_level": "G", // P / G / O
|
||||||
|
"overall_score": 78.5,
|
||||||
|
"report_hash": "sha256:789ghi..."
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9.2.3 上链交易确认事件
|
||||||
|
- **Topic**: `topic.chain.tx.confirmed`
|
||||||
|
- **生产者**: `chain-svc` (版权链引擎)
|
||||||
|
- **消费者**: `code-svc` (生成AVCC), `settlement-svc` (更新清算状态)
|
||||||
|
|
||||||
|
**Payload 定义:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"avcc_record_id": 10042,
|
||||||
|
"chain_type": "copyright_main", // copyright_main / settlement
|
||||||
|
"tx_hash": "0xabc123...",
|
||||||
|
"block_height": 123456,
|
||||||
|
"status": "success",
|
||||||
|
"crd_address": "0x7f3e9a..."
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9.2.4 播放回传事件 (海量数据)
|
||||||
|
- **Topic**: `topic.playback.event`
|
||||||
|
- **生产者**: `gateway-svc` (数据回传 API 接收后发送)
|
||||||
|
- **消费者**: `clickhouse-sink` (存入时序数据库), `flink-job` (实时异常检测)
|
||||||
|
|
||||||
|
**Payload 定义:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"avcc_code": "MA.156.10005.8361/...",
|
||||||
|
"platform_node": "8361",
|
||||||
|
"user_hash": "sha256:user123",
|
||||||
|
"event_type": "play", // play / complete / purchase
|
||||||
|
"duration_sec": 1800,
|
||||||
|
"revenue_cny": 0.00
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9.3 可靠性与顺序保证机制
|
||||||
|
|
||||||
|
### 9.3.1 消息投递语义 (Delivery Semantics)
|
||||||
|
- **核心业务流**(申请、审核、上链):采用 **At-Least-Once**(至少一次)语义。
|
||||||
|
- 生产者配置:`acks=all`, `retries=Integer.MAX_VALUE`, `enable.idempotence=true`。
|
||||||
|
- 消费者处理必须保证幂等性(基于 DB 的 unique key 或 event_id 去重表)。
|
||||||
|
- **播放数据流**(海量统计):采用 **At-Most-Once / 高吞吐** 配置。
|
||||||
|
- 生产者配置:`acks=1`, `linger.ms=5`, `batch.size=64KB`,允许极小概率的数据丢失以换取极高吞吐。
|
||||||
|
|
||||||
|
### 9.3.2 局部顺序保证 (Ordering)
|
||||||
|
同一个 AVCC 作品的事件需要保序处理(例如先创建、后审核、再上链)。
|
||||||
|
- **策略**:在发送 `topic.avcc.*`, `topic.review.*`, `topic.chain.*` 时,指定 Kafka 消息的 **Key = `avcc_record_id`**。
|
||||||
|
- **效果**:同一个作品的所有生命周期事件会被路由到同一个 Partition,确保同一作品的状态流转严格有序。
|
||||||
|
|
||||||
|
### 9.3.3 失败重试与死信队列 (DLQ)
|
||||||
|
消费者处理失败(如依赖的第三方服务超时、数据库锁冲突)时的处理策略:
|
||||||
|
1. **内部重试**:消费者内部捕获非致命异常,执行指数退避重试(如 1s, 2s, 4s, 8s),最大重试 3 次。
|
||||||
|
2. **重试队列 (Retry Topic)**:若内部重试失败,将消息转发至 `topic.system.retry`,由专门的 Retry Consumer 延时消费(利用内存或单独逻辑处理延时)。
|
||||||
|
3. **死信队列 (DLQ)**:若重试队列依然失败,将其移入 `topic.system.dlq`,触发 P2 级告警。
|
||||||
|
4. **人工介入**:运营/开发人员通过后台界面查看 DLQ 消息,排查 bug 或脏数据后,可一键将消息重新注入原 Topic。
|
||||||
|
|
||||||
|
### 9.3.4 消费堆积监控
|
||||||
|
为确保 SLA(如 O类作品秒级赋码),配置严格的 Consumer Lag 告警:
|
||||||
|
- `topic.avcc.apply.created`:Lag > 1000 或持续时长 > 1分钟 -> 触发告警(自动扩容 `review-svc` Pod)。
|
||||||
|
- `topic.playback.event`:Lag > 50000 -> 触发告警(检查 ClickHouse 写入瓶颈)。
|
||||||
@@ -0,0 +1,167 @@
|
|||||||
|
# 第十章 C2PA 与第三方系统对接详细设计
|
||||||
|
|
||||||
|
> 版本:V1.0
|
||||||
|
> 基于文档:《AIGC-Hub智视码(AVCC)体系建设方案 V2.0》
|
||||||
|
|
||||||
|
本章详细定义了 AIGC-Hub 与外部系统(AI 工具、ZIIOT 根节点、联盟链底链)的底层对接实现逻辑,为 SDK 开发组和中间件开发组提供编码依据。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10.1 C2PA 水印 SDK 内部实现与工具对接
|
||||||
|
|
||||||
|
SDK 的核心目标是:在 AI 生成的图片/视频文件中,非破坏性地注入符合 C2PA 标准的元数据(Manifest),并包含 MA 专属扩展字段。
|
||||||
|
|
||||||
|
### 10.1.1 核心签名流程设计(基于 Rust c2pa-rs)
|
||||||
|
|
||||||
|
生成内容凭证的步骤:
|
||||||
|
|
||||||
|
1. **构造 Claim**:收集生成环境信息(模型名、工具版本、时间戳)。
|
||||||
|
2. **附加 Assertions**:
|
||||||
|
- 基础哈希断言 (`c2pa.hash.data`)
|
||||||
|
- 训练数据来源断言 (`c2pa.training-mining`)
|
||||||
|
- MA 专属断言 (`ma.avcc.fragment`)
|
||||||
|
3. **加载签名密钥**:使用广电云颁发的 CA 证书或创作者关联的证书。
|
||||||
|
4. **签名并嵌入**:计算文件哈希,用私钥对 Claim 签名,并将签名打包成 JUMBF 格式注入文件头部(如 MP4 的 `uuid` box 或 JPEG 的 `APP11` marker)。
|
||||||
|
|
||||||
|
### 10.1.2 AI 工具适配器 (Adapters) 实现逻辑
|
||||||
|
|
||||||
|
以最流行的开源生图工具 **Stable Diffusion WebUI (A1111)** 为例,实现对接扩展:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# 伪代码:sd-webui-aigchub-extension/scripts/c2pa_hook.py
|
||||||
|
import modules.scripts as scripts
|
||||||
|
from modules.processing import Processed
|
||||||
|
from aigc_hub_sdk import C2PAManifestBuilder, MAExtension
|
||||||
|
|
||||||
|
class AIGCHubScript(scripts.Script):
|
||||||
|
def title(self):
|
||||||
|
return "AIGC-Hub C2PA 自动打码"
|
||||||
|
|
||||||
|
def show(self, is_img2img):
|
||||||
|
return scripts.AlwaysVisible
|
||||||
|
|
||||||
|
def postprocess(self, p, processed: Processed, *args):
|
||||||
|
# 拦截生成后的图像
|
||||||
|
for i, image in enumerate(processed.images):
|
||||||
|
# 获取用户配置的 MA 节点代码
|
||||||
|
platform_node = get_user_ma_node()
|
||||||
|
|
||||||
|
# 构建 MA 扩展
|
||||||
|
ma_ext = MAExtension(
|
||||||
|
platform_node=platform_node,
|
||||||
|
object_category="10.1300200.AIGC",
|
||||||
|
model_name=p.sampler_name, # 记录采样器
|
||||||
|
model_version=p.sd_model_name, # 记录模型名
|
||||||
|
generation_log_hash=hash(p.prompt) # 记录 Prompt 哈希
|
||||||
|
)
|
||||||
|
|
||||||
|
# 注入 C2PA 水印并覆盖原图
|
||||||
|
image_path = processed.images_paths[i]
|
||||||
|
builder = C2PAManifestBuilder()
|
||||||
|
builder.add_assertion(ma_ext)
|
||||||
|
builder.embed_in_place(image_path, private_key=get_local_key())
|
||||||
|
```
|
||||||
|
|
||||||
|
针对**闭源云端工具(如 Runway/可灵)**,方案为:提供服务端 API,云端工具在渲染完成后,调用 AIGC-Hub 提供的 SDK 或 HTTP API 完成签名注入。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10.2 MA 根解析对接设计 (ZIIOT 对接)
|
||||||
|
|
||||||
|
广电云网关 (`gateway-svc`) 需要与 ZIIOT 全球根解析服务进行实时通信。
|
||||||
|
|
||||||
|
### 10.2.1 根解析协议与通信方式
|
||||||
|
|
||||||
|
- **协议**:遵循 ISO/IEC 15459 标准的 RESTful API 或 Handle System 协议。
|
||||||
|
- **寻址逻辑**:
|
||||||
|
当第三方请求解析 `MA.156.10005.8361/10...` 时:
|
||||||
|
1. `gateway-svc` 发现前缀 `MA.156.10005` 属于本节点,直接在本地 PostgreSQL/Redis 查询。
|
||||||
|
2. 如果平台请求验证 `MA.156.99999...` (其他行业节点),`gateway-svc` 将请求代理至 ZIIOT 根服务器。
|
||||||
|
|
||||||
|
### 10.2.2 根节点注册/同步逻辑
|
||||||
|
|
||||||
|
广电云需要将自己分配出去的三级节点(如各大平台的 `MA.156.10005.xxxx`)定期或实时同步给 ZIIOT,以保证全球解析的可达性。
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant Gateway as 广电云网关
|
||||||
|
participant ZIIOT as ZIIOT根系统
|
||||||
|
|
||||||
|
Note over Gateway, ZIIOT: 平台节点注册同步
|
||||||
|
Gateway->>ZIIOT: POST /api/v1/ma/sync_node
|
||||||
|
Note right of Gateway: payload: {"node": "MA.156.10005.8361", "resolve_url": "https://gateway.aigc-hub.cn/resolve/"}
|
||||||
|
ZIIOT-->>Gateway: 200 OK
|
||||||
|
|
||||||
|
Note over Gateway, ZIIOT: 违规码全网吊销
|
||||||
|
Gateway->>ZIIOT: POST /api/v1/ma/revoke
|
||||||
|
Note right of Gateway: payload: {"avcc": "MA...CRD(xxx)", "reason": "blacklisted"}
|
||||||
|
ZIIOT-->>Gateway: 200 OK (同步全球黑名单)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10.3 联盟链底层对接设计 (ChainMaker/Fabric)
|
||||||
|
|
||||||
|
`chain-svc` 作为区块链代理,负责屏蔽底链细节,向上层业务提供易用的 REST/gRPC 接口。
|
||||||
|
|
||||||
|
### 10.3.1 链服务架构
|
||||||
|
|
||||||
|
```text
|
||||||
|
[ Business Services: CodeSvc / SettlementSvc ]
|
||||||
|
│
|
||||||
|
REST / Kafka
|
||||||
|
▼
|
||||||
|
[ chain-svc (Go) ]
|
||||||
|
│
|
||||||
|
(交易拼装/签名/序列化)
|
||||||
|
│
|
||||||
|
[ ChainMaker Go SDK ]
|
||||||
|
│
|
||||||
|
gRPC
|
||||||
|
▼
|
||||||
|
[ ChainMaker Nodes (联盟网络) ]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 10.3.2 异步上链与确认机制
|
||||||
|
|
||||||
|
由于区块链共识(如 TBFT/Raft)存在延迟(通常秒级),不能同步阻塞业务请求。
|
||||||
|
|
||||||
|
**处理流程:**
|
||||||
|
1. 业务服务发送消息至 Kafka `topic.chain.tx.pending`。
|
||||||
|
2. `chain-svc` 消费消息,调用 SDK `InvokeContract` 发起交易。
|
||||||
|
3. `chain-svc` 收到同步返回的 `tx_id`,但这**并不代表上链成功**。
|
||||||
|
4. `chain-svc` 将 `tx_id` 写入本地表 `chain_records` (status=pending)。
|
||||||
|
5. `chain-svc` 启动一个**区块监听器 (Block Listener/Event Subscriber)**,订阅链上的新区块事件。
|
||||||
|
6. 当监听到该 `tx_id` 被打包进区块且交易有效时,更新本地表为 `confirmed`,并发送 `topic.chain.tx.confirmed` 消息。
|
||||||
|
|
||||||
|
**Go 代码示意(订阅事件):**
|
||||||
|
```go
|
||||||
|
// 监听链上合约事件
|
||||||
|
func SubscribeChainEvents() {
|
||||||
|
ctx := context.Background()
|
||||||
|
// 订阅 AIGC_Copyright 合约的 "RegisterSuccess" 事件
|
||||||
|
ch, err := chainClient.SubscribeContractEvent(ctx, "AIGC_Copyright", "RegisterSuccess")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case event := <-ch:
|
||||||
|
txId := event.TxId
|
||||||
|
payload := event.EventData
|
||||||
|
// 1. 更新数据库状态
|
||||||
|
db.UpdateChainRecordStatus(txId, "confirmed")
|
||||||
|
// 2. 发送 Kafka 消息通知 CodeSvc
|
||||||
|
kafkaProducer.Produce("topic.chain.tx.confirmed", buildMessage(txId, payload))
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 10.3.3 链上隐私与权限控制
|
||||||
|
|
||||||
|
- **明文不入链**:用户身份证号、敏感提示词(Prompt)、详细台词不能直接上链。上链的数据必须经过 SHA-256 哈希处理。
|
||||||
|
- **跨组织鉴权**:智能合约内必须判断交易发起者的公钥/证书。例如 `RecordUserRights`(记录跨平台购买)只能由授权的 `platform_node` 或广电云节点发起,创作者无权直接调用。
|
||||||
@@ -0,0 +1,181 @@
|
|||||||
|
# 第十一章 广电机顶盒生态与边缘算力赋能方案
|
||||||
|
|
||||||
|
> 版本:V1.0
|
||||||
|
> 编制日期:2026年6月
|
||||||
|
> 核心目标:盘活广电亿级家庭机顶盒资源,构建 AIGC-Hub 的去中心化算力与分发网络。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11.1 战略破局:从“被动终端”到“主动节点”
|
||||||
|
|
||||||
|
中国广电拥有超 2 亿的家庭机顶盒终端,这是中国最大的家庭边缘节点网络。在 AIGC-Hub 体系中,传统的机顶盒将从单纯的“电视播放器”升级为兼具 **“边缘算力节点、内容分发节点、Token 结算节点”** 的三位一体微枢纽。
|
||||||
|
|
||||||
|
这不仅大幅降低广电云总部的中心化算力与带宽成本,还为广电网络构建了独特的竞争壁垒,形成“中心云(AIGC-Hub) + 边缘网(机顶盒集群)”的算网融合生态。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11.2 机顶盒三大赋能场景设计
|
||||||
|
|
||||||
|
### 场景一:分布式边缘算力池(Edge AI 计算节点)
|
||||||
|
|
||||||
|
AIGC 时代最大的痛点是算力成本。虽然单台机顶盒算力微弱,但数以亿计的 ARM 芯片和 NPU 闲置算力聚合起来,将是一个庞大的算力池。
|
||||||
|
|
||||||
|
* **工作机制**:
|
||||||
|
* 在夜间或设备空闲时(如凌晨 2:00-6:00),AIGC-Hub 调度系统通过广电内网向机顶盒下发微型计算任务。
|
||||||
|
* **业务应用**:
|
||||||
|
1. **AI 预审辅助切片**:中心服务器将长视频分发到机顶盒集群,由机顶盒负责基础的视频抽帧、图片感知哈希(pHash)计算或音频指纹提取。将极度消耗 CPU 资源的预处理任务卸载到边缘。
|
||||||
|
2. **C2PA 水印批量验证**:大批量短视频的 C2PA 水印签名验证计算。
|
||||||
|
3. **大模型推理的闲时轮询**:对于非实时性要求的 AI 审核任务(如旧片库的重新审查),利用机顶盒 NPU/DSP 进行轻量级违规识别初筛。
|
||||||
|
|
||||||
|
### 场景二:AIGC 专属边缘 CDN(去中心化分发)
|
||||||
|
|
||||||
|
高质量 AIGC 视频(如 4K/8K AI 电影)对带宽压力极大。广电网络天然的组播、多播优势以及机顶盒的本地存储,是完美的 CDN 替代方案。
|
||||||
|
|
||||||
|
* **工作机制**:
|
||||||
|
* 机顶盒作为 IPFS(星际文件系统)/ PCDN 节点,利用其内置的 Flash/硬盘或外接硬盘存储 AIGC 内容切片。
|
||||||
|
* 用户在移动端/PC 端请求带有 AVCC 标识的 AI 漫剧时,网络会优先调度同小区或同城广电节点(其他用户的机顶盒)提供数据流。
|
||||||
|
* **结合 AVCC**:因为每一个 AIGC 视频的切片都有不可篡改的 AVCC 哈希值验证,所以通过不信任节点(别人的机顶盒)传输数据是安全的。这完美契合了 AIGC-Hub “码链同源” 的设计。
|
||||||
|
|
||||||
|
### 场景三:去中心化账本节点与 Token 分发器(DePIN 模式)
|
||||||
|
|
||||||
|
将 Web3 的 DePIN (去中心化物理基础设施网络) 模式引入广电生态,激励用户贡献算力与带宽。
|
||||||
|
|
||||||
|
* **广电积分/Token 体系(如:广电算力通证/视听积分)**:
|
||||||
|
* **贡献即挖矿**:当用户的机顶盒在闲时贡献了 CPU 算力(处理了多少个视频抽帧),或贡献了上行带宽(作为 PCDN 节点传输了多少 GB 数据),AIGC-Hub 清算引擎会自动向该机顶盒绑定的账户发放“视听积分”。
|
||||||
|
* **积分消耗场景**:
|
||||||
|
1. 兑换广电有线电视套餐、宽带费减免。
|
||||||
|
2. **(重点核心)购买 AIGC 内容**:用户可以直接使用积分兑换 AIGC-Hub 体系下收费 AI 漫剧的观影权(权益记录在 AVCC 的用户权益子链中)。
|
||||||
|
3. **打赏创作者**:用户可以将积分打赏给喜欢的 AI 漫剧创作者,创作者再将积分在广电云平台上变现或用于购买高阶的 AI 算力与赋码服务。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11.3 技术架构融合设计
|
||||||
|
|
||||||
|
在现有的 AIGC-Hub 架构(参见 `01-总体技术架构.md`)基础上,增加**边缘网关与调度中心**。
|
||||||
|
|
||||||
|
```text
|
||||||
|
┌─────────────────────────────────────────────────────────────┐
|
||||||
|
│ AIGC-Hub 中心云 (广电云总部) │
|
||||||
|
│ [赋码引擎] [审核引擎] [版权链(ChainMaker)] [清算引擎] │
|
||||||
|
│ │ │ │ │ │
|
||||||
|
│ └───────────┼────────────────┴────────────────┘ │
|
||||||
|
│ ▼ │
|
||||||
|
│ ┌──────────────────┐ │
|
||||||
|
│ │ 边缘调度中心 │ (新增:任务切分、分发、带宽统计) │
|
||||||
|
│ └────────┬─────────┘ │
|
||||||
|
└───────────────────┼─────────────────────────────────────────┘
|
||||||
|
│ 广电专网 / DVB 广播下发 / IP 双向网络
|
||||||
|
▼
|
||||||
|
┌─────────────────────────────────────────────────────────────┐
|
||||||
|
│ 边缘网络层 (广电家庭机顶盒集群) │
|
||||||
|
│ │
|
||||||
|
│ ┌────────────────┐ ┌────────────────┐ ┌───────────┐ │
|
||||||
|
│ │ 机顶盒节点 A │ │ 机顶盒节点 B │ │ 机顶盒 ...│ │
|
||||||
|
│ │ ├─ 计算Agent │ │ ├─ PCDN Agent │ │ │ │
|
||||||
|
│ │ ├─ PCDN Agent │ │ ├─ 钱包/积分SDK │ │ │ │
|
||||||
|
│ │ └─ 钱包/积分SDK │ │ └─ 闲时策略引擎 │ │ │ │
|
||||||
|
│ └────────────────┘ └────────────────┘ └───────────┘ │
|
||||||
|
└─────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 11.3.1 边缘计算框架选型
|
||||||
|
* **计算框架**:采用 KubeEdge 或 OpenYurt 等边缘计算框架,将机顶盒纳管为边缘计算节点。
|
||||||
|
* **任务下发**:针对低配机顶盒,可部署基于 WebAssembly (Wasm) 的沙箱环境,执行轻量级的抽帧、哈希计算脚本,保证安全与跨平台兼容。
|
||||||
|
|
||||||
|
### 11.3.2 链上结算融合
|
||||||
|
* 机顶盒的算力贡献证明(Proof of Work/Proof of Traffic)经过调度中心汇总后,**批量上链**至版权链的清算合约中。
|
||||||
|
* 原有的跨平台清算引擎增加一个**“算力激励池”**,从 AIGC 商业化总收入的广电云手续费(6%-8%)中拨出 1%-2% 注入激励池,作为支撑整个机顶盒积分体系流转的价值锚。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11.4 具体技术实现细节
|
||||||
|
|
||||||
|
### 11.4.1 边缘算力调度引擎实现
|
||||||
|
边缘算力调度基于 **KubeEdge** 或类似边缘原生架构,核心分为云端(CloudCore)与边缘端(EdgeCore)。
|
||||||
|
* **任务沙箱(WebAssembly)**:考虑到机顶盒操作系统的异构性(Android、Linux)与安全性要求,所有下发的 AI 预处理计算任务均被编译为 WebAssembly (Wasm) 格式。例如,使用 Rust 编写视频抽帧与图片感知哈希(pHash)算法,编译为轻量级 `.wasm` 文件。
|
||||||
|
* **调度时序**:
|
||||||
|
1. 广电云 `ReviewSvc` 将长视频切分为 10 秒片段,生成若干微任务(Micro-Task)。
|
||||||
|
2. 调度中心根据机顶盒的心跳状态(如 CPU 负载 < 30%、处于凌晨空闲时段),通过 MQTT 或 EdgeMesh 将任务指令与 Wasm 模块路由至空闲的机顶盒。
|
||||||
|
3. 机顶盒内的 EdgeCore 下载视频切片,在 Wasm 运行时代(如 WasmEdge)中执行计算。
|
||||||
|
4. 机顶盒将计算结果连同 PoW(工作量证明)签名,异步返回给云端聚合。
|
||||||
|
|
||||||
|
### 11.4.2 PCDN 去中心化分发网络架构
|
||||||
|
AIGC 视听内容(HLS/DASH 格式的 `.ts` 或 `.m4s` 切片)将被智能缓存在机顶盒的本地存储中。
|
||||||
|
* **Tracker 与路由发现**:广电云部署超级 Tracker 服务器,记录全网每个内容切片存在哪些机顶盒(Peer ID)中。系统结合广电宽带的网络拓扑,实现“同小区/同城”节点优先匹配。
|
||||||
|
* **P2P 传输协议**:基于 WebRTC DataChannel 或 libp2p 构建机顶盒之间、机顶盒与手机客户端之间的直连通信(支持 NAT 穿透)。
|
||||||
|
* **安全防篡改(AVCC 赋能)**:接收端下载完 P2P 切片后,立刻计算该切片的 SHA-256 哈希。该哈希必须与版权链上 AVCC 元数据包含的“全局默克尔树(Merkle Tree)节点”严格一致,一旦不符即丢弃并拉黑该 Peer,从而在去中心化网络中杜绝内容污染作恶。
|
||||||
|
|
||||||
|
### 11.4.3 Token / 积分智能合约对接(DePIN 机制)
|
||||||
|
在版权链(ChainMaker)上额外部署“广电算力通证”智能合约,实现 PoT(流量证明)和 PoW(工作量证明)的自动化结算与闭环消费。
|
||||||
|
|
||||||
|
**核心智能合约逻辑(Go 实现示意):**
|
||||||
|
```go
|
||||||
|
// 边缘节点与 Token 账本合约
|
||||||
|
type EdgeNode struct {
|
||||||
|
NodeID string // 机顶盒硬件唯一序列号哈希
|
||||||
|
OwnerAddress string // 用户绑定的广电账户地址
|
||||||
|
TotalToken uint64 // 累计视听积分
|
||||||
|
Status string // active / offline
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubmitProofBatch 批量提交工作量/流量证明 (由云端调度中心在凌晨汇总并上链)
|
||||||
|
func SubmitProofBatch(ctx contractapi.TransactionContextInterface, proofs []Proof) error {
|
||||||
|
for _, p := range proofs {
|
||||||
|
// 校验边缘节点的加密签名与任务真实性
|
||||||
|
if VerifySignature(p) {
|
||||||
|
// Token 奖励公式:基础奖励 * 任务难度 + 贡献流量(GB) * 单价系数
|
||||||
|
reward := CalculateReward(p.TaskType, p.DataSize)
|
||||||
|
|
||||||
|
// 更新节点所有者的积分账户余额
|
||||||
|
node := GetNode(ctx, p.NodeID)
|
||||||
|
node.TotalToken += reward
|
||||||
|
SaveNode(ctx, node)
|
||||||
|
|
||||||
|
// 记录发放日志,触发前端消息
|
||||||
|
EmitEvent("TokenMinted", p.NodeID, reward)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RedeemAIGCContent 积分消耗:兑换收费 AIGC 剧集的跨平台观影权
|
||||||
|
func RedeemAIGCContent(ctx contractapi.TransactionContextInterface, avcc string, userAddress string) error {
|
||||||
|
price := GetAVCCPrice(avcc)
|
||||||
|
userBalance := GetBalance(userAddress)
|
||||||
|
|
||||||
|
if userBalance < price {
|
||||||
|
return errors.New("Insufficient tokens")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. 扣除用户积分
|
||||||
|
DeductBalance(userAddress, price)
|
||||||
|
|
||||||
|
// 2. 将消耗的积分按法币锚定比例,转入该 AVCC 的分账池(供创作者、平台分成)
|
||||||
|
AddToSettlementPool(avcc, price)
|
||||||
|
|
||||||
|
// 3. 写入用户权益子链,允许其在任意接入 AIGC-Hub 的平台免费播放该剧集
|
||||||
|
RecordUserRights(avcc, userAddress)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11.5 该模式带来的战略价值
|
||||||
|
|
||||||
|
1. **极度压低 AIGC-Hub 运营成本**:
|
||||||
|
传统的集中式视频审核(尤其是切片、转码、算特征值)需要海量 CPU 资源。将其卸载到亿级免费边缘算力,广电云的算力成本将断崖式下降,构建了互联网大厂(如腾讯、字节)无法复制的成本优势。
|
||||||
|
2. **盘活广电存量资产,增强用户粘性**:
|
||||||
|
有线电视用户流失是广电目前的痛点。“贡献算力赚免费看片积分”的模式,赋予了机顶盒全新的价值,吸引用户保持设备在线。
|
||||||
|
3. **闭环的 AIGC 经济体**:
|
||||||
|
创作者生产内容 -> 广电赋码审核 -> 边缘 CDN 加速分发 -> 用户看广告/花钱/花算力积分消费 -> 智能合约分账给创作者和算力提供者(机顶盒)。
|
||||||
|
**广电云通过 AIGC-Hub 真正成为一个生态制定者和数字资产结算行。**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11.6 实施建议
|
||||||
|
|
||||||
|
* **一期试点(选定高配机型)**:挑选近年发放的具备智能操作系统(如 Android 9.0+)和较好 CPU/NPU 性能的广电机顶盒(如中国广电 5G 智能机顶盒),在几个活跃省份(如江苏、浙江)进行灰度测试,主要测试 PCDN 功能和积分结算。
|
||||||
|
* **二期拓展(算力调度)**:部署 WebAssembly 边缘计算环境,承接部分图像哈希与切片预处理任务。
|
||||||
|
* **三期生态(Token 化)**:完全打通 AIGC-Hub 版权链,实现边缘算力证明上链与 AIGC 购买权益积分通兑。
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
# AIGC-Hub 智视码(AVCC) 技术实现方案 — 汇总索引
|
||||||
|
|
||||||
|
> 版本:V1.0
|
||||||
|
> 编制日期:2026年6月
|
||||||
|
> 基于文档:《AIGC-Hub智视码(AVCC)体系建设方案 V2.0(MA融合修订版)》
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 文档清单
|
||||||
|
|
||||||
|
| 序号 | 文件名 | 内容概要 |
|
||||||
|
|------|--------|----------|
|
||||||
|
| 概要 | [00-技术实现方案-概要.md](00-技术实现方案-概要.md) | 方案概述、核心架构速览、技术栈速查 |
|
||||||
|
| 第一章 | [01-总体技术架构.md](01-总体技术架构.md) | 架构设计原则、总体架构图(四层)、技术栈选型详表(15+组件)、系统间交互关系、数据流总览 |
|
||||||
|
| 第二章 | [02-核心系统模块设计.md](02-核心系统模块设计.md) | 赋码引擎(编码生成逻辑/服务拆分)、审核引擎(5模型服务/状态机/报告JSON)、版权链引擎(3智能合约)、MA编码网关(7接口/解析流程)、C2PA SDK(架构/扩展字段)、创作者工作台(6模块)、清算引擎(分账模型/估值模型) |
|
||||||
|
| 第三章 | [03-数据库与数据模型.md](03-数据库与数据模型.md) | 存储策略总览、PostgreSQL 9张核心表(creators/platforms/avcc_records/review_reports/chain_records/settlement_records/blacklist/review_tasks/api_call_logs)、Redis 缓存设计、ClickHouse 4张分析表、向量数据库、对象存储目录结构、高可用与灾备 |
|
||||||
|
| 第四章 | [04-API接口设计.md](04-API接口设计.md) | 统一接口规范(鉴权HMAC/限流/错误码)、赋码服务4接口、审核服务3接口、MA网关4接口、版权链与清算4接口、数据回传2接口、监管接口2接口 |
|
||||||
|
| 第五章 | [05-部署与运维架构.md](05-部署与运维架构.md) | K8s 部署拓扑、一期资源预估表(10+组件)、网络6安全域、高可用RPO/RTO、监控告警体系 |
|
||||||
|
| 第六章 | [06-安全设计.md](06-安全设计.md) | 等保三级合规框架(9项)、数据加密策略(6类)、隐私计算4方案、审计日志6类、安全事件响应4级 |
|
||||||
|
| 第七章 | [07-分阶段实施路线图.md](07-分阶段实施路线图.md) | 三期里程碑、每期技术任务表(负责人/工期/依赖)、资源投入、关键风险与应对 |
|
||||||
|
| 第八章 | [08-核心业务时序图与状态机.md](08-核心业务时序图与状态机.md) | 赋码全链路/跨平台解析/分账时序图,审核/流通状态机流转 |
|
||||||
|
| 第九章 | [09-异步消息流转设计.md](09-异步消息流转设计.md) | Kafka Topic 规划、事件 Payload Schema、失败重试与 DLQ |
|
||||||
|
| 第十章 | [10-C2PA与第三方对接详细设计.md](10-C2PA与第三方对接详细设计.md) | C2PA SDK 嵌入逻辑、ZIIOT 根解析同步机制、联盟链异步监听 |
|
||||||
|
| 第十一章 | [11-广电机顶盒生态与边缘算力赋能方案.md](11-广电机顶盒生态与边缘算力赋能方案.md) | 边缘算力节点、PCDN去中心化分发、Token/积分结算体系融合 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 术语对照表
|
||||||
|
|
||||||
|
| 术语 | 英文 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| AIGC-Hub | — | 国家 AIGC 视听内容登记与分发基础设施 |
|
||||||
|
| AVCC | AI Visual Content Code | 智视码,国家 AIGC 视听内容统一标识码 |
|
||||||
|
| MA | — | MA 标识代码,ISO/IEC 15459 全球代码发行机构 |
|
||||||
|
| ZIIOT | 中关村工信二维码技术研究院 | MA 全球代码发行机构和根节点运营方 |
|
||||||
|
| 网标 | — | 网络剧片发行许可证,广电总局行政许可 |
|
||||||
|
| C2PA | Coalition for Content Provenance and Authenticity | 内容凭证技术标准 |
|
||||||
|
| 版权链 | — | 基于联盟链的版权存证与分账系统 |
|
||||||
|
| MA 行业节点 | — | 拟申请代码 MA.156.10005,广电云运营 |
|
||||||
|
| P/G/O | — | 重点/普通/其他,三类分级管理 |
|
||||||
|
| CRD | Copyright Registration Data | 版权链存证地址标识 |
|
||||||
|
| AI-HASH | — | AI 生成内容哈希值 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 核心技术栈索引
|
||||||
|
|
||||||
|
| 用途 | 选型 | 版本 |
|
||||||
|
|------|------|------|
|
||||||
|
| API 网关 | Kong / Apache APISIX | 最新稳定版 |
|
||||||
|
| 前端框架 | React + Ant Design | 18.x / 5.x |
|
||||||
|
| 高并发网关/赋码/清算 | Go + Gin | 1.22+ |
|
||||||
|
| 业务编排/AI管道 | Python + FastAPI | 3.11+ / 0.110+ |
|
||||||
|
| 底层媒体处理 | Rust (c2pa-rs) | 最新版 |
|
||||||
|
| 区块链 | 长安链 / Hyperledger Fabric | 2.x / 2.5+ |
|
||||||
|
| 关系数据库 | PostgreSQL | 16.x |
|
||||||
|
| 缓存 | Redis Cluster | 7.x |
|
||||||
|
| 时序分析 | ClickHouse | 24.x |
|
||||||
|
| 消息队列 | Apache Kafka | 3.x |
|
||||||
|
| 对象存储 | MinIO | 最新版 |
|
||||||
|
| AI 推理 | Triton + PyTorch | 2.x / 2.x |
|
||||||
|
| 向量检索 | Milvus / pgvector | 最新版 |
|
||||||
|
| 监控 | Prometheus + Grafana + ELK | 最新版 |
|
||||||
|
| CI/CD | GitLab CI + ArgoCD | 最新版 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## AVCC 编码结构速查
|
||||||
|
|
||||||
|
```
|
||||||
|
MA.156.10005.{platform_node}/{object_category}/{license_no}-{review_level}-AI-HASH({hash})-CRD({crd})
|
||||||
|
|
||||||
|
示例:
|
||||||
|
MA.156.10005.8361/10.1300200.AIGC/(京)网微剧审字(2026)第001号-P-AI-HASH(a1b2c3)-CRD(0x7f3e9a)
|
||||||
|
|
||||||
|
分段说明:
|
||||||
|
- MA 根:MA(ZIIOT 全球代码发行机构)
|
||||||
|
- 国家/行业节点:156.10005(中国 + AIGC视听内容行业节点)
|
||||||
|
- 平台节点:8361(接入平台/机构)
|
||||||
|
- 对象类目:10.1300200.AIGC(视听内容大类 + AI漫剧细分类目 + AIGC标识)
|
||||||
|
- 监管段:(京)网微剧审字(2026)第001号(网标号)
|
||||||
|
- 类别段:P(重点,全网首页推荐)/ G(普通)/ O(其他)
|
||||||
|
- 技术段:AI-HASH(a1b2c3)(内容哈希)
|
||||||
|
- 版权段:CRD(0x7f3e9a)(版权链存证地址)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 快速导航
|
||||||
|
|
||||||
|
- **需要了解整体架构?** → [01-总体技术架构.md](01-总体技术架构.md)
|
||||||
|
- **需要查看具体系统实现?** → [02-核心系统模块设计.md](02-核心系统模块设计.md)
|
||||||
|
- **需要查看数据库表结构?** → [03-数据库与数据模型.md](03-数据库与数据模型.md)
|
||||||
|
- **需要对接 API?** → [04-API接口设计.md](04-API接口设计.md)
|
||||||
|
- **需要部署方案?** → [05-部署与运维架构.md](05-部署与运维架构.md)
|
||||||
|
- **需要安全合规方案?** → [06-安全设计.md](06-安全设计.md)
|
||||||
|
- **需要实施计划?** → [07-分阶段实施路线图.md](07-分阶段实施路线图.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> 本文档由 AI 辅助生成,基于《AIGC-Hub智视码(AVCC)体系建设方案 V2.0》进行技术实现方案的细化与拆解。
|
||||||
@@ -0,0 +1,328 @@
|
|||||||
|
# AIGC-Hub 智视码(AVCC) 体系全景架构图 — 绘制描述
|
||||||
|
|
||||||
|
> 用途:下午业务+技术专家交流用图
|
||||||
|
> 建议工具:Figma / draw.io / ProcessOn / PPT
|
||||||
|
> 画布方向:从上到下(纵向四层) + 左侧价值流 + 右侧数据流 + 底部时间轴
|
||||||
|
> 建议尺寸:A1 横版(841×594mm)或 16:9 超宽屏投影
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、图的整体构图逻辑
|
||||||
|
|
||||||
|
采用 **"四层架构 × 两条主线 × 一个闭环"** 的视觉结构:
|
||||||
|
|
||||||
|
- **纵轴(从上到下)**:监管层 → 运营层 → 标识层 → 应用层(四层体系)
|
||||||
|
- **左侧主线**:业务价值流(内容从生成到变现的生命周期)
|
||||||
|
- **右侧主线**:数据/技术流(事件驱动的系统交互)
|
||||||
|
- **闭环**:资金流回路(用户付费 → 智能合约分账 → 多方收益)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、分区详细绘制说明
|
||||||
|
|
||||||
|
### 区域 A:顶部标题栏
|
||||||
|
|
||||||
|
```
|
||||||
|
位置:画布最顶部,全宽横条
|
||||||
|
内容:
|
||||||
|
- 主标题:AIGC-Hub 智视码(AVCC) 体系全景架构
|
||||||
|
- 副标题:一剧一码 · 一码全网 · 码链同源 · 全球互认
|
||||||
|
- 角标:MA 根节点 + 1朵云 + 3大引擎 + N个接入方
|
||||||
|
- 右上角:等保三级 | ISO/IEC 15459 | C2PA
|
||||||
|
样式:深蓝渐变底色,白色大字
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 区域 B:第一层 — 监管层(最上层,红色调)
|
||||||
|
|
||||||
|
```
|
||||||
|
位置:标题下方,占画布 12% 高度
|
||||||
|
背景色:浅红/中国红渐变,象征国家级监管
|
||||||
|
角色标注:国家广播电视总局 / 省级广电
|
||||||
|
|
||||||
|
绘制元素(从左到右):
|
||||||
|
┌─────────────────────────────────────────────────────────────┐
|
||||||
|
│ 🏛️ 监管层 │
|
||||||
|
│ │
|
||||||
|
│ [监管大屏] [终审工作台] [黑名单管理] [数据抽查] │
|
||||||
|
│ (数据看板) (P类终审) (全网封禁) (合规审计) │
|
||||||
|
│ │
|
||||||
|
│ 关键词标注:精准靶向监管 · 不介入日常 · 只抓标准/抽查/黑名单 │
|
||||||
|
└─────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
连接线:
|
||||||
|
- 向下的粗箭头(双向),标注"数据回传 / 指令下发"
|
||||||
|
- 线上标注:安全数据交换网关 · 专线对接
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 区域 C:第二层 — 运营层(核心区域,蓝色调,占比最大)
|
||||||
|
|
||||||
|
```
|
||||||
|
位置:画布中部,占 45% 高度
|
||||||
|
背景色:科技蓝渐变
|
||||||
|
角色标注:广电云 AIGC-Hub(唯一建设和运营主体)
|
||||||
|
|
||||||
|
整体布局:中间是 7 大核心引擎/系统,排列为 2 行
|
||||||
|
外围是技术基座(K8s、数据库、消息队列等)
|
||||||
|
|
||||||
|
═══════════════════════════════════════════════════════════════
|
||||||
|
广电云 AIGC-Hub 运营层(等保三级 VPC · K8s 集群)
|
||||||
|
═══════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
第一行(核心引擎,用大方块+图标表示):
|
||||||
|
|
||||||
|
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
|
||||||
|
│ 🔢 赋码引擎│ │ 🤖 审核引擎│ │ ⛓️ 版权链引擎│ │ 💰 清算引擎│
|
||||||
|
│ │ │ │ │ │ │ │
|
||||||
|
│ · 六段式编码│ │ · 画面审核 │ │ · 版权存证 │ │ · 跨平台分账│
|
||||||
|
│ · 码资源分配│ │ · 台词审核 │ │ · 用户权益链│ │ · 版权估值 │
|
||||||
|
│ · 预检4步 │ │ · 声音审核 │ │ · 智能合约 │ │ · 金融衍生 │
|
||||||
|
│ · 生命周期 │ │ · AIGC真实性│ │ · 联盟链5组织│ │ · 法币结算 │
|
||||||
|
│ │ │ · 融合决策 │ │ │ │ │
|
||||||
|
│ Go+Gin │ │ Triton+GPU │ │ ChainMaker │ │ Go+Gin │
|
||||||
|
└──────────┘ └──────────┘ └──────────┘ └──────────┘
|
||||||
|
|
||||||
|
第二行(支撑系统):
|
||||||
|
|
||||||
|
┌──────────┐ ┌──────────┐ ┌──────────┐
|
||||||
|
│ 🌐 MA编码网关│ │ 🔐 C2PA SDK │ │ 🖥️ 创作者工作台│
|
||||||
|
│ │ │ │ │ │
|
||||||
|
│ · AVCC解析 │ │ · 水印嵌入 │ │ · 赋码申请 │
|
||||||
|
│ · 流通权限 │ │ · MA标识片段│ │ · 版权登记 │
|
||||||
|
│ · 根解析对接│ │ · 多语言绑定│ │ · 分账查询 │
|
||||||
|
│ · 平台鉴权 │ │ · AI工具适配│ │ · 审核报告 │
|
||||||
|
│ Go 万级QPS │ │ Rust c2pa-rs│ │ React+AntD │
|
||||||
|
└──────────┘ └──────────┘ └──────────┘
|
||||||
|
|
||||||
|
引擎间连线(用带标号的箭头):
|
||||||
|
① 工作台 → 赋码引擎(提交申请)
|
||||||
|
② 赋码引擎 → 审核引擎(Kafka: 创建审核任务)
|
||||||
|
③ 审核引擎 → 版权链引擎(审核报告哈希上链)
|
||||||
|
④ 版权链引擎 → 赋码引擎(存证完成触发编码生成)
|
||||||
|
⑤ 赋码引擎 → MA网关(注册新 AVCC)
|
||||||
|
⑥ 平台 → MA网关(解析校验流通权限)
|
||||||
|
⑦ 清算引擎 → 版权链引擎(定时链上清算)
|
||||||
|
|
||||||
|
─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
||||||
|
技术基座层(底部小图标带,灰色背景):
|
||||||
|
|
||||||
|
[PostgreSQL] [Redis] [Kafka] [ClickHouse] [MinIO]
|
||||||
|
[Milvus] [ES] [Prometheus] [Grafana] [GitLab CI]
|
||||||
|
═══════════════════════════════════════════════════════════════
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 区域 D:第三层 — MA 标识层(绿色调)
|
||||||
|
|
||||||
|
```
|
||||||
|
位置:运营层下方,占 12% 高度
|
||||||
|
背景色:深绿/国际绿,象征国际标准
|
||||||
|
角色标注:ZIIOT MA 全球根节点体系
|
||||||
|
|
||||||
|
绘制为树状节点结构(从左到右展开):
|
||||||
|
|
||||||
|
MA (全球根)
|
||||||
|
└─ MA.156 (中国节点)
|
||||||
|
└─ MA.156.10005 (AIGC视听行业节点 ← 广电云运营)
|
||||||
|
├─ MA.156.10005.8361 (平台A)
|
||||||
|
├─ MA.156.10005.8362 (平台B)
|
||||||
|
└─ MA.156.10005.xxxx (更多...)
|
||||||
|
|
||||||
|
右侧放置 AVCC 编码结构示意:
|
||||||
|
┌─────────────────────────────────────────────────────────────┐
|
||||||
|
│ MA.156.10005.8361 / 10.1300200.AIGC / (京)网微剧审字... -P │
|
||||||
|
│ ├─ MA根 ─┤ 国家 ─┤ 行业 ─┤ 平台 / 类目 / 网标-级别-哈希-版权 │
|
||||||
|
│ 智视码 AVCC = 全球唯一数字身份证 │
|
||||||
|
└─────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
标注:
|
||||||
|
- ISO/IEC 15459 国际标准
|
||||||
|
- 全球码资源管理
|
||||||
|
- 根解析服务(跨境互认)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 区域 E:第四层 — 应用层(多彩色调)
|
||||||
|
|
||||||
|
```
|
||||||
|
位置:最底部,占 15% 高度
|
||||||
|
背景色:浅灰,各接入方用不同品牌色的小方块
|
||||||
|
|
||||||
|
绘制为 5 个接入方分类(每类下列举 2-3 个代表):
|
||||||
|
|
||||||
|
┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐
|
||||||
|
│ 长视频 │ │ 短视频 │ │AI工具厂│ │ MCN机构│ │ 创作者 │
|
||||||
|
│ 平台 │ │ 平台 │ │ 商 │ │ │ │ │
|
||||||
|
├───────┤ ├───────┤ ├───────┤ ├───────┤ ├───────┤
|
||||||
|
│爱奇艺 │ │ 抖音 │ │ComfyUI │ │ XX传媒 │ │ 个人 │
|
||||||
|
│腾讯视频│ │ 快手 │ │ 可灵AI │ │ YY MCN│ │ 工作室 │
|
||||||
|
│ 优酷 │ │小红书 │ │Runway │ │ │ │ │
|
||||||
|
└───────┘ └───────┘ └───────┘ └───────┘ └───────┘
|
||||||
|
|
||||||
|
接入方式标注:
|
||||||
|
- RESTful API(HMAC-SHA256 签名鉴权)
|
||||||
|
- C2PA SDK(Python/JS/Go 多语言绑定)
|
||||||
|
- 创作者工作台 SaaS
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 区域 F:左侧 — 业务价值生命周期流(竖向贯穿)
|
||||||
|
|
||||||
|
```
|
||||||
|
位置:画布左侧 15% 宽度,纵向贯穿全图
|
||||||
|
样式:用一条蜿蜒向下的粗流程线,每个节点是一个圆角方块
|
||||||
|
|
||||||
|
生命周期节点(从上到下):
|
||||||
|
|
||||||
|
① 创作(AI工具生成 + C2PA水印嵌入)
|
||||||
|
↓
|
||||||
|
② 赋码(提交申请 → 预检 → 审核 → 编码生成)
|
||||||
|
↓
|
||||||
|
③ 确权(版权链存证 → 智能合约绑定权益方)
|
||||||
|
↓
|
||||||
|
④ 分发(MA网关校验 → P/G/O分级流通)
|
||||||
|
↓
|
||||||
|
⑤ 消费(用户观看/购买 → 播放数据回传)
|
||||||
|
↓
|
||||||
|
⑥ 结算(智能合约自动分账 → 法币提现)
|
||||||
|
↓
|
||||||
|
⑦ 监管(数据上报 → 黑名单 → 吊销/冻结)
|
||||||
|
|
||||||
|
每个节点旁边标注对应的系统引擎名称。
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 区域 G:右侧 — 数据流与事件驱动(竖向贯穿)
|
||||||
|
|
||||||
|
```
|
||||||
|
位置:画布右侧 15% 宽度
|
||||||
|
样式:用 Kafka topic 图标串联的事件流
|
||||||
|
|
||||||
|
事件流节点:
|
||||||
|
|
||||||
|
[topic.avcc.apply.created] → 赋码申请创建
|
||||||
|
↓
|
||||||
|
[topic.review.task.finished] → 审核完成
|
||||||
|
↓
|
||||||
|
[topic.chain.tx.confirmed] → 上链确认
|
||||||
|
↓
|
||||||
|
[topic.playback.event] → 播放数据回传
|
||||||
|
↓
|
||||||
|
[topic.system.dlq] → 异常/死信处理
|
||||||
|
|
||||||
|
旁边标注:
|
||||||
|
- At-Least-Once 语义(核心业务流)
|
||||||
|
- 同一作品保序(Key = avcc_record_id)
|
||||||
|
- 失败重试 3 次 → DLQ → 人工介入
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 区域 H:底部 — 实施路线时间轴
|
||||||
|
|
||||||
|
```
|
||||||
|
位置:画布最底部,全宽窄条
|
||||||
|
样式:水平时间轴,三段分期
|
||||||
|
|
||||||
|
|← ─ ─ 一期:筑基(0-6月) ─ ─ →|← ─ 二期:贯通(6-12月) ─ →|← ─ 三期:生态(1-2年) ─ →|
|
||||||
|
|
||||||
|
一期关键词:赋码引擎V1 · 审核MVP · 3-5平台试点 · MA节点申请 · 30人
|
||||||
|
二期关键词:SDK发布 · 版权链全贯通 · 清算上线 · 80%智能审核 · 40人
|
||||||
|
三期关键词:AIGC片库 · 跨平台通兑 · 版权金融 · 跨境MA · 50人
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 区域 I:右下角 — 商业模式四层飞轮
|
||||||
|
|
||||||
|
```
|
||||||
|
位置:右下角,小型环形图
|
||||||
|
样式:四层同心环或四象限
|
||||||
|
|
||||||
|
外环:数据与生态运营(行业报告/过审险/榜单)
|
||||||
|
三环:跨平台清算(6-8%服务费 · 版权金融 · ABS)
|
||||||
|
二环:合规 SaaS(AI预审API · 版权比对 · 白名单认证)
|
||||||
|
内核:赋码服务(50-2000元/部 · 年百万部)
|
||||||
|
|
||||||
|
中心文字:编码权 × 审核权 × 结算权 × 数据权
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 区域 J(可选扩展):边缘生态(机顶盒)
|
||||||
|
|
||||||
|
```
|
||||||
|
位置:如果画布空间允许,在底部应用层下方用虚线框追加
|
||||||
|
|
||||||
|
┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─┐
|
||||||
|
│ 🔮 远期愿景:广电机顶盒边缘算力网络(2亿节点) │
|
||||||
|
│ │
|
||||||
|
│ [边缘算力池] [PCDN去中心化分发] [视听积分Token] │
|
||||||
|
│ · Wasm微任务 · 同城P2P加速 · 贡献=挖矿 │
|
||||||
|
│ · 闲时抽帧/哈希 · AVCC防篡改校验 · 积分兑换观影权 │
|
||||||
|
│ · KubeEdge · WebRTC/libp2p · 链上清算 │
|
||||||
|
│ │
|
||||||
|
│ 价值:降低90%预处理算力成本 · 盘活存量资产 · 生态闭环 │
|
||||||
|
└ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、分账模型插图(建议单独放大或作为图中插图)
|
||||||
|
|
||||||
|
```
|
||||||
|
用户支付 10 元
|
||||||
|
├── 平台 30% ─────→ 3.00 元
|
||||||
|
├── 广电云 6% ────→ 0.60 元 (清算服务费)
|
||||||
|
└── 内容池 64% ──→ 6.40 元
|
||||||
|
├── 创作者 40% → 4.00 元
|
||||||
|
├── 模型方 15% → 1.50 元
|
||||||
|
├── IP方 10% → 1.00 元
|
||||||
|
└── 运营 9% → 0.90 元
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、视觉设计建议
|
||||||
|
|
||||||
|
| 元素 | 建议 |
|
||||||
|
|------|------|
|
||||||
|
| 色彩体系 | 监管层-中国红,运营层-科技蓝,标识层-国际绿,应用层-中性灰 |
|
||||||
|
| 图标风格 | 扁平线性图标(类 Ant Design Icons),统一线宽 |
|
||||||
|
| 字体 | 标题:思源黑体 Bold;正文:思源黑体 Regular;英文:Inter/SF Pro |
|
||||||
|
| 连线 | 核心数据流用实线+箭头(蓝色),监管通道用虚线(红色),资金流用金色 |
|
||||||
|
| 分级信息 | 第一眼看结构(四层+闭环),第二眼看引擎(7个核心组件),第三眼看细节(技术栈/接口) |
|
||||||
|
| 信息密度 | 业务专家只看左半边(流程+价值),技术专家只看右半边(架构+数据流)—— 一图两面 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、核心沟通要点(图旁备注/讲解要点)
|
||||||
|
|
||||||
|
1. **"为什么要做"**:AIGC 爆发 → 管不住+成本高+变现难 → 需要国家级基础设施
|
||||||
|
2. **"做什么"**:以 AVCC 智视码为核心,建设登记-审核-分发-结算全链路
|
||||||
|
3. **"怎么做"**:MA国际标准 + AI审核 + 联盟链 + 云原生,三期递进
|
||||||
|
4. **"怎么赚"**:赋码费 + SaaS API + 清算手续费 + 数据运营,四层商业飞轮
|
||||||
|
5. **"广电云的角色"**:中立枢纽 — 不做内容、只做治理+清算+标准 — 不可替代性
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 六、交付物建议
|
||||||
|
|
||||||
|
| 格式 | 用途 |
|
||||||
|
|------|------|
|
||||||
|
| **PPT 单页(16:9)** | 投影讲解,大字少细节 |
|
||||||
|
| **A1 海报(PDF)** | 打印展板,细节全量 |
|
||||||
|
| **draw.io 源文件** | 后续迭代修改 |
|
||||||
|
| **Mermaid/PlantUML 源码** | 版本管理,嵌入技术文档 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> 本描述文件是"一张图"的绘制蓝图,覆盖了全部 11 章技术方案的核心信息。
|
||||||
|
> 请设计师/绘图者按照上述区域划分进行排版,确保业务和技术专家都能从这一张图中找到自己关注的信息层次。
|
||||||
@@ -0,0 +1,292 @@
|
|||||||
|
# AIGC-Hub 商业模式与收入测算详图 — 绘制描述
|
||||||
|
|
||||||
|
> 用途:面向决策者/投资人,说清"怎么赚钱、赚多少、什么时候回本"
|
||||||
|
> 建议工具:Figma / PPT / ProcessOn
|
||||||
|
> 画布方向:横版 16:9,左侧飞轮模型 + 右侧收入预测曲线 + 底部盈亏平衡分析
|
||||||
|
> 建议尺寸:16:9 单页(投影用)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、整体构图逻辑
|
||||||
|
|
||||||
|
**"飞轮 + 曲线 + 平衡点"** 三段式:
|
||||||
|
|
||||||
|
- **左区(40%)**:四层商业飞轮(同心环)— 说清四个收入来源及其关系
|
||||||
|
- **右区(40%)**:三年收入预测曲线 — 量化每层在各阶段的收入贡献
|
||||||
|
- **底部(20%)**:盈亏平衡条件分析 — 关键假设与敏感性分析
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、左区:四层商业飞轮模型
|
||||||
|
|
||||||
|
### 绘制方式:同心环/洋葱圈,从内到外四层,带箭头表示飞轮驱动方向
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────┐
|
||||||
|
│ 四层商业飞轮 │
|
||||||
|
│ │
|
||||||
|
│ ┌─────────────┐ │
|
||||||
|
│ ┌────┤ 第四层 ├────┐ │
|
||||||
|
│ ┌────┤ │ 数据与生态 │ ├────┐ │
|
||||||
|
│ ┌────┤ │ │ 运营 │ │ ├────┐ │
|
||||||
|
│ │ │ │ └─────────────┘ │ │ │ │
|
||||||
|
│ │ │ │ ┌─────────────┐ │ │ │ │
|
||||||
|
│ │ │ └───┤ 第三层 ├────┘ │ │ │
|
||||||
|
│ │ │ │ 跨平台清算 │ │ │ │
|
||||||
|
│ │ │ │ 版权金融 │ │ │ │
|
||||||
|
│ │ │ └─────────────┘ │ │ │
|
||||||
|
│ │ │ ┌─────────────┐ │ │ │
|
||||||
|
│ │ └───────┤ 第二层 ├──────────┘ │ │
|
||||||
|
│ │ │ 合规 SaaS │ │ │
|
||||||
|
│ │ │ API 服务 │ │ │
|
||||||
|
│ │ └─────────────┘ │ │
|
||||||
|
│ │ ┌─────────────┐ │ │
|
||||||
|
│ └───────────┤ 第一层 ├───────────────┘ │
|
||||||
|
│ │ 赋码服务 │ │
|
||||||
|
│ │ (门票经济) │ │
|
||||||
|
│ └─────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ 飞轮驱动逻辑(顺时针箭头): │
|
||||||
|
│ 赋码量↑ → 平台接入↑ → API调用↑ → 播放数据↑ │
|
||||||
|
│ → 清算GMV↑ → 数据资产↑ → 生态吸引力↑ → 赋码量↑↑ │
|
||||||
|
└─────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 每层详细说明(环形图旁边配文字卡片)
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─ 第一层:赋码服务(门票经济 · 基础现金流)─────────────────────┐
|
||||||
|
│ │
|
||||||
|
│ 收费模式: │
|
||||||
|
│ · P类(重点AI漫剧):2000元/部(含全网标+终审+优先排期) │
|
||||||
|
│ · G类(普通AI漫剧):200元/部 (含平台标+AI预审) │
|
||||||
|
│ · O类(其他AI漫剧):50元/部 (秒级自动赋码) │
|
||||||
|
│ · MCN批量套餐:按量阶梯折扣(>100部打8折,>1000部打6折) │
|
||||||
|
│ │
|
||||||
|
│ 核心指标: │
|
||||||
|
│ · 一期目标:月赋码 5,000部 → 年收入 ≈ 600万 │
|
||||||
|
│ · 二期目标:月赋码 50,000部 → 年收入 ≈ 5,000万 │
|
||||||
|
│ · 三期目标:月赋码 200,000部 → 年收入 ≈ 1.5亿 │
|
||||||
|
│ │
|
||||||
|
│ 毛利率:90%+(边际成本趋近于零,主要是码资源管理费给ZIIOT) │
|
||||||
|
│ 护城河:行政许可垄断 — 无码不流通,政策强制 │
|
||||||
|
└──────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
┌─ 第二层:合规 SaaS(高毛利技术输出)─────────────────────────┐
|
||||||
|
│ │
|
||||||
|
│ 收费模式: │
|
||||||
|
│ · AI预审API:0.5-2元/次(按调用量阶梯计费) │
|
||||||
|
│ · AIGC真实性核验API:1-5元/次 │
|
||||||
|
│ · 版权比对API:2-10元/次 │
|
||||||
|
│ · C2PA水印嵌入/验证API:0.1-0.5元/次 │
|
||||||
|
│ · 模型白名单认证年费:10万-50万/模型/年 │
|
||||||
|
│ · SDK企业版授权:5万-20万/年 │
|
||||||
|
│ │
|
||||||
|
│ 核心指标: │
|
||||||
|
│ · 一期:日均API调用 10万次 → 年收入 ≈ 1,500万 │
|
||||||
|
│ · 二期:日均API调用 500万次 → 年收入 ≈ 5亿 │
|
||||||
|
│ · 三期:日均API调用 2000万次 → 年收入 ≈ 15亿 │
|
||||||
|
│ · 白名单认证:一期10个模型 → 三期100+模型 │
|
||||||
|
│ │
|
||||||
|
│ 毛利率:85%(主要成本是GPU推理) │
|
||||||
|
│ 护城河:审核模型持续迭代 + 数据飞轮(越用越准) │
|
||||||
|
└──────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
┌─ 第三层:跨平台清算与版权金融(核心爆发点)─────────────────┐
|
||||||
|
│ │
|
||||||
|
│ 收费模式: │
|
||||||
|
│ · 清算服务费:跨平台结算GMV的 6%-8% │
|
||||||
|
│ · 版权估值报告:5,000-50,000元/份 │
|
||||||
|
│ · 数据要素登记证书(联合数据交易所):1万-10万/份 │
|
||||||
|
│ · 版权质押融资服务费:融资额的 1%-2% │
|
||||||
|
│ · ABS发行技术服务费:发行规模的 0.5%-1% │
|
||||||
|
│ │
|
||||||
|
│ 核心指标: │
|
||||||
|
│ · 二期:年清算GMV 2亿 × 7% = 年收入 ≈ 1,400万 │
|
||||||
|
│ · 三期:年清算GMV 50亿 × 7% = 年收入 ≈ 3.5亿 │
|
||||||
|
│ · 远期:年清算GMV 200亿 × 7% = 年收入 ≈ 14亿 │
|
||||||
|
│ │
|
||||||
|
│ 毛利率:95%+(智能合约自动执行,几乎无边际成本) │
|
||||||
|
│ 护城河:联盟链+MA标识 双重锁定,切换成本极高 │
|
||||||
|
└──────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
┌─ 第四层:数据与生态运营(战略壁垒)────────────────────────┐
|
||||||
|
│ │
|
||||||
|
│ 收费模式: │
|
||||||
|
│ · AIGC行业白皮书:20万-100万/份(定制分析报告) │
|
||||||
|
│ · 模型效能榜单冠名/订阅:50万-200万/年 │
|
||||||
|
│ · "过审险"保费分成:保费的 20%-30%(联合保险公司) │
|
||||||
|
│ · 创作者培训认证:1,000-5,000元/人(联合教育机构) │
|
||||||
|
│ · 广告/流量分发佣金:CPA/CPS模式 │
|
||||||
|
│ │
|
||||||
|
│ 核心指标: │
|
||||||
|
│ · 三期起步:年收入 ≈ 5,000万-2亿 │
|
||||||
|
│ · 远期:随生态规模指数增长 │
|
||||||
|
│ │
|
||||||
|
│ 毛利率:70%-90%(轻资产运营) │
|
||||||
|
│ 护城河:数据独占性 — 全行业AVCC数据只有广电云拥有 │
|
||||||
|
└──────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、右区:三年收入预测曲线
|
||||||
|
|
||||||
|
### 绘制方式:堆叠面积图,X轴为时间(月),Y轴为收入(万元/月)
|
||||||
|
|
||||||
|
```
|
||||||
|
收入
|
||||||
|
(万元/月)
|
||||||
|
│ ┌──── 数据生态
|
||||||
|
8000│ ╱───┤
|
||||||
|
│ ╱──── └──── 清算金融
|
||||||
|
6000│ ╱─────
|
||||||
|
│ ╱────── ┌──── 合规SaaS
|
||||||
|
4000│ ╱───────────────┤
|
||||||
|
│ ╱──── └──── 赋码服务
|
||||||
|
2000│ ╱─────
|
||||||
|
│ ╱──────
|
||||||
|
1000│ ╱────────
|
||||||
|
│ ╱─────
|
||||||
|
500│ ╱───
|
||||||
|
│╱
|
||||||
|
├──────────────┬──────────────┬──────────────────→ 时间
|
||||||
|
0 一期(M1-6) 二期(M7-12) 三期(Y2)
|
||||||
|
|
||||||
|
关键数据点标注:
|
||||||
|
M6: 月收入 ≈ 300万(赋码为主)
|
||||||
|
M12: 月收入 ≈ 3,000万(SaaS爆发)
|
||||||
|
Y2: 月收入 ≈ 8,000万-1.2亿(清算+金融驱动)
|
||||||
|
|
||||||
|
成本线(虚线叠加):
|
||||||
|
一期:月成本 ≈ 500万(研发30人+云资源+MA费用)
|
||||||
|
二期:月成本 ≈ 800万(扩编40人+GPU+运营)
|
||||||
|
三期:月成本 ≈ 1,500万(50人+全量运营)
|
||||||
|
|
||||||
|
盈亏交叉点标注:★ 预计 M10-M12 实现月度盈亏平衡
|
||||||
|
```
|
||||||
|
|
||||||
|
### 各期收入结构饼图(小型辅图,三个并列)
|
||||||
|
|
||||||
|
```
|
||||||
|
一期(M6)饼图: 二期(M12)饼图: 三期(Y2)饼图:
|
||||||
|
┌──────────┐ ┌──────────┐ ┌──────────┐
|
||||||
|
│ 赋码 60% │ │ SaaS 45% │ │ 清算 40% │
|
||||||
|
│ SaaS 30% │ │ 清算 25% │ │ SaaS 25% │
|
||||||
|
│ 清算 5% │ │ 赋码 20% │ │ 生态 20% │
|
||||||
|
│ 其他 5% │ │ 生态 10% │ │ 赋码 10% │
|
||||||
|
└──────────┘ └──────────┘ │ 金融 5% │
|
||||||
|
└──────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、底部:盈亏平衡分析
|
||||||
|
|
||||||
|
### 绘制方式:关键假设表 + 敏感性矩阵
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 盈亏平衡条件分析 │
|
||||||
|
├─────────────────────────────────────────────────────────────────┤
|
||||||
|
│ │
|
||||||
|
│ 路径一(赋码驱动): │
|
||||||
|
│ 年赋码量达到 50万部 × 平均单价300元 = 年收入1.5亿 │
|
||||||
|
│ - 固定成本(人力+云) ≈ 8,000万/年 │
|
||||||
|
│ - 达到条件:接入平台 > 20家,创作者注册 > 10万 │
|
||||||
|
│ - 预计时间:M10-M14 │
|
||||||
|
│ │
|
||||||
|
│ 路径二(清算驱动): │
|
||||||
|
│ 跨平台结算GMV达到 10亿元 × 7% = 年收入7,000万 │
|
||||||
|
│ - 达到条件:头部平台3家+实际付费用户>500万 │
|
||||||
|
│ - 预计时间:M12-M18 │
|
||||||
|
│ │
|
||||||
|
│ 路径三(SaaS驱动): │
|
||||||
|
│ 日均API调用达到 100万次 × 平均1元/次 = 年收入3.65亿 │
|
||||||
|
│ - 达到条件:所有头部平台接入+短视频实时校验 │
|
||||||
|
│ - 预计时间:M8-M12 │
|
||||||
|
│ │
|
||||||
|
│ 最可能路径:三条路径并行,M10 前后实现月度盈亏平衡 │
|
||||||
|
│ │
|
||||||
|
├─────────────────────────────────────────────────────────────────┤
|
||||||
|
│ 敏感性分析矩阵 │
|
||||||
|
│ │
|
||||||
|
│ ┌───────────────┬──────────┬──────────┬──────────┐ │
|
||||||
|
│ │ │ 平台接入5家│ 平台接入10家│ 平台接入20家│ │
|
||||||
|
│ ├───────────────┼──────────┼──────────┼──────────┤ │
|
||||||
|
│ │ 赋码单价200元 │ M16盈亏 │ M12盈亏 │ M9盈亏 │ │
|
||||||
|
│ │ 赋码单价300元 │ M14盈亏 │ M10盈亏 │ M8盈亏 │ │
|
||||||
|
│ │ 赋码单价500元 │ M12盈亏 │ M9盈亏 │ M7盈亏 │ │
|
||||||
|
│ └───────────────┴──────────┴──────────┴──────────┘ │
|
||||||
|
│ │
|
||||||
|
│ 最大风险因子:平台接入意愿(政策推动力度决定) │
|
||||||
|
│ 最大确定性:赋码为行政许可,只要政策落地,需求刚性 │
|
||||||
|
└─────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、广电云收入来源全景(瀑布图/桑基图)
|
||||||
|
|
||||||
|
```
|
||||||
|
建议用桑基图展示资金流向:
|
||||||
|
|
||||||
|
用户支付(100%)
|
||||||
|
├──→ 平台抽成 30%
|
||||||
|
├──→ 广电云服务费 6-8% ←── 核心收入
|
||||||
|
│ ├── 清算服务费 4%
|
||||||
|
│ ├── 赋码分摊 1%
|
||||||
|
│ └── 技术服务 1-3%
|
||||||
|
└──→ 内容分成池 62-64%
|
||||||
|
├── 创作者 40%
|
||||||
|
├── 模型方 15%
|
||||||
|
├── IP方 10%
|
||||||
|
└── 平台运营补贴 9%
|
||||||
|
|
||||||
|
额外收入来源(非分账模式):
|
||||||
|
· API调用费 ← 各平台日常调用
|
||||||
|
· 白名单认证费 ← AI模型厂商年费
|
||||||
|
· 数据报告费 ← 行业机构订阅
|
||||||
|
· 金融服务费 ← 版权质押/ABS
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 六、投资回报摘要(右上角金色框)
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────┐
|
||||||
|
│ 投资回报核心指标 │
|
||||||
|
│ │
|
||||||
|
│ 总投资(三年):≈ 2.8亿 │
|
||||||
|
│ · 一期:5,000万(研发+云+MA申请) │
|
||||||
|
│ · 二期:8,000万(扩编+GPU+运营) │
|
||||||
|
│ · 三期:1.5亿(全量运营+金融牌照) │
|
||||||
|
│ │
|
||||||
|
│ 预计三年累计收入:8-15亿 │
|
||||||
|
│ 预计三年累计利润:3-8亿 │
|
||||||
|
│ IRR(内部收益率):60%-120% │
|
||||||
|
│ │
|
||||||
|
│ 关键前提: │
|
||||||
|
│ · 广电总局政策支持(无码不流通) │
|
||||||
|
│ · MA行业节点如期获批 │
|
||||||
|
│ · 头部平台接入 ≥ 5家 │
|
||||||
|
└─────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 七、视觉设计建议
|
||||||
|
|
||||||
|
| 元素 | 建议 |
|
||||||
|
|------|------|
|
||||||
|
| 主色调 | 金色+深蓝(金融+科技感) |
|
||||||
|
| 飞轮 | 四层同心环,内到外颜色由深到浅,顺时针箭头表示增长驱动 |
|
||||||
|
| 曲线图 | 堆叠面积图,四种颜色对应四层收入 |
|
||||||
|
| 盈亏点 | 用星号★标注在曲线图上,配红色虚线(成本线)交叉 |
|
||||||
|
| 数字 | 关键金额用大字号加粗,带¥符号 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> 本图回答一个核心问题:"广电云凭什么能从这个项目中赚到钱?"
|
||||||
|
> 答案:编码权(行政垄断)+ 清算权(链上不可替代)+ 数据权(全行业唯一汇聚点)= 三重护城河
|
||||||
@@ -0,0 +1,229 @@
|
|||||||
|
# AIGC-Hub 安全与合规架构详图 — 绘制描述
|
||||||
|
|
||||||
|
> 用途:面向安全/合规专家,展示等保三级全栈落地方案
|
||||||
|
> 建议工具:draw.io / Figma / PPT
|
||||||
|
> 画布方向:横版,左侧为六安全域拓扑,右侧为数据加密链路 + 隐私计算方案
|
||||||
|
> 建议尺寸:16:9 单页
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、整体构图逻辑
|
||||||
|
|
||||||
|
**"域 + 链 + 盾"** 三部分:
|
||||||
|
|
||||||
|
- **左区(40%)**:六安全域网络拓扑 — 物理/逻辑隔离关系
|
||||||
|
- **中区(30%)**:数据全生命周期加密链路 — 从传输到存储到销毁
|
||||||
|
- **右区(30%)**:等保三级九项落实矩阵 + 隐私计算四方案
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、左区:六安全域网络拓扑
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────────────────────────────────────────────────────────┐
|
||||||
|
│ 六安全域拓扑图 │
|
||||||
|
│ │
|
||||||
|
│ ┌────────── 公网(互联网) ──────────┐ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ WAF + DDoS防护 + CDN │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ └────────────────┬─────────────────┘ │
|
||||||
|
│ │ 443(HTTPS/TLS1.3) │
|
||||||
|
│ ┌────────────────▼─────────────────┐ │
|
||||||
|
│ │ ① DMZ 区 │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ Kong API Gateway (3 replicas) │ │
|
||||||
|
│ │ · JWT/HMAC鉴权 │ │
|
||||||
|
│ │ · 限流/熔断 │ │
|
||||||
|
│ │ · 请求日志(脱敏) │ │
|
||||||
|
│ │ · IP白名单(监管专线) │ │
|
||||||
|
│ └────────────────┬─────────────────┘ │
|
||||||
|
│ │ mTLS (Istio) │
|
||||||
|
│ ┌────────────────▼─────────────────┐ │
|
||||||
|
│ │ ② 应用区 │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ 微服务Pod (NetworkPolicy隔离) │ │
|
||||||
|
│ │ · code-svc · review-svc │ │
|
||||||
|
│ │ · workbench-svc · settlement │ │
|
||||||
|
│ │ · 服务间mTLS加密 │ │
|
||||||
|
│ │ · Pod Security Standards │ │
|
||||||
|
│ │ · Falco 运行时防护 │ │
|
||||||
|
│ └─────────┬──────────┬────────────┘ │
|
||||||
|
│ │ │ │
|
||||||
|
│ ┌─────────▼──┐ ┌───▼────────────┐ │
|
||||||
|
│ │ ③ 数据区 │ │ ④ AI推理区 │ │
|
||||||
|
│ │ │ │ │ │
|
||||||
|
│ │ PG(加密) │ │ Triton Server │ │
|
||||||
|
│ │ Redis │ │ GPU独占 │ │
|
||||||
|
│ │ Kafka │ │ 模型文件加密 │ │
|
||||||
|
│ │ ClickHouse │ │ 推理日志审计 │ │
|
||||||
|
│ │ MinIO(SSE) │ │ │ │
|
||||||
|
│ │ │ │ 仅应用区可访问 │ │
|
||||||
|
│ │ 仅应用区 │ └────────────────┘ │
|
||||||
|
│ │ 白名单访问 │ │
|
||||||
|
│ └─────────┬──┘ │
|
||||||
|
│ │ 专线/VPN │
|
||||||
|
│ ┌─────────▼──────────────┐ ┌──────────────────┐ │
|
||||||
|
│ │ ⑤ 区块链区 │ │ ⑥ 监管区 │ │
|
||||||
|
│ │ │ │ │ │
|
||||||
|
│ │ ChainMaker 5节点 │ │ regulatory-svc │ │
|
||||||
|
│ │ 联盟组织专线互连 │ │ 专线对接广电总局 │ │
|
||||||
|
│ │ HSM密钥管理 │ │ 安全数据交换网关 │ │
|
||||||
|
│ │ 国密SM2/SM3/SM4 │ │ 单向数据推送 │ │
|
||||||
|
│ │ │ │ 审计日志不可删 │ │
|
||||||
|
│ └────────────────────────┘ └──────────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ 防火墙规则摘要: │
|
||||||
|
│ · DMZ → 应用区:单向,仅转发已鉴权请求 │
|
||||||
|
│ · 应用区 → 数据区:白名单端口(5432/6379/9092) │
|
||||||
|
│ · 应用区 → AI区:白名单端口(8000/8001 Triton) │
|
||||||
|
│ · 应用区 → 区块链区:白名单端口(gRPC 12301) │
|
||||||
|
│ · 监管区:仅出站(推送数据),不接受入站 │
|
||||||
|
│ · 所有区间:零信任,默认拒绝 │
|
||||||
|
└──────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、中区:数据全生命周期加密链路
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────────────────────────────────────────────────────────┐
|
||||||
|
│ 数据全生命周期安全链路 │
|
||||||
|
│ │
|
||||||
|
│ ┌─── 传输加密 ───┐ ┌─── 存储加密 ───┐ ┌─── 使用控制 ──┐ │
|
||||||
|
│ │ │ │ │ │ │ │
|
||||||
|
│ │ · 公网: TLS1.3 │ │ · PG字段级: │ │ · 脱敏展示 │ │
|
||||||
|
│ │ · 内网: mTLS │ │ SM4-CBC │ │ · 最小权限 │ │
|
||||||
|
│ │ (Istio证书) │ │ · MinIO: SSE-S3│ │ · RBAC │ │
|
||||||
|
│ │ · 链上: mTLS │ │ · Redis: 内存 │ │ · 审计日志 │ │
|
||||||
|
│ │ + 国密TLS │ │ 加密(可选) │ │ · 水印追踪 │ │
|
||||||
|
│ │ · 专线: IPSec │ │ · 链上: 国密 │ │ │ │
|
||||||
|
│ └────────────────┘ └────────────────┘ └──────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ 数据分类分级(四级): │
|
||||||
|
│ ┌──────────┬──────────┬──────────┬──────────┐ │
|
||||||
|
│ │ L4 核心 │ L3 敏感 │ L2 内部 │ L1 公开 │ │
|
||||||
|
│ ├──────────┼──────────┼──────────┼──────────┤ │
|
||||||
|
│ │ 私钥/证书 │ 身份证号 │ 审核报告 │ AVCC编码 │ │
|
||||||
|
│ │ API Secret│ 手机号 │ 播放统计 │ 证书PDF │ │
|
||||||
|
│ │ 链上密钥 │ prompt │ 分账明细 │ C2PA水印 │ │
|
||||||
|
│ ├──────────┼──────────┼──────────┼──────────┤ │
|
||||||
|
│ │ HSM存储 │ SM4加密 │ PG+审计 │ 明文 │ │
|
||||||
|
│ │ 不可导出 │ Vault管理│ 脱敏展示 │ CDN分发 │ │
|
||||||
|
│ └──────────┴──────────┴──────────┴──────────┘ │
|
||||||
|
│ │
|
||||||
|
│ 密钥管理架构: │
|
||||||
|
│ ┌────────────────────────────────────────────┐ │
|
||||||
|
│ │ HashiCorp Vault │ │
|
||||||
|
│ │ · 动态密钥生成(DB密码每24h轮换) │ │
|
||||||
|
│ │ · PKI证书签发(mTLS证书自动续期) │ │
|
||||||
|
│ │ · Transit引擎(应用层加密不见明文密钥) │ │
|
||||||
|
│ │ · Audit日志(所有密钥访问可追溯) │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ HSM (硬件安全模块) │ │
|
||||||
|
│ │ · 区块链节点私钥(不可导出) │ │
|
||||||
|
│ │ · C2PA签名根证书 │ │
|
||||||
|
│ │ · 监管数据交换密钥 │ │
|
||||||
|
│ └────────────────────────────────────────────┘ │
|
||||||
|
└──────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、右区:等保三级九项 + 隐私计算
|
||||||
|
|
||||||
|
### 等保三级落实矩阵
|
||||||
|
|
||||||
|
```
|
||||||
|
┌────────────────────────────────────────────────┐
|
||||||
|
│ 等保三级(GB/T 22239-2019)落实 │
|
||||||
|
├──────────────┬────────────────┬────────────────┤
|
||||||
|
│ 要求项 │ 落实措施 │ 技术实现 │
|
||||||
|
├──────────────┼────────────────┼────────────────┤
|
||||||
|
│ 安全物理环境 │ 广电云等保机房 │ 门禁+监控+UPS │
|
||||||
|
│ 安全通信网络 │ 全链路加密 │ TLS1.3+mTLS │
|
||||||
|
│ 安全区域边界 │ 六安全域隔离 │ K8s NetPol │
|
||||||
|
│ 安全计算环境 │ 容器安全 │ Harbor+Falco │
|
||||||
|
│ 安全管理中心 │ 集中管控 │ Vault+SIEM │
|
||||||
|
│ 身份鉴别 │ 多因素认证 │ MFA+HMAC │
|
||||||
|
│ 访问控制 │ 最小权限 │ OPA/RBAC │
|
||||||
|
│ 安全审计 │ 不可篡改日志 │ 审计链+ELK │
|
||||||
|
│ 数据安全 │ 加密+脱敏 │ SM4+隐私计算 │
|
||||||
|
└──────────────┴────────────────┴────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 隐私计算四方案
|
||||||
|
|
||||||
|
```
|
||||||
|
┌────────────────────────────────────────────────┐
|
||||||
|
│ 隐私计算方案 │
|
||||||
|
│ │
|
||||||
|
│ ┌─────────────────────────────────────────┐ │
|
||||||
|
│ │ 方案1: 联邦学习 + 差分隐私 │ │
|
||||||
|
│ │ 场景: AI审核模型训练 │ │
|
||||||
|
│ │ 做法: 各平台本地训练→仅上传梯度→聚合 │ │
|
||||||
|
│ │ 效果: 训练数据不出域,模型质量不下降 │ │
|
||||||
|
│ └─────────────────────────────────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ ┌─────────────────────────────────────────┐ │
|
||||||
|
│ │ 方案2: 多方安全计算 (MPC) │ │
|
||||||
|
│ │ 场景: 跨平台版权比对 │ │
|
||||||
|
│ │ 做法: 指纹分片→各方持有片段→安全求交 │ │
|
||||||
|
│ │ 效果: 不暴露原始指纹即可完成侵权比对 │ │
|
||||||
|
│ └─────────────────────────────────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ ┌─────────────────────────────────────────┐ │
|
||||||
|
│ │ 方案3: 同态加密 │ │
|
||||||
|
│ │ 场景: 用户行为数据聚合分析 │ │
|
||||||
|
│ │ 做法: 密文状态下完成统计计算 │ │
|
||||||
|
│ │ 效果: 广电云只看到聚合结果,不见用户明文 │ │
|
||||||
|
│ └─────────────────────────────────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ ┌─────────────────────────────────────────┐ │
|
||||||
|
│ │ 方案4: 哈希上链 + 原文本地 │ │
|
||||||
|
│ │ 场景: 版权链存证 │ │
|
||||||
|
│ │ 做法: 仅content_hash上链,原文存MinIO │ │
|
||||||
|
│ │ 效果: 链上可验证、不可逆向还原原始内容 │ │
|
||||||
|
│ └─────────────────────────────────────────┘ │
|
||||||
|
└────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、安全事件响应与审计
|
||||||
|
|
||||||
|
```
|
||||||
|
┌────────────────────────────────────────────────┐
|
||||||
|
│ 安全事件分级响应 │
|
||||||
|
├──────┬───────────────┬─────────┬───────────────┤
|
||||||
|
│ 级别 │ 事件类型 │ 响应时间 │ 处置措施 │
|
||||||
|
├──────┼───────────────┼─────────┼───────────────┤
|
||||||
|
│ P0 │ 密钥泄露/数据泄 │ 15分钟 │ 立即熔断+通知 │
|
||||||
|
│ P1 │ 链节点异常/DDoS │ 30分钟 │ 切换+限流 │
|
||||||
|
│ P2 │ 服务故障/队列堆 │ 2小时 │ 扩容+人工 │
|
||||||
|
│ P3 │ 性能下降 │ 24小时 │ 排期优化 │
|
||||||
|
└──────┴───────────────┴─────────┴───────────────┘
|
||||||
|
|
||||||
|
审计日志保留策略:
|
||||||
|
· 赋码/审核操作:10年(PG + 审计链双写)
|
||||||
|
· API调用日志:5年(ClickHouse + 审计链摘要)
|
||||||
|
· 链上交易:永久(联盟链不可删除)
|
||||||
|
· 管理员操作:10年(PG + 审计链)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 六、视觉设计建议
|
||||||
|
|
||||||
|
| 元素 | 建议 |
|
||||||
|
|------|------|
|
||||||
|
| 安全域 | 用不同色块+虚线边框表示隔离区域 |
|
||||||
|
| 加密 | 用锁图标🔒标注加密节点 |
|
||||||
|
| 数据流 | 用箭头标注加密方式(TLS/SM4/HSM) |
|
||||||
|
| 告警 | P0用红色,P1用橙色,P2用黄色 |
|
||||||
|
| 合规标签 | 等保三级logo + 国密logo + ISO标志 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> 本图回答:系统如何满足等保三级要求?数据怎么保护?出了安全事件怎么响应?
|
||||||
@@ -0,0 +1,517 @@
|
|||||||
|
# AIGC-Hub 技术选型、实现与技术路线详图 — 绘制描述
|
||||||
|
|
||||||
|
> 用途:下午与技术专家深度交流,聚焦技术选型理由、混合语言分工、系统实现细节与技术演进路线
|
||||||
|
> 建议工具:Figma / draw.io / ProcessOn / PPT
|
||||||
|
> 画布方向:横版,左侧为技术分层架构,右侧为技术路线甘特图
|
||||||
|
> 建议尺寸:A1 横版 或 双屏16:9拼接
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、图的整体构图逻辑
|
||||||
|
|
||||||
|
采用 **"左架构 · 中选型 · 右路线"** 三栏式布局:
|
||||||
|
|
||||||
|
- **左栏(40%)**:技术分层架构图 — 从接入层到基础设施逐层展开,每层标注具体技术组件
|
||||||
|
- **中栏(25%)**:混合语言选型矩阵 — 按性能/场景/团队维度说明每种语言的分工定位
|
||||||
|
- **右栏(35%)**:技术路线甘特图 — 三期演进,每期标注技术里程碑与组件版本升级
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、左栏:技术分层架构详图
|
||||||
|
|
||||||
|
### 绘制方式:7 层水平堆叠,每层用不同色带区分
|
||||||
|
|
||||||
|
```
|
||||||
|
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||||
|
┃ ⓪ 接入与流量层 ┃
|
||||||
|
┃━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┌─────────┐ ┌─────────────┐ ┌─────────┐ ┌────────────┐ ┃
|
||||||
|
┃ │ CDN │ │ WAF / DDoS │ │ DNS │ │ TLS 1.3 │ ┃
|
||||||
|
┃ │广电云CDN │ │ 防护 │ │ 解析 │ │ 证书管理 │ ┃
|
||||||
|
┃ └─────────┘ └─────────────┘ └─────────┘ └────────────┘ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┌───────────────────────────────────────────────────────┐ ┃
|
||||||
|
┃ │ API Gateway: Kong / Apache APISIX │ ┃
|
||||||
|
┃ │ · 流量控制 · JWT/HMAC鉴权 · 灰度发布 · 日志采集 │ ┃
|
||||||
|
┃ │ · 限流: Token Bucket (500-2000 QPS/平台) │ ┃
|
||||||
|
┃ └───────────────────────────────────────────────────────┘ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┌───────────────────────────────────────────────────────┐ ┃
|
||||||
|
┃ │ Nginx Ingress Controller (K8s L7) │ ┃
|
||||||
|
┃ │ · TLS终止 · 路由规则 · 3 replicas │ ┃
|
||||||
|
┃ └───────────────────────────────────────────────────────┘ ┃
|
||||||
|
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||||
|
|
||||||
|
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||||
|
┃ ① 前端与客户端层 ┃
|
||||||
|
┃━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┃
|
||||||
|
┃ │ 监管大屏 │ │ 运营后台 │ │ 创作者工作台 │ ┃
|
||||||
|
┃ │ React 18 │ │ React 18 │ │ React 18 │ ┃
|
||||||
|
┃ │ ECharts │ │ Ant Design 5│ │ Ant Design 5│ ┃
|
||||||
|
┃ │ WebSocket │ │ Zustand │ │ 大文件上传 │ ┃
|
||||||
|
┃ └──────────────┘ └──────────────┘ └──────────────┘ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┌──────────────┐ ┌──────────────┐ ┃
|
||||||
|
┃ │ 移动端(扫码) │ │ C2PA CLI │ ┃
|
||||||
|
┃ │ React Native │ │ Rust编译 │ ┃
|
||||||
|
┃ │ / 小程序 │ │ 跨平台二进制 │ ┃
|
||||||
|
┃ └──────────────┘ └──────────────┘ ┃
|
||||||
|
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||||
|
|
||||||
|
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||||
|
┃ ② 后端微服务层(混合语言架构 · 核心) ┃
|
||||||
|
┃━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┌─── Go 1.22+ (高并发 · 低延迟 · 网关级) ──────────────────┐ ┃
|
||||||
|
┃ │ │ ┃
|
||||||
|
┃ │ [MA编码网关] [赋码引擎] [清算引擎] │ ┃
|
||||||
|
┃ │ Gin/Echo Gin+GORM Gin+GORM │ ┃
|
||||||
|
┃ │ 万级QPS 编码规则计算 实时分账对账 │ ┃
|
||||||
|
┃ │ AVCC解析 码资源分配 数值精度计算 │ ┃
|
||||||
|
┃ │ │ ┃
|
||||||
|
┃ │ [区块链服务] │ ┃
|
||||||
|
┃ │ ChainMaker SDK / Fabric SDK │ ┃
|
||||||
|
┃ │ 国密SM2/SM3/SM4 · gRPC高性能交互 │ ┃
|
||||||
|
┃ └─────────────────────────────────────────────────────────┘ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┌─── Kotlin 2.0+ / Spring Boot 3.x (业务中台 · 企业级) ───┐ ┃
|
||||||
|
┃ │ │ ┃
|
||||||
|
┃ │ [工作台BFF服务] [审核编排服务] [平台接入管理] │ ┃
|
||||||
|
┃ │ Spring WebFlux Coroutines Spring Security │ ┃
|
||||||
|
┃ │ 协程非阻塞 任务状态机 OAuth2/RBAC │ ┃
|
||||||
|
┃ │ GraphQL聚合 审核流程编排 多租户隔离 │ ┃
|
||||||
|
┃ │ │ ┃
|
||||||
|
┃ │ [数据回传服务] [报表与对账服务] [通知与回调服务] │ ┃
|
||||||
|
┃ │ Kafka Consumer ClickHouse查询 WebHook/邮件/短信 │ ┃
|
||||||
|
┃ │ 批量数据校验 定时报表生成 重试与幂等保证 │ ┃
|
||||||
|
┃ │ │ ┃
|
||||||
|
┃ │ 选型理由: │ ┃
|
||||||
|
┃ │ · JVM生态成熟,企业级中间件(Spring全家桶)开箱即用 │ ┃
|
||||||
|
┃ │ · Coroutines 协程模型兼顾高并发与代码可读性 │ ┃
|
||||||
|
┃ │ · 空安全+DSL 减少运行时NPE,提升代码健壮性 │ ┃
|
||||||
|
┃ │ · 与Java互操作,可复用成熟的ChainMaker Java SDK │ ┃
|
||||||
|
┃ │ · 团队可从Java/Kotlin渐进迁移,降低招聘门槛 │ ┃
|
||||||
|
┃ └─────────────────────────────────────────────────────────┘ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┌─── Python 3.11+ (AI管道 · 业务编排 · 快速迭代) ─────────┐ ┃
|
||||||
|
┃ │ │ ┃
|
||||||
|
┃ │ [审核AI管道] [版权链交互层] [文档生成] │ ┃
|
||||||
|
┃ │ FastAPI FastAPI WeasyPrint │ ┃
|
||||||
|
┃ │ Triton Client Web3py ReportLab │ ┃
|
||||||
|
┃ │ 模型推理编排 合约调用封装 PDF证书 │ ┃
|
||||||
|
┃ │ │ ┃
|
||||||
|
┃ │ [审核任务调度] │ ┃
|
||||||
|
┃ │ Celery + Redis │ ┃
|
||||||
|
┃ │ 异步任务分发与结果聚合 │ ┃
|
||||||
|
┃ └─────────────────────────────────────────────────────────┘ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┌─── Rust (底层性能 · 媒体处理 · 安全关键) ───────────────┐ ┃
|
||||||
|
┃ │ │ ┃
|
||||||
|
┃ │ [C2PA SDK核心] [视频指纹提取] [编解码加速] │ ┃
|
||||||
|
┃ │ c2pa-rs FFmpeg绑定 感知哈希算法 │ ┃
|
||||||
|
┃ │ JUMBF嵌入/验证 大文件流处理 高性能无GC │ ┃
|
||||||
|
┃ │ │ ┃
|
||||||
|
┃ │ 提供绑定: PyO3(Python) / N-API(JS) / CGO(Go) │ ┃
|
||||||
|
┃ └─────────────────────────────────────────────────────────┘ ┃
|
||||||
|
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||||
|
|
||||||
|
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||||
|
┃ ③ AI 推理层 ┃
|
||||||
|
┃━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┌──────────────────────────────────────────────────────┐ ┃
|
||||||
|
┃ │ NVIDIA Triton Inference Server 2.x │ ┃
|
||||||
|
┃ │ · 动态批处理 · 多框架(PyTorch/ONNX) · GPU调度 │ ┃
|
||||||
|
┃ └──────────────────────────────────────────────────────┘ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ ┌────────────┐ ┃
|
||||||
|
┃ │画面合规│ │台词NLP│ │音频合规│ │AIGC真实│ │版权指纹向量│ ┃
|
||||||
|
┃ │Vision │ │NLP │ │Audio │ │Deep │ │Fingerprint│ ┃
|
||||||
|
┃ │A10/A100│ │A10 │ │A10 │ │Fake │ │CPU+Milvus │ ┃
|
||||||
|
┃ │PyTorch│ │Trans- │ │torch- │ │A100 │ │HNSW索引 │ ┃
|
||||||
|
┃ │OpenMM │ │formers│ │audio │ │PyTorch│ │COSINE相似 │ ┃
|
||||||
|
┃ └───────┘ └───────┘ └───────┘ └───────┘ └────────────┘ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ 模型版本管理: MLflow / DVC ┃
|
||||||
|
┃ A/B测试: 流量切分 + 灰度发布 ┃
|
||||||
|
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||||
|
|
||||||
|
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||||
|
┃ ④ 数据存储层 ┃
|
||||||
|
┃━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┌─────────────── 关系型 (OLTP) ──────────────────────────┐ ┃
|
||||||
|
┃ │ PostgreSQL 16 + Patroni + etcd │ ┃
|
||||||
|
┃ │ · 1主2从 · JSONB灵活schema · 等保审计日志 │ ┃
|
||||||
|
┃ │ · 核心表: avcc_records / review_reports / chain_records│ ┃
|
||||||
|
┃ │ · RPO<1s · RTO<30s │ ┃
|
||||||
|
┃ └────────────────────────────────────────────────────────┘ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┌──────┐ ┌──────────┐ ┌──────────┐ ┌───────┐ ┌─────────┐ ┃
|
||||||
|
┃ │Redis │ │ClickHouse│ │Elastic- │ │Milvus │ │ MinIO │ ┃
|
||||||
|
┃ │Cluster│ │ 24.x │ │search 8.x│ │/pgvec │ │对象存储 │ ┃
|
||||||
|
┃ │7.x │ │ │ │ │ │ │ │ │ ┃
|
||||||
|
┃ │3主3从 │ │3节点副本 │ │3节点 │ │HNSW │ │4节点纠删│ ┃
|
||||||
|
┃ │ │ │ │ │ │ │ │ │ │ ┃
|
||||||
|
┃ │缓存 │ │时序分析 │ │全文检索 │ │向量 │ │视频/水印│ ┃
|
||||||
|
┃ │限流 │ │播放统计 │ │审核报告 │ │指纹 │ │证书PDF │ ┃
|
||||||
|
┃ │分布式锁│ │运营报表 │ │日志 │ │版权比对│ │证据包 │ ┃
|
||||||
|
┃ └──────┘ └──────────┘ └──────────┘ └───────┘ └─────────┘ ┃
|
||||||
|
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||||
|
|
||||||
|
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||||
|
┃ ⑤ 消息与异步层 ┃
|
||||||
|
┃━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┌────────────────────────────────────────────────────────┐ ┃
|
||||||
|
┃ │ Apache Kafka 3.x (3 Broker) │ ┃
|
||||||
|
┃ │ Topics: │ ┃
|
||||||
|
┃ │ · topic.avcc.apply.created (6分区, 7天) │ ┃
|
||||||
|
┃ │ · topic.review.task.finished (12分区, 7天) │ ┃
|
||||||
|
┃ │ · topic.chain.tx.confirmed (6分区, 30天) │ ┃
|
||||||
|
┃ │ · topic.playback.event (24分区, 3天, 高吞吐) │ ┃
|
||||||
|
┃ │ · topic.system.dlq (3分区, 永久) │ ┃
|
||||||
|
┃ │ │ ┃
|
||||||
|
┃ │ 语义: 核心流At-Least-Once · 播放流At-Most-Once │ ┃
|
||||||
|
┃ │ 保序: Key=avcc_record_id → 同Partition │ ┃
|
||||||
|
┃ └────────────────────────────────────────────────────────┘ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┌──────────┐ ┌──────────────┐ ┌────────────────┐ ┃
|
||||||
|
┃ │Celery │ │Kafka Streams │ │APScheduler │ ┃
|
||||||
|
┃ │+ Redis │ │/ Flink │ │/ Airflow │ ┃
|
||||||
|
┃ │异步任务 │ │实时流处理 │ │定时调度 │ ┃
|
||||||
|
┃ │PDF/邮件 │ │异常检测 │ │清算/报表 │ ┃
|
||||||
|
┃ └──────────┘ └──────────────┘ └────────────────┘ ┃
|
||||||
|
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||||
|
|
||||||
|
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||||
|
┃ ⑥ 区块链层 ┃
|
||||||
|
┃━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┌────────────────────────────────────────────────────────┐ ┃
|
||||||
|
┃ │ 长安链 ChainMaker 2.x (首选) / Fabric 2.5+ │ ┃
|
||||||
|
┃ │ │ ┃
|
||||||
|
┃ │ 共识: TBFT/Raft · 国密SM2/SM3/SM4 · 5组织联盟 │ ┃
|
||||||
|
┃ │ │ ┃
|
||||||
|
┃ │ 智能合约(Go实现): │ ┃
|
||||||
|
┃ │ ┌────────────┐ ┌────────────┐ ┌────────────┐ │ ┃
|
||||||
|
┃ │ │AVCC_Copy- │ │AVCC_User- │ │AVCC_Settle-│ │ ┃
|
||||||
|
┃ │ │right │ │Rights │ │ment │ │ ┃
|
||||||
|
┃ │ │版权主链合约│ │用户权益合约│ │分账清算合约│ │ ┃
|
||||||
|
┃ │ └────────────┘ └────────────┘ └────────────┘ │ ┃
|
||||||
|
┃ │ │ ┃
|
||||||
|
┃ │ 链服务代理: chain-svc (Go) → gRPC → ChainMaker Nodes │ ┃
|
||||||
|
┃ │ 异步上链: Kafka → chain-svc → 区块监听 → 确认回调 │ ┃
|
||||||
|
┃ │ 密钥管理: HSM硬件安全模块(等保三级必要) │ ┃
|
||||||
|
┃ └────────────────────────────────────────────────────────┘ ┃
|
||||||
|
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||||
|
|
||||||
|
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||||
|
┃ ⑦ 基础设施与 DevOps 层 ┃
|
||||||
|
┃━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┃
|
||||||
|
┃ ┃
|
||||||
|
┃ ┌─── 容器编排 ───┐ ┌─── 可观测性 ───┐ ┌─── CI/CD ──────┐ ┃
|
||||||
|
┃ │ K8s 1.29+ │ │ Prometheus │ │ GitLab CI │ ┃
|
||||||
|
┃ │ Istio(可选) │ │ Grafana 10.x │ │ ArgoCD │ ┃
|
||||||
|
┃ │ Harbor 2.x │ │ Jaeger/OTel │ │ Harbor扫描 │ ┃
|
||||||
|
┃ │ Vault │ │ ELK / Loki │ │ Nexus制品库 │ ┃
|
||||||
|
┃ └───────────────┘ └───────────────┘ └────────────────┘ ┃
|
||||||
|
┃ ┃
|
||||||
|
┃ 安全域: DMZ → 应用区 → 数据区 → AI推理区 → 区块链区 → 监管区 ┃
|
||||||
|
┃ 网络策略: mTLS · NetworkPolicy · WAF · 等保三级全栈合规 ┃
|
||||||
|
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、中栏:混合语言选型矩阵
|
||||||
|
|
||||||
|
### 绘制方式:横向对比表 + 雷达图
|
||||||
|
|
||||||
|
```
|
||||||
|
┌────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 混合语言选型决策矩阵 │
|
||||||
|
├─────────┬────────────┬─────────────┬──────────────┬───────────────┤
|
||||||
|
│ 维度 │ Go 1.22 │ Kotlin 2.0 │ Python 3.11 │ Rust │
|
||||||
|
├─────────┼────────────┼─────────────┼──────────────┼───────────────┤
|
||||||
|
│ 定位 │ 网关/计算 │ 业务中台 │ AI管道/编排 │ 底层/媒体 │
|
||||||
|
│ │ 密集型 │ 企业级服务 │ 快速迭代 │ 安全关键 │
|
||||||
|
├─────────┼────────────┼─────────────┼──────────────┼───────────────┤
|
||||||
|
│ 并发模型 │ Goroutine │ Coroutines │ asyncio │ async/await │
|
||||||
|
│ │ 百万级轻量 │ 结构化并发 │ + Celery │ 零成本抽象 │
|
||||||
|
├─────────┼────────────┼─────────────┼──────────────┼───────────────┤
|
||||||
|
│ 典型QPS │ 5万-10万 │ 1万-5万 │ 1千-5千 │ 10万+ │
|
||||||
|
│ (单实例) │ │ (WebFlux) │ (FastAPI) │ (裸性能) │
|
||||||
|
├─────────┼────────────┼─────────────┼──────────────┼───────────────┤
|
||||||
|
│ 生态优势 │ 云原生原生 │ Spring全家桶│ AI/ML生态 │ 安全/性能 │
|
||||||
|
│ │ K8s/Docker │ 企业中间件 │ PyTorch/HF │ WASM/嵌入式 │
|
||||||
|
├─────────┼────────────┼─────────────┼──────────────┼───────────────┤
|
||||||
|
│ 团队门槛 │ 中等 │ 低(Java转型)│ 低 │ 高 │
|
||||||
|
├─────────┼────────────┼─────────────┼──────────────┼───────────────┤
|
||||||
|
│ 负责服务 │ MA网关 │ 工作台BFF │ 审核AI管道 │ C2PA SDK │
|
||||||
|
│ │ 赋码引擎 │ 审核编排 │ 版权链交互 │ 视频指纹 │
|
||||||
|
│ │ 清算引擎 │ 平台接入 │ 文档生成 │ 编解码加速 │
|
||||||
|
│ │ 区块链服务 │ 数据回传 │ 任务调度 │ │
|
||||||
|
│ │ │ 报表对账 │ │ │
|
||||||
|
│ │ │ 通知回调 │ │ │
|
||||||
|
├─────────┼────────────┼─────────────┼──────────────┼───────────────┤
|
||||||
|
│ 框架 │ Gin/Echo │ Spring Boot │ FastAPI │ c2pa-rs │
|
||||||
|
│ │ GORM │ 3.x+WebFlux │ Celery │ PyO3/N-API │
|
||||||
|
│ │ ChainMaker │ Exposed/R2DBC│ SQLAlchemy │ CGO │
|
||||||
|
│ │ SDK │ Ktor(备选) │ Triton Cli │ │
|
||||||
|
├─────────┼────────────┼─────────────┼──────────────┼───────────────┤
|
||||||
|
│ 构建产物 │ 静态二进制 │ JVM JAR/ │ Docker容器 │ .so/.dylib │
|
||||||
|
│ │ <20MB │ Native(GraalVM)│ + wheel │ + WASM │
|
||||||
|
├─────────┼────────────┼─────────────┼──────────────┼───────────────┤
|
||||||
|
│ 一期占比 │ 35% │ 25% │ 30% │ 10% │
|
||||||
|
│ 三期占比 │ 30% │ 35% │ 20% │ 15% │
|
||||||
|
└─────────┴────────────┴─────────────┴──────────────┴───────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 选型理由可视化(雷达图)
|
||||||
|
|
||||||
|
```
|
||||||
|
建议绘制 4 个重叠雷达图,5 个维度轴:
|
||||||
|
- 性能 (Performance)
|
||||||
|
- 生态成熟度 (Ecosystem)
|
||||||
|
- 团队可得性 (Hiring)
|
||||||
|
- 类型安全 (Type Safety)
|
||||||
|
- AI/ML亲和力 (AI Affinity)
|
||||||
|
|
||||||
|
Go: 性能★★★★☆ 生态★★★★★ 招聘★★★★☆ 类型★★★☆☆ AI★★☆☆☆
|
||||||
|
Kotlin: 性能★★★★☆ 生态★★★★★ 招聘★★★★★ 类型★★★★★ AI★★★☆☆
|
||||||
|
Python: 性能★★☆☆☆ 生态★★★★☆ 招聘★★★★★ 类型★★☆☆☆ AI★★★★★
|
||||||
|
Rust: 性能★★★★★ 生态★★★☆☆ 招聘★★☆☆☆ 类型★★★★★ AI★★☆☆☆
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、Kotlin 在系统中的具体定位与服务拆分
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────┐
|
||||||
|
│ Kotlin 服务群(Spring Boot 3.x) │
|
||||||
|
│ │
|
||||||
|
│ ┌─────────────────────────────────────────────────────┐ │
|
||||||
|
│ │ workbench-bff (工作台聚合网关) │ │
|
||||||
|
│ │ · GraphQL/REST → 聚合赋码+审核+分账数据 │ │
|
||||||
|
│ │ · WebFlux 非阻塞 · R2DBC 响应式DB │ │
|
||||||
|
│ │ · 协程处理:并行调用多个下游微服务 │ │
|
||||||
|
│ └─────────────────────────────────────────────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ ┌─────────────────────────────────────────────────────┐ │
|
||||||
|
│ │ review-orchestrator (审核编排服务) │ │
|
||||||
|
│ │ · 状态机驱动(Spring StateMachine / 自研 Kotlin DSL)│ │
|
||||||
|
│ │ · queued→preprocessing→inferencing→fusion→completed │ │
|
||||||
|
│ │ · 协程编排多个AI模型的并行推理结果聚合 │ │
|
||||||
|
│ │ · 优先级队列管理(P/G/O 三级) │ │
|
||||||
|
│ └─────────────────────────────────────────────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ ┌─────────────────────────────────────────────────────┐ │
|
||||||
|
│ │ platform-access-svc (平台接入管理) │ │
|
||||||
|
│ │ · 平台注册/激活/冻结全生命周期 │ │
|
||||||
|
│ │ · API Key 管理 · 配额管控 · OAuth2 Server │ │
|
||||||
|
│ │ · 多租户数据隔离 │ │
|
||||||
|
│ └─────────────────────────────────────────────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ ┌─────────────────────────────────────────────────────┐ │
|
||||||
|
│ │ data-ingest-svc (数据回传服务) │ │
|
||||||
|
│ │ · Kafka Consumer (Kotlin Coroutines) │ │
|
||||||
|
│ │ · 批量数据校验 + ClickHouse 批写入 │ │
|
||||||
|
│ │ · 播放数据聚合 · 异常检测触发 │ │
|
||||||
|
│ └─────────────────────────────────────────────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ ┌─────────────────────────────────────────────────────┐ │
|
||||||
|
│ │ report-svc (报表与对账服务) │ │
|
||||||
|
│ │ · 定时任务(Spring Scheduler + Coroutines) │ │
|
||||||
|
│ │ · 月度对账单 · 版权估值报告 · 监管日报 │ │
|
||||||
|
│ │ · 导出 PDF/Excel │ │
|
||||||
|
│ └─────────────────────────────────────────────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ ┌─────────────────────────────────────────────────────┐ │
|
||||||
|
│ │ notification-svc (通知与回调服务) │ │
|
||||||
|
│ │ · WebHook 回调(审核完成/赋码成功/分账到账) │ │
|
||||||
|
│ │ · 邮件/短信/站内信 · 重试+幂等 │ │
|
||||||
|
│ │ · Spring Retry + Kotlin sealed class 状态建模 │ │
|
||||||
|
│ └─────────────────────────────────────────────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ 技术栈明细: │
|
||||||
|
│ · Kotlin 2.0 + Spring Boot 3.3 + Spring WebFlux │
|
||||||
|
│ · Kotlin Coroutines + Flow(响应式流) │
|
||||||
|
│ · Exposed / R2DBC(响应式数据库访问) │
|
||||||
|
│ · Spring Security + OAuth2 Resource Server │
|
||||||
|
│ · Kotest(测试)+ MockK(Mock)+ Testcontainers │
|
||||||
|
│ · GraalVM Native Image(可选,冷启动优化) │
|
||||||
|
│ · Gradle Kotlin DSL 构建 │
|
||||||
|
└─────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、右栏:技术路线甘特图
|
||||||
|
|
||||||
|
### 绘制方式:横向时间轴 + 纵向服务/组件行
|
||||||
|
|
||||||
|
```
|
||||||
|
时间轴 → M1 M2 M3 M4 M5 M6 │ M7 M8 M9 M10 M11 M12 │ Y2
|
||||||
|
├─────── 一期:筑基 ─────────┤├──────── 二期:贯通 ──────────┤├─ 三期 ─→
|
||||||
|
|
||||||
|
═══════════════════════════════════════════════════════════════════════════════
|
||||||
|
基础设施
|
||||||
|
─────────────────────────────────────────────────────────────────────────────
|
||||||
|
K8s集群 ████████ 升级1.30+→
|
||||||
|
PG+Redis+Kafka ████████
|
||||||
|
等保三级测评 ░░░░░░░░░░░░░░░░████ 复测
|
||||||
|
Harbor+Vault ████
|
||||||
|
|
||||||
|
═══════════════════════════════════════════════════════════════════════════════
|
||||||
|
Go 服务
|
||||||
|
─────────────────────────────────────────────────────────────────────────────
|
||||||
|
赋码引擎V1 ████████████████
|
||||||
|
MA网关V1 ████████████
|
||||||
|
清算引擎V1 ████████████████
|
||||||
|
区块链服务V1 ████████████████████
|
||||||
|
MA网关V2(根解析) ████████████
|
||||||
|
|
||||||
|
═══════════════════════════════════════════════════════════════════════════════
|
||||||
|
Kotlin 服务
|
||||||
|
─────────────────────────────────────────────────────────────────────────────
|
||||||
|
工作台BFF V1 ████████████████
|
||||||
|
审核编排V1 ████████████████
|
||||||
|
平台接入管理 ████████████
|
||||||
|
工作台BFF V2 ████████████
|
||||||
|
数据回传服务 ████████
|
||||||
|
报表对账服务 ████████████
|
||||||
|
通知回调服务 ████████
|
||||||
|
平台接入V2(OAuth2) ████████
|
||||||
|
|
||||||
|
═══════════════════════════════════════════════════════════════════════════════
|
||||||
|
Python 服务
|
||||||
|
─────────────────────────────────────────────────────────────────────────────
|
||||||
|
审核AI管道V1(画面+台词) ████████████████████
|
||||||
|
文档生成(PDF证书) ████████
|
||||||
|
审核AI管道V2(+声音+真实性) ████████████████████████
|
||||||
|
版权链交互层 ████████████████
|
||||||
|
|
||||||
|
═══════════════════════════════════════════════════════════════════════════════
|
||||||
|
Rust 服务
|
||||||
|
─────────────────────────────────────────────────────────────────────────────
|
||||||
|
C2PA SDK V1(Python绑定) ████████████████
|
||||||
|
视频指纹提取 ████████████████
|
||||||
|
C2PA SDK V2(JS/Go绑定) ████████████████
|
||||||
|
WASM边缘模块(机顶盒) ████████→
|
||||||
|
|
||||||
|
═══════════════════════════════════════════════════════════════════════════════
|
||||||
|
区块链
|
||||||
|
─────────────────────────────────────────────────────────────────────────────
|
||||||
|
ChainMaker部署+合约V1 ████████████████████████
|
||||||
|
版权主链合约 ████████████████
|
||||||
|
用户权益合约 ████████████████
|
||||||
|
分账清算合约 ████████████████
|
||||||
|
|
||||||
|
═══════════════════════════════════════════════════════════════════════════════
|
||||||
|
AI 模型
|
||||||
|
─────────────────────────────────────────────────────────────────────────────
|
||||||
|
画面合规模型V1 ████████████████
|
||||||
|
台词NLP模型V1 ████████████████
|
||||||
|
Triton部署+调优 ████████████████
|
||||||
|
声音合规模型V1 ████████████████
|
||||||
|
AIGC真实性模型V1 ████████████████████
|
||||||
|
版权指纹+Milvus ████████████████
|
||||||
|
模型V2全量迭代 ████→
|
||||||
|
|
||||||
|
═══════════════════════════════════════════════════════════════════════════════
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 六、服务间通信矩阵(附图)
|
||||||
|
|
||||||
|
```
|
||||||
|
┌───────────────────────────────────────────────────────────────┐
|
||||||
|
│ 服务间通信方式矩阵 │
|
||||||
|
├─────────────────┬──────────┬──────────┬──────────┬───────────┤
|
||||||
|
│ 调用方 → 被调方 │ 同步REST │ 异步Kafka│ gRPC │ 内部SDK │
|
||||||
|
├─────────────────┼──────────┼──────────┼──────────┼───────────┤
|
||||||
|
│ 工作台BFF(Kt) │ → 赋码(Go)│ │ │ │
|
||||||
|
│ │ → 审核(Kt)│ │ │ │
|
||||||
|
│ │ → 清算(Go)│ │ │ │
|
||||||
|
├─────────────────┼──────────┼──────────┼──────────┼───────────┤
|
||||||
|
│ 赋码引擎(Go) │ │ → 审核 │ │ │
|
||||||
|
│ │ │ → 链服务 │ │ → C2PA(Rust)│
|
||||||
|
├─────────────────┼──────────┼──────────┼──────────┼───────────┤
|
||||||
|
│ 审核编排(Kt) │ → Triton │ │ │ → 指纹(Rust)│
|
||||||
|
│ │(HTTP/gRPC)│→ 链服务 │ │ │
|
||||||
|
├─────────────────┼──────────┼──────────┼──────────┼───────────┤
|
||||||
|
│ 清算引擎(Go) │ │ → 链服务 │ │ │
|
||||||
|
│ │ → CH查询 │ │ │ │
|
||||||
|
├─────────────────┼──────────┼──────────┼──────────┼───────────┤
|
||||||
|
│ 链服务(Go) │ │ ← 赋码 │→ ChainMaker│ │
|
||||||
|
│ │ │ ← 审核 │ (gRPC) │ │
|
||||||
|
│ │ │ → 确认 │ │ │
|
||||||
|
├─────────────────┼──────────┼──────────┼──────────┼───────────┤
|
||||||
|
│ 数据回传(Kt) │ │ ← 网关 │ │ │
|
||||||
|
│ │ → CH写入 │ → 清算 │ │ │
|
||||||
|
├─────────────────┼──────────┼──────────┼──────────┼───────────┤
|
||||||
|
│ MA网关(Go) │ → ZIIOT │ → 播放 │ │ │
|
||||||
|
│ │ ← 平台 │ │ │ │
|
||||||
|
└─────────────────┴──────────┴──────────┴──────────┴───────────┘
|
||||||
|
|
||||||
|
通信规范:
|
||||||
|
· 同步REST: OpenAPI 3.1 规范 · 超时3s · 重试2次 · 熔断(Resilience4j/Go breaker)
|
||||||
|
· 异步Kafka: Avro/JSON Schema Registry · 幂等消费 · DLQ兜底
|
||||||
|
· gRPC: Protobuf 3 · 双向流 · 链上事件订阅
|
||||||
|
· 内部SDK: Rust FFI (CGO/PyO3) · 进程内调用 · 零网络开销
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 七、关键技术决策记录(ADR 摘要,图旁备注)
|
||||||
|
|
||||||
|
| 决策编号 | 决策 | 理由 | 替代方案 |
|
||||||
|
|---------|------|------|---------|
|
||||||
|
| ADR-001 | Go 作为网关/赋码/清算语言 | 单机万级QPS,编译为静态二进制,容器镜像<20MB | Java(GC暂停),Rust(开发效率) |
|
||||||
|
| ADR-002 | Kotlin 作为业务中台语言 | Spring生态+协程+空安全,Java团队无缝迁移 | Java 21(虚拟线程),Go(缺乏Spring生态) |
|
||||||
|
| ADR-003 | Python 专注AI管道 | PyTorch/Triton Client原生支持,模型迭代快 | Kotlin(JVM推理慢),Go(AI生态弱) |
|
||||||
|
| ADR-004 | Rust 负责C2PA与媒体处理 | c2pa-rs官方实现,零GC大文件处理,安全关键 | Go(无c2pa库),C++(内存安全) |
|
||||||
|
| ADR-005 | 长安链优先于Fabric | 国密原生支持,国产自主可控,等保三级必要 | Fabric(成熟但国密需额外适配) |
|
||||||
|
| ADR-006 | PostgreSQL 而非 MySQL | JSONB灵活schema,高级索引,PostGIS备用 | MySQL 8(JSONB弱),TiDB(运维复杂) |
|
||||||
|
| ADR-007 | Kafka 而非 RabbitMQ | 海量播放数据(日亿级)吞吐需求,持久化回溯 | RabbitMQ(吞吐不足),Pulsar(生态不成熟) |
|
||||||
|
| ADR-008 | Kotlin Coroutines而非WebFlux纯响应式 | 代码可读性远优于Reactor链式,调试友好 | Reactor Mono/Flux(回调地狱),Vert.x |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 八、性能指标与容量规划(图旁表格)
|
||||||
|
|
||||||
|
| 指标 | 一期目标 | 二期目标 | 三期目标 |
|
||||||
|
|------|---------|---------|---------|
|
||||||
|
| MA网关解析QPS | 2,000 | 10,000 | 50,000 |
|
||||||
|
| 赋码引擎TPS | 100 | 500 | 2,000 |
|
||||||
|
| AI审核吞吐(部/天) | 500 | 5,000 | 50,000 |
|
||||||
|
| 播放数据写入(条/秒) | 10,000 | 100,000 | 1,000,000 |
|
||||||
|
| 链上TPS | 100 | 500 | 2,000 |
|
||||||
|
| P99延迟(网关解析) | <50ms | <30ms | <20ms |
|
||||||
|
| P99延迟(赋码流程) | <5s | <3s | <1s |
|
||||||
|
| 存储容量 | 50TB | 200TB | 1PB+ |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 九、视觉设计建议
|
||||||
|
|
||||||
|
| 元素 | 建议 |
|
||||||
|
|------|------|
|
||||||
|
| 语言色彩编码 | Go=天蓝 · Kotlin=紫色 · Python=金黄 · Rust=橙红 |
|
||||||
|
| 层级色彩 | 接入层-浅灰 · 服务层-白底+语言色块 · 数据层-深灰 · 基础设施-黑色 |
|
||||||
|
| 连线 | 同步调用=实线 · 异步Kafka=虚线+闪电图标 · gRPC=双线 · FFI=波浪线 |
|
||||||
|
| 甘特图配色 | Go任务=天蓝条 · Kotlin任务=紫色条 · Python=金黄 · Rust=橙红 · 基础设施=灰 |
|
||||||
|
| 信息层次 | 架构师看左栏分层 · 开发者看中栏选型 · PM看右栏路线图 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> 本文档是面向技术专家的"深度详图"绘制蓝图。
|
||||||
|
> 与"全景图"的区别:全景图侧重业务+技术平衡,本图100%聚焦技术实现细节。
|
||||||
|
> Kotlin 作为第四种核心语言加入,承担原方案中 Python 业务编排层与部分 Go 业务服务的职责,
|
||||||
|
> 形成 **Go(网关/计算) + Kotlin(业务中台) + Python(AI) + Rust(底层)** 的四语言协同架构。
|
||||||
@@ -0,0 +1,858 @@
|
|||||||
|
# AIGC-Hub智视码(AVCC)体系建设方案
|
||||||
|
|
||||||
|
国家 AIGC 视听内容登记与分发基础设
|
||||||
|
施
|
||||||
|
(AIGC-Hub)总体方案
|
||||||
|
—— 智视码(AVCC)体系建设方案 ——
|
||||||
|
基于 MA 全球统一标识代码体系(ISO/IEC 15459)
|
||||||
|
建设和运营方:广电云
|
||||||
|
(中国广电网络股份有限公司)
|
||||||
|
MA 全球代码发行机构:中关村工信二维码技术研究院(ZIIOT)
|
||||||
|
二〇二六年五月
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
1
|
||||||
|
文档控制信息
|
||||||
|
文档名称 国家 AIGC 视听内容登记与分发基础设施
|
||||||
|
(AIGC-Hub)总体方案——智视码(AVCC)
|
||||||
|
基于 MA 全球统一标识代码体系建设方案
|
||||||
|
版本号 V2.0(MA 融合修订版)
|
||||||
|
编制单位 广电云(中国广电网络股份有限公司)
|
||||||
|
MA 技术支撑 中关村工信二维码技术研究院(ZIIOT)
|
||||||
|
密级 内部公开
|
||||||
|
适用范围 国家广播电视总局、省级广电主管部门、网
|
||||||
|
络视听平台、AIGC 内容创作者、MA 标识注册
|
||||||
|
管理机构
|
||||||
|
编制日期 2026 年 5 月
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
2
|
||||||
|
执行摘要
|
||||||
|
随着生成式人工智能(AIGC)技术的爆发,AI 漫剧(AI 生成的动画/漫画短剧)正以前所
|
||||||
|
未有的速度涌入网络视听市场。传统的内容监管体系面临产量爆炸、溯源困难、版权混乱、平
|
||||||
|
台割裂四大挑战。与此同时,Movies Anywhere(MA)模式在好莱坞的成功实践,证明了统一
|
||||||
|
编码、跨平台互认、权益聚合在数字内容治理中的巨大价值。
|
||||||
|
本方案提出建设国家 AIGC 视听内容登记与分发基础设施(AIGC-Hub),由广电云作为建
|
||||||
|
设和运营主体,创新设计智视码(AI Visual Content Code, AVCC)国家 AIGC 视听内容统一标
|
||||||
|
识码体系。
|
||||||
|
关键创新:本方案将 AVCC 深度融入 MA 全球统一标识代码体系(ISO/IEC 15459)。MA 是
|
||||||
|
由中关村工信二维码技术研究院(ZIIOT)获得国际标准化组织(ISO)、欧洲标准委员会
|
||||||
|
(CEN)、国际自动识别与移动技术协会(AIM)三大国际组织批准认可的全球代码发行机构,
|
||||||
|
发行机构代码为 MA。MA 标识体系具有完全自主知识产权、全球唯一性和国际通用性,是中国
|
||||||
|
首个具有全球根节点管理权和代码资源分配权的国际标识代码。
|
||||||
|
通过将 AVCC 纳入 MA 体系(根标识符 MA + 中国国家代码 156 + 广电云视听内容行业节
|
||||||
|
点),AIGC-Hub 实现了:
|
||||||
|
(1)编码国际化:AVCC 从行业内部码升级为具有全球唯一性的国际标识,为 AIGC 内容出
|
||||||
|
海、跨境版权维权提供技术基础;
|
||||||
|
(2)解析全球化:依托 MA 标识解析国家顶级节点(广州、上海、北京、重庆、武汉)和
|
||||||
|
全球根服务体系,实现一码跨域、跨平台、跨国界解析;
|
||||||
|
(3)监管合规化:对接国家数据基础设施建设指引(2025)、工业互联网标识解析体系
|
||||||
|
贯通行动计划(2024-2026)、城市码建设要求,构建基于统一目录标识、统一身份登记、统
|
||||||
|
一接口要求的数据流通利用设施底座;
|
||||||
|
(4)产业生态化:借鉴 MA 在工业互联网、数字贸易、地理实体、碳码等领域的行业根节
|
||||||
|
点建设经验,建立 MA.AIGC 视听内容行业根节点,形成从 ZIIOT 全球根节点到广电云行业节点
|
||||||
|
再到平台企业节点的三级架构。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
3
|
||||||
|
方案核心遵循监管集权、运营中立、责任分散三大原则:广电总局握规则、握终审、握黑
|
||||||
|
名单;广电云搭基础设施、卖合规工具、做跨平台清算,同时作为 MA 行业节点负责码资源分
|
||||||
|
配与解析;平台承担主体责任,但可借助广电云和 MA 工具大幅降低合规成本;创作者/工具方
|
||||||
|
承担源头责任,但获得确权、分账、跨平台变现的明确路径。
|
||||||
|
通过四层商业模式(赋码服务、审核增值、版权链结算、数据运营),广电云实现从管道
|
||||||
|
商到内容金融基础设施运营商的战略升级,为 AI 时代网络视听产业的管得住与放得活提供系
|
||||||
|
统性解决方案。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
4
|
||||||
|
第一章 项目定位与目标
|
||||||
|
1.1 项目背景
|
||||||
|
2022 年 6 月 1 日起,国家广电总局对国产重点网络剧片实施《网络剧片发行许可证》
|
||||||
|
(业内俗称网标)制度,标志着网络视听内容进入许可证时代。2025 年 2 月,广电总局进一
|
||||||
|
步对网络微短剧实行分类分层审核。
|
||||||
|
与此同时,AIGC 技术的爆发式增长带来了全新挑战:AI 漫剧日产量可达传统内容的百
|
||||||
|
倍,单部作品版权链条涉及模型商、数据方、提示词工程师、人工后期等多方,同一作品经
|
||||||
|
AI 微调后可在多平台以不同形态重复传播。
|
||||||
|
更为关键的是,数字身份基础设施已成为全球竞争的战略制高点。美国将数字身份基础设
|
||||||
|
施纳入国家战略,欧盟创建安全的数字身份系统,中国通过《数字中国建设整体布局规划》
|
||||||
|
《国家数据基础设施建设指引》等文件,明确要求建立基于统一目录标识、统一身份登记、统
|
||||||
|
一接口要求的数据流通利用设施底座。
|
||||||
|
1.2 MA 全球标识代码体系:AIGC-Hub 的技术底座
|
||||||
|
MA 标识代码体系由中关村工信二维码技术研究院(ZIIOT)运营管理。2018 年 8 月 1 日,
|
||||||
|
ZIIOT 获得 ISO、CEN、AIM 三大国际组织批准认可成为全球代码发行机构,发行机构代码为
|
||||||
|
MA,填补了我国在基础代码资源领域的空白。
|
||||||
|
MA 标识代码也称数字身份代码,是基础信息资源。万物互联时代,所有链接对象都需要
|
||||||
|
有自己的身份证。MA 编码结构分为三个层级:WHO(用户根,一组织一码)、WHAT(对象类
|
||||||
|
目,一品类一码)、WHICH(个体编码,一物一码)。
|
||||||
|
MA 标识体系具有四大优势:(1)完全自主知识产权的国际标准标识代码,具有全球唯一
|
||||||
|
性和国际通用性;(2)中国首个具有全球根节点管理权和代码资源分配权的国际标识代码,
|
||||||
|
拥有面向全球发码的资格;(3)矩阵式编码结构,编码灵活,可分权、分层、分级管理;
|
||||||
|
(4)兼容开放、可扩展性强,实现跨地域、跨平台、跨系统、跨载体之间的互联互通。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
5
|
||||||
|
1.3 项目定位
|
||||||
|
项目名称:国家 AIGC 视听内容登记与分发基础设施(AIGC-Hub)
|
||||||
|
建设和运营方:广电云(中国广电网络股份有限公司)
|
||||||
|
MA 全球代码发行与技术支撑:中关村工信二维码技术研究院(ZIIOT)
|
||||||
|
核心目标:以现行网络剧片发行许可证(网标)制度为监管底座,以 MA 全球统一标识代
|
||||||
|
码体系(ISO/IEC 15459)为技术底座,为 AI 漫剧建立一剧一码、一码全网、码链同源、全球
|
||||||
|
互认的国家级管理基础设施。
|
||||||
|
1.4 关键约束
|
||||||
|
方案设计必须满足双重约束:既满足广电总局对 AI 生成内容管得住的监管要求,又通过
|
||||||
|
分层责任架构将日常审核、技术验证、版权举证等责任适当分解至平台、创作者、AI 工具
|
||||||
|
方;同时必须遵循 MA 标识体系的国际标准规范,确保编码的全球唯一性、可解析性和可扩展
|
||||||
|
性。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
6
|
||||||
|
第二章 核心设计原则:监管与分责的平衡
|
||||||
|
AIGC-Hub 体系围绕以下七项原则构建责任分配机制:
|
||||||
|
设计原则 监管侧(广电总局/广电云/ZIIOT) 分责侧(平台/创作者/工具
|
||||||
|
方)
|
||||||
|
标准统一 广电总局制定 AIGC 内容审核标准;ZIIOT 制定 MA
|
||||||
|
标识编码与解析国际标准;广电云制定行业应用
|
||||||
|
规范
|
||||||
|
平台按统一标准执行,不得自行
|
||||||
|
降标;创作者按标准嵌入 C2PA
|
||||||
|
水印
|
||||||
|
分类分级 广电总局/省级广电掌握重点内容终审权;广电云
|
||||||
|
作为 MA 行业节点负责码资源分配
|
||||||
|
平台对普通/其他类承担主体责
|
||||||
|
任,自主审核、自主处置
|
||||||
|
技术赋能 广电云提供智能审核引擎、编码系统、版权链工
|
||||||
|
具;ZIIOT 提供 MA 根解析服务
|
||||||
|
平台可选择调用或自建,但结果
|
||||||
|
必须符合国标和 MA 标准
|
||||||
|
源头举证 广电云建立 C2PA 水印规范;ZIIOT 建立 MA 标识
|
||||||
|
注册管理机制
|
||||||
|
创作者/工具方在生成环节即嵌
|
||||||
|
入水印和 MA 标识,承担源头合
|
||||||
|
规责任
|
||||||
|
一码全球 ZIIOT 确保 MA 标识全球唯一、全球解析;广电云
|
||||||
|
确保 AVCC 与网标衔接
|
||||||
|
平台通过 MA 编码网关实现跨平
|
||||||
|
台、跨境内容识别与权益互认
|
||||||
|
事后追责 广电总局保留全网下架、黑名单、行政处罚权;
|
||||||
|
ZIIOT 保留违规码资源回收权
|
||||||
|
平台对未及时发现违规内容承担
|
||||||
|
连带管理责任
|
||||||
|
运营中立 广电云作为中立基础设施运营方,不投资、不经
|
||||||
|
营内容;ZIIOT 作为代码发行机构中立发码
|
||||||
|
各市场主体在统一规则下公平竞
|
||||||
|
争
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
7
|
||||||
|
第三章 总体架构:MA 根节点+1+3+N
|
||||||
|
AIGC-Hub 采用 MA 根节点+1+3+N 总体架构,以 ZIIOT MA 全球根节点为技术底座,以广电云为
|
||||||
|
核心运营节点,构建监管层、运营层、应用层四级体系:
|
||||||
|
MA 全球根节点:ZIIOT 运营,代码 MA,负责全球码资源分配、根解析服务、国际标准对
|
||||||
|
接。
|
||||||
|
1 朵云:广电云提供等保三级以上的专属云资源池,作为 AIGC-Hub 的唯一建设和运营主
|
||||||
|
体,同时承担 MA.AIGC 视听内容行业节点运营职责。
|
||||||
|
3 大引擎:赋码引擎(智视码发行)、审核引擎(AI 辅助合规检测)、链上存证引擎(版
|
||||||
|
权链与分账清算)。
|
||||||
|
N 个接入方:长视频平台、短视频平台、AI 生成工具、MCN 机构、版权方等全产业链主
|
||||||
|
体,作为 MA 三级节点或注册使用方接入。
|
||||||
|
3.1 MA 标识解析体系架构融入
|
||||||
|
MA 标识解析体系整体架构为树形层次结构,从上到下分别是 MA 根节点、一级节点、二级
|
||||||
|
节点和三级节点及以下节点。AIGC-Hub 完全融入该架构:
|
||||||
|
MA 层级 AIGC-Hub 对应角色 代码示例
|
||||||
|
根节点 ZIIOT(全球代码发行机构) MA
|
||||||
|
一级节点 中国(国家地域节点) MA.156
|
||||||
|
二级节点(行业节点) 广电云(AIGC 视听内容行业节点) MA.156.10005(拟申请)
|
||||||
|
三级节点及以下 长视频平台、短视频平台、AI 工具
|
||||||
|
厂商、MCN 机构
|
||||||
|
MA.156.10005.0001(平台节
|
||||||
|
点)
|
||||||
|
注:参照 ZIIOT 已授权的行业根节点模式——MA.1001(基础地理实体,联合中国测绘科学
|
||||||
|
研究院)、MA.1002(全球河网,联合清华大学)、MA.10003(数字贸易,联合商务部研究
|
||||||
|
院)、MA.10001(安全应急,联合中国安全生产科学研究院)——广电云向 ZIIOT 申请 MA.AIGC
|
||||||
|
视听内容行业根节点(建议代码 MA.156.10005)。
|
||||||
|
3.2 责任边界说明
|
||||||
|
层级 责任主体 责任边界
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
8
|
||||||
|
监管层 广电总局/省级广电 不直接面对海量创作者,只面对广电云和重点内
|
||||||
|
容;不审其他类微短剧,只审重点/特殊题材;握规
|
||||||
|
则、握终审、握黑名单。
|
||||||
|
MA 全球根 ZIIOT 负责 MA 代码资源全球分配、根解析服务、国际标
|
||||||
|
准维护;对违规码资源行使回收权;不介入具体内
|
||||||
|
容审核。
|
||||||
|
运营层 广电云 作为 MA.AIGC 行业节点,负责行业码资源分配、赋
|
||||||
|
码发行、解析服务;不做内容价值的审美判断,只
|
||||||
|
做合规性的技术检测和编码发行;不替平台承担内
|
||||||
|
容主体责任。
|
||||||
|
平台层 长视频/短视频平台 不能将审核责任完全外包给广电云,必须建立自有
|
||||||
|
审核团队,对上线内容承担主体责任;作为 MA 三
|
||||||
|
级节点负责平台内内容注册与解析。
|
||||||
|
源头层 创作者/AI 工具方 对作品源头真实性负责,必须提交 C2PA 水印、MA
|
||||||
|
标识和版权自证材料,否则不予赋码;对 MA 标识
|
||||||
|
段的真实性负完全法律责任。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
9
|
||||||
|
第四章 智视码(AVCC)编码体系——MA 融合版
|
||||||
|
智视码(AI Visual Content Code, AVCC)是 AIGC-Hub 的核心标识体系。在 MA 融合版本
|
||||||
|
中,AVCC 采用六段式结构,前段完全纳入 MA 全球标识代码体系,中段复用现行网络剧片发行
|
||||||
|
许可证编号,后段增加 AIGC 专属标识,实现国际标准、国内监管、行业应用的三位一体。
|
||||||
|
4.1 编码结构
|
||||||
|
AVCC(MA 融合版)= [MA 根] + [国家/行业节点] + [监管段] + [类别段] + [技术段]
|
||||||
|
+ [版权段]
|
||||||
|
完整示例:MA.156.10005.8361/10.1300200.AIGC/(京)网微剧审字(2026)第 001 号-P-AI-
|
||||||
|
HASH(a1b2c3)-CRD(0x7f3e9a)
|
||||||
|
编码段 内容示例 生成主体 可修改主体 责任/标准说明
|
||||||
|
MA 根 MA ZIIOT(全球代码
|
||||||
|
发行机构)
|
||||||
|
ZIIOT ISO/IEC 15459 国际标
|
||||||
|
准,全球唯一根标识符
|
||||||
|
国家/行业节点 156.10005.8361 ZIIOT 分配国家代
|
||||||
|
码 156;广电云运
|
||||||
|
营行业节点
|
||||||
|
10005;平台/机构
|
||||||
|
代码 8361
|
||||||
|
ZIIOT 分配,广电
|
||||||
|
云管理
|
||||||
|
参照 MA.1001/1002/10003
|
||||||
|
等行业根节点授权模式
|
||||||
|
对象类目 10.1300200.AIGC 广电云编码系统 广电云(类目扩
|
||||||
|
展时更新)
|
||||||
|
10=视听内容大类;
|
||||||
|
1300200=AI 漫剧细分类
|
||||||
|
目;AIGC=内容生成方式
|
||||||
|
标识
|
||||||
|
监管段 (京)网微剧审字
|
||||||
|
(2026)第 001 号
|
||||||
|
广电云(对接广电
|
||||||
|
总局系统)
|
||||||
|
广电总局 唯一权威,不可篡改,
|
||||||
|
代表行政许可
|
||||||
|
类别段 -P- 广电云智能审核引
|
||||||
|
擎
|
||||||
|
省级广电/广电总
|
||||||
|
局(申诉复核)
|
||||||
|
P=重点;G=普通;O=其
|
||||||
|
他
|
||||||
|
技术段 -AI-HASH(a1b2c3) 创作者/工具方提
|
||||||
|
交,广电云核验
|
||||||
|
创作者(修改后
|
||||||
|
重新赋码)
|
||||||
|
创作者对生成日志真实
|
||||||
|
性负责,造假者列入黑
|
||||||
|
名单
|
||||||
|
版权段 -CRD(0x7f3e9a) 创作者填写,广电
|
||||||
|
云上链
|
||||||
|
创作者(授权变
|
||||||
|
更时更新)
|
||||||
|
区块链存证地址,创作
|
||||||
|
者对版权声明真实性负
|
||||||
|
责
|
||||||
|
4.2 类别段与流通权限映射
|
||||||
|
类别 编码前缀 流通范围 MA 解析权限 平台责任
|
||||||
|
重点 AI 漫剧 AVCC-P 全网全平台,首 MA 根节点+行业 承担主体责任,
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
10
|
||||||
|
页推荐 节点+平台节点三
|
||||||
|
级解析
|
||||||
|
必须人工复核广
|
||||||
|
电云 AI 预审报告
|
||||||
|
普通 AI 漫剧 AVCC-G 平台内播放,非
|
||||||
|
首页推荐
|
||||||
|
MA 行业节点+平
|
||||||
|
台节点解析
|
||||||
|
承担主体责任,
|
||||||
|
复核记录上链备
|
||||||
|
查
|
||||||
|
其他 AI 漫剧 AVCC-O 限本平台/限免流
|
||||||
|
播放
|
||||||
|
平台节点本地解
|
||||||
|
析
|
||||||
|
承担全部主体责
|
||||||
|
任,禁止买量推
|
||||||
|
荐
|
||||||
|
4.3 MA 编码优势在 AIGC 领域的延伸
|
||||||
|
全球唯一性:通过 MA 根节点(ZIIOT)分配,确保每一部 AI 漫剧在全球范围内的身份唯
|
||||||
|
一,解决换平台、换剧名、换脸后的重复识别问题。
|
||||||
|
国际通用性:MA 标识获得 ISO/CEN/AIM 三大国际组织认可,AVCC 可无障碍在国际平台解
|
||||||
|
析,为中国 AIGC 内容出海提供身份认证基础。
|
||||||
|
分权分层管理:ZIIOT 管理根节点,广电云管理行业节点,平台管理企业节点,创作者管
|
||||||
|
理个体编码,权责清晰。
|
||||||
|
跨域互联互通:AVCC 不仅可在视听平台间解析,还可与工业互联网(MA.10000)、数字贸
|
||||||
|
易(MA.10003)、碳码(MA.C.)等领域实现数据互通,支撑 AIGC 内容作为数字资产的全生命
|
||||||
|
周期管理。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
11
|
||||||
|
第五章 全链路业务流程与责任分解
|
||||||
|
5.1 创作端:源头举证(创作者/AI 工具方责任)
|
||||||
|
第一步:AI 绘画/视频工具接入广电云 SDK,在生成作品时自动嵌入 C2PA 水印(含模型版
|
||||||
|
本、训练数据授权摘要)和 MA 标识片段(平台/机构代码+对象类目)。
|
||||||
|
第二步:创作者提交至广电云赋码中心(MA 行业节点),同步提交:①剧本/分镜 ②生成
|
||||||
|
日志 ③版权自证材料(训练数据授权书/人工修改说明)。
|
||||||
|
第三步:广电云网关预检——是否重复?是否使用黑名单模型?版权材料是否齐全?MA
|
||||||
|
标识片段是否合规?
|
||||||
|
第四步:材料不全则退回补正(创作者责任);材料齐全则进入审核队列,审核通过后由
|
||||||
|
广电云 MA 行业节点分配完整 MA 码资源。
|
||||||
|
责任要点:创作者和工具方对 MA 标识段、技术段和版权段的真实性负完全法律责任。若
|
||||||
|
事后发现伪造授权书、隐瞒未授权模型,直接列入 AIGC-Hub 黑名单,ZIIOT 有权回收其 MA 码
|
||||||
|
资源,全网平台同步禁发。
|
||||||
|
5.2 审核端:分类分级赋码(分层责任)
|
||||||
|
步骤 重点 AI 漫剧 普通 AI 漫剧 其他 AI 漫剧 赋码主体 责任主体
|
||||||
|
规划备案 广电总局/省级
|
||||||
|
广电
|
||||||
|
省级广电 平台自审(广
|
||||||
|
电云提供工
|
||||||
|
具)
|
||||||
|
广电总局/省级
|
||||||
|
广电
|
||||||
|
广电总局承担
|
||||||
|
最终内容责任
|
||||||
|
成片审查 省级广电人工
|
||||||
|
终审(50 日
|
||||||
|
内)
|
||||||
|
广电云 AI 主审
|
||||||
|
+平台人工复核
|
||||||
|
平台 AI 实时审
|
||||||
|
核(广电云提
|
||||||
|
供 API)
|
||||||
|
广电云/平台 平台承担主体
|
||||||
|
责任,广电云
|
||||||
|
承担技术工具
|
||||||
|
责任
|
||||||
|
赋码时效 5-30 个工作日 1-3 个工作日 实时赋码(秒
|
||||||
|
级)
|
||||||
|
广电云 MA 行业
|
||||||
|
节点
|
||||||
|
平台承担全部
|
||||||
|
主体责任
|
||||||
|
MA 码分配 ZIIOT 根节点授
|
||||||
|
权,广电云行
|
||||||
|
业节点分配
|
||||||
|
广电云行业节
|
||||||
|
点直接分配
|
||||||
|
平台节点在授
|
||||||
|
权范围内分配
|
||||||
|
ZIIOT/广电云 码资源滥用由
|
||||||
|
分配方追责
|
||||||
|
责任设计关键:广电总局不审其他类海量内容,只制定标准和事后抽查;平台审不过的内
|
||||||
|
容,广电总局不兜底。广电云对普通类提供 AI 预审报告,但平台必须人工复核并签字确认,
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
12
|
||||||
|
复核记录上链备查。对其他类,广电云仅提供实时赋码接口和基础合规检测,平台自行决定上
|
||||||
|
线,但事后被广电总局抽查发现违规,平台承担管理责任。
|
||||||
|
5.3 分发端:一码全网通(平台责任)
|
||||||
|
作品在 A 平台取得 AVCC 后,B/C/D 平台通过广电云 MA 编码网关解析,自动识别其流通权
|
||||||
|
限,无需重复送审。
|
||||||
|
平台必须校验 AVCC 有效性(含 MA 标识段合法性),不得播放已注销、已下架或类别不符
|
||||||
|
的作品。
|
||||||
|
平台首页推荐、会员付费、广告投放等商业行为,必须校验 AVCC 类别段,禁止为 AVCC-O
|
||||||
|
类作品购买流量推荐。违规平台由广电总局约谈处罚。
|
||||||
|
跨境场景:海外平台通过 ZIIOT MA 根解析服务,可验证 AVCC 的 MA 标识真伪,实现中国
|
||||||
|
AIGC 内容的跨境可信传播。
|
||||||
|
5.4 消费端:权益跨平台(广电云清算责任)
|
||||||
|
用户购买某 AI 漫剧后,权益写入 AVCC 版权段的用户权益子链。
|
||||||
|
用户登录任何接入广电云 MA 网关的平台,扫码/输入 AVCC 即可解锁已购内容。
|
||||||
|
广电云作为跨平台清算中心,负责分账结算和技术服务,但不承担内容消费纠纷的法律责
|
||||||
|
任(纠纷由平台按用户协议处理)。
|
||||||
|
MA 标识支撑:用户权益子链通过 MA 标识与版权主链关联,确保权益在全球范围内的可追
|
||||||
|
溯性。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
13
|
||||||
|
第六章 责任分层设计详解(核心章节)
|
||||||
|
6.1 广电总局:握权不揽事
|
||||||
|
广电总局作为行业最高监管机关,在 AIGC-Hub 体系中行使规则制定权和最终裁决权,但
|
||||||
|
不介入日常运营和海量内容审核。
|
||||||
|
权力/责任 边界说明
|
||||||
|
规则制定权 制定《AIGC 网络视听内容审核细则》,明确 AI 生成内容的禁止性条款、分类
|
||||||
|
标准、黑名单目录
|
||||||
|
终审权 仅对重点 AI 漫剧(AVCC-P)和特殊题材(历史、军事、民族宗教)行使终
|
||||||
|
审,不审普通/其他类
|
||||||
|
黑名单权 对违规模型、违规训练数据集、违规主体实施全网封禁,各平台同步执行
|
||||||
|
事后追责权 对平台主体责任落实情况进行抽查,发现问题依法处罚;对广电云运营合规
|
||||||
|
性进行年度审计
|
||||||
|
不承担责任 不审普通/其他类海量内容;不替平台判断内容价值;不介入具体版权纠纷;
|
||||||
|
不担保广电云技术结果
|
||||||
|
6.2 ZIIOT:全球发码,中立授权
|
||||||
|
ZIIOT 作为 MA 全球代码发行机构,在 AIGC-Hub 体系中承担技术标准底座角色,不介入内
|
||||||
|
容审核和商业运营。
|
||||||
|
责任/权利 边界说明
|
||||||
|
全球代码发行 按照 ISO/IEC 15459 标准,向广电云分配 MA.AIGC 视听内容行业节点代码资
|
||||||
|
源,确保全球唯一性
|
||||||
|
根解析服务 运营 MA 全球根解析系统,支撑 AVCC 的跨境、跨域、跨平台解析
|
||||||
|
标准维护 维护 MA 标识体系的国际标准合规性,与 ISO/CEN/AIM 对接
|
||||||
|
违规码回收 对严重违规的 MA 码资源行使回收权(如伪造国际标识、跨境侵权等)
|
||||||
|
不承担责任 不介入 AIGC 内容的具体审核;不担保广电云的行业节点运营;不参与 AIGC-
|
||||||
|
Hub 的商业分账
|
||||||
|
6.3 广电云:搭台不唱戏,行业节点运营
|
||||||
|
广电云作为中立基础设施运营方和 MA.AIGC 行业节点运营方,承担工具提供、码资源分
|
||||||
|
配、数据存证、跨平台清算等运营责任,但明确划定免责边界。
|
||||||
|
责任/免责 边界说明
|
||||||
|
MA 行业节点运营 向 ZIIOT 申请并运营 MA.AIGC 视听内容行业节点,向平台/创作者分配三级
|
||||||
|
节点代码和个体编码
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
14
|
||||||
|
提供统一工具 提供赋码系统、审核 API、版权链、MA 编码网关,确保工具符合国家标准
|
||||||
|
和 MA 国际标准
|
||||||
|
数据存证 对 AVCC 全生命周期数据进行不可篡改存证,作为监管和仲裁的技术依据
|
||||||
|
跨平台清算 按智能合约执行分账,确保结算数据透明、可追溯、不可篡改
|
||||||
|
技术迭代 持续优化 AIGC 检测模型,识别深度伪造、盗用画风、换皮重发等新型违
|
||||||
|
规手段
|
||||||
|
不承担责任 不替平台做内容终审;不替创作者担保版权真实性;不介入用户消费纠
|
||||||
|
纷;不对平台使用工具的方式负责
|
||||||
|
6.4 平台:主体责任不能甩
|
||||||
|
平台是内容安全的第一道防线,也是内容消费纠纷的直接处理方。AIGC-Hub 为平台提供
|
||||||
|
先进工具,但绝不替代平台的主体责任。
|
||||||
|
必须承担的责任 可借助广电云/ZIIOT 分担的责任
|
||||||
|
内容安全主体责任:上线内容必须符合《网络
|
||||||
|
视听节目内容审核通则》
|
||||||
|
调用广电云 AI 预审 API 降低人工成本;通过
|
||||||
|
MA 编码网关自动识别作品类别
|
||||||
|
流量管控责任:不得为 AVCC-O 类作品购买推
|
||||||
|
荐流量
|
||||||
|
通过编码网关自动识别作品类别,辅助流量管
|
||||||
|
控决策
|
||||||
|
用户投诉处理责任:建立 7×24 小时投诉响应
|
||||||
|
机制
|
||||||
|
投诉涉及版权链争议时,可向广电云申请链上
|
||||||
|
数据仲裁;涉及 MA 标识真伪时,可向 ZIIOT 申
|
||||||
|
请根解析验证
|
||||||
|
数据回传责任:每日回传播放数据、处置记
|
||||||
|
录、异动哈希
|
||||||
|
通过标准化 API 自动回传,降低对接成本
|
||||||
|
不能推卸的责任 即使调用广电云审核 API,平台仍须建立自有
|
||||||
|
审核团队进行复核,最终上线决定由平台做出
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
15
|
||||||
|
6.5 创作者/工具方:源头责任自负
|
||||||
|
创作者和 AI 工具方是内容的源头,对 AVCC 中 MA 标识段、技术段和版权段的真实性负完
|
||||||
|
全法律责任。
|
||||||
|
责任 后果
|
||||||
|
MA 标识嵌入:生成作品时必须嵌入符合 MA 国
|
||||||
|
际标准的 C2PA 水印和内容凭证
|
||||||
|
未嵌入或嵌入虚假信息,不予赋码;ZIIOT 有
|
||||||
|
权回收已分配的 MA 码资源
|
||||||
|
版权自证:提交训练数据授权书、人工修改比
|
||||||
|
例说明
|
||||||
|
事后发现侵权,自行承担法律赔偿,并列入
|
||||||
|
AIGC-Hub 黑名单,MA 码资源被回收
|
||||||
|
生成日志提交:提交模型版本、提示词摘要、
|
||||||
|
修改记录
|
||||||
|
拒绝提交或伪造日志,视为规避监管,全网禁
|
||||||
|
发
|
||||||
|
编码迭代申报:作品被二次 AI 修改后,须重新
|
||||||
|
申请 AVCC-v2
|
||||||
|
擅自修改不换码,按未持证播出处理,平台连
|
||||||
|
带担责
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
16
|
||||||
|
第七章 商业模式:四层收入体系
|
||||||
|
广电云作为中立基础设施运营方和 MA.AIGC 行业节点运营方,围绕编码权、审核权、结算
|
||||||
|
权、数据权构建四层商业闭环,实现从管道商到内容金融基础设施运营商的战略升级。
|
||||||
|
7.1 第一层:赋码服务(基础现金流)
|
||||||
|
赋码是 AIGC-Hub 的门票经济。任何 AI 漫剧要获得合法流通身份,必须经由广电云 MA 行
|
||||||
|
业节点生成 AVCC。
|
||||||
|
收费对象 计费模式 价格逻辑 预估规模
|
||||||
|
重点 AI 漫剧 按项目收费 纳入重点监管体系,
|
||||||
|
免费赋码(行政服务
|
||||||
|
属性)
|
||||||
|
年 1-2 万部
|
||||||
|
普通 AI 漫剧 按项目收费 500-2000 元/部(含
|
||||||
|
AI 预审+人工抽查成
|
||||||
|
本)
|
||||||
|
年 10-20 万部
|
||||||
|
其他 AI 漫剧 按量/按时长 50-200 元/部或 10 元/
|
||||||
|
分钟(纯 AI 审核,边
|
||||||
|
际成本极低)
|
||||||
|
年 100 万+部
|
||||||
|
紧急加急通道 按项目溢价 3 工作日出码:2 倍;
|
||||||
|
24 小时出码:5 倍
|
||||||
|
按需
|
||||||
|
商业设计要点:其他类走量,靠规模摊薄云资源成本;普通类走价,覆盖审核人力成本;
|
||||||
|
重点类免费,换取监管准入的垄断性地位。对 MCN 机构和 AI 工具厂商推出批量赋码年包:预
|
||||||
|
充值 10 万元享 8 折,锁定上游产能。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
17
|
||||||
|
7.2 第二层:审核增值 SaaS(高毛利技术输出)
|
||||||
|
广电云将智能审核引擎以 SaaS/API 形式输出给各平台,平台可选择自建审核或调用广电云
|
||||||
|
审核。
|
||||||
|
产品名 功能 计费模式 目标客户
|
||||||
|
AI 预审 API 画面/台词/声音合规初
|
||||||
|
筛
|
||||||
|
0.5-2 元/次调用 短视频平台、MCN
|
||||||
|
AIGC 真实性核验 检测未授权模型、盗
|
||||||
|
用画风、深度伪造
|
||||||
|
50-500 元/部(按复杂
|
||||||
|
度)
|
||||||
|
长视频平台、版权方
|
||||||
|
版权链比对服务 上传作品与版权库自
|
||||||
|
动比对,防侵权
|
||||||
|
0.1 元/次查询 所有平台
|
||||||
|
模型白名单认证 对合规模型/数据集进
|
||||||
|
行认证,通过认证的
|
||||||
|
作品免审或快审
|
||||||
|
5-20 万元/年(模型认
|
||||||
|
证费)
|
||||||
|
AI 工具厂商
|
||||||
|
商业逻辑:平台自建审核团队成本极高(人均年成本 20 万+,且需持续培训 AIGC 新
|
||||||
|
规)。广电云以 1/3 成本提供标准化审核能力,平台按调用量付费,轻资产运营。认证费是隐
|
||||||
|
性壁垒:AI 模型厂商要进入广电云认证模型库,需缴纳年费并通过合规审查,进入白名单的
|
||||||
|
模型生成的作品自动获得快审通道。
|
||||||
|
7.3 第三层:版权链与跨平台结算(核心变现)
|
||||||
|
这是类 MA 模式最核心的变现层。广电云通过版权链存证平台,成为 AI 漫剧跨平台流通的
|
||||||
|
央行清算中心。同时深度融合 MA 数据要素登记体系。
|
||||||
|
链上存证服务:基础存证 100-500 元/次(含时间戳、哈希锚定);智能合约部署 2000-1
|
||||||
|
万元/合约(复杂分账结构);侵权监测 1 万-10 万元/年/作品(全网爬虫监测 AVCC 作品被非法
|
||||||
|
切片、二次 AI 修改)。
|
||||||
|
MA 数据要素登记证书:联合 ZIIOT、深圳数据交易所、人民数据等机构,为优质 AIGC 内
|
||||||
|
容签发 MA 数据要素登记证书(参照工业互联网数据要素登记证书模式),按证书等级收费
|
||||||
|
(500-5000 元/份)。
|
||||||
|
跨平台清算佣金:当用户通过 AVCC 体系实现跨平台权益互认(如在抖音购买,在 B 站观
|
||||||
|
看),广电云作为清算方抽取 6-8%技术服务费。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
18
|
||||||
|
跨境数字贸易:接入 MA 数字贸易标识根节点(MA.10003),AIGC 内容作为数字文化产品
|
||||||
|
出口时,通过 MA 标识实现跨境全程可追溯,广电云收取跨境标识服务费(1-3%交易金额)。
|
||||||
|
版权金融衍生:基于版权链存证,创作者以 AVCC 作品版权向银行申请质押贷款,广电云
|
||||||
|
提供版权估值报告(按播放量、分账流水、用户评分),收取评估服务费;将一批优质 AVCC
|
||||||
|
作品的预期分账收益打包发行 ABS,广电云作为底层数据提供方和清算代理,收取通道费。
|
||||||
|
7.4 第四层:数据与生态运营(战略壁垒)
|
||||||
|
数据产品 内容 售价 买家
|
||||||
|
AIGC 内容白皮书 季度/年度题材趋势、
|
||||||
|
爆款模型分析、用户
|
||||||
|
画像
|
||||||
|
5-20 万/份 投资机构、咨询公司
|
||||||
|
合规风险预警 实时监测某类题材
|
||||||
|
(如穿越、重生、霸
|
||||||
|
总)的审核通过率变
|
||||||
|
化
|
||||||
|
10-50 万/年 制作公司、MCN
|
||||||
|
模型效能报告 各 AI 绘画/视频模型的
|
||||||
|
过审率、用户完播
|
||||||
|
率、投诉率排名
|
||||||
|
30-100 万/年 AI 工具厂商(竞品分
|
||||||
|
析)
|
||||||
|
MA 行业节点运营数据 AIGC 视听内容行业节
|
||||||
|
点的发码量、解析
|
||||||
|
量、跨境流通量
|
||||||
|
20-80 万/年 ZIIOT、行业研究机构
|
||||||
|
创作者生态工具:创作者工作台(赋码、版权登记、分账查询一站式 SaaS),基础功能
|
||||||
|
免费,高级功能(多平台数据聚合、智能报税)299 元/月。创作者保险:联合保险公司推出 AI
|
||||||
|
漫剧过审险(未过审赔付制作成本 30%),广电云作为数据背书方收取渠道费。
|
||||||
|
7.5 成本结构与盈亏平衡
|
||||||
|
成本项 占比 说明
|
||||||
|
云资源与带宽 25% 视频指纹提取、区块链节点、MA 解析网关、API 网关
|
||||||
|
AI 模型与算力 30% 自研/采购审核大模型、AIGC 检测模型
|
||||||
|
人工审核团队 20% 重点内容终审、AI 审核复核、投诉处理
|
||||||
|
商务与合规 15% 与广电总局、ZIIOT、各平台、AI 厂商的对接
|
||||||
|
研发与运维 10% C2PA 水印 SDK、版权链、MA 编码网关、根节点对接
|
||||||
|
盈亏平衡点预估:年赋码量达到 50 万部,或跨平台结算 GMV 达到 10 亿元时,项目实现盈
|
||||||
|
亏平衡。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
19
|
||||||
|
第八章 各方参与价值
|
||||||
|
AIGC-Hub 体系通过明确的责任分配和合理的利益机制,使产业链各方均获得实质性价
|
||||||
|
值,形成可持续的生态闭环。
|
||||||
|
8.1 广电总局:从管不住到管得住
|
||||||
|
实时赋码:作品生成即备案,数据自动回传监管后台,告别手工录入滞后 3-6 个月的困
|
||||||
|
境。
|
||||||
|
一码追踪:AVCC 技术指纹识别换皮内容,全网异动告警,解决同一作品换平台、换剧
|
||||||
|
名、换脸后重复播出的难题。
|
||||||
|
标准统一:广电云作为中立运营方执行同一套 AI 审核标准,解决平台各自为政、审核标
|
||||||
|
准不一、劣币驱逐良币的问题。
|
||||||
|
数据透明:平台自审记录实时上链,广电总局可随时抽查回溯,微短剧其他类的监管盲区
|
||||||
|
大幅缩小。
|
||||||
|
国际对接:通过 MA 标识体系,中国 AIGC 内容监管标准可与国际数字身份基础设施对接,
|
||||||
|
提升文化治理国际话语权。
|
||||||
|
8.2 ZIIOT:MA 标识体系向数字文化领域延伸
|
||||||
|
行业拓展:MA 标识从工业互联网、数字贸易、地理实体、碳码等领域,成功拓展至 AIGC
|
||||||
|
视听内容领域,验证了 MA 矩阵式编码结构的兼容开放性和可扩展性。
|
||||||
|
根解析增量:AIGC-Hub 带来的海量发码和解析需求,提升 MA 根解析系统的使用频率和产
|
||||||
|
业影响力。
|
||||||
|
国际标准实践:通过 AIGC 领域的应用,进一步验证 MA 标识在数字内容确权、跨境流通、
|
||||||
|
全生命周期管理中的价值,为 ISO/IEC 15459 标准修订提供实践依据。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
20
|
||||||
|
8.3 长视频平台:降低合规成本,打开跨平台增量
|
||||||
|
审核外包:调用广电云 API,审核成本降低 60-70%,但主体责任仍在平台。
|
||||||
|
跨平台权益互认:用户片库聚合,提升付费意愿(类 MA 体验),长视频平台从内容竞争
|
||||||
|
者转变为内容结算受益者。
|
||||||
|
版权链维权:AVCC 全网监测,侵权内容自动下架,分账可追溯,解决优质 AI 漫剧被短视
|
||||||
|
频平台切片传播的痛点。
|
||||||
|
重点内容独占:AVCC-P 类作品优先在长视频平台首页推荐,获得流量倾斜。
|
||||||
|
出海便利:通过 MA 国际标识,长视频平台的 AIGC 内容在海外平台可直接解析验证,降低
|
||||||
|
出海合规成本。
|
||||||
|
8.4 短视频平台:合规安全,流量不流失
|
||||||
|
秒级赋码:其他类 AI 漫剧实时赋码,平台合规风险转移,但保留内容首发优势。
|
||||||
|
快审通道:通过广电云预审的重点内容,3-5 个工作日拿码,保障创作者权益。
|
||||||
|
结算分账:即使内容在其他平台播放,本平台作为首发平台仍获得分账比例。
|
||||||
|
版权链举证:AVCC 自动记录模型授权和训练数据来源,平台在侵权投诉中免责。
|
||||||
|
8.5 AI 工具/模型厂商:从黑箱到白名单
|
||||||
|
认证准入:通过广电云白名单认证,模型生成作品自动获得快审通道,成为核心卖点。
|
||||||
|
数据存证:训练数据集在版权链预登记,生成作品时自动关联授权记录,降低诉讼风险。
|
||||||
|
分账参与:AVCC 版权段明确模型方分成比例(如 15%),模型商从工具商升级为内容合伙
|
||||||
|
人。
|
||||||
|
统一 SDK:广电云提供标准化 C2PA 水印+MA 标识嵌入 SDK,一次接入,全网通用,降低各
|
||||||
|
平台接口适配成本。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
21
|
||||||
|
8.6 创作者/MCN:确权、分账、跨平台变现
|
||||||
|
版权段明确:人工创作比例、AI 模型贡献、修改记录全部上链,确权清晰,解决 AI 辅助
|
||||||
|
创作后版权归属说不清的痛点。
|
||||||
|
一码维权:AVCC 全网监测,盗传内容自动识别并下架,收益回归创作者。
|
||||||
|
智能合约分账:分账比例写入版权链,播放数据实时可查,自动结算,解决平台分账不透
|
||||||
|
明的问题。
|
||||||
|
审核报告透明:未通过审核的作品,广电云提供详细 AI 预审报告(哪一帧违规、哪句台
|
||||||
|
词违规),指导修改。
|
||||||
|
跨平台片库:类 MA 体验,用户购买记录跨平台通兑,创作者获得数字版权身份证。
|
||||||
|
数据要素变现:优质作品可申请 MA 数据要素登记证书,进入深圳数据交易所、人民数据
|
||||||
|
等平台交易,拓展变现渠道。
|
||||||
|
8.7 版权方/IP 方:防止 AI 洗稿
|
||||||
|
版权链比对:AI 漫剧提交赋码时,自动比对原著版权库,疑似侵权触发人工复核。
|
||||||
|
授权追踪:每次 AI 改编生成新 AVCC,自动关联原著版权段,授权范围实时可查。
|
||||||
|
链上分账:播放和收益数据由广电云汇总,不可篡改,按智能合约自动分配。
|
||||||
|
8.8 用户/消费者:一个片库,全网通行
|
||||||
|
跨平台权益通兑:购买记录写入 AVCC 版权段,换平台扫码解锁。
|
||||||
|
扫码验真:扫描 AVCC 二维码,查看作品完整版权链、MA 标识溯源和审核状态,识别正版
|
||||||
|
与 AI 盗改。
|
||||||
|
一码追责:AVCC 记录完整审核和责任主体,用户投诉直达广电云仲裁中心。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
22
|
||||||
|
8.9 广电云自身:从管道到枢纽
|
||||||
|
角色升级:从云资源出租商(IaaS)升级为 AIGC 内容治理运营商(RegTech+FinTech)+
|
||||||
|
MA 行业节点运营商。
|
||||||
|
标准制定:主动定义行业标准(AVCC 编码规则、AIGC 审核标准、版权分账协议),从被
|
||||||
|
动承接广电业务转向主动定义游戏规则。
|
||||||
|
收入多元:四层收入(赋码费+审核 SaaS+清算佣金+数据金融),摆脱收入来源单一(带
|
||||||
|
宽、存储)的困境。
|
||||||
|
生态垄断:唯一具备监管+技术+结算+MA 行业节点运营四重资质的运营主体,构建不可
|
||||||
|
复制的竞争壁垒。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
23
|
||||||
|
第九章 实施路线图
|
||||||
|
AIGC-Hub 建设分三期推进,每期设定明确的里程碑和责任分工,同时完成 MA 行业节点的
|
||||||
|
申请与建设。
|
||||||
|
阶段 时间 里程碑 广电云任务 MA/ZIIOT 任务
|
||||||
|
一期:筑基 0-6 个月 与现行网标系统打通,完成
|
||||||
|
AVCC 规则制定;3-5 家头部平
|
||||||
|
台试点;向 ZIIOT 申请 MA.AIGC
|
||||||
|
行业节点
|
||||||
|
完成编码规则制
|
||||||
|
定;上线赋码中
|
||||||
|
心;接入首批平
|
||||||
|
台;提交 MA 行业
|
||||||
|
节点申请材料
|
||||||
|
ZIIOT 审核行业节
|
||||||
|
点申请,分配
|
||||||
|
MA.156.10005 代码
|
||||||
|
资源;提供根解析
|
||||||
|
接口对接支持
|
||||||
|
二期:贯通 6-12 个月 AIGC 全链路上链,发布 AI 工具
|
||||||
|
SDK;智能审核覆盖 80%普通
|
||||||
|
类;MA 行业节点正式运营
|
||||||
|
发布 AI 工具 SDK;
|
||||||
|
版权链存证平台运
|
||||||
|
营;智能审核引擎
|
||||||
|
迭代;MA 行业节点
|
||||||
|
正式发码
|
||||||
|
ZIIOT 完成行业节
|
||||||
|
点授权;MA 根解析
|
||||||
|
系统与广电云行业
|
||||||
|
节点实现对接;联
|
||||||
|
合发布 MA.AIGC 标
|
||||||
|
识白皮书
|
||||||
|
三期:生态 1-2 年 推出中国 AIGC 片库统一入口;
|
||||||
|
跨平台权益通兑;建立行业分
|
||||||
|
账标准;MA 标识跨境应用
|
||||||
|
推出统一片库入
|
||||||
|
口;运营跨平台清
|
||||||
|
算;制定分账标
|
||||||
|
准;拓展跨境数字
|
||||||
|
贸易标识服务
|
||||||
|
ZIIOT 将 MA.AIGC 纳
|
||||||
|
入全球标识解析体
|
||||||
|
系;对接国际平台
|
||||||
|
解析节点;联合开
|
||||||
|
展国际推广
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
24
|
||||||
|
第十章 风险识别与应对策略
|
||||||
|
AIGC-Hub 作为国家级创新基础设施,在推进过程中面临技术、商业、政策、生态等多维
|
||||||
|
度风险,需提前识别并制定应对策略。
|
||||||
|
风险类别 具体风险 应对策略
|
||||||
|
平台抵触 平台不愿接入,担心流量
|
||||||
|
和数据被广电云掌握
|
||||||
|
广电总局将 AVCC 作为重点内容准入的前置条件;广
|
||||||
|
电云承诺不经营内容、不干预平台算法;通过合同
|
||||||
|
明确数据使用边界;MA 标识的中立性由 ZIIOT 背书
|
||||||
|
创作者抵触 创作者嫌赋码麻烦,增加
|
||||||
|
创作成本
|
||||||
|
其他类实时赋码,秒级完成;对 MCN 推出批量赋码
|
||||||
|
工具;将赋码与流量推荐挂钩(无证不得推荐);
|
||||||
|
MA 标识嵌入 SDK 自动化,创作者无感知
|
||||||
|
标准滞后 AI 技术迭代太快,审核
|
||||||
|
标准刚出台就滞后
|
||||||
|
建立标准动态更新机制,广电总局每季度发布审核
|
||||||
|
细则补丁;广电云 AI 模型每月迭代;ZIIOT 参与
|
||||||
|
ISO/IEC 15459 标准修订,确保 MA 标识体系与时俱进
|
||||||
|
隐私泄露 版权链记录详细 prompt
|
||||||
|
和生成参数,可能泄露创
|
||||||
|
作者商业秘密
|
||||||
|
详细 prompt 和生成参数采用隐私计算(联邦学习+
|
||||||
|
多方安全计算),仅创作者和版权方可查看完整信
|
||||||
|
息;广电云和平台仅见哈希摘要;MA 标识段仅包含
|
||||||
|
公开类目信息
|
||||||
|
责任甩锅 平台以用了广电云审核为
|
||||||
|
由推卸主体责任
|
||||||
|
合同明确:平台必须人工复核并签字确认;审核记
|
||||||
|
录上链,责任可追溯;广电总局对平台主体责任落
|
||||||
|
实情况进行年度审计;ZIIOT 不参与内容审核,避免
|
||||||
|
平台向国际标准组织甩锅
|
||||||
|
MA 国际合规 海外对 MA 标识的认可度
|
||||||
|
不足,影响 AIGC 内容出
|
||||||
|
海
|
||||||
|
ZIIOT 依托 ISO/CEN/AIM 三大国际组织授权,开展 MA
|
||||||
|
国际推广;与海外平台建立 MA 解析对接;通过跨境
|
||||||
|
数字贸易项目(如乌拉圭牛肉追溯)验证 MA 国际可
|
||||||
|
信度
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
25
|
||||||
|
第十一章 总结
|
||||||
|
AIGC-Hub 方案的核心设计哲学是监管集权、运营中立、责任分散、全球互认。
|
||||||
|
广电总局握规则、握终审、握黑名单,但不审海量内容。广电总局通过广电云掌握实时数
|
||||||
|
据,通过 AVCC 技术指纹实现一码追踪,通过事后抽查和黑名单机制实现精准监管,从被动审
|
||||||
|
批转向主动监测。
|
||||||
|
ZIIOT 作为 MA 全球代码发行机构,提供国际标准底座和全球根解析服务,不介入 AIGC 内
|
||||||
|
容的具体审核和商业运营,但通过对违规码资源的回收权保障 MA 标识体系的全球公信力。
|
||||||
|
广电云搭基础设施、卖合规工具、做跨平台清算、运营 MA.AIGC 行业节点,但不替平台做
|
||||||
|
内容判断、不替创作者担保版权。广电云作为中立基础设施运营方,明确划定运营责任与免责
|
||||||
|
边界,通过四层商业模式(赋码服务、审核增值、版权链结算、数据运营)实现可持续运营,
|
||||||
|
从管道商升级为内容金融基础设施运营商和 MA 行业节点运营商。
|
||||||
|
平台承担主体责任不能甩,但可借助广电云和 MA 工具大幅降低合规成本。平台必须建立
|
||||||
|
自有审核团队,对上线内容承担最终管理责任,但可通过调用广电云 AI 预审 API 降低 60-70%
|
||||||
|
审核成本,通过 MA 编码网关自动识别作品类别辅助流量管控,通过版权链举证在侵权投诉中
|
||||||
|
免责。
|
||||||
|
创作者/工具方承担源头责任,但获得确权、分账、跨平台变现的明确路径。创作者和 AI
|
||||||
|
工具厂商对 AVCC 中 MA 标识段、技术段和版权段的真实性负完全法律责任,但通过 C2PA 水印
|
||||||
|
嵌入、MA 标识自动分配、版权链上链存证、智能合约自动分账、跨平台片库聚合等机制,获
|
||||||
|
得数字版权身份证和类 MA 的无缝消费体验。
|
||||||
|
智视码(AVCC)作为连接监管、运营、平台、创作者、用户的统一标识,是 AIGC 时代网
|
||||||
|
络视听内容治理的关键基础设施。通过将 AVCC 纳入 MA 全球统一标识代码体系(ISO/IEC
|
||||||
|
15459),实现了从行业内部码到国际标识的跨越,为中国 AIGC 内容的管得住、放得活、出得
|
||||||
|
去提供了系统性制度保障和技术底座。
|
||||||
|
附录 A:术语表
|
||||||
|
术语 定义
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
26
|
||||||
|
AIGC-Hub 国家 AIGC 视听内容登记与分发基础设施,由广电云建设和运营
|
||||||
|
AVCC 智视码(AI Visual Content Code),国家 AIGC 视听内容统一标识码
|
||||||
|
体系,基于 MA 全球标识代码体系
|
||||||
|
MA MA 标识代码,由 ZIIOT 获得 ISO/CEN/AIM 三大国际组织批准认可的全
|
||||||
|
球代码发行机构代码
|
||||||
|
ZIIOT 中关村工信二维码技术研究院,MA 全球代码发行机构和根节点运营
|
||||||
|
方
|
||||||
|
网标 网络剧片发行许可证,广电总局对网络视听内容实施的行政许可制度
|
||||||
|
C2PA 内容来源与真实性联盟(Coalition for Content Provenance and
|
||||||
|
Authenticity),内容凭证技术标准
|
||||||
|
版权链 基于联盟链的版权存证与分账系统,广电云作为核心节点运营
|
||||||
|
编码网关 广电云向各平台开放的统一 API 网关,用于 AVCC 解析和流通权限识
|
||||||
|
别,对接 MA 根解析服务
|
||||||
|
AI 漫剧 AI 生成的动画/漫画短剧,包括 AI 绘画、AI 视频、AI 配音等技术生成
|
||||||
|
的视听内容
|
||||||
|
重点/普通/其他 广电总局对网络微短剧的三类分级管理标准
|
||||||
|
MA 行业节点 广电云向 ZIIOT 申请的 MA.AIGC 视听内容行业根节点(拟申请代码
|
||||||
|
MA.156.10005)
|
||||||
|
数据要素登记证书 联合 ZIIOT、深圳数据交易所等机构签发的 AIGC 内容数据资产凭证
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
27
|
||||||
|
附录 B:AVCC(MA 融合版)编码示例
|
||||||
|
以下为不同类型 AI 漫剧的 AVCC 编码完整示例:
|
||||||
|
重点 AI 漫剧(全网首页推荐):MA.156.10005.8361/10.1300200.AIGC/(京)网微剧审字(2026)第
|
||||||
|
001 号-P-AI-HASH(a1b2c3)-CRD(0x7f3e9a)
|
||||||
|
普通 AI 漫剧(平台内播放):MA.156.10005.8361/10.1300200.AIGC/(沪)网微剧审字(2026)第
|
||||||
|
0158 号-G-AI-HASH(b2c3d4)-CRD(0x8g4f0b)
|
||||||
|
其他 AI 漫剧(限本平台):MA.156.10005.8361/10.1300200.AIGC/(浙)网微剧审字(2026)第
|
||||||
|
08921 号-O-AI-HASH(c3d4e5)-CRD(0x9h5g1c)
|
||||||
|
AI 动画电影(重点):MA.156.10005.8361/10.1300300.AIGC/(总局)网动审字(2026)第 003 号-P-
|
||||||
|
AI-HASH(d4e5f6)-CRD(0x0i6h2d)
|
||||||
|
二次 AI 修改迭代版:MA.156.10005.8361/10.1300200.AIGC/(京)网微剧审字(2026)第 001 号-P-
|
||||||
|
v2-AI-HASH(e5f6g7)-CRD(0x1j7i3e)
|
||||||
|
注:v2 表示该作品经过二次 AI 修改后的迭代版本,需重新申请 AVCC 并重新走审核流程。
|
||||||
|
MA.156.10005 为拟申请的广电云 AIGC 视听内容行业节点代码,实际代码以 ZIIOT 授权为准。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
28
|
||||||
|
附录 C:MA 标识体系政策支撑文件
|
||||||
|
发布时间 政策文件 与 AIGC-Hub 的关联
|
||||||
|
2020 年 12 月 工信部《工业互联网标识管
|
||||||
|
理办法》
|
||||||
|
明确未取得许可不得从事工业互联网标识服
|
||||||
|
务;ZIIOT 取得 D2-20220003 号许可证
|
||||||
|
2021 年 8 月 MA 标识代码管理委员会成立 工信部、应急管理部、自然资源部、交通运输
|
||||||
|
部等部委参与,推动 MA 协同发展
|
||||||
|
2022 年 6 月 MA 纳入国家工业互联网标识
|
||||||
|
解析体系
|
||||||
|
MA 标识解析体系与国家顶级节点(广州、上
|
||||||
|
海、北京、重庆、武汉)实现对接
|
||||||
|
2023 年 12 月 国家发改委等《东数西算实
|
||||||
|
施意见》
|
||||||
|
提出算力、存力、运力、码力一体化;探索构
|
||||||
|
建多源异构数据统一标识编码体系
|
||||||
|
2024 年 1 月 十二部委《工业互联网标识
|
||||||
|
解析体系贯通行动计划
|
||||||
|
(2024-2026 年)》
|
||||||
|
提出到 2026 年建成自主可控的标识解析体
|
||||||
|
系;AIGC-Hub 作为视听内容领域的贯通应用
|
||||||
|
2025 年 1 月 国家发改委等《国家数据基
|
||||||
|
础设施建设指引》
|
||||||
|
明确要求建立基于统一目录标识、统一身份登
|
||||||
|
记、统一接口要求的数据流通利用设施底座
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
@@ -0,0 +1,284 @@
|
|||||||
|
# AIGC-Hub 机顶盒边缘生态详图 — 绘制描述
|
||||||
|
|
||||||
|
> 用途:面向创新业务讨论,展示2亿机顶盒如何变成AIGC-Hub的去中心化算力+分发+经济网络
|
||||||
|
> 建议工具:Figma / draw.io / PPT
|
||||||
|
> 画布方向:横版,上方为中心云,下方为边缘网,中间为调度层
|
||||||
|
> 建议尺寸:16:9 单页
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、整体构图逻辑
|
||||||
|
|
||||||
|
**"云 + 管 + 端 + 币"** 四层结构:
|
||||||
|
|
||||||
|
- **顶层**:AIGC-Hub 中心云(已有能力)
|
||||||
|
- **中层**:边缘调度中心(新增的桥梁)
|
||||||
|
- **底层**:2亿机顶盒节点网络(三种角色)
|
||||||
|
- **右侧**:Token经济闭环(算力积分流转)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、详细绘制
|
||||||
|
|
||||||
|
```
|
||||||
|
┌══════════════════════════════════════════════════════════════════════┐
|
||||||
|
│ AIGC-Hub 中心云 (广电云总部) │
|
||||||
|
│ │
|
||||||
|
│ [赋码引擎] [审核引擎] [版权链ChainMaker] [清算引擎] [MA网关] │
|
||||||
|
│ │ │ │ │ │
|
||||||
|
│ │ │ ┌────────┴────────┐ │ │
|
||||||
|
│ │ │ │ 算力激励池 │ │ │
|
||||||
|
│ │ │ │ (从6-8%手续费 │ │ │
|
||||||
|
│ │ │ │ 拨出1-2%注入) │ │ │
|
||||||
|
│ │ │ └────────┬────────┘ │ │
|
||||||
|
│ └──────────┼──────────────┼──────────────┘ │
|
||||||
|
│ ▼ ▼ │
|
||||||
|
│ ┌───────────────────────────────────────────────────────┐ │
|
||||||
|
│ │ 边缘调度中心 (新增核心组件) │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
|
||||||
|
│ │ │ 任务切分 │ │ 节点调度 │ │ 带宽统计 │ │ │
|
||||||
|
│ │ │ 引擎 │ │ 引擎 │ │ 引擎 │ │ │
|
||||||
|
│ │ │ │ │ │ │ │ │ │
|
||||||
|
│ │ │ 长视频→ │ │ 心跳监测 │ │ PCDN流量 │ │ │
|
||||||
|
│ │ │ 10s微任务│ │ 负载评估 │ │ 归因统计 │ │ │
|
||||||
|
│ │ │ Wasm打包 │ │ 地理路由 │ │ 贡献量化 │ │ │
|
||||||
|
│ │ └──────────┘ └──────────┘ └──────────┘ │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ 通信协议: MQTT(任务下发) + EdgeMesh(结果回传) │ │
|
||||||
|
│ │ 框架: KubeEdge / OpenYurt │ │
|
||||||
|
│ └───────────────────────────────────────────────────────┘ │
|
||||||
|
└═══════════════════════════════╤══════════════════════════════════════┘
|
||||||
|
│
|
||||||
|
广电专网 / DVB广播 / IP双向网络
|
||||||
|
│
|
||||||
|
┌═══════════════════════════════▼══════════════════════════════════════┐
|
||||||
|
│ 边缘网络层:2亿+ 广电家庭机顶盒集群 │
|
||||||
|
│ │
|
||||||
|
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ ┌────────────────┐ ┌────────────────┐ ┌──────────────┐ │ │
|
||||||
|
│ │ │ 机顶盒节点 A │ │ 机顶盒节点 B │ │ 机顶盒 C ... │ │ │
|
||||||
|
│ │ │ │ │ │ │ │ │ │
|
||||||
|
│ │ │ ┌────────────┐ │ │ ┌────────────┐ │ │ │ │ │
|
||||||
|
│ │ │ │ 🧮 计算Agent│ │ │ │ 📡 PCDN │ │ │ │ │ │
|
||||||
|
│ │ │ │ WasmEdge │ │ │ │ Agent │ │ │ (休眠/ │ │ │
|
||||||
|
│ │ │ │ 抽帧/哈希 │ │ │ │ 内容缓存 │ │ │ 低配) │ │ │
|
||||||
|
│ │ │ │ C2PA验证 │ │ │ │ P2P传输 │ │ │ │ │ │
|
||||||
|
│ │ │ └────────────┘ │ │ └────────────┘ │ │ │ │ │
|
||||||
|
│ │ │ ┌────────────┐ │ │ ┌────────────┐ │ │ │ │ │
|
||||||
|
│ │ │ │ 📡 PCDN │ │ │ │ 💰 钱包SDK │ │ │ │ │ │
|
||||||
|
│ │ │ │ Agent │ │ │ │ 积分余额 │ │ │ │ │ │
|
||||||
|
│ │ │ └────────────┘ │ │ │ 贡献记录 │ │ │ │ │ │
|
||||||
|
│ │ │ ┌────────────┐ │ │ └────────────┘ │ │ │ │ │
|
||||||
|
│ │ │ │ 💰 钱包SDK │ │ │ ┌────────────┐ │ │ │ │ │
|
||||||
|
│ │ │ │ 积分余额 │ │ │ │ 闲时策略 │ │ │ │ │ │
|
||||||
|
│ │ │ │ 贡献记录 │ │ │ │ 引擎 │ │ │ │ │ │
|
||||||
|
│ │ │ └────────────┘ │ │ └────────────┘ │ │ │ │ │
|
||||||
|
│ │ └────────────────┘ └────────────────┘ └──────────────┘ │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ 节点分级: │ │
|
||||||
|
│ │ · A级(高配 Android 9.0+ NPU): 计算+PCDN+钱包 = 全功能 │ │
|
||||||
|
│ │ · B级(中配): PCDN+钱包 = 存储+传输 │ │
|
||||||
|
│ │ · C级(低配/旧机型): 休眠 = 仅接收广播更新 │ │
|
||||||
|
│ └─────────────────────────────────────────────────────────────┘ │
|
||||||
|
└══════════════════════════════════════════════════════════════════════┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、三大场景详解
|
||||||
|
|
||||||
|
### 场景一:分布式边缘算力池
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────┐
|
||||||
|
│ 🧮 场景一:边缘算力(降低90%预处理成本) │
|
||||||
|
│ │
|
||||||
|
│ 中心云(审核引擎) │
|
||||||
|
│ │ │
|
||||||
|
│ │ ① 长视频切分为N个10秒片段 │
|
||||||
|
│ ▼ │
|
||||||
|
│ 边缘调度中心 │
|
||||||
|
│ │ │
|
||||||
|
│ │ ② 选择空闲机顶盒(CPU<30%, 凌晨2-6点) │
|
||||||
|
│ │ 通过MQTT下发: {task_id, video_slice_url, wasm_module} │
|
||||||
|
│ ▼ │
|
||||||
|
│ 机顶盒A 机顶盒B │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ ③ WasmEdge执行: │ ③ WasmEdge执行: │
|
||||||
|
│ │ · 视频抽帧(1fps) │ · 图片pHash计算 │
|
||||||
|
│ │ · 感知哈希计算 │ · 音频指纹提取 │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ ④ 返回结果+PoW签名 │ ④ 返回结果+PoW签名 │
|
||||||
|
│ ▼ ▼ │
|
||||||
|
│ 边缘调度中心 │
|
||||||
|
│ │ │
|
||||||
|
│ │ ⑤ 聚合结果 → 送入AI推理(GPU)做最终判断 │
|
||||||
|
│ │ ⑥ 记录机顶盒贡献量 → 批量上链 │
|
||||||
|
│ ▼ │
|
||||||
|
│ 版权链: Token奖励 │
|
||||||
|
│ │
|
||||||
|
│ 成本对比: │
|
||||||
|
│ · 传统:100台8C16G云服务器 × 24h = 年成本600万+ │
|
||||||
|
│ · 边缘:2亿机顶盒闲时贡献 = 年成本≈0(仅调度服务器费用) │
|
||||||
|
│ · 节省:90%+ 预处理算力成本 │
|
||||||
|
└─────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 场景二:PCDN去中心化分发
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────┐
|
||||||
|
│ 📡 场景二:PCDN分发(降低80%带宽成本) │
|
||||||
|
│ │
|
||||||
|
│ 用户手机请求播放 AVCC-X (4K AI电影) │
|
||||||
|
│ │ │
|
||||||
|
│ │ ① 请求到达广电云Tracker │
|
||||||
|
│ ▼ │
|
||||||
|
│ Tracker查询: AVCC-X的切片存在哪些机顶盒? │
|
||||||
|
│ │ │
|
||||||
|
│ │ ② 返回: 同小区机顶盒A有切片1-5, 同城B有切片6-10 │
|
||||||
|
│ ▼ │
|
||||||
|
│ 手机客户端 │
|
||||||
|
│ │ │
|
||||||
|
│ │ ③ WebRTC DataChannel直连机顶盒A/B │
|
||||||
|
│ │ P2P下载视频切片 │
|
||||||
|
│ │ │
|
||||||
|
│ │ ④ 每个切片下载后: 计算SHA-256 │
|
||||||
|
│ │ vs 链上Merkle Tree节点 → 校验一致 → 安全播放 │
|
||||||
|
│ │ 如不一致 → 丢弃 + 拉黑Peer │
|
||||||
|
│ ▼ │
|
||||||
|
│ 播放成功 │
|
||||||
|
│ │
|
||||||
|
│ AVCC赋能关键: │
|
||||||
|
│ · 每个切片哈希记录在AVCC元数据中(Merkle Tree) │
|
||||||
|
│ · P2P网络中的内容防篡改完全依赖AVCC哈希校验 │
|
||||||
|
│ · 没有AVCC → 无法验证P2P内容真实性 → PCDN不可行 │
|
||||||
|
│ │
|
||||||
|
│ 带宽对比: │
|
||||||
|
│ · 传统CDN: 1PB/月 × 0.1元/GB = 年成本1.2亿 │
|
||||||
|
│ · PCDN: 80%流量由机顶盒P2P承担 = 年省 ≈ 1亿 │
|
||||||
|
└─────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 场景三:Token经济闭环(DePIN模式)
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────┐
|
||||||
|
│ 💰 场景三:视听积分Token经济闭环 │
|
||||||
|
│ │
|
||||||
|
│ ┌─── 贡献(挖矿)───┐ │
|
||||||
|
│ │ │ │
|
||||||
|
│ ▼ │ │
|
||||||
|
│ ┌─────────┐ ┌───┴──────┐ │
|
||||||
|
│ │ 机顶盒 │ │ 算力激励池│ │
|
||||||
|
│ │ 贡献算力 │────────→│ (链上合约)│ │
|
||||||
|
│ │ 贡献带宽 │ PoW/PoT │ │ │
|
||||||
|
│ └─────────┘ └───┬──────┘ │
|
||||||
|
│ ▲ │ │
|
||||||
|
│ │ Token发放 │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ ▼ │
|
||||||
|
│ │ ┌─────────────┐ │
|
||||||
|
│ │ │ 用户积分账户 │ │
|
||||||
|
│ │ │ (链上余额) │ │
|
||||||
|
│ │ └──┬───┬───┬──┘ │
|
||||||
|
│ │ │ │ │ │
|
||||||
|
│ │ ┌──────────┘ │ └──────────┐ │
|
||||||
|
│ │ ▼ ▼ ▼ │
|
||||||
|
│ │ ┌──────┐ ┌──────────┐ ┌──────────┐ │
|
||||||
|
│ │ │兑换套餐│ │购买AIGC │ │打赏创作者│ │
|
||||||
|
│ │ │宽带减免│ │内容观影权│ │ │ │
|
||||||
|
│ │ └──────┘ └────┬─────┘ └────┬─────┘ │
|
||||||
|
│ │ │ │ │
|
||||||
|
│ │ ▼ ▼ │
|
||||||
|
│ │ ┌──────────────┐ ┌──────────┐ │
|
||||||
|
│ │ │用户权益子链 │ │创作者收入│ │
|
||||||
|
│ │ │(跨平台通看) │ │(变现/购买│ │
|
||||||
|
│ │ └──────────────┘ │ AI算力) │ │
|
||||||
|
│ │ └──────────┘ │
|
||||||
|
│ │ │
|
||||||
|
│ └──── 创作者购买赋码服务/AI算力 ← 积分回流 ────────────┘│
|
||||||
|
│ │
|
||||||
|
│ 闭环总结: │
|
||||||
|
│ 机顶盒贡献算力/带宽 → 获得积分 → 积分购买AIGC内容 │
|
||||||
|
│ → 收入进入分账池 → 创作者+模型方+平台分成 │
|
||||||
|
│ → 广电云从中收取清算服务费 → 部分注入算力激励池 │
|
||||||
|
│ → 激励更多机顶盒参与 → 飞轮转动 │
|
||||||
|
└─────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、实施节奏
|
||||||
|
|
||||||
|
```
|
||||||
|
┌────────────────────────────────────────────────────────────┐
|
||||||
|
│ 分期实施(与主项目三期对齐) │
|
||||||
|
│ │
|
||||||
|
│ 一期试点(同步主项目二期,M6-M12): │
|
||||||
|
│ · 选定2省高配机顶盒(Android 9.0+) │
|
||||||
|
│ · 部署PCDN Agent → 测试P2P分发+积分结算 │
|
||||||
|
│ · 目标:1万台试点,验证模式 │
|
||||||
|
│ │
|
||||||
|
│ 二期拓展(同步主项目三期,Y2前半): │
|
||||||
|
│ · 部署WasmEdge边缘计算环境 │
|
||||||
|
│ · 承接图像哈希+切片预处理任务 │
|
||||||
|
│ · 扩展至10省100万台 │
|
||||||
|
│ │
|
||||||
|
│ 三期生态(Y2后半-Y3): │
|
||||||
|
│ · 完全打通版权链Token经济 │
|
||||||
|
│ · 积分兑换AIGC观影权上线 │
|
||||||
|
│ · 全国2000万+活跃边缘节点 │
|
||||||
|
│ │
|
||||||
|
│ 远期愿景: │
|
||||||
|
│ · 2亿机顶盒 = 中国最大的去中心化算力+分发网络 │
|
||||||
|
│ · 广电专网 = 互联网大厂无法复制的网络优势 │
|
||||||
|
└────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、战略价值总结框
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────┐
|
||||||
|
│ 机顶盒边缘生态的三大战略价值 │
|
||||||
|
│ │
|
||||||
|
│ ① 成本壁垒: │
|
||||||
|
│ · 2亿免费边缘算力 vs 字节/腾讯需自建数据中心 │
|
||||||
|
│ · 广电专网P2P vs 公网CDN成本 │
|
||||||
|
│ → 不可复制的成本结构优势 │
|
||||||
|
│ │
|
||||||
|
│ ② 存量激活: │
|
||||||
|
│ · 有线电视用户流失痛点 → "贡献=赚积分"留住用户 │
|
||||||
|
│ · 机顶盒从"电视盒子"变为"数字资产终端" │
|
||||||
|
│ → 广电网络存量资产价值重估 │
|
||||||
|
│ │
|
||||||
|
│ ③ 经济闭环: │
|
||||||
|
│ · 创作者生产 → 广电赋码审核 → 边缘加速分发 │
|
||||||
|
│ · → 用户用积分消费 → 合约分账给创作者和算力提供者 │
|
||||||
|
│ → 广电云 = 数字资产结算行 │
|
||||||
|
│ │
|
||||||
|
│ 一句话:把"包袱"变成"金矿",把"管道"变成"银行" │
|
||||||
|
└─────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 六、视觉设计建议
|
||||||
|
|
||||||
|
| 元素 | 建议 |
|
||||||
|
|------|------|
|
||||||
|
| 中心云 | 蓝色方块(顶部),体现"已有能力" |
|
||||||
|
| 调度层 | 绿色横条(中间),体现"新增桥梁" |
|
||||||
|
| 机顶盒 | 大量小型图标散布底部,密集感体现"2亿规模" |
|
||||||
|
| Token流 | 金色环形箭头,体现经济闭环 |
|
||||||
|
| 对比数据 | 红绿对比框(传统成本 vs 边缘成本) |
|
||||||
|
| 分期 | 底部时间轴,灰→蓝→金渐变表示成熟度提升 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> 本图回答:广电2亿机顶盒如何从"沉默资产"变为"算力金矿"?
|
||||||
|
> 核心说服点:不需要新建基础设施,利用已有终端即可构建互联网大厂无法复制的去中心化网络。
|
||||||
@@ -0,0 +1,267 @@
|
|||||||
|
# AIGC-Hub 核心业务流程泳道图 — 绘制描述
|
||||||
|
|
||||||
|
> 用途:面向产品经理/研发负责人,逐步骤对齐"赋码全链路"每个角色的职责与交互
|
||||||
|
> 建议工具:draw.io / ProcessOn / Mermaid / Lucidchart
|
||||||
|
> 画布方向:横版,泳道从上到下(角色维度),流程从左到右(时间维度)
|
||||||
|
> 建议尺寸:A1 横版 或 双屏16:9
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、整体构图逻辑
|
||||||
|
|
||||||
|
**六泳道 × 三阶段 × 关键判断节点**:
|
||||||
|
|
||||||
|
- **纵向六泳道**:创作者/AI工具 · 创作者工作台(前端) · 赋码引擎(Go) · 审核引擎(Python+Kotlin) · 版权链引擎(Go) · MA网关/ZIIOT
|
||||||
|
- **横向三阶段**:申请阶段 → 审核阶段 → 签发阶段
|
||||||
|
- **关键判断**:菱形决策节点(预检通过?审核通过?人工终审?)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、泳道详细绘制
|
||||||
|
|
||||||
|
```
|
||||||
|
时间轴 →→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→
|
||||||
|
│← ─ 申请阶段 ─ →│← ─ ─ ─ ─ 审核阶段 ─ ─ ─ ─ →│← ─ 签发阶段 ─ →│
|
||||||
|
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
泳道1:创作者 / AI工具
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
|
┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐
|
||||||
|
│AI工具 │──→│C2PA SDK│──→│导出作品 │ │收到AVCC│
|
||||||
|
│生成内容 │ │自动嵌入│ │(含MA │ │证书 │
|
||||||
|
│ │ │MA片段 │ │ 片段) │ │通知 │
|
||||||
|
└────────┘ └────────┘ └───┬────┘ └────────┘
|
||||||
|
│ ↑
|
||||||
|
▼ │
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
泳道2:创作者工作台 (React + Kotlin BFF)
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
|
┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐
|
||||||
|
│上传作品 │──→│填写版权│──→│提交赋码│ ┌─────────┐ │展示证书│
|
||||||
|
│视频+材料│ │材料信息│ │申请 │ ┌───→│查看审核 │ │二维码 │
|
||||||
|
│(分片上传)│ │(表单) │ │(REST) │ │ │进度/报告│ │PDF下载 │
|
||||||
|
└────────┘ └────────┘ └───┬────┘ │ └─────────┘ └────────┘
|
||||||
|
│ │ (WebSocket推送/轮询) ↑
|
||||||
|
▼ │ │
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
泳道3:赋码引擎 (Go · code-svc)
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
|
┌────────┐ ┌────────────────────────────┐
|
||||||
|
│接收申请 │──→│ 四步预检 │
|
||||||
|
│创建记录 │ │ │
|
||||||
|
│(PG写入) │ │ ① 重复检测(视频指纹) │
|
||||||
|
└────────┘ │ ② 黑名单查询(Redis缓存) │
|
||||||
|
│ ③ 版权材料完整性校验 │
|
||||||
|
│ ④ MA标识片段合规性检测 │
|
||||||
|
└──────────────┬───────────────┘
|
||||||
|
│
|
||||||
|
◇ 预检通过?
|
||||||
|
╱ ╲
|
||||||
|
是 ╱ ╲ 否
|
||||||
|
╱ ╲
|
||||||
|
┌─────▼──┐ ┌────▼───┐
|
||||||
|
│发布Kafka│ │返回拒绝 │
|
||||||
|
│topic. │ │(原因明细)│
|
||||||
|
│avcc. │ └────────┘
|
||||||
|
│apply. │
|
||||||
|
│created │ ┌────────┐ ┌────────┐
|
||||||
|
└─────────┘ │消费链上 │─→│生成AVCC│
|
||||||
|
│确认事件 │ │六段式 │
|
||||||
|
│(Kafka) │ │编码 │
|
||||||
|
└────────┘ └───┬────┘
|
||||||
|
│
|
||||||
|
┌────▼────┐
|
||||||
|
│分配码资源│
|
||||||
|
│(Redis锁)│
|
||||||
|
│写入PG │
|
||||||
|
└────┬────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
泳道4:审核引擎 (Python AI管道 + Kotlin编排)
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
|
┌────────┐ ┌─────────────────────────────────────────┐
|
||||||
|
│消费Kafka│──→│ AI 多模态审核 │
|
||||||
|
│创建审核 │ │ │
|
||||||
|
│任务 │ │ ┌─────┐ ┌─────┐ ┌─────┐ ┌──────┐ │
|
||||||
|
└────────┘ │ │画面 │ │台词 │ │声音 │ │AIGC │ │
|
||||||
|
│ │审核 │ │审核 │ │审核 │ │真实性│ │
|
||||||
|
│ │(GPU)│ │(GPU)│ │(GPU)│ │(GPU) │ │
|
||||||
|
│ └──┬──┘ └──┬──┘ └──┬──┘ └──┬───┘ │
|
||||||
|
│ └───────┼───────┼───────┘ │
|
||||||
|
│ ▼ │
|
||||||
|
│ ┌─────────────────────────┐ │
|
||||||
|
│ │ 多模态融合决策层 │ │
|
||||||
|
│ │ (加权投票+LLM报告生成) │ │
|
||||||
|
│ │ overall_score = 78.5 │ │
|
||||||
|
│ │ suggested_level = G │ │
|
||||||
|
│ └────────────┬────────────┘ │
|
||||||
|
└───────────────┼────────────────────────┘
|
||||||
|
│
|
||||||
|
◇ 分级决策?
|
||||||
|
╱ │ ╲
|
||||||
|
╱ │ ╲
|
||||||
|
P(高分)╱ G(中间) O(低分╲合规)
|
||||||
|
╱ │ ╲
|
||||||
|
┌─────▼──┐ ┌────▼───┐ ┌───▼─────┐
|
||||||
|
│转人工 │ │平台复核│ │自动通过 │
|
||||||
|
│终审队列 │ │(可选) │ │秒级赋码 │
|
||||||
|
│(广电总局)│ └────┬───┘ └───┬─────┘
|
||||||
|
└────┬────┘ │ │
|
||||||
|
│ │ │
|
||||||
|
▼ ▼ ▼
|
||||||
|
┌──────────────────────────────┐
|
||||||
|
│ 发布 Kafka: │
|
||||||
|
│ topic.review.task.finished │
|
||||||
|
│ {decision, final_level, hash} │
|
||||||
|
└──────────────────────────────┘
|
||||||
|
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
泳道5:版权链引擎 (Go · chain-svc + ChainMaker)
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
|
┌────────┐ ┌────────────┐
|
||||||
|
│消费审核│──→│调用智能合约 │
|
||||||
|
│完成事件│ │Register- │
|
||||||
|
│(Kafka) │ │Copyright │
|
||||||
|
└────────┘ └─────┬──────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌──────────┐
|
||||||
|
│ChainMaker│
|
||||||
|
│共识确认 │
|
||||||
|
│(TBFT) │
|
||||||
|
└─────┬────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌──────────┐
|
||||||
|
│区块监听器│
|
||||||
|
│确认tx有效│
|
||||||
|
└─────┬────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌──────────┐
|
||||||
|
│发布Kafka: │
|
||||||
|
│topic.chain│
|
||||||
|
│.tx. │
|
||||||
|
│confirmed │
|
||||||
|
└──────────┘
|
||||||
|
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
泳道6:MA网关 / ZIIOT 根节点
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
|
┌────────┐
|
||||||
|
│MA网关 │
|
||||||
|
│注册新 │
|
||||||
|
│AVCC到 │
|
||||||
|
│缓存 │
|
||||||
|
└───┬────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌────────┐
|
||||||
|
│同步ZIIOT│
|
||||||
|
│根解析 │
|
||||||
|
│索引 │
|
||||||
|
└────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
全球可解析 ✓
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、关键时间标注
|
||||||
|
|
||||||
|
```
|
||||||
|
在泳道图顶部,用时间标尺标注各阶段耗时:
|
||||||
|
|
||||||
|
│← ─ ─ ─ 申请 ─ ─ ─ →│← ─ ─ ─ ─ 审核 ─ ─ ─ ─ →│← ─ 签发 ─ →│
|
||||||
|
|
||||||
|
O类(其他): │ 秒级提交 │ 秒级AI自动通过 │ 秒级签发 │ = 总计<10s
|
||||||
|
G类(普通): │ 分钟级上传 │ 1-3工作日(AI+平台复核) │ 分钟级 │ = 总计1-3天
|
||||||
|
P类(重点): │ 分钟级上传 │ 5-30工作日(AI+人工终审)│ 小时级 │ = 总计5-30天
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、异常处理分支(红色虚线标注)
|
||||||
|
|
||||||
|
```
|
||||||
|
在主流程旁边用红色虚线标注异常路径:
|
||||||
|
|
||||||
|
异常1:预检失败 → 返回拒绝原因 → 创作者修改后重新提交
|
||||||
|
异常2:AI审核发现严重违规 → 直接拒绝 → 记入黑名单系统
|
||||||
|
异常3:版权链上链失败 → DLQ重试3次 → 仍失败则人工介入
|
||||||
|
异常4:人工终审驳回 → 生成驳回报告 → 创作者可申诉
|
||||||
|
|
||||||
|
Saga补偿模式:
|
||||||
|
上链失败 → topic.chain.tx.failed → 赋码引擎回滚status → 通知创作者
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、数据流标注(蓝色标签)
|
||||||
|
|
||||||
|
```
|
||||||
|
在每个步骤旁边标注数据写入/读取:
|
||||||
|
|
||||||
|
步骤 写入 读取
|
||||||
|
──────────────────────────────────────────────────
|
||||||
|
接收申请 PG: avcc_records —
|
||||||
|
MinIO: 视频文件
|
||||||
|
预检 — Redis: blacklist
|
||||||
|
Milvus: 指纹比对
|
||||||
|
创建审核任务 PG: review_tasks —
|
||||||
|
Kafka: event
|
||||||
|
AI推理 — Triton: GPU模型
|
||||||
|
融合决策 PG: review_reports PG: review_tasks
|
||||||
|
上链存证 PG: chain_records —
|
||||||
|
ChainMaker: 链上
|
||||||
|
生成AVCC PG: avcc_records Redis: 码池
|
||||||
|
Redis: 缓存AVCC
|
||||||
|
注册MA — ZIIOT API
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 六、状态机快照(右侧配图)
|
||||||
|
|
||||||
|
```
|
||||||
|
在泳道图右侧放置审核状态机简图:
|
||||||
|
|
||||||
|
[pending] → [pre_checking] → [ai_reviewing] → [approved] → AVCC签发
|
||||||
|
│ │ ↑
|
||||||
|
↓ ↓ │
|
||||||
|
[rejected] [human_reviewing]────┘
|
||||||
|
│
|
||||||
|
↓
|
||||||
|
[rejected]
|
||||||
|
|
||||||
|
流通状态机:
|
||||||
|
[active] → [suspended] → [active](恢复)
|
||||||
|
│ │
|
||||||
|
↓ ↓
|
||||||
|
[expired] [revoked] → 永久失效
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 七、视觉设计建议
|
||||||
|
|
||||||
|
| 元素 | 建议 |
|
||||||
|
|------|------|
|
||||||
|
| 泳道底色 | 创作者-浅紫 · 工作台-浅蓝 · 赋码-浅绿 · 审核-浅橙 · 链-浅灰 · MA-浅金 |
|
||||||
|
| 步骤形状 | 操作=圆角矩形 · 判断=菱形 · 事件=平行四边形 · 数据=圆柱体 |
|
||||||
|
| 连线 | 正常流=黑实线箭头 · 异步(Kafka)=蓝虚线闪电 · 异常=红虚线 |
|
||||||
|
| 技术标注 | 每个步骤下方小字标注技术实现(Go/Kotlin/Python/Kafka/PG等) |
|
||||||
|
| 时间标注 | 每段流程上方标注耗时范围 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> 本图回答:产品和研发如何逐步骤对齐赋码全链路的实现细节。
|
||||||
|
> 每个泳道 = 一个团队的职责边界,每条连线 = 一个接口契约。
|
||||||
@@ -0,0 +1,332 @@
|
|||||||
|
# AIGC-Hub 生态参与方利益分配详图 — 绘制描述
|
||||||
|
|
||||||
|
> 用途:回答"为什么各方愿意参与",展示各角色的付出与收益关系
|
||||||
|
> 建议工具:Figma / draw.io / PPT
|
||||||
|
> 画布方向:中心辐射式,广电云AIGC-Hub居中,六方环绕
|
||||||
|
> 建议尺寸:16:9 单页
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、整体构图逻辑
|
||||||
|
|
||||||
|
**"中心枢纽 + 六方环绕 + 价值流动"**:
|
||||||
|
|
||||||
|
- **中心**:广电云 AIGC-Hub(中立枢纽)
|
||||||
|
- **六方**:广电总局 · ZIIOT · 视听平台 · AI工具厂商 · 创作者/MCN · 用户/观众
|
||||||
|
- **连线**:每条线标注双向关系(给出什么 / 获得什么)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、中心枢纽
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────┐
|
||||||
|
│ 广电云 AIGC-Hub │
|
||||||
|
│ (中立运营枢纽) │
|
||||||
|
│ │
|
||||||
|
│ 核心定位: │
|
||||||
|
│ · 不做内容(保持中立公信力) │
|
||||||
|
│ · 只做治理+清算+标准 │
|
||||||
|
│ · 编码权 × 审核权 × 结算权 × 数据权 │
|
||||||
|
│ │
|
||||||
|
│ 商业模式: │
|
||||||
|
│ · 赋码费 + SaaS API费 │
|
||||||
|
│ · 清算服务费(6-8%) │
|
||||||
|
│ · 数据运营收入 │
|
||||||
|
└─────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、六方环绕详细关系
|
||||||
|
|
||||||
|
### 参与方 ①:广电总局(监管者)
|
||||||
|
|
||||||
|
```
|
||||||
|
位置:中心正上方(12点方向),红色
|
||||||
|
图标:国徽/政府大楼
|
||||||
|
|
||||||
|
┌─────────────────────────────────────────────────┐
|
||||||
|
│ 🏛️ 广电总局 / 省级广电 │
|
||||||
|
│ │
|
||||||
|
│ 角色:规则制定者 · 终审裁决者 · 黑名单执行者 │
|
||||||
|
│ │
|
||||||
|
│ ─── 给出 ──→ AIGC-Hub: │
|
||||||
|
│ · 政策授权("无码不流通"行政许可) │
|
||||||
|
│ · 终审决策(P类重点内容最终裁决) │
|
||||||
|
│ · 黑名单指令(全网封禁) │
|
||||||
|
│ │
|
||||||
|
│ ←── 获得 ─── AIGC-Hub: │
|
||||||
|
│ · 精准靶向监管能力(不再逐平台通知) │
|
||||||
|
│ · 全行业数据看板(实时掌握AIGC产业全景) │
|
||||||
|
│ · 秒级全网下架能力(MA根节点联动) │
|
||||||
|
│ · 减少人力投入(AI预审替代80%+人工审核) │
|
||||||
|
│ │
|
||||||
|
│ 核心诉求:管得住 · 管得省力 · 数据可视 │
|
||||||
|
│ 参与动力:★★★★★(行政职责驱动) │
|
||||||
|
└─────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 参与方 ②:ZIIOT(标准制定方)
|
||||||
|
|
||||||
|
```
|
||||||
|
位置:中心右上方(2点方向),绿色
|
||||||
|
图标:ISO标准/全球网络
|
||||||
|
|
||||||
|
┌─────────────────────────────────────────────────┐
|
||||||
|
│ 🌐 ZIIOT 中关村工信二维码技术研究院 │
|
||||||
|
│ │
|
||||||
|
│ 角色:MA全球根节点运营 · 国际标准对接 │
|
||||||
|
│ │
|
||||||
|
│ ─── 给出 ──→ AIGC-Hub: │
|
||||||
|
│ · MA行业节点授权(MA.156.10005) │
|
||||||
|
│ · 全球根解析服务(跨境互认基础) │
|
||||||
|
│ · 码资源分配(唯一性保障) │
|
||||||
|
│ · ISO/IEC 15459 标准背书 │
|
||||||
|
│ │
|
||||||
|
│ ←── 获得 ─── AIGC-Hub: │
|
||||||
|
│ · 年度节点维护费(百万级) │
|
||||||
|
│ · MA标识在文化领域的落地案例(标准推广) │
|
||||||
|
│ · 海量解析流量(证明MA体系价值) │
|
||||||
|
│ · 中国数字文化产业的国际话语权 │
|
||||||
|
│ │
|
||||||
|
│ 核心诉求:标准落地 · 案例输出 · 国际影响力 │
|
||||||
|
│ 参与动力:★★★★☆(战略价值驱动) │
|
||||||
|
└─────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 参与方 ③:视听平台(抖音/B站/快手/爱奇艺等)
|
||||||
|
|
||||||
|
```
|
||||||
|
位置:中心右下方(4点方向),蓝色
|
||||||
|
图标:视频播放/多平台
|
||||||
|
|
||||||
|
┌─────────────────────────────────────────────────┐
|
||||||
|
│ 📺 视听平台(长视频 + 短视频) │
|
||||||
|
│ │
|
||||||
|
│ 角色:内容分发方 · 播放数据提供方 · 审核主责方 │
|
||||||
|
│ │
|
||||||
|
│ ─── 给出 ──→ AIGC-Hub: │
|
||||||
|
│ · API调用费(按次付费,审核/解析/比对) │
|
||||||
|
│ · 播放数据回传(跨平台清算基础) │
|
||||||
|
│ · 处置记录回传(监管合规) │
|
||||||
|
│ · 赋码配合(上线内容必须持有AVCC) │
|
||||||
|
│ │
|
||||||
|
│ ←── 获得 ─── AIGC-Hub: │
|
||||||
|
│ · 审核成本降低70%(AI预审替代人工) │
|
||||||
|
│ · 合规风险转嫁(广电云背书,出问题不是平台责任) │
|
||||||
|
│ · 跨平台确权(别人抄我的内容,有AVCC可维权) │
|
||||||
|
│ · 内容分级标签(P/G/O直接用于推荐策略) │
|
||||||
|
│ · 跨平台权益通兑(吸引用户,减少流失) │
|
||||||
|
│ │
|
||||||
|
│ 核心诉求:降成本 · 降风险 · 不被处罚 │
|
||||||
|
│ 参与动力:★★★★☆(合规压力+成本驱动) │
|
||||||
|
│ │
|
||||||
|
│ 算账: │
|
||||||
|
│ · 原自建审核成本:5000万/年(100人团队) │
|
||||||
|
│ · 接入AIGC-Hub:1500万/年(API调用费) │
|
||||||
|
│ · 节省:3500万/年,且标准统一、责任明确 │
|
||||||
|
└─────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 参与方 ④:AI工具厂商(SD/可灵/Runway等)
|
||||||
|
|
||||||
|
```
|
||||||
|
位置:中心左下方(8点方向),紫色
|
||||||
|
图标:AI芯片/画笔
|
||||||
|
|
||||||
|
┌─────────────────────────────────────────────────┐
|
||||||
|
│ 🤖 AI 工具厂商(模型提供方) │
|
||||||
|
│ │
|
||||||
|
│ 角色:内容生成源头 · C2PA嵌入端 · 模型认证方 │
|
||||||
|
│ │
|
||||||
|
│ ─── 给出 ──→ AIGC-Hub: │
|
||||||
|
│ · 集成C2PA SDK(在生成环节自动打码) │
|
||||||
|
│ · 白名单认证年费(10万-50万/模型/年) │
|
||||||
|
│ · 模型元数据(版本、训练数据授权摘要) │
|
||||||
|
│ │
|
||||||
|
│ ←── 获得 ─── AIGC-Hub: │
|
||||||
|
│ · "白名单认证"标签(审核加分项,提升通过率) │
|
||||||
|
│ · 模型效能榜单曝光(官方背书,市场推广) │
|
||||||
|
│ · 分账收益(创作者收入的15%归模型方) │
|
||||||
|
│ · 合规免责(用户用我的模型生成违规内容≠我的责任) │
|
||||||
|
│ · 市场准入(未认证模型生成内容可能无法赋码) │
|
||||||
|
│ │
|
||||||
|
│ 核心诉求:合规背书 · 商业分成 · 市场准入 │
|
||||||
|
│ 参与动力:★★★☆☆(利益驱动+准入压力) │
|
||||||
|
└─────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 参与方 ⑤:创作者 / MCN 机构
|
||||||
|
|
||||||
|
```
|
||||||
|
位置:中心左上方(10点方向),橙色
|
||||||
|
图标:画家/团队
|
||||||
|
|
||||||
|
┌─────────────────────────────────────────────────┐
|
||||||
|
│ 🎨 创作者 / MCN 机构 │
|
||||||
|
│ │
|
||||||
|
│ 角色:内容生产者 · 版权持有者 · 收益主体 │
|
||||||
|
│ │
|
||||||
|
│ ─── 给出 ──→ AIGC-Hub: │
|
||||||
|
│ · 赋码费(50-2000元/部) │
|
||||||
|
│ · 版权材料(授权书、训练数据来源) │
|
||||||
|
│ · 作品内容(上传至平台存储) │
|
||||||
|
│ │
|
||||||
|
│ ←── 获得 ─── AIGC-Hub: │
|
||||||
|
│ · 全球唯一版权证书(AVCC = 数字身份证) │
|
||||||
|
│ · 跨平台自动分账(不再逐平台对账) │
|
||||||
|
│ · 分账透明可审计(链上记录,不怕平台暗箱) │
|
||||||
|
│ · 一次创作全网分发(P类可首页推荐) │
|
||||||
|
│ · 版权维权证据(链上存证,法律效力) │
|
||||||
|
│ · 版权金融(质押贷款、ABS、估值报告) │
|
||||||
|
│ · 多平台数据聚合(一个面板看全网数据) │
|
||||||
|
│ │
|
||||||
|
│ 核心诉求:赚到钱 · 赚得透明 · 版权被保护 │
|
||||||
|
│ 参与动力:★★★★★(收益驱动,刚需) │
|
||||||
|
│ │
|
||||||
|
│ 算账(头部创作者视角): │
|
||||||
|
│ · 月播放量 1000万 × 全平台汇总 │
|
||||||
|
│ · 月收入 ≈ 40万(创作者40%分成) │
|
||||||
|
│ · 赋码费 2000元/部 vs 月收入40万 = ROI 200倍 │
|
||||||
|
└─────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 参与方 ⑥:用户 / 观众
|
||||||
|
|
||||||
|
```
|
||||||
|
位置:中心正下方(6点方向),灰色
|
||||||
|
图标:人群/手机
|
||||||
|
|
||||||
|
┌─────────────────────────────────────────────────┐
|
||||||
|
│ 👥 用户 / 观众 │
|
||||||
|
│ │
|
||||||
|
│ 角色:内容消费者 · 付费者 · 权益持有者 │
|
||||||
|
│ │
|
||||||
|
│ ─── 给出 ──→ 生态: │
|
||||||
|
│ · 付费观看/订阅/打赏 │
|
||||||
|
│ · 播放行为数据(匿名化后回传) │
|
||||||
|
│ · 投诉举报(生态净化) │
|
||||||
|
│ │
|
||||||
|
│ ←── 获得 ─── 生态: │
|
||||||
|
│ · 一次购买全网通看(AVCC跨平台权益通兑) │
|
||||||
|
│ · 内容质量保障(经过AI+人工审核的合规内容) │
|
||||||
|
│ · 溯源验真(扫码验证AVCC,防止盗版/换皮) │
|
||||||
|
│ · 未来:贡献算力赚积分(机顶盒DePIN模式) │
|
||||||
|
│ │
|
||||||
|
│ 核心诉求:内容好 · 不重复付费 · 体验流畅 │
|
||||||
|
│ 参与动力:★★★☆☆(间接受益,感知度中等) │
|
||||||
|
└─────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、利益流动总图(桑基图/关系网)
|
||||||
|
|
||||||
|
```
|
||||||
|
绘制方式:中心广电云,六方围绕,双向箭头连接
|
||||||
|
箭头粗细 = 价值量大小
|
||||||
|
箭头颜色 = 类型(绿色=资金流 · 蓝色=数据流 · 红色=权力流 · 金色=服务流)
|
||||||
|
|
||||||
|
┌────────────┐
|
||||||
|
│ 广电总局 │
|
||||||
|
└─────┬──────┘
|
||||||
|
政策授权 ↓ ↑ 数据回传+合规报告
|
||||||
|
┌─────▼──────┐ ┌────────────┐
|
||||||
|
码资源 ←────┤ ├────→ 节点费│ ZIIOT │
|
||||||
|
根解析 ←────┤ 广电云 ├────→ 案例 │ │
|
||||||
|
│ AIGC-Hub │ └────────────┘
|
||||||
|
审核API ←───┤ ├───→ API费
|
||||||
|
合规背书←───┤ ├───→ 数据回传
|
||||||
|
│ │ ┌────────────┐
|
||||||
|
分账收入←───┤ ├───→ 赋码费│ 创作者 │
|
||||||
|
版权证书←───┤ ├───→ 作品 │ /MCN │
|
||||||
|
│ │ └────────────┘
|
||||||
|
白名单 ←────┤ ├───→ 认证费
|
||||||
|
分成收入←───┤ ├───→ SDK集成
|
||||||
|
└─────┬──────┘ ┌────────────┐
|
||||||
|
│ │ AI工具厂商 │
|
||||||
|
跨平台通兑 ↓ ↑ 付费 └────────────┘
|
||||||
|
┌─────▼──────┐
|
||||||
|
│ 用户/观众 │ ┌────────────┐
|
||||||
|
└────────────┘ │ 视听平台 │
|
||||||
|
└────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、各方"参与动力评估"雷达图
|
||||||
|
|
||||||
|
```
|
||||||
|
为六方各画一个小型雷达图(3个维度):
|
||||||
|
· 政策驱动力(是否有政策强制/引导)
|
||||||
|
· 经济驱动力(是否有明确经济收益)
|
||||||
|
· 替代成本(不参与的损失有多大)
|
||||||
|
|
||||||
|
广电总局:政策★★★★★ 经济★☆☆☆☆ 替代★★★★★ → 必须参与
|
||||||
|
ZIIOT: 政策★★★☆☆ 经济★★★☆☆ 替代★★☆☆☆ → 战略参与
|
||||||
|
平台: 政策★★★★☆ 经济★★★★☆ 替代★★★★☆ → 主动参与
|
||||||
|
AI工具: 政策★★★☆☆ 经济★★★☆☆ 替代★★☆☆☆ → 配合参与
|
||||||
|
创作者: 政策★★☆☆☆ 经济★★★★★ 替代★★★★★ → 积极参与
|
||||||
|
用户: 政策★☆☆☆☆ 经济★★☆☆☆ 替代★☆☆☆☆ → 被动受益
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 六、"如果不参与会怎样"对比
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────────┬───────────────────────────────┐
|
||||||
|
│ 参与方 │ 不参与的后果 │
|
||||||
|
├──────────────┼───────────────────────────────┤
|
||||||
|
│ 广电总局 │ AIGC内容失控,监管真空 │
|
||||||
|
│ ZIIOT │ MA标识在文化领域无落地案例 │
|
||||||
|
│ 视听平台 │ 无法上线AIGC内容(无码不流通) │
|
||||||
|
│ AI工具厂商 │ 生成内容无法获得赋码→无法流通 │
|
||||||
|
│ 创作者 │ 作品无法合法分发,收益为零 │
|
||||||
|
│ 用户 │ 同一内容需多平台重复付费 │
|
||||||
|
└──────────────┴───────────────────────────────┘
|
||||||
|
|
||||||
|
结论:各方都有"不得不参与"的理由 — 这是一个正和博弈
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 七、广电云的"不可替代性"三角
|
||||||
|
|
||||||
|
```
|
||||||
|
位置:图的右下角,金色强调框
|
||||||
|
|
||||||
|
编码权
|
||||||
|
╱ ╲
|
||||||
|
╱ 广电云 ╲
|
||||||
|
╱ 不可替代 ╲
|
||||||
|
╱ 位置 ╲
|
||||||
|
╱________________╲
|
||||||
|
审核权 结算权
|
||||||
|
|
||||||
|
· 编码权:MA行业节点唯一运营方,码资源垄断分配
|
||||||
|
· 审核权:AI审核模型+训练数据+标注数据独占积累
|
||||||
|
· 结算权:联盟链唯一排序节点,清算合约唯一部署方
|
||||||
|
|
||||||
|
三权合一 = 自然垄断 = 深广护城河
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 八、视觉设计建议
|
||||||
|
|
||||||
|
| 元素 | 建议 |
|
||||||
|
|------|------|
|
||||||
|
| 中心 | 广电云用金色/深蓝圆形,大而醒目 |
|
||||||
|
| 六方 | 各用品牌色的圆角方块,环绕中心 |
|
||||||
|
| 连线 | 双向箭头,粗细代表价值量,颜色代表类型 |
|
||||||
|
| 标注 | 每条线上用小标签标注"给出/获得" |
|
||||||
|
| 驱动力 | 小型雷达图嵌入各方方块内 |
|
||||||
|
| 金额 | 关键收益数字用金色大字标注 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> 本图回答:为什么各方愿意进入这个生态?
|
||||||
|
> 核心答案:政策强制(监管驱动)+ 经济利益(分账驱动)+ 替代成本高(锁定效应)
|
||||||
|
> 广电云的战略位置:中立枢纽,不与任何一方竞争,所有人都需要它
|
||||||
@@ -0,0 +1,448 @@
|
|||||||
|
# AIGC-Hub 系统建设与运营计划详图 — 绘制描述
|
||||||
|
|
||||||
|
> 用途:面向项目管理层/PMO,完整展示从立项到持续运营的全周期计划,含组织、资源、里程碑、运营指标
|
||||||
|
> 建议工具:PPT / Figma / Project / ProcessOn
|
||||||
|
> 画布方向:横版,上方为三期甘特图,中部为组织与资源投入,下方为运营指标仪表盘
|
||||||
|
> 建议尺寸:A1 横版 或 16:9 双页
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、整体构图逻辑
|
||||||
|
|
||||||
|
**"路线 + 组织 + 指标"** 三段垂直布局:
|
||||||
|
|
||||||
|
- **上段(40%)**:三期建设路线图(甘特图 + 里程碑 + 交付物)
|
||||||
|
- **中段(30%)**:组织架构 + 资源投入 + 预算分配
|
||||||
|
- **下段(30%)**:运营计划 + 核心KPI + 增长飞轮
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、上段:三期建设路线图
|
||||||
|
|
||||||
|
### 绘制方式:横向甘特图 + 菱形里程碑标记 + 依赖线
|
||||||
|
|
||||||
|
```
|
||||||
|
时间轴 →
|
||||||
|
M1 M2 M3 M4 M5 M6 M7 M8 M9 M10 M11 M12 Y2-Q1 Y2-Q2 Y2-Q3 Y2-Q4
|
||||||
|
├─────────────── 一期:筑基 ──────────────┤├────────────── 二期:贯通 ──────────────┤├──── 三期:生态 ────→
|
||||||
|
|
||||||
|
═════════════════════════════════════════════════════════════════════════════════════════════════════════════
|
||||||
|
🏗️ 基础设施建设
|
||||||
|
─────────────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||||
|
等保VPC申请+审批 ████
|
||||||
|
K8s集群搭建 ████████
|
||||||
|
数据库/中间件部署 ████████
|
||||||
|
GPU节点采购+部署 ████████████
|
||||||
|
ChainMaker联盟链组网 ████████████████
|
||||||
|
等保三级预测评 ████████
|
||||||
|
◆ M6: 等保三级测评通过 ◆
|
||||||
|
生产环境扩容 ████████████████
|
||||||
|
跨可用区灾备 ████████████████
|
||||||
|
◆ M12: 双活部署完成 ◆
|
||||||
|
|
||||||
|
═════════════════════════════════════════════════════════════════════════════════════════════════════════════
|
||||||
|
🔧 系统研发(按模块)
|
||||||
|
─────────────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||||
|
赋码引擎V1 ████████████████
|
||||||
|
MA编码网关V1 ████████████████
|
||||||
|
审核引擎V1(画面+台词) ████████████████████████
|
||||||
|
创作者工作台V1 ████████████████████
|
||||||
|
C2PA SDK V1(Python) ████████████████████
|
||||||
|
版权链V1(存证+查询) ████████████████████████
|
||||||
|
◆ M5: 核心链路内部联调完成 ◆
|
||||||
|
◆ M6: 一期MVP上线,3平台试点 ◆
|
||||||
|
|
||||||
|
审核引擎V2(+声音+真实性) ████████████████████████████
|
||||||
|
清算引擎V1 ████████████████████████
|
||||||
|
C2PA SDK V2(JS/Go+插件) ████████████████████████
|
||||||
|
MA网关V2(根解析+跨境) ████████████████
|
||||||
|
数据回传服务 ████████████
|
||||||
|
工作台V2(版权+分账) ████████████████
|
||||||
|
监管大屏V1 ████████████
|
||||||
|
◆ M9: 版权链全链路贯通 ◆
|
||||||
|
◆ M11: 清算引擎上线,首笔分账 ◆
|
||||||
|
◆ M12: 二期全量上线 ◆
|
||||||
|
|
||||||
|
AIGC片库统一入口 ████████████████████
|
||||||
|
跨平台权益通兑V2 ████████████████
|
||||||
|
版权金融系统 ████████████████████
|
||||||
|
MA跨境解析网关 ████████████████
|
||||||
|
机顶盒边缘试点 ████████████████████
|
||||||
|
◆ Y2-Q2: AIGC片库上线 ◆
|
||||||
|
◆ Y2-Q4: 跨境MA首批3海外平台 ◆
|
||||||
|
|
||||||
|
═════════════════════════════════════════════════════════════════════════════════════════════════════════════
|
||||||
|
📋 标准与合规
|
||||||
|
─────────────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||||
|
AVCC编码规则制定 ████████████
|
||||||
|
◆ M3: AVCC标准内部评审通过 ◆
|
||||||
|
MA行业节点申请(ZIIOT) ████████████████████████
|
||||||
|
◆ M4-M6: MA.156.10005获批(关键依赖) ◆◆◆
|
||||||
|
行业分账标准草案 ████████████████████████████
|
||||||
|
◆ Y2-Q3: 行业分账标准发布 ◆
|
||||||
|
|
||||||
|
═════════════════════════════════════════════════════════════════════════════════════════════════════════════
|
||||||
|
🤝 商务与生态
|
||||||
|
─────────────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||||
|
头部平台商务对接 ████████████████████████████
|
||||||
|
◆ M4: 首家平台签约 ◆
|
||||||
|
◆ M6: 3-5家平台试点接入 ◆
|
||||||
|
AI工具厂商SDK推广 ████████████████████████████████████
|
||||||
|
◆ M9: 10+主流AI工具集成 ◆
|
||||||
|
MCN/创作者拉新运营 ████████████████████████████████████████████
|
||||||
|
◆ M8: 注册创作者>1万 ◆
|
||||||
|
◆ M12: 注册创作者>10万 ◆
|
||||||
|
新增平台拓展(10+) ████████████████████████████████████
|
||||||
|
跨境平台对接 ████████████████████
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、里程碑汇总表(甘特图下方)
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────┬──────────────────────────────────────────┬────────────────────────┐
|
||||||
|
│ 时间 │ 里程碑 │ 交付物/判定标准 │
|
||||||
|
├──────┼──────────────────────────────────────────┼────────────────────────┤
|
||||||
|
│ M3 │ AVCC编码规则内部评审通过 │ 规则文档V1.0 + 评审纪要 │
|
||||||
|
│ M4 │ 首家头部平台签约 │ 商务合同签署 │
|
||||||
|
│ M4-6 │ MA.156.10005 行业节点获批 ★(关键路径) │ ZIIOT正式批文 │
|
||||||
|
│ M5 │ 核心链路内部联调完成 │ 赋码→审核→上链 端到端通 │
|
||||||
|
│ M6 │ 一期MVP上线 + 等保三级通过 │ 3平台试点+测评报告 │
|
||||||
|
│ M8 │ 注册创作者突破1万 │ 运营数据 │
|
||||||
|
│ M9 │ 版权链全链路贯通 │ 创作→赋码→链→分发 全通 │
|
||||||
|
│ M9 │ 10+主流AI工具集成SDK │ 适配器发布 │
|
||||||
|
│ M11 │ 清算引擎上线,首笔跨平台分账 │ 链上交易记录 │
|
||||||
|
│ M12 │ 二期全量上线 + 月度盈亏平衡 │ 财务报表 │
|
||||||
|
│ Y2Q2 │ AIGC片库统一入口上线 │ 产品发布 │
|
||||||
|
│ Y2Q3 │ 行业分账标准发布 │ 标准文件 │
|
||||||
|
│ Y2Q4 │ MA标识跨境应用(3海外平台) │ 跨境解析验证通过 │
|
||||||
|
└──────┴──────────────────────────────────────────┴────────────────────────┘
|
||||||
|
|
||||||
|
关键路径(红色高亮):
|
||||||
|
MA节点获批 → 赋码引擎上线 → 平台接入 → 清算上线 → 盈亏平衡
|
||||||
|
任何环节延迟都直接影响后续全部节点
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、中段:组织架构与资源投入
|
||||||
|
|
||||||
|
### 总预算框架
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 预算总盘: │
|
||||||
|
│ · 研发+运营预算(本图覆盖):5000万(三年) │
|
||||||
|
│ · 云资源+GPU租用:另行列支(按需弹性,不入本预算) │
|
||||||
|
│ · 原则:自有团队做核心,外包做边缘,云资源按用量付费 │
|
||||||
|
└─────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 团队规模(自有+外包一体化视图,三期演进)
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 团队规模演进(自有 + 外包协作) │
|
||||||
|
│ │
|
||||||
|
│ 一期(15人自有+外包≈8人力) 二期(20人自有+外包≈5人力) 三期(25人自有) │
|
||||||
|
│ ┌──────────────────────┐ ┌──────────────────────┐ ┌────────────────┐│
|
||||||
|
│ │ 🔵 自有核心(15人) │ │ 🔵 自有核心(20人) │ │ 🔵 自有(25人) ││
|
||||||
|
│ │ │ │ │ │ ││
|
||||||
|
│ │ 技术负责人/架构师 (1) │ │ 技术负责人 (1) │ │ 技术负责人 (1) ││
|
||||||
|
│ │ Go工程师 (4) │ │ Go工程师 (4) │ │ Go工程师 (4) ││
|
||||||
|
│ │ 网关+赋码+链服务 │ │ +清算引擎 │ │ ││
|
||||||
|
│ │ Kotlin工程师 (3) │ │ Kotlin工程师 (4) │ │ Kotlin (5) ││
|
||||||
|
│ │ 工作台BFF+审核编排 │ │ +数据回传+报表 │ │ +金融/数据 ││
|
||||||
|
│ │ Python/AI (4) │ │ Python/AI (5) │ │ Python/AI (6)││
|
||||||
|
│ │ 审核模型+AI管道 │ │ +声音+真实性+比对 │ │ +模型迭代 ││
|
||||||
|
│ │ 安全/运维 (1) │ │ 安全/运维 (2) │ │ 安全/SRE (3) ││
|
||||||
|
│ │ 产品/项目管理 (2) │ │ 产品/项目 (2) │ │ 产品/项目 (2) ││
|
||||||
|
│ │ │ │ 运营/BD (2) │ │ 运营/BD (4) ││
|
||||||
|
│ └──────────────────────┘ └──────────────────────┘ └────────────────┘│
|
||||||
|
│ │
|
||||||
|
│ ┌──────────────────────┐ ┌──────────────────────┐ │
|
||||||
|
│ │ 🟡 外包协作(≈8人力) │ │ 🟡 外包协作(≈5人力) │ (三期外包收回) │
|
||||||
|
│ │ │ │ │ │
|
||||||
|
│ │ 前端开发 (3) │ │ 前端维护 (2) │ │
|
||||||
|
│ │ 工作台UI+监管大屏 │ │ 迭代优化 │ │
|
||||||
|
│ │ Rust/C2PA (2) │ │ Rust/C2PA (2) │ │
|
||||||
|
│ │ SDK核心+适配器 │ │ 新工具适配 │ │
|
||||||
|
│ │ 区块链 (2) │ │ 测试/QA (1) │ │
|
||||||
|
│ │ 合约开发+节点部署 │ │ │ │
|
||||||
|
│ │ 测试/QA (1) │ │ │ │
|
||||||
|
│ └──────────────────────┘ └──────────────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ 外包策略: │
|
||||||
|
│ · 一期外包重:前端UI、C2PA SDK、区块链合约等"可定义清楚边界"的模块 │
|
||||||
|
│ · 二期外包轻:仅保留SDK适配器新增、前端微调 │
|
||||||
|
│ · 三期外包收回:核心能力全部内化,外包仅用于短期项目制需求 │
|
||||||
|
│ │
|
||||||
|
│ 核心岗位(自有必须到位): │
|
||||||
|
│ · 技术负责人(全栈架构) — M1到位 │
|
||||||
|
│ · Go资深(网关级调优) — M1到位 │
|
||||||
|
│ · Kotlin架构师(Spring+协程) — M2前到位 │
|
||||||
|
│ · AI算法Lead(多模态审核) — M1到位 │
|
||||||
|
│ · Python/AI工程师 — M1-M2陆续到位 │
|
||||||
|
└─────────────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 预算分配(三期,不含云资源/GPU)
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 三期预算分配(总计5000万,不含云资源/GPU) │
|
||||||
|
│ │
|
||||||
|
│ 一期(6个月) 二期(6个月) 三期(12个月) │
|
||||||
|
│ (1200万) (1400万) (2400万) │
|
||||||
|
│ │
|
||||||
|
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
|
||||||
|
│ │ 自有人力 63% │ │ 自有人力 71% │ │ 自有人力 83% │ │
|
||||||
|
│ │ (750万) │ │ (1000万) │ │ (2000万) │ │
|
||||||
|
│ │ 15人×6月 │ │ 20人×6月 │ │ 25人×12月 │ │
|
||||||
|
│ │ 均薪8.3万/月 │ │ 均薪8.3万/月 │ │ 均薪6.7万/月 │ │
|
||||||
|
│ ├─────────────────┤ ├─────────────────┤ ├─────────────────┤ │
|
||||||
|
│ │ 外包开发 25% │ │ 外包开发 14% │ │ 外包 4% │ │
|
||||||
|
│ │ (300万) │ │ (200万) │ │ (100万) │ │
|
||||||
|
│ │ ≈8人力×6月 │ │ ≈5人力×6月 │ │ 短期项目制 │ │
|
||||||
|
│ ├─────────────────┤ ├─────────────────┤ ├─────────────────┤ │
|
||||||
|
│ │ MA/合规 8% │ │ 运营/BD 11% │ │ 运营/BD 10% │ │
|
||||||
|
│ │ (100万) │ │ (150万) │ │ (250万) │ │
|
||||||
|
│ │ 节点费+测评+律师│ │ 推广+补贴+活动 │ │ 全量运营 │ │
|
||||||
|
│ ├─────────────────┤ ├─────────────────┤ ├─────────────────┤ │
|
||||||
|
│ │ 其他 4% │ │ 其他 4% │ │ 其他 2% │ │
|
||||||
|
│ │ (50万) │ │ (50万) │ │ (50万) │ │
|
||||||
|
│ │ 差旅+工具+培训 │ │ 差旅+工具 │ │ 差旅+工具 │ │
|
||||||
|
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ ════════════════════════════════════════════════════════════ │
|
||||||
|
│ 另行列支(不含在5000万内): │
|
||||||
|
│ · 云资源(K8s/PG/Redis/Kafka/MinIO等):按需,预计年200-500万 │
|
||||||
|
│ · GPU租用(Triton推理):按需,预计年100-300万 │
|
||||||
|
│ · 合计云+GPU:三年约800-1500万(弹性伸缩,按实际用量) │
|
||||||
|
│ ════════════════════════════════════════════════════════════ │
|
||||||
|
│ │
|
||||||
|
│ 成本控制策略: │
|
||||||
|
│ · 自有团队只招核心骨干,拒绝"人海战术" │
|
||||||
|
│ · 外包选"交付物明确"的模块,验收后付款 │
|
||||||
|
│ · GPU不买卡,全部按需租用(A10按小时计费) │
|
||||||
|
│ · 云资源跟着业务量走(一期小规格,二期按需扩) │
|
||||||
|
│ · 开源优先(Kong/PG/Redis/Kafka/ChainMaker 全开源) │
|
||||||
|
└─────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、下段:运营计划与核心KPI
|
||||||
|
|
||||||
|
### 运营阶段划分
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 运营计划四阶段 │
|
||||||
|
│ │
|
||||||
|
│ ┌─── 冷启动期(M1-M6) ───┐ │
|
||||||
|
│ │ 目标:跑通核心流程,验证模式 │
|
||||||
|
│ │ 策略: │
|
||||||
|
│ │ · 头部平台定向商务(1v1 CEO级对接) │
|
||||||
|
│ │ · 首批创作者免费赋码(种子用户100个) │
|
||||||
|
│ │ · AI工具厂商SDK共建(联合开发2-3个适配器) │
|
||||||
|
│ │ · 广电总局联合发文(政策推动力) │
|
||||||
|
│ │ KPI: │
|
||||||
|
│ │ · 平台签约 ≥ 3家 │
|
||||||
|
│ │ · 月赋码量 ≥ 1000部 │
|
||||||
|
│ │ · 系统可用性 ≥ 99.5% │
|
||||||
|
│ └─────────────────────────────────────────────────────────────────────┘│
|
||||||
|
│ │
|
||||||
|
│ ┌─── 增长期(M7-M12) ────┐ │
|
||||||
|
│ │ 目标:规模化放量,建立行业认知 │
|
||||||
|
│ │ 策略: │
|
||||||
|
│ │ · 开放平台接入(自助注册+人工审核) │
|
||||||
|
│ │ · 创作者拉新运营(培训+社区+赋码补贴) │
|
||||||
|
│ │ · SDK推广(AI工具厂商分成激励) │
|
||||||
|
│ │ · 行业白皮书发布(建立权威性) │
|
||||||
|
│ │ · 清算服务上线推广(平台分账方案定制) │
|
||||||
|
│ │ KPI: │
|
||||||
|
│ │ · 平台接入 ≥ 15家 │
|
||||||
|
│ │ · 月赋码量 ≥ 50,000部 │
|
||||||
|
│ │ · 日均API调用 ≥ 100万次 │
|
||||||
|
│ │ · 注册创作者 ≥ 10万 │
|
||||||
|
│ │ · 月度盈亏平衡 │
|
||||||
|
│ └─────────────────────────────────────────────────────────────────────┘│
|
||||||
|
│ │
|
||||||
|
│ ┌─── 成熟期(Y2) ────────┐ │
|
||||||
|
│ │ 目标:生态完善,金融变现 │
|
||||||
|
│ │ 策略: │
|
||||||
|
│ │ · AIGC片库运营(搜索+推荐+支付) │
|
||||||
|
│ │ · 跨平台权益通兑全面推广 │
|
||||||
|
│ │ · 版权金融产品上线(估值+质押+ABS) │
|
||||||
|
│ │ · 机顶盒边缘试点 │
|
||||||
|
│ │ · 跨境MA拓展 │
|
||||||
|
│ │ KPI: │
|
||||||
|
│ │ · 平台接入 ≥ 30家(含3海外) │
|
||||||
|
│ │ · 月赋码量 ≥ 200,000部 │
|
||||||
|
│ │ · 年清算GMV ≥ 50亿 │
|
||||||
|
│ │ · 年收入 ≥ 10亿 │
|
||||||
|
│ └─────────────────────────────────────────────────────────────────────┘│
|
||||||
|
│ │
|
||||||
|
│ ┌─── 生态期(Y3+) ───────┐ │
|
||||||
|
│ │ 目标:成为不可替代的行业基础设施 │
|
||||||
|
│ │ 策略: │
|
||||||
|
│ │ · 行业标准输出(分账标准/审核标准/编码标准) │
|
||||||
|
│ │ · 数据运营变现(行业报告/模型榜单/趋势预测) │
|
||||||
|
│ │ · 金融衍生扩展(保险/基金/交易所对接) │
|
||||||
|
│ │ · 国际化(MA跨境全面运营) │
|
||||||
|
│ │ · 机顶盒DePIN全面铺开 │
|
||||||
|
│ │ KPI: │
|
||||||
|
│ │ · 年收入 ≥ 50亿 │
|
||||||
|
│ │ · 行业渗透率 ≥ 80% │
|
||||||
|
│ │ · 边缘节点 ≥ 2000万 │
|
||||||
|
│ └─────────────────────────────────────────────────────────────────────┘│
|
||||||
|
└─────────────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 核心运营指标仪表盘
|
||||||
|
|
||||||
|
```
|
||||||
|
建议绘制为仪表盘/Dashboard样式,6个核心指标:
|
||||||
|
|
||||||
|
┌───────────┐ ┌───────────┐ ┌───────────┐
|
||||||
|
│ 月赋码量 │ │ 平台接入数 │ │ 日API调用 │
|
||||||
|
│ │ │ │ │ │
|
||||||
|
│ 目标:5万/月│ │ 目标:15家 │ │ 目标:100万 │
|
||||||
|
│ │ │ │ │ │
|
||||||
|
│ ████░░░ │ │ ████████ │ │ ██████░ │
|
||||||
|
│ 60% │ │ 80% │ │ 70% │
|
||||||
|
└───────────┘ └───────────┘ └───────────┘
|
||||||
|
|
||||||
|
┌───────────┐ ┌───────────┐ ┌───────────┐
|
||||||
|
│ 注册创作者 │ │ 月清算GMV │ │ 系统可用性 │
|
||||||
|
│ │ │ │ │ │
|
||||||
|
│ 目标:10万 │ │ 目标:2亿 │ │ 目标:99.9% │
|
||||||
|
│ │ │ │ │ │
|
||||||
|
│ ██████░ │ │ ████░░░ │ │ █████████ │
|
||||||
|
│ 75% │ │ 45% │ │ 99.95% │
|
||||||
|
└───────────┘ └───────────┘ └───────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 六、运营分工(融入自有团队,不单设运营部门)
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 运营职责分配(一期精简模式) │
|
||||||
|
│ │
|
||||||
|
│ 一期:运营由产品/项目管理(2人)兼任 + 技术负责人BD │
|
||||||
|
│ · 平台BD:技术负责人直接对接CTO级(技术方案即商务方案) │
|
||||||
|
│ · 创作者运营:产品经理兼任种子用户维护 │
|
||||||
|
│ · SDK推广:对应开发者自行维护文档+社区 │
|
||||||
|
│ │
|
||||||
|
│ 二期起:自有团队中增设2名运营/BD岗 │
|
||||||
|
│ · 1人负责平台BD + 客户成功 │
|
||||||
|
│ · 1人负责创作者运营 + 内容审核QA │
|
||||||
|
│ │
|
||||||
|
│ 三期:运营扩至4人 │
|
||||||
|
│ · +1 数据运营(行业报告/榜单) │
|
||||||
|
│ · +1 生态运营(金融产品/跨境/机顶盒) │
|
||||||
|
│ │
|
||||||
|
│ 原则:技术驱动型团队,运营轻量化,用产品和API替代人力运营 │
|
||||||
|
└─────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 七、风险管控与应对(右侧配表)
|
||||||
|
|
||||||
|
```
|
||||||
|
┌───────────────────────────────────────────────────────────────┐
|
||||||
|
│ 建设与运营风险矩阵 │
|
||||||
|
├───────────────┬──────┬────────────────┬───────────────────────┤
|
||||||
|
│ 风险 │ 概率 │ 影响 │ 应对措施 │
|
||||||
|
├───────────────┼──────┼────────────────┼───────────────────────┤
|
||||||
|
│ MA节点审批延迟 │ 中 │ 一期延期1-2月 │ 提前3月申请+高层沟通 │
|
||||||
|
│ 头部平台拒绝接入│ 中 │ 生态难以启动 │ 政策推动+利益绑定 │
|
||||||
|
│ AI审核准确率低 │ 中高 │ 人工复核压力大 │ 持续迭代+人机协同 │
|
||||||
|
│ 区块链性能不足 │ 低 │ 高并发时延迟 │ 链下计算+批量上链 │
|
||||||
|
│ 等保测评不过 │ 低 │ 无法上线 │ 预审+安全左移 │
|
||||||
|
│ 关键人才流失 │ 中 │ 项目延期 │ 竞业+期权+梯队建设 │
|
||||||
|
│ 政策方向变化 │ 低 │ 商业模式受影响 │ 保持政策敏感度+多条腿 │
|
||||||
|
│ 竞品出现 │ 低 │ 市场分流 │ MA标准锁定+先发优势 │
|
||||||
|
├───────────────┼──────┼────────────────┼───────────────────────┤
|
||||||
|
│ 最大单点风险:MA行业节点审批 │
|
||||||
|
│ 缓解策略:一期同步开发,M4前即使未获批也可用内部编码先跑通流程 │
|
||||||
|
│ 获批后切换为正式MA编码,向下兼容 │
|
||||||
|
└───────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 八、交付与验收节奏
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 交付节奏(敏捷+里程碑混合) │
|
||||||
|
│ │
|
||||||
|
│ 日常节奏: │
|
||||||
|
│ · 2周一个Sprint · 每Sprint至少1个可演示功能 │
|
||||||
|
│ · 每周五内部Demo · 每月一次外部利益方Review │
|
||||||
|
│ │
|
||||||
|
│ 里程碑验收: │
|
||||||
|
│ · M3 内部验收:编码规则+基础设施就绪 │
|
||||||
|
│ · M6 一期验收:MVP上线+3平台试点+等保通过 │
|
||||||
|
│ · M9 中期验收:版权链贯通+SDK发布+10工具适配 │
|
||||||
|
│ · M12 二期验收:全量上线+盈亏平衡+20平台接入 │
|
||||||
|
│ · Y2Q4 三期验收:片库上线+跨境应用+年收入10亿 │
|
||||||
|
│ │
|
||||||
|
│ 验收标准: │
|
||||||
|
│ · 功能验收:需求覆盖率100% + 严重缺陷0 │
|
||||||
|
│ · 性能验收:满足容量规划表指标(网关P99<50ms等) │
|
||||||
|
│ · 安全验收:等保三级测评通过 + 渗透测试0高危 │
|
||||||
|
│ · 运营验收:核心KPI达标率 ≥ 80% │
|
||||||
|
└─────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 九、持续运营体系(上线后)
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 持续运营体系 │
|
||||||
|
│ │
|
||||||
|
│ ┌─── 技术运营 ───┐ ┌─── 业务运营 ───┐ ┌─── 数据运营 ───┐ │
|
||||||
|
│ │ │ │ │ │ │ │
|
||||||
|
│ │ SRE值班 7×24 │ │ 平台BD持续拓展 │ │ 日报/周报/月报 │ │
|
||||||
|
│ │ 变更窗口(周二四)│ │ 创作者社区运营 │ │ 行业报告(季度) │ │
|
||||||
|
│ │ 容量巡检(周) │ │ 内容审核运营 │ │ 模型效能榜(月) │ │
|
||||||
|
│ │ 安全扫描(日) │ │ 客户成功保障 │ │ 异常检测告警 │ │
|
||||||
|
│ │ 灾备演练(季度) │ │ 活动策划(月) │ │ 趋势预测(季度) │ │
|
||||||
|
│ │ 混沌工程(月) │ │ 投诉处理SLA │ │ 收入分析(周) │ │
|
||||||
|
│ └────────────────┘ └────────────────┘ └────────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ SLA承诺(对外): │
|
||||||
|
│ · 系统可用性:99.9%(月度) │
|
||||||
|
│ · MA网关解析延迟:P99 < 50ms │
|
||||||
|
│ · 审核任务响应:O类<10s · G类<3天 · P类<30天 │
|
||||||
|
│ · 故障恢复:P0<15min · P1<30min │
|
||||||
|
│ · 数据安全:零泄露事件 │
|
||||||
|
└─────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 十、视觉设计建议
|
||||||
|
|
||||||
|
| 元素 | 建议 |
|
||||||
|
|------|------|
|
||||||
|
| 甘特图 | 彩色横条,按团队/语言着色(Go蓝/Kotlin紫/Python黄/Rust橙/基础设施灰) |
|
||||||
|
| 里程碑 | 菱形◆标记,关键路径用红色连线 |
|
||||||
|
| 组织图 | 树状结构,人数用圆形标注 |
|
||||||
|
| 预算 | 堆叠柱状图,三年对比 |
|
||||||
|
| KPI仪表盘 | 环形进度条 + 目标标注 |
|
||||||
|
| 风险 | 红黄绿三色标注概率/影响 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> 本图回答:这个项目怎么建?怎么管?怎么运营?人从哪来?钱怎么花?
|
||||||
|
> 核心价值:让管理层看到清晰的"人-钱-事-时间"全景规划,建立执行信心。
|
||||||
@@ -0,0 +1,359 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1600 2200" font-family="'PingFang SC','Microsoft YaHei','Helvetica Neue',sans-serif">
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="headerGrad" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||||
|
<stop offset="0%" style="stop-color:#1a237e"/>
|
||||||
|
<stop offset="100%" style="stop-color:#283593"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="phase1" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||||
|
<stop offset="0%" style="stop-color:#e3f2fd"/>
|
||||||
|
<stop offset="100%" style="stop-color:#bbdefb"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="phase2" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||||
|
<stop offset="0%" style="stop-color:#e8f5e9"/>
|
||||||
|
<stop offset="100%" style="stop-color:#c8e6c9"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="phase3" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||||
|
<stop offset="0%" style="stop-color:#fff3e0"/>
|
||||||
|
<stop offset="100%" style="stop-color:#ffe0b2"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
|
||||||
|
<!-- 标题 -->
|
||||||
|
<rect x="0" y="0" width="1600" height="80" fill="url(#headerGrad)"/>
|
||||||
|
<text x="800" y="35" text-anchor="middle" fill="white" font-size="22" font-weight="bold">AIGC-Hub 智视码(AVCC) 系统建设与运营计划</text>
|
||||||
|
<text x="800" y="62" text-anchor="middle" fill="#b3e5fc" font-size="13">三年总预算 5000万(不含云资源/GPU) · 自有团队15→20→25人 · 外包边缘模块递减策略</text>
|
||||||
|
|
||||||
|
<!-- ========== 第一部分:三期甘特图 ========== -->
|
||||||
|
<text x="40" y="110" font-size="16" font-weight="bold" fill="#1a237e">▎三期建设路线图</text>
|
||||||
|
|
||||||
|
<!-- 时间轴背景 -->
|
||||||
|
<rect x="40" y="120" width="1520" height="480" rx="8" fill="#fafafa" stroke="#e0e0e0"/>
|
||||||
|
|
||||||
|
<!-- 阶段背景色带 -->
|
||||||
|
<rect x="160" y="130" width="440" height="460" fill="url(#phase1)" opacity="0.4" rx="4"/>
|
||||||
|
<rect x="600" y="130" width="440" height="460" fill="url(#phase2)" opacity="0.4" rx="4"/>
|
||||||
|
<rect x="1040" y="130" width="500" height="460" fill="url(#phase3)" opacity="0.4" rx="4"/>
|
||||||
|
|
||||||
|
<!-- 阶段标签 -->
|
||||||
|
<text x="380" y="150" text-anchor="middle" font-size="13" font-weight="bold" fill="#1565c0">一期:筑基(M1-M6)</text>
|
||||||
|
<text x="820" y="150" text-anchor="middle" font-size="13" font-weight="bold" fill="#2e7d32">二期:贯通(M7-M12)</text>
|
||||||
|
<text x="1290" y="150" text-anchor="middle" font-size="13" font-weight="bold" fill="#e65100">三期:生态(Y2)</text>
|
||||||
|
|
||||||
|
<!-- 月份刻度 -->
|
||||||
|
<g font-size="9" fill="#757575" text-anchor="middle">
|
||||||
|
<text x="197" y="168">M1</text><text x="270" y="168">M2</text><text x="343" y="168">M3</text>
|
||||||
|
<text x="416" y="168">M4</text><text x="489" y="168">M5</text><text x="562" y="168">M6</text>
|
||||||
|
<text x="637" y="168">M7</text><text x="710" y="168">M8</text><text x="783" y="168">M9</text>
|
||||||
|
<text x="856" y="168">M10</text><text x="929" y="168">M11</text><text x="1002" y="168">M12</text>
|
||||||
|
<text x="1110" y="168">Q1</text><text x="1230" y="168">Q2</text><text x="1350" y="168">Q3</text><text x="1470" y="168">Q4</text>
|
||||||
|
</g>
|
||||||
|
<line x1="160" y1="172" x2="1540" y2="172" stroke="#bdbdbd" stroke-width="0.5"/>
|
||||||
|
|
||||||
|
<!-- 行标签 -->
|
||||||
|
<g font-size="10" fill="#424242">
|
||||||
|
<text x="50" y="195">基础设施</text>
|
||||||
|
<text x="50" y="235">赋码引擎</text>
|
||||||
|
<text x="50" y="265">MA网关</text>
|
||||||
|
<text x="50" y="295">审核引擎</text>
|
||||||
|
<text x="50" y="325">工作台</text>
|
||||||
|
<text x="50" y="355">C2PA SDK</text>
|
||||||
|
<text x="50" y="385">版权链</text>
|
||||||
|
<text x="50" y="415">清算引擎</text>
|
||||||
|
<text x="50" y="445">数据回传</text>
|
||||||
|
<text x="50" y="475">监管大屏</text>
|
||||||
|
<text x="50" y="505">AIGC片库</text>
|
||||||
|
<text x="50" y="535">跨境MA</text>
|
||||||
|
<text x="50" y="565">机顶盒试点</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- 甘特条 -->
|
||||||
|
<!-- 基础设施 -->
|
||||||
|
<rect x="170" y="185" width="350" height="14" rx="3" fill="#78909c"/>
|
||||||
|
<!-- 赋码引擎 -->
|
||||||
|
<rect x="230" y="225" width="300" height="14" rx="3" fill="#1976d2"/>
|
||||||
|
<!-- MA网关V1+V2 -->
|
||||||
|
<rect x="270" y="255" width="250" height="14" rx="3" fill="#1976d2"/>
|
||||||
|
<rect x="637" y="255" width="220" height="14" rx="3" fill="#1976d2"/>
|
||||||
|
<!-- 审核引擎V1+V2 -->
|
||||||
|
<rect x="250" y="285" width="330" height="14" rx="3" fill="#f57c00"/>
|
||||||
|
<rect x="637" y="285" width="360" height="14" rx="3" fill="#f57c00"/>
|
||||||
|
<!-- 工作台V1(外包)+V2 -->
|
||||||
|
<rect x="250" y="315" width="290" height="14" rx="3" fill="#7b1fa2" opacity="0.6"/>
|
||||||
|
<rect x="680" y="315" width="250" height="14" rx="3" fill="#7b1fa2"/>
|
||||||
|
<!-- C2PA SDK(外包) -->
|
||||||
|
<rect x="260" y="345" width="280" height="14" rx="3" fill="#d84315" opacity="0.6"/>
|
||||||
|
<rect x="637" y="345" width="280" height="14" rx="3" fill="#d84315" opacity="0.6"/>
|
||||||
|
<!-- 版权链(外包+自有) -->
|
||||||
|
<rect x="300" y="375" width="350" height="14" rx="3" fill="#455a64" opacity="0.7"/>
|
||||||
|
<!-- 清算引擎 -->
|
||||||
|
<rect x="637" y="405" width="320" height="14" rx="3" fill="#1976d2"/>
|
||||||
|
<!-- 数据回传 -->
|
||||||
|
<rect x="637" y="435" width="200" height="14" rx="3" fill="#7b1fa2"/>
|
||||||
|
<!-- 监管大屏(外包) -->
|
||||||
|
<rect x="750" y="465" width="200" height="14" rx="3" fill="#78909c" opacity="0.6"/>
|
||||||
|
<!-- AIGC片库 -->
|
||||||
|
<rect x="1060" y="495" width="350" height="14" rx="3" fill="#e65100"/>
|
||||||
|
<!-- 跨境MA -->
|
||||||
|
<rect x="1100" y="525" width="300" height="14" rx="3" fill="#1976d2"/>
|
||||||
|
<!-- 机顶盒 -->
|
||||||
|
<rect x="1060" y="555" width="400" height="14" rx="3" fill="#78909c"/>
|
||||||
|
|
||||||
|
<!-- 里程碑菱形 -->
|
||||||
|
<g fill="#d32f2f">
|
||||||
|
<polygon points="489,195 497,188 505,195 497,202"/><!-- M5内部联调 -->
|
||||||
|
<polygon points="562,195 570,188 578,195 570,202"/><!-- M6 MVP上线 -->
|
||||||
|
<polygon points="783,395 791,388 799,395 791,402"/><!-- M9版权链贯通 -->
|
||||||
|
<polygon points="929,415 937,408 945,415 937,422"/><!-- M11首笔分账 -->
|
||||||
|
<polygon points="1002,195 1010,188 1018,195 1010,202"/><!-- M12二期全量 -->
|
||||||
|
</g>
|
||||||
|
<g font-size="8" fill="#d32f2f">
|
||||||
|
<text x="510" y="200">M5联调</text>
|
||||||
|
<text x="582" y="200">M6上线</text>
|
||||||
|
<text x="803" y="400">M9链通</text>
|
||||||
|
<text x="949" y="420">M11分账</text>
|
||||||
|
<text x="1022" y="200">M12全量</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- 图例 -->
|
||||||
|
<g transform="translate(40,590)">
|
||||||
|
<rect x="0" y="0" width="12" height="12" rx="2" fill="#1976d2"/><text x="18" y="10" font-size="9" fill="#424242">Go服务(自有)</text>
|
||||||
|
<rect x="110" y="0" width="12" height="12" rx="2" fill="#7b1fa2"/><text x="128" y="10" font-size="9" fill="#424242">Kotlin服务(自有)</text>
|
||||||
|
<rect x="240" y="0" width="12" height="12" rx="2" fill="#f57c00"/><text x="258" y="10" font-size="9" fill="#424242">Python/AI(自有)</text>
|
||||||
|
<rect x="370" y="0" width="12" height="12" rx="2" fill="#d84315" opacity="0.6"/><text x="388" y="10" font-size="9" fill="#424242">Rust/外包</text>
|
||||||
|
<rect x="470" y="0" width="12" height="12" rx="2" fill="#78909c" opacity="0.6"/><text x="488" y="10" font-size="9" fill="#424242">基础设施/外包</text>
|
||||||
|
<polygon points="610,6 617,0 624,6 617,12" fill="#d32f2f"/><text x="630" y="10" font-size="9" fill="#424242">关键里程碑</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- ========== 第二部分:团队与预算 ========== -->
|
||||||
|
<text x="40" y="640" font-size="16" font-weight="bold" fill="#1a237e">▎团队与预算</text>
|
||||||
|
|
||||||
|
<!-- 三期团队卡片 -->
|
||||||
|
<!-- 一期 -->
|
||||||
|
<rect x="40" y="655" width="480" height="280" rx="8" fill="white" stroke="#1565c0" stroke-width="1.5"/>
|
||||||
|
<rect x="40" y="655" width="480" height="30" rx="8" fill="#1565c0"/>
|
||||||
|
<text x="280" y="675" text-anchor="middle" fill="white" font-size="12" font-weight="bold">一期:筑基(M1-M6) · 预算 1200万</text>
|
||||||
|
|
||||||
|
<g font-size="10" fill="#424242" transform="translate(60,700)">
|
||||||
|
<text x="0" y="0" font-weight="bold" fill="#1565c0">🔵 自有核心 15人</text>
|
||||||
|
<text x="0" y="20">技术负责人/架构师 ........ 1人</text>
|
||||||
|
<text x="0" y="38">Go工程师(网关+赋码+链) ... 4人</text>
|
||||||
|
<text x="0" y="56">Kotlin(BFF+审核编排) ..... 3人</text>
|
||||||
|
<text x="0" y="74">Python/AI(审核管道) ...... 4人</text>
|
||||||
|
<text x="0" y="92">安全/运维 ................ 1人</text>
|
||||||
|
<text x="0" y="110">产品/项目管理 ............ 2人</text>
|
||||||
|
|
||||||
|
<text x="0" y="140" font-weight="bold" fill="#f57c00">🟡 外包协作 ≈8人力</text>
|
||||||
|
<text x="0" y="158">前端(工作台+监管大屏) .... 3人</text>
|
||||||
|
<text x="0" y="176">Rust/C2PA SDK ............ 2人</text>
|
||||||
|
<text x="0" y="194">区块链合约+部署 .......... 2人</text>
|
||||||
|
<text x="0" y="212">测试/QA .................. 1人</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- 预算饼图-一期 -->
|
||||||
|
<g transform="translate(370,760)">
|
||||||
|
<circle cx="0" cy="0" r="55" fill="none" stroke="#e0e0e0" stroke-width="20"/>
|
||||||
|
<circle cx="0" cy="0" r="55" fill="none" stroke="#1976d2" stroke-width="20" stroke-dasharray="218 128" stroke-dashoffset="0"/>
|
||||||
|
<circle cx="0" cy="0" r="55" fill="none" stroke="#f57c00" stroke-width="20" stroke-dasharray="86 260" stroke-dashoffset="-218"/>
|
||||||
|
<circle cx="0" cy="0" r="55" fill="none" stroke="#43a047" stroke-width="20" stroke-dasharray="28 318" stroke-dashoffset="-304"/>
|
||||||
|
<text x="0" y="4" text-anchor="middle" font-size="11" font-weight="bold" fill="#333">1200万</text>
|
||||||
|
<text x="0" y="80" text-anchor="middle" font-size="8" fill="#1976d2">■自有750万(63%)</text>
|
||||||
|
<text x="0" y="93" text-anchor="middle" font-size="8" fill="#f57c00">■外包300万(25%)</text>
|
||||||
|
<text x="0" y="106" text-anchor="middle" font-size="8" fill="#43a047">■MA/运营150万(12%)</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- 二期 -->
|
||||||
|
<rect x="560" y="655" width="480" height="280" rx="8" fill="white" stroke="#2e7d32" stroke-width="1.5"/>
|
||||||
|
<rect x="560" y="655" width="480" height="30" rx="8" fill="#2e7d32"/>
|
||||||
|
<text x="800" y="675" text-anchor="middle" fill="white" font-size="12" font-weight="bold">二期:贯通(M7-M12) · 预算 1400万</text>
|
||||||
|
|
||||||
|
<g font-size="10" fill="#424242" transform="translate(580,700)">
|
||||||
|
<text x="0" y="0" font-weight="bold" fill="#2e7d32">🔵 自有核心 20人(+5)</text>
|
||||||
|
<text x="0" y="20">技术负责人 ............... 1人</text>
|
||||||
|
<text x="0" y="38">Go工程师(+清算) .......... 4人</text>
|
||||||
|
<text x="0" y="56">Kotlin(+数据回传+报表) ... 4人</text>
|
||||||
|
<text x="0" y="74">Python/AI(+声音+真实性) .. 5人</text>
|
||||||
|
<text x="0" y="92">安全/运维 ................ 2人</text>
|
||||||
|
<text x="0" y="110">产品/项目管理 ............ 2人</text>
|
||||||
|
<text x="0" y="128">运营/BD .................. 2人</text>
|
||||||
|
|
||||||
|
<text x="0" y="158" font-weight="bold" fill="#f57c00">🟡 外包协作 ≈5人力(递减)</text>
|
||||||
|
<text x="0" y="176">前端维护迭代 ............. 2人</text>
|
||||||
|
<text x="0" y="194">Rust/C2PA新工具适配 ...... 2人</text>
|
||||||
|
<text x="0" y="212">测试/QA .................. 1人</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- 预算饼图-二期 -->
|
||||||
|
<g transform="translate(890,760)">
|
||||||
|
<circle cx="0" cy="0" r="55" fill="none" stroke="#e0e0e0" stroke-width="20"/>
|
||||||
|
<circle cx="0" cy="0" r="55" fill="none" stroke="#1976d2" stroke-width="20" stroke-dasharray="246 100" stroke-dashoffset="0"/>
|
||||||
|
<circle cx="0" cy="0" r="55" fill="none" stroke="#f57c00" stroke-width="20" stroke-dasharray="50 296" stroke-dashoffset="-246"/>
|
||||||
|
<circle cx="0" cy="0" r="55" fill="none" stroke="#43a047" stroke-width="20" stroke-dasharray="50 296" stroke-dashoffset="-296"/>
|
||||||
|
<text x="0" y="4" text-anchor="middle" font-size="11" font-weight="bold" fill="#333">1400万</text>
|
||||||
|
<text x="0" y="80" text-anchor="middle" font-size="8" fill="#1976d2">■自有1000万(71%)</text>
|
||||||
|
<text x="0" y="93" text-anchor="middle" font-size="8" fill="#f57c00">■外包200万(14%)</text>
|
||||||
|
<text x="0" y="106" text-anchor="middle" font-size="8" fill="#43a047">■运营/其他200万(15%)</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- 三期 -->
|
||||||
|
<rect x="1080" y="655" width="480" height="280" rx="8" fill="white" stroke="#e65100" stroke-width="1.5"/>
|
||||||
|
<rect x="1080" y="655" width="480" height="30" rx="8" fill="#e65100"/>
|
||||||
|
<text x="1320" y="675" text-anchor="middle" fill="white" font-size="12" font-weight="bold">三期:生态(Y2) · 预算 2400万</text>
|
||||||
|
|
||||||
|
<g font-size="10" fill="#424242" transform="translate(1100,700)">
|
||||||
|
<text x="0" y="0" font-weight="bold" fill="#e65100">🔵 自有核心 25人(+5)</text>
|
||||||
|
<text x="0" y="20">技术负责人 ............... 1人</text>
|
||||||
|
<text x="0" y="38">Go工程师 ................. 4人</text>
|
||||||
|
<text x="0" y="56">Kotlin(+金融/数据) ....... 5人</text>
|
||||||
|
<text x="0" y="74">Python/AI(+模型迭代) ..... 6人</text>
|
||||||
|
<text x="0" y="92">安全/SRE ................. 3人</text>
|
||||||
|
<text x="0" y="110">产品/项目管理 ............ 2人</text>
|
||||||
|
<text x="0" y="128">运营/BD/数据 ............. 4人</text>
|
||||||
|
|
||||||
|
<text x="0" y="158" font-weight="bold" fill="#9e9e9e">🟡 外包收回(仅短期项目制100万)</text>
|
||||||
|
<text x="0" y="178">核心能力全部内化</text>
|
||||||
|
<text x="0" y="196">外包仅用于临时性需求</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- 预算饼图-三期 -->
|
||||||
|
<g transform="translate(1410,760)">
|
||||||
|
<circle cx="0" cy="0" r="55" fill="none" stroke="#e0e0e0" stroke-width="20"/>
|
||||||
|
<circle cx="0" cy="0" r="55" fill="none" stroke="#1976d2" stroke-width="20" stroke-dasharray="288 58" stroke-dashoffset="0"/>
|
||||||
|
<circle cx="0" cy="0" r="55" fill="none" stroke="#f57c00" stroke-width="20" stroke-dasharray="14 332" stroke-dashoffset="-288"/>
|
||||||
|
<circle cx="0" cy="0" r="55" fill="none" stroke="#43a047" stroke-width="20" stroke-dasharray="44 302" stroke-dashoffset="-302"/>
|
||||||
|
<text x="0" y="4" text-anchor="middle" font-size="11" font-weight="bold" fill="#333">2400万</text>
|
||||||
|
<text x="0" y="80" text-anchor="middle" font-size="8" fill="#1976d2">■自有2000万(83%)</text>
|
||||||
|
<text x="0" y="93" text-anchor="middle" font-size="8" fill="#f57c00">■外包100万(4%)</text>
|
||||||
|
<text x="0" y="106" text-anchor="middle" font-size="8" fill="#43a047">■运营/其他300万(13%)</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- ========== 第三部分:里程碑验收 ========== -->
|
||||||
|
<text x="40" y="970" font-size="16" font-weight="bold" fill="#1a237e">▎关键里程碑与验收标准</text>
|
||||||
|
|
||||||
|
<rect x="40" y="980" width="1520" height="220" rx="8" fill="white" stroke="#e0e0e0"/>
|
||||||
|
|
||||||
|
<!-- 里程碑表格 -->
|
||||||
|
<g font-size="10" fill="#424242">
|
||||||
|
<!-- 表头 -->
|
||||||
|
<rect x="50" y="990" width="1500" height="22" fill="#eceff1"/>
|
||||||
|
<text x="110" y="1005" font-weight="bold">时间</text>
|
||||||
|
<text x="300" y="1005" font-weight="bold">里程碑</text>
|
||||||
|
<text x="700" y="1005" font-weight="bold">交付物/判定标准</text>
|
||||||
|
<text x="1100" y="1005" font-weight="bold">风险等级</text>
|
||||||
|
|
||||||
|
<!-- 数据行 -->
|
||||||
|
<text x="110" y="1030">M3</text><text x="300" y="1030">AVCC编码规则内部评审通过</text><text x="700" y="1030">规则文档V1.0 + 评审纪要</text><rect x="1100" y="1020" width="40" height="14" rx="3" fill="#43a047"/><text x="1108" y="1031" fill="white" font-size="8">低</text>
|
||||||
|
<text x="110" y="1055">M4-M6</text><text x="300" y="1055">MA.156.10005行业节点获批 ★关键路径</text><text x="700" y="1055">ZIIOT正式批文</text><rect x="1100" y="1045" width="40" height="14" rx="3" fill="#e53935"/><text x="1108" y="1056" fill="white" font-size="8">高</text>
|
||||||
|
<text x="110" y="1080">M5</text><text x="300" y="1080">核心链路内部联调(赋码→审核→上链)</text><text x="700" y="1080">端到端自动化测试通过</text><rect x="1100" y="1070" width="40" height="14" rx="3" fill="#fb8c00"/><text x="1108" y="1081" fill="white" font-size="8">中</text>
|
||||||
|
<text x="110" y="1105">M6</text><text x="300" y="1105">一期MVP上线 + 3平台试点 + 等保三级</text><text x="700" y="1105">上线公告 + 平台对接完成 + 测评报告</text><rect x="1100" y="1095" width="40" height="14" rx="3" fill="#fb8c00"/><text x="1108" y="1106" fill="white" font-size="8">中</text>
|
||||||
|
<text x="110" y="1130">M9</text><text x="300" y="1130">版权链全链路贯通 + 10+AI工具集成SDK</text><text x="700" y="1130">链上交易验证 + SDK发布</text><rect x="1100" y="1120" width="40" height="14" rx="3" fill="#43a047"/><text x="1108" y="1131" fill="white" font-size="8">低</text>
|
||||||
|
<text x="110" y="1155">M11</text><text x="300" y="1155">清算引擎上线,首笔跨平台分账</text><text x="700" y="1155">链上分账交易记录</text><rect x="1100" y="1145" width="40" height="14" rx="3" fill="#43a047"/><text x="1108" y="1156" fill="white" font-size="8">低</text>
|
||||||
|
<text x="110" y="1180">M12</text><text x="300" y="1180">二期全量上线 + 月度盈亏平衡</text><text x="700" y="1180">财务报表 + 15+平台接入</text><rect x="1100" y="1170" width="40" height="14" rx="3" fill="#fb8c00"/><text x="1108" y="1181" fill="white" font-size="8">中</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- ========== 第四部分:运营KPI ========== -->
|
||||||
|
<text x="40" y="1230" font-size="16" font-weight="bold" fill="#1a237e">▎运营阶段与核心KPI</text>
|
||||||
|
|
||||||
|
<!-- 四阶段运营 -->
|
||||||
|
<g transform="translate(40,1245)">
|
||||||
|
<!-- 冷启动 -->
|
||||||
|
<rect x="0" y="0" width="370" height="160" rx="8" fill="#e3f2fd" stroke="#1565c0"/>
|
||||||
|
<text x="185" y="22" text-anchor="middle" font-size="11" font-weight="bold" fill="#1565c0">冷启动期(M1-M6)</text>
|
||||||
|
<g font-size="9" fill="#424242" transform="translate(15,38)">
|
||||||
|
<text x="0" y="0">策略:CEO级1v1平台BD</text>
|
||||||
|
<text x="0" y="16">· 首批100创作者免费赋码(种子)</text>
|
||||||
|
<text x="0" y="32">· 联合2-3工具厂商共建SDK</text>
|
||||||
|
<text x="0" y="48">· 广电总局联合发文推动</text>
|
||||||
|
<text x="0" y="72" font-weight="bold" fill="#1565c0">KPI目标:</text>
|
||||||
|
<text x="0" y="88">· 平台签约 ≥ 3家</text>
|
||||||
|
<text x="0" y="104">· 月赋码量 ≥ 1,000部</text>
|
||||||
|
<text x="0" y="120">· 可用性 ≥ 99.5%</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- 增长期 -->
|
||||||
|
<rect x="390" y="0" width="370" height="160" rx="8" fill="#e8f5e9" stroke="#2e7d32"/>
|
||||||
|
<text x="575" y="22" text-anchor="middle" font-size="11" font-weight="bold" fill="#2e7d32">增长期(M7-M12)</text>
|
||||||
|
<g font-size="9" fill="#424242" transform="translate(405,38)">
|
||||||
|
<text x="0" y="0">策略:开放接入+创作者拉新</text>
|
||||||
|
<text x="0" y="16">· 平台自助注册+人工审核</text>
|
||||||
|
<text x="0" y="32">· 创作者社区+培训+补贴</text>
|
||||||
|
<text x="0" y="48">· 行业白皮书发布</text>
|
||||||
|
<text x="0" y="72" font-weight="bold" fill="#2e7d32">KPI目标:</text>
|
||||||
|
<text x="0" y="88">· 平台接入 ≥ 15家</text>
|
||||||
|
<text x="0" y="104">· 月赋码量 ≥ 50,000部</text>
|
||||||
|
<text x="0" y="120">· 月度盈亏平衡</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- 成熟期 -->
|
||||||
|
<rect x="780" y="0" width="370" height="160" rx="8" fill="#fff3e0" stroke="#e65100"/>
|
||||||
|
<text x="965" y="22" text-anchor="middle" font-size="11" font-weight="bold" fill="#e65100">成熟期(Y2)</text>
|
||||||
|
<g font-size="9" fill="#424242" transform="translate(795,38)">
|
||||||
|
<text x="0" y="0">策略:生态完善+金融变现</text>
|
||||||
|
<text x="0" y="16">· AIGC片库运营</text>
|
||||||
|
<text x="0" y="32">· 跨平台权益通兑全面推广</text>
|
||||||
|
<text x="0" y="48">· 版权金融产品上线</text>
|
||||||
|
<text x="0" y="72" font-weight="bold" fill="#e65100">KPI目标:</text>
|
||||||
|
<text x="0" y="88">· 平台 ≥ 30家(含3海外)</text>
|
||||||
|
<text x="0" y="104">· 年清算GMV ≥ 50亿</text>
|
||||||
|
<text x="0" y="120">· 年收入 ≥ 10亿</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- 生态期 -->
|
||||||
|
<rect x="1170" y="0" width="370" height="160" rx="8" fill="#fce4ec" stroke="#880e4f"/>
|
||||||
|
<text x="1355" y="22" text-anchor="middle" font-size="11" font-weight="bold" fill="#880e4f">生态期(Y3+)</text>
|
||||||
|
<g font-size="9" fill="#424242" transform="translate(1185,38)">
|
||||||
|
<text x="0" y="0">策略:行业基础设施不可替代</text>
|
||||||
|
<text x="0" y="16">· 行业标准输出</text>
|
||||||
|
<text x="0" y="32">· 数据运营变现</text>
|
||||||
|
<text x="0" y="48">· 机顶盒DePIN全面铺开</text>
|
||||||
|
<text x="0" y="72" font-weight="bold" fill="#880e4f">KPI目标:</text>
|
||||||
|
<text x="0" y="88">· 年收入 ≥ 50亿</text>
|
||||||
|
<text x="0" y="104">· 行业渗透率 ≥ 80%</text>
|
||||||
|
<text x="0" y="120">· 边缘节点 ≥ 2000万</text>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- ========== 第五部分:风险矩阵 ========== -->
|
||||||
|
<text x="40" y="1440" font-size="16" font-weight="bold" fill="#1a237e">▎风险矩阵与应对</text>
|
||||||
|
|
||||||
|
<rect x="40" y="1455" width="1520" height="180" rx="8" fill="white" stroke="#e0e0e0"/>
|
||||||
|
<g font-size="10" fill="#424242">
|
||||||
|
<rect x="50" y="1465" width="1500" height="22" fill="#eceff1"/>
|
||||||
|
<text x="80" y="1480" font-weight="bold">风险</text>
|
||||||
|
<text x="380" y="1480" font-weight="bold">概率</text>
|
||||||
|
<text x="480" y="1480" font-weight="bold">影响</text>
|
||||||
|
<text x="620" y="1480" font-weight="bold">应对措施</text>
|
||||||
|
<text x="1050" y="1480" font-weight="bold">责任人</text>
|
||||||
|
|
||||||
|
<text x="80" y="1505">MA行业节点审批延迟</text><text x="380" y="1505" fill="#e53935" font-weight="bold">中高</text><text x="480" y="1505">一期延期1-2月</text><text x="620" y="1505">提前3月申请 · 高层沟通 · 先用内部编码过渡</text><text x="1050" y="1505">技术负责人+BD</text>
|
||||||
|
<text x="80" y="1530">头部平台拒绝接入</text><text x="380" y="1530" fill="#fb8c00">中</text><text x="480" y="1530">生态启动慢</text><text x="620" y="1530">政策推动 · 利益绑定(审核成本节省70%) · 降接入门槛</text><text x="1050" y="1530">BD+产品</text>
|
||||||
|
<text x="80" y="1555">AI审核准确率不足</text><text x="380" y="1555" fill="#fb8c00">中</text><text x="480" y="1555">人工复核压力</text><text x="620" y="1555">持续模型迭代 · A/B测试 · 人机协同降级方案</text><text x="1050" y="1555">AI Lead</text>
|
||||||
|
<text x="80" y="1580">关键人才流失</text><text x="380" y="1580" fill="#fb8c00">中</text><text x="480" y="1580">项目延期</text><text x="620" y="1580">竞业协议 · 期权激励 · 核心岗位AB角 · 知识文档化</text><text x="1050" y="1580">技术负责人</text>
|
||||||
|
<text x="80" y="1605">等保三级测评不通过</text><text x="380" y="1605" fill="#43a047">低</text><text x="480" y="1605">无法上线</text><text x="620" y="1605">提前聘请测评机构预审 · 安全左移 · 专人跟进</text><text x="1050" y="1605">安全/运维</text>
|
||||||
|
<text x="80" y="1630">区块链性能瓶颈</text><text x="380" y="1630" fill="#43a047">低</text><text x="480" y="1630">高峰延迟</text><text x="620" y="1630">批量上链 · 链下计算 · 异步确认机制已设计</text><text x="1050" y="1630">Go工程师</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- ========== 第六部分:成本控制策略 ========== -->
|
||||||
|
<text x="40" y="1670" font-size="16" font-weight="bold" fill="#1a237e">▎成本控制策略</text>
|
||||||
|
|
||||||
|
<rect x="40" y="1685" width="1520" height="130" rx="8" fill="#f3e5f5" stroke="#7b1fa2" stroke-width="0.5"/>
|
||||||
|
<g font-size="11" fill="#424242" transform="translate(70,1710)">
|
||||||
|
<text x="0" y="0" font-weight="bold" fill="#7b1fa2">六大成本控制原则:</text>
|
||||||
|
<text x="0" y="25">① 自有团队只招核心骨干(架构师+Lead级),拒绝人海战术 — 15人做30人的事靠架构设计和自动化</text>
|
||||||
|
<text x="0" y="48">② 外包选"交付物边界清晰"的模块(前端UI/SDK适配器/合约),验收后一次性付款,不养人</text>
|
||||||
|
<text x="0" y="71">③ GPU不买卡,全部按需租用(A10/A100按小时),审核高峰弹性扩,低谷缩零</text>
|
||||||
|
<text x="0" y="94">④ 云资源跟着业务量走(一期最小规格起步),利用K8s HPA自动伸缩,不预留冗余</text>
|
||||||
|
<text x="0" y="117">⑤ 技术栈全开源(Kong/PG/Redis/Kafka/ChainMaker/Triton),零License费用</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- ========== 第七部分:总结框 ========== -->
|
||||||
|
<rect x="40" y="1840" width="1520" height="100" rx="8" fill="#1a237e"/>
|
||||||
|
<g font-size="13" fill="white" transform="translate(800,1870)" text-anchor="middle">
|
||||||
|
<text x="0" y="0" font-weight="bold" font-size="15">三年规划总结</text>
|
||||||
|
<text x="0" y="28">研发+运营预算 5000万(不含云/GPU) · 自有15→25人精英团队 · 外包逐期收回</text>
|
||||||
|
<text x="0" y="52">M6 MVP上线 → M10 月度盈亏平衡 → M12 全量运营 → Y2 年收入10亿</text>
|
||||||
|
<text x="0" y="76" font-size="11" fill="#b3e5fc">关键成功因子:MA节点获批(M4-M6) × 头部平台接入(≥3家) × 政策推动力度</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- 底部水印 -->
|
||||||
|
<text x="800" y="1970" text-anchor="middle" font-size="9" fill="#9e9e9e">AIGC-Hub 智视码(AVCC) 体系建设方案 · 系统建设与运营计划 · V2.0 · 2026年6月</text>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 24 KiB |
@@ -0,0 +1,107 @@
|
|||||||
|
# AIGC-Hub 项目总体与分阶段详细预算方案
|
||||||
|
|
||||||
|
> 版本:V1.0
|
||||||
|
> 编制日期:2026年6月
|
||||||
|
> 货币单位:人民币(RMB/万元)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 总体预算摘要
|
||||||
|
|
||||||
|
AIGC-Hub 项目整体规划为期两年(分为三期)。前两年的总预算约为 **3,300 万元**。
|
||||||
|
预算的核心投入方向从一期的“研发与基础设施建设”逐渐向三期的“生态运营与合规算力”倾斜。
|
||||||
|
|
||||||
|
| 阶段 | 周期 | 核心目标 | 预计预算 (万元) | 占比 |
|
||||||
|
|------|------|----------|-----------------|------|
|
||||||
|
| **一期:筑基** | 第1-6个月 | 核心系统从0到1,打通赋码与基本审核 | 850 | 25.7% |
|
||||||
|
| **二期:贯通** | 第7-12个月 | 全链路上链,SDK推广,AI算力扩容 | 1,050 | 31.8% |
|
||||||
|
| **三期:生态** | 第13-24个月| 跨平台结算,商业变现,生态全面运营 | 1,400 | 42.5% |
|
||||||
|
| **总计** | **24个月** | | **3,300** | **100%** |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 详细预算分解
|
||||||
|
|
||||||
|
### 一、 一期:筑基(第1-6个月)- 总预算 850 万元
|
||||||
|
|
||||||
|
**目标:完成赋码中心 V1.0、审核引擎 MVP、MA 节点申请、3-5 家平台接入。**
|
||||||
|
|
||||||
|
#### 1. 研发与团队人力成本(510 万元)
|
||||||
|
*团队规模:约 30 人(按一线城市互联网行业平均成本计算,含社保公积金)*
|
||||||
|
- **核心架构与后端组 (10人)**:150万 (网关、赋码引擎)
|
||||||
|
- **前端与移动端组 (5人)**:60万 (创作者工作台、监管大屏)
|
||||||
|
- **AI 算法与工程组 (8人)**:160万 (多模态合规模型定制与推理服务)
|
||||||
|
- **区块链与安全组 (4人)**:80万 (版权联盟链底座、等保建设)
|
||||||
|
- **产品/项目/测试 (3人)**:60万
|
||||||
|
|
||||||
|
#### 2. 云资源与基础设施(180 万元)
|
||||||
|
- **等保三级 VPC 专区(包含防火墙/WAF/堡垒机/态势感知等)**:40万/半年
|
||||||
|
- **基础云服务器与数据库 (PG/Redis/Kafka/ClickHouse集群)**:50万/半年
|
||||||
|
- **AI 推理 GPU 节点 (A10 * 4)**:40万/半年
|
||||||
|
- **对象存储 (MinIO/OSS) 及带宽流量**:30万/半年
|
||||||
|
- **专线接入 (广电总局、ZIIOT根节点)**:20万/半年
|
||||||
|
|
||||||
|
#### 3. 合规与外部资质费用(60 万元)
|
||||||
|
- **等保三级测评及整改服务费**:20万
|
||||||
|
- **ZIIOT MA 行业节点申请与技术对接服务费**:30万
|
||||||
|
- **商用密码应用安全性评估(密评)**:10万
|
||||||
|
|
||||||
|
#### 4. 运营与市场启动(100 万元)
|
||||||
|
- **头部平台对接商务公关与技术支持**:50万
|
||||||
|
- **品牌发布会及行业白皮书制作**:50万
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 二、 二期:贯通(第7-12个月)- 总预算 1,050 万元
|
||||||
|
|
||||||
|
**目标:全面贯通版权链、发布 AI SDK、覆盖 80% AIGC 内容预审,处理量激增。**
|
||||||
|
|
||||||
|
#### 1. 研发与团队人力成本(600 万元)
|
||||||
|
*团队规模:扩编至 40 人(增加清算组与 SDK 组)*
|
||||||
|
- **新增清算与分账组 (2人)**:40万
|
||||||
|
- **新增 C2PA SDK 研发组 (3人)**:60万
|
||||||
|
- **原有团队及新增商务技术支持 (35人)**:500万
|
||||||
|
|
||||||
|
#### 2. 云资源与 AI 算力扩容(300 万元)
|
||||||
|
- **AI 算力大规模扩容 (A100 * 4 替换部分 A10,支持深伪检测)**:150万/半年
|
||||||
|
- **带宽与 CDN 流量费(视频回传与解析量激增)**:80万/半年
|
||||||
|
- **数据库扩容与灾备节点建设**:70万/半年
|
||||||
|
|
||||||
|
#### 3. 运营、审核与业务拓展(150 万元)
|
||||||
|
- **人工终审及人工复核外包团队(约 20 人,处理边缘 Case)**:80万/半年
|
||||||
|
- **全网版权监测及爬虫服务费(防侵权切片)**:30万
|
||||||
|
- **开发者与 MCN 机构扶持补贴及宣发**:40万
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 三、 三期:生态(第13-24个月)- 总预算 1,400 万元
|
||||||
|
|
||||||
|
**目标:跨平台结算常态化、金融衍生品落地、跨境应用、实现全面商业化变现。**
|
||||||
|
|
||||||
|
#### 1. 研发与团队人力成本(700 万元)
|
||||||
|
*团队规模:约 50 人(增加金融衍生与数据运营团队),进入稳定迭代期*
|
||||||
|
- **金融系统与数据要素团队建设**:150万
|
||||||
|
- **核心研发与运维支持常态化**:550万
|
||||||
|
|
||||||
|
#### 2. 基础设施与全网算力(400 万元)
|
||||||
|
- **核心计算与存储资源 (多地多活部署保障金融级高可用)**:200万/年
|
||||||
|
- **推理节点弹性扩容与边缘计算投入**:120万/年
|
||||||
|
- **跨平台对账系统与清算通道手续费垫资**:80万/年
|
||||||
|
|
||||||
|
#### 3. 深度运营与生态金融(300 万元)
|
||||||
|
- **数据要素登记与交易所挂牌专项费用**:50万
|
||||||
|
- **跨平台商业化宣发与创作者激励计划**:100万
|
||||||
|
- **日常人工终审/客服外包及法务维权**:150万/年
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 预算与营收预期测算(ROI简析)
|
||||||
|
|
||||||
|
虽然前期投入 3,300 万,但根据商业模式设计,项目有望在第二年末实现 **现金流回正与规模化盈利**。
|
||||||
|
|
||||||
|
**关键收入预期模型:**
|
||||||
|
1. **赋码费(门票收入)**:假设第二年处理普通及其他类微短剧 50 万部,平均赋码及预审费 100 元/部,年收入可达 **5,000 万元**。
|
||||||
|
2. **跨平台清算佣金**:假设通过 AVCC 实现的跨平台付费点播 GMV 为 2 亿元,提取 6% 技术清算服务费,年收入可达 **1,200 万元**。
|
||||||
|
3. **SaaS 与认证费**:向 AI 厂商收取白名单年费,向平台提供侵权检测 SaaS,预估年收入 **500 万元**。
|
||||||
|
|
||||||
|
**结论**:在保守预估下,项目在第 18-24 个月即可覆盖前期所有的研发与基础设施投入。该预算规划(3,300万投入换取高壁垒护城河)对于广电云实现向“金融与治理基础设施运营商”的转型具有极高的投资性价比。
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
# 国家 AIGC 视听内容登记与分发基础设施(AIGC-Hub)项目总体概述
|
||||||
|
|
||||||
|
> **面向管理层与决策委员会**
|
||||||
|
> 编制日期:2026年6月
|
||||||
|
> 核心定位:**“AI 时代网络视听产业的金融与治理基础设施”**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、 项目背景与战略机遇
|
||||||
|
|
||||||
|
### 1. 产业痛点与挑战
|
||||||
|
随着生成式人工智能(AIGC)的爆发,AI 漫剧等新型视听内容正以前所未有的速度涌入市场,传统网络视听监管与商业体系面临严峻挑战:
|
||||||
|
* **监管侧“管不住”**:内容产量呈指数级增长,同质化、换皮重发严重,传统人工审核与滞后的备案机制无法应对。
|
||||||
|
* **平台侧“成本高”**:各平台自建审核团队成本极高,且缺乏统一标准,跨平台确权维权困难。
|
||||||
|
* **创作侧“变现难”**:AI 辅助创作的版权归属不清,分账机制不透明,创作者权益难以保障。
|
||||||
|
|
||||||
|
### 2. 战略破局:MA 国际标识赋能
|
||||||
|
在数字身份基础设施成为全球竞争制高点的当下,本方案创新性地将网络视听监管与 **MA 全球统一标识代码体系(ISO/IEC 15459)** 深度融合。通过向中关村工信二维码技术研究院(ZIIOT)申请建立 **MA.AIGC 视听内容行业根节点**,赋予每一部 AIGC 作品全球唯一、不可篡改的“数字身份证”——**智视码(AVCC)**。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、 核心定位与项目愿景
|
||||||
|
|
||||||
|
**建设和运营主体**:广电云(中国广电网络股份有限公司)
|
||||||
|
|
||||||
|
**核心定位**:
|
||||||
|
打造以“智视码(AVCC)”为核心的国家级 AIGC 视听内容登记、审核、分发与结算的基础设施。实现“一剧一码、一码全网、码链同源、全球互认”。
|
||||||
|
|
||||||
|
**广电云的角色蜕变**:
|
||||||
|
从传统的“云资源管道商(IaaS)”全面升级为不可替代的 **“内容治理运营商(RegTech) + 内容金融基础设施运营商(FinTech)”**。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、 “管得住与放得活”的生态闭环
|
||||||
|
|
||||||
|
AIGC-Hub 的核心设计哲学是:**监管集权、运营中立、责任分散、利益共享。**
|
||||||
|
|
||||||
|
* **广电总局(握终审/定规则)**:不介入海量内容日常审核,只抓“标准、抽查、黑名单”,通过数据回传实现“精准靶向监管”。
|
||||||
|
* **ZIIOT(定标准/发根码)**:提供国际标准底座和全球根解析服务,提升中国数字文化产业的国际话语权。
|
||||||
|
* **广电云(搭平台/做清算)**:作为中立枢纽,提供智能审核工具、分配 AVCC 编码、运营版权链,不涉足内容经营,确保公信力。
|
||||||
|
* **视听平台(担主责/降成本)**:依托广电云 AI 审核 API 降低 70% 审核成本,通过 MA 编码网关实现内容合规快筛与跨平台确权。
|
||||||
|
* **创作者与 AI 工具(源头举证/享收益)**:在生成源头嵌入 C2PA 水印与 MA 标识,作品确权上链,通过智能合约实现自动化分账。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、 高毛利的四层商业模式
|
||||||
|
|
||||||
|
广电云围绕“编码权、审核权、结算权、数据权”,构建了多元化的商业变现闭环:
|
||||||
|
|
||||||
|
1. **第一层:赋码服务(门票经济,基础现金流)**
|
||||||
|
* 所有 AI 漫剧必须持码(AVCC)流通,按件或按量收取 50-2000 元不等的赋码费,预计年赋码量超百万部。
|
||||||
|
2. **第二层:合规 SaaS(高毛利技术输出)**
|
||||||
|
* 向各大平台与 MCN 机构提供 AI 预审 API、AIGC 真实性核验、版权比对等云端调用服务,按次计费;向 AI 模型厂商收取“白名单认证年费”。
|
||||||
|
3. **第三层:跨平台清算与版权金融(核心爆发点)**
|
||||||
|
* 依托联盟链,作为 AI 漫剧跨平台流转的“央行”,抽取 6%-8% 的分账清算服务费。
|
||||||
|
* 衍生版权质押估值报告、数据要素登记证书(联合数据交易所)等金融服务。
|
||||||
|
4. **第四层:数据与生态运营(战略壁垒)**
|
||||||
|
* 售卖 AIGC 行业趋势报告、模型效能榜单;联合保险公司推出“过审险”等生态产品。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、 总体架构:MA根节点 + 1朵云 + 3大引擎 + N个接入方
|
||||||
|
|
||||||
|
系统架构在设计上高度兼顾了合规性与先进性(等保三级、混合语言高性能架构):
|
||||||
|
|
||||||
|
* **底层**:ZIIOT MA 全球根解析体系
|
||||||
|
* **核心基座(1朵云)**:广电云等保三级专属资源池
|
||||||
|
* **核心引擎(3大引擎)**:
|
||||||
|
* **赋码引擎**:自动生成六段式 AVCC 国际标准编码。
|
||||||
|
* **审核引擎**:利用 AI 大模型进行画面、台词、声音的多模态秒级预审。
|
||||||
|
* **版权链与清算引擎**:基于联盟链(长安链)实现不可篡改的确权与智能合约分账。
|
||||||
|
* **接入端(N方)**:长短视频平台、AI 绘画/视频生成工具、MCN 及创作者。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 六、 实施路线图与投资回报预期
|
||||||
|
|
||||||
|
项目采取“小步快跑,生态优先”的策略,分三期推进:
|
||||||
|
|
||||||
|
* **一期:筑基(第 1-6 个月)**
|
||||||
|
* **目标**:跑通 AVCC 赋码与 AI 预审核心链路,获取 MA 行业节点授权。
|
||||||
|
* **成果**:接通 3-5 家头部平台试点,上线创作者工作台。
|
||||||
|
* **二期:贯通(第 6-12 个月)**
|
||||||
|
* **目标**:发布 AI 工具打码 SDK,全面覆盖各类 AIGC 内容;上线版权链分账功能。
|
||||||
|
* **成果**:建立完整的“生成-确权-赋码-分发-结算”链条。
|
||||||
|
* **三期:生态(第 1-2 年)**
|
||||||
|
* **目标**:打造中国 AIGC 内容数字资产交易中枢,推动 MA 标识的跨境文化贸易应用。
|
||||||
|
* **成果**:实现规模化盈利与金融衍生变现。
|
||||||
|
|
||||||
|
**盈亏平衡预期**:预计在年赋码量达到 50 万部,或跨平台结算 GMV 达到 10 亿元时,项目可实现全面盈亏平衡,并依托垄断性枢纽地位转化为持续的利润引擎。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 七、 总结
|
||||||
|
|
||||||
|
AIGC-Hub 项目不是一个单纯的软件外包工程,而是**国家级数字资产基础设施的抢位之战**。通过本项目的建设,广电云将成功卡位“数字中国”与“数据基础设施”建设的战略核心节点,既为国家解决了 AIGC 时代网络视听的治理难题,又为公司开辟了具有深广护城河的全新百亿级数字经济赛道。
|
||||||
@@ -0,0 +1,498 @@
|
|||||||
|
# MA+哈希码 IPTV内容可信锁定系统(TCS-IPTV)完整方案
|
||||||
|
|
||||||
|
## 一、方案概述
|
||||||
|
|
||||||
|
### 1.1 背景
|
||||||
|
IPTV内容流转涉及CP(内容供应商)、IPTV集成播控平台、运营商(分发网络)三方主体,各自使用独立编码体系,导致:
|
||||||
|
- 同一内容反复审核,边际成本不降
|
||||||
|
- 版本替换、换壳重发难以识别
|
||||||
|
- 违规下架指令逐层翻译,响应滞后
|
||||||
|
- 跨省跨运营商复用几乎要重新走全流程
|
||||||
|
|
||||||
|
### 1.2 核心目标
|
||||||
|
建立**"监管身份+技术指纹"双锚定机制**,以MA码为监管主键、哈希码为技术指纹,实现:
|
||||||
|
- **审播一致**:送审版=播出版,任何篡改秒级识别
|
||||||
|
- **一码通行**:一省过审,全网凭MA码+哈希准入
|
||||||
|
- **精准溯源**:出问题凭MA码秒级定位三方系统
|
||||||
|
- **数据可信**:播放量、结算、上报以统一标识聚合
|
||||||
|
|
||||||
|
### 1.3 设计原则
|
||||||
|
- **不替代现有系统**:三方保留自有编码,通过映射层对接
|
||||||
|
- **最小侵入**:关键节点(送审、入库、分发、播放)嵌入校验
|
||||||
|
- **监管合规**:完全符合广电总局网络剧片发行许可及备案制度
|
||||||
|
- **可扩展**:支持网络剧、微短剧、网络电影、网络动画等多形态
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、系统总体架构
|
||||||
|
|
||||||
|
### 2.1 四方角色与定位
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────┐
|
||||||
|
│ 监管侧(广电总局/省局) │
|
||||||
|
│ 网络剧片发行许可证系统 / 备案系统 │
|
||||||
|
│ ↓ 签发MA码 │
|
||||||
|
├─────────────────────────────────────────────────────────────┤
|
||||||
|
│ CP端 播控平台端 运营商端 │
|
||||||
|
│ (内容供应商) (集成播控) (分发网络) │
|
||||||
|
│ │
|
||||||
|
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
|
||||||
|
│ │ 媒资系统 │ ──→ │ 审核系统 │ ──→ │ CDN/EPG │ │
|
||||||
|
│ │ 生产哈希 │ │ 验真哈希 │ │ 校验哈希 │ │
|
||||||
|
│ └─────────┘ └─────────┘ └─────────┘ │
|
||||||
|
│ │ │ │ │
|
||||||
|
│ └────────────────┴───────────────────┘ │
|
||||||
|
│ │ │
|
||||||
|
│ ┌──────────┴──────────┐ │
|
||||||
|
│ │ 可信数据空间(区块链) │ │
|
||||||
|
│ │ MA码↔哈希↔三方编码映射 │ │
|
||||||
|
│ └─────────────────────┘ │
|
||||||
|
└─────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.2 三层技术架构
|
||||||
|
|
||||||
|
| 层级 | 功能 | 技术组件 |
|
||||||
|
|------|------|---------|
|
||||||
|
| **接入层** | 三方系统对接、文件上传、哈希计算 | 哈希计算SDK、API网关、文件切片服务 |
|
||||||
|
| **可信层** | MA码与哈希绑定、存证、映射查询 | 联盟链(或分布式账本)、智能合约、Merkle Tree存储 |
|
||||||
|
| **应用层** | 审核验真、分发校验、终端抽检、数据上报 | 审核工作台、CDN注入校验、播放器SDK、监管大屏 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、双锚定模型设计
|
||||||
|
|
||||||
|
### 3.1 核心概念:Content Twin ID(CTID)
|
||||||
|
|
||||||
|
每一条内容在系统中拥有唯一的**Content Twin ID**,由双锚定构成:
|
||||||
|
|
||||||
|
```
|
||||||
|
CTID = {
|
||||||
|
"ma_code": "(京)网微剧审字(2025)第XXX号", // 监管锚点
|
||||||
|
"content_hash": "sha256:a1b2c3d4...", // 技术锚点
|
||||||
|
"version": "v1.0", // 版本锚点
|
||||||
|
"merkle_root": "sha256:xyz789..." // 分段聚合锚点
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**绑定规则**:
|
||||||
|
- MA码由广电总局/省局签发,代表**合法身份**
|
||||||
|
- 哈希码由内容本体计算,代表**数据真实性**
|
||||||
|
- 两者在可信数据空间中**1:1强绑定**,不可解绑
|
||||||
|
- 内容任何帧级变动 → 哈希变化 → 绑定断裂 → 需重新送审
|
||||||
|
|
||||||
|
### 3.2 双哈希机制
|
||||||
|
|
||||||
|
| 哈希类型 | 算法 | 用途 | 敏感度 |
|
||||||
|
|---------|------|------|--------|
|
||||||
|
| **文件哈希(File Hash)** | SHA-256 | 精确锁定某一版本文件 | 比特级敏感(转码即变) |
|
||||||
|
| **感知哈希(Perceptual Hash)** | aHash/dHash/pHash | 跨格式识别同一内容 | 容忍转码、压缩、分辨率调整 |
|
||||||
|
|
||||||
|
**应用逻辑**:
|
||||||
|
- 审核准入:文件哈希必须完全匹配
|
||||||
|
- 内容识别:感知哈希用于跨版本、跨格式关联
|
||||||
|
- 终端校验:文件哈希抽检完整性
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、全流程设计
|
||||||
|
|
||||||
|
### 4.1 第一阶段:CP端(内容生产与送审)
|
||||||
|
|
||||||
|
**Step 1:母版哈希生成**
|
||||||
|
- CP完成内容制作后,在**原始母版文件**(ProRes/DPX等)上计算:
|
||||||
|
- 全文件SHA-256
|
||||||
|
- 分段哈希(按场景/集数切分,生成Merkle Tree)
|
||||||
|
- 感知哈希
|
||||||
|
- 哈希值本地存证,不上传原文件,仅上传哈希
|
||||||
|
|
||||||
|
**Step 2:送审申报**
|
||||||
|
- CP登录广电总局"重点网络影视剧信息备案系统"或省级备案系统
|
||||||
|
- 填写节目信息,上传:
|
||||||
|
- 片花、海报、剧本
|
||||||
|
- **哈希值包**(含Merkle Tree根哈希)
|
||||||
|
- 系统返回**送审流水号**
|
||||||
|
|
||||||
|
**Step 3:审核通过与MA码签发**
|
||||||
|
- 省级广电/广电总局审核内容
|
||||||
|
- 审核通过后,系统:
|
||||||
|
- 签发MA码(或备案号)
|
||||||
|
- **将MA码与送审哈希包绑定写入可信数据空间**
|
||||||
|
- CP获得"MA码+哈希证书",方可进入播控平台
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4.2 第二阶段:播控平台端(审核与入库)
|
||||||
|
|
||||||
|
**Step 4:送审文件验真**
|
||||||
|
- CP向播控平台送审,提交:
|
||||||
|
- MA码
|
||||||
|
- 送审文件(母版或播出版)
|
||||||
|
- 授权链文件
|
||||||
|
- 播控平台**计算送审文件哈希**,查询可信数据空间:
|
||||||
|
- 哈希匹配 → 确认是"正版过审内容",进入内容审核
|
||||||
|
- 哈希不匹配 → 直接退回,标记"疑似版本替换"
|
||||||
|
|
||||||
|
**Step 5:内容审核与转码授权**
|
||||||
|
- 播控平台对内容进行合规审核(政治、色情、暴力等)
|
||||||
|
- 审核通过后,如需转码(H.264/H.265/4K/HD多版本):
|
||||||
|
- 由**授权转码中心**执行,转码后重新计算各版本文件哈希
|
||||||
|
- 生成"转码版哈希证书",与MA码绑定,写入可信数据空间
|
||||||
|
- 原母版哈希与转码版哈希建立父子关系
|
||||||
|
|
||||||
|
**Step 6:EPG编排与编码映射**
|
||||||
|
- 播控平台将内容纳入EPG,内部保留自有审核流水号
|
||||||
|
- 在可信数据空间中建立映射:
|
||||||
|
```
|
||||||
|
播控流水号 ↔ MA码 ↔ 文件哈希 ↔ 转码版哈希
|
||||||
|
```
|
||||||
|
- 向运营商分发时,**必须携带MA码+哈希证书**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4.3 第三阶段:运营商端(分发与播出)
|
||||||
|
|
||||||
|
**Step 7:CDN注入校验**
|
||||||
|
- 运营商收到播控平台分发内容,注入CDN前:
|
||||||
|
- 计算注入文件哈希
|
||||||
|
- 查询可信数据空间,比对MA码绑定的哈希
|
||||||
|
- 匹配 → 注入CDN,生成分发编码
|
||||||
|
- 不匹配 → 拒绝注入,告警退回播控平台
|
||||||
|
|
||||||
|
**Step 8:EPG发布与终端播放**
|
||||||
|
- 运营商EPG系统展示内容,用户点播
|
||||||
|
- 播放器SDK(或机顶盒固件)**支持可选的终端哈希抽检**:
|
||||||
|
- 下载片段后计算哈希
|
||||||
|
- 与链上哈希比对,防止CDN劫持或传输篡改
|
||||||
|
- (此步骤为增强安全,可根据网络负载策略性开启)
|
||||||
|
|
||||||
|
**Step 9:数据上报**
|
||||||
|
- 运营商上报播出数据时,以MA码为统一维度
|
||||||
|
- 可信数据空间聚合三方数据(CP播放量、播控审核量、运营商分发量),口径一致
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4.4 第四阶段:监管与应急
|
||||||
|
|
||||||
|
**Step 10:全生命周期监管**
|
||||||
|
- 广电总局/省局通过监管大屏,按MA码查询内容全链路状态:
|
||||||
|
- 当前在哪个播控平台
|
||||||
|
- 当前在哪个运营商CDN
|
||||||
|
- 当前哈希版本是否最新
|
||||||
|
- 历史版本变更记录
|
||||||
|
|
||||||
|
**Step 11:违规应急下架**
|
||||||
|
- 监管部门下发指令:"下架MA码(京)网微剧审字(2025)第XXX号"
|
||||||
|
- 可信数据空间解析MA码 → 查询所有绑定的三方编码
|
||||||
|
- 指令自动翻译为:
|
||||||
|
- 播控平台:下架审核流水号XXX
|
||||||
|
- 运营商:下架分发编码YYY、CDN资源ZZZ
|
||||||
|
- **秒级全网同步**,无需人工逐层翻译
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、数据模型与编码规范
|
||||||
|
|
||||||
|
### 5.1 可信数据空间核心表结构
|
||||||
|
|
||||||
|
```json
|
||||||
|
// 内容主表(Content Registry)
|
||||||
|
{
|
||||||
|
"ctid": "ctid-uuid-001",
|
||||||
|
"ma_code": "(京)网微剧审字(2025)第123号",
|
||||||
|
"ma_type": "重点网络微短剧",
|
||||||
|
"title": "示例剧集",
|
||||||
|
"episode_count": 24,
|
||||||
|
"status": "已发证",
|
||||||
|
"issue_date": "2025-06-01",
|
||||||
|
"issuer": "北京市广播电视局"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 哈希绑定表(Hash Binding)
|
||||||
|
{
|
||||||
|
"ctid": "ctid-uuid-001",
|
||||||
|
"hash_type": "file_sha256",
|
||||||
|
"hash_value": "a1b2c3d4e5f6...",
|
||||||
|
"file_format": "ProRes 422 HQ",
|
||||||
|
"resolution": "3840x2160",
|
||||||
|
"duration": 2700,
|
||||||
|
"version": "v1.0",
|
||||||
|
"merkle_root": "m1n2o3p4q5r6...",
|
||||||
|
"created_at": "2025-05-20T10:00:00Z",
|
||||||
|
"created_by": "CP-FS-MEDIA"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 三方编码映射表(Identity Mapping)
|
||||||
|
{
|
||||||
|
"ctid": "ctid-uuid-001",
|
||||||
|
"party": "cp",
|
||||||
|
"party_id": "FS-MEDIA-77821",
|
||||||
|
"party_name": "飞翮信息"
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"ctid": "ctid-uuid-001",
|
||||||
|
"party": "broadcast",
|
||||||
|
"party_id": "GD-2025-NS-004472",
|
||||||
|
"party_name": "广东IPTV播控"
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"ctid": "ctid-uuid-001",
|
||||||
|
"party": "operator",
|
||||||
|
"party_id": "CT-IPTV-20250612-008923",
|
||||||
|
"party_name": "中国电信广东"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 版本变更表(Version History)
|
||||||
|
{
|
||||||
|
"ctid": "ctid-uuid-001",
|
||||||
|
"version": "v2.0",
|
||||||
|
"change_reason": "片尾字幕修正",
|
||||||
|
"prev_hash": "a1b2c3d4...",
|
||||||
|
"new_hash": "b2c3d4e5...",
|
||||||
|
"reaudit_required": true,
|
||||||
|
"reaudit_status": "待审核"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.2 Merkle Tree分段设计(针对多集/长内容)
|
||||||
|
|
||||||
|
```
|
||||||
|
Root Hash
|
||||||
|
/ \
|
||||||
|
Hash(A) Hash(B)
|
||||||
|
/ \ / \
|
||||||
|
Hash(E1) Hash(E2) Hash(E3) Hash(E4)
|
||||||
|
|
||||||
|
E1=第1集, E2=第2集, E3=第3集, E4=第4集
|
||||||
|
```
|
||||||
|
|
||||||
|
- 单集被替换:只需重新计算该集哈希,Merkle Root变化,系统识别
|
||||||
|
- 精准定位:可定位到"第几集被篡改",无需全量重审
|
||||||
|
- 增量校验:终端播放时,可按集校验,降低计算负载
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 六、关键技术细节
|
||||||
|
|
||||||
|
### 6.1 哈希计算SDK(CP端集成)
|
||||||
|
|
||||||
|
```python
|
||||||
|
# 伪代码示例
|
||||||
|
import hashlib
|
||||||
|
from merkletools import MerkleTools
|
||||||
|
|
||||||
|
def compute_content_hash(file_path, segment_size=10*1024*1024):
|
||||||
|
# 分段计算
|
||||||
|
segments = []
|
||||||
|
with open(file_path, 'rb') as f:
|
||||||
|
while chunk := f.read(segment_size):
|
||||||
|
segments.append(hashlib.sha256(chunk).hexdigest())
|
||||||
|
|
||||||
|
# Merkle Tree
|
||||||
|
mt = MerkleTools(hash_type="sha256")
|
||||||
|
mt.add_leaf(segments)
|
||||||
|
mt.make_tree()
|
||||||
|
|
||||||
|
return {
|
||||||
|
"file_sha256": hashlib.sha256(open(file_path, 'rb').read()).hexdigest(),
|
||||||
|
"merkle_root": mt.get_merkle_root(),
|
||||||
|
"segment_hashes": segments,
|
||||||
|
"perceptual_hash": compute_phash(file_path) # 感知哈希
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.2 智能合约核心逻辑(可信数据空间)
|
||||||
|
|
||||||
|
```solidity
|
||||||
|
// 伪代码:Solidity风格
|
||||||
|
contract ContentRegistry {
|
||||||
|
|
||||||
|
mapping(string => Content) public contents; // MA码 => 内容
|
||||||
|
|
||||||
|
struct Content {
|
||||||
|
string maCode;
|
||||||
|
string merkleRoot;
|
||||||
|
string perceptualHash;
|
||||||
|
mapping(string => string) partyMappings; // 三方编码映射
|
||||||
|
bool isActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 仅监管节点可调用
|
||||||
|
function issueMA(string memory maCode, string memory merkleRoot) public {
|
||||||
|
require(isRegulator(msg.sender), "Only regulator");
|
||||||
|
contents[maCode] = Content(maCode, merkleRoot, "", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// CP/播控/运营商注册映射
|
||||||
|
function registerMapping(string memory maCode, string memory party, string memory partyId) public {
|
||||||
|
require(contents[maCode].isActive, "MA not issued");
|
||||||
|
contents[maCode].partyMappings[party] = partyId;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 哈希校验
|
||||||
|
function verifyHash(string memory maCode, string memory fileHash) public view returns (bool) {
|
||||||
|
return keccak256(abi.encodePacked(contents[maCode].merkleRoot))
|
||||||
|
== keccak256(abi.encodePacked(fileHash));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.3 转码版哈希处理
|
||||||
|
|
||||||
|
当内容需要多版本分发(4K/HD/SD)时:
|
||||||
|
- 授权转码中心执行转码后,计算新版本文件哈希
|
||||||
|
- 在可信数据空间中建立**父子关系**:
|
||||||
|
```
|
||||||
|
母版哈希(父)──┬── 转码版A哈希(H.265 4K)
|
||||||
|
├── 转码版B哈希(H.264 HD)
|
||||||
|
└── 转码版C哈希(H.264 SD)
|
||||||
|
```
|
||||||
|
- 所有转码版共享同一MA码,但各自有独立哈希记录
|
||||||
|
- 运营商注入任一版本时,校验对应版本哈希
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 七、接口规范(关键API)
|
||||||
|
|
||||||
|
### 7.1 哈希上链接口(CP调用)
|
||||||
|
|
||||||
|
```
|
||||||
|
POST /api/v1/content/register
|
||||||
|
Headers: Authorization: Bearer {cp_token}
|
||||||
|
|
||||||
|
Body:
|
||||||
|
{
|
||||||
|
"title": "示例剧集",
|
||||||
|
"episode_count": 24,
|
||||||
|
"file_hashes": [
|
||||||
|
{
|
||||||
|
"episode": 1,
|
||||||
|
"file_sha256": "a1b2...",
|
||||||
|
"merkle_root": "m1n2...",
|
||||||
|
"perceptual_hash": "p1q2...",
|
||||||
|
"duration": 2700,
|
||||||
|
"resolution": "3840x2160"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"cp_media_id": "FS-MEDIA-77821"
|
||||||
|
}
|
||||||
|
|
||||||
|
Response:
|
||||||
|
{
|
||||||
|
"review_id": "REV-2025-12345",
|
||||||
|
"status": "pending_review",
|
||||||
|
"message": "哈希已存证,请进入备案系统完成申报"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7.2 哈希验真接口(播控/运营商调用)
|
||||||
|
|
||||||
|
```
|
||||||
|
GET /api/v1/content/verify?ma_code={ma_code}&file_hash={hash}
|
||||||
|
|
||||||
|
Response:
|
||||||
|
{
|
||||||
|
"valid": true,
|
||||||
|
"ma_code": "(京)网微剧审字(2025)第123号",
|
||||||
|
"bound_hash": "a1b2...",
|
||||||
|
"submitted_hash": "a1b2...",
|
||||||
|
"match": true,
|
||||||
|
"version": "v1.0",
|
||||||
|
"transcoded_versions": [
|
||||||
|
{"format": "H.265 4K", "hash": "t1u2..."}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7.3 映射查询接口(应急下架)
|
||||||
|
|
||||||
|
```
|
||||||
|
GET /api/v1/content/mappings?ma_code={ma_code}
|
||||||
|
|
||||||
|
Response:
|
||||||
|
{
|
||||||
|
"ma_code": "(京)网微剧审字(2025)第123号",
|
||||||
|
"mappings": [
|
||||||
|
{"party": "cp", "party_id": "FS-MEDIA-77821"},
|
||||||
|
{"party": "broadcast", "party_id": "GD-2025-NS-004472"},
|
||||||
|
{"party": "operator", "party_id": "CT-IPTV-20250612-008923"}
|
||||||
|
],
|
||||||
|
"cdn_endpoints": [
|
||||||
|
"cdn://ct-gd/iptv/vod/008923"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 八、治理与运营机制
|
||||||
|
|
||||||
|
### 8.1 角色权限矩阵
|
||||||
|
|
||||||
|
| 角色 | 签发MA码 | 注册哈希 | 验真查询 | 映射管理 | 应急下架 |
|
||||||
|
|------|---------|---------|---------|---------|---------|
|
||||||
|
| 广电总局/省局 | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
|
| 播控平台 | ❌ | ❌ | ✅ | ✅(本方) | ❌(执行指令) |
|
||||||
|
| 运营商 | ❌ | ❌ | ✅ | ✅(本方) | ❌(执行指令) |
|
||||||
|
| CP | ❌ | ✅(送审时) | ✅(自查) | ✅(本方) | ❌ |
|
||||||
|
|
||||||
|
### 8.2 异常处理规则
|
||||||
|
|
||||||
|
| 异常场景 | 处理规则 |
|
||||||
|
|---------|---------|
|
||||||
|
| 哈希不匹配(送审) | 退回CP,要求说明版本差异,必要时重新送审 |
|
||||||
|
| 哈希不匹配(CDN注入) | 拒绝注入,告警播控平台,暂停该内容分发 |
|
||||||
|
| 哈希不匹配(终端抽检) | 断流并切换至备用源,上报异常日志 |
|
||||||
|
| 版本变更(剪辑/修改) | 必须重新计算哈希,提交变更申请,触发重新审核 |
|
||||||
|
| CP换壳重发(同一哈希) | 系统识别哈希已存在,拒绝重复申报,关联原MA码 |
|
||||||
|
|
||||||
|
### 8.3 跨省复用流程
|
||||||
|
|
||||||
|
```
|
||||||
|
A省过审取得MA码 + 哈希证书
|
||||||
|
↓
|
||||||
|
CP向B省播控平台送审,仅提交:
|
||||||
|
- MA码
|
||||||
|
- 哈希证书(无需重新提交内容文件)
|
||||||
|
↓
|
||||||
|
B省播控平台查询可信数据空间:
|
||||||
|
- 验证MA码真实有效
|
||||||
|
- 验证哈希与A省过审版一致
|
||||||
|
- 确认内容未在黑名单
|
||||||
|
↓
|
||||||
|
B省播控平台快速准入(内容审核可简化为合规性抽检)
|
||||||
|
- 生成B省审核流水号
|
||||||
|
- 注册映射关系
|
||||||
|
↓
|
||||||
|
进入B省运营商分发流程
|
||||||
|
```
|
||||||
|
|
||||||
|
**核心价值**:跨省复用从"重新走全流程"压缩为"验真+抽检",CP边际成本大幅下降。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 九、实施路径建议
|
||||||
|
|
||||||
|
| 阶段 | 周期 | 目标 | 关键动作 |
|
||||||
|
|------|------|------|---------|
|
||||||
|
| **一期:试点验证** | 3个月 | 单省单运营商跑通 | 选择广东/湖南等IPTV大省,对接1家CP、1家播控、1家运营商,完成微短剧品类全流程验证 |
|
||||||
|
| **二期:扩展覆盖** | 6个月 | 多省多运营商接入 | 扩展至3-5省,覆盖网络剧、网络电影,接入主流CP 10家以上 |
|
||||||
|
| **三期:全国贯通** | 12个月 | 全国IPTV统一接入 | 对接广电总局备案系统,成为全国IPTV内容准入的基础设施 |
|
||||||
|
| **四期:大小屏融合** | 18个月 | OTT/APP同步接入 | 将MA+哈希机制扩展至OTT、手机APP,实现大小屏内容身份互通 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 十、预期成效
|
||||||
|
|
||||||
|
| 指标 | 现状 | 目标 |
|
||||||
|
|------|------|------|
|
||||||
|
| 跨省复用审核周期 | 15-30天 | 3-5天(验真为主) |
|
||||||
|
| 违规内容下架响应 | 2-24小时 | 分钟级 |
|
||||||
|
| 内容版本替换识别 | 几乎无法识别 | 100%自动识别 |
|
||||||
|
| 三方数据对账差异 | 15-30% | <5% |
|
||||||
|
| CP重复录入成本 | 每省每运营商重复录入 | 一次录入,全网复用 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**总结**:这套方案的核心不是让三方放弃自己的系统,而是在三方系统之上建立一层**"可信身份映射层"**——用MA码解决"是谁"的监管问题,用哈希码解决"是不是"的技术问题,用可信数据空间解决"在哪"的溯源问题。三者叠加,IPTV内容才能真正实现"审过即锁定,锁定即通行,通行可追溯"。
|
||||||
@@ -0,0 +1,534 @@
|
|||||||
|
# MA 标识体系全流程与价值发挥详图 — 绘制描述
|
||||||
|
|
||||||
|
> 用途:向业务和技术专家阐述 MA 标识在 AIGC-Hub 中的全链路价值,说清楚"为什么非 MA 不可"
|
||||||
|
> 核心主题:MA 标识如何贯穿"创作→赋码→流通→结算→监管→跨境"六大环节,在每个环节发挥不可替代的价值
|
||||||
|
> 建议工具:Figma / draw.io / ProcessOn / PPT
|
||||||
|
> 画布方向:横版,主体为从左到右的全生命周期流 + 上方为 MA 节点层级 + 下方为价值输出层
|
||||||
|
> 建议尺寸:A1 横版 或 16:9 双屏
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、图的整体构图逻辑
|
||||||
|
|
||||||
|
采用 **"一条主河 + 一棵树 + 一张网"** 的三层视觉结构:
|
||||||
|
|
||||||
|
- **上层(树)**:MA 全球节点层级树(根→国家→行业→平台),展示编码体系的层级关系
|
||||||
|
- **中层(河)**:MA 标识在 AIGC 内容全生命周期中的流转主线(六大环节,从左到右)
|
||||||
|
- **下层(网)**:每个环节中 MA 标识输出的具体价值与受益方
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、上层:MA 全球节点层级树
|
||||||
|
|
||||||
|
### 绘制方式:自上而下的树状结构,横向铺开
|
||||||
|
|
||||||
|
```
|
||||||
|
位置:画布顶部 20% 区域
|
||||||
|
背景:深绿渐变,象征国际标准底色
|
||||||
|
标题:MA 全球统一标识代码体系 (ISO/IEC 15459)
|
||||||
|
|
||||||
|
┌──────────────┐
|
||||||
|
│ MA 全球根 │
|
||||||
|
│ (ZIIOT) │
|
||||||
|
│ 全球唯一发行 │
|
||||||
|
└──────┬───────┘
|
||||||
|
│
|
||||||
|
┌──────────────────┼──────────────────┐
|
||||||
|
│ │ │
|
||||||
|
┌───────▼──────┐ ┌───────▼──────┐ ┌───────▼──────┐
|
||||||
|
│ MA.156 │ │ MA.840 │ │ MA.392 │
|
||||||
|
│ 中国节点 │ │ 美国节点 │ │ 日本节点 │
|
||||||
|
└───────┬──────┘ └──────────────┘ └──────────────┘
|
||||||
|
│
|
||||||
|
┌─────────┼─────────────────────┐
|
||||||
|
│ │ │
|
||||||
|
┌───▼────┐ ┌──▼──────────┐ ┌──────▼──────┐
|
||||||
|
│MA.156 │ │MA.156.10005 │ │MA.156.xxxxx │
|
||||||
|
│.00001 │ │AIGC视听内容 │ │ 其他行业 │
|
||||||
|
│制造业 │ │行业节点 ★ │ │ │
|
||||||
|
└────────┘ │(广电云运营) │ └─────────────┘
|
||||||
|
└──────┬──────┘
|
||||||
|
│
|
||||||
|
┌─────────────┼──────────────────────────────┐
|
||||||
|
│ │ │ │
|
||||||
|
┌───▼────┐ ┌────▼────┐ ┌────▼────┐ ┌───────▼───────┐
|
||||||
|
│.10005 │ │.10005 │ │.10005 │ │.10005.xxxx │
|
||||||
|
│.8361 │ │.8362 │ │.8363 │ │ 更多平台/机构 │
|
||||||
|
│ 抖音 │ │ B站 │ │ 快手 │ │ AI工具/MCN │
|
||||||
|
└────────┘ └─────────┘ └─────────┘ └───────────────┘
|
||||||
|
|
||||||
|
标注说明:
|
||||||
|
★ MA.156.10005 = 拟申请的 AIGC 视听内容行业节点
|
||||||
|
· 全球唯一 · 不可伪造 · 层级解析 · 跨境互认
|
||||||
|
· 每个平台/机构获得唯一三级节点代码,纳入全球解析网络
|
||||||
|
|
||||||
|
右侧放置 AVCC 编码解剖图:
|
||||||
|
┌────────────────────────────────────────────────────────────────┐
|
||||||
|
│ MA.156.10005.8361 / 10.1300200.AIGC / (京)网微剧审字(2026) │
|
||||||
|
│ 第001号 - P - AI-HASH(a1b2c3) - CRD(0x7f3e9a) │
|
||||||
|
│ │
|
||||||
|
│ ┌──┐ ┌───┐ ┌─────┐ ┌────┐ ┌──────────┐ ┌─────┐ ┌─┐ ┌────┐ │
|
||||||
|
│ │MA│.│156│.│10005│.│8361│/│10.1300200│/│网标号│-│P│-│哈希│ │
|
||||||
|
│ └┬─┘ └─┬─┘ └──┬──┘ └─┬──┘ └────┬─────┘ └──┬──┘ └┬┘ └─┬──┘ │
|
||||||
|
│ │ │ │ │ │ │ │ │ │
|
||||||
|
│ 根 国家 行业 平台 类目 监管 级别 技术 │
|
||||||
|
│ 节点 节点 节点 节点 编码 许可 分类 溯源 │
|
||||||
|
│ │
|
||||||
|
│ 六段式结构 = 国际标识 + 国内监管 + 技术溯源 三合一 │
|
||||||
|
└────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、中层:MA 标识全生命周期流转主线(核心区域)
|
||||||
|
|
||||||
|
### 绘制方式:从左到右的六大环节,用河流/管道比喻,MA 标识如水流贯穿始终
|
||||||
|
|
||||||
|
```
|
||||||
|
位置:画布中部 50% 区域
|
||||||
|
背景:白底,每个环节用不同色块区分
|
||||||
|
主视觉:一条从左到右的流线,串联六个大节点
|
||||||
|
|
||||||
|
═══════════════════════════════════════════════════════════════════════════════
|
||||||
|
[创作源头] → [赋码登记] → [合规流通] → [消费分发] → [结算清算] → [监管治理]
|
||||||
|
═══════════════════════════════════════════════════════════════════════════════
|
||||||
|
```
|
||||||
|
|
||||||
|
### 环节 ①:创作源头 — MA 标识的"出生"
|
||||||
|
|
||||||
|
```
|
||||||
|
色块:浅紫色
|
||||||
|
图标:画笔/AI工具
|
||||||
|
|
||||||
|
┌─────────────────────────────────────────────────────────┐
|
||||||
|
│ ① 创作源头:MA 标识片段嵌入 │
|
||||||
|
│ │
|
||||||
|
│ 触发时机:AI工具(ComfyUI/可灵/Runway等)生成内容的瞬间 │
|
||||||
|
│ │
|
||||||
|
│ MA 做了什么: │
|
||||||
|
│ ┌─────────────────────────────────────────────────┐ │
|
||||||
|
│ │ C2PA SDK 自动将 MA 标识片段写入文件元数据 │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ ma.avcc.fragment = { │ │
|
||||||
|
│ │ platform_node: "8361", ← MA三级节点 │ │
|
||||||
|
│ │ object_category: "10.1300200.AIGC", │ │
|
||||||
|
│ │ model_name: "SD-XL", │ │
|
||||||
|
│ │ generation_timestamp: "2026-...", │ │
|
||||||
|
│ │ generation_log_hash: "a1b2c3..." │ │
|
||||||
|
│ │ } │ │
|
||||||
|
│ └─────────────────────────────────────────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ 价值: │
|
||||||
|
│ · 从"第一帧"就绑定了全球唯一标识(不是事后补登记) │
|
||||||
|
│ · 记录了"谁用什么工具在什么时候生成了什么" │
|
||||||
|
│ · C2PA国际标准 + MA中国标准 双重锚定 │
|
||||||
|
│ · 无论作品后续如何流转/复制,MA片段始终跟随 │
|
||||||
|
│ │
|
||||||
|
│ 参与方:AI工具厂商(通过SDK集成)· 创作者 │
|
||||||
|
└─────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 环节 ②:赋码登记 — MA 标识的"身份证签发"
|
||||||
|
|
||||||
|
```
|
||||||
|
色块:浅蓝色
|
||||||
|
图标:二维码/证书
|
||||||
|
|
||||||
|
┌─────────────────────────────────────────────────────────┐
|
||||||
|
│ ② 赋码登记:生成完整六段式 AVCC │
|
||||||
|
│ │
|
||||||
|
│ 触发时机:创作者通过工作台提交赋码申请 │
|
||||||
|
│ │
|
||||||
|
│ MA 做了什么: │
|
||||||
|
│ ┌─────────────────────────────────────────────────┐ │
|
||||||
|
│ │ Step 1: 验证创作者的 MA 三级节点归属 │ │
|
||||||
|
│ │ Step 2: 从 MA 行业节点(10005)码池分配唯一编码 │ │
|
||||||
|
│ │ Step 3: 拼装六段式 AVCC 完整编码 │ │
|
||||||
|
│ │ Step 4: 将 AVCC 注册到 MA 全球解析系统 │ │
|
||||||
|
│ │ Step 5: 签发 AVCC 证书(PDF + 二维码) │ │
|
||||||
|
│ └─────────────────────────────────────────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ MA 层级解析注册: │
|
||||||
|
│ ┌─────────────────────────────────────────────────┐ │
|
||||||
|
│ │ 广电云(行业节点) →→ ZIIOT(根节点) │ │
|
||||||
|
│ │ "我注册了一个新的 AVCC: MA.156.10005.8361/..." │ │
|
||||||
|
│ │ ZIIOT 更新全球解析索引 │ │
|
||||||
|
│ │ → 从此刻起,全球任何MA终端都能解析这个编码 │ │
|
||||||
|
│ └─────────────────────────────────────────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ 同时完成: │
|
||||||
|
│ · 版权链存证(AVCC + 内容哈希 + 权益方 → 上链) │
|
||||||
|
│ · P/G/O 分级标定(决定流通范围) │
|
||||||
|
│ │
|
||||||
|
│ 价值: │
|
||||||
|
│ · 全球唯一编码 ≠ 平台内部ID,不依赖任何单一平台 │
|
||||||
|
│ · 跨平台互认的基础 — 抖音、B站、快手看到同一个AVCC │
|
||||||
|
│ · 码资源有限性 → "编码权"即监管权力的体现 │
|
||||||
|
│ │
|
||||||
|
│ 参与方:广电云(赋码) · ZIIOT(根注册) · 创作者(申请) │
|
||||||
|
└─────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 环节 ③:合规流通 — MA 标识的"通行证"
|
||||||
|
|
||||||
|
```
|
||||||
|
色块:浅绿色
|
||||||
|
图标:盾牌/通行
|
||||||
|
|
||||||
|
┌─────────────────────────────────────────────────────────┐
|
||||||
|
│ ③ 合规流通:MA 网关解析 + 流通权限判定 │
|
||||||
|
│ │
|
||||||
|
│ 触发时机:平台准备上线/推荐某个AIGC内容时 │
|
||||||
|
│ │
|
||||||
|
│ MA 做了什么: │
|
||||||
|
│ ┌─────────────────────────────────────────────────┐ │
|
||||||
|
│ │ 平台调用 MA 网关: POST /api/v1/avcc/parse │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ 网关执行三级解析: │ │
|
||||||
|
│ │ 1. 本地解析(格式校验 + 签名验证) │ │
|
||||||
|
│ │ 2. 缓存查询(Redis TTL=1h) │ │
|
||||||
|
│ │ 3. 根解析验证(ZIIOT全球根,严格模式可选) │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ 返回结果: │ │
|
||||||
|
│ │ · valid: true/false │ │
|
||||||
|
│ │ · circulation_rights: { │ │
|
||||||
|
│ │ scope: "全网全平台首页推荐" (P类) │ │
|
||||||
|
│ │ scope: "平台内播放" (G类) │ │
|
||||||
|
│ │ scope: "限本平台" (O类) │ │
|
||||||
|
│ │ } │ │
|
||||||
|
│ │ · blacklist_check: passed/blocked │ │
|
||||||
|
│ │ · expiration_status: active/expired │ │
|
||||||
|
│ └─────────────────────────────────────────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ P/G/O 三级流通控制(MA解析权限映射): │
|
||||||
|
│ ┌──────────────────────────────────────────┐ │
|
||||||
|
│ │ P(重点):MA根+行业+平台 三级解析验证 │ │
|
||||||
|
│ │ → 全网全平台首页推荐 │ │
|
||||||
|
│ │ G(普通):MA行业+平台 二级解析 │ │
|
||||||
|
│ │ → 平台内播放,不上首页 │ │
|
||||||
|
│ │ O(其他):平台本地解析即可 │ │
|
||||||
|
│ │ → 限本平台/限免流 │ │
|
||||||
|
│ └──────────────────────────────────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ 价值: │
|
||||||
|
│ · 无码不流通 — AVCC 是 AIGC 内容的"上路证" │
|
||||||
|
│ · 分级管控粒度 — 重点内容严审严管,普通内容快速流转 │
|
||||||
|
│ · 跨平台统一校验 — 所有平台调同一个MA网关,标准一致 │
|
||||||
|
│ · 实时黑名单 — 一处吊销,全网秒级生效(根节点同步) │
|
||||||
|
│ · 万级QPS低延迟 — Go实现,P99<50ms,不影响用户体验 │
|
||||||
|
│ │
|
||||||
|
│ 参与方:各视听平台(调用方) · 广电云MA网关(校验) · ZIIOT │
|
||||||
|
└─────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 环节 ④:消费分发 — MA 标识的"消费凭证"
|
||||||
|
|
||||||
|
```
|
||||||
|
色块:浅橙色
|
||||||
|
图标:播放/购买
|
||||||
|
|
||||||
|
┌─────────────────────────────────────────────────────────┐
|
||||||
|
│ ④ 消费分发:跨平台权益确认 + 播放数据归因 │
|
||||||
|
│ │
|
||||||
|
│ 触发时机:用户在某平台购买/观看 AIGC 内容 │
|
||||||
|
│ │
|
||||||
|
│ MA 做了什么: │
|
||||||
|
│ ┌─────────────────────────────────────────────────┐ │
|
||||||
|
│ │ 场景A:跨平台权益验证 │ │
|
||||||
|
│ │ 用户在抖音(8361)购买了AVCC-X,去B站(8362)想看 │ │
|
||||||
|
│ │ B站调用: /api/v1/chain/user-rights/verify │ │
|
||||||
|
│ │ → 版权链验证购买记录 → 返回 valid:true │ │
|
||||||
|
│ │ → B站放行播放(无需二次付费) │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ 关键:AVCC 是跨平台的"统一钥匙", │ │
|
||||||
|
│ │ 平台内部UID不通,但AVCC+user_hash全网通用 │ │
|
||||||
|
│ └─────────────────────────────────────────────────┘ │
|
||||||
|
│ ┌─────────────────────────────────────────────────┐ │
|
||||||
|
│ │ 场景B:播放数据精准归因 │ │
|
||||||
|
│ │ 每次播放事件都绑定 AVCC 编码回传: │ │
|
||||||
|
│ │ {avcc: "MA.156.10005.8361/...", │ │
|
||||||
|
│ │ platform_node: "8362", ← 播放发生的平台 │ │
|
||||||
|
│ │ event_type: "play", │ │
|
||||||
|
│ │ duration_sec: 1800} │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ AVCC 让"一部作品在N个平台的播放数据" │ │
|
||||||
|
│ │ 可以精准汇总到同一个标识下 │ │
|
||||||
|
│ └─────────────────────────────────────────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ 价值: │
|
||||||
|
│ · "一次购买,全网通看" — 用户不再为同一内容重复付费 │
|
||||||
|
│ · 精准数据归因 — 无论在哪个平台播放,收益归属同一个AVCC │
|
||||||
|
│ · 打破平台数据孤岛 — MA编码让跨平台数据聚合成为可能 │
|
||||||
|
│ · 版权估值基础 — 全网播放数据汇总 → 版权真实价值可计算 │
|
||||||
|
│ │
|
||||||
|
│ 参与方:用户(消费) · 各平台(回传数据) · 广电云(聚合) │
|
||||||
|
└─────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 环节 ⑤:结算清算 — MA 标识的"分账凭据"
|
||||||
|
|
||||||
|
```
|
||||||
|
色块:浅金色
|
||||||
|
图标:金币/合约
|
||||||
|
|
||||||
|
┌─────────────────────────────────────────────────────────┐
|
||||||
|
│ ⑤ 结算清算:基于 AVCC 的智能合约自动分账 │
|
||||||
|
│ │
|
||||||
|
│ 触发时机:定期清算周期(日/周/月)到期 │
|
||||||
|
│ │
|
||||||
|
│ MA 做了什么: │
|
||||||
|
│ ┌─────────────────────────────────────────────────┐ │
|
||||||
|
│ │ 1. 清算引擎按 AVCC 从 ClickHouse 聚合全网收益: │ │
|
||||||
|
│ │ SELECT avcc_code, SUM(revenue) │ │
|
||||||
|
│ │ FROM playback_metrics │ │
|
||||||
|
│ │ WHERE period = '2026-05' │ │
|
||||||
|
│ │ GROUP BY avcc_code │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ 2. 查询 AVCC 绑定的权益方列表(链上合约): │ │
|
||||||
|
│ │ AVCC → CopyrightRecord.RightHolders: │ │
|
||||||
|
│ │ · creator(40%) · model(15%) │ │
|
||||||
|
│ │ · ip(10%) · platform(30%) │ │
|
||||||
|
│ │ · hub_fee(6%) │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ 3. 触发链上清算合约 ExecuteSettlement: │ │
|
||||||
|
│ │ → 按比例拆分 → 各方账户入账 │ │
|
||||||
|
│ │ → 生成不可篡改的清算记录 │ │
|
||||||
|
│ └─────────────────────────────────────────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ AVCC = 分账的"最小原子单位": │
|
||||||
|
│ ┌──────────────────────────────────────────┐ │
|
||||||
|
│ │ 传统模式: │ │
|
||||||
|
│ │ 平台A按自己规则分 · 平台B按自己规则分 │ │
|
||||||
|
│ │ → 创作者在不同平台分别对账,规则不透明 │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ AVCC模式: │ │
|
||||||
|
│ │ AVCC绑定统一分账合约 · 无论在哪个平台播放 │ │
|
||||||
|
│ │ → 同一智能合约执行 · 全网一本账 · 创作者 │ │
|
||||||
|
│ │ 只需看一个AVCC的总收益 │ │
|
||||||
|
│ └──────────────────────────────────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ 价值: │
|
||||||
|
│ · 跨平台统一清算 — 一个AVCC = 一份合约 = 所有平台通用 │
|
||||||
|
│ · 分账透明不可篡改 — 链上记录,创作者可审计 │
|
||||||
|
│ · 自动化无人工 — 智能合约按规则自动执行,无中间商 │
|
||||||
|
│ · 版权金融基础 — 链上清算记录 → 版权估值 → ABS/质押 │
|
||||||
|
│ │
|
||||||
|
│ 参与方:清算引擎 · 联盟链 · 创作者 · 模型方 · IP方 · 平台│
|
||||||
|
└─────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 环节 ⑥:监管治理 — MA 标识的"治理抓手"
|
||||||
|
|
||||||
|
```
|
||||||
|
色块:浅红色
|
||||||
|
图标:监管/法槌
|
||||||
|
|
||||||
|
┌─────────────────────────────────────────────────────────┐
|
||||||
|
│ ⑥ 监管治理:精准靶向 + 全网联动 │
|
||||||
|
│ │
|
||||||
|
│ 触发时机:监管需要处置/查询/统计时 │
|
||||||
|
│ │
|
||||||
|
│ MA 做了什么: │
|
||||||
|
│ ┌─────────────────────────────────────────────────┐ │
|
||||||
|
│ │ 场景A:精准定点处置 │ │
|
||||||
|
│ │ 广电总局发现某内容违规: │ │
|
||||||
|
│ │ → 下发 AVCC 编码到广电云 │ │
|
||||||
|
│ │ → 广电云执行: circulation_status = 'revoked' │ │
|
||||||
|
│ │ → MA网关缓存即时失效 │ │
|
||||||
|
│ │ → 同步 ZIIOT 根节点全球注销 │ │
|
||||||
|
│ │ → 所有平台下次解析该AVCC时返回 blacklisted │ │
|
||||||
|
│ │ → 全网下架,无死角 │ │
|
||||||
|
│ └─────────────────────────────────────────────────┘ │
|
||||||
|
│ ┌─────────────────────────────────────────────────┐ │
|
||||||
|
│ │ 场景B:穿透式溯源 │ │
|
||||||
|
│ │ 投诉/举报某内容 → 提取AVCC → 一键反查: │ │
|
||||||
|
│ │ · 谁生成的(creator_id + MA节点) │ │
|
||||||
|
│ │ · 用什么模型(C2PA中的model_name/version) │ │
|
||||||
|
│ │ · 训练数据是否合规(training_assertion) │ │
|
||||||
|
│ │ · 审核历史(review_reports全链路) │ │
|
||||||
|
│ │ · 流通轨迹(哪些平台上线过、播放量多少) │ │
|
||||||
|
│ │ · 收益明细(链上清算记录) │ │
|
||||||
|
│ └─────────────────────────────────────────────────┘ │
|
||||||
|
│ ┌─────────────────────────────────────────────────┐ │
|
||||||
|
│ │ 场景C:宏观数据治理 │ │
|
||||||
|
│ │ 因为所有AIGC内容都有统一的AVCC编码: │ │
|
||||||
|
│ │ → 行业总量可精确统计(年赋码量=行业产出量) │ │
|
||||||
|
│ │ → 平台合规率可比较(各平台P/G/O比例) │ │
|
||||||
|
│ │ → 模型风险可预警(某模型生成内容违规率高) │ │
|
||||||
|
│ │ → 产业趋势可预判(类目/地域/创作者分布) │ │
|
||||||
|
│ └─────────────────────────────────────────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ MA的独特价值(vs 平台内部ID): │
|
||||||
|
│ ┌──────────────────────────────────────────┐ │
|
||||||
|
│ │ · 跨平台穿透:一个AVCC串联所有平台数据 │ │
|
||||||
|
│ │ · 全网联动:根节点注销 = 全球失效 │ │
|
||||||
|
│ │ · 不可伪造:MA层级签名,无法自行编造 │ │
|
||||||
|
│ │ · 国际互认:ZIIOT全球根,跨境执法可协作 │ │
|
||||||
|
│ └──────────────────────────────────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ 参与方:广电总局(决策) · 广电云(执行) · ZIIOT(全球同步) │
|
||||||
|
└─────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、附加环节:跨境互认 — MA 标识的"国际护照"
|
||||||
|
|
||||||
|
```
|
||||||
|
色块:浅蓝紫色(国际色调)
|
||||||
|
位置:主流程右侧延伸
|
||||||
|
|
||||||
|
┌─────────────────────────────────────────────────────────┐
|
||||||
|
│ ⑦ 跨境互认:MA 标识的国际化价值 │
|
||||||
|
│ │
|
||||||
|
│ ┌─────────────────────────────────────────────────┐ │
|
||||||
|
│ │ 中国 AIGC 作品出海流程: │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ 创作者(中国) → AVCC(MA.156.10005.8361/...) │ │
|
||||||
|
│ │ │ │ │
|
||||||
|
│ │ ▼ MA根解析全球可达 │ │
|
||||||
|
│ │ 海外平台 → 调用 MA 根解析 │ │
|
||||||
|
│ │ │ │ │
|
||||||
|
│ │ ▼ 验证通过 │ │
|
||||||
|
│ │ 海外平台合规上线 │ │
|
||||||
|
│ │ │ │ │
|
||||||
|
│ │ ▼ 播放数据回传 │ │
|
||||||
|
│ │ 智能合约跨境清算 │ │
|
||||||
|
│ └─────────────────────────────────────────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ vs 没有 MA 的情况: │
|
||||||
|
│ · 海外平台无法验证中国内容合规性 │
|
||||||
|
│ · 跨境版权纠纷无统一标识可引用 │
|
||||||
|
│ · 跨境分账无链上依据 │
|
||||||
|
│ │
|
||||||
|
│ MA 给出的解: │
|
||||||
|
│ · ISO/IEC 15459 国际标准 → 海外平台天然认可 │
|
||||||
|
│ · ZIIOT全球根 → 任何国家的MA终端都能解析 │
|
||||||
|
│ · 链上记录 → 跨境版权仲裁有链上证据 │
|
||||||
|
│ │
|
||||||
|
│ 战略意义:中国AIGC产业的"国际话语权"基础设施 │
|
||||||
|
└─────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、下层:MA 标识在每个环节的价值输出矩阵
|
||||||
|
|
||||||
|
### 绘制方式:横向表格,与上方六大环节一一对齐
|
||||||
|
|
||||||
|
```
|
||||||
|
位置:画布底部 20% 区域
|
||||||
|
背景:浅灰
|
||||||
|
|
||||||
|
┌──────────┬──────────┬──────────┬──────────┬──────────┬──────────┐
|
||||||
|
│ 创作源头 │ 赋码登记 │ 合规流通 │ 消费分发 │ 结算清算 │ 监管治理 │
|
||||||
|
├──────────┼──────────┼──────────┼──────────┼──────────┼──────────┤
|
||||||
|
│ │ │ │ │ │ │
|
||||||
|
│ 对创作者 │ 对创作者 │ 对平台 │ 对用户 │ 对创作者 │ 对监管 │
|
||||||
|
│ 源头确权 │ 全球身份 │ 一键合规 │ 一购全看 │ 透明分账 │ 精准治理 │
|
||||||
|
│ 防止抄袭 │ 版权锚定 │ 降70%成本│ 跨平台通兑│ 自动结算 │ 秒级下架 │
|
||||||
|
│ │ │ │ │ │ │
|
||||||
|
├──────────┼──────────┼──────────┼──────────┼──────────┼──────────┤
|
||||||
|
│ 对AI工具 │ 对广电云 │ 对ZIIOT │ 对平台 │ 对模型方 │ 对产业 │
|
||||||
|
│ 白名单认证│ 编码权变现│ 标准落地 │ 数据互通 │ 分成保障 │ 数据沉淀 │
|
||||||
|
│ 合规背书 │ 码即门票 │ 国际影响力│ 流量精算 │ 贡献可量化│ 趋势可判 │
|
||||||
|
│ │ │ │ │ │ │
|
||||||
|
├──────────┼──────────┼──────────┼──────────┼──────────┼──────────┤
|
||||||
|
│ │ │ │ │ │ │
|
||||||
|
│ MA价值 │ MA价值 │ MA价值 │ MA价值 │ MA价值 │ MA价值 │
|
||||||
|
│ 全球唯一 │ 层级编码 │ 实时解析 │ 统一标识 │ 链上锚定 │ 穿透溯源 │
|
||||||
|
│ 不可伪造 │ 码资源管理│ 权限映射 │ 跨平台桥梁│ 分账凭据 │ 全网联动 │
|
||||||
|
│ │ │ │ │ │ │
|
||||||
|
└──────────┴──────────┴──────────┴──────────┴──────────┴──────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 六、核心对比:有 MA vs 没有 MA
|
||||||
|
|
||||||
|
### 绘制方式:左右对比表,红绿色调
|
||||||
|
|
||||||
|
```
|
||||||
|
位置:可作为图的独立插图区域或翻页附录
|
||||||
|
|
||||||
|
┌────────────────────────────┬────────────────────────────────────┐
|
||||||
|
│ ❌ 没有 MA 标识 │ ✅ 有 MA 标识 │
|
||||||
|
├────────────────────────────┼────────────────────────────────────┤
|
||||||
|
│ 各平台自编ID,互不认识 │ 全球唯一AVCC,所有平台统一解析 │
|
||||||
|
│ 跨平台侵权无法追踪 │ 一码串联全网流转轨迹 │
|
||||||
|
│ 用户重复付费(每个平台买一次)│ 一次购买,链上确权,全网通看 │
|
||||||
|
│ 分账靠平台自觉,不透明 │ 智能合约自动执行,链上可审计 │
|
||||||
|
│ 监管只能逐平台下发通知 │ 根节点一次注销,全球秒级失效 │
|
||||||
|
│ 出海无标准,海外无法验证 │ ISO标准+全球根解析,国际互认 │
|
||||||
|
│ 数据孤岛,行业无全景统计 │ AVCC维度聚合,产业全景可视 │
|
||||||
|
│ 版权价值无法跨平台评估 │ 全网数据→版权估值→金融衍生 │
|
||||||
|
├────────────────────────────┼────────────────────────────────────┤
|
||||||
|
│ 本质:每个平台是一座"孤岛" │ 本质:MA是连接所有孤岛的"桥梁" │
|
||||||
|
└────────────────────────────┴────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 七、MA 标识的三大"不可替代性"总结
|
||||||
|
|
||||||
|
```
|
||||||
|
位置:画布右上角或底部,金色强调框
|
||||||
|
|
||||||
|
┌─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ │
|
||||||
|
│ MA 标识的三大不可替代性 │
|
||||||
|
│ │
|
||||||
|
│ ① 国际标准唯一性 (ISO/IEC 15459) │
|
||||||
|
│ · 不是企业标准,是国际标准 │
|
||||||
|
│ · ZIIOT是全球唯一的MA代码发行机构 │
|
||||||
|
│ · 任何其他体系无法提供同等国际认可度 │
|
||||||
|
│ │
|
||||||
|
│ ② 层级解析网络性 │
|
||||||
|
│ · 根→国家→行业→平台 四级树状结构 │
|
||||||
|
│ · 任何一级都可以独立解析本级下属编码 │
|
||||||
|
│ · 天然支撑"监管分层" — 总局管行业节点,行业节点管平台 │
|
||||||
|
│ │
|
||||||
|
│ ③ 全球互操作性 │
|
||||||
|
│ · 跨境文化贸易需要全球可解析的标识 │
|
||||||
|
│ · MA根节点全球部署,解析延迟<100ms │
|
||||||
|
│ · 中国AIGC产业国际化的"通行证" │
|
||||||
|
│ │
|
||||||
|
│ 结论:MA 不是"可选项",而是 AIGC-Hub 整个体系的"地基" │
|
||||||
|
│ 没有 MA = 没有跨平台 = 没有国际互认 = 没有监管穿透力 │
|
||||||
|
│ │
|
||||||
|
└─────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 八、视觉设计建议
|
||||||
|
|
||||||
|
| 元素 | 建议 |
|
||||||
|
|------|------|
|
||||||
|
| 主色调 | 以深绿(MA/国际标准色)为主色,六个环节各有辅色 |
|
||||||
|
| 流线样式 | 粗实线贯穿六环节,MA标识用金色高亮标记在流线上 |
|
||||||
|
| 节点树 | 上方树形用圆角矩形+连接线,当前节点(10005)用金色描边 |
|
||||||
|
| AVCC编码 | 用等宽字体,每段用不同颜色高亮,类似语法高亮 |
|
||||||
|
| 对比表 | 红/绿双色对比,直观感受"有vs没有"的巨大差距 |
|
||||||
|
| 参与方图标 | 每个环节底部小头像图标:创作者/平台/监管/ZIIOT/广电云 |
|
||||||
|
| 信息层次 | 业务看流程线+价值框 · 技术看API调用+数据结构 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 九、讲解要点备注(给演讲者)
|
||||||
|
|
||||||
|
1. **开场切入**:"这个体系的基石不是某个技术组件,而是 MA 国际标识。如果把 AIGC-Hub 比作高速公路,MA 就是车牌系统 — 没有车牌,交通管理就是空谈。"
|
||||||
|
|
||||||
|
2. **环节①强调**:"MA 标识不是事后补登记,而是在 AI 生成的第一帧就植入了。这是源头治理,不是事后追溯。"
|
||||||
|
|
||||||
|
3. **环节③强调**:"所有平台调同一个 MA 网关 — 这意味着规则统一。不存在'A平台认为合规、B平台认为违规'的情况。"
|
||||||
|
|
||||||
|
4. **环节⑤强调**:"传统模式下,创作者要在每个平台分别查分账。AVCC 模式下,一个编码 = 一份合约 = 全网一本账。"
|
||||||
|
|
||||||
|
5. **结束总结**:"MA 给了 AIGC-Hub 三样东西:国际标准的合法性、跨平台互通的可能性、监管穿透的技术性。缺了 MA,这个系统就是又一个平台级产品;有了 MA,这是国家级基础设施。"
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> 本文档是 MA 标识全流程价值专题详图的绘制蓝图。
|
||||||
|
> 与全景图和技术详图的区别:聚焦回答一个问题 —— "MA 标识到底在整个体系中做了什么、为什么不可替代"。
|
||||||
|
> 适合在下午讨论中,当业务专家问"为什么要用 MA 而不是自建编码体系"时展示。
|
||||||
@@ -0,0 +1,412 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1700 2050" font-family="'PingFang SC','Microsoft YaHei','Helvetica Neue',sans-serif">
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="regGrad" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||||
|
<stop offset="0%" style="stop-color:#b71c1c"/>
|
||||||
|
<stop offset="100%" style="stop-color:#c62828"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="chainGrad" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||||
|
<stop offset="0%" style="stop-color:#1a237e"/>
|
||||||
|
<stop offset="100%" style="stop-color:#311b92"/>
|
||||||
|
</linearGradient>
|
||||||
|
<marker id="arrow" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto" markerUnits="strokeWidth">
|
||||||
|
<path d="M0,0 L8,3 L0,6 Z" fill="#455a64"/>
|
||||||
|
</marker>
|
||||||
|
<marker id="arrowRed" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto" markerUnits="strokeWidth">
|
||||||
|
<path d="M0,0 L8,3 L0,6 Z" fill="#c62828"/>
|
||||||
|
</marker>
|
||||||
|
<marker id="arrowBlue" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto" markerUnits="strokeWidth">
|
||||||
|
<path d="M0,0 L8,3 L0,6 Z" fill="#1565c0"/>
|
||||||
|
</marker>
|
||||||
|
<marker id="arrowGreen" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto" markerUnits="strokeWidth">
|
||||||
|
<path d="M0,0 L8,3 L0,6 Z" fill="#2e7d32"/>
|
||||||
|
</marker>
|
||||||
|
</defs>
|
||||||
|
|
||||||
|
<!-- 标题 -->
|
||||||
|
<rect x="0" y="0" width="1700" height="78" fill="url(#chainGrad)"/>
|
||||||
|
<text x="850" y="34" text-anchor="middle" fill="white" font-size="23" font-weight="bold">TCS-IPTV 内容可信锁定系统 · 总体线框图</text>
|
||||||
|
<text x="850" y="60" text-anchor="middle" fill="#b3c5ff" font-size="13">MA码(监管身份)+ 哈希码(技术指纹)双锚定 · 不替代现有系统,在三方之上建立"可信身份映射层"</text>
|
||||||
|
|
||||||
|
<!-- ============ 监管层 ============ -->
|
||||||
|
<rect x="40" y="100" width="1620" height="150" rx="10" fill="#fff5f5" stroke="#c62828" stroke-width="2"/>
|
||||||
|
<rect x="40" y="100" width="1620" height="34" rx="10" fill="url(#regGrad)"/>
|
||||||
|
<text x="60" y="123" fill="white" font-size="15" font-weight="bold">① 监管侧 — 广电总局 / 省级广电局(监管主键签发方 · 价值核心)</text>
|
||||||
|
<text x="1640" y="123" text-anchor="end" fill="#ffcdd2" font-size="11">★ 唯一拥有 MA码签发权 与 应急下架权</text>
|
||||||
|
|
||||||
|
<!-- 监管子系统 -->
|
||||||
|
<g>
|
||||||
|
<rect x="70" y="148" width="280" height="88" rx="6" fill="white" stroke="#c62828" stroke-width="1.2"/>
|
||||||
|
<text x="210" y="170" text-anchor="middle" font-size="12" font-weight="bold" fill="#b71c1c">网络剧片发行许可证系统</text>
|
||||||
|
<text x="210" y="190" text-anchor="middle" font-size="10" fill="#555">(已有系统)</text>
|
||||||
|
<text x="210" y="210" text-anchor="middle" font-size="10" fill="#777">签发网标号 / 行政许可</text>
|
||||||
|
<text x="210" y="226" text-anchor="middle" font-size="10" fill="#777">网络剧·微短剧·网络电影</text>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<rect x="370" y="148" width="280" height="88" rx="6" fill="white" stroke="#c62828" stroke-width="1.2"/>
|
||||||
|
<text x="510" y="170" text-anchor="middle" font-size="12" font-weight="bold" fill="#b71c1c">重点网络影视剧备案系统</text>
|
||||||
|
<text x="510" y="190" text-anchor="middle" font-size="10" fill="#555">(已有系统)</text>
|
||||||
|
<text x="510" y="210" text-anchor="middle" font-size="10" fill="#777">节目备案 / 送审申报</text>
|
||||||
|
<text x="510" y="226" text-anchor="middle" font-size="10" fill="#777">返回送审流水号</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- 新建: MA签发与监管大屏 -->
|
||||||
|
<g>
|
||||||
|
<rect x="700" y="148" width="290" height="88" rx="6" fill="#ffebee" stroke="#c62828" stroke-width="2" stroke-dasharray="5,3"/>
|
||||||
|
<text x="845" y="168" text-anchor="middle" font-size="12" font-weight="bold" fill="#b71c1c">★ MA码签发引擎(新建)</text>
|
||||||
|
<text x="845" y="187" text-anchor="middle" font-size="10" fill="#555">审核通过 → 签发MA码</text>
|
||||||
|
<text x="845" y="203" text-anchor="middle" font-size="10" fill="#555">MA码 ↔ 哈希包 强绑定上链</text>
|
||||||
|
<text x="845" y="222" text-anchor="middle" font-size="10" fill="#c62828">仅监管节点可调用 issueMA()</text>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<rect x="1010" y="148" width="290" height="88" rx="6" fill="#ffebee" stroke="#c62828" stroke-width="2" stroke-dasharray="5,3"/>
|
||||||
|
<text x="1155" y="168" text-anchor="middle" font-size="12" font-weight="bold" fill="#b71c1c">★ 全生命周期监管大屏(新建)</text>
|
||||||
|
<text x="1155" y="187" text-anchor="middle" font-size="10" fill="#555">按MA码查全链路状态</text>
|
||||||
|
<text x="1155" y="203" text-anchor="middle" font-size="10" fill="#555">在哪个播控/CDN/哈希版本</text>
|
||||||
|
<text x="1155" y="222" text-anchor="middle" font-size="10" fill="#555">历史版本变更追溯</text>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<rect x="1320" y="148" width="320" height="88" rx="6" fill="#ffebee" stroke="#c62828" stroke-width="2" stroke-dasharray="5,3"/>
|
||||||
|
<text x="1480" y="168" text-anchor="middle" font-size="12" font-weight="bold" fill="#b71c1c">★ 违规应急下架指挥台(新建)</text>
|
||||||
|
<text x="1480" y="187" text-anchor="middle" font-size="10" fill="#555">下发:下架 MA码 第XXX号</text>
|
||||||
|
<text x="1480" y="203" text-anchor="middle" font-size="10" fill="#555">自动翻译为三方编码指令</text>
|
||||||
|
<text x="1480" y="222" text-anchor="middle" font-size="10" fill="#c62828">秒级全网同步,无需逐层人工</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- 监管 → 可信空间 签发MA码 箭头 -->
|
||||||
|
<line x1="845" y1="236" x2="845" y2="300" stroke="#c62828" stroke-width="2.5" marker-end="url(#arrowRed)"/>
|
||||||
|
<text x="855" y="272" font-size="11" font-weight="bold" fill="#c62828">签发MA码 + 绑定哈希</text>
|
||||||
|
|
||||||
|
<!-- 应急下架 → 可信空间 -->
|
||||||
|
<line x1="1480" y1="236" x2="1480" y2="300" stroke="#c62828" stroke-width="2.5" stroke-dasharray="6,3" marker-end="url(#arrowRed)"/>
|
||||||
|
<text x="1340" y="272" font-size="11" font-weight="bold" fill="#c62828">下架指令解析</text>
|
||||||
|
|
||||||
|
<!-- ============ 可信数据空间(核心枢纽) ============ -->
|
||||||
|
<rect x="40" y="300" width="1620" height="200" rx="10" fill="#ede7f6" stroke="#311b92" stroke-width="2.5"/>
|
||||||
|
<rect x="40" y="300" width="1620" height="34" rx="10" fill="url(#chainGrad)"/>
|
||||||
|
<text x="60" y="323" fill="white" font-size="15" font-weight="bold">② 可信数据空间(联盟链 / 分布式账本)— 三方之上的"可信身份映射层"(新建核心)</text>
|
||||||
|
<text x="1640" y="323" text-anchor="end" fill="#b3c5ff" font-size="11">智能合约 · Merkle Tree存储 · 跨方一致口径</text>
|
||||||
|
|
||||||
|
<!-- CTID 核心模型 -->
|
||||||
|
<g>
|
||||||
|
<rect x="70" y="348" width="340" height="138" rx="6" fill="white" stroke="#311b92" stroke-width="1.5"/>
|
||||||
|
<text x="240" y="370" text-anchor="middle" font-size="12" font-weight="bold" fill="#311b92">Content Twin ID (CTID)</text>
|
||||||
|
<line x1="90" y1="378" x2="390" y2="378" stroke="#d1c4e9"/>
|
||||||
|
<text x="90" y="398" font-size="10" fill="#444">ma_code: (京)网微剧审字第XXX号</text>
|
||||||
|
<text x="90" y="418" font-size="10" fill="#444">content_hash: sha256:a1b2c3d4...</text>
|
||||||
|
<text x="90" y="438" font-size="10" fill="#444">version: v1.0</text>
|
||||||
|
<text x="90" y="458" font-size="10" fill="#444">merkle_root: sha256:xyz789...</text>
|
||||||
|
<text x="90" y="478" font-size="9" fill="#c62828">监管锚点 + 技术锚点 1:1 强绑定不可解绑</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- 双哈希机制 -->
|
||||||
|
<g>
|
||||||
|
<rect x="430" y="348" width="300" height="138" rx="6" fill="white" stroke="#311b92" stroke-width="1.5"/>
|
||||||
|
<text x="580" y="370" text-anchor="middle" font-size="12" font-weight="bold" fill="#311b92">双哈希机制</text>
|
||||||
|
<line x1="450" y1="378" x2="710" y2="378" stroke="#d1c4e9"/>
|
||||||
|
<text x="450" y="398" font-size="10" fill="#444" font-weight="bold">文件哈希 (SHA-256)</text>
|
||||||
|
<text x="450" y="414" font-size="9" fill="#777">比特级敏感,锁定某版本,审核准入</text>
|
||||||
|
<text x="450" y="438" font-size="10" fill="#444" font-weight="bold">感知哈希 (aHash/dHash/pHash)</text>
|
||||||
|
<text x="450" y="454" font-size="9" fill="#777">容忍转码压缩,跨版本识别同一内容</text>
|
||||||
|
<text x="450" y="478" font-size="9" fill="#c62828">换壳重发 → 哈希已存在 → 自动识别</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- 三方编码映射表 -->
|
||||||
|
<g>
|
||||||
|
<rect x="750" y="348" width="430" height="138" rx="6" fill="white" stroke="#311b92" stroke-width="1.5"/>
|
||||||
|
<text x="965" y="370" text-anchor="middle" font-size="12" font-weight="bold" fill="#311b92">三方编码映射表(Identity Mapping)</text>
|
||||||
|
<line x1="770" y1="378" x2="1160" y2="378" stroke="#d1c4e9"/>
|
||||||
|
<text x="770" y="400" font-size="10" fill="#444">CP编码 FS-MEDIA-77821 ┐</text>
|
||||||
|
<text x="770" y="422" font-size="10" fill="#444">播控编码 GD-2025-NS-004472 ├─ ↔ MA码</text>
|
||||||
|
<text x="770" y="444" font-size="10" fill="#444">运营商编码 CT-IPTV-...008923 ┘</text>
|
||||||
|
<text x="770" y="468" font-size="9" fill="#777">一个MA码解析出全部三方编码 + CDN端点</text>
|
||||||
|
<text x="770" y="481" font-size="9" fill="#2e7d32">→ 应急下架时一键定位全网资源</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- 版本变更 + 智能合约 -->
|
||||||
|
<g>
|
||||||
|
<rect x="1200" y="348" width="440" height="138" rx="6" fill="white" stroke="#311b92" stroke-width="1.5"/>
|
||||||
|
<text x="1420" y="370" text-anchor="middle" font-size="12" font-weight="bold" fill="#311b92">智能合约 + 版本变更表</text>
|
||||||
|
<line x1="1220" y1="378" x2="1620" y2="378" stroke="#d1c4e9"/>
|
||||||
|
<text x="1220" y="398" font-size="10" fill="#444">issueMA() — 仅监管节点</text>
|
||||||
|
<text x="1220" y="416" font-size="10" fill="#444">registerMapping() — 三方注册编码</text>
|
||||||
|
<text x="1220" y="434" font-size="10" fill="#444">verifyHash() — 哈希校验</text>
|
||||||
|
<text x="1220" y="456" font-size="10" fill="#444">版本变更 → 哈希变化 → 绑定断裂</text>
|
||||||
|
<text x="1220" y="472" font-size="9" fill="#c62828">→ reaudit_required=true 触发重审</text>
|
||||||
|
<text x="1220" y="485" font-size="9" fill="#777">Merkle Tree 定位"第几集被篡改"</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- ============ 三方业务系统 ============ -->
|
||||||
|
<text x="40" y="540" font-size="16" font-weight="bold" fill="#1a237e">③ 三方业务系统 — 保留自有系统,关键节点最小侵入嵌入哈希校验</text>
|
||||||
|
|
||||||
|
<!-- CP端 -->
|
||||||
|
<rect x="40" y="560" width="520" height="380" rx="10" fill="#e8f5e9" stroke="#2e7d32" stroke-width="2"/>
|
||||||
|
<rect x="40" y="560" width="520" height="32" rx="10" fill="#2e7d32"/>
|
||||||
|
<text x="300" y="582" text-anchor="middle" fill="white" font-size="14" font-weight="bold">CP端(内容供应商)</text>
|
||||||
|
|
||||||
|
<!-- CP 已有系统 -->
|
||||||
|
<g>
|
||||||
|
<rect x="70" y="610" width="220" height="80" rx="6" fill="white" stroke="#2e7d32"/>
|
||||||
|
<text x="180" y="632" text-anchor="middle" font-size="11" font-weight="bold" fill="#1b5e20">媒资生产系统</text>
|
||||||
|
<text x="180" y="650" text-anchor="middle" font-size="9" fill="#555">(已有系统)</text>
|
||||||
|
<text x="180" y="668" text-anchor="middle" font-size="9" fill="#777">保留CP自有编码体系</text>
|
||||||
|
<text x="180" y="683" text-anchor="middle" font-size="9" fill="#777">母版 ProRes/DPX 制作</text>
|
||||||
|
</g>
|
||||||
|
<!-- CP 新建 SDK -->
|
||||||
|
<g>
|
||||||
|
<rect x="310" y="610" width="220" height="80" rx="6" fill="#c8e6c9" stroke="#2e7d32" stroke-width="2" stroke-dasharray="5,3"/>
|
||||||
|
<text x="420" y="632" text-anchor="middle" font-size="11" font-weight="bold" fill="#1b5e20">★ 哈希计算SDK(新建)</text>
|
||||||
|
<text x="420" y="650" text-anchor="middle" font-size="9" fill="#555">母版本地计算哈希</text>
|
||||||
|
<text x="420" y="666" text-anchor="middle" font-size="9" fill="#555">分段Merkle Tree + 感知哈希</text>
|
||||||
|
<text x="420" y="682" text-anchor="middle" font-size="9" fill="#c62828">仅上传哈希,不传原文件</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- CP 流程步骤 -->
|
||||||
|
<g font-size="10" fill="#333">
|
||||||
|
<rect x="70" y="710" width="460" height="210" rx="6" fill="#f1f8e9" stroke="#a5d6a7"/>
|
||||||
|
<text x="300" y="732" text-anchor="middle" font-size="11" font-weight="bold" fill="#1b5e20">CP全流程(生产与送审)</text>
|
||||||
|
<text x="90" y="758">Step1 母版哈希生成:全文件SHA-256 + 分段哈希 + 感知哈希</text>
|
||||||
|
<text x="90" y="784">Step2 送审申报:登录备案系统,上传哈希值包(不传原文件)</text>
|
||||||
|
<text x="110" y="804" fill="#777">片花/海报/剧本 + Merkle Tree根哈希 → 返回送审流水号</text>
|
||||||
|
<text x="90" y="830">Step3 审核通过:省级/总局签发MA码,MA码↔哈希包上链</text>
|
||||||
|
<text x="110" y="850" fill="#777">CP获"MA码+哈希证书",方可进入播控平台</text>
|
||||||
|
<text x="90" y="882" fill="#2e7d32" font-weight="bold">权限:注册哈希(送审时) · 验真自查 · 管理本方映射</text>
|
||||||
|
<text x="90" y="904" fill="#c62828">换壳重发:同哈希已存在 → 拒绝重复申报,关联原MA码</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- 播控平台端 -->
|
||||||
|
<rect x="590" y="560" width="520" height="380" rx="10" fill="#e3f2fd" stroke="#1565c0" stroke-width="2"/>
|
||||||
|
<rect x="590" y="560" width="520" height="32" rx="10" fill="#1565c0"/>
|
||||||
|
<text x="850" y="582" text-anchor="middle" fill="white" font-size="14" font-weight="bold">播控平台端(集成播控)</text>
|
||||||
|
|
||||||
|
<g>
|
||||||
|
<rect x="620" y="610" width="220" height="80" rx="6" fill="white" stroke="#1565c0"/>
|
||||||
|
<text x="730" y="632" text-anchor="middle" font-size="11" font-weight="bold" fill="#0d47a1">内容审核系统 + EPG</text>
|
||||||
|
<text x="730" y="650" text-anchor="middle" font-size="9" fill="#555">(已有系统)</text>
|
||||||
|
<text x="730" y="668" text-anchor="middle" font-size="9" fill="#777">保留自有审核流水号</text>
|
||||||
|
<text x="730" y="683" text-anchor="middle" font-size="9" fill="#777">合规审核 / EPG编排</text>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<rect x="860" y="610" width="220" height="80" rx="6" fill="#bbdefb" stroke="#1565c0" stroke-width="2" stroke-dasharray="5,3"/>
|
||||||
|
<text x="970" y="632" text-anchor="middle" font-size="11" font-weight="bold" fill="#0d47a1">★ 验真+映射模块(新建)</text>
|
||||||
|
<text x="970" y="650" text-anchor="middle" font-size="9" fill="#555">送审文件哈希验真</text>
|
||||||
|
<text x="970" y="666" text-anchor="middle" font-size="9" fill="#555">转码版哈希绑定</text>
|
||||||
|
<text x="970" y="682" text-anchor="middle" font-size="9" fill="#555">建立播控流水号↔MA码映射</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<g font-size="10" fill="#333">
|
||||||
|
<rect x="620" y="710" width="460" height="210" rx="6" fill="#e1f5fe" stroke="#90caf9"/>
|
||||||
|
<text x="850" y="732" text-anchor="middle" font-size="11" font-weight="bold" fill="#0d47a1">播控全流程(审核与入库)</text>
|
||||||
|
<text x="640" y="758">Step4 送审验真:计算送审文件哈希,查询可信空间</text>
|
||||||
|
<text x="660" y="778" fill="#2e7d32">匹配 → 正版过审内容,进入审核</text>
|
||||||
|
<text x="660" y="796" fill="#c62828">不匹配 → 直接退回,标记"疑似版本替换"</text>
|
||||||
|
<text x="640" y="822">Step5 审核+转码:授权转码中心转码,重算各版本哈希</text>
|
||||||
|
<text x="660" y="842" fill="#777">母版哈希与转码版建立父子关系上链</text>
|
||||||
|
<text x="640" y="868">Step6 EPG编排:建立 播控流水号↔MA码↔哈希 映射</text>
|
||||||
|
<text x="640" y="894" fill="#1565c0" font-weight="bold">权限:验真查询 · 本方映射管理 · 执行下架指令</text>
|
||||||
|
<text x="640" y="914" fill="#c62828">向运营商分发必须携带 MA码+哈希证书</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- 运营商端 -->
|
||||||
|
<rect x="1140" y="560" width="520" height="380" rx="10" fill="#fff3e0" stroke="#e65100" stroke-width="2"/>
|
||||||
|
<rect x="1140" y="560" width="520" height="32" rx="10" fill="#e65100"/>
|
||||||
|
<text x="1400" y="582" text-anchor="middle" fill="white" font-size="14" font-weight="bold">运营商端(分发网络)</text>
|
||||||
|
|
||||||
|
<g>
|
||||||
|
<rect x="1170" y="610" width="220" height="80" rx="6" fill="white" stroke="#e65100"/>
|
||||||
|
<text x="1280" y="632" text-anchor="middle" font-size="11" font-weight="bold" fill="#bf360c">CDN / EPG 分发系统</text>
|
||||||
|
<text x="1280" y="650" text-anchor="middle" font-size="9" fill="#555">(已有系统)</text>
|
||||||
|
<text x="1280" y="668" text-anchor="middle" font-size="9" fill="#777">保留自有分发编码</text>
|
||||||
|
<text x="1280" y="683" text-anchor="middle" font-size="9" fill="#777">CDN注入 / EPG发布 / 点播</text>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<rect x="1410" y="610" width="220" height="80" rx="6" fill="#ffe0b2" stroke="#e65100" stroke-width="2" stroke-dasharray="5,3"/>
|
||||||
|
<text x="1520" y="632" text-anchor="middle" font-size="11" font-weight="bold" fill="#bf360c">★ 注入校验+播放SDK(新建)</text>
|
||||||
|
<text x="1520" y="650" text-anchor="middle" font-size="9" fill="#555">CDN注入前哈希校验</text>
|
||||||
|
<text x="1520" y="666" text-anchor="middle" font-size="9" fill="#555">播放器终端哈希抽检(可选)</text>
|
||||||
|
<text x="1520" y="682" text-anchor="middle" font-size="9" fill="#555">防CDN劫持/传输篡改</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<g font-size="10" fill="#333">
|
||||||
|
<rect x="1170" y="710" width="460" height="210" rx="6" fill="#fff8e1" stroke="#ffcc80"/>
|
||||||
|
<text x="1400" y="732" text-anchor="middle" font-size="11" font-weight="bold" fill="#bf360c">运营商全流程(分发与播出)</text>
|
||||||
|
<text x="1190" y="758">Step7 CDN注入校验:注入前计算哈希,比对链上绑定哈希</text>
|
||||||
|
<text x="1210" y="778" fill="#2e7d32">匹配 → 注入CDN,生成分发编码</text>
|
||||||
|
<text x="1210" y="796" fill="#c62828">不匹配 → 拒绝注入,告警退回播控平台</text>
|
||||||
|
<text x="1190" y="822">Step8 EPG发布+终端播放:播放器SDK片段哈希抽检</text>
|
||||||
|
<text x="1210" y="842" fill="#777">下载片段比对链上哈希,异常断流切备用源</text>
|
||||||
|
<text x="1190" y="868">Step9 数据上报:以MA码为统一维度聚合三方数据</text>
|
||||||
|
<text x="1190" y="894" fill="#e65100" font-weight="bold">权限:验真查询 · 本方映射管理 · 执行下架指令</text>
|
||||||
|
<text x="1190" y="914" fill="#777">CP播放量/播控审核量/运营商分发量口径一致</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- 三方 ↔ 可信空间 双向连接 -->
|
||||||
|
<line x1="300" y1="560" x2="300" y2="500" stroke="#2e7d32" stroke-width="2" marker-end="url(#arrowGreen)"/>
|
||||||
|
<line x1="320" y1="500" x2="320" y2="560" stroke="#2e7d32" stroke-width="2" stroke-dasharray="4,2" marker-end="url(#arrowGreen)"/>
|
||||||
|
<text x="200" y="530" font-size="9" fill="#2e7d32">注册哈希/验真</text>
|
||||||
|
|
||||||
|
<line x1="850" y1="560" x2="850" y2="500" stroke="#1565c0" stroke-width="2" marker-end="url(#arrowBlue)"/>
|
||||||
|
<line x1="870" y1="500" x2="870" y2="560" stroke="#1565c0" stroke-width="2" stroke-dasharray="4,2" marker-end="url(#arrowBlue)"/>
|
||||||
|
<text x="760" y="530" font-size="9" fill="#1565c0">验真/映射</text>
|
||||||
|
|
||||||
|
<line x1="1400" y1="560" x2="1400" y2="500" stroke="#e65100" stroke-width="2" marker-end="url(#arrowRed)"/>
|
||||||
|
<line x1="1420" y1="500" x2="1420" y2="560" stroke="#e65100" stroke-width="2" stroke-dasharray="4,2" marker-end="url(#arrowRed)"/>
|
||||||
|
<text x="1310" y="530" font-size="9" fill="#e65100">注入校验/上报</text>
|
||||||
|
|
||||||
|
<!-- 三方横向流转箭头 -->
|
||||||
|
<line x1="560" y1="650" x2="588" y2="650" stroke="#455a64" stroke-width="2.5" marker-end="url(#arrow)"/>
|
||||||
|
<text x="574" y="642" text-anchor="middle" font-size="9" fill="#455a64">送审</text>
|
||||||
|
<line x1="1110" y1="650" x2="1138" y2="650" stroke="#455a64" stroke-width="2.5" marker-end="url(#arrow)"/>
|
||||||
|
<text x="1124" y="642" text-anchor="middle" font-size="9" fill="#455a64">分发</text>
|
||||||
|
|
||||||
|
<!-- ============ 监管价值区 ============ -->
|
||||||
|
<text x="40" y="985" font-size="16" font-weight="bold" fill="#b71c1c">④ 监管部门的核心价值(为什么这套系统让监管"管得住、管得省、管得准")</text>
|
||||||
|
|
||||||
|
<!-- 价值卡片 -->
|
||||||
|
<g>
|
||||||
|
<rect x="40" y="1000" width="390" height="150" rx="8" fill="#fff5f5" stroke="#c62828" stroke-width="1.5"/>
|
||||||
|
<text x="235" y="1024" text-anchor="middle" font-size="13" font-weight="bold" fill="#b71c1c">价值① 审播一致</text>
|
||||||
|
<line x1="60" y1="1032" x2="410" y2="1032" stroke="#ffcdd2"/>
|
||||||
|
<text x="60" y="1056" font-size="10" fill="#444">送审版 = 播出版,哈希强绑定</text>
|
||||||
|
<text x="60" y="1078" font-size="10" fill="#444">任何帧级篡改 → 哈希变化 → 秒级识别</text>
|
||||||
|
<text x="60" y="1100" font-size="10" fill="#444">杜绝"过审一版,播出另一版"</text>
|
||||||
|
<text x="60" y="1128" font-size="11" fill="#c62828" font-weight="bold">版本替换识别:几乎无法 → 100%自动</text>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<rect x="445" y="1000" width="390" height="150" rx="8" fill="#fff5f5" stroke="#c62828" stroke-width="1.5"/>
|
||||||
|
<text x="640" y="1024" text-anchor="middle" font-size="13" font-weight="bold" fill="#b71c1c">价值② 精准溯源</text>
|
||||||
|
<line x1="465" y1="1032" x2="815" y2="1032" stroke="#ffcdd2"/>
|
||||||
|
<text x="465" y="1056" font-size="10" fill="#444">凭一个MA码秒级定位三方系统</text>
|
||||||
|
<text x="465" y="1078" font-size="10" fill="#444">在哪个播控、哪个CDN、哪个哈希版本</text>
|
||||||
|
<text x="465" y="1100" font-size="10" fill="#444">历史版本变更全程留痕</text>
|
||||||
|
<text x="465" y="1128" font-size="11" fill="#c62828" font-weight="bold">出问题 → MA码一键穿透全链路</text>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<rect x="850" y="1000" width="390" height="150" rx="8" fill="#fff5f5" stroke="#c62828" stroke-width="1.5"/>
|
||||||
|
<text x="1045" y="1024" text-anchor="middle" font-size="13" font-weight="bold" fill="#b71c1c">价值③ 应急下架</text>
|
||||||
|
<line x1="870" y1="1032" x2="1220" y2="1032" stroke="#ffcdd2"/>
|
||||||
|
<text x="870" y="1056" font-size="10" fill="#444">下发"下架MA码第XXX号"单一指令</text>
|
||||||
|
<text x="870" y="1078" font-size="10" fill="#444">系统自动翻译为三方编码下架动作</text>
|
||||||
|
<text x="870" y="1100" font-size="10" fill="#444">无需人工逐层翻译/逐省协调</text>
|
||||||
|
<text x="870" y="1128" font-size="11" fill="#c62828" font-weight="bold">下架响应:2-24小时 → 分钟级</text>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<rect x="1255" y="1000" width="385" height="150" rx="8" fill="#fff5f5" stroke="#c62828" stroke-width="1.5"/>
|
||||||
|
<text x="1447" y="1024" text-anchor="middle" font-size="13" font-weight="bold" fill="#b71c1c">价值④ 数据可信</text>
|
||||||
|
<line x1="1275" y1="1032" x2="1625" y2="1032" stroke="#ffcdd2"/>
|
||||||
|
<text x="1275" y="1056" font-size="10" fill="#444">播放量/结算/上报以MA码统一聚合</text>
|
||||||
|
<text x="1275" y="1078" font-size="10" fill="#444">三方数据同一口径,消除对账争议</text>
|
||||||
|
<text x="1275" y="1100" font-size="10" fill="#444">监管掌握真实全网数据</text>
|
||||||
|
<text x="1275" y="1128" font-size="11" fill="#c62828" font-weight="bold">三方对账差异:15-30% → <5%</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- ============ 跨省复用价值 ============ -->
|
||||||
|
<text x="40" y="1190" font-size="16" font-weight="bold" fill="#1a237e">⑤ 跨省复用流程 — "一码通行":一省过审,全网凭MA码+哈希准入</text>
|
||||||
|
|
||||||
|
<rect x="40" y="1205" width="1620" height="130" rx="8" fill="#f3e5f5" stroke="#311b92" stroke-width="1.5"/>
|
||||||
|
<g font-size="11">
|
||||||
|
<!-- 流程步骤横向 -->
|
||||||
|
<rect x="70" y="1235" width="230" height="70" rx="6" fill="white" stroke="#311b92"/>
|
||||||
|
<text x="185" y="1262" text-anchor="middle" font-weight="bold" fill="#311b92">A省过审</text>
|
||||||
|
<text x="185" y="1283" text-anchor="middle" font-size="9" fill="#555">取得 MA码 + 哈希证书</text>
|
||||||
|
|
||||||
|
<line x1="300" y1="1270" x2="345" y2="1270" stroke="#311b92" stroke-width="2.5" marker-end="url(#arrowBlue)"/>
|
||||||
|
|
||||||
|
<rect x="350" y="1235" width="250" height="70" rx="6" fill="white" stroke="#311b92"/>
|
||||||
|
<text x="475" y="1258" text-anchor="middle" font-weight="bold" fill="#311b92">向B省播控送审</text>
|
||||||
|
<text x="475" y="1278" text-anchor="middle" font-size="9" fill="#555">仅提交 MA码+哈希证书</text>
|
||||||
|
<text x="475" y="1294" text-anchor="middle" font-size="9" fill="#c62828">无需重新提交内容文件</text>
|
||||||
|
|
||||||
|
<line x1="600" y1="1270" x2="645" y2="1270" stroke="#311b92" stroke-width="2.5" marker-end="url(#arrowBlue)"/>
|
||||||
|
|
||||||
|
<rect x="650" y="1235" width="280" height="70" rx="6" fill="white" stroke="#311b92"/>
|
||||||
|
<text x="790" y="1258" text-anchor="middle" font-weight="bold" fill="#311b92">可信空间验真</text>
|
||||||
|
<text x="790" y="1278" text-anchor="middle" font-size="9" fill="#555">MA码有效 + 哈希一致 + 非黑名单</text>
|
||||||
|
<text x="790" y="1294" text-anchor="middle" font-size="9" fill="#555">三重校验通过</text>
|
||||||
|
|
||||||
|
<line x1="930" y1="1270" x2="975" y2="1270" stroke="#311b92" stroke-width="2.5" marker-end="url(#arrowBlue)"/>
|
||||||
|
|
||||||
|
<rect x="980" y="1235" width="280" height="70" rx="6" fill="white" stroke="#2e7d32"/>
|
||||||
|
<text x="1120" y="1258" text-anchor="middle" font-weight="bold" fill="#2e7d32">B省快速准入</text>
|
||||||
|
<text x="1120" y="1278" text-anchor="middle" font-size="9" fill="#555">审核简化为合规性抽检</text>
|
||||||
|
<text x="1120" y="1294" text-anchor="middle" font-size="9" fill="#555">生成B省流水号 + 注册映射</text>
|
||||||
|
|
||||||
|
<line x1="1260" y1="1270" x2="1305" y2="1270" stroke="#2e7d32" stroke-width="2.5" marker-end="url(#arrowGreen)"/>
|
||||||
|
|
||||||
|
<rect x="1310" y="1235" width="320" height="70" rx="6" fill="#e8f5e9" stroke="#2e7d32"/>
|
||||||
|
<text x="1470" y="1258" text-anchor="middle" font-weight="bold" fill="#2e7d32">核心价值</text>
|
||||||
|
<text x="1470" y="1278" text-anchor="middle" font-size="9" fill="#555">"重走全流程" → "验真+抽检"</text>
|
||||||
|
<text x="1470" y="1294" text-anchor="middle" font-size="10" fill="#c62828" font-weight="bold">复用周期 15-30天 → 3-5天</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- ============ 预期成效对比 ============ -->
|
||||||
|
<text x="40" y="1375" font-size="16" font-weight="bold" fill="#1a237e">⑥ 预期成效对比</text>
|
||||||
|
|
||||||
|
<rect x="40" y="1390" width="1620" height="230" rx="8" fill="white" stroke="#e0e0e0"/>
|
||||||
|
<g font-size="11" fill="#333">
|
||||||
|
<rect x="50" y="1400" width="1600" height="28" fill="#eceff1"/>
|
||||||
|
<text x="120" y="1419" font-weight="bold">指标</text>
|
||||||
|
<text x="700" y="1419" font-weight="bold">现状</text>
|
||||||
|
<text x="1150" y="1419" font-weight="bold">目标</text>
|
||||||
|
|
||||||
|
<text x="70" y="1452">跨省复用审核周期</text><text x="700" y="1452" fill="#c62828">15-30天</text><text x="1150" y="1452" fill="#2e7d32" font-weight="bold">3-5天(验真为主)</text>
|
||||||
|
<line x1="50" y1="1463" x2="1650" y2="1463" stroke="#f0f0f0"/>
|
||||||
|
<text x="70" y="1486">违规内容下架响应</text><text x="700" y="1486" fill="#c62828">2-24小时</text><text x="1150" y="1486" fill="#2e7d32" font-weight="bold">分钟级</text>
|
||||||
|
<line x1="50" y1="1497" x2="1650" y2="1497" stroke="#f0f0f0"/>
|
||||||
|
<text x="70" y="1520">内容版本替换识别</text><text x="700" y="1520" fill="#c62828">几乎无法识别</text><text x="1150" y="1520" fill="#2e7d32" font-weight="bold">100%自动识别</text>
|
||||||
|
<line x1="50" y1="1531" x2="1650" y2="1531" stroke="#f0f0f0"/>
|
||||||
|
<text x="70" y="1554">三方数据对账差异</text><text x="700" y="1554" fill="#c62828">15-30%</text><text x="1150" y="1554" fill="#2e7d32" font-weight="bold"><5%</text>
|
||||||
|
<line x1="50" y1="1565" x2="1650" y2="1565" stroke="#f0f0f0"/>
|
||||||
|
<text x="70" y="1588">CP重复录入成本</text><text x="700" y="1588" fill="#c62828">每省每运营商重复录入</text><text x="1150" y="1588" fill="#2e7d32" font-weight="bold">一次录入,全网复用</text>
|
||||||
|
<line x1="50" y1="1599" x2="1650" y2="1599" stroke="#f0f0f0"/>
|
||||||
|
<text x="70" y="1614" font-weight="bold" fill="#1a237e">同一内容反复审核 → 一码通行 · 审过即锁定,锁定即通行,通行可追溯</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- ============ 实施路径 ============ -->
|
||||||
|
<text x="40" y="1655" font-size="16" font-weight="bold" fill="#1a237e">⑦ 实施路径</text>
|
||||||
|
|
||||||
|
<g transform="translate(40,1670)">
|
||||||
|
<rect x="0" y="0" width="395" height="120" rx="8" fill="#e3f2fd" stroke="#1565c0"/>
|
||||||
|
<text x="197" y="24" text-anchor="middle" font-size="12" font-weight="bold" fill="#0d47a1">一期 试点验证(3个月)</text>
|
||||||
|
<text x="20" y="48" font-size="10" fill="#444">单省单运营商跑通</text>
|
||||||
|
<text x="20" y="68" font-size="10" fill="#555">广东/湖南IPTV大省试点</text>
|
||||||
|
<text x="20" y="88" font-size="10" fill="#555">1家CP+1家播控+1家运营商</text>
|
||||||
|
<text x="20" y="108" font-size="10" fill="#555">微短剧品类全流程验证</text>
|
||||||
|
|
||||||
|
<rect x="408" y="0" width="395" height="120" rx="8" fill="#e8f5e9" stroke="#2e7d32"/>
|
||||||
|
<text x="605" y="24" text-anchor="middle" font-size="12" font-weight="bold" fill="#1b5e20">二期 扩展覆盖(6个月)</text>
|
||||||
|
<text x="428" y="48" font-size="10" fill="#444">多省多运营商接入</text>
|
||||||
|
<text x="428" y="68" font-size="10" fill="#555">扩展至3-5省</text>
|
||||||
|
<text x="428" y="88" font-size="10" fill="#555">覆盖网络剧、网络电影</text>
|
||||||
|
<text x="428" y="108" font-size="10" fill="#555">接入主流CP 10家以上</text>
|
||||||
|
|
||||||
|
<rect x="816" y="0" width="395" height="120" rx="8" fill="#fff3e0" stroke="#e65100"/>
|
||||||
|
<text x="1013" y="24" text-anchor="middle" font-size="12" font-weight="bold" fill="#bf360c">三期 全国贯通(12个月)</text>
|
||||||
|
<text x="836" y="48" font-size="10" fill="#444">全国IPTV统一接入</text>
|
||||||
|
<text x="836" y="68" font-size="10" fill="#555">对接广电总局备案系统</text>
|
||||||
|
<text x="836" y="88" font-size="10" fill="#555">成为全国IPTV内容</text>
|
||||||
|
<text x="836" y="108" font-size="10" fill="#555">准入的基础设施</text>
|
||||||
|
|
||||||
|
<rect x="1224" y="0" width="396" height="120" rx="8" fill="#fce4ec" stroke="#880e4f"/>
|
||||||
|
<text x="1422" y="24" text-anchor="middle" font-size="12" font-weight="bold" fill="#880e4f">四期 大小屏融合(18个月)</text>
|
||||||
|
<text x="1244" y="48" font-size="10" fill="#444">OTT/APP同步接入</text>
|
||||||
|
<text x="1244" y="68" font-size="10" fill="#555">MA+哈希扩展至OTT、手机APP</text>
|
||||||
|
<text x="1244" y="88" font-size="10" fill="#555">大小屏内容身份互通</text>
|
||||||
|
<text x="1244" y="108" font-size="10" fill="#555">统一内容准入基础设施</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- ============ 总结框 ============ -->
|
||||||
|
<rect x="40" y="1820" width="1620" height="120" rx="10" fill="url(#chainGrad)"/>
|
||||||
|
<text x="850" y="1855" text-anchor="middle" fill="white" font-size="16" font-weight="bold">设计哲学:不替代现有系统,在三方之上建立"可信身份映射层"</text>
|
||||||
|
<text x="850" y="1888" text-anchor="middle" fill="#d1c4e9" font-size="13">MA码解决"是谁"(监管身份)· 哈希码解决"是不是"(数据真实)· 可信数据空间解决"在哪"(全链溯源)</text>
|
||||||
|
<text x="850" y="1918" text-anchor="middle" fill="#b3c5ff" font-size="13" font-weight="bold">三者叠加 → 审过即锁定,锁定即通行,通行可追溯 · 监管从"逐层翻译滞后"升级为"一码穿透秒级响应"</text>
|
||||||
|
|
||||||
|
<!-- 图例 -->
|
||||||
|
<g transform="translate(40,1965)" font-size="10" fill="#555">
|
||||||
|
<rect x="0" y="0" width="14" height="14" rx="2" fill="white" stroke="#999"/><text x="20" y="11">已有系统(保留)</text>
|
||||||
|
<rect x="150" y="0" width="14" height="14" rx="2" fill="#ffebee" stroke="#c62828" stroke-dasharray="3,2"/><text x="170" y="11">★ 新建系统(TCS-IPTV)</text>
|
||||||
|
<line x1="350" y1="7" x2="385" y2="7" stroke="#455a64" stroke-width="2.5" marker-end="url(#arrow)"/><text x="392" y="11">业务流转</text>
|
||||||
|
<line x1="480" y1="7" x2="515" y2="7" stroke="#c62828" stroke-width="2.5" marker-end="url(#arrowRed)"/><text x="522" y="11">监管指令</text>
|
||||||
|
<line x1="610" y1="7" x2="645" y2="7" stroke="#1565c0" stroke-width="2" stroke-dasharray="4,2"/><text x="652" y="11">验真/映射(双向)</text>
|
||||||
|
</g>
|
||||||
|
<text x="1640" y="1976" text-anchor="end" font-size="9" fill="#9e9e9e">TCS-IPTV 内容可信锁定系统 · 系统线框图 · 2026</text>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 31 KiB |
@@ -0,0 +1,349 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# ============================================================
|
||||||
|
# 百度网盘备份脚本
|
||||||
|
# 用法: ./baidu-backup.sh [目标目录]
|
||||||
|
# 示例: ./baidu-backup.sh /2026/0517
|
||||||
|
# ./baidu-backup.sh # 自动使用 /年份/月日
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# ---- 配置 ----
|
||||||
|
APP_KEY="z3gemBZfg7KYj6U3eHNfIzTs7uYS9OMh"
|
||||||
|
SECRET_KEY="ptCKj2DfxL0KtGR1pM08c9KO2t2UC7SR"
|
||||||
|
TOKEN_FILE="$HOME/.baidu_pan_token.json"
|
||||||
|
BLOCK_SIZE=$((4 * 1024 * 1024)) # 4MB
|
||||||
|
|
||||||
|
# ---- 自动识别项目 ----
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
PROJECT_NAME="$(basename "$SCRIPT_DIR")"
|
||||||
|
PARENT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||||
|
ZIP_FILE="/tmp/${PROJECT_NAME}.zip"
|
||||||
|
MD5_FILE="/tmp/baidu_md5_list.txt"
|
||||||
|
|
||||||
|
# ---- 目标目录 ----
|
||||||
|
if [ -n "$1" ]; then
|
||||||
|
REMOTE_DIR="$1"
|
||||||
|
else
|
||||||
|
REMOTE_DIR="/$(date +%Y)/$(date +%m%d)"
|
||||||
|
fi
|
||||||
|
REMOTE_PATH="${REMOTE_DIR}/${PROJECT_NAME}.zip"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "╔══════════════════════════════════════════╗"
|
||||||
|
echo "║ 📦 百度网盘备份工具 ║"
|
||||||
|
echo "╚══════════════════════════════════════════╝"
|
||||||
|
echo ""
|
||||||
|
echo " 项目: $PROJECT_NAME"
|
||||||
|
echo " 目标: $REMOTE_PATH"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 步骤1: 打包
|
||||||
|
# ============================================================
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
echo "[1/5] 📦 打包项目文件..."
|
||||||
|
rm -f "$ZIP_FILE"
|
||||||
|
cd "$PARENT_DIR"
|
||||||
|
|
||||||
|
# 先统计文件总数
|
||||||
|
TOTAL_FILES=$(find "$PROJECT_NAME" -not -path "${PROJECT_NAME}/.git/*" -type f | wc -l | tr -d ' ')
|
||||||
|
echo " 📊 共 ${TOTAL_FILES} 个文件"
|
||||||
|
|
||||||
|
# 打包并实时显示百分比
|
||||||
|
COUNTER=0
|
||||||
|
zip -r "$ZIP_FILE" "$PROJECT_NAME" -x "${PROJECT_NAME}/.git/*" 2>&1 | while IFS= read -r line; do
|
||||||
|
COUNTER=$((COUNTER + 1))
|
||||||
|
PCT=$((COUNTER * 100 / TOTAL_FILES))
|
||||||
|
if [ $PCT -gt 100 ]; then PCT=100; fi
|
||||||
|
# 进度条
|
||||||
|
BAR_FILLED=$((PCT * 30 / 100))
|
||||||
|
BAR_EMPTY=$((30 - BAR_FILLED))
|
||||||
|
BAR=""
|
||||||
|
for ((b=0; b<BAR_FILLED; b++)); do BAR="${BAR}█"; done
|
||||||
|
for ((b=0; b<BAR_EMPTY; b++)); do BAR="${BAR}░"; done
|
||||||
|
printf "\r %s %3d%% (%d/%d) " "$BAR" "$PCT" "$COUNTER" "$TOTAL_FILES"
|
||||||
|
done
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
FILE_SIZE=$(stat -f%z "$ZIP_FILE" 2>/dev/null || stat -c%s "$ZIP_FILE" 2>/dev/null)
|
||||||
|
FILE_SIZE_MB=$((FILE_SIZE / 1024 / 1024))
|
||||||
|
echo " ✅ 打包完成: ${FILE_SIZE_MB}MB"
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 步骤2: 获取 Token(缓存 / 刷新 / 设备授权)
|
||||||
|
# ============================================================
|
||||||
|
echo ""
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
echo "[2/5] 🔑 获取百度网盘授权..."
|
||||||
|
|
||||||
|
ACCESS_TOKEN=""
|
||||||
|
|
||||||
|
# 尝试读取缓存
|
||||||
|
if [ -f "$TOKEN_FILE" ]; then
|
||||||
|
CACHED=$(python3 -c "
|
||||||
|
import json, time, sys
|
||||||
|
with open('$TOKEN_FILE') as f:
|
||||||
|
d = json.load(f)
|
||||||
|
if time.time() < d.get('expires_at', 0):
|
||||||
|
print('VALID|' + d['access_token'])
|
||||||
|
else:
|
||||||
|
print('EXPIRED|' + d.get('refresh_token', ''))
|
||||||
|
" 2>/dev/null || echo "FAIL|")
|
||||||
|
|
||||||
|
STATUS="${CACHED%%|*}"
|
||||||
|
VALUE="${CACHED#*|}"
|
||||||
|
|
||||||
|
if [ "$STATUS" = "VALID" ]; then
|
||||||
|
ACCESS_TOKEN="$VALUE"
|
||||||
|
echo " ✅ 使用缓存 Token(有效)"
|
||||||
|
elif [ "$STATUS" = "EXPIRED" ] && [ -n "$VALUE" ]; then
|
||||||
|
echo " ⏳ Token 已过期,尝试刷新..."
|
||||||
|
RESP=$(curl -s -X POST "https://openapi.baidu.com/oauth/2.0/token" \
|
||||||
|
-d "grant_type=refresh_token&refresh_token=${VALUE}&client_id=${APP_KEY}&client_secret=${SECRET_KEY}")
|
||||||
|
NEW_TOKEN=$(echo "$RESP" | python3 -c "import sys,json;d=json.load(sys.stdin);print(d.get('access_token',''))" 2>/dev/null)
|
||||||
|
if [ -n "$NEW_TOKEN" ]; then
|
||||||
|
ACCESS_TOKEN="$NEW_TOKEN"
|
||||||
|
# 更新缓存
|
||||||
|
python3 -c "
|
||||||
|
import json, time
|
||||||
|
d = json.loads('$RESP'.replace(\"'\", '\"'))
|
||||||
|
token = {'access_token': d['access_token'], 'refresh_token': d['refresh_token'], 'expires_at': int(time.time()) + d['expires_in']}
|
||||||
|
with open('$TOKEN_FILE', 'w') as f: json.dump(token, f)
|
||||||
|
" 2>/dev/null
|
||||||
|
echo " ✅ Token 刷新成功"
|
||||||
|
else
|
||||||
|
echo " ⚠️ 刷新失败,需要重新授权"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 如果没有有效 Token,走设备授权流程
|
||||||
|
if [ -z "$ACCESS_TOKEN" ]; then
|
||||||
|
echo " 🔐 需要设备授权..."
|
||||||
|
DEVICE_RESP=$(curl -s -X POST "https://openapi.baidu.com/oauth/2.0/device/code" \
|
||||||
|
-d "response_type=device_code&client_id=${APP_KEY}&scope=basic,netdisk")
|
||||||
|
|
||||||
|
DEVICE_CODE=$(echo "$DEVICE_RESP" | python3 -c "import sys,json;print(json.load(sys.stdin)['device_code'])")
|
||||||
|
USER_CODE=$(echo "$DEVICE_RESP" | python3 -c "import sys,json;print(json.load(sys.stdin)['user_code'])")
|
||||||
|
QRCODE_URL=$(echo "$DEVICE_RESP" | python3 -c "import sys,json;print(json.load(sys.stdin)['qrcode_url'])")
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo " ┌─────────────────────────────────────┐"
|
||||||
|
echo " │ 请打开: https://openapi.baidu.com/device"
|
||||||
|
echo " │ 输入码: $USER_CODE"
|
||||||
|
echo " │ 或扫码: $QRCODE_URL"
|
||||||
|
echo " └─────────────────────────────────────┘"
|
||||||
|
echo ""
|
||||||
|
read -p " 授权完成后按回车继续..." _
|
||||||
|
|
||||||
|
TOKEN_RESP=$(curl -s -X POST "https://openapi.baidu.com/oauth/2.0/token" \
|
||||||
|
-d "grant_type=device_token&code=${DEVICE_CODE}&client_id=${APP_KEY}&client_secret=${SECRET_KEY}")
|
||||||
|
ACCESS_TOKEN=$(echo "$TOKEN_RESP" | python3 -c "import sys,json;print(json.load(sys.stdin).get('access_token',''))" 2>/dev/null)
|
||||||
|
|
||||||
|
if [ -z "$ACCESS_TOKEN" ]; then
|
||||||
|
echo " ❌ 授权失败: $TOKEN_RESP"
|
||||||
|
rm -f "$ZIP_FILE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 保存缓存
|
||||||
|
echo "$TOKEN_RESP" | python3 -c "
|
||||||
|
import sys, json, time
|
||||||
|
d = json.load(sys.stdin)
|
||||||
|
token = {'access_token': d['access_token'], 'refresh_token': d['refresh_token'], 'expires_at': int(time.time()) + d['expires_in']}
|
||||||
|
with open('$TOKEN_FILE', 'w') as f: json.dump(token, f)
|
||||||
|
"
|
||||||
|
echo " ✅ 授权成功,Token 已缓存"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 步骤3: 预创建文件
|
||||||
|
# ============================================================
|
||||||
|
echo ""
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
BLOCKS=$(( (FILE_SIZE + BLOCK_SIZE - 1) / BLOCK_SIZE ))
|
||||||
|
echo "[3/5] 📋 预创建文件(${BLOCKS}个分片)..."
|
||||||
|
BLOCK_LIST=$(python3 -c "import json; print(json.dumps(['0'*32]*$BLOCKS))")
|
||||||
|
PRE_RESP=$(curl -s "https://pan.baidu.com/rest/2.0/xpan/file?method=precreate&access_token=${ACCESS_TOKEN}" \
|
||||||
|
-d "path=${REMOTE_PATH}&size=${FILE_SIZE}&isdir=0&autoinit=1&block_list=${BLOCK_LIST}")
|
||||||
|
UPLOAD_ID=$(echo "$PRE_RESP" | python3 -c "import sys,json;print(json.load(sys.stdin).get('uploadid',''))" 2>/dev/null)
|
||||||
|
if [ -z "$UPLOAD_ID" ]; then
|
||||||
|
echo " ❌ 预创建失败: $PRE_RESP"
|
||||||
|
rm -f "$ZIP_FILE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo " ✅ 预创建成功"
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 步骤4: 分片上传(并发)
|
||||||
|
# ============================================================
|
||||||
|
echo ""
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
PARALLEL="${BAIDU_PARALLEL:-8}"
|
||||||
|
if [ "$PARALLEL" -gt "$BLOCKS" ]; then PARALLEL=$BLOCKS; fi
|
||||||
|
echo "[4/5] 🚀 上传中(${PARALLEL} 路并发)..."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
UNSORTED_MD5="/tmp/baidu_md5_unsorted_${UPLOAD_ID}.txt"
|
||||||
|
PROGRESS_FILE="/tmp/baidu_progress_${UPLOAD_ID}.txt"
|
||||||
|
ERR_FILE="/tmp/baidu_err_${UPLOAD_ID}.txt"
|
||||||
|
DONE_FLAG="/tmp/baidu_done_${UPLOAD_ID}"
|
||||||
|
: > "$UNSORTED_MD5"
|
||||||
|
: > "$PROGRESS_FILE"
|
||||||
|
: > "$ERR_FILE"
|
||||||
|
rm -f "$DONE_FLAG"
|
||||||
|
: > "$MD5_FILE"
|
||||||
|
START_TIME=$(date +%s)
|
||||||
|
|
||||||
|
# 单分片上传 worker(并发安全:单行 echo < PIPE_BUF 是原子写)
|
||||||
|
upload_part() {
|
||||||
|
local i=$1
|
||||||
|
local chunk="/tmp/baidu_chunk_${UPLOAD_ID}_${i}"
|
||||||
|
dd if="$ZIP_FILE" bs="$BLOCK_SIZE" skip="$i" count=1 2>/dev/null > "$chunk"
|
||||||
|
local resp md5 attempt
|
||||||
|
md5=""
|
||||||
|
for attempt in 1 2 3; do
|
||||||
|
resp=$(curl -s --max-time 600 \
|
||||||
|
"https://d.pcs.baidu.com/rest/2.0/pcs/superfile2?method=upload&access_token=${ACCESS_TOKEN}&type=tmpfile&path=${REMOTE_PATH}&uploadid=${UPLOAD_ID}&partseq=${i}" \
|
||||||
|
-F "file=@${chunk}")
|
||||||
|
md5=$(echo "$resp" | python3 -c "import sys,json;print(json.load(sys.stdin).get('md5',''))" 2>/dev/null)
|
||||||
|
[ -n "$md5" ] && break
|
||||||
|
sleep $((attempt * 2))
|
||||||
|
done
|
||||||
|
rm -f "$chunk"
|
||||||
|
if [ -z "$md5" ]; then
|
||||||
|
echo "part ${i} failed after 3 attempts: ${resp}" >> "$ERR_FILE"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
echo "${i}|${md5}" >> "$UNSORTED_MD5"
|
||||||
|
echo "x" >> "$PROGRESS_FILE"
|
||||||
|
}
|
||||||
|
export -f upload_part
|
||||||
|
export ZIP_FILE BLOCK_SIZE ACCESS_TOKEN REMOTE_PATH UPLOAD_ID
|
||||||
|
export UNSORTED_MD5 PROGRESS_FILE ERR_FILE
|
||||||
|
|
||||||
|
# 后台进度刷新进程(每秒刷新一次)
|
||||||
|
(
|
||||||
|
while :; do
|
||||||
|
DONE=$(wc -l < "$PROGRESS_FILE" 2>/dev/null | tr -d ' ')
|
||||||
|
DONE=${DONE:-0}
|
||||||
|
if [ "$DONE" -gt "$BLOCKS" ]; then DONE=$BLOCKS; fi
|
||||||
|
PCT=$((DONE * 100 / BLOCKS))
|
||||||
|
UPLOADED_MB=$((DONE * BLOCK_SIZE / 1024 / 1024))
|
||||||
|
if [ $UPLOADED_MB -gt $FILE_SIZE_MB ]; then UPLOADED_MB=$FILE_SIZE_MB; fi
|
||||||
|
NOW=$(date +%s)
|
||||||
|
ELAPSED=$((NOW - START_TIME))
|
||||||
|
if [ $ELAPSED -gt 0 ] && [ $DONE -gt 0 ]; then
|
||||||
|
SPEED_KB=$((DONE * BLOCK_SIZE / 1024 / ELAPSED))
|
||||||
|
SPEED_INT=$((SPEED_KB / 1024))
|
||||||
|
SPEED_DEC=$(( (SPEED_KB % 1024) * 10 / 1024 ))
|
||||||
|
if [ "$SPEED_KB" -gt 0 ]; then
|
||||||
|
REMAINING_KB=$(( (FILE_SIZE - DONE * BLOCK_SIZE) / 1024 ))
|
||||||
|
if [ $REMAINING_KB -lt 0 ]; then REMAINING_KB=0; fi
|
||||||
|
ETA=$(( REMAINING_KB / SPEED_KB ))
|
||||||
|
ETA_MIN=$((ETA / 60))
|
||||||
|
ETA_SEC=$((ETA % 60))
|
||||||
|
ETA_STR="${ETA_MIN}m${ETA_SEC}s"
|
||||||
|
else
|
||||||
|
ETA_STR="计算中"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
SPEED_INT=0
|
||||||
|
SPEED_DEC=0
|
||||||
|
ETA_STR="计算中"
|
||||||
|
fi
|
||||||
|
BAR_FILLED=$((PCT * 30 / 100))
|
||||||
|
BAR_EMPTY=$((30 - BAR_FILLED))
|
||||||
|
BAR=""
|
||||||
|
for ((b=0; b<BAR_FILLED; b++)); do BAR="${BAR}█"; done
|
||||||
|
for ((b=0; b<BAR_EMPTY; b++)); do BAR="${BAR}░"; done
|
||||||
|
printf "\r %s %3d%% | %d/%dMB | %d.%dMB/s | 剩余%s " "$BAR" "$PCT" "$UPLOADED_MB" "$FILE_SIZE_MB" "$SPEED_INT" "$SPEED_DEC" "$ETA_STR"
|
||||||
|
if [ -f "$DONE_FLAG" ] || [ "$DONE" -ge "$BLOCKS" ]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
) &
|
||||||
|
PROGRESS_PID=$!
|
||||||
|
|
||||||
|
# 并发上传:xargs -P 同时跑 PARALLEL 个 worker(绕开百度 PCS 单连接限速)
|
||||||
|
XARGS_RC=0
|
||||||
|
seq 0 $((BLOCKS-1)) | xargs -P "$PARALLEL" -I % bash -c 'upload_part "$@"' _ % || XARGS_RC=$?
|
||||||
|
|
||||||
|
# 通知进度进程退出并等待,最后重画一行
|
||||||
|
touch "$DONE_FLAG"
|
||||||
|
wait "$PROGRESS_PID" 2>/dev/null || true
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
if [ "$XARGS_RC" -ne 0 ]; then
|
||||||
|
echo ""
|
||||||
|
echo " ❌ 分片上传失败:"
|
||||||
|
if [ -s "$ERR_FILE" ]; then
|
||||||
|
head -n 5 "$ERR_FILE"
|
||||||
|
fi
|
||||||
|
rm -f "$ZIP_FILE" "$MD5_FILE" "$UNSORTED_MD5" "$PROGRESS_FILE" "$ERR_FILE" "$DONE_FLAG"
|
||||||
|
rm -f /tmp/baidu_chunk_${UPLOAD_ID}_*
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 校验分片数
|
||||||
|
DONE_COUNT=$(wc -l < "$UNSORTED_MD5" | tr -d ' ')
|
||||||
|
if [ "$DONE_COUNT" != "$BLOCKS" ]; then
|
||||||
|
echo ""
|
||||||
|
echo " ❌ 分片数不匹配: ${DONE_COUNT}/${BLOCKS}"
|
||||||
|
if [ -s "$ERR_FILE" ]; then
|
||||||
|
head -n 5 "$ERR_FILE"
|
||||||
|
fi
|
||||||
|
rm -f "$ZIP_FILE" "$MD5_FILE" "$UNSORTED_MD5" "$PROGRESS_FILE" "$ERR_FILE" "$DONE_FLAG"
|
||||||
|
rm -f /tmp/baidu_chunk_${UPLOAD_ID}_*
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 按 partseq 升序生成最终 MD5_FILE
|
||||||
|
sort -t'|' -k1n "$UNSORTED_MD5" | cut -d'|' -f2 > "$MD5_FILE"
|
||||||
|
rm -f "$UNSORTED_MD5" "$PROGRESS_FILE" "$ERR_FILE" "$DONE_FLAG"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo " ✅ 所有分片上传完成"
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 步骤5: 合并文件
|
||||||
|
# ============================================================
|
||||||
|
echo ""
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
echo "[5/5] 🔗 合并文件..."
|
||||||
|
MD5_LIST=$(awk '{printf "\"%s\",", $0}' "$MD5_FILE" | sed 's/,$//')
|
||||||
|
CREATE_RESP=$(curl -s "https://pan.baidu.com/rest/2.0/xpan/file?method=create&access_token=${ACCESS_TOKEN}" \
|
||||||
|
-d "path=${REMOTE_PATH}&size=${FILE_SIZE}&isdir=0&uploadid=${UPLOAD_ID}&block_list=[${MD5_LIST}]")
|
||||||
|
CREATE_ERRNO=$(echo "$CREATE_RESP" | python3 -c "import sys,json;print(json.load(sys.stdin).get('errno',99))" 2>/dev/null)
|
||||||
|
FINAL_PATH=$(echo "$CREATE_RESP" | python3 -c "import sys,json;print(json.load(sys.stdin).get('path',''))" 2>/dev/null)
|
||||||
|
|
||||||
|
# 清理
|
||||||
|
rm -f "$ZIP_FILE" "$MD5_FILE"
|
||||||
|
rm -f /tmp/baidu_chunk_${UPLOAD_ID}_* 2>/dev/null || true
|
||||||
|
|
||||||
|
# 计算耗时
|
||||||
|
END_TIME=$(date +%s)
|
||||||
|
TOTAL=$((END_TIME - START_TIME))
|
||||||
|
T_MIN=$((TOTAL / 60))
|
||||||
|
T_SEC=$((TOTAL % 60))
|
||||||
|
|
||||||
|
# 输出结果
|
||||||
|
echo ""
|
||||||
|
echo "╔══════════════════════════════════════════════╗"
|
||||||
|
if [ "$CREATE_ERRNO" = "0" ]; then
|
||||||
|
echo "║ 📦 百度网盘备份完成! ║"
|
||||||
|
echo "╠══════════════════════════════════════════════╣"
|
||||||
|
echo " 📁 路径: $FINAL_PATH"
|
||||||
|
echo " 📊 大小: ${FILE_SIZE_MB} MB"
|
||||||
|
echo " ⏱️ 耗时: ${T_MIN}分${T_SEC}秒"
|
||||||
|
echo " ✅ 状态: 上传成功"
|
||||||
|
else
|
||||||
|
echo "║ ❌ 合并失败 ║"
|
||||||
|
echo "╠══════════════════════════════════════════════╣"
|
||||||
|
echo " errno: $CREATE_ERRNO"
|
||||||
|
echo " 响应: $CREATE_RESP"
|
||||||
|
fi
|
||||||
|
echo "╚══════════════════════════════════════════════╝"
|
||||||
|
echo ""
|
||||||
|
After Width: | Height: | Size: 2.0 MiB |
|
After Width: | Height: | Size: 1.7 MiB |
|
After Width: | Height: | Size: 1.9 MiB |
|
After Width: | Height: | Size: 2.2 MiB |
|
After Width: | Height: | Size: 2.1 MiB |
|
After Width: | Height: | Size: 1.8 MiB |
|
After Width: | Height: | Size: 1.7 MiB |
|
After Width: | Height: | Size: 1.9 MiB |
|
After Width: | Height: | Size: 1.9 MiB |
|
After Width: | Height: | Size: 1.9 MiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 1.9 MiB |
|
After Width: | Height: | Size: 1.6 MiB |
@@ -0,0 +1,19 @@
|
|||||||
|
# Go
|
||||||
|
/bin/
|
||||||
|
*.test
|
||||||
|
*.out
|
||||||
|
vendor/
|
||||||
|
|
||||||
|
# Env
|
||||||
|
.env
|
||||||
|
*.local
|
||||||
|
|
||||||
|
# Node / web-console
|
||||||
|
web-console/node_modules/
|
||||||
|
web-console/dist/
|
||||||
|
web-console/build/
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
.DS_Store
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
.PHONY: build test tidy run-api run-chain run-hash migrate db-check redis-check fmt vet
|
||||||
|
|
||||||
|
build:
|
||||||
|
go build ./...
|
||||||
|
|
||||||
|
test:
|
||||||
|
go test ./... -count=1
|
||||||
|
|
||||||
|
tidy:
|
||||||
|
go mod tidy
|
||||||
|
|
||||||
|
fmt:
|
||||||
|
gofmt -w .
|
||||||
|
|
||||||
|
vet:
|
||||||
|
go vet ./...
|
||||||
|
|
||||||
|
run-api:
|
||||||
|
go run ./cmd/api-svc
|
||||||
|
|
||||||
|
run-chain:
|
||||||
|
go run ./cmd/chain-svc
|
||||||
|
|
||||||
|
run-hash:
|
||||||
|
go run ./cmd/hash-api
|
||||||
|
|
||||||
|
# 本地依赖(直接使用本机已安装的 PostgreSQL / Redis,无需 Docker)
|
||||||
|
# psql 已加入 PATH(Postgres.app v16)
|
||||||
|
PG ?= psql
|
||||||
|
PG_DSN ?= postgres://postgres@localhost:5432/tcs_iptv?sslmode=disable
|
||||||
|
|
||||||
|
migrate:
|
||||||
|
@for f in deploy/migrations/*.sql; do echo "applying $$f"; $(PG) "$(PG_DSN)" -f $$f; done
|
||||||
|
|
||||||
|
db-check:
|
||||||
|
$(PG) "$(PG_DSN)" -c "\dt"
|
||||||
|
|
||||||
|
redis-check:
|
||||||
|
redis-cli ping
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
# TCS-IPTV 内容可信锁定系统
|
||||||
|
|
||||||
|
> MA码(监管身份)+ 哈希码(技术指纹)双锚定,在 CP / 审核和监管部门 / 运营商 三方系统之上建立"可信身份映射层"。
|
||||||
|
>
|
||||||
|
> 上游文档:`../0-req-IPTV.md`(需求)、`../1-prd-IPTV.md`(PRD)、`../2-task-IPTV.md`(任务)
|
||||||
|
|
||||||
|
## 技术栈
|
||||||
|
|
||||||
|
- 后端 / 链交互 / 哈希SDK:Go 1.23 + Gin
|
||||||
|
- 智能合约:Go(ChainMaker 链原生)
|
||||||
|
- 联盟链:长安链 ChainMaker 2.x(国密)
|
||||||
|
- 数据库 / 缓存:PostgreSQL 16 / Redis 7.x
|
||||||
|
- 监管大屏:React 18 + Ant Design 5 + ECharts
|
||||||
|
|
||||||
|
## 工程结构
|
||||||
|
|
||||||
|
```
|
||||||
|
tcs-iptv/
|
||||||
|
├── cmd/ # 各服务入口
|
||||||
|
│ ├── api-svc/ # 业务后端(验真/签发/映射/下架/查询)
|
||||||
|
│ ├── chain-svc/ # 链交互服务(封装 ChainMaker SDK)
|
||||||
|
│ └── hash-api/ # 哈希SDK 的 HTTP API
|
||||||
|
├── internal/ # 内部包
|
||||||
|
│ ├── hash/ # 哈希核心(SHA-256 / Merkle / 感知哈希)
|
||||||
|
│ ├── chain/ # 链客户端抽象(MVP 含 mock 实现)
|
||||||
|
│ ├── config/ # 配置加载
|
||||||
|
│ ├── httpx/ # 通用 HTTP / 鉴权中间件
|
||||||
|
│ └── model/ # 领域模型
|
||||||
|
├── contracts/ # ChainMaker Go 合约源码
|
||||||
|
│ └── tcs_registry/
|
||||||
|
├── deploy/ # 部署
|
||||||
|
│ ├── docker-compose.yml
|
||||||
|
│ └── migrations/ # 数据库迁移
|
||||||
|
├── web-console/ # 监管大屏(React)
|
||||||
|
├── Makefile
|
||||||
|
└── go.mod
|
||||||
|
```
|
||||||
|
|
||||||
|
## 快速开始
|
||||||
|
|
||||||
|
> 本地直接使用已安装的 PostgreSQL / Redis,无需 Docker。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 初始化数据库(数据库 tcs_iptv 需已创建)
|
||||||
|
make migrate
|
||||||
|
|
||||||
|
# 检查依赖
|
||||||
|
make db-check # 列出已建表
|
||||||
|
make redis-check # 应返回 PONG
|
||||||
|
|
||||||
|
# 构建全部服务
|
||||||
|
make build
|
||||||
|
|
||||||
|
# 运行测试
|
||||||
|
make test
|
||||||
|
|
||||||
|
# 启动哈希 API(示例)
|
||||||
|
make run-hash
|
||||||
|
```
|
||||||
|
|
||||||
|
环境变量(可选,缺省适配本地):
|
||||||
|
|
||||||
|
| 变量 | 默认值 |
|
||||||
|
|------|--------|
|
||||||
|
| TCS_POSTGRES_DSN | postgres://postgres@localhost:5432/tcs_iptv?sslmode=disable |
|
||||||
|
| TCS_REDIS_ADDR | localhost:6379 |
|
||||||
|
| TCS_API_ADDR | :8080 |
|
||||||
|
| TCS_CHAIN_ADDR | :8081 |
|
||||||
|
| TCS_HASH_ADDR | :8082 |
|
||||||
|
|
||||||
|
## 服务端口(默认)
|
||||||
|
|
||||||
|
| 服务 | 端口 |
|
||||||
|
|------|------|
|
||||||
|
| api-svc | 8080 |
|
||||||
|
| chain-svc | 8081 |
|
||||||
|
| hash-api | 8082 |
|
||||||
|
| PostgreSQL | 5432 |
|
||||||
|
| Redis | 6379 |
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
_ "github.com/lib/pq"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/tcs-iptv/tcs/internal/api"
|
||||||
|
"github.com/tcs-iptv/tcs/internal/chain"
|
||||||
|
"github.com/tcs-iptv/tcs/internal/config"
|
||||||
|
"github.com/tcs-iptv/tcs/internal/httpx"
|
||||||
|
"github.com/tcs-iptv/tcs/internal/macode"
|
||||||
|
"github.com/tcs-iptv/tcs/internal/service"
|
||||||
|
)
|
||||||
|
|
||||||
|
// newAllocationStore 优先使用 PostgreSQL(持久、防重号),不可用时回退内存。
|
||||||
|
func newAllocationStore(dsn string) macode.AllocationStore {
|
||||||
|
db, err := sql.Open("postgres", dsn)
|
||||||
|
if err == nil {
|
||||||
|
if pingErr := db.Ping(); pingErr == nil {
|
||||||
|
log.Printf("macode: 使用 PostgreSQL 号段存储")
|
||||||
|
return macode.NewPostgresStore(db)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Printf("macode: PostgreSQL 不可用,回退内存号段存储(仅开发用)")
|
||||||
|
return macode.NewMemoryStore()
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cfg := config.Load()
|
||||||
|
|
||||||
|
// 装配依赖:链(MVP 用内存 mock)+ MA 码生成器(登记号段)+ 业务服务
|
||||||
|
ch := chain.NewMemoryChain()
|
||||||
|
gen := macode.NewGenerator(newAllocationStore(cfg.PostgresDSN))
|
||||||
|
// 示例号段(生产由与发码机构对接后配置)
|
||||||
|
// 机构节点 6101 = 陕西(管理方:陕西IPTV运营公司);行业节点 8531 = IPTV视听内容
|
||||||
|
_ = gen.RegisterSegment(macode.Segment{
|
||||||
|
IndustryNode: "8531", OrgNode: "6101",
|
||||||
|
Category: macode.CategoryMicroDrama, Start: 1, End: 9999999, SeqWidth: 7,
|
||||||
|
})
|
||||||
|
_ = gen.RegisterSegment(macode.Segment{
|
||||||
|
IndustryNode: "8531", OrgNode: "6101",
|
||||||
|
Category: macode.CategoryWebSeries, Start: 1, End: 9999999, SeqWidth: 7,
|
||||||
|
})
|
||||||
|
_ = gen.RegisterSegment(macode.Segment{
|
||||||
|
IndustryNode: "8531", OrgNode: "6101",
|
||||||
|
Category: macode.CategoryWebMovie, Start: 1, End: 9999999, SeqWidth: 7,
|
||||||
|
})
|
||||||
|
svc := service.New(ch, gen)
|
||||||
|
h := api.NewHandler(svc)
|
||||||
|
|
||||||
|
// 鉴权密钥库(MVP 预置四角色示例密钥;生产从 Vault/DB 加载)
|
||||||
|
keys := httpx.NewMemoryKeyStore()
|
||||||
|
keys.Add("ak-regulator", "sk-regulator", string(chain.RoleRegulator))
|
||||||
|
keys.Add("ak-reviewer", "sk-reviewer", string(chain.RoleReviewer))
|
||||||
|
keys.Add("ak-cp", "sk-cp", string(chain.RoleCP))
|
||||||
|
keys.Add("ak-operator", "sk-operator", string(chain.RoleOperator))
|
||||||
|
|
||||||
|
r := gin.Default()
|
||||||
|
httpx.Health(r, "api-svc")
|
||||||
|
|
||||||
|
v1 := r.Group("/api/v1", httpx.AuthMiddleware(keys))
|
||||||
|
h.Register(v1)
|
||||||
|
|
||||||
|
log.Printf("api-svc listening on %s", cfg.APIAddr)
|
||||||
|
if err := r.Run(cfg.APIAddr); err != nil {
|
||||||
|
log.Fatalf("api-svc failed: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/tcs-iptv/tcs/internal/config"
|
||||||
|
"github.com/tcs-iptv/tcs/internal/httpx"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cfg := config.Load()
|
||||||
|
r := gin.Default()
|
||||||
|
httpx.Health(r, "chain-svc")
|
||||||
|
|
||||||
|
log.Printf("chain-svc listening on %s", cfg.ChainAddr)
|
||||||
|
if err := r.Run(cfg.ChainAddr); err != nil {
|
||||||
|
log.Fatalf("chain-svc failed: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/tcs-iptv/tcs/internal/config"
|
||||||
|
"github.com/tcs-iptv/tcs/internal/httpx"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cfg := config.Load()
|
||||||
|
r := gin.Default()
|
||||||
|
httpx.Health(r, "hash-api")
|
||||||
|
|
||||||
|
log.Printf("hash-api listening on %s", cfg.HashAddr)
|
||||||
|
if err := r.Run(cfg.HashAddr); err != nil {
|
||||||
|
log.Fatalf("hash-api failed: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
# tcs_registry — ChainMaker 智能合约(Go)
|
||||||
|
|
||||||
|
可信数据空间的链上合约,实现 TCS-IPTV 的四类核心数据结构与合约方法。
|
||||||
|
与 `internal/chain` 的 `Client` 接口语义一一对应:MVP 用 `MemoryChain` 开发测试,
|
||||||
|
真实部署时由 chain-svc 通过 ChainMaker Go SDK 调用本合约。
|
||||||
|
|
||||||
|
## 合约方法(对应需求16-AC2)
|
||||||
|
|
||||||
|
| 方法 | 权限 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| `IssueMA(maCode, ctid, merkleRoot, fileHash, contentJSON)` | 仅监管节点 | 签发 MA 码并 1:1 强绑定哈希;不可重复、不可解绑 |
|
||||||
|
| `RegisterHashBinding(ctid, bindingJSON)` | 审核/监管 | 追加哈希绑定(转码版父子关系) |
|
||||||
|
| `RegisterMapping(ctid, party, partyID, cdnEndpoint)` | 三方 | 注册编码映射;MA 必须已签发 |
|
||||||
|
| `VerifyHash(maCode, fileHash) -> bool` | 任意 | 校验提交哈希与绑定哈希是否一致 |
|
||||||
|
| `QueryContent(maCode) -> json` | 任意 | 查询内容主记录 |
|
||||||
|
| `QueryMappings(maCode) -> json` | 任意 | 查询全部三方映射与 CDN 端点 |
|
||||||
|
| `RecordVersionChange(ctid, vcJSON)` | 审核/监管 | 记录版本变更,触发重审 |
|
||||||
|
| `Revoke(maCode, reason)` | 仅监管节点 | 下架,返回受影响映射 |
|
||||||
|
|
||||||
|
## 权限模型(对应需求14)
|
||||||
|
|
||||||
|
合约内通过 `sender()` 的组织/角色证书判断调用方身份:
|
||||||
|
- `RoleRegulator`(监管主体):`IssueMA` / `Revoke` 唯一发起方
|
||||||
|
- `RoleReviewer`(审核主体/CSPS/媒资库):哈希绑定、版本变更
|
||||||
|
- `RoleCP`:送审时注册哈希、本方映射
|
||||||
|
- `RoleOperator`:注册本方映射、验真
|
||||||
|
|
||||||
|
## 国密
|
||||||
|
|
||||||
|
底层链使用长安链 ChainMaker(国密 SM2 签名 / SM3 哈希)。
|
||||||
|
内容哈希在链外用 SHA-256 计算(哈希SDK),链上仅存哈希值与映射,明文不入链(需求20-AC2)。
|
||||||
|
|
||||||
|
## 状态键设计(KV)
|
||||||
|
|
||||||
|
```
|
||||||
|
content:{maCode} -> Content JSON
|
||||||
|
binding:{maCode}:{idx} -> HashBinding JSON
|
||||||
|
hashidx:{fileHash} -> maCode (防换壳重发)
|
||||||
|
mapping:{maCode}:{idx} -> Mapping JSON
|
||||||
|
version:{maCode}:{idx} -> VersionChange JSON
|
||||||
|
ctid2ma:{ctid} -> maCode
|
||||||
|
```
|
||||||
|
|
||||||
|
## 构建与部署(真实链,二期接入)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 依赖 ChainMaker contract SDK
|
||||||
|
go mod init tcs_registry
|
||||||
|
# 编译为 wasm 或 docker-go 合约,按 ChainMaker 部署流程发布
|
||||||
|
```
|
||||||
|
|
||||||
|
> MVP 阶段:业务逻辑与规则已在 `internal/chain.MemoryChain` 完整实现并测试通过,
|
||||||
|
> 本合约为真实链落地的等价实现规格,二期搭建 ChainMaker 测试网后落地替换。
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
-- TCS-IPTV 初始化迁移
|
||||||
|
-- 说明:链上为权威数据源;PostgreSQL 存业务元数据与链上数据镜像,用于高效查询。
|
||||||
|
-- 对应需求:需求16(数据结构)、需求3/6/7(映射)、需求12(版本变更)
|
||||||
|
-- 注:CTID 概念列统一命名为 content_twin_id,避开 PostgreSQL 系统保留列名 ctid。
|
||||||
|
|
||||||
|
BEGIN;
|
||||||
|
|
||||||
|
-- 内容主表(Content Registry 镜像)
|
||||||
|
CREATE TABLE IF NOT EXISTS content_registry (
|
||||||
|
content_twin_id VARCHAR(64) PRIMARY KEY,
|
||||||
|
ma_code VARCHAR(128) NOT NULL UNIQUE,
|
||||||
|
ma_type VARCHAR(64),
|
||||||
|
title VARCHAR(256) NOT NULL,
|
||||||
|
episode_count INT DEFAULT 1,
|
||||||
|
status VARCHAR(32) NOT NULL DEFAULT 'pending',
|
||||||
|
issuer VARCHAR(128),
|
||||||
|
issue_date DATE,
|
||||||
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||||
|
);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_content_status ON content_registry(status);
|
||||||
|
|
||||||
|
-- 哈希绑定表(Hash Binding 镜像)
|
||||||
|
CREATE TABLE IF NOT EXISTS hash_binding (
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
content_twin_id VARCHAR(64) NOT NULL REFERENCES content_registry(content_twin_id),
|
||||||
|
hash_type VARCHAR(32) NOT NULL, -- file_sha256 / perceptual / transcoded
|
||||||
|
hash_value VARCHAR(128) NOT NULL,
|
||||||
|
merkle_root VARCHAR(128),
|
||||||
|
file_format VARCHAR(64),
|
||||||
|
resolution VARCHAR(32),
|
||||||
|
duration INT,
|
||||||
|
version VARCHAR(32) NOT NULL DEFAULT 'v1.0',
|
||||||
|
parent_hash VARCHAR(128), -- 转码版指向母版哈希(父子关系)
|
||||||
|
created_by VARCHAR(128),
|
||||||
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||||
|
);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_hash_ctid ON hash_binding(content_twin_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_hash_value ON hash_binding(hash_value);
|
||||||
|
|
||||||
|
-- 三方编码映射表(Identity Mapping 镜像)
|
||||||
|
CREATE TABLE IF NOT EXISTS identity_mapping (
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
content_twin_id VARCHAR(64) NOT NULL REFERENCES content_registry(content_twin_id),
|
||||||
|
party VARCHAR(32) NOT NULL, -- cp / reviewer / operator
|
||||||
|
party_id VARCHAR(128) NOT NULL,
|
||||||
|
party_name VARCHAR(128),
|
||||||
|
cdn_endpoint VARCHAR(256),
|
||||||
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
|
UNIQUE (content_twin_id, party, party_id)
|
||||||
|
);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_mapping_ctid ON identity_mapping(content_twin_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_mapping_party ON identity_mapping(party, party_id);
|
||||||
|
|
||||||
|
-- 版本变更表(Version History 镜像)
|
||||||
|
CREATE TABLE IF NOT EXISTS version_history (
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
content_twin_id VARCHAR(64) NOT NULL REFERENCES content_registry(content_twin_id),
|
||||||
|
version VARCHAR(32) NOT NULL,
|
||||||
|
change_reason TEXT,
|
||||||
|
prev_hash VARCHAR(128),
|
||||||
|
new_hash VARCHAR(128),
|
||||||
|
reaudit_required BOOLEAN NOT NULL DEFAULT TRUE,
|
||||||
|
reaudit_status VARCHAR(32) DEFAULT 'pending',
|
||||||
|
affected_episode INT,
|
||||||
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||||
|
);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_version_ctid ON version_history(content_twin_id);
|
||||||
|
|
||||||
|
-- 链交易记录(异步上链确认)
|
||||||
|
CREATE TABLE IF NOT EXISTS chain_tx (
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
content_twin_id VARCHAR(64),
|
||||||
|
tx_id VARCHAR(128) NOT NULL UNIQUE,
|
||||||
|
method VARCHAR(64) NOT NULL, -- issueMA / registerMapping / ...
|
||||||
|
status VARCHAR(16) NOT NULL DEFAULT 'pending', -- pending / confirmed / failed
|
||||||
|
block_height BIGINT,
|
||||||
|
payload_hash VARCHAR(128),
|
||||||
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
|
confirmed_at TIMESTAMPTZ
|
||||||
|
);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_tx_ctid ON chain_tx(content_twin_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_tx_status ON chain_tx(status);
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
-- MA 码号段游标表(模式B 自行发码的原子分配)
|
||||||
|
-- 保证多实例/重启下序列不重号、不丢号。对应需求3-AC3/AC4。
|
||||||
|
|
||||||
|
BEGIN;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS macode_cursor (
|
||||||
|
segment_key VARCHAR(128) PRIMARY KEY, -- {industryNode}:{orgNode}:{category}
|
||||||
|
cursor BIGINT NOT NULL, -- 已分配的最大序列
|
||||||
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
COMMENT ON TABLE macode_cursor IS 'MA码号段分配游标,行级原子自增';
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
-- 集级哈希粒度:一剧一 MA 码,每集独立哈希绑定(episode > 0)。
|
||||||
|
-- 对应需求3(集级粒度补齐)、需求12(按集定位)。
|
||||||
|
|
||||||
|
BEGIN;
|
||||||
|
|
||||||
|
ALTER TABLE hash_binding
|
||||||
|
ADD COLUMN IF NOT EXISTS episode INT NOT NULL DEFAULT 0; -- 0=整剧/单体,>0=具体集
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_hash_episode ON hash_binding(content_twin_id, episode);
|
||||||
|
|
||||||
|
COMMENT ON COLUMN hash_binding.episode IS '集号:0表示整剧/单体内容,>0表示具体集';
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
module github.com/tcs-iptv/tcs
|
||||||
|
|
||||||
|
go 1.23
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/gin-gonic/gin v1.10.0
|
||||||
|
github.com/lib/pq v1.12.3
|
||||||
|
github.com/stretchr/testify v1.9.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/bytedance/sonic v1.11.6 // indirect
|
||||||
|
github.com/bytedance/sonic/loader v0.1.1 // indirect
|
||||||
|
github.com/cloudwego/base64x v0.1.4 // indirect
|
||||||
|
github.com/cloudwego/iasm v0.2.0 // indirect
|
||||||
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
||||||
|
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||||
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
|
github.com/go-playground/validator/v10 v10.20.0 // indirect
|
||||||
|
github.com/goccy/go-json v0.10.2 // indirect
|
||||||
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
||||||
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
|
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||||
|
golang.org/x/arch v0.8.0 // indirect
|
||||||
|
golang.org/x/crypto v0.23.0 // indirect
|
||||||
|
golang.org/x/net v0.25.0 // indirect
|
||||||
|
golang.org/x/sys v0.20.0 // indirect
|
||||||
|
golang.org/x/text v0.15.0 // indirect
|
||||||
|
google.golang.org/protobuf v1.34.1 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
)
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
|
||||||
|
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
|
||||||
|
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
|
||||||
|
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||||
|
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
|
||||||
|
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
||||||
|
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
|
||||||
|
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
||||||
|
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||||
|
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||||
|
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
|
||||||
|
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
|
||||||
|
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||||
|
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||||
|
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||||
|
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||||
|
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||||
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||||
|
github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
|
||||||
|
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||||
|
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||||
|
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||||
|
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||||
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||||
|
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||||
|
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||||
|
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||||
|
github.com/lib/pq v1.12.3 h1:tTWxr2YLKwIvK90ZXEw8GP7UFHtcbTtty8zsI+YjrfQ=
|
||||||
|
github.com/lib/pq v1.12.3/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA=
|
||||||
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||||
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
|
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||||
|
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||||
|
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
|
||||||
|
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||||
|
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||||
|
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
|
||||||
|
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||||
|
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
||||||
|
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||||
|
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||||
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||||
|
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
||||||
|
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
|
||||||
|
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||||
|
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||||
@@ -0,0 +1,388 @@
|
|||||||
|
// Package api 暴露 TCS-IPTV 的 HTTP 接口,串联 service 业务编排。
|
||||||
|
// 对应需求17(接口规范)与各业务需求。
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/tcs-iptv/tcs/internal/chain"
|
||||||
|
"github.com/tcs-iptv/tcs/internal/httpx"
|
||||||
|
"github.com/tcs-iptv/tcs/internal/model"
|
||||||
|
"github.com/tcs-iptv/tcs/internal/service"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Handler 持有业务服务。
|
||||||
|
type Handler struct {
|
||||||
|
svc *service.Service
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewHandler 创建 API 处理器。
|
||||||
|
func NewHandler(svc *service.Service) *Handler {
|
||||||
|
return &Handler{svc: svc}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register 注册路由(受鉴权中间件保护的路由组由调用方组装)。
|
||||||
|
func (h *Handler) Register(rg *gin.RouterGroup) {
|
||||||
|
rg.POST("/content/register", h.register) // CP 送审上链(需求2)
|
||||||
|
rg.POST("/content/csps-result", h.cspsResult) // CSPS 合规审核(发码前,需求5)
|
||||||
|
rg.POST("/content/issue", h.issue) // 审核通过后发码签发(需求3)
|
||||||
|
rg.POST("/content/verify", h.verify) // 哈希验真(需求4/7)
|
||||||
|
rg.POST("/content/transcoded", h.bindTranscoded) // 转码版绑定(需求5)
|
||||||
|
rg.POST("/content/ingest", h.ingest) // 媒资库入库(需求6)
|
||||||
|
rg.POST("/content/publish", h.publish) // 发布给运营商(需求6)
|
||||||
|
rg.POST("/content/inject", h.inject) // CDN 注入校验(需求7)
|
||||||
|
rg.POST("/content/version-change", h.versionChange) // 版本变更重审(需求12)
|
||||||
|
rg.POST("/content/takedown", h.takedown) // 应急下架(需求11)
|
||||||
|
rg.POST("/content/takedown-episode", h.takedownEpisode) // 集级下架(只下架某集)
|
||||||
|
rg.POST("/content/restore", h.restore) // 恢复上架整剧
|
||||||
|
rg.POST("/content/restore-episode", h.restoreEpisode) // 恢复上架某集
|
||||||
|
rg.GET("/content/mappings", h.mappings) // 映射查询(需求11/17)
|
||||||
|
rg.POST("/content/verify-episode", h.verifyEpisode) // 集级验真(一剧多集)
|
||||||
|
rg.GET("/content/episodes", h.listEpisodes) // 列出集级哈希
|
||||||
|
rg.GET("/content/reviews", h.listReviews) // 送审待办队列(待审/待发码)
|
||||||
|
rg.GET("/content/list", h.listContents) // 内容队列(待入库/待发布/待注入)
|
||||||
|
}
|
||||||
|
|
||||||
|
func roleOf(c *gin.Context) chain.Role {
|
||||||
|
return chain.Role(httpx.RoleFromContext(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- handlers ---
|
||||||
|
|
||||||
|
type episodeHashReq struct {
|
||||||
|
Episode int `json:"episode"`
|
||||||
|
FileSHA256 string `json:"file_sha256"`
|
||||||
|
MerkleRoot string `json:"merkle_root"`
|
||||||
|
Perceptual string `json:"perceptual_hash"`
|
||||||
|
Duration int `json:"duration"`
|
||||||
|
Resolution string `json:"resolution"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type registerReq struct {
|
||||||
|
Title string `json:"title"`
|
||||||
|
EpisodeCount int `json:"episode_count"`
|
||||||
|
Category string `json:"category"`
|
||||||
|
FileHash string `json:"file_sha256"`
|
||||||
|
MerkleRoot string `json:"merkle_root"`
|
||||||
|
Perceptual string `json:"perceptual_hash"`
|
||||||
|
Episodes []episodeHashReq `json:"episodes"`
|
||||||
|
CPMediaID string `json:"cp_media_id"`
|
||||||
|
CPName string `json:"cp_name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) register(c *gin.Context) {
|
||||||
|
var req registerReq
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
httpx.Error(c, http.StatusBadRequest, "INVALID_REQUEST", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
eps := make([]model.EpisodeHash, 0, len(req.Episodes))
|
||||||
|
for _, e := range req.Episodes {
|
||||||
|
eps = append(eps, model.EpisodeHash{
|
||||||
|
Episode: e.Episode, FileSHA256: e.FileSHA256, MerkleRoot: e.MerkleRoot,
|
||||||
|
Perceptual: e.Perceptual, Duration: e.Duration, Resolution: e.Resolution,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
res, err := h.svc.SubmitForReview(service.Submission{
|
||||||
|
Title: req.Title, EpisodeCount: req.EpisodeCount, Category: req.Category,
|
||||||
|
FileHash: req.FileHash, MerkleRoot: req.MerkleRoot, Perceptual: req.Perceptual,
|
||||||
|
Episodes: eps,
|
||||||
|
CPMediaID: req.CPMediaID, CPName: req.CPName,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
httpx.Error(c, http.StatusBadRequest, "REGISTER_FAILED", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
httpx.Accepted(c, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
type issueReq struct {
|
||||||
|
ReviewID string `json:"review_id"`
|
||||||
|
Issuer string `json:"issuer"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) issue(c *gin.Context) {
|
||||||
|
var req issueReq
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
httpx.Error(c, http.StatusBadRequest, "INVALID_REQUEST", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res, err := h.svc.ApproveAndIssue(roleOf(c), req.ReviewID, req.Issuer)
|
||||||
|
if err != nil {
|
||||||
|
httpx.Error(c, http.StatusForbidden, "ISSUE_FAILED", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
httpx.OK(c, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
type verifyReq struct {
|
||||||
|
MACode string `json:"ma_code"`
|
||||||
|
FileHash string `json:"file_sha256"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) verify(c *gin.Context) {
|
||||||
|
var req verifyReq
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
httpx.Error(c, http.StatusBadRequest, "INVALID_REQUEST", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res, err := h.svc.Verify(req.MACode, req.FileHash)
|
||||||
|
if err != nil {
|
||||||
|
// 验真不匹配也返回结果体,便于调用方据 match 处理
|
||||||
|
httpx.Error(c, http.StatusBadRequest, "VERIFY_MISMATCH", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
httpx.OK(c, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
type cspsReq struct {
|
||||||
|
ReviewID string `json:"review_id"`
|
||||||
|
Approved bool `json:"approved"`
|
||||||
|
ReviewerID string `json:"reviewer_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) cspsResult(c *gin.Context) {
|
||||||
|
var req cspsReq
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
httpx.Error(c, http.StatusBadRequest, "INVALID_REQUEST", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := h.svc.ReviewCSPS(req.ReviewID, req.Approved, req.ReviewerID); err != nil {
|
||||||
|
httpx.Error(c, http.StatusBadRequest, "CSPS_FAILED", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
httpx.OK(c, gin.H{"review_id": req.ReviewID, "approved": req.Approved})
|
||||||
|
}
|
||||||
|
|
||||||
|
type transcodedReq struct {
|
||||||
|
CTID string `json:"content_twin_id"`
|
||||||
|
ParentFileHash string `json:"parent_file_hash"`
|
||||||
|
TranscodedHash string `json:"transcoded_hash"`
|
||||||
|
Format string `json:"format"`
|
||||||
|
Resolution string `json:"resolution"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) bindTranscoded(c *gin.Context) {
|
||||||
|
var req transcodedReq
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
httpx.Error(c, http.StatusBadRequest, "INVALID_REQUEST", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tx, err := h.svc.BindTranscoded(roleOf(c), req.CTID, req.ParentFileHash,
|
||||||
|
req.TranscodedHash, req.Format, req.Resolution, req.Version)
|
||||||
|
if err != nil {
|
||||||
|
httpx.Error(c, http.StatusBadRequest, "TRANSCODE_BIND_FAILED", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
httpx.OK(c, gin.H{"tx_id": tx})
|
||||||
|
}
|
||||||
|
|
||||||
|
type ingestReq struct {
|
||||||
|
MACode string `json:"ma_code"`
|
||||||
|
CTID string `json:"content_twin_id"`
|
||||||
|
MediaAssetID string `json:"media_asset_id"`
|
||||||
|
LibName string `json:"lib_name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) ingest(c *gin.Context) {
|
||||||
|
var req ingestReq
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
httpx.Error(c, http.StatusBadRequest, "INVALID_REQUEST", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := h.svc.IngestToLibrary(roleOf(c), req.MACode, req.CTID, req.MediaAssetID, req.LibName); err != nil {
|
||||||
|
httpx.Error(c, http.StatusBadRequest, "INGEST_FAILED", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
httpx.OK(c, gin.H{"ma_code": req.MACode, "status": "in_library"})
|
||||||
|
}
|
||||||
|
|
||||||
|
type publishReq struct {
|
||||||
|
MACode string `json:"ma_code"`
|
||||||
|
Certificate string `json:"certificate"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) publish(c *gin.Context) {
|
||||||
|
var req publishReq
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
httpx.Error(c, http.StatusBadRequest, "INVALID_REQUEST", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := h.svc.PublishToOperator(service.PublishRequest{MACode: req.MACode, Certificate: req.Certificate}); err != nil {
|
||||||
|
httpx.Error(c, http.StatusBadRequest, "PUBLISH_FAILED", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
httpx.OK(c, gin.H{"ma_code": req.MACode, "status": "published"})
|
||||||
|
}
|
||||||
|
|
||||||
|
type injectReq struct {
|
||||||
|
CTID string `json:"content_twin_id"`
|
||||||
|
MACode string `json:"ma_code"`
|
||||||
|
FileHash string `json:"file_sha256"`
|
||||||
|
OperatorID string `json:"operator_id"`
|
||||||
|
CDNEndpoint string `json:"cdn_endpoint"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) inject(c *gin.Context) {
|
||||||
|
var req injectReq
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
httpx.Error(c, http.StatusBadRequest, "INVALID_REQUEST", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res, err := h.svc.InjectToCDN(roleOf(c), req.CTID, req.MACode, req.FileHash, req.OperatorID, req.CDNEndpoint)
|
||||||
|
if err != nil {
|
||||||
|
httpx.Error(c, http.StatusBadRequest, "INJECT_REJECTED", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
httpx.OK(c, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
type versionChangeReq struct {
|
||||||
|
CTID string `json:"content_twin_id"`
|
||||||
|
Reason string `json:"reason"`
|
||||||
|
PrevHash string `json:"prev_hash"`
|
||||||
|
NewHash string `json:"new_hash"`
|
||||||
|
OldSegments []string `json:"old_segments"`
|
||||||
|
NewSegments []string `json:"new_segments"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) versionChange(c *gin.Context) {
|
||||||
|
var req versionChangeReq
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
httpx.Error(c, http.StatusBadRequest, "INVALID_REQUEST", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
episodes, err := h.svc.ReportVersionChange(req.CTID, req.Reason, req.PrevHash, req.NewHash, req.OldSegments, req.NewSegments)
|
||||||
|
if err != nil {
|
||||||
|
httpx.Error(c, http.StatusBadRequest, "VERSION_CHANGE_FAILED", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
httpx.OK(c, gin.H{"reaudit_required": true, "affected_episodes": episodes})
|
||||||
|
}
|
||||||
|
|
||||||
|
type takedownReq struct {
|
||||||
|
MACode string `json:"ma_code"`
|
||||||
|
Reason string `json:"reason"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) takedown(c *gin.Context) {
|
||||||
|
var req takedownReq
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
httpx.Error(c, http.StatusBadRequest, "INVALID_REQUEST", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res, err := h.svc.Takedown(roleOf(c), req.MACode, req.Reason)
|
||||||
|
if err != nil {
|
||||||
|
httpx.Error(c, http.StatusForbidden, "TAKEDOWN_FAILED", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
httpx.OK(c, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
type takedownEpisodeReq struct {
|
||||||
|
MACode string `json:"ma_code"`
|
||||||
|
Episode int `json:"episode"`
|
||||||
|
Reason string `json:"reason"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) takedownEpisode(c *gin.Context) {
|
||||||
|
var req takedownEpisodeReq
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
httpx.Error(c, http.StatusBadRequest, "INVALID_REQUEST", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := h.svc.TakedownEpisode(roleOf(c), req.MACode, req.Episode, req.Reason); err != nil {
|
||||||
|
httpx.Error(c, http.StatusForbidden, "TAKEDOWN_EPISODE_FAILED", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
httpx.OK(c, gin.H{"ma_code": req.MACode, "episode": req.Episode, "revoked": true})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) restore(c *gin.Context) {
|
||||||
|
var req takedownReq
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
httpx.Error(c, http.StatusBadRequest, "INVALID_REQUEST", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := h.svc.Restore(roleOf(c), req.MACode); err != nil {
|
||||||
|
httpx.Error(c, http.StatusForbidden, "RESTORE_FAILED", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
httpx.OK(c, gin.H{"ma_code": req.MACode, "status": "published"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) restoreEpisode(c *gin.Context) {
|
||||||
|
var req takedownEpisodeReq
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
httpx.Error(c, http.StatusBadRequest, "INVALID_REQUEST", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := h.svc.RestoreEpisode(roleOf(c), req.MACode, req.Episode); err != nil {
|
||||||
|
httpx.Error(c, http.StatusForbidden, "RESTORE_EPISODE_FAILED", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
httpx.OK(c, gin.H{"ma_code": req.MACode, "episode": req.Episode, "revoked": false})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) mappings(c *gin.Context) {
|
||||||
|
maCode := c.Query("ma_code")
|
||||||
|
if maCode == "" {
|
||||||
|
httpx.Error(c, http.StatusBadRequest, "INVALID_REQUEST", "缺少 ma_code")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res, err := h.svc.QueryMappings(maCode)
|
||||||
|
if err != nil {
|
||||||
|
httpx.Error(c, http.StatusNotFound, "NOT_FOUND", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
httpx.OK(c, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
type verifyEpisodeReq struct {
|
||||||
|
MACode string `json:"ma_code"`
|
||||||
|
Episode int `json:"episode"`
|
||||||
|
FileHash string `json:"file_sha256"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) verifyEpisode(c *gin.Context) {
|
||||||
|
var req verifyEpisodeReq
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
httpx.Error(c, http.StatusBadRequest, "INVALID_REQUEST", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res, err := h.svc.VerifyEpisode(req.MACode, req.Episode, req.FileHash)
|
||||||
|
if err != nil {
|
||||||
|
httpx.Error(c, http.StatusBadRequest, "VERIFY_MISMATCH", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
httpx.OK(c, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) listEpisodes(c *gin.Context) {
|
||||||
|
maCode := c.Query("ma_code")
|
||||||
|
if maCode == "" {
|
||||||
|
httpx.Error(c, http.StatusBadRequest, "INVALID_REQUEST", "缺少 ma_code")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
eps, err := h.svc.ListEpisodes(maCode)
|
||||||
|
if err != nil {
|
||||||
|
httpx.Error(c, http.StatusNotFound, "NOT_FOUND", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
httpx.OK(c, gin.H{"ma_code": maCode, "episodes": eps, "count": len(eps)})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) listReviews(c *gin.Context) {
|
||||||
|
httpx.OK(c, gin.H{"reviews": h.svc.ListReviews(c.Query("status"))})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) listContents(c *gin.Context) {
|
||||||
|
list, err := h.svc.ListContentsByStatus(c.Query("status"))
|
||||||
|
if err != nil {
|
||||||
|
httpx.Error(c, http.StatusInternalServerError, "INTERNAL_ERROR", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
httpx.OK(c, gin.H{"contents": list, "count": len(list)})
|
||||||
|
}
|
||||||
@@ -0,0 +1,271 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/tcs-iptv/tcs/internal/chain"
|
||||||
|
"github.com/tcs-iptv/tcs/internal/hash"
|
||||||
|
"github.com/tcs-iptv/tcs/internal/httpx"
|
||||||
|
"github.com/tcs-iptv/tcs/internal/macode"
|
||||||
|
"github.com/tcs-iptv/tcs/internal/service"
|
||||||
|
)
|
||||||
|
|
||||||
|
// testServer 组装完整 API 栈(鉴权 + 路由 + service + 内存链/号段)。
|
||||||
|
func testServer(t *testing.T) (*httptest.Server, *httpx.MemoryKeyStore) {
|
||||||
|
t.Helper()
|
||||||
|
gin.SetMode(gin.TestMode)
|
||||||
|
|
||||||
|
ch := chain.NewMemoryChain()
|
||||||
|
gen := macode.NewGenerator(macode.NewMemoryStore())
|
||||||
|
require.NoError(t, gen.RegisterSegment(macode.Segment{
|
||||||
|
IndustryNode: "8531", OrgNode: "4401",
|
||||||
|
Category: macode.CategoryMicroDrama, Start: 1, End: 9999999, SeqWidth: 7,
|
||||||
|
}))
|
||||||
|
svc := service.New(ch, gen)
|
||||||
|
h := NewHandler(svc)
|
||||||
|
|
||||||
|
keys := httpx.NewMemoryKeyStore()
|
||||||
|
keys.Add("ak-regulator", "sk-regulator", string(chain.RoleRegulator))
|
||||||
|
keys.Add("ak-reviewer", "sk-reviewer", string(chain.RoleReviewer))
|
||||||
|
keys.Add("ak-cp", "sk-cp", string(chain.RoleCP))
|
||||||
|
keys.Add("ak-operator", "sk-operator", string(chain.RoleOperator))
|
||||||
|
|
||||||
|
r := gin.New()
|
||||||
|
v1 := r.Group("/api/v1", httpx.AuthMiddleware(keys))
|
||||||
|
h.Register(v1)
|
||||||
|
return httptest.NewServer(r), keys
|
||||||
|
}
|
||||||
|
|
||||||
|
// signedCall 发起带 HMAC 签名的请求,返回状态码与解析后的响应。
|
||||||
|
func signedCall(t *testing.T, base, apiKey, secret, method, path string, body any) (int, map[string]any) {
|
||||||
|
t.Helper()
|
||||||
|
var buf []byte
|
||||||
|
if body != nil {
|
||||||
|
buf, _ = json.Marshal(body)
|
||||||
|
}
|
||||||
|
signPath := "/api/v1" + path
|
||||||
|
if i := indexByte(path, '?'); i >= 0 {
|
||||||
|
signPath = "/api/v1" + path[:i]
|
||||||
|
}
|
||||||
|
sig := httpx.Sign(secret, method, signPath)
|
||||||
|
|
||||||
|
req, err := http.NewRequest(method, base+"/api/v1"+path, bytes.NewReader(buf))
|
||||||
|
require.NoError(t, err)
|
||||||
|
req.Header.Set("Authorization", "TCS "+apiKey+":"+sig)
|
||||||
|
if body != nil {
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
}
|
||||||
|
resp, err := http.DefaultClient.Do(req)
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
var out map[string]any
|
||||||
|
_ = json.NewDecoder(resp.Body).Decode(&out)
|
||||||
|
return resp.StatusCode, out
|
||||||
|
}
|
||||||
|
|
||||||
|
func indexByte(s string, b byte) int {
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
if s[i] == b {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataOf(m map[string]any) map[string]any {
|
||||||
|
if d, ok := m["data"].(map[string]any); ok {
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
return map[string]any{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestE2E_FullLifecycle 覆盖 MVP 全闭环:送审→发码→审核→入库→发布→注入→下架。
|
||||||
|
func TestE2E_FullLifecycle(t *testing.T) {
|
||||||
|
srv, _ := testServer(t)
|
||||||
|
defer srv.Close()
|
||||||
|
b := srv.URL
|
||||||
|
|
||||||
|
// 1) CP 送审
|
||||||
|
st, resp := signedCall(t, b, "ak-cp", "sk-cp", "POST", "/content/register", map[string]any{
|
||||||
|
"title": "示例微短剧", "episode_count": 24, "category": "WD",
|
||||||
|
"file_sha256": "fh-e2e", "merkle_root": "mr-e2e", "perceptual_hash": "ph-e2e",
|
||||||
|
"cp_media_id": "FS-77821", "cp_name": "飞翮信息",
|
||||||
|
})
|
||||||
|
require.Equal(t, http.StatusAccepted, st)
|
||||||
|
reviewID := dataOf(resp)["review_id"].(string)
|
||||||
|
ctid := dataOf(resp)["content_twin_id"].(string)
|
||||||
|
require.NotEmpty(t, reviewID)
|
||||||
|
|
||||||
|
// 2) CSPS 合规审核(发码前)
|
||||||
|
st, _ = signedCall(t, b, "ak-reviewer", "sk-reviewer", "POST", "/content/csps-result", map[string]any{
|
||||||
|
"review_id": reviewID, "approved": true, "reviewer_id": "rv-1",
|
||||||
|
})
|
||||||
|
require.Equal(t, http.StatusOK, st)
|
||||||
|
|
||||||
|
// 3) 监管发码签发(审核通过后)
|
||||||
|
st, resp = signedCall(t, b, "ak-regulator", "sk-regulator", "POST", "/content/issue", map[string]any{
|
||||||
|
"review_id": reviewID, "issuer": "北京市广播电视局",
|
||||||
|
})
|
||||||
|
require.Equal(t, http.StatusOK, st)
|
||||||
|
maCode := dataOf(resp)["ma_code"].(string)
|
||||||
|
cert := dataOf(resp)["certificate"].(string)
|
||||||
|
assert.True(t, macode.IsValid(maCode))
|
||||||
|
|
||||||
|
// 4) 入媒资库
|
||||||
|
st, _ = signedCall(t, b, "ak-reviewer", "sk-reviewer", "POST", "/content/ingest", map[string]any{
|
||||||
|
"ma_code": maCode, "content_twin_id": ctid, "media_asset_id": "MEDIA-001", "lib_name": "广东IPTV媒资库",
|
||||||
|
})
|
||||||
|
require.Equal(t, http.StatusOK, st)
|
||||||
|
|
||||||
|
// 5) 发布
|
||||||
|
st, _ = signedCall(t, b, "ak-reviewer", "sk-reviewer", "POST", "/content/publish", map[string]any{
|
||||||
|
"ma_code": maCode, "certificate": cert,
|
||||||
|
})
|
||||||
|
require.Equal(t, http.StatusOK, st)
|
||||||
|
|
||||||
|
// 6) CDN 注入(匹配)
|
||||||
|
st, resp = signedCall(t, b, "ak-operator", "sk-operator", "POST", "/content/inject", map[string]any{
|
||||||
|
"content_twin_id": ctid, "ma_code": maCode, "file_sha256": "fh-e2e",
|
||||||
|
"operator_id": "CT-IPTV-GD", "cdn_endpoint": "cdn://ct-gd/vod/1",
|
||||||
|
})
|
||||||
|
require.Equal(t, http.StatusOK, st)
|
||||||
|
assert.Equal(t, true, dataOf(resp)["allowed"])
|
||||||
|
|
||||||
|
// 7) 映射查询
|
||||||
|
st, resp = signedCall(t, b, "ak-regulator", "sk-regulator", "GET", "/content/mappings?ma_code="+maCode, nil)
|
||||||
|
require.Equal(t, http.StatusOK, st)
|
||||||
|
mappings := dataOf(resp)["mappings"].([]any)
|
||||||
|
assert.Len(t, mappings, 3) // cp + reviewer + operator
|
||||||
|
|
||||||
|
// 8) 监管下架
|
||||||
|
st, resp = signedCall(t, b, "ak-regulator", "sk-regulator", "POST", "/content/takedown", map[string]any{
|
||||||
|
"ma_code": maCode, "reason": "违规",
|
||||||
|
})
|
||||||
|
require.Equal(t, http.StatusOK, st)
|
||||||
|
assert.NotEmpty(t, dataOf(resp)["cdn_endpoints"])
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestE2E_TamperRejected 版本篡改专项:注入篡改文件应被拒绝(需求7/15/18-AC4)。
|
||||||
|
func TestE2E_TamperRejected(t *testing.T) {
|
||||||
|
srv, _ := testServer(t)
|
||||||
|
defer srv.Close()
|
||||||
|
b := srv.URL
|
||||||
|
|
||||||
|
st, resp := signedCall(t, b, "ak-cp", "sk-cp", "POST", "/content/register", map[string]any{
|
||||||
|
"title": "X", "episode_count": 1, "category": "WD",
|
||||||
|
"file_sha256": "fh-orig", "merkle_root": "mr-orig",
|
||||||
|
})
|
||||||
|
require.Equal(t, http.StatusAccepted, st)
|
||||||
|
reviewID := dataOf(resp)["review_id"].(string)
|
||||||
|
ctid := dataOf(resp)["content_twin_id"].(string)
|
||||||
|
|
||||||
|
signedCall(t, b, "ak-reviewer", "sk-reviewer", "POST", "/content/csps-result", map[string]any{"review_id": reviewID, "approved": true})
|
||||||
|
_, resp = signedCall(t, b, "ak-regulator", "sk-regulator", "POST", "/content/issue", map[string]any{
|
||||||
|
"review_id": reviewID, "issuer": "x",
|
||||||
|
})
|
||||||
|
maCode := dataOf(resp)["ma_code"].(string)
|
||||||
|
cert := dataOf(resp)["certificate"].(string)
|
||||||
|
signedCall(t, b, "ak-reviewer", "sk-reviewer", "POST", "/content/ingest", map[string]any{"ma_code": maCode, "content_twin_id": ctid, "media_asset_id": "M", "lib_name": "L"})
|
||||||
|
signedCall(t, b, "ak-reviewer", "sk-reviewer", "POST", "/content/publish", map[string]any{"ma_code": maCode, "certificate": cert})
|
||||||
|
|
||||||
|
// 篡改文件注入 → 拒绝
|
||||||
|
st, _ = signedCall(t, b, "ak-operator", "sk-operator", "POST", "/content/inject", map[string]any{
|
||||||
|
"content_twin_id": ctid, "ma_code": maCode, "file_sha256": "fh-TAMPERED",
|
||||||
|
"operator_id": "OP", "cdn_endpoint": "cdn://x",
|
||||||
|
})
|
||||||
|
assert.Equal(t, http.StatusBadRequest, st, "篡改注入必须被拒")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestE2E_VersionChangeLocatesEpisode 版本变更定位被篡改集(需求12-AC3)。
|
||||||
|
func TestE2E_VersionChangeLocatesEpisode(t *testing.T) {
|
||||||
|
srv, _ := testServer(t)
|
||||||
|
defer srv.Close()
|
||||||
|
b := srv.URL
|
||||||
|
|
||||||
|
st, resp := signedCall(t, b, "ak-cp", "sk-cp", "POST", "/content/register", map[string]any{
|
||||||
|
"title": "多集剧", "episode_count": 3, "category": "WD",
|
||||||
|
"file_sha256": "fh-multi", "merkle_root": "mr-multi",
|
||||||
|
})
|
||||||
|
require.Equal(t, http.StatusAccepted, st)
|
||||||
|
reviewID := dataOf(resp)["review_id"].(string)
|
||||||
|
ctid := dataOf(resp)["content_twin_id"].(string)
|
||||||
|
signedCall(t, b, "ak-reviewer", "sk-reviewer", "POST", "/content/csps-result", map[string]any{"review_id": reviewID, "approved": true})
|
||||||
|
signedCall(t, b, "ak-regulator", "sk-regulator", "POST", "/content/issue", map[string]any{"review_id": reviewID, "issuer": "x"})
|
||||||
|
|
||||||
|
old := []string{hash.SHA256Hex([]byte("ep1")), hash.SHA256Hex([]byte("ep2")), hash.SHA256Hex([]byte("ep3"))}
|
||||||
|
neu := []string{hash.SHA256Hex([]byte("ep1")), hash.SHA256Hex([]byte("ep2-X")), hash.SHA256Hex([]byte("ep3"))}
|
||||||
|
|
||||||
|
st, resp = signedCall(t, b, "ak-reviewer", "sk-reviewer", "POST", "/content/version-change", map[string]any{
|
||||||
|
"content_twin_id": ctid, "reason": "第2集替换",
|
||||||
|
"prev_hash": "mr-multi", "new_hash": "mr-new",
|
||||||
|
"old_segments": old, "new_segments": neu,
|
||||||
|
})
|
||||||
|
require.Equal(t, http.StatusOK, st)
|
||||||
|
eps := dataOf(resp)["affected_episodes"].([]any)
|
||||||
|
require.Len(t, eps, 1)
|
||||||
|
assert.Equal(t, float64(2), eps[0], "应定位到第2集")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestE2E_PermissionMatrix 权限矩阵:越权操作被拒(需求14)。
|
||||||
|
func TestE2E_PermissionMatrix(t *testing.T) {
|
||||||
|
srv, _ := testServer(t)
|
||||||
|
defer srv.Close()
|
||||||
|
b := srv.URL
|
||||||
|
|
||||||
|
// 准备一条已签发内容
|
||||||
|
_, resp := signedCall(t, b, "ak-cp", "sk-cp", "POST", "/content/register", map[string]any{
|
||||||
|
"title": "P", "episode_count": 1, "category": "WD", "file_sha256": "fh-perm", "merkle_root": "mr-perm",
|
||||||
|
})
|
||||||
|
reviewID := dataOf(resp)["review_id"].(string)
|
||||||
|
|
||||||
|
// 先过 CSPS 审核(否则发码会因未审核被拒,无法测到角色权限)
|
||||||
|
signedCall(t, b, "ak-reviewer", "sk-reviewer", "POST", "/content/csps-result", map[string]any{"review_id": reviewID, "approved": true})
|
||||||
|
|
||||||
|
// CP 越权发码(签发仅监管主体)→ 403
|
||||||
|
st, _ := signedCall(t, b, "ak-cp", "sk-cp", "POST", "/content/issue", map[string]any{"review_id": reviewID, "issuer": "x"})
|
||||||
|
assert.Equal(t, http.StatusForbidden, st, "CP 不得发码")
|
||||||
|
|
||||||
|
// 正常签发
|
||||||
|
_, resp = signedCall(t, b, "ak-regulator", "sk-regulator", "POST", "/content/issue", map[string]any{"review_id": reviewID, "issuer": "x"})
|
||||||
|
maCode := dataOf(resp)["ma_code"].(string)
|
||||||
|
|
||||||
|
// 运营商越权下架 → 403
|
||||||
|
st, _ = signedCall(t, b, "ak-operator", "sk-operator", "POST", "/content/takedown", map[string]any{"ma_code": maCode, "reason": "越权"})
|
||||||
|
assert.Equal(t, http.StatusForbidden, st, "运营商不得发起下架")
|
||||||
|
|
||||||
|
// 无效签名 → 401
|
||||||
|
req, _ := http.NewRequest("GET", b+"/api/v1/content/mappings?ma_code="+maCode, nil)
|
||||||
|
req.Header.Set("Authorization", "TCS ak-regulator:badsig")
|
||||||
|
r, _ := http.DefaultClient.Do(req)
|
||||||
|
assert.Equal(t, http.StatusUnauthorized, r.StatusCode, "错误签名应 401")
|
||||||
|
r.Body.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestE2E_TakedownLatency 下架时效:端到端应远快于分钟级(需求11/18-AC1)。
|
||||||
|
func TestE2E_TakedownLatency(t *testing.T) {
|
||||||
|
srv, _ := testServer(t)
|
||||||
|
defer srv.Close()
|
||||||
|
b := srv.URL
|
||||||
|
|
||||||
|
_, resp := signedCall(t, b, "ak-cp", "sk-cp", "POST", "/content/register", map[string]any{
|
||||||
|
"title": "L", "episode_count": 1, "category": "WD", "file_sha256": "fh-lat", "merkle_root": "mr-lat",
|
||||||
|
})
|
||||||
|
reviewID := dataOf(resp)["review_id"].(string)
|
||||||
|
signedCall(t, b, "ak-reviewer", "sk-reviewer", "POST", "/content/csps-result", map[string]any{"review_id": reviewID, "approved": true})
|
||||||
|
_, resp = signedCall(t, b, "ak-regulator", "sk-regulator", "POST", "/content/issue", map[string]any{"review_id": reviewID, "issuer": "x"})
|
||||||
|
maCode := dataOf(resp)["ma_code"].(string)
|
||||||
|
|
||||||
|
start := time.Now()
|
||||||
|
st, _ := signedCall(t, b, "ak-regulator", "sk-regulator", "POST", "/content/takedown", map[string]any{"ma_code": maCode, "reason": "违规"})
|
||||||
|
elapsed := time.Since(start)
|
||||||
|
require.Equal(t, http.StatusOK, st)
|
||||||
|
assert.Less(t, elapsed, time.Second, "下架端到端应在秒级内(目标分钟级)")
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
// Package chain 定义可信数据空间(联盟链)的客户端抽象。
|
||||||
|
// MVP 提供内存 mock 实现,使业务逻辑可在无真实 ChainMaker 网络时开发与测试;
|
||||||
|
// 后续以 ChainMaker Go SDK 实现替换,接口不变。
|
||||||
|
// 对应需求:需求16(智能合约方法)、需求3/4(签发与验真)、需求14(权限)。
|
||||||
|
package chain
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/tcs-iptv/tcs/internal/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Role 调用方角色,用于合约级权限控制(需求14)。
|
||||||
|
type Role string
|
||||||
|
|
||||||
|
const (
|
||||||
|
RoleRegulator Role = "regulator" // 监管主体:唯一可 issueMA / 下架
|
||||||
|
RoleReviewer Role = "reviewer" // 审核主体(CSPS/媒资库)
|
||||||
|
RoleCP Role = "cp" // 内容提供商
|
||||||
|
RoleOperator Role = "operator" // 运营商
|
||||||
|
)
|
||||||
|
|
||||||
|
// 错误定义。
|
||||||
|
var (
|
||||||
|
ErrPermissionDenied = errors.New("chain: permission denied")
|
||||||
|
ErrMANotIssued = errors.New("chain: MA not issued")
|
||||||
|
ErrMAAlreadyIssued = errors.New("chain: MA already issued (1:1 binding immutable)")
|
||||||
|
ErrHashExists = errors.New("chain: content hash already exists")
|
||||||
|
ErrNotFound = errors.New("chain: not found")
|
||||||
|
)
|
||||||
|
|
||||||
|
// IssueRequest 签发 MA 码并强绑定哈希包。
|
||||||
|
type IssueRequest struct {
|
||||||
|
MACode string
|
||||||
|
ContentTwinID string
|
||||||
|
MerkleRoot string
|
||||||
|
FileHash string
|
||||||
|
PerceptualHash string
|
||||||
|
Episodes []model.EpisodeHash // 集级哈希(分集内容)
|
||||||
|
Content model.Content
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyResult 哈希验真结果(需求4-AC4)。
|
||||||
|
type VerifyResult struct {
|
||||||
|
Valid bool `json:"valid"`
|
||||||
|
MACode string `json:"ma_code"`
|
||||||
|
BoundHash string `json:"bound_hash"`
|
||||||
|
SubmittedHash string `json:"submitted_hash"`
|
||||||
|
Match bool `json:"match"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MappingsResult 映射查询结果(需求11/17)。
|
||||||
|
type MappingsResult struct {
|
||||||
|
MACode string `json:"ma_code"`
|
||||||
|
Mappings []model.Mapping `json:"mappings"`
|
||||||
|
CDNEndpoints []string `json:"cdn_endpoints"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client 是可信数据空间的统一访问接口。
|
||||||
|
// 业务服务只依赖此接口,不感知底层是 mock 还是 ChainMaker。
|
||||||
|
type Client interface {
|
||||||
|
// IssueMA 签发 MA 码并与哈希包 1:1 强绑定(仅监管主体)。
|
||||||
|
IssueMA(role Role, req IssueRequest) (txID string, err error)
|
||||||
|
// RegisterHashBinding 追加哈希绑定(如转码版,建立父子关系)。
|
||||||
|
RegisterHashBinding(role Role, b model.HashBinding) (txID string, err error)
|
||||||
|
// RegisterMapping 注册三方编码映射(MA 必须已签发)。
|
||||||
|
RegisterMapping(role Role, m model.Mapping) (txID string, err error)
|
||||||
|
// VerifyHash 按 MA 码校验提交哈希是否与绑定哈希一致。
|
||||||
|
VerifyHash(maCode, fileHash string) (VerifyResult, error)
|
||||||
|
// VerifyEpisodeHash 按 MA 码+集号校验该集哈希。
|
||||||
|
VerifyEpisodeHash(maCode string, episode int, fileHash string) (VerifyResult, error)
|
||||||
|
// ListEpisodes 返回某 MA 码下的全部集级哈希绑定。
|
||||||
|
ListEpisodes(maCode string) ([]model.HashBinding, error)
|
||||||
|
// HashExists 判断内容哈希是否已存在(防换壳重发)。
|
||||||
|
HashExists(fileHash string) (maCode string, exists bool)
|
||||||
|
// QueryContent 查询内容主记录。
|
||||||
|
QueryContent(maCode string) (model.Content, error)
|
||||||
|
// ListContents 按状态列出内容(空状态返回全部)。
|
||||||
|
ListContents(status string) ([]model.Content, error)
|
||||||
|
// QueryMappings 查询 MA 码绑定的全部三方映射与 CDN 端点。
|
||||||
|
QueryMappings(maCode string) (MappingsResult, error)
|
||||||
|
// RecordVersionChange 记录版本变更(绑定断裂触发重审)。
|
||||||
|
RecordVersionChange(vc model.VersionChange) (txID string, err error)
|
||||||
|
// Revoke 下架(仅监管主体),返回受影响的映射。
|
||||||
|
Revoke(role Role, maCode, reason string) (MappingsResult, error)
|
||||||
|
// RevokeEpisode 集级下架(仅监管主体):只下架指定集,整剧其他集不受影响。
|
||||||
|
RevokeEpisode(role Role, maCode string, episode int, reason string) error
|
||||||
|
// Restore 恢复上架整剧(仅监管主体):下架状态恢复为流通中。
|
||||||
|
Restore(role Role, maCode string) error
|
||||||
|
// RestoreEpisode 恢复上架指定集(仅监管主体)。
|
||||||
|
RestoreEpisode(role Role, maCode string, episode int) error
|
||||||
|
// SetContentStatus 更新内容状态。
|
||||||
|
SetContentStatus(maCode, status string) error
|
||||||
|
}
|
||||||
@@ -0,0 +1,396 @@
|
|||||||
|
package chain
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/tcs-iptv/tcs/internal/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MemoryChain 是 Client 的内存实现(MVP / 测试用)。
|
||||||
|
// 严格执行合约级业务规则:签发权限、1:1 不可解绑、映射前置签发、防重复哈希。
|
||||||
|
type MemoryChain struct {
|
||||||
|
mu sync.RWMutex
|
||||||
|
contents map[string]model.Content // maCode -> Content
|
||||||
|
bindings map[string][]model.HashBinding // maCode -> bindings
|
||||||
|
mappings map[string][]model.Mapping // maCode -> mappings
|
||||||
|
versions map[string][]model.VersionChange
|
||||||
|
hashIndex map[string]string // fileHash -> maCode(防换壳重发)
|
||||||
|
txSeq int
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMemoryChain 创建内存链客户端。
|
||||||
|
func NewMemoryChain() *MemoryChain {
|
||||||
|
return &MemoryChain{
|
||||||
|
contents: make(map[string]model.Content),
|
||||||
|
bindings: make(map[string][]model.HashBinding),
|
||||||
|
mappings: make(map[string][]model.Mapping),
|
||||||
|
versions: make(map[string][]model.VersionChange),
|
||||||
|
hashIndex: make(map[string]string),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MemoryChain) nextTx(method string) string {
|
||||||
|
m.txSeq++
|
||||||
|
return fmt.Sprintf("tx-%s-%06d", method, m.txSeq)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IssueMA 仅监管主体可调用;MA 不可重复签发;哈希 1:1 强绑定不可解绑。
|
||||||
|
func (m *MemoryChain) IssueMA(role Role, req IssueRequest) (string, error) {
|
||||||
|
if role != RoleRegulator {
|
||||||
|
return "", ErrPermissionDenied
|
||||||
|
}
|
||||||
|
m.mu.Lock()
|
||||||
|
defer m.mu.Unlock()
|
||||||
|
|
||||||
|
if _, ok := m.contents[req.MACode]; ok {
|
||||||
|
return "", ErrMAAlreadyIssued
|
||||||
|
}
|
||||||
|
if existing, ok := m.hashIndex[req.FileHash]; ok {
|
||||||
|
return "", fmt.Errorf("%w: bound to %s", ErrHashExists, existing)
|
||||||
|
}
|
||||||
|
|
||||||
|
c := req.Content
|
||||||
|
c.MACode = req.MACode
|
||||||
|
c.ContentTwinID = req.ContentTwinID
|
||||||
|
c.Status = model.StatusApproved
|
||||||
|
if c.CreatedAt.IsZero() {
|
||||||
|
c.CreatedAt = time.Now()
|
||||||
|
}
|
||||||
|
m.contents[req.MACode] = c
|
||||||
|
|
||||||
|
m.bindings[req.MACode] = []model.HashBinding{{
|
||||||
|
ContentTwinID: req.ContentTwinID,
|
||||||
|
HashType: model.HashFile,
|
||||||
|
HashValue: req.FileHash,
|
||||||
|
MerkleRoot: req.MerkleRoot,
|
||||||
|
Version: "v1.0",
|
||||||
|
CreatedBy: string(RoleRegulator),
|
||||||
|
}}
|
||||||
|
if req.PerceptualHash != "" {
|
||||||
|
m.bindings[req.MACode] = append(m.bindings[req.MACode], model.HashBinding{
|
||||||
|
ContentTwinID: req.ContentTwinID,
|
||||||
|
HashType: model.HashPerceptual,
|
||||||
|
HashValue: req.PerceptualHash,
|
||||||
|
Version: "v1.0",
|
||||||
|
CreatedBy: string(RoleRegulator),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
m.hashIndex[req.FileHash] = req.MACode
|
||||||
|
|
||||||
|
// 集级哈希绑定(分集内容):每集独立哈希,挂在同一 MA 码下。
|
||||||
|
for _, ep := range req.Episodes {
|
||||||
|
m.bindings[req.MACode] = append(m.bindings[req.MACode], model.HashBinding{
|
||||||
|
ContentTwinID: req.ContentTwinID,
|
||||||
|
HashType: model.HashFile,
|
||||||
|
HashValue: ep.FileSHA256,
|
||||||
|
MerkleRoot: ep.MerkleRoot,
|
||||||
|
Episode: ep.Episode,
|
||||||
|
Resolution: ep.Resolution,
|
||||||
|
Duration: ep.Duration,
|
||||||
|
Version: "v1.0",
|
||||||
|
CreatedBy: string(RoleRegulator),
|
||||||
|
})
|
||||||
|
if ep.FileSHA256 != "" {
|
||||||
|
if _, ok := m.hashIndex[ep.FileSHA256]; !ok {
|
||||||
|
m.hashIndex[ep.FileSHA256] = req.MACode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m.nextTx("issueMA"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterHashBinding 追加哈希绑定(如转码版)。MA 必须已签发。
|
||||||
|
func (m *MemoryChain) RegisterHashBinding(role Role, b model.HashBinding) (string, error) {
|
||||||
|
if role != RoleReviewer && role != RoleRegulator {
|
||||||
|
return "", ErrPermissionDenied
|
||||||
|
}
|
||||||
|
m.mu.Lock()
|
||||||
|
defer m.mu.Unlock()
|
||||||
|
|
||||||
|
maCode := m.maCodeByCTID(b.ContentTwinID)
|
||||||
|
if maCode == "" {
|
||||||
|
return "", ErrMANotIssued
|
||||||
|
}
|
||||||
|
m.bindings[maCode] = append(m.bindings[maCode], b)
|
||||||
|
if b.HashType == model.HashFile || b.HashType == model.HashTranscoded {
|
||||||
|
if _, ok := m.hashIndex[b.HashValue]; !ok {
|
||||||
|
m.hashIndex[b.HashValue] = maCode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m.nextTx("registerHashBinding"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterMapping 注册三方编码映射;MA 必须已签发(需求16-AC3)。
|
||||||
|
func (m *MemoryChain) RegisterMapping(role Role, mp model.Mapping) (string, error) {
|
||||||
|
m.mu.Lock()
|
||||||
|
defer m.mu.Unlock()
|
||||||
|
|
||||||
|
maCode := m.maCodeByCTID(mp.ContentTwinID)
|
||||||
|
if maCode == "" {
|
||||||
|
return "", ErrMANotIssued
|
||||||
|
}
|
||||||
|
m.mappings[maCode] = append(m.mappings[maCode], mp)
|
||||||
|
return m.nextTx("registerMapping"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyHash 按 MA 码校验提交哈希。
|
||||||
|
func (m *MemoryChain) VerifyHash(maCode, fileHash string) (VerifyResult, error) {
|
||||||
|
m.mu.RLock()
|
||||||
|
defer m.mu.RUnlock()
|
||||||
|
|
||||||
|
bs, ok := m.bindings[maCode]
|
||||||
|
if !ok {
|
||||||
|
return VerifyResult{Valid: false, MACode: maCode, SubmittedHash: fileHash}, ErrMANotIssued
|
||||||
|
}
|
||||||
|
for _, b := range bs {
|
||||||
|
if b.HashType == model.HashFile || b.HashType == model.HashTranscoded {
|
||||||
|
if b.HashValue == fileHash {
|
||||||
|
return VerifyResult{
|
||||||
|
Valid: true, MACode: maCode,
|
||||||
|
BoundHash: b.HashValue, SubmittedHash: fileHash,
|
||||||
|
Match: true, Version: b.Version,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 取首个文件哈希作为 bound 参考
|
||||||
|
bound := ""
|
||||||
|
for _, b := range bs {
|
||||||
|
if b.HashType == model.HashFile {
|
||||||
|
bound = b.HashValue
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return VerifyResult{Valid: true, MACode: maCode, BoundHash: bound, SubmittedHash: fileHash, Match: false}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// HashExists 判断内容哈希是否已存在。
|
||||||
|
func (m *MemoryChain) HashExists(fileHash string) (string, bool) {
|
||||||
|
m.mu.RLock()
|
||||||
|
defer m.mu.RUnlock()
|
||||||
|
ma, ok := m.hashIndex[fileHash]
|
||||||
|
return ma, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyEpisodeHash 按 MA 码+集号校验该集哈希。
|
||||||
|
func (m *MemoryChain) VerifyEpisodeHash(maCode string, episode int, fileHash string) (VerifyResult, error) {
|
||||||
|
m.mu.RLock()
|
||||||
|
defer m.mu.RUnlock()
|
||||||
|
bs, ok := m.bindings[maCode]
|
||||||
|
if !ok {
|
||||||
|
return VerifyResult{Valid: false, MACode: maCode, SubmittedHash: fileHash}, ErrMANotIssued
|
||||||
|
}
|
||||||
|
var bound string
|
||||||
|
for _, b := range bs {
|
||||||
|
if b.Episode == episode && (b.HashType == model.HashFile || b.HashType == model.HashTranscoded) {
|
||||||
|
if bound == "" {
|
||||||
|
bound = b.HashValue
|
||||||
|
}
|
||||||
|
if b.HashValue == fileHash {
|
||||||
|
return VerifyResult{
|
||||||
|
Valid: true, MACode: maCode,
|
||||||
|
BoundHash: b.HashValue, SubmittedHash: fileHash,
|
||||||
|
Match: true, Version: b.Version,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if bound == "" {
|
||||||
|
return VerifyResult{Valid: false, MACode: maCode, SubmittedHash: fileHash}, ErrNotFound
|
||||||
|
}
|
||||||
|
return VerifyResult{Valid: true, MACode: maCode, BoundHash: bound, SubmittedHash: fileHash, Match: false}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListEpisodes 返回某 MA 码下的全部集级哈希绑定(episode > 0)。
|
||||||
|
func (m *MemoryChain) ListEpisodes(maCode string) ([]model.HashBinding, error) {
|
||||||
|
m.mu.RLock()
|
||||||
|
defer m.mu.RUnlock()
|
||||||
|
bs, ok := m.bindings[maCode]
|
||||||
|
if !ok {
|
||||||
|
return nil, ErrMANotIssued
|
||||||
|
}
|
||||||
|
var out []model.HashBinding
|
||||||
|
for _, b := range bs {
|
||||||
|
if b.Episode > 0 {
|
||||||
|
out = append(out, b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueryContent 查询内容主记录。
|
||||||
|
func (m *MemoryChain) QueryContent(maCode string) (model.Content, error) {
|
||||||
|
m.mu.RLock()
|
||||||
|
defer m.mu.RUnlock()
|
||||||
|
c, ok := m.contents[maCode]
|
||||||
|
if !ok {
|
||||||
|
return model.Content{}, ErrNotFound
|
||||||
|
}
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListContents 按状态列出内容(空状态返回全部),附带整剧文件哈希便于演示。
|
||||||
|
func (m *MemoryChain) ListContents(status string) ([]model.Content, error) {
|
||||||
|
m.mu.RLock()
|
||||||
|
defer m.mu.RUnlock()
|
||||||
|
var out []model.Content
|
||||||
|
for ma, c := range m.contents {
|
||||||
|
if status == "" || c.Status == status {
|
||||||
|
// 附带整剧文件哈希(episode==0 的 file 绑定)
|
||||||
|
for _, b := range m.bindings[ma] {
|
||||||
|
if b.HashType == model.HashFile && b.Episode == 0 {
|
||||||
|
c.FileHash = b.HashValue
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out = append(out, c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueryMappings 查询 MA 码绑定的全部映射与 CDN 端点。
|
||||||
|
func (m *MemoryChain) QueryMappings(maCode string) (MappingsResult, error) {
|
||||||
|
m.mu.RLock()
|
||||||
|
defer m.mu.RUnlock()
|
||||||
|
if _, ok := m.contents[maCode]; !ok {
|
||||||
|
return MappingsResult{}, ErrNotFound
|
||||||
|
}
|
||||||
|
res := MappingsResult{MACode: maCode, Mappings: m.mappings[maCode]}
|
||||||
|
for _, mp := range m.mappings[maCode] {
|
||||||
|
if mp.CDNEndpoint != "" {
|
||||||
|
res.CDNEndpoints = append(res.CDNEndpoints, mp.CDNEndpoint)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RecordVersionChange 记录版本变更。
|
||||||
|
func (m *MemoryChain) RecordVersionChange(vc model.VersionChange) (string, error) {
|
||||||
|
m.mu.Lock()
|
||||||
|
defer m.mu.Unlock()
|
||||||
|
maCode := m.maCodeByCTID(vc.ContentTwinID)
|
||||||
|
if maCode == "" {
|
||||||
|
return "", ErrMANotIssued
|
||||||
|
}
|
||||||
|
m.versions[maCode] = append(m.versions[maCode], vc)
|
||||||
|
return m.nextTx("recordVersionChange"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Revoke 下架,仅监管主体。
|
||||||
|
func (m *MemoryChain) Revoke(role Role, maCode, reason string) (MappingsResult, error) {
|
||||||
|
if role != RoleRegulator {
|
||||||
|
return MappingsResult{}, ErrPermissionDenied
|
||||||
|
}
|
||||||
|
m.mu.Lock()
|
||||||
|
defer m.mu.Unlock()
|
||||||
|
c, ok := m.contents[maCode]
|
||||||
|
if !ok {
|
||||||
|
return MappingsResult{}, ErrNotFound
|
||||||
|
}
|
||||||
|
c.Status = model.StatusRevoked
|
||||||
|
m.contents[maCode] = c
|
||||||
|
|
||||||
|
res := MappingsResult{MACode: maCode, Mappings: m.mappings[maCode]}
|
||||||
|
for _, mp := range m.mappings[maCode] {
|
||||||
|
if mp.CDNEndpoint != "" {
|
||||||
|
res.CDNEndpoints = append(res.CDNEndpoints, mp.CDNEndpoint)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RevokeEpisode 集级下架:只下架指定集,整剧其他集不受影响(仅监管主体)。
|
||||||
|
func (m *MemoryChain) RevokeEpisode(role Role, maCode string, episode int, reason string) error {
|
||||||
|
if role != RoleRegulator {
|
||||||
|
return ErrPermissionDenied
|
||||||
|
}
|
||||||
|
m.mu.Lock()
|
||||||
|
defer m.mu.Unlock()
|
||||||
|
bs, ok := m.bindings[maCode]
|
||||||
|
if !ok {
|
||||||
|
return ErrMANotIssued
|
||||||
|
}
|
||||||
|
found := false
|
||||||
|
for i := range bs {
|
||||||
|
if bs[i].Episode == episode {
|
||||||
|
bs[i].Revoked = true
|
||||||
|
bs[i].RevokedReason = reason
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
return ErrNotFound
|
||||||
|
}
|
||||||
|
m.bindings[maCode] = bs
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore 恢复上架整剧:下架状态恢复为流通中(仅监管主体)。
|
||||||
|
func (m *MemoryChain) Restore(role Role, maCode string) error {
|
||||||
|
if role != RoleRegulator {
|
||||||
|
return ErrPermissionDenied
|
||||||
|
}
|
||||||
|
m.mu.Lock()
|
||||||
|
defer m.mu.Unlock()
|
||||||
|
c, ok := m.contents[maCode]
|
||||||
|
if !ok {
|
||||||
|
return ErrNotFound
|
||||||
|
}
|
||||||
|
c.Status = model.StatusPublished
|
||||||
|
m.contents[maCode] = c
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RestoreEpisode 恢复上架指定集(仅监管主体)。
|
||||||
|
func (m *MemoryChain) RestoreEpisode(role Role, maCode string, episode int) error {
|
||||||
|
if role != RoleRegulator {
|
||||||
|
return ErrPermissionDenied
|
||||||
|
}
|
||||||
|
m.mu.Lock()
|
||||||
|
defer m.mu.Unlock()
|
||||||
|
bs, ok := m.bindings[maCode]
|
||||||
|
if !ok {
|
||||||
|
return ErrMANotIssued
|
||||||
|
}
|
||||||
|
found := false
|
||||||
|
for i := range bs {
|
||||||
|
if bs[i].Episode == episode {
|
||||||
|
bs[i].Revoked = false
|
||||||
|
bs[i].RevokedReason = ""
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
return ErrNotFound
|
||||||
|
}
|
||||||
|
m.bindings[maCode] = bs
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetContentStatus 更新内容状态。
|
||||||
|
func (m *MemoryChain) SetContentStatus(maCode, status string) error {
|
||||||
|
m.mu.Lock()
|
||||||
|
defer m.mu.Unlock()
|
||||||
|
c, ok := m.contents[maCode]
|
||||||
|
if !ok {
|
||||||
|
return ErrNotFound
|
||||||
|
}
|
||||||
|
c.Status = status
|
||||||
|
m.contents[maCode] = c
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// maCodeByCTID 内部辅助:通过 CTID 反查 MA 码(调用方已持锁)。
|
||||||
|
func (m *MemoryChain) maCodeByCTID(ctid string) string {
|
||||||
|
for ma, c := range m.contents {
|
||||||
|
if c.ContentTwinID == ctid {
|
||||||
|
return ma
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ Client = (*MemoryChain)(nil)
|
||||||
@@ -0,0 +1,149 @@
|
|||||||
|
package chain
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/tcs-iptv/tcs/internal/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newIssued(t *testing.T) *MemoryChain {
|
||||||
|
t.Helper()
|
||||||
|
c := NewMemoryChain()
|
||||||
|
_, err := c.IssueMA(RoleRegulator, IssueRequest{
|
||||||
|
MACode: "(京)网微剧审字(2025)第123号",
|
||||||
|
ContentTwinID: "ctid-001",
|
||||||
|
MerkleRoot: "merkle-root-1",
|
||||||
|
FileHash: "filehash-1",
|
||||||
|
Content: model.Content{Title: "示例剧集", EpisodeCount: 24},
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIssueMA_OnlyRegulator(t *testing.T) {
|
||||||
|
c := NewMemoryChain()
|
||||||
|
_, err := c.IssueMA(RoleCP, IssueRequest{MACode: "MA-1", ContentTwinID: "ct-1", FileHash: "h1"})
|
||||||
|
assert.ErrorIs(t, err, ErrPermissionDenied)
|
||||||
|
|
||||||
|
_, err = c.IssueMA(RoleReviewer, IssueRequest{MACode: "MA-1", ContentTwinID: "ct-1", FileHash: "h1"})
|
||||||
|
assert.ErrorIs(t, err, ErrPermissionDenied)
|
||||||
|
|
||||||
|
_, err = c.IssueMA(RoleRegulator, IssueRequest{MACode: "MA-1", ContentTwinID: "ct-1", FileHash: "h1"})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIssueMA_NoReissue(t *testing.T) {
|
||||||
|
c := newIssued(t)
|
||||||
|
// 同 MA 码重复签发被拒(1:1 不可解绑/不可覆盖)
|
||||||
|
_, err := c.IssueMA(RoleRegulator, IssueRequest{
|
||||||
|
MACode: "(京)网微剧审字(2025)第123号", ContentTwinID: "ctid-001", FileHash: "other",
|
||||||
|
})
|
||||||
|
assert.ErrorIs(t, err, ErrMAAlreadyIssued)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIssueMA_DuplicateHashRejected(t *testing.T) {
|
||||||
|
c := newIssued(t)
|
||||||
|
// 换壳重发:不同 MA 码但相同内容哈希 → 拒绝
|
||||||
|
_, err := c.IssueMA(RoleRegulator, IssueRequest{
|
||||||
|
MACode: "(沪)网微剧审字(2025)第999号", ContentTwinID: "ctid-002", FileHash: "filehash-1",
|
||||||
|
})
|
||||||
|
assert.ErrorIs(t, err, ErrHashExists)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVerifyHash_MatchAndMismatch(t *testing.T) {
|
||||||
|
c := newIssued(t)
|
||||||
|
|
||||||
|
res, err := c.VerifyHash("(京)网微剧审字(2025)第123号", "filehash-1")
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.True(t, res.Match)
|
||||||
|
assert.True(t, res.Valid)
|
||||||
|
|
||||||
|
res, err = c.VerifyHash("(京)网微剧审字(2025)第123号", "tampered-hash")
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.False(t, res.Match)
|
||||||
|
assert.Equal(t, "filehash-1", res.BoundHash)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVerifyHash_UnknownMA(t *testing.T) {
|
||||||
|
c := NewMemoryChain()
|
||||||
|
_, err := c.VerifyHash("no-such-ma", "h")
|
||||||
|
assert.ErrorIs(t, err, ErrMANotIssued)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRegisterMapping_RequiresIssuedMA(t *testing.T) {
|
||||||
|
c := NewMemoryChain()
|
||||||
|
// CTID 未签发 → 拒绝
|
||||||
|
_, err := c.RegisterMapping(RoleOperator, model.Mapping{
|
||||||
|
ContentTwinID: "ctid-x", Party: model.PartyOperator, PartyID: "OP-1",
|
||||||
|
})
|
||||||
|
assert.ErrorIs(t, err, ErrMANotIssued)
|
||||||
|
|
||||||
|
c = newIssued(t)
|
||||||
|
_, err = c.RegisterMapping(RoleOperator, model.Mapping{
|
||||||
|
ContentTwinID: "ctid-001", Party: model.PartyOperator,
|
||||||
|
PartyID: "CT-IPTV-008923", CDNEndpoint: "cdn://ct-gd/iptv/vod/008923",
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
res, err := c.QueryMappings("(京)网微剧审字(2025)第123号")
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Len(t, res.Mappings, 1)
|
||||||
|
assert.Equal(t, []string{"cdn://ct-gd/iptv/vod/008923"}, res.CDNEndpoints)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTranscodedBinding_ParentChild(t *testing.T) {
|
||||||
|
c := newIssued(t)
|
||||||
|
_, err := c.RegisterHashBinding(RoleReviewer, model.HashBinding{
|
||||||
|
ContentTwinID: "ctid-001",
|
||||||
|
HashType: model.HashTranscoded,
|
||||||
|
HashValue: "transcoded-h265-4k",
|
||||||
|
ParentHash: "filehash-1",
|
||||||
|
Version: "v1.0-h265",
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// 转码版哈希也能验真通过
|
||||||
|
res, err := c.VerifyHash("(京)网微剧审字(2025)第123号", "transcoded-h265-4k")
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.True(t, res.Match)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRevoke_OnlyRegulator(t *testing.T) {
|
||||||
|
c := newIssued(t)
|
||||||
|
_, _ = c.RegisterMapping(RoleOperator, model.Mapping{
|
||||||
|
ContentTwinID: "ctid-001", Party: model.PartyOperator,
|
||||||
|
PartyID: "OP-1", CDNEndpoint: "cdn://x/y/z",
|
||||||
|
})
|
||||||
|
|
||||||
|
_, err := c.Revoke(RoleOperator, "(京)网微剧审字(2025)第123号", "试图越权")
|
||||||
|
assert.ErrorIs(t, err, ErrPermissionDenied)
|
||||||
|
|
||||||
|
res, err := c.Revoke(RoleRegulator, "(京)网微剧审字(2025)第123号", "违规")
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Contains(t, res.CDNEndpoints, "cdn://x/y/z")
|
||||||
|
|
||||||
|
ct, _ := c.QueryContent("(京)网微剧审字(2025)第123号")
|
||||||
|
assert.Equal(t, model.StatusRevoked, ct.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRecordVersionChange(t *testing.T) {
|
||||||
|
c := newIssued(t)
|
||||||
|
_, err := c.RecordVersionChange(model.VersionChange{
|
||||||
|
ContentTwinID: "ctid-001", Version: "v2.0",
|
||||||
|
ChangeReason: "片尾字幕修正", PrevHash: "filehash-1", NewHash: "filehash-2",
|
||||||
|
ReauditRequired: true, AffectedEpisode: 24,
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHashExists(t *testing.T) {
|
||||||
|
c := newIssued(t)
|
||||||
|
ma, ok := c.HashExists("filehash-1")
|
||||||
|
assert.True(t, ok)
|
||||||
|
assert.Equal(t, "(京)网微剧审字(2025)第123号", ma)
|
||||||
|
|
||||||
|
_, ok = c.HashExists("unknown")
|
||||||
|
assert.False(t, ok)
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Config 保存服务运行所需的通用配置。
|
||||||
|
// MVP 阶段从环境变量加载,缺省值适配本地开发。
|
||||||
|
type Config struct {
|
||||||
|
APIAddr string
|
||||||
|
ChainAddr string
|
||||||
|
HashAddr string
|
||||||
|
PostgresDSN string
|
||||||
|
RedisAddr string
|
||||||
|
}
|
||||||
|
|
||||||
|
func getEnv(key, def string) string {
|
||||||
|
if v := os.Getenv(key); v != "" {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
return def
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load 从环境变量加载配置。
|
||||||
|
func Load() Config {
|
||||||
|
return Config{
|
||||||
|
APIAddr: getEnv("TCS_API_ADDR", ":8080"),
|
||||||
|
ChainAddr: getEnv("TCS_CHAIN_ADDR", ":8081"),
|
||||||
|
HashAddr: getEnv("TCS_HASH_ADDR", ":8082"),
|
||||||
|
PostgresDSN: getEnv("TCS_POSTGRES_DSN", "postgres://postgres@localhost:5432/tcs_iptv?sslmode=disable"),
|
||||||
|
RedisAddr: getEnv("TCS_REDIS_ADDR", "localhost:6379"),
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
package hash
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func writeTempFile(t *testing.T, data []byte) string {
|
||||||
|
t.Helper()
|
||||||
|
dir := t.TempDir()
|
||||||
|
p := filepath.Join(dir, "master.bin")
|
||||||
|
require.NoError(t, os.WriteFile(p, data, 0o644))
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSHA256Hex_Deterministic(t *testing.T) {
|
||||||
|
a := SHA256Hex([]byte("hello"))
|
||||||
|
b := SHA256Hex([]byte("hello"))
|
||||||
|
assert.Equal(t, a, b)
|
||||||
|
// 已知向量
|
||||||
|
assert.Equal(t, "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFileSHA256_MatchesBytes(t *testing.T) {
|
||||||
|
data := []byte("the quick brown fox")
|
||||||
|
p := writeTempFile(t, data)
|
||||||
|
got, err := FileSHA256(p)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, SHA256Hex(data), got)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSegmentHashes_SmallSegments(t *testing.T) {
|
||||||
|
// 25 字节,分段 10 → 3 段(10/10/5)
|
||||||
|
data := []byte("0123456789ABCDEFGHIJ12345")
|
||||||
|
p := writeTempFile(t, data)
|
||||||
|
segs, err := SegmentHashes(p, 10)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, segs, 3)
|
||||||
|
assert.Equal(t, SHA256Hex(data[0:10]), segs[0])
|
||||||
|
assert.Equal(t, SHA256Hex(data[10:20]), segs[1])
|
||||||
|
assert.Equal(t, SHA256Hex(data[20:25]), segs[2])
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMerkleTree_RootStableAndChangesOnEdit(t *testing.T) {
|
||||||
|
leaves := []string{
|
||||||
|
SHA256Hex([]byte("ep1")),
|
||||||
|
SHA256Hex([]byte("ep2")),
|
||||||
|
SHA256Hex([]byte("ep3")),
|
||||||
|
SHA256Hex([]byte("ep4")),
|
||||||
|
}
|
||||||
|
root1 := BuildMerkleTree(leaves).Root()
|
||||||
|
root2 := BuildMerkleTree(leaves).Root()
|
||||||
|
assert.Equal(t, root1, root2, "同样叶子根应一致")
|
||||||
|
assert.NotEmpty(t, root1)
|
||||||
|
|
||||||
|
// 改第3集 → 根变化
|
||||||
|
edited := append([]string(nil), leaves...)
|
||||||
|
edited[2] = SHA256Hex([]byte("ep3-tampered"))
|
||||||
|
root3 := BuildMerkleTree(edited).Root()
|
||||||
|
assert.NotEqual(t, root1, root3, "篡改任一集,根必变")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMerkleTree_OddLeaves(t *testing.T) {
|
||||||
|
leaves := []string{
|
||||||
|
SHA256Hex([]byte("a")),
|
||||||
|
SHA256Hex([]byte("b")),
|
||||||
|
SHA256Hex([]byte("c")),
|
||||||
|
}
|
||||||
|
mt := BuildMerkleTree(leaves)
|
||||||
|
assert.NotEmpty(t, mt.Root())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLocateChangedLeaves(t *testing.T) {
|
||||||
|
old := []string{"h1", "h2", "h3", "h4"}
|
||||||
|
neu := []string{"h1", "x2", "h3", "x4"}
|
||||||
|
changed := LocateChangedLeaves(old, neu)
|
||||||
|
assert.Equal(t, []int{1, 3}, changed, "应定位到第2集和第4集被改")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestComputeFile_FullPackage(t *testing.T) {
|
||||||
|
data := make([]byte, 25*1024) // 25KB
|
||||||
|
for i := range data {
|
||||||
|
data[i] = byte(i % 251)
|
||||||
|
}
|
||||||
|
p := writeTempFile(t, data)
|
||||||
|
|
||||||
|
pkg, err := ComputeFile(p, Options{SegmentSize: 10 * 1024})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NoError(t, pkg.Validate())
|
||||||
|
assert.Equal(t, int64(25*1024), pkg.FileSize)
|
||||||
|
assert.Len(t, pkg.SegmentHashes, 3)
|
||||||
|
assert.NotEmpty(t, pkg.MerkleRoot)
|
||||||
|
assert.Equal(t, SHA256Hex(data), pkg.FileSHA256)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestComputeFile_EmptyFileRejected(t *testing.T) {
|
||||||
|
p := writeTempFile(t, []byte{})
|
||||||
|
_, err := ComputeFile(p, Options{})
|
||||||
|
assert.ErrorIs(t, err, ErrEmptyInput)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestComputeFile_MissingFile(t *testing.T) {
|
||||||
|
_, err := ComputeFile("/no/such/file.bin", Options{})
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHashPackage_ValidateMissingFields(t *testing.T) {
|
||||||
|
assert.Error(t, (&HashPackage{MerkleRoot: "x"}).Validate()) // 缺 file_sha256
|
||||||
|
assert.Error(t, (&HashPackage{FileSHA256: "x"}).Validate()) // 缺 merkle_root
|
||||||
|
assert.NoError(t, (&HashPackage{FileSHA256: "a", MerkleRoot: "b"}).Validate())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPerceptualHash_IdenticalAndDifferent(t *testing.T) {
|
||||||
|
// 全黑与全白图,aHash/dHash 应可区分
|
||||||
|
black := make([][]uint8, 16)
|
||||||
|
white := make([][]uint8, 16)
|
||||||
|
grad := make([][]uint8, 16)
|
||||||
|
for y := 0; y < 16; y++ {
|
||||||
|
black[y] = make([]uint8, 16)
|
||||||
|
white[y] = make([]uint8, 16)
|
||||||
|
grad[y] = make([]uint8, 16)
|
||||||
|
for x := 0; x < 16; x++ {
|
||||||
|
white[y][x] = 255
|
||||||
|
grad[y][x] = uint8(x * 16) // 水平渐变
|
||||||
|
}
|
||||||
|
}
|
||||||
|
imgBlack := newGrayTestImage(black)
|
||||||
|
imgWhite := newGrayTestImage(white)
|
||||||
|
imgGrad := newGrayTestImage(grad)
|
||||||
|
|
||||||
|
// 同一图的哈希稳定
|
||||||
|
assert.Equal(t, AHash(imgGrad), AHash(imgGrad))
|
||||||
|
assert.Equal(t, DHash(imgGrad), DHash(imgGrad))
|
||||||
|
|
||||||
|
// 渐变图的 dHash 应与纯色不同
|
||||||
|
assert.NotEqual(t, DHash(imgGrad), DHash(imgBlack))
|
||||||
|
|
||||||
|
// 汉明距离:渐变 vs 纯白 应 > 0
|
||||||
|
d, err := HammingDistance(DHash(imgGrad), DHash(imgWhite))
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Greater(t, d, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHammingDistance_LengthMismatch(t *testing.T) {
|
||||||
|
_, err := HammingDistance("ffff", "ffffffff")
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
package hash
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/hex"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MerkleTree 表示一棵基于 SHA-256 的 Merkle 树。
|
||||||
|
// 叶子为各分段(或各集)的哈希,根用于整体内容的聚合锚定。
|
||||||
|
// 对应需求:需求1-AC2、需求16-AC4(按集定位篡改)。
|
||||||
|
type MerkleTree struct {
|
||||||
|
Leaves []string // 叶子哈希(十六进制)
|
||||||
|
Levels [][]string // 自底向上的各层,Levels[0] 为叶子层
|
||||||
|
}
|
||||||
|
|
||||||
|
// BuildMerkleTree 由叶子哈希构建 Merkle 树。
|
||||||
|
// 当某层节点数为奇数时,复制最后一个节点与自身配对(标准做法)。
|
||||||
|
func BuildMerkleTree(leaves []string) *MerkleTree {
|
||||||
|
mt := &MerkleTree{Leaves: append([]string(nil), leaves...)}
|
||||||
|
if len(leaves) == 0 {
|
||||||
|
mt.Levels = [][]string{{}}
|
||||||
|
return mt
|
||||||
|
}
|
||||||
|
|
||||||
|
level := append([]string(nil), leaves...)
|
||||||
|
mt.Levels = [][]string{level}
|
||||||
|
|
||||||
|
for len(level) > 1 {
|
||||||
|
next := make([]string, 0, (len(level)+1)/2)
|
||||||
|
for i := 0; i < len(level); i += 2 {
|
||||||
|
left := level[i]
|
||||||
|
right := left // 奇数个时与自身配对
|
||||||
|
if i+1 < len(level) {
|
||||||
|
right = level[i+1]
|
||||||
|
}
|
||||||
|
next = append(next, hashPair(left, right))
|
||||||
|
}
|
||||||
|
mt.Levels = append(mt.Levels, next)
|
||||||
|
level = next
|
||||||
|
}
|
||||||
|
return mt
|
||||||
|
}
|
||||||
|
|
||||||
|
// Root 返回 Merkle 根哈希;空树返回空字符串。
|
||||||
|
func (mt *MerkleTree) Root() string {
|
||||||
|
if len(mt.Levels) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
top := mt.Levels[len(mt.Levels)-1]
|
||||||
|
if len(top) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return top[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// hashPair 将两个十六进制哈希拼接后再次 SHA-256。
|
||||||
|
func hashPair(left, right string) string {
|
||||||
|
lb, _ := hex.DecodeString(left)
|
||||||
|
rb, _ := hex.DecodeString(right)
|
||||||
|
h := sha256.New()
|
||||||
|
h.Write(lb)
|
||||||
|
h.Write(rb)
|
||||||
|
return hex.EncodeToString(h.Sum(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// LocateChangedLeaves 比较两组叶子哈希,返回发生变化的叶子索引。
|
||||||
|
// 用于"定位被篡改的具体集"(需求12-AC3)。
|
||||||
|
func LocateChangedLeaves(oldLeaves, newLeaves []string) []int {
|
||||||
|
var changed []int
|
||||||
|
max := len(oldLeaves)
|
||||||
|
if len(newLeaves) > max {
|
||||||
|
max = len(newLeaves)
|
||||||
|
}
|
||||||
|
for i := 0; i < max; i++ {
|
||||||
|
var o, n string
|
||||||
|
if i < len(oldLeaves) {
|
||||||
|
o = oldLeaves[i]
|
||||||
|
}
|
||||||
|
if i < len(newLeaves) {
|
||||||
|
n = newLeaves[i]
|
||||||
|
}
|
||||||
|
if o != n {
|
||||||
|
changed = append(changed, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return changed
|
||||||
|
}
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
package hash
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"image"
|
||||||
|
"image/color"
|
||||||
|
"math/bits"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 感知哈希用于跨格式/转码识别同一内容(需求1-AC3)。
|
||||||
|
// MVP 实现 aHash(均值哈希)与 dHash(差值哈希),输入为已解码的视频代表帧图像。
|
||||||
|
// 真实视频抽帧由上层(ffmpeg)完成,本包专注哈希算法以便独立测试。
|
||||||
|
|
||||||
|
const phashDim = 8 // 8x8 → 64-bit 哈希
|
||||||
|
|
||||||
|
// grayResize 将图像缩放为 w×h 的灰度矩阵(最近邻,零依赖)。
|
||||||
|
func grayResize(img image.Image, w, h int) [][]float64 {
|
||||||
|
b := img.Bounds()
|
||||||
|
srcW, srcH := b.Dx(), b.Dy()
|
||||||
|
out := make([][]float64, h)
|
||||||
|
for y := 0; y < h; y++ {
|
||||||
|
out[y] = make([]float64, w)
|
||||||
|
for x := 0; x < w; x++ {
|
||||||
|
sx := b.Min.X + x*srcW/w
|
||||||
|
sy := b.Min.Y + y*srcH/h
|
||||||
|
r, g, bb, _ := img.At(sx, sy).RGBA()
|
||||||
|
// 转 8 位灰度(ITU-R 601 亮度)
|
||||||
|
gray := 0.299*float64(r>>8) + 0.587*float64(g>>8) + 0.114*float64(bb>>8)
|
||||||
|
out[y][x] = gray
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// AHash 计算均值哈希(64-bit,十六进制 16 字符)。
|
||||||
|
func AHash(img image.Image) string {
|
||||||
|
m := grayResize(img, phashDim, phashDim)
|
||||||
|
var sum float64
|
||||||
|
for y := 0; y < phashDim; y++ {
|
||||||
|
for x := 0; x < phashDim; x++ {
|
||||||
|
sum += m[y][x]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
avg := sum / float64(phashDim*phashDim)
|
||||||
|
|
||||||
|
var hash uint64
|
||||||
|
var bit uint
|
||||||
|
for y := 0; y < phashDim; y++ {
|
||||||
|
for x := 0; x < phashDim; x++ {
|
||||||
|
if m[y][x] >= avg {
|
||||||
|
hash |= 1 << bit
|
||||||
|
}
|
||||||
|
bit++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%016x", hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DHash 计算差值哈希(64-bit)。对水平相邻像素比较亮度。
|
||||||
|
func DHash(img image.Image) string {
|
||||||
|
// 需要 (phashDim+1) 列以产生 phashDim 个差值
|
||||||
|
m := grayResize(img, phashDim+1, phashDim)
|
||||||
|
var hash uint64
|
||||||
|
var bit uint
|
||||||
|
for y := 0; y < phashDim; y++ {
|
||||||
|
for x := 0; x < phashDim; x++ {
|
||||||
|
if m[y][x] < m[y][x+1] {
|
||||||
|
hash |= 1 << bit
|
||||||
|
}
|
||||||
|
bit++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%016x", hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HammingDistance 计算两个等长十六进制哈希的汉明距离。
|
||||||
|
// 距离越小越相似;用于版权比对与跨版本识别。
|
||||||
|
func HammingDistance(a, b string) (int, error) {
|
||||||
|
if len(a) != len(b) {
|
||||||
|
return 0, fmt.Errorf("hash: length mismatch %d vs %d", len(a), len(b))
|
||||||
|
}
|
||||||
|
var va, vb uint64
|
||||||
|
if _, err := fmt.Sscanf(a, "%x", &va); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if _, err := fmt.Sscanf(b, "%x", &vb); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return bits.OnesCount64(va ^ vb), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// newGrayTestImage 是测试辅助:由灰度矩阵生成图像。
|
||||||
|
func newGrayTestImage(gray [][]uint8) image.Image {
|
||||||
|
h := len(gray)
|
||||||
|
w := 0
|
||||||
|
if h > 0 {
|
||||||
|
w = len(gray[0])
|
||||||
|
}
|
||||||
|
img := image.NewGray(image.Rect(0, 0, w, h))
|
||||||
|
for y := 0; y < h; y++ {
|
||||||
|
for x := 0; x < w; x++ {
|
||||||
|
img.SetGray(x, y, color.Gray{Y: gray[y][x]})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return img
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package hash
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HashPackage 是哈希值包,对应需求1-AC5。
|
||||||
|
// 仅包含哈希与元数据,绝不包含原始内容(需求20-AC2)。
|
||||||
|
type HashPackage struct {
|
||||||
|
FileSHA256 string `json:"file_sha256"`
|
||||||
|
MerkleRoot string `json:"merkle_root"`
|
||||||
|
SegmentHashes []string `json:"segment_hashes"`
|
||||||
|
PerceptualHash string `json:"perceptual_hash,omitempty"`
|
||||||
|
FileSize int64 `json:"file_size"`
|
||||||
|
SegmentSize int `json:"segment_size"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Options 控制哈希计算行为。
|
||||||
|
type Options struct {
|
||||||
|
SegmentSize int // 分段大小;<=0 用默认
|
||||||
|
PerceptualHash string // 上层已抽帧并算好的感知哈希(可选)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ComputeFile 对母版文件计算完整哈希值包(文件哈希 + 分段 Merkle)。
|
||||||
|
// 感知哈希需上层先抽帧,再通过 opts.PerceptualHash 传入或单独调用 AHash/DHash。
|
||||||
|
func ComputeFile(path string, opts Options) (*HashPackage, error) {
|
||||||
|
info, err := os.Stat(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("hash: stat file: %w", err)
|
||||||
|
}
|
||||||
|
if info.IsDir() {
|
||||||
|
return nil, fmt.Errorf("hash: path is a directory: %s", path)
|
||||||
|
}
|
||||||
|
if info.Size() == 0 {
|
||||||
|
return nil, ErrEmptyInput
|
||||||
|
}
|
||||||
|
|
||||||
|
segSize := opts.SegmentSize
|
||||||
|
if segSize <= 0 {
|
||||||
|
segSize = DefaultSegmentSize
|
||||||
|
}
|
||||||
|
|
||||||
|
fileHash, err := FileSHA256(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("hash: file sha256: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
segments, err := SegmentHashes(path, segSize)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("hash: segment hashes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tree := BuildMerkleTree(segments)
|
||||||
|
|
||||||
|
return &HashPackage{
|
||||||
|
FileSHA256: fileHash,
|
||||||
|
MerkleRoot: tree.Root(),
|
||||||
|
SegmentHashes: segments,
|
||||||
|
PerceptualHash: opts.PerceptualHash,
|
||||||
|
FileSize: info.Size(),
|
||||||
|
SegmentSize: segSize,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate 校验哈希值包的完整性(需求2-AC5:缺文件哈希/Merkle根则非法)。
|
||||||
|
func (p *HashPackage) Validate() error {
|
||||||
|
if p == nil {
|
||||||
|
return fmt.Errorf("hash: nil package")
|
||||||
|
}
|
||||||
|
if p.FileSHA256 == "" {
|
||||||
|
return fmt.Errorf("hash: missing file_sha256")
|
||||||
|
}
|
||||||
|
if p.MerkleRoot == "" {
|
||||||
|
return fmt.Errorf("hash: missing merkle_root")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
// Package hash 实现 TCS-IPTV 的内容哈希核心:
|
||||||
|
// 文件 SHA-256、分段 Merkle Tree、感知哈希。
|
||||||
|
// 对应需求:需求1(母版哈希生成)。
|
||||||
|
package hash
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DefaultSegmentSize 是分段哈希的默认分段大小(10 MiB)。
|
||||||
|
const DefaultSegmentSize = 10 * 1024 * 1024
|
||||||
|
|
||||||
|
// ErrEmptyInput 表示输入为空。
|
||||||
|
var ErrEmptyInput = errors.New("hash: empty input")
|
||||||
|
|
||||||
|
// SHA256Hex 计算字节切片的 SHA-256,返回十六进制字符串。
|
||||||
|
func SHA256Hex(data []byte) string {
|
||||||
|
sum := sha256.Sum256(data)
|
||||||
|
return hex.EncodeToString(sum[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// FileSHA256 流式计算文件的整体 SHA-256,避免一次性载入大文件。
|
||||||
|
func FileSHA256(path string) (string, error) {
|
||||||
|
f, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
h := sha256.New()
|
||||||
|
if _, err := io.Copy(h, f); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return hex.EncodeToString(h.Sum(nil)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SegmentHashes 按 segmentSize 分段计算文件各段的 SHA-256。
|
||||||
|
// 用于构建 Merkle Tree 的叶子节点。
|
||||||
|
func SegmentHashes(path string, segmentSize int) ([]string, error) {
|
||||||
|
if segmentSize <= 0 {
|
||||||
|
segmentSize = DefaultSegmentSize
|
||||||
|
}
|
||||||
|
f, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
var segments []string
|
||||||
|
buf := make([]byte, segmentSize)
|
||||||
|
for {
|
||||||
|
n, err := io.ReadFull(f, buf)
|
||||||
|
if n > 0 {
|
||||||
|
segments = append(segments, SHA256Hex(buf[:n]))
|
||||||
|
}
|
||||||
|
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return segments, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
package httpx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 鉴权采用 API Key + HMAC-SHA256(需求17-AC4、需求20)。
|
||||||
|
// 请求头:
|
||||||
|
// Authorization: TCS {apiKey}:{signature}
|
||||||
|
// X-TCS-Role: regulator | reviewer | cp | operator
|
||||||
|
// signature = base64(HMAC-SHA256(apiSecret, method+"\n"+path))
|
||||||
|
|
||||||
|
// KeyStore 提供 apiKey -> (apiSecret, role) 的查询。MVP 用内存实现。
|
||||||
|
type KeyStore interface {
|
||||||
|
Lookup(apiKey string) (secret string, role string, ok bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MemoryKeyStore 内存密钥库。
|
||||||
|
type MemoryKeyStore struct {
|
||||||
|
keys map[string]struct {
|
||||||
|
secret string
|
||||||
|
role string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMemoryKeyStore 创建并预置密钥。
|
||||||
|
func NewMemoryKeyStore() *MemoryKeyStore {
|
||||||
|
return &MemoryKeyStore{keys: map[string]struct {
|
||||||
|
secret string
|
||||||
|
role string
|
||||||
|
}{}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add 注册一个密钥及其角色。
|
||||||
|
func (m *MemoryKeyStore) Add(apiKey, secret, role string) {
|
||||||
|
m.keys[apiKey] = struct {
|
||||||
|
secret string
|
||||||
|
role string
|
||||||
|
}{secret, role}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lookup 查询密钥。
|
||||||
|
func (m *MemoryKeyStore) Lookup(apiKey string) (string, string, bool) {
|
||||||
|
v, ok := m.keys[apiKey]
|
||||||
|
return v.secret, v.role, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sign 计算签名(供客户端/测试使用)。
|
||||||
|
func Sign(secret, method, path string) string {
|
||||||
|
mac := hmac.New(sha256.New, []byte(secret))
|
||||||
|
mac.Write([]byte(method + "\n" + path))
|
||||||
|
return base64.StdEncoding.EncodeToString(mac.Sum(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 上下文键。
|
||||||
|
const ctxRoleKey = "tcs_role"
|
||||||
|
|
||||||
|
// AuthMiddleware 校验 HMAC 签名,将角色写入上下文(需求14 权限基础)。
|
||||||
|
func AuthMiddleware(store KeyStore) gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
authz := c.GetHeader("Authorization")
|
||||||
|
if !strings.HasPrefix(authz, "TCS ") {
|
||||||
|
Error(c, 401, "UNAUTHORIZED", "缺少或非法 Authorization 头")
|
||||||
|
c.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
parts := strings.SplitN(strings.TrimPrefix(authz, "TCS "), ":", 2)
|
||||||
|
if len(parts) != 2 {
|
||||||
|
Error(c, 401, "UNAUTHORIZED", "Authorization 格式应为 TCS {apiKey}:{signature}")
|
||||||
|
c.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
apiKey, sig := parts[0], parts[1]
|
||||||
|
secret, role, ok := store.Lookup(apiKey)
|
||||||
|
if !ok {
|
||||||
|
Error(c, 401, "UNAUTHORIZED", "未知 API Key")
|
||||||
|
c.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
expected := Sign(secret, c.Request.Method, c.Request.URL.Path)
|
||||||
|
if !hmac.Equal([]byte(expected), []byte(sig)) {
|
||||||
|
Error(c, 401, "UNAUTHORIZED", "签名校验失败")
|
||||||
|
c.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.Set(ctxRoleKey, role)
|
||||||
|
c.Next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RoleFromContext 取出鉴权后的角色。
|
||||||
|
func RoleFromContext(c *gin.Context) string {
|
||||||
|
if v, ok := c.Get(ctxRoleKey); ok {
|
||||||
|
return fmt.Sprintf("%v", v)
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package httpx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Resp 是统一响应结构。
|
||||||
|
type Resp struct {
|
||||||
|
Code string `json:"code"`
|
||||||
|
Message string `json:"message,omitempty"`
|
||||||
|
Data interface{} `json:"data,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// OK 返回成功响应。
|
||||||
|
func OK(c *gin.Context, data interface{}) {
|
||||||
|
c.JSON(200, Resp{Code: "SUCCESS", Data: data})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Created 返回 201。
|
||||||
|
func Created(c *gin.Context, data interface{}) {
|
||||||
|
c.JSON(201, Resp{Code: "CREATED", Data: data})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accepted 返回 202(异步任务已受理)。
|
||||||
|
func Accepted(c *gin.Context, data interface{}) {
|
||||||
|
c.JSON(202, Resp{Code: "ACCEPTED", Data: data})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error 返回错误响应。
|
||||||
|
func Error(c *gin.Context, status int, code, message string) {
|
||||||
|
c.JSON(status, Resp{Code: code, Message: message})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Health 注册通用健康检查端点。
|
||||||
|
func Health(r *gin.Engine, service string) {
|
||||||
|
r.GET("/healthz", func(c *gin.Context) {
|
||||||
|
c.JSON(200, gin.H{"status": "ok", "service": service})
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,153 @@
|
|||||||
|
// Package macode 实现 MA 码生成服务(模式B:自行发码)。
|
||||||
|
// TCS 与 MA 发码机构合作获取「码段(号段)」与「备案规则」,在本地按规则原子发码。
|
||||||
|
// 对应需求:需求3(MA码签发)、需求16;与 ISO/IEC 15459 MA 标识体系对齐。
|
||||||
|
//
|
||||||
|
// MA 码结构(六段式,可由备案规则配置):
|
||||||
|
//
|
||||||
|
// MA.156.{industryNode}.{orgNode}/{category}/{yyyy}{sequence}
|
||||||
|
//
|
||||||
|
// 示例:MA.156.8531.4401/WD/20250000123
|
||||||
|
// - MA 固定前缀(标识体系根)
|
||||||
|
// - 156 国家码(中国)
|
||||||
|
// - 8531 行业节点(IPTV 视听内容,由发码机构分配)
|
||||||
|
// - 4401 机构节点(运营主体/省局,由发码机构分配)
|
||||||
|
// - WD 内容类目(WD=微短剧 / WJ=网络剧 / DY=网络电影 / DH=网络动画)
|
||||||
|
// - yyyy 年份
|
||||||
|
// - sequence 号段内递增序列(按位补零)
|
||||||
|
package macode
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 错误定义。
|
||||||
|
var (
|
||||||
|
ErrSegmentExhausted = errors.New("macode: code segment exhausted")
|
||||||
|
ErrUnknownCategory = errors.New("macode: unknown content category")
|
||||||
|
ErrInvalidSegment = errors.New("macode: invalid segment range")
|
||||||
|
)
|
||||||
|
|
||||||
|
// 内容类目码。
|
||||||
|
const (
|
||||||
|
CategoryMicroDrama = "WD" // 网络微短剧
|
||||||
|
CategoryWebSeries = "WJ" // 网络剧
|
||||||
|
CategoryWebMovie = "DY" // 网络电影
|
||||||
|
CategoryAnimation = "DH" // 网络动画
|
||||||
|
)
|
||||||
|
|
||||||
|
// Segment 是 MA 发码机构分配给本运营主体的「码段(号段)」。
|
||||||
|
// 同一 (industryNode, orgNode, category) 下,序列在 [Start, End] 内递增分配。
|
||||||
|
type Segment struct {
|
||||||
|
IndustryNode string // 行业节点(发码机构分配)
|
||||||
|
OrgNode string // 机构节点(发码机构分配)
|
||||||
|
Category string // 适用内容类目
|
||||||
|
Start uint64 // 号段起始序列(含)
|
||||||
|
End uint64 // 号段结束序列(含)
|
||||||
|
SeqWidth int // 序列补零宽度,如 7 → 0000123
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate 校验号段合法性。
|
||||||
|
func (s Segment) Validate() error {
|
||||||
|
if s.IndustryNode == "" || s.OrgNode == "" || s.Category == "" {
|
||||||
|
return ErrInvalidSegment
|
||||||
|
}
|
||||||
|
if s.End < s.Start {
|
||||||
|
return ErrInvalidSegment
|
||||||
|
}
|
||||||
|
if s.SeqWidth <= 0 {
|
||||||
|
s.SeqWidth = 7
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AllocationStore 持久化号段游标,保证重启后不重号、并发下原子分配。
|
||||||
|
// MVP 提供内存实现;生产可用 PostgreSQL 行锁 / Redis INCR 实现。
|
||||||
|
type AllocationStore interface {
|
||||||
|
// Next 原子取得指定号段键的下一个序列值;超出 end 返回 ErrSegmentExhausted。
|
||||||
|
Next(segmentKey string, start, end uint64) (uint64, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generator MA 码生成器。
|
||||||
|
type Generator struct {
|
||||||
|
mu sync.RWMutex
|
||||||
|
segments map[string]Segment // category -> segment
|
||||||
|
store AllocationStore
|
||||||
|
clock func() time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGenerator 创建生成器。
|
||||||
|
func NewGenerator(store AllocationStore) *Generator {
|
||||||
|
return &Generator{
|
||||||
|
segments: make(map[string]Segment),
|
||||||
|
store: store,
|
||||||
|
clock: time.Now,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterSegment 登记一个码段(通常在与发码机构对接后配置)。
|
||||||
|
func (g *Generator) RegisterSegment(seg Segment) error {
|
||||||
|
if err := seg.Validate(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if seg.SeqWidth <= 0 {
|
||||||
|
seg.SeqWidth = 7
|
||||||
|
}
|
||||||
|
g.mu.Lock()
|
||||||
|
defer g.mu.Unlock()
|
||||||
|
g.segments[seg.Category] = seg
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// segmentKey 唯一标识一个号段(用于持久化游标)。
|
||||||
|
func segmentKey(s Segment) string {
|
||||||
|
return fmt.Sprintf("%s:%s:%s", s.IndustryNode, s.OrgNode, s.Category)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Issued 一次发码结果。
|
||||||
|
type Issued struct {
|
||||||
|
MACode string `json:"ma_code"`
|
||||||
|
IndustryNode string `json:"industry_node"`
|
||||||
|
OrgNode string `json:"org_node"`
|
||||||
|
Category string `json:"category"`
|
||||||
|
Sequence uint64 `json:"sequence"`
|
||||||
|
Year int `json:"year"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate 为指定类目原子分配并格式化一个全局唯一 MA 码。
|
||||||
|
func (g *Generator) Allocate(category string) (Issued, error) {
|
||||||
|
g.mu.RLock()
|
||||||
|
seg, ok := g.segments[category]
|
||||||
|
g.mu.RUnlock()
|
||||||
|
if !ok {
|
||||||
|
return Issued{}, ErrUnknownCategory
|
||||||
|
}
|
||||||
|
|
||||||
|
seq, err := g.store.Next(segmentKey(seg), seg.Start, seg.End)
|
||||||
|
if err != nil {
|
||||||
|
return Issued{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
year := g.clock().Year()
|
||||||
|
code := Format(seg, year, seq)
|
||||||
|
return Issued{
|
||||||
|
MACode: code,
|
||||||
|
IndustryNode: seg.IndustryNode,
|
||||||
|
OrgNode: seg.OrgNode,
|
||||||
|
Category: category,
|
||||||
|
Sequence: seq,
|
||||||
|
Year: year,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format 按备案规则拼装 MA 码。
|
||||||
|
func Format(seg Segment, year int, seq uint64) string {
|
||||||
|
w := seg.SeqWidth
|
||||||
|
if w <= 0 {
|
||||||
|
w = 7
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("MA.156.%s.%s/%s/%d%0*d",
|
||||||
|
seg.IndustryNode, seg.OrgNode, seg.Category, year, w, seq)
|
||||||
|
}
|
||||||
@@ -0,0 +1,135 @@
|
|||||||
|
package macode
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
// fixedTime 固定为 2025 年,便于断言年份段。
|
||||||
|
var fixedTime = time.Date(2025, 6, 1, 0, 0, 0, 0, time.UTC)
|
||||||
|
|
||||||
|
func newGen(t *testing.T) *Generator {
|
||||||
|
t.Helper()
|
||||||
|
g := NewGenerator(NewMemoryStore())
|
||||||
|
require.NoError(t, g.RegisterSegment(Segment{
|
||||||
|
IndustryNode: "8531", OrgNode: "4401", Category: CategoryMicroDrama,
|
||||||
|
Start: 1, End: 100, SeqWidth: 7,
|
||||||
|
}))
|
||||||
|
// 固定年份便于断言
|
||||||
|
g.clock = func() time.Time { return fixedTime }
|
||||||
|
return g
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAllocate_SequentialUnique(t *testing.T) {
|
||||||
|
g := newGen(t)
|
||||||
|
seen := make(map[string]bool)
|
||||||
|
for i := 0; i < 50; i++ {
|
||||||
|
issued, err := g.Allocate(CategoryMicroDrama)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.False(t, seen[issued.MACode], "MA 码必须唯一: %s", issued.MACode)
|
||||||
|
seen[issued.MACode] = true
|
||||||
|
assert.True(t, IsValid(issued.MACode), "应符合格式: %s", issued.MACode)
|
||||||
|
}
|
||||||
|
assert.Len(t, seen, 50)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAllocate_FormatCorrect(t *testing.T) {
|
||||||
|
g := newGen(t)
|
||||||
|
issued, err := g.Allocate(CategoryMicroDrama)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, "MA.156.8531.4401/WD/20250000001", issued.MACode)
|
||||||
|
assert.Equal(t, uint64(1), issued.Sequence)
|
||||||
|
assert.Equal(t, 2025, issued.Year)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAllocate_UnknownCategory(t *testing.T) {
|
||||||
|
g := newGen(t)
|
||||||
|
_, err := g.Allocate("XX")
|
||||||
|
assert.ErrorIs(t, err, ErrUnknownCategory)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAllocate_SegmentExhausted(t *testing.T) {
|
||||||
|
g := NewGenerator(NewMemoryStore())
|
||||||
|
g.clock = func() time.Time { return fixedTime }
|
||||||
|
require.NoError(t, g.RegisterSegment(Segment{
|
||||||
|
IndustryNode: "8531", OrgNode: "4401", Category: CategoryWebMovie,
|
||||||
|
Start: 1, End: 2, SeqWidth: 5,
|
||||||
|
}))
|
||||||
|
_, err := g.Allocate(CategoryWebMovie)
|
||||||
|
require.NoError(t, err)
|
||||||
|
_, err = g.Allocate(CategoryWebMovie)
|
||||||
|
require.NoError(t, err)
|
||||||
|
_, err = g.Allocate(CategoryWebMovie) // 第3个超出 [1,2]
|
||||||
|
assert.ErrorIs(t, err, ErrSegmentExhausted)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAllocate_ConcurrentNoDuplicate(t *testing.T) {
|
||||||
|
g := NewGenerator(NewMemoryStore())
|
||||||
|
g.clock = func() time.Time { return fixedTime }
|
||||||
|
require.NoError(t, g.RegisterSegment(Segment{
|
||||||
|
IndustryNode: "8531", OrgNode: "4401", Category: CategoryWebSeries,
|
||||||
|
Start: 1, End: 1000, SeqWidth: 7,
|
||||||
|
}))
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
var mu sync.Mutex
|
||||||
|
seen := make(map[string]bool)
|
||||||
|
dup := 0
|
||||||
|
for i := 0; i < 200; i++ {
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
issued, err := g.Allocate(CategoryWebSeries)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
mu.Lock()
|
||||||
|
if seen[issued.MACode] {
|
||||||
|
dup++
|
||||||
|
}
|
||||||
|
seen[issued.MACode] = true
|
||||||
|
mu.Unlock()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
assert.Equal(t, 0, dup, "并发分配不得出现重号")
|
||||||
|
assert.Len(t, seen, 200)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParse_RoundTrip(t *testing.T) {
|
||||||
|
seg := Segment{IndustryNode: "8531", OrgNode: "4401", Category: CategoryMicroDrama, SeqWidth: 7}
|
||||||
|
code := Format(seg, 2025, 123)
|
||||||
|
assert.Equal(t, "MA.156.8531.4401/WD/20250000123", code)
|
||||||
|
|
||||||
|
p, err := Parse(code)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, "MA", p.Root)
|
||||||
|
assert.Equal(t, "156", p.CountryCode)
|
||||||
|
assert.Equal(t, "8531", p.IndustryNode)
|
||||||
|
assert.Equal(t, "4401", p.OrgNode)
|
||||||
|
assert.Equal(t, "WD", p.Category)
|
||||||
|
assert.Equal(t, 2025, p.Year)
|
||||||
|
assert.Equal(t, uint64(123), p.Sequence)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParse_Invalid(t *testing.T) {
|
||||||
|
bad := []string{
|
||||||
|
"", "MA.156", "MA.156.8531.4401/WD", "(京)网微剧审字(2025)第123号",
|
||||||
|
"MA.156.8531.4401/wd/20250000123", // 类目须大写两位
|
||||||
|
}
|
||||||
|
for _, b := range bad {
|
||||||
|
_, err := Parse(b)
|
||||||
|
assert.Error(t, err, "应判为非法: %q", b)
|
||||||
|
assert.False(t, IsValid(b))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSegment_Validate(t *testing.T) {
|
||||||
|
assert.Error(t, Segment{}.Validate())
|
||||||
|
assert.Error(t, Segment{IndustryNode: "1", OrgNode: "2", Category: "WD", Start: 10, End: 5}.Validate())
|
||||||
|
assert.NoError(t, Segment{IndustryNode: "1", OrgNode: "2", Category: "WD", Start: 1, End: 5, SeqWidth: 7}.Validate())
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package macode
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Parsed 是解析后的 MA 码各段。
|
||||||
|
type Parsed struct {
|
||||||
|
Root string
|
||||||
|
CountryCode string
|
||||||
|
IndustryNode string
|
||||||
|
OrgNode string
|
||||||
|
Category string
|
||||||
|
Year int
|
||||||
|
Sequence uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
// maCodePattern 匹配六段式 MA 码:
|
||||||
|
// MA.156.{industry}.{org}/{category}/{yyyy}{sequence}
|
||||||
|
var maCodePattern = regexp.MustCompile(
|
||||||
|
`^(MA)\.(\d{3})\.([0-9A-Za-z]+)\.([0-9A-Za-z]+)/([A-Z]{2})/(\d{4})(\d+)$`)
|
||||||
|
|
||||||
|
// Parse 将 MA 码字符串解析为结构化字段;格式非法返回错误(需求4 校验基础)。
|
||||||
|
func Parse(code string) (Parsed, error) {
|
||||||
|
m := maCodePattern.FindStringSubmatch(code)
|
||||||
|
if m == nil {
|
||||||
|
return Parsed{}, fmt.Errorf("macode: invalid format: %s", code)
|
||||||
|
}
|
||||||
|
year, _ := strconv.Atoi(m[6])
|
||||||
|
seq, err := strconv.ParseUint(m[7], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return Parsed{}, fmt.Errorf("macode: invalid sequence: %w", err)
|
||||||
|
}
|
||||||
|
return Parsed{
|
||||||
|
Root: m[1],
|
||||||
|
CountryCode: m[2],
|
||||||
|
IndustryNode: m[3],
|
||||||
|
OrgNode: m[4],
|
||||||
|
Category: m[5],
|
||||||
|
Year: year,
|
||||||
|
Sequence: seq,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsValid 仅校验格式合法性。
|
||||||
|
func IsValid(code string) bool {
|
||||||
|
return maCodePattern.MatchString(code)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EpisodeSubID 生成集级子标识:{maCode}#E{NN}。
|
||||||
|
// 整剧用 MA 码,单集用子标识,便于按集验真/追更/下架。
|
||||||
|
func EpisodeSubID(maCode string, episode int) string {
|
||||||
|
return fmt.Sprintf("%s#E%02d", maCode, episode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// episodeSubPattern 匹配集级子标识后缀。
|
||||||
|
var episodeSubPattern = regexp.MustCompile(`^(.+)#E(\d+)$`)
|
||||||
|
|
||||||
|
// ParseEpisodeSubID 拆解集级子标识,返回主 MA 码与集号。
|
||||||
|
// 若无 #E 后缀,episode 返回 0(表示整剧)。
|
||||||
|
func ParseEpisodeSubID(subID string) (maCode string, episode int) {
|
||||||
|
m := episodeSubPattern.FindStringSubmatch(subID)
|
||||||
|
if m == nil {
|
||||||
|
return subID, 0
|
||||||
|
}
|
||||||
|
ep, _ := strconv.Atoi(m[2])
|
||||||
|
return m[1], ep
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package macode
|
||||||
|
|
||||||
|
import "sync"
|
||||||
|
|
||||||
|
// MemoryStore 是 AllocationStore 的内存实现(MVP / 测试)。
|
||||||
|
// 生产环境应替换为 PostgreSQL 行锁或 Redis INCR,保证多实例下原子且持久。
|
||||||
|
type MemoryStore struct {
|
||||||
|
mu sync.Mutex
|
||||||
|
cursors map[string]uint64 // segmentKey -> 已分配的最大序列
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMemoryStore 创建内存分配存储。
|
||||||
|
func NewMemoryStore() *MemoryStore {
|
||||||
|
return &MemoryStore{cursors: make(map[string]uint64)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next 原子返回下一个序列:首次取 start,之后递增;超过 end 返回耗尽错误。
|
||||||
|
func (s *MemoryStore) Next(segmentKey string, start, end uint64) (uint64, error) {
|
||||||
|
s.mu.Lock()
|
||||||
|
defer s.mu.Unlock()
|
||||||
|
|
||||||
|
cur, ok := s.cursors[segmentKey]
|
||||||
|
var next uint64
|
||||||
|
if !ok {
|
||||||
|
next = start
|
||||||
|
} else {
|
||||||
|
next = cur + 1
|
||||||
|
}
|
||||||
|
if next > end {
|
||||||
|
return 0, ErrSegmentExhausted
|
||||||
|
}
|
||||||
|
s.cursors[segmentKey] = next
|
||||||
|
return next, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ AllocationStore = (*MemoryStore)(nil)
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package macode
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PostgresStore 是 AllocationStore 的 PostgreSQL 实现。
|
||||||
|
// 通过行级原子 UPSERT + 返回值保证多实例下序列分配原子、持久、不重号。
|
||||||
|
// 解决 MemoryStore 重启丢号、多实例重号的问题(生产用)。
|
||||||
|
type PostgresStore struct {
|
||||||
|
db *sql.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPostgresStore 创建基于 *sql.DB 的分配存储。
|
||||||
|
func NewPostgresStore(db *sql.DB) *PostgresStore {
|
||||||
|
return &PostgresStore{db: db}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next 原子获取下一个序列。
|
||||||
|
// 使用 INSERT ... ON CONFLICT DO UPDATE 的原子自增语义:
|
||||||
|
// - 首次:cursor = start
|
||||||
|
// - 之后:cursor = cursor + 1
|
||||||
|
//
|
||||||
|
// 单条 SQL 在行锁内完成读改写,并发安全;超过 end 返回耗尽错误。
|
||||||
|
func (s *PostgresStore) Next(segmentKey string, start, end uint64) (uint64, error) {
|
||||||
|
const q = `
|
||||||
|
INSERT INTO macode_cursor (segment_key, cursor)
|
||||||
|
VALUES ($1, $2)
|
||||||
|
ON CONFLICT (segment_key)
|
||||||
|
DO UPDATE SET cursor = macode_cursor.cursor + 1, updated_at = NOW()
|
||||||
|
RETURNING cursor;`
|
||||||
|
|
||||||
|
var next uint64
|
||||||
|
if err := s.db.QueryRow(q, segmentKey, start).Scan(&next); err != nil {
|
||||||
|
return 0, fmt.Errorf("macode: pg next: %w", err)
|
||||||
|
}
|
||||||
|
if next > end {
|
||||||
|
return 0, ErrSegmentExhausted
|
||||||
|
}
|
||||||
|
return next, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ AllocationStore = (*PostgresStore)(nil)
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
package macode
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
_ "github.com/lib/pq"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 集成测试:需本地 PostgreSQL。通过 TCS_TEST_PG_DSN 提供连接串;未提供则跳过。
|
||||||
|
func openTestDB(t *testing.T) *sql.DB {
|
||||||
|
t.Helper()
|
||||||
|
dsn := os.Getenv("TCS_TEST_PG_DSN")
|
||||||
|
if dsn == "" {
|
||||||
|
dsn = "postgres://postgres@localhost:5432/tcs_iptv?sslmode=disable"
|
||||||
|
}
|
||||||
|
db, err := sql.Open("postgres", dsn)
|
||||||
|
if err != nil {
|
||||||
|
t.Skipf("跳过 PG 集成测试:%v", err)
|
||||||
|
}
|
||||||
|
if err := db.Ping(); err != nil {
|
||||||
|
t.Skipf("跳过 PG 集成测试(无法连接):%v", err)
|
||||||
|
}
|
||||||
|
return db
|
||||||
|
}
|
||||||
|
|
||||||
|
func cleanupKey(t *testing.T, db *sql.DB, key string) {
|
||||||
|
t.Helper()
|
||||||
|
_, _ = db.Exec("DELETE FROM macode_cursor WHERE segment_key = $1", key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPostgresStore_Sequential(t *testing.T) {
|
||||||
|
db := openTestDB(t)
|
||||||
|
defer db.Close()
|
||||||
|
store := NewPostgresStore(db)
|
||||||
|
key := "test:seq:WD"
|
||||||
|
cleanupKey(t, db, key)
|
||||||
|
defer cleanupKey(t, db, key)
|
||||||
|
|
||||||
|
for want := uint64(1); want <= 5; want++ {
|
||||||
|
got, err := store.Next(key, 1, 100)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPostgresStore_Exhausted(t *testing.T) {
|
||||||
|
db := openTestDB(t)
|
||||||
|
defer db.Close()
|
||||||
|
store := NewPostgresStore(db)
|
||||||
|
key := "test:exhaust:DY"
|
||||||
|
cleanupKey(t, db, key)
|
||||||
|
defer cleanupKey(t, db, key)
|
||||||
|
|
||||||
|
_, err := store.Next(key, 1, 2)
|
||||||
|
require.NoError(t, err)
|
||||||
|
_, err = store.Next(key, 1, 2)
|
||||||
|
require.NoError(t, err)
|
||||||
|
_, err = store.Next(key, 1, 2)
|
||||||
|
assert.ErrorIs(t, err, ErrSegmentExhausted)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPostgresStore_ConcurrentNoDuplicate(t *testing.T) {
|
||||||
|
db := openTestDB(t)
|
||||||
|
defer db.Close()
|
||||||
|
store := NewPostgresStore(db)
|
||||||
|
key := "test:concurrent:WJ"
|
||||||
|
cleanupKey(t, db, key)
|
||||||
|
defer cleanupKey(t, db, key)
|
||||||
|
|
||||||
|
const n = 200
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
var mu sync.Mutex
|
||||||
|
seen := make(map[uint64]bool)
|
||||||
|
dup := 0
|
||||||
|
errs := 0
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
v, err := store.Next(key, 1, 1000)
|
||||||
|
if err != nil {
|
||||||
|
mu.Lock()
|
||||||
|
errs++
|
||||||
|
mu.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
mu.Lock()
|
||||||
|
if seen[v] {
|
||||||
|
dup++
|
||||||
|
}
|
||||||
|
seen[v] = true
|
||||||
|
mu.Unlock()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
assert.Equal(t, 0, errs, "并发分配不应报错")
|
||||||
|
assert.Equal(t, 0, dup, "并发分配不得重号")
|
||||||
|
assert.Len(t, seen, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestPostgresStore_WithGenerator 验证 PG 存储与生成器联动产出唯一 MA 码。
|
||||||
|
func TestPostgresStore_WithGenerator(t *testing.T) {
|
||||||
|
db := openTestDB(t)
|
||||||
|
defer db.Close()
|
||||||
|
key := fmt.Sprintf("%s:%s:%s", "8531", "4401", CategoryAnimation)
|
||||||
|
cleanupKey(t, db, key)
|
||||||
|
defer cleanupKey(t, db, key)
|
||||||
|
|
||||||
|
g := NewGenerator(NewPostgresStore(db))
|
||||||
|
require.NoError(t, g.RegisterSegment(Segment{
|
||||||
|
IndustryNode: "8531", OrgNode: "4401",
|
||||||
|
Category: CategoryAnimation, Start: 1, End: 1000, SeqWidth: 7,
|
||||||
|
}))
|
||||||
|
|
||||||
|
seen := map[string]bool{}
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
issued, err := g.Allocate(CategoryAnimation)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.False(t, seen[issued.MACode])
|
||||||
|
assert.True(t, IsValid(issued.MACode))
|
||||||
|
seen[issued.MACode] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
// Package model 定义 TCS-IPTV 的领域模型,
|
||||||
|
// 对应需求16的四类核心数据结构与 CTID 双锚定模型。
|
||||||
|
package model
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
// Party 三方角色标识。
|
||||||
|
type Party string
|
||||||
|
|
||||||
|
const (
|
||||||
|
PartyCP Party = "cp" // 内容提供商
|
||||||
|
PartyReviewer Party = "reviewer" // 审核和监管部门(审核主体:CSPS/媒资库)
|
||||||
|
PartyOperator Party = "operator" // 运营商
|
||||||
|
)
|
||||||
|
|
||||||
|
// Content 内容主表(Content Registry)。
|
||||||
|
type Content struct {
|
||||||
|
ContentTwinID string `json:"content_twin_id"`
|
||||||
|
MACode string `json:"ma_code"`
|
||||||
|
MAType string `json:"ma_type"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
EpisodeCount int `json:"episode_count"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
Issuer string `json:"issuer"`
|
||||||
|
IssueDate string `json:"issue_date"`
|
||||||
|
FileHash string `json:"file_hash,omitempty"` // 传输便利:列表时附带整剧文件哈希(供运营商演示注入)
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// HashType 哈希类型。
|
||||||
|
type HashType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
HashFile HashType = "file_sha256"
|
||||||
|
HashPerceptual HashType = "perceptual"
|
||||||
|
HashTranscoded HashType = "transcoded"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HashBinding 哈希绑定(Hash Binding)。
|
||||||
|
type HashBinding struct {
|
||||||
|
ContentTwinID string `json:"content_twin_id"`
|
||||||
|
HashType HashType `json:"hash_type"`
|
||||||
|
HashValue string `json:"hash_value"`
|
||||||
|
MerkleRoot string `json:"merkle_root"`
|
||||||
|
Episode int `json:"episode"` // 集号;0 表示整剧/单体(非分集)
|
||||||
|
FileFormat string `json:"file_format"`
|
||||||
|
Resolution string `json:"resolution"`
|
||||||
|
Duration int `json:"duration"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
ParentHash string `json:"parent_hash"` // 转码版指向母版哈希
|
||||||
|
Revoked bool `json:"revoked"` // 集级下架标记(true=该集已下架)
|
||||||
|
RevokedReason string `json:"revoked_reason,omitempty"`
|
||||||
|
CreatedBy string `json:"created_by"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// EpisodeHash 单集哈希(送审时按集提交)。
|
||||||
|
type EpisodeHash struct {
|
||||||
|
Episode int `json:"episode"`
|
||||||
|
FileSHA256 string `json:"file_sha256"`
|
||||||
|
MerkleRoot string `json:"merkle_root"`
|
||||||
|
Perceptual string `json:"perceptual_hash"`
|
||||||
|
Duration int `json:"duration"`
|
||||||
|
Resolution string `json:"resolution"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mapping 三方编码映射(Identity Mapping)。
|
||||||
|
type Mapping struct {
|
||||||
|
ContentTwinID string `json:"content_twin_id"`
|
||||||
|
Party Party `json:"party"`
|
||||||
|
PartyID string `json:"party_id"`
|
||||||
|
PartyName string `json:"party_name"`
|
||||||
|
CDNEndpoint string `json:"cdn_endpoint"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// VersionChange 版本变更(Version History)。
|
||||||
|
type VersionChange struct {
|
||||||
|
ContentTwinID string `json:"content_twin_id"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
ChangeReason string `json:"change_reason"`
|
||||||
|
PrevHash string `json:"prev_hash"`
|
||||||
|
NewHash string `json:"new_hash"`
|
||||||
|
ReauditRequired bool `json:"reaudit_required"`
|
||||||
|
ReauditStatus string `json:"reaudit_status"`
|
||||||
|
AffectedEpisode int `json:"affected_episode"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 内容审核状态。
|
||||||
|
const (
|
||||||
|
StatusPending = "pending" // 待审
|
||||||
|
StatusPreChecking = "pre_checking" // 预检中
|
||||||
|
StatusReviewing = "reviewing" // CSPS 审核中
|
||||||
|
StatusApproved = "approved" // 审核通过(待发码)
|
||||||
|
StatusIssued = "issued" // 已发码(送审单完结)
|
||||||
|
StatusRejected = "rejected" // 驳回
|
||||||
|
StatusInLibrary = "in_library" // 已入媒资库
|
||||||
|
StatusPublished = "published" // 已发布
|
||||||
|
StatusRevoked = "revoked" // 已下架
|
||||||
|
)
|
||||||
@@ -0,0 +1,176 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/tcs-iptv/tcs/internal/chain"
|
||||||
|
"github.com/tcs-iptv/tcs/internal/hash"
|
||||||
|
"github.com/tcs-iptv/tcs/internal/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ---- 工作包7:转码版哈希绑定(需求5) ----
|
||||||
|
// 注:CSPS 合规审核已前移至发码前(service.ReviewCSPS),此处仅处理转码。
|
||||||
|
|
||||||
|
// BindTranscoded 绑定转码版哈希,与母版建立父子关系(需求5-AC3/AC4/AC5)。
|
||||||
|
func (s *Service) BindTranscoded(role chain.Role, ctid, parentFileHash, transcodedHash, format, resolution, version string) (string, error) {
|
||||||
|
if transcodedHash == "" {
|
||||||
|
return "", ErrIncompleteHashPkg
|
||||||
|
}
|
||||||
|
return s.chain.RegisterHashBinding(role, model.HashBinding{
|
||||||
|
ContentTwinID: ctid,
|
||||||
|
HashType: model.HashTranscoded,
|
||||||
|
HashValue: transcodedHash,
|
||||||
|
ParentHash: parentFileHash,
|
||||||
|
FileFormat: format,
|
||||||
|
Resolution: resolution,
|
||||||
|
Version: version,
|
||||||
|
CreatedBy: string(role),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- 工作包8:媒体资源库入库、发布与映射(需求6) ----
|
||||||
|
|
||||||
|
// IngestToLibrary 审核合格内容入媒资库,建立媒资编码映射(需求6-AC1/AC2/AC3)。
|
||||||
|
func (s *Service) IngestToLibrary(role chain.Role, maCode, ctid, mediaAssetID, libName string) error {
|
||||||
|
c, err := s.chain.QueryContent(maCode)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// 门禁:未审核通过/未绑定 MA 码不得入库可发布状态
|
||||||
|
if c.Status == model.StatusRejected || c.Status == model.StatusRevoked {
|
||||||
|
return ErrNotApproved
|
||||||
|
}
|
||||||
|
if _, err := s.chain.RegisterMapping(role, model.Mapping{
|
||||||
|
ContentTwinID: ctid,
|
||||||
|
Party: model.PartyReviewer,
|
||||||
|
PartyID: mediaAssetID,
|
||||||
|
PartyName: libName,
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return s.chain.SetContentStatus(maCode, model.StatusInLibrary)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PublishRequest 从媒资库向运营商发布的请求(需求6-AC4)。
|
||||||
|
type PublishRequest struct {
|
||||||
|
MACode string
|
||||||
|
Certificate string // 必须携带 MA码+哈希证书
|
||||||
|
}
|
||||||
|
|
||||||
|
// PublishToOperator 校验证书后将内容置为已发布(需求6-AC4/AC5、需求3-AC8)。
|
||||||
|
func (s *Service) PublishToOperator(req PublishRequest) error {
|
||||||
|
c, err := s.chain.QueryContent(req.MACode)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if c.Status != model.StatusInLibrary && c.Status != model.StatusPublished {
|
||||||
|
return ErrNotApproved
|
||||||
|
}
|
||||||
|
// 发布必须携带证书(含 MA 码)
|
||||||
|
if req.Certificate == "" || !certContainsMA(req.Certificate, req.MACode) {
|
||||||
|
return ErrNoCertificate
|
||||||
|
}
|
||||||
|
return s.chain.SetContentStatus(req.MACode, model.StatusPublished)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- 工作包9:CDN 注入校验(需求7) ----
|
||||||
|
|
||||||
|
// InjectResult CDN 注入校验结果。
|
||||||
|
type InjectResult struct {
|
||||||
|
Allowed bool `json:"allowed"`
|
||||||
|
DistributionID string `json:"distribution_id,omitempty"`
|
||||||
|
Reason string `json:"reason,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// InjectToCDN 运营商注入 CDN 前校验哈希;匹配则放行并注册运营商映射(需求7-AC1~AC4)。
|
||||||
|
func (s *Service) InjectToCDN(role chain.Role, ctid, maCode, injectFileHash, operatorID, cdnEndpoint string) (InjectResult, error) {
|
||||||
|
// 内容须处于已发布状态
|
||||||
|
c, err := s.chain.QueryContent(maCode)
|
||||||
|
if err != nil {
|
||||||
|
return InjectResult{}, err
|
||||||
|
}
|
||||||
|
if c.Status == model.StatusRevoked {
|
||||||
|
return InjectResult{Allowed: false, Reason: "内容已下架"}, ErrNotApproved
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := s.chain.VerifyHash(maCode, injectFileHash)
|
||||||
|
if err != nil {
|
||||||
|
return InjectResult{Allowed: false, Reason: err.Error()}, err
|
||||||
|
}
|
||||||
|
if !res.Match {
|
||||||
|
// 不匹配:拒绝注入(需求7-AC3、需求15-AC2)
|
||||||
|
return InjectResult{Allowed: false, Reason: "哈希不匹配,疑似篡改,拒绝注入并告警"}, ErrHashMismatch
|
||||||
|
}
|
||||||
|
|
||||||
|
distID := s.nextID("DIST")
|
||||||
|
if _, err := s.chain.RegisterMapping(role, model.Mapping{
|
||||||
|
ContentTwinID: ctid,
|
||||||
|
Party: model.PartyOperator,
|
||||||
|
PartyID: operatorID,
|
||||||
|
CDNEndpoint: cdnEndpoint,
|
||||||
|
}); err != nil {
|
||||||
|
return InjectResult{}, err
|
||||||
|
}
|
||||||
|
return InjectResult{Allowed: true, DistributionID: distID}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- 工作包10:版本变更与重审(需求12) ----
|
||||||
|
|
||||||
|
// ReportVersionChange 上报内容变更:哈希变化判定绑定断裂,触发重审(需求12-AC1/AC2)。
|
||||||
|
// 当提供 oldSegments/newSegments 时,定位被篡改的具体集(需求12-AC3)。
|
||||||
|
func (s *Service) ReportVersionChange(ctid, reason, prevHash, newHash string, oldSegments, newSegments []string) ([]int, error) {
|
||||||
|
var changedEpisodes []int
|
||||||
|
affected := 0
|
||||||
|
if len(oldSegments) > 0 || len(newSegments) > 0 {
|
||||||
|
changedEpisodes = hash.LocateChangedLeaves(oldSegments, newSegments)
|
||||||
|
if len(changedEpisodes) > 0 {
|
||||||
|
affected = changedEpisodes[0] + 1 // 1-based 集号
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, err := s.chain.RecordVersionChange(model.VersionChange{
|
||||||
|
ContentTwinID: ctid,
|
||||||
|
Version: "v-next",
|
||||||
|
ChangeReason: reason,
|
||||||
|
PrevHash: prevHash,
|
||||||
|
NewHash: newHash,
|
||||||
|
ReauditRequired: true,
|
||||||
|
ReauditStatus: "pending",
|
||||||
|
AffectedEpisode: affected,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// 转为 1-based 集号返回
|
||||||
|
episodes := make([]int, len(changedEpisodes))
|
||||||
|
for i, idx := range changedEpisodes {
|
||||||
|
episodes[i] = idx + 1
|
||||||
|
}
|
||||||
|
return episodes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- 工作包14:违规应急下架(需求11) ----
|
||||||
|
|
||||||
|
// Takedown 监管主体一键下架:解析 MA 码绑定的三方编码与 CDN 端点(需求11-AC1/AC2/AC4)。
|
||||||
|
func (s *Service) Takedown(role chain.Role, maCode, reason string) (chain.MappingsResult, error) {
|
||||||
|
return s.chain.Revoke(role, maCode, reason)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TakedownEpisode 集级下架:只下架指定集,整剧其他集继续流通(仅监管主体)。
|
||||||
|
func (s *Service) TakedownEpisode(role chain.Role, maCode string, episode int, reason string) error {
|
||||||
|
return s.chain.RevokeEpisode(role, maCode, episode, reason)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore 恢复上架整剧(仅监管主体)。
|
||||||
|
func (s *Service) Restore(role chain.Role, maCode string) error {
|
||||||
|
return s.chain.Restore(role, maCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RestoreEpisode 恢复上架指定集(仅监管主体)。
|
||||||
|
func (s *Service) RestoreEpisode(role chain.Role, maCode string, episode int) error {
|
||||||
|
return s.chain.RestoreEpisode(role, maCode, episode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// certContainsMA 校验证书是否包含指定 MA 码。
|
||||||
|
func certContainsMA(cert, maCode string) bool {
|
||||||
|
return cert != "" && maCode != "" && strings.Contains(cert, maCode)
|
||||||
|
}
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/tcs-iptv/tcs/internal/chain"
|
||||||
|
"github.com/tcs-iptv/tcs/internal/hash"
|
||||||
|
)
|
||||||
|
|
||||||
|
// issueOne 完成一次"送审→CSPS审核→发码签发",返回 maCode、ctid、证书。
|
||||||
|
func issueOne(t *testing.T, s *Service) (string, string, string) {
|
||||||
|
t.Helper()
|
||||||
|
sub, err := s.SubmitForReview(sampleSub())
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NoError(t, s.ReviewCSPS(sub.ReviewID, true, "reviewer-1")) // 审核在前
|
||||||
|
issued, err := s.ApproveAndIssue(chain.RoleRegulator, sub.ReviewID, "北京市广播电视局")
|
||||||
|
require.NoError(t, err)
|
||||||
|
return issued.MACode, issued.ContentTwinID, issued.Certificate
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCSPSAndTranscode(t *testing.T) {
|
||||||
|
s := newService(t)
|
||||||
|
maCode, ctid, _ := issueOne(t, s)
|
||||||
|
|
||||||
|
_, err := s.BindTranscoded(chain.RoleReviewer, ctid, "filehash-abc",
|
||||||
|
"transcoded-h265-4k", "H.265", "3840x2160", "v1.0-4k")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// 转码版也能验真通过
|
||||||
|
res, err := s.Verify(maCode, "transcoded-h265-4k")
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.True(t, res.Match)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCSPSRejected(t *testing.T) {
|
||||||
|
s := newService(t)
|
||||||
|
sub, err := s.SubmitForReview(sampleSub())
|
||||||
|
require.NoError(t, err)
|
||||||
|
// CSPS 审核驳回 → 不得发码
|
||||||
|
require.NoError(t, s.ReviewCSPS(sub.ReviewID, false, "reviewer-1"))
|
||||||
|
_, err = s.ApproveAndIssue(chain.RoleRegulator, sub.ReviewID, "issuer")
|
||||||
|
assert.ErrorIs(t, err, ErrNotApproved)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIssueRequiresCSPSApproval(t *testing.T) {
|
||||||
|
s := newService(t)
|
||||||
|
sub, err := s.SubmitForReview(sampleSub())
|
||||||
|
require.NoError(t, err)
|
||||||
|
// 未经 CSPS 审核直接发码 → 拒绝
|
||||||
|
_, err = s.ApproveAndIssue(chain.RoleRegulator, sub.ReviewID, "issuer")
|
||||||
|
assert.ErrorIs(t, err, ErrNotApproved)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIngestAndPublish(t *testing.T) {
|
||||||
|
s := newService(t)
|
||||||
|
maCode, ctid, cert := issueOne(t, s)
|
||||||
|
|
||||||
|
require.NoError(t, s.IngestToLibrary(chain.RoleReviewer, maCode, ctid, "MEDIA-001", "广东IPTV媒资库"))
|
||||||
|
|
||||||
|
// 无证书发布被拒
|
||||||
|
err := s.PublishToOperator(PublishRequest{MACode: maCode, Certificate: ""})
|
||||||
|
assert.ErrorIs(t, err, ErrNoCertificate)
|
||||||
|
|
||||||
|
// 携带证书发布成功
|
||||||
|
require.NoError(t, s.PublishToOperator(PublishRequest{MACode: maCode, Certificate: cert}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInjectToCDN_MatchAndMismatch(t *testing.T) {
|
||||||
|
s := newService(t)
|
||||||
|
maCode, ctid, cert := issueOne(t, s)
|
||||||
|
require.NoError(t, s.IngestToLibrary(chain.RoleReviewer, maCode, ctid, "MEDIA-001", "媒资库"))
|
||||||
|
require.NoError(t, s.PublishToOperator(PublishRequest{MACode: maCode, Certificate: cert}))
|
||||||
|
|
||||||
|
// 哈希匹配 → 允许注入
|
||||||
|
res, err := s.InjectToCDN(chain.RoleOperator, ctid, maCode, "filehash-abc",
|
||||||
|
"CT-IPTV-GD", "cdn://ct-gd/iptv/vod/008923")
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.True(t, res.Allowed)
|
||||||
|
assert.NotEmpty(t, res.DistributionID)
|
||||||
|
|
||||||
|
// 哈希不匹配 → 拒绝注入
|
||||||
|
res, err = s.InjectToCDN(chain.RoleOperator, ctid, maCode, "tampered-hash",
|
||||||
|
"CT-IPTV-GD", "cdn://x")
|
||||||
|
assert.ErrorIs(t, err, ErrHashMismatch)
|
||||||
|
assert.False(t, res.Allowed)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInjectToCDN_RevokedBlocked(t *testing.T) {
|
||||||
|
s := newService(t)
|
||||||
|
maCode, ctid, cert := issueOne(t, s)
|
||||||
|
require.NoError(t, s.IngestToLibrary(chain.RoleReviewer, maCode, ctid, "MEDIA-001", "媒资库"))
|
||||||
|
require.NoError(t, s.PublishToOperator(PublishRequest{MACode: maCode, Certificate: cert}))
|
||||||
|
|
||||||
|
// 下架后不得注入
|
||||||
|
_, err := s.Takedown(chain.RoleRegulator, maCode, "违规")
|
||||||
|
require.NoError(t, err)
|
||||||
|
_, err = s.InjectToCDN(chain.RoleOperator, ctid, maCode, "filehash-abc", "OP", "cdn://x")
|
||||||
|
assert.ErrorIs(t, err, ErrNotApproved)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTakedown_ResolvesMappings(t *testing.T) {
|
||||||
|
s := newService(t)
|
||||||
|
maCode, ctid, cert := issueOne(t, s)
|
||||||
|
require.NoError(t, s.IngestToLibrary(chain.RoleReviewer, maCode, ctid, "MEDIA-001", "媒资库"))
|
||||||
|
require.NoError(t, s.PublishToOperator(PublishRequest{MACode: maCode, Certificate: cert}))
|
||||||
|
_, _ = s.InjectToCDN(chain.RoleOperator, ctid, maCode, "filehash-abc", "CT-IPTV-GD", "cdn://ct-gd/vod/1")
|
||||||
|
|
||||||
|
// 非监管主体不得下架
|
||||||
|
_, err := s.Takedown(chain.RoleOperator, maCode, "越权")
|
||||||
|
assert.ErrorIs(t, err, chain.ErrPermissionDenied)
|
||||||
|
|
||||||
|
// 监管下架,解析出 CDN 端点
|
||||||
|
res, err := s.Takedown(chain.RoleRegulator, maCode, "违规")
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Contains(t, res.CDNEndpoints, "cdn://ct-gd/vod/1")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReportVersionChange_LocatesEpisode(t *testing.T) {
|
||||||
|
s := newService(t)
|
||||||
|
_, ctid, _ := issueOne(t, s)
|
||||||
|
|
||||||
|
old := []string{
|
||||||
|
hash.SHA256Hex([]byte("ep1")),
|
||||||
|
hash.SHA256Hex([]byte("ep2")),
|
||||||
|
hash.SHA256Hex([]byte("ep3")),
|
||||||
|
}
|
||||||
|
neu := []string{
|
||||||
|
hash.SHA256Hex([]byte("ep1")),
|
||||||
|
hash.SHA256Hex([]byte("ep2-tampered")),
|
||||||
|
hash.SHA256Hex([]byte("ep3")),
|
||||||
|
}
|
||||||
|
episodes, err := s.ReportVersionChange(ctid, "第2集被替换", "root-old", "root-new", old, neu)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, []int{2}, episodes, "应定位到第2集(1-based)")
|
||||||
|
}
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/tcs-iptv/tcs/internal/chain"
|
||||||
|
"github.com/tcs-iptv/tcs/internal/macode"
|
||||||
|
"github.com/tcs-iptv/tcs/internal/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 24 集微短剧:一剧一 MA 码,每集独立哈希,可按集验真。
|
||||||
|
func TestEpisodeLevel_OneSeriesOneCodeMultiEpisodeHash(t *testing.T) {
|
||||||
|
s := newService(t)
|
||||||
|
|
||||||
|
eps := make([]model.EpisodeHash, 0, 24)
|
||||||
|
for i := 1; i <= 24; i++ {
|
||||||
|
eps = append(eps, model.EpisodeHash{
|
||||||
|
Episode: i,
|
||||||
|
FileSHA256: "ep-hash-" + string(rune('a'+i)),
|
||||||
|
MerkleRoot: "ep-mr-" + string(rune('a'+i)),
|
||||||
|
Duration: 180,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
sub := Submission{
|
||||||
|
Title: "长安少年行", EpisodeCount: 24, Category: macode.CategoryMicroDrama,
|
||||||
|
FileHash: "series-root-hash", MerkleRoot: "series-merkle-root",
|
||||||
|
Episodes: eps,
|
||||||
|
CPMediaID: "XAQJSL-2026-001", CPName: "西安曲江丝路文化传播有限公司",
|
||||||
|
}
|
||||||
|
r, err := s.SubmitForReview(sub)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NoError(t, s.ReviewCSPS(r.ReviewID, true, "rv-1"))
|
||||||
|
issued, err := s.ApproveAndIssue(chain.RoleRegulator, r.ReviewID, "陕西IPTV运营公司")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// 一剧一码
|
||||||
|
assert.True(t, macode.IsValid(issued.MACode))
|
||||||
|
|
||||||
|
// 24 集哈希全部绑定在同一 MA 码下
|
||||||
|
list, err := s.ListEpisodes(issued.MACode)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Len(t, list, 24)
|
||||||
|
|
||||||
|
// 按集验真:第 7 集正确哈希匹配
|
||||||
|
res, err := s.VerifyEpisode(issued.MACode, 7, "ep-hash-"+string(rune('a'+7)))
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.True(t, res.Match)
|
||||||
|
|
||||||
|
// 第 7 集错误哈希 → 不匹配(疑似该集被替换)
|
||||||
|
_, err = s.VerifyEpisode(issued.MACode, 7, "tampered-ep7")
|
||||||
|
assert.ErrorIs(t, err, ErrHashMismatch)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 集级下架:只下架第3集,整剧其他集不受影响。
|
||||||
|
func TestEpisodeTakedown(t *testing.T) {
|
||||||
|
s := newService(t)
|
||||||
|
|
||||||
|
eps := []model.EpisodeHash{
|
||||||
|
{Episode: 1, FileSHA256: "h1"}, {Episode: 2, FileSHA256: "h2"},
|
||||||
|
{Episode: 3, FileSHA256: "h3"}, {Episode: 4, FileSHA256: "h4"},
|
||||||
|
}
|
||||||
|
sub := Submission{
|
||||||
|
Title: "多集剧", EpisodeCount: 4, Category: macode.CategoryMicroDrama,
|
||||||
|
FileHash: "series-h", MerkleRoot: "series-mr", Episodes: eps,
|
||||||
|
}
|
||||||
|
r, err := s.SubmitForReview(sub)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NoError(t, s.ReviewCSPS(r.ReviewID, true, "rv-1"))
|
||||||
|
issued, err := s.ApproveAndIssue(chain.RoleRegulator, r.ReviewID, "陕西IPTV运营公司")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// 运营商无权集级下架
|
||||||
|
err = s.TakedownEpisode(chain.RoleOperator, issued.MACode, 3, "第3集违规")
|
||||||
|
assert.ErrorIs(t, err, chain.ErrPermissionDenied)
|
||||||
|
|
||||||
|
// 监管下架第3集
|
||||||
|
require.NoError(t, s.TakedownEpisode(chain.RoleRegulator, issued.MACode, 3, "第3集违规"))
|
||||||
|
|
||||||
|
list, err := s.ListEpisodes(issued.MACode)
|
||||||
|
require.NoError(t, err)
|
||||||
|
for _, b := range list {
|
||||||
|
if b.Episode == 3 {
|
||||||
|
assert.True(t, b.Revoked, "第3集应已下架")
|
||||||
|
} else {
|
||||||
|
assert.False(t, b.Revoked, "第%d集不应受影响", b.Episode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 集级子标识:MA码#E07 解析与生成。
|
||||||
|
func TestEpisodeSubID(t *testing.T) {
|
||||||
|
ma := "MA.156.8531.6101/WD/20260000001"
|
||||||
|
sub := macode.EpisodeSubID(ma, 7)
|
||||||
|
assert.Equal(t, "MA.156.8531.6101/WD/20260000001#E07", sub)
|
||||||
|
|
||||||
|
parsedMA, ep := macode.ParseEpisodeSubID(sub)
|
||||||
|
assert.Equal(t, ma, parsedMA)
|
||||||
|
assert.Equal(t, 7, ep)
|
||||||
|
|
||||||
|
// 无后缀 → 整剧(episode 0)
|
||||||
|
parsedMA2, ep2 := macode.ParseEpisodeSubID(ma)
|
||||||
|
assert.Equal(t, ma, parsedMA2)
|
||||||
|
assert.Equal(t, 0, ep2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 单体内容(电影,无分集):episodes 为空也能正常签发与整剧验真。
|
||||||
|
func TestSingleContent_NoEpisodes(t *testing.T) {
|
||||||
|
s := newService(t)
|
||||||
|
sub := sampleSub()
|
||||||
|
sub.Episodes = nil
|
||||||
|
r, err := s.SubmitForReview(sub)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NoError(t, s.ReviewCSPS(r.ReviewID, true, "rv-1"))
|
||||||
|
issued, err := s.ApproveAndIssue(chain.RoleRegulator, r.ReviewID, "陕西IPTV运营公司")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
list, err := s.ListEpisodes(issued.MACode)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Empty(t, list, "单体内容无集级绑定")
|
||||||
|
|
||||||
|
// 整剧验真仍可用
|
||||||
|
res, err := s.Verify(issued.MACode, sub.FileHash)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.True(t, res.Match)
|
||||||
|
}
|
||||||
@@ -0,0 +1,270 @@
|
|||||||
|
// Package service 实现 TCS-IPTV 的业务编排,
|
||||||
|
// 依赖 chain.Client(链)与哈希校验,串联送审→签发→验真→入库→发布→下架全流程。
|
||||||
|
// 对应需求:需求2/3/4/5/6/7/11/12/15。
|
||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/tcs-iptv/tcs/internal/chain"
|
||||||
|
"github.com/tcs-iptv/tcs/internal/macode"
|
||||||
|
"github.com/tcs-iptv/tcs/internal/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 业务错误。
|
||||||
|
var (
|
||||||
|
ErrIncompleteHashPkg = errors.New("service: incomplete hash package")
|
||||||
|
ErrDuplicateContent = errors.New("service: duplicate content (hash exists)")
|
||||||
|
ErrHashMismatch = errors.New("service: hash mismatch (suspected version replacement)")
|
||||||
|
ErrNotApproved = errors.New("service: content not approved")
|
||||||
|
ErrNoCertificate = errors.New("service: missing MA code or hash certificate")
|
||||||
|
ErrReauditPending = errors.New("service: reaudit pending, distribution blocked")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Submission 送审申报(需求2)。
|
||||||
|
type Submission struct {
|
||||||
|
Title string
|
||||||
|
EpisodeCount int
|
||||||
|
Category string // 内容类目(macode.CategoryXxx),决定发码号段
|
||||||
|
FileHash string
|
||||||
|
MerkleRoot string
|
||||||
|
Perceptual string
|
||||||
|
Episodes []model.EpisodeHash // 分集哈希(按集提交)
|
||||||
|
CPMediaID string
|
||||||
|
CPName string
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubmissionResult 送审受理结果。
|
||||||
|
type SubmissionResult struct {
|
||||||
|
ReviewID string `json:"review_id"`
|
||||||
|
ContentTwinID string `json:"content_twin_id"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Service 业务编排器。
|
||||||
|
type Service struct {
|
||||||
|
chain chain.Client
|
||||||
|
gen *macode.Generator
|
||||||
|
mu sync.Mutex
|
||||||
|
seqMu sync.Mutex
|
||||||
|
seqs map[string]int // 按前缀独立计数(REV/ctid/DIST 各自从 1 递增)
|
||||||
|
// reviewStore 暂存送审申报(MVP 内存;生产落 PG)
|
||||||
|
reviews map[string]*reviewItem
|
||||||
|
}
|
||||||
|
|
||||||
|
type reviewItem struct {
|
||||||
|
ContentTwinID string
|
||||||
|
Sub Submission
|
||||||
|
Status string
|
||||||
|
MACode string
|
||||||
|
}
|
||||||
|
|
||||||
|
// New 创建业务服务。
|
||||||
|
func New(c chain.Client, gen *macode.Generator) *Service {
|
||||||
|
return &Service{chain: c, gen: gen, seqs: make(map[string]int), reviews: make(map[string]*reviewItem)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) nextID(prefix string) string {
|
||||||
|
s.seqMu.Lock()
|
||||||
|
defer s.seqMu.Unlock()
|
||||||
|
s.seqs[prefix]++
|
||||||
|
return fmt.Sprintf("%s-%s-%04d", prefix, time.Now().Format("20060102"), s.seqs[prefix])
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubmitForReview 处理 CP 送审申报(需求2)。
|
||||||
|
// 校验哈希包完整性、拦截换壳重发,受理后返回送审流水号。
|
||||||
|
func (s *Service) SubmitForReview(sub Submission) (SubmissionResult, error) {
|
||||||
|
if sub.FileHash == "" || sub.MerkleRoot == "" {
|
||||||
|
return SubmissionResult{}, ErrIncompleteHashPkg
|
||||||
|
}
|
||||||
|
// 防换壳重发(需求2-AC3、需求15-AC5)
|
||||||
|
if maCode, exists := s.chain.HashExists(sub.FileHash); exists {
|
||||||
|
return SubmissionResult{
|
||||||
|
Status: "rejected",
|
||||||
|
Message: fmt.Sprintf("内容哈希已存在,关联原 MA 码: %s", maCode),
|
||||||
|
}, ErrDuplicateContent
|
||||||
|
}
|
||||||
|
|
||||||
|
s.mu.Lock()
|
||||||
|
defer s.mu.Unlock()
|
||||||
|
reviewID := s.nextID("REV")
|
||||||
|
ctid := s.nextID("ctid")
|
||||||
|
s.reviews[reviewID] = &reviewItem{
|
||||||
|
ContentTwinID: ctid,
|
||||||
|
Sub: sub,
|
||||||
|
Status: model.StatusPending,
|
||||||
|
}
|
||||||
|
return SubmissionResult{
|
||||||
|
ReviewID: reviewID,
|
||||||
|
ContentTwinID: ctid,
|
||||||
|
Status: model.StatusPending,
|
||||||
|
Message: "哈希已受理,待审核签发 MA 码",
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IssueResult 签发结果。
|
||||||
|
type IssueResult struct {
|
||||||
|
MACode string `json:"ma_code"`
|
||||||
|
ContentTwinID string `json:"content_twin_id"`
|
||||||
|
TxID string `json:"tx_id"`
|
||||||
|
Certificate string `json:"certificate"` // MA码+哈希证书(MVP 简化为字符串)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReviewCSPS CSPS 合规审核(发码前)。审核通过后方可发码,体现"审过才发证发码"。
|
||||||
|
// 对应需求5(CSPS审核)+ 需求3-AC2(审核通过后生成MA码)。
|
||||||
|
func (s *Service) ReviewCSPS(reviewID string, approved bool, reviewerID string) error {
|
||||||
|
s.mu.Lock()
|
||||||
|
defer s.mu.Unlock()
|
||||||
|
item, ok := s.reviews[reviewID]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("service: review %s not found", reviewID)
|
||||||
|
}
|
||||||
|
if approved {
|
||||||
|
item.Status = model.StatusApproved
|
||||||
|
} else {
|
||||||
|
item.Status = model.StatusRejected
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApproveAndIssue 在 CSPS 审核通过后**生成 MA 码**并强绑定哈希(需求3,模式B 自行发码)。
|
||||||
|
// 前置:该送审必须已通过 CSPS 审核(审过才发码)。
|
||||||
|
// MA 码由 macode.Generator 按内容类目从号段中原子分配。仅监管主体可调用。
|
||||||
|
func (s *Service) ApproveAndIssue(role chain.Role, reviewID, issuer string) (IssueResult, error) {
|
||||||
|
s.mu.Lock()
|
||||||
|
item, ok := s.reviews[reviewID]
|
||||||
|
s.mu.Unlock()
|
||||||
|
if !ok {
|
||||||
|
return IssueResult{}, fmt.Errorf("service: review %s not found", reviewID)
|
||||||
|
}
|
||||||
|
// 审核门禁:未通过 CSPS 审核不得发码
|
||||||
|
if item.Status == model.StatusRejected {
|
||||||
|
return IssueResult{}, ErrNotApproved
|
||||||
|
}
|
||||||
|
if item.Status != model.StatusApproved {
|
||||||
|
return IssueResult{}, fmt.Errorf("%w: 需先通过 CSPS 审核", ErrNotApproved)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 模式B:按类目自行发码
|
||||||
|
issued, err := s.gen.Allocate(item.Sub.Category)
|
||||||
|
if err != nil {
|
||||||
|
return IssueResult{}, fmt.Errorf("service: allocate MA code: %w", err)
|
||||||
|
}
|
||||||
|
maCode := issued.MACode
|
||||||
|
|
||||||
|
txID, err := s.chain.IssueMA(role, chain.IssueRequest{
|
||||||
|
MACode: maCode,
|
||||||
|
ContentTwinID: item.ContentTwinID,
|
||||||
|
MerkleRoot: item.Sub.MerkleRoot,
|
||||||
|
FileHash: item.Sub.FileHash,
|
||||||
|
PerceptualHash: item.Sub.Perceptual,
|
||||||
|
Episodes: item.Sub.Episodes,
|
||||||
|
Content: model.Content{
|
||||||
|
Title: item.Sub.Title,
|
||||||
|
EpisodeCount: item.Sub.EpisodeCount,
|
||||||
|
MAType: item.Sub.Category,
|
||||||
|
Issuer: issuer,
|
||||||
|
IssueDate: time.Now().Format("2006-01-02"),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return IssueResult{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
s.mu.Lock()
|
||||||
|
item.Status = model.StatusIssued // 已发码,移出"待发码"队列
|
||||||
|
item.MACode = maCode
|
||||||
|
s.mu.Unlock()
|
||||||
|
|
||||||
|
// CP 注册本方映射
|
||||||
|
_, _ = s.chain.RegisterMapping(role, model.Mapping{
|
||||||
|
ContentTwinID: item.ContentTwinID,
|
||||||
|
Party: model.PartyCP,
|
||||||
|
PartyID: item.Sub.CPMediaID,
|
||||||
|
PartyName: item.Sub.CPName,
|
||||||
|
})
|
||||||
|
|
||||||
|
cert := fmt.Sprintf("CERT|%s|%s|%s", maCode, item.Sub.FileHash, item.Sub.MerkleRoot)
|
||||||
|
return IssueResult{
|
||||||
|
MACode: maCode,
|
||||||
|
ContentTwinID: item.ContentTwinID,
|
||||||
|
TxID: txID,
|
||||||
|
Certificate: cert,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify 送审文件验真 / CDN 注入校验通用入口(需求4、需求7)。
|
||||||
|
func (s *Service) Verify(maCode, fileHash string) (chain.VerifyResult, error) {
|
||||||
|
res, err := s.chain.VerifyHash(maCode, fileHash)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
if !res.Match {
|
||||||
|
return res, ErrHashMismatch
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueryMappings 查询 MA 码绑定的三方映射与 CDN 端点(需求11/17)。
|
||||||
|
func (s *Service) QueryMappings(maCode string) (chain.MappingsResult, error) {
|
||||||
|
return s.chain.QueryMappings(maCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyEpisode 按集级子标识(MA码#E07)或 MA码+集号 验真单集。
|
||||||
|
func (s *Service) VerifyEpisode(maCode string, episode int, fileHash string) (chain.VerifyResult, error) {
|
||||||
|
res, err := s.chain.VerifyEpisodeHash(maCode, episode, fileHash)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
if !res.Match {
|
||||||
|
return res, ErrHashMismatch
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListEpisodes 列出某剧的全部集级哈希绑定。
|
||||||
|
func (s *Service) ListEpisodes(maCode string) ([]model.HashBinding, error) {
|
||||||
|
return s.chain.ListEpisodes(maCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReviewSummary 送审待办摘要(发码前阶段)。
|
||||||
|
type ReviewSummary struct {
|
||||||
|
ReviewID string `json:"review_id"`
|
||||||
|
ContentTwinID string `json:"content_twin_id"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Category string `json:"category"`
|
||||||
|
EpisodeCount int `json:"episode_count"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
CPName string `json:"cp_name"`
|
||||||
|
MACode string `json:"ma_code"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListReviews 列出指定状态的送审待办(用于审核台/发码台队列)。
|
||||||
|
// status 空则返回全部;常用 pending(待审)、approved(待发码)。
|
||||||
|
func (s *Service) ListReviews(status string) []ReviewSummary {
|
||||||
|
s.mu.Lock()
|
||||||
|
defer s.mu.Unlock()
|
||||||
|
var out []ReviewSummary
|
||||||
|
for id, item := range s.reviews {
|
||||||
|
if status != "" && item.Status != status {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
out = append(out, ReviewSummary{
|
||||||
|
ReviewID: id, ContentTwinID: item.ContentTwinID,
|
||||||
|
Title: item.Sub.Title, Category: item.Sub.Category,
|
||||||
|
EpisodeCount: item.Sub.EpisodeCount, Status: item.Status,
|
||||||
|
CPName: item.Sub.CPName, MACode: item.MACode,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListContentsByStatus 列出指定状态的内容(用于入库台/发布台/注入台队列)。
|
||||||
|
// 常用 approved(待入库)、in_library(待发布)、published(待注入)。
|
||||||
|
func (s *Service) ListContentsByStatus(status string) ([]model.Content, error) {
|
||||||
|
return s.chain.ListContents(status)
|
||||||
|
}
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/tcs-iptv/tcs/internal/chain"
|
||||||
|
"github.com/tcs-iptv/tcs/internal/macode"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newService(t *testing.T) *Service {
|
||||||
|
t.Helper()
|
||||||
|
gen := macode.NewGenerator(macode.NewMemoryStore())
|
||||||
|
require.NoError(t, gen.RegisterSegment(macode.Segment{
|
||||||
|
IndustryNode: "8531", OrgNode: "4401",
|
||||||
|
Category: macode.CategoryMicroDrama, Start: 1, End: 100, SeqWidth: 7,
|
||||||
|
}))
|
||||||
|
return New(chain.NewMemoryChain(), gen)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sampleSub() Submission {
|
||||||
|
return Submission{
|
||||||
|
Title: "示例微短剧", EpisodeCount: 24, Category: macode.CategoryMicroDrama,
|
||||||
|
FileHash: "filehash-abc", MerkleRoot: "merkle-abc", Perceptual: "phash-abc",
|
||||||
|
CPMediaID: "FS-MEDIA-77821", CPName: "飞翮信息",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSubmit_IncompleteHashRejected(t *testing.T) {
|
||||||
|
s := newService(t)
|
||||||
|
_, err := s.SubmitForReview(Submission{Title: "无哈希", Category: macode.CategoryMicroDrama})
|
||||||
|
assert.ErrorIs(t, err, ErrIncompleteHashPkg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSubmit_Success(t *testing.T) {
|
||||||
|
s := newService(t)
|
||||||
|
res, err := s.SubmitForReview(sampleSub())
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.NotEmpty(t, res.ReviewID)
|
||||||
|
assert.NotEmpty(t, res.ContentTwinID)
|
||||||
|
assert.Equal(t, "pending", res.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestApproveAndIssue_GeneratesMACode(t *testing.T) {
|
||||||
|
s := newService(t)
|
||||||
|
sub, err := s.SubmitForReview(sampleSub())
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NoError(t, s.ReviewCSPS(sub.ReviewID, true, "rv-1"))
|
||||||
|
|
||||||
|
issued, err := s.ApproveAndIssue(chain.RoleRegulator, sub.ReviewID, "北京市广播电视局")
|
||||||
|
require.NoError(t, err)
|
||||||
|
// 模式B:MA 码由系统按号段生成
|
||||||
|
assert.True(t, macode.IsValid(issued.MACode), "应生成合法 MA 码: %s", issued.MACode)
|
||||||
|
assert.True(t, strings.HasPrefix(issued.MACode, "MA.156.8531.4401/WD/"), "前缀应匹配号段: %s", issued.MACode)
|
||||||
|
assert.NotEmpty(t, issued.TxID)
|
||||||
|
assert.Contains(t, issued.Certificate, issued.MACode)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestApproveAndIssue_OnlyRegulator(t *testing.T) {
|
||||||
|
s := newService(t)
|
||||||
|
sub, _ := s.SubmitForReview(sampleSub())
|
||||||
|
require.NoError(t, s.ReviewCSPS(sub.ReviewID, true, "rv-1")) // 先过审,才轮到校验角色
|
||||||
|
_, err := s.ApproveAndIssue(chain.RoleCP, sub.ReviewID, "x")
|
||||||
|
assert.ErrorIs(t, err, chain.ErrPermissionDenied)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSubmit_DuplicateRejectedAfterIssue(t *testing.T) {
|
||||||
|
s := newService(t)
|
||||||
|
sub, _ := s.SubmitForReview(sampleSub())
|
||||||
|
require.NoError(t, s.ReviewCSPS(sub.ReviewID, true, "rv-1"))
|
||||||
|
_, err := s.ApproveAndIssue(chain.RoleRegulator, sub.ReviewID, "issuer")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// 同哈希再次送审 → 换壳重发拦截
|
||||||
|
_, err = s.SubmitForReview(sampleSub())
|
||||||
|
assert.ErrorIs(t, err, ErrDuplicateContent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVerify_MatchAndMismatch(t *testing.T) {
|
||||||
|
s := newService(t)
|
||||||
|
sub, _ := s.SubmitForReview(sampleSub())
|
||||||
|
require.NoError(t, s.ReviewCSPS(sub.ReviewID, true, "rv-1"))
|
||||||
|
issued, _ := s.ApproveAndIssue(chain.RoleRegulator, sub.ReviewID, "issuer")
|
||||||
|
|
||||||
|
res, err := s.Verify(issued.MACode, "filehash-abc")
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.True(t, res.Match)
|
||||||
|
|
||||||
|
_, err = s.Verify(issued.MACode, "tampered")
|
||||||
|
assert.ErrorIs(t, err, ErrHashMismatch)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestApproveAndIssue_TwoContentsUniqueCodes(t *testing.T) {
|
||||||
|
s := newService(t)
|
||||||
|
sub1, _ := s.SubmitForReview(sampleSub())
|
||||||
|
require.NoError(t, s.ReviewCSPS(sub1.ReviewID, true, "rv-1"))
|
||||||
|
i1, err := s.ApproveAndIssue(chain.RoleRegulator, sub1.ReviewID, "issuer")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
sub2v := sampleSub()
|
||||||
|
sub2v.FileHash = "filehash-def"
|
||||||
|
sub2v.MerkleRoot = "merkle-def"
|
||||||
|
sub2, _ := s.SubmitForReview(sub2v)
|
||||||
|
require.NoError(t, s.ReviewCSPS(sub2.ReviewID, true, "rv-1"))
|
||||||
|
i2, err := s.ApproveAndIssue(chain.RoleRegulator, sub2.ReviewID, "issuer")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert.NotEqual(t, i1.MACode, i2.MACode, "两条内容应分配不同 MA 码")
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# 端到端冒烟:送审→发码签发→CSPS→入库→发布→注入→下架
|
||||||
|
# 依赖:api-svc 运行在 :8080
|
||||||
|
set -e
|
||||||
|
BASE="http://localhost:8080/api/v1"
|
||||||
|
|
||||||
|
# HMAC 签名工具(与 httpx.Sign 一致:base64(HMAC-SHA256(secret, METHOD\nPATH)))
|
||||||
|
sign() { # secret method path
|
||||||
|
printf '%s\n%s' "$2" "$3" | openssl dgst -sha256 -hmac "$1" -binary | base64
|
||||||
|
}
|
||||||
|
|
||||||
|
call() { # apiKey secret method path jsonBody
|
||||||
|
local key="$1" secret="$2" method="$3" path="$4" body="$5"
|
||||||
|
# 签名只用 path(不含 query),与 Go 端 c.Request.URL.Path 一致
|
||||||
|
local sigpath="/api/v1${path%%\?*}"
|
||||||
|
local sig; sig=$(sign "$secret" "$method" "$sigpath")
|
||||||
|
if [ "$method" = "GET" ]; then
|
||||||
|
curl -s -X GET "$BASE$path" -H "Authorization: TCS $key:$sig"
|
||||||
|
else
|
||||||
|
curl -s -X "$method" "$BASE$path" \
|
||||||
|
-H "Authorization: TCS $key:$sig" \
|
||||||
|
-H "Content-Type: application/json" -d "$body"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "== 1) CP 送审 =="
|
||||||
|
REG=$(call ak-cp sk-cp POST /content/register \
|
||||||
|
'{"title":"示例微短剧","episode_count":24,"category":"WD","file_sha256":"fh-001","merkle_root":"mr-001","perceptual_hash":"ph-001","cp_media_id":"FS-77821","cp_name":"飞翮信息"}')
|
||||||
|
echo "$REG"
|
||||||
|
REVIEW_ID=$(echo "$REG" | sed -n 's/.*"review_id":"\([^"]*\)".*/\1/p')
|
||||||
|
CTID=$(echo "$REG" | sed -n 's/.*"content_twin_id":"\([^"]*\)".*/\1/p')
|
||||||
|
echo "review_id=$REVIEW_ID ctid=$CTID"
|
||||||
|
|
||||||
|
echo "== 2) 监管发码签发 =="
|
||||||
|
ISS=$(call ak-regulator sk-regulator POST /content/issue \
|
||||||
|
"{\"review_id\":\"$REVIEW_ID\",\"issuer\":\"北京市广播电视局\"}")
|
||||||
|
echo "$ISS"
|
||||||
|
MA=$(echo "$ISS" | sed -n 's/.*"ma_code":"\([^"]*\)".*/\1/p')
|
||||||
|
CERT=$(echo "$ISS" | sed -n 's/.*"certificate":"\([^"]*\)".*/\1/p')
|
||||||
|
echo "ma_code=$MA"
|
||||||
|
|
||||||
|
echo "== 3) CSPS 审核通过 =="
|
||||||
|
call ak-reviewer sk-reviewer POST /content/csps-result \
|
||||||
|
"{\"ma_code\":\"$MA\",\"approved\":true,\"reviewer_id\":\"rv-1\"}"; echo
|
||||||
|
|
||||||
|
echo "== 4) 入媒资库 =="
|
||||||
|
call ak-reviewer sk-reviewer POST /content/ingest \
|
||||||
|
"{\"ma_code\":\"$MA\",\"content_twin_id\":\"$CTID\",\"media_asset_id\":\"MEDIA-001\",\"lib_name\":\"广东IPTV媒资库\"}"; echo
|
||||||
|
|
||||||
|
echo "== 5) 发布给运营商 =="
|
||||||
|
call ak-reviewer sk-reviewer POST /content/publish \
|
||||||
|
"{\"ma_code\":\"$MA\",\"certificate\":\"$CERT\"}"; echo
|
||||||
|
|
||||||
|
echo "== 6) CDN 注入校验(匹配) =="
|
||||||
|
call ak-operator sk-operator POST /content/inject \
|
||||||
|
"{\"content_twin_id\":\"$CTID\",\"ma_code\":\"$MA\",\"file_sha256\":\"fh-001\",\"operator_id\":\"CT-IPTV-GD\",\"cdn_endpoint\":\"cdn://ct-gd/vod/1\"}"; echo
|
||||||
|
|
||||||
|
echo "== 7) CDN 注入校验(篡改,应拒绝) =="
|
||||||
|
call ak-operator sk-operator POST /content/inject \
|
||||||
|
"{\"content_twin_id\":\"$CTID\",\"ma_code\":\"$MA\",\"file_sha256\":\"tampered\",\"operator_id\":\"CT-IPTV-GD\",\"cdn_endpoint\":\"cdn://x\"}"; echo
|
||||||
|
|
||||||
|
echo "== 8) 映射查询 =="
|
||||||
|
call ak-regulator sk-regulator GET "/content/mappings?ma_code=$MA" ""; echo
|
||||||
|
|
||||||
|
echo "== 9) 运营商越权下架(应拒绝) =="
|
||||||
|
call ak-operator sk-operator POST /content/takedown \
|
||||||
|
"{\"ma_code\":\"$MA\",\"reason\":\"越权\"}"; echo
|
||||||
|
|
||||||
|
echo "== 10) 监管应急下架 =="
|
||||||
|
call ak-regulator sk-regulator POST /content/takedown \
|
||||||
|
"{\"ma_code\":\"$MA\",\"reason\":\"违规\"}"; echo
|
||||||
|
|
||||||
|
echo "== 完成 =="
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# 陕西 IPTV 场景演示数据:造若干条内容,跑通"送审→发码→审核→入库→发布→注入"。
|
||||||
|
#
|
||||||
|
# 参与方设定:
|
||||||
|
# 管理方(审核+监管):陕西IPTV运营公司(机构节点 6101)
|
||||||
|
# 内容提供商(CP):西安曲江丝路文化传播 / 陕文投艺达影视 / 西部电影集团(西影)
|
||||||
|
# 运营商:中国电信陕西(天翼高清) / 中国移动陕西(魔百和) / 中国联通陕西
|
||||||
|
set -e
|
||||||
|
BASE="http://localhost:8080/api/v1"
|
||||||
|
|
||||||
|
sign() { printf '%s\n%s' "$2" "$3" | openssl dgst -sha256 -hmac "$1" -binary | base64; }
|
||||||
|
call() { # key secret method path body
|
||||||
|
local key="$1" secret="$2" method="$3" path="$4" body="$5"
|
||||||
|
local sig; sig=$(sign "$secret" "$method" "/api/v1${path%%\?*}")
|
||||||
|
if [ "$method" = "GET" ]; then
|
||||||
|
curl -s -X GET "$BASE$path" -H "Authorization: TCS $key:$sig"
|
||||||
|
else
|
||||||
|
curl -s -X "$method" "$BASE$path" -H "Authorization: TCS $key:$sig" \
|
||||||
|
-H "Content-Type: application/json" -d "$body"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
field() { echo "$1" | sed -n "s/.*\"$2\":\"\([^\"]*\)\".*/\1/p"; }
|
||||||
|
|
||||||
|
# 一条内容完整流转:title category fhash cp_id cp_name op_id op_name cdn
|
||||||
|
flow() {
|
||||||
|
local title="$1" cat="$2" fh="$3" cpid="$4" cpname="$5" opid="$6" opname="$7" cdn="$8"
|
||||||
|
echo ">>> [$title] CP=$cpname"
|
||||||
|
local reg; reg=$(call ak-cp sk-cp POST /content/register \
|
||||||
|
"{\"title\":\"$title\",\"episode_count\":24,\"category\":\"$cat\",\"file_sha256\":\"$fh\",\"merkle_root\":\"mr-$fh\",\"perceptual_hash\":\"ph-$fh\",\"cp_media_id\":\"$cpid\",\"cp_name\":\"$cpname\"}")
|
||||||
|
local rid ctid; rid=$(field "$reg" review_id); ctid=$(field "$reg" content_twin_id)
|
||||||
|
|
||||||
|
# CSPS 合规审核(发码前)
|
||||||
|
call ak-reviewer sk-reviewer POST /content/csps-result \
|
||||||
|
"{\"review_id\":\"$rid\",\"approved\":true,\"reviewer_id\":\"sxiptv-审核员01\"}" >/dev/null
|
||||||
|
|
||||||
|
# 审核通过后发码签发
|
||||||
|
local iss; iss=$(call ak-regulator sk-regulator POST /content/issue \
|
||||||
|
"{\"review_id\":\"$rid\",\"issuer\":\"陕西IPTV运营公司\"}")
|
||||||
|
local ma cert; ma=$(field "$iss" ma_code); cert=$(field "$iss" certificate)
|
||||||
|
echo " MA码: $ma"
|
||||||
|
|
||||||
|
call ak-reviewer sk-reviewer POST /content/ingest \
|
||||||
|
"{\"ma_code\":\"$ma\",\"content_twin_id\":\"$ctid\",\"media_asset_id\":\"SXMEDIA-$fh\",\"lib_name\":\"陕西IPTV媒体资源库\"}" >/dev/null
|
||||||
|
call ak-reviewer sk-reviewer POST /content/publish \
|
||||||
|
"{\"ma_code\":\"$ma\",\"certificate\":\"$cert\"}" >/dev/null
|
||||||
|
local inj; inj=$(call ak-operator sk-operator POST /content/inject \
|
||||||
|
"{\"content_twin_id\":\"$ctid\",\"ma_code\":\"$ma\",\"file_sha256\":\"$fh\",\"operator_id\":\"$opid\",\"cdn_endpoint\":\"$cdn\"}")
|
||||||
|
echo " 运营商: $opname 注入: $(field "$inj" distribution_id)"
|
||||||
|
echo "$ma" >> /tmp/tcs_demo_macodes.txt
|
||||||
|
}
|
||||||
|
|
||||||
|
: > /tmp/tcs_demo_macodes.txt
|
||||||
|
|
||||||
|
flow "长安少年行" WD "fh-changan-001" \
|
||||||
|
"XAQJSL-2026-001" "西安曲江丝路文化传播有限公司" \
|
||||||
|
"CT-SX-IPTV" "中国电信陕西公司(天翼高清)" "cdn://ct-sx/iptv/vod/changan001"
|
||||||
|
|
||||||
|
flow "白鹿原·麦客" WJ "fh-bailuyuan-002" \
|
||||||
|
"SWTYD-2026-007" "陕文投艺达影视有限公司" \
|
||||||
|
"CM-SX-IPTV" "中国移动陕西公司(魔百和)" "cdn://cm-sx/iptv/vod/bailuyuan002"
|
||||||
|
|
||||||
|
flow "丝路驼铃" DY "fh-silu-003" \
|
||||||
|
"XIYING-2026-015" "西部电影集团(西影视频)" \
|
||||||
|
"CU-SX-IPTV" "中国联通陕西公司" "cdn://cu-sx/iptv/vod/silu003"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== 已生成 MA 码(可复制到监管大屏查询)==="
|
||||||
|
cat /tmp/tcs_demo_macodes.txt
|
||||||
|
echo ""
|
||||||
|
echo "提示:在 http://localhost:5174 输入上述任一 MA 码查询全链路三方映射。"
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>TCS-IPTV 监管大屏</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="root"></div>
|
||||||
|
<script type="module" src="/src/main.jsx"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"name": "tcs-iptv-console",
|
||||||
|
"private": true,
|
||||||
|
"version": "1.0.0",
|
||||||
|
"type": "module",
|
||||||
|
"description": "TCS-IPTV 监管大屏(全生命周期查询 + 应急下架 + 哈希验真)",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "vite build",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"antd": "^5.21.0",
|
||||||
|
"react": "^18.3.1",
|
||||||
|
"react-dom": "^18.3.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@vitejs/plugin-react": "^4.3.1",
|
||||||
|
"vite": "^5.4.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,158 @@
|
|||||||
|
import React, { useState } from 'react'
|
||||||
|
import {
|
||||||
|
Layout, Typography, Card, Input, Button, Space, Table, Tag,
|
||||||
|
message, Modal, Descriptions, Alert, Row, Col, Statistic, Tabs,
|
||||||
|
} from 'antd'
|
||||||
|
import { SearchOutlined, StopOutlined, CheckCircleOutlined } from '@ant-design/icons'
|
||||||
|
import { api } from './api.js'
|
||||||
|
import FlowDemo from './FlowDemo.jsx'
|
||||||
|
import RoleDesk from './RoleDesk.jsx'
|
||||||
|
|
||||||
|
const { Header, Content } = Layout
|
||||||
|
const { Title, Text } = Typography
|
||||||
|
|
||||||
|
const partyLabel = { cp: '内容提供商', reviewer: '审核和监管部门', operator: '运营商' }
|
||||||
|
const partyColor = { cp: 'green', reviewer: 'blue', operator: 'orange' }
|
||||||
|
|
||||||
|
function RegulatorConsole() {
|
||||||
|
const [maCode, setMaCode] = useState('')
|
||||||
|
const [loading, setLoading] = useState(false)
|
||||||
|
const [mappings, setMappings] = useState(null)
|
||||||
|
const [cdnEndpoints, setCdnEndpoints] = useState([])
|
||||||
|
const [verifyHash, setVerifyHash] = useState('')
|
||||||
|
const [verifyResult, setVerifyResult] = useState(null)
|
||||||
|
|
||||||
|
async function doQuery() {
|
||||||
|
if (!maCode) return message.warning('请输入 MA 码')
|
||||||
|
setLoading(true)
|
||||||
|
try {
|
||||||
|
const { status, data } = await api.mappings(maCode)
|
||||||
|
if (status === 200) {
|
||||||
|
setMappings(data.data.mappings || [])
|
||||||
|
setCdnEndpoints(data.data.cdn_endpoints || [])
|
||||||
|
message.success('查询成功')
|
||||||
|
} else {
|
||||||
|
setMappings(null); setCdnEndpoints([])
|
||||||
|
message.error(data.message || '查询失败')
|
||||||
|
}
|
||||||
|
} catch (e) { message.error('请求失败:' + e.message) }
|
||||||
|
setLoading(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function doVerify() {
|
||||||
|
if (!maCode || !verifyHash) return message.warning('请输入 MA 码与文件哈希')
|
||||||
|
try {
|
||||||
|
const { status, data } = await api.verify(maCode, verifyHash)
|
||||||
|
setVerifyResult({ ok: status === 200, ...data })
|
||||||
|
} catch (e) { message.error('请求失败:' + e.message) }
|
||||||
|
}
|
||||||
|
|
||||||
|
function confirmTakedown() {
|
||||||
|
if (!maCode) return message.warning('请先输入 MA 码')
|
||||||
|
Modal.confirm({
|
||||||
|
title: '违规应急下架',
|
||||||
|
content: `确认对 ${maCode} 执行全网下架?该操作将解析三方编码并秒级同步。`,
|
||||||
|
okText: '确认下架', okType: 'danger', cancelText: '取消',
|
||||||
|
onOk: async () => {
|
||||||
|
const { status, data } = await api.takedown(maCode, '监管大屏手动下架')
|
||||||
|
if (status === 200) {
|
||||||
|
message.success('已下架,受影响 CDN: ' + (data.data.cdn_endpoints || []).join(', '))
|
||||||
|
doQuery()
|
||||||
|
} else {
|
||||||
|
message.error(data.message || '下架失败')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{ title: '角色', dataIndex: 'party', render: (p) => <Tag color={partyColor[p]}>{partyLabel[p] || p}</Tag> },
|
||||||
|
{ title: '本方编码', dataIndex: 'party_id' },
|
||||||
|
{ title: '名称', dataIndex: 'party_name', render: (v) => v || '-' },
|
||||||
|
{ title: 'CDN 端点', dataIndex: 'cdn_endpoint', render: (v) => v || '-' },
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Card title="按 MA 码查询全链路" style={{ marginBottom: 16 }}>
|
||||||
|
<Space.Compact style={{ width: '100%', maxWidth: 720 }}>
|
||||||
|
<Input
|
||||||
|
placeholder="如 MA.156.8531.6101/WD/20260000001"
|
||||||
|
value={maCode} onChange={(e) => setMaCode(e.target.value)}
|
||||||
|
onPressEnter={doQuery}
|
||||||
|
/>
|
||||||
|
<Button type="primary" icon={<SearchOutlined />} loading={loading} onClick={doQuery}>
|
||||||
|
查询
|
||||||
|
</Button>
|
||||||
|
<Button danger icon={<StopOutlined />} onClick={confirmTakedown}>
|
||||||
|
应急下架
|
||||||
|
</Button>
|
||||||
|
</Space.Compact>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
{mappings && (
|
||||||
|
<Row gutter={16} style={{ marginBottom: 16 }}>
|
||||||
|
<Col span={6}><Card><Statistic title="三方映射数" value={mappings.length} /></Card></Col>
|
||||||
|
<Col span={6}><Card><Statistic title="CDN 端点数" value={cdnEndpoints.length} /></Card></Col>
|
||||||
|
</Row>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{mappings && (
|
||||||
|
<Card title="三方编码映射" style={{ marginBottom: 16 }}>
|
||||||
|
<Table rowKey={(r, i) => i} columns={columns} dataSource={mappings} pagination={false} size="middle" />
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Card title="哈希验真">
|
||||||
|
<Space direction="vertical" style={{ width: '100%', maxWidth: 720 }}>
|
||||||
|
<Space.Compact style={{ width: '100%' }}>
|
||||||
|
<Input
|
||||||
|
placeholder="待校验文件哈希(file_sha256)"
|
||||||
|
value={verifyHash} onChange={(e) => setVerifyHash(e.target.value)}
|
||||||
|
/>
|
||||||
|
<Button icon={<CheckCircleOutlined />} onClick={doVerify}>验真</Button>
|
||||||
|
</Space.Compact>
|
||||||
|
{verifyResult && (
|
||||||
|
<Descriptions bordered size="small" column={1}>
|
||||||
|
<Descriptions.Item label="结果">
|
||||||
|
{verifyResult.ok && verifyResult.data?.match
|
||||||
|
? <Tag color="green">匹配(正版过审内容)</Tag>
|
||||||
|
: <Tag color="red">不匹配(疑似版本替换)</Tag>}
|
||||||
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="绑定哈希">{verifyResult.data?.bound_hash || '-'}</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="提交哈希">{verifyResult.data?.submitted_hash || verifyHash}</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="消息">{verifyResult.message || '-'}</Descriptions.Item>
|
||||||
|
</Descriptions>
|
||||||
|
)}
|
||||||
|
</Space>
|
||||||
|
</Card>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function App() {
|
||||||
|
return (
|
||||||
|
<Layout style={{ minHeight: '100vh' }}>
|
||||||
|
<Header style={{ background: '#1a237e', display: 'flex', alignItems: 'center' }}>
|
||||||
|
<Title level={3} style={{ color: '#fff', margin: 0 }}>TCS-IPTV 内容可信锁定系统</Title>
|
||||||
|
<Text style={{ color: '#b3c5ff', marginLeft: 16 }}>
|
||||||
|
陕西IPTV运营公司 · MA码+哈希双锚定
|
||||||
|
</Text>
|
||||||
|
</Header>
|
||||||
|
<Content style={{ padding: 24, background: '#f0f2f5' }}>
|
||||||
|
<Alert
|
||||||
|
type="warning" showIcon style={{ marginBottom: 16 }}
|
||||||
|
message="演示模式:以四角色密钥直连 api-svc。生产环境应改为控制台 BFF + 会话令牌,密钥不下发浏览器。"
|
||||||
|
/>
|
||||||
|
<Tabs
|
||||||
|
defaultActiveKey="desk"
|
||||||
|
items={[
|
||||||
|
{ key: 'desk', label: '角色工作台(多方协作)', children: <RoleDesk /> },
|
||||||
|
{ key: 'flow', label: '全流程演示(一键)', children: <FlowDemo /> },
|
||||||
|
{ key: 'console', label: '监管大屏', children: <RegulatorConsole /> },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</Content>
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,276 @@
|
|||||||
|
import React, { useState } from 'react'
|
||||||
|
import {
|
||||||
|
Card, Steps, Button, Space, Input, Select, Form, Tag, Timeline,
|
||||||
|
Descriptions, message, Row, Col, Typography, Divider, Alert, Table,
|
||||||
|
} from 'antd'
|
||||||
|
import {
|
||||||
|
PlayCircleOutlined, RedoOutlined, StopOutlined, SafetyCertificateOutlined,
|
||||||
|
} from '@ant-design/icons'
|
||||||
|
import { api } from './api.js'
|
||||||
|
|
||||||
|
const { Text, Paragraph } = Typography
|
||||||
|
|
||||||
|
const roleColor = { cp: 'green', regulator: 'red', reviewer: 'blue', operator: 'orange' }
|
||||||
|
const roleLabel = { cp: '内容提供商', regulator: '监管主体', reviewer: '审核/媒资', operator: '运营商' }
|
||||||
|
|
||||||
|
// 七步流水线定义(审核在前,发码在后——审过才发证发码)
|
||||||
|
const STEPS = [
|
||||||
|
{ key: 'register', title: 'CP 送审', role: 'cp', desc: '原片送 CSPS 既有审核渠道 + 哈希包上链(链上不存原片)' },
|
||||||
|
{ key: 'csps', title: 'CSPS 合规审核', role: 'reviewer', desc: '基于原片审画面/台词/声音;验真送审哈希=上链哈希(审播一致)' },
|
||||||
|
{ key: 'issue', title: '审核通过·发码签发', role: 'regulator', desc: '审过才发码:按号段生成 MA 码,1:1 强绑定哈希' },
|
||||||
|
{ key: 'ingest', title: '媒资库入库', role: 'reviewer', desc: '审合格入库,建立媒资编码映射' },
|
||||||
|
{ key: 'publish', title: '发布给运营商', role: 'reviewer', desc: '携 MA 码+哈希证书发布' },
|
||||||
|
{ key: 'inject', title: 'CDN 注入校验', role: 'operator', desc: '注入前哈希比对,匹配放行(防偷换)' },
|
||||||
|
]
|
||||||
|
|
||||||
|
export default function FlowDemo() {
|
||||||
|
const [form] = Form.useForm()
|
||||||
|
const [current, setCurrent] = useState(0)
|
||||||
|
const [running, setRunning] = useState(false)
|
||||||
|
const [logs, setLogs] = useState([])
|
||||||
|
const [ctx, setCtx] = useState({}) // reviewID/ctid/maCode/cert/fileHash/episodeHashes
|
||||||
|
const [done, setDone] = useState(false)
|
||||||
|
const [episodes, setEpisodes] = useState([]) // 集级哈希列表
|
||||||
|
const [epVerify, setEpVerify] = useState({}) // {episode: 'match'|'mismatch'}
|
||||||
|
|
||||||
|
function addLog(role, title, ok, detail) {
|
||||||
|
setLogs((prev) => [...prev, { role, title, ok, detail, t: new Date().toLocaleTimeString() }])
|
||||||
|
}
|
||||||
|
|
||||||
|
function reset() {
|
||||||
|
setCurrent(0); setLogs([]); setCtx({}); setDone(false); setRunning(false)
|
||||||
|
setEpisodes([]); setEpVerify({})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行单步,返回是否成功
|
||||||
|
async function runStep(idx, shared) {
|
||||||
|
const step = STEPS[idx]
|
||||||
|
const v = form.getFieldsValue()
|
||||||
|
const fileHash = shared.fileHash
|
||||||
|
let res
|
||||||
|
switch (step.key) {
|
||||||
|
case 'register':
|
||||||
|
// 一剧一码 + 集级哈希:按集数生成每集独立哈希
|
||||||
|
shared.episodeHashes = []
|
||||||
|
const epArr = []
|
||||||
|
const epCount = Number(v.episodes) || 1
|
||||||
|
for (let i = 1; i <= epCount; i++) {
|
||||||
|
const eh = `${fileHash}-E${i}`
|
||||||
|
shared.episodeHashes.push({ episode: i, hash: eh })
|
||||||
|
epArr.push({ episode: i, file_sha256: eh, merkle_root: `mr-${eh}` })
|
||||||
|
}
|
||||||
|
res = await api.register({
|
||||||
|
title: v.title, episode_count: epCount, category: v.category,
|
||||||
|
file_sha256: fileHash, merkle_root: 'mr-' + fileHash, perceptual_hash: 'ph-' + fileHash,
|
||||||
|
episodes: epArr,
|
||||||
|
cp_media_id: v.cpId, cp_name: v.cpName,
|
||||||
|
})
|
||||||
|
if (res.ok) { shared.reviewID = res.data.data.review_id; shared.ctid = res.data.data.content_twin_id }
|
||||||
|
addLog(step.role, step.title, res.ok, res.ok ? `流水号 ${shared.reviewID}(${epCount}集,每集独立哈希)` : res.data.message)
|
||||||
|
break
|
||||||
|
case 'issue':
|
||||||
|
res = await api.issue({ review_id: shared.reviewID, issuer: '陕西IPTV运营公司' })
|
||||||
|
if (res.ok) { shared.maCode = res.data.data.ma_code; shared.cert = res.data.data.certificate }
|
||||||
|
addLog(step.role, step.title, res.ok, res.ok ? `MA码 ${shared.maCode}` : res.data.message)
|
||||||
|
break
|
||||||
|
case 'csps':
|
||||||
|
res = await api.csps({ review_id: shared.reviewID, approved: true, reviewer_id: 'sxiptv-审核01' })
|
||||||
|
addLog(step.role, step.title, res.ok, res.ok ? '审核通过(发码前置)' : res.data.message)
|
||||||
|
break
|
||||||
|
case 'ingest':
|
||||||
|
res = await api.ingest({
|
||||||
|
ma_code: shared.maCode, content_twin_id: shared.ctid,
|
||||||
|
media_asset_id: 'SXMEDIA-' + fileHash, lib_name: '陕西IPTV媒体资源库',
|
||||||
|
})
|
||||||
|
addLog(step.role, step.title, res.ok, res.ok ? '已入媒资库' : res.data.message)
|
||||||
|
break
|
||||||
|
case 'publish':
|
||||||
|
res = await api.publish({ ma_code: shared.maCode, certificate: shared.cert })
|
||||||
|
addLog(step.role, step.title, res.ok, res.ok ? '已发布' : res.data.message)
|
||||||
|
break
|
||||||
|
case 'inject':
|
||||||
|
res = await api.inject({
|
||||||
|
content_twin_id: shared.ctid, ma_code: shared.maCode, file_sha256: fileHash,
|
||||||
|
operator_id: v.opId, cdn_endpoint: v.cdn,
|
||||||
|
})
|
||||||
|
addLog(step.role, step.title, res.ok,
|
||||||
|
res.ok ? `注入成功 ${res.data.data.distribution_id}` : res.data.message)
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
res = { ok: false }
|
||||||
|
}
|
||||||
|
return res.ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// 一键全流程
|
||||||
|
async function runAll() {
|
||||||
|
setRunning(true); setLogs([]); setDone(false); setCurrent(0)
|
||||||
|
const shared = { fileHash: 'fh-' + Date.now().toString(36) }
|
||||||
|
for (let i = 0; i < STEPS.length; i++) {
|
||||||
|
setCurrent(i)
|
||||||
|
const ok = await runStep(i, shared)
|
||||||
|
if (!ok) {
|
||||||
|
message.error(`第 ${i + 1} 步「${STEPS[i].title}」失败,流程中断`)
|
||||||
|
setRunning(false); setCtx(shared)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
await new Promise((r) => setTimeout(r, 500)) // 放慢便于演示观看
|
||||||
|
}
|
||||||
|
setCurrent(STEPS.length)
|
||||||
|
setCtx(shared); setDone(true); setRunning(false)
|
||||||
|
message.success('全流程跑通:审过即锁定,锁定即通行')
|
||||||
|
await loadEpisodes(shared.maCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadEpisodes(maCode) {
|
||||||
|
const res = await api.episodes(maCode)
|
||||||
|
if (res.ok) setEpisodes(res.data.data.episodes || [])
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按集验真:correct=true 用正确哈希,false 用篡改哈希
|
||||||
|
async function verifyEp(ep, correct) {
|
||||||
|
const realHash = (ctx.episodeHashes || []).find((e) => e.episode === ep)?.hash
|
||||||
|
const submit = correct ? realHash : 'TAMPERED-' + realHash
|
||||||
|
const res = await api.verifyEpisode(ctx.maCode, ep, submit)
|
||||||
|
const matched = res.ok && res.data.data?.match
|
||||||
|
setEpVerify((prev) => ({ ...prev, [ep]: matched ? 'match' : 'mismatch' }))
|
||||||
|
if (matched) message.success(`第${ep}集验真通过`)
|
||||||
|
else message.warning(`第${ep}集不匹配(疑似该集被替换)`)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function doTakedown() {
|
||||||
|
const res = await api.takedown(ctx.maCode, '监管演示下架')
|
||||||
|
if (res.ok) {
|
||||||
|
addLog('regulator', '违规应急下架', true,
|
||||||
|
`秒级下架,受影响 CDN: ${(res.data.data.cdn_endpoints || []).join(', ')}`)
|
||||||
|
message.success('已全网下架')
|
||||||
|
} else message.error(res.data.message)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function doTamperTest() {
|
||||||
|
const res = await api.inject({
|
||||||
|
content_twin_id: ctx.ctid, ma_code: ctx.maCode, file_sha256: 'TAMPERED-' + ctx.fileHash,
|
||||||
|
operator_id: 'OP-X', cdn_endpoint: 'cdn://x',
|
||||||
|
})
|
||||||
|
addLog('operator', '篡改注入测试', !res.ok, res.ok ? '⚠️ 异常:篡改竟通过' : '✅ 已拒绝:' + res.data.message)
|
||||||
|
if (!res.ok) message.success('篡改内容被正确拦截')
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Row gutter={16}>
|
||||||
|
<Col span={9}>
|
||||||
|
<Card title="演示参数" size="small" style={{ marginBottom: 16 }}>
|
||||||
|
<Form form={form} layout="vertical" size="small" initialValues={{
|
||||||
|
title: '长安少年行', category: 'WD', episodes: 6,
|
||||||
|
cpId: 'XAQJSL-2026-001', cpName: '西安曲江丝路文化传播有限公司',
|
||||||
|
opId: 'CT-SX-IPTV', cdn: 'cdn://ct-sx/iptv/vod/changan001',
|
||||||
|
}}>
|
||||||
|
<Form.Item label="作品标题" name="title"><Input /></Form.Item>
|
||||||
|
<Row gutter={8}>
|
||||||
|
<Col span={12}>
|
||||||
|
<Form.Item label="类目" name="category">
|
||||||
|
<Select options={[
|
||||||
|
{ value: 'WD', label: '微短剧' }, { value: 'WJ', label: '网络剧' },
|
||||||
|
{ value: 'DY', label: '网络电影' }, { value: 'DH', label: '网络动画' },
|
||||||
|
]} />
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}><Form.Item label="集数" name="episodes"><Input type="number" /></Form.Item></Col>
|
||||||
|
</Row>
|
||||||
|
<Form.Item label="内容提供商 (CP)" name="cpName"><Input /></Form.Item>
|
||||||
|
<Form.Item label="CP 媒资编码" name="cpId"><Input /></Form.Item>
|
||||||
|
<Form.Item label="运营商编码" name="opId"><Input /></Form.Item>
|
||||||
|
<Form.Item label="CDN 端点" name="cdn"><Input /></Form.Item>
|
||||||
|
</Form>
|
||||||
|
<Space>
|
||||||
|
<Button type="primary" icon={<PlayCircleOutlined />} loading={running} onClick={runAll}>
|
||||||
|
一键全流程
|
||||||
|
</Button>
|
||||||
|
<Button icon={<RedoOutlined />} onClick={reset} disabled={running}>重置</Button>
|
||||||
|
</Space>
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
|
|
||||||
|
<Col span={15}>
|
||||||
|
<Card title="内容生命周期流水线" style={{ marginBottom: 16 }}>
|
||||||
|
<Steps
|
||||||
|
direction="vertical" size="small" current={current}
|
||||||
|
status={running ? 'process' : done ? 'finish' : 'wait'}
|
||||||
|
items={STEPS.map((s) => ({
|
||||||
|
title: <Space>{s.title}<Tag color={roleColor[s.role]}>{roleLabel[s.role]}</Tag></Space>,
|
||||||
|
description: s.desc,
|
||||||
|
}))}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
{done && (
|
||||||
|
<Card title={<Space><SafetyCertificateOutlined />赋码结果(双锚定)</Space>} style={{ marginBottom: 16 }}>
|
||||||
|
<Descriptions bordered size="small" column={1}>
|
||||||
|
<Descriptions.Item label="MA 码(监管锚点)"><Text strong copyable>{ctx.maCode}</Text></Descriptions.Item>
|
||||||
|
<Descriptions.Item label="文件哈希(技术锚点)">{ctx.fileHash}</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="CTID(机器主键)">{ctx.ctid}</Descriptions.Item>
|
||||||
|
</Descriptions>
|
||||||
|
<Divider />
|
||||||
|
<Space>
|
||||||
|
<Button onClick={doTamperTest}>篡改注入测试(应拒绝)</Button>
|
||||||
|
<Button danger icon={<StopOutlined />} onClick={doTakedown}>违规应急下架</Button>
|
||||||
|
</Space>
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{done && episodes.length > 0 && (
|
||||||
|
<Card
|
||||||
|
title={<Space>集级面板<Tag color="purple">一剧一码 · {episodes.length} 集独立哈希</Tag></Space>}
|
||||||
|
style={{ marginBottom: 16 }}
|
||||||
|
extra={<Text type="secondary">集级子标识:{ctx.maCode}#E01 …</Text>}
|
||||||
|
>
|
||||||
|
<Table
|
||||||
|
size="small" rowKey="episode" pagination={false}
|
||||||
|
dataSource={episodes}
|
||||||
|
columns={[
|
||||||
|
{ title: '集号', dataIndex: 'episode', width: 70, render: (e) => <Tag>第 {e} 集</Tag> },
|
||||||
|
{ title: '集级子标识', render: (_, r) => <Text code>{`${ctx.maCode}#E${String(r.episode).padStart(2, '0')}`}</Text> },
|
||||||
|
{ title: '该集哈希', dataIndex: 'hash_value', ellipsis: true },
|
||||||
|
{
|
||||||
|
title: '验真状态', width: 110, render: (_, r) => {
|
||||||
|
const st = epVerify[r.episode]
|
||||||
|
if (st === 'match') return <Tag color="green">匹配</Tag>
|
||||||
|
if (st === 'mismatch') return <Tag color="red">不匹配</Tag>
|
||||||
|
return <Tag>未验</Tag>
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '按集验真', width: 200, render: (_, r) => (
|
||||||
|
<Space>
|
||||||
|
<Button size="small" onClick={() => verifyEp(r.episode, true)}>正确</Button>
|
||||||
|
<Button size="small" danger onClick={() => verifyEp(r.episode, false)}>模拟篡改</Button>
|
||||||
|
</Space>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Card title="执行日志" size="small">
|
||||||
|
{logs.length === 0
|
||||||
|
? <Alert type="info" message='点击「一键全流程」开始演示' />
|
||||||
|
: <Timeline items={logs.map((l) => ({
|
||||||
|
color: l.ok ? 'green' : 'red',
|
||||||
|
children: (
|
||||||
|
<Space direction="vertical" size={0}>
|
||||||
|
<Space>
|
||||||
|
<Tag color={roleColor[l.role]}>{roleLabel[l.role]}</Tag>
|
||||||
|
<Text strong>{l.title}</Text>
|
||||||
|
<Text type="secondary" style={{ fontSize: 12 }}>{l.t}</Text>
|
||||||
|
</Space>
|
||||||
|
<Text type={l.ok ? 'success' : 'danger'}>{l.detail}</Text>
|
||||||
|
</Space>
|
||||||
|
),
|
||||||
|
}))} />
|
||||||
|
}
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,430 @@
|
|||||||
|
import React, { useState, useEffect } from 'react'
|
||||||
|
import {
|
||||||
|
Card, Tabs, Table, Button, Space, Tag, Form, Input, Select, message,
|
||||||
|
Typography, Empty, Badge, Modal, Descriptions, Segmented,
|
||||||
|
} from 'antd'
|
||||||
|
import { ReloadOutlined, SendOutlined, StopOutlined } from '@ant-design/icons'
|
||||||
|
import { call, api } from './api.js'
|
||||||
|
|
||||||
|
const { Text } = Typography
|
||||||
|
|
||||||
|
const statusMeta = {
|
||||||
|
approved: { label: '待入库', color: 'green' },
|
||||||
|
in_library: { label: '在库待发布', color: 'cyan' },
|
||||||
|
published: { label: '流通中', color: 'blue' },
|
||||||
|
revoked: { label: '已下架', color: 'red' },
|
||||||
|
}
|
||||||
|
|
||||||
|
const catLabel = { WD: '微短剧', WJ: '网络剧', DY: '网络电影', DH: '网络动画' }
|
||||||
|
|
||||||
|
// 各角色工作台共享的刷新钩子:通过 bump 触发全局重拉
|
||||||
|
function useTick() {
|
||||||
|
const [tick, setTick] = useState(0)
|
||||||
|
return [tick, () => setTick((t) => t + 1)]
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============ CP 工作台 ============
|
||||||
|
function CPDesk({ onChanged }) {
|
||||||
|
const [form] = Form.useForm()
|
||||||
|
const [submitting, setSubmitting] = useState(false)
|
||||||
|
|
||||||
|
async function submit() {
|
||||||
|
const v = await form.validateFields()
|
||||||
|
setSubmitting(true)
|
||||||
|
const fh = 'fh-' + Date.now().toString(36)
|
||||||
|
const epCount = Number(v.episodes) || 1
|
||||||
|
const episodes = []
|
||||||
|
for (let i = 1; i <= epCount; i++) {
|
||||||
|
episodes.push({ episode: i, file_sha256: `${fh}-E${i}`, merkle_root: `mr-${fh}-E${i}` })
|
||||||
|
}
|
||||||
|
const res = await call('cp', 'POST', '/content/register', {
|
||||||
|
title: v.title, episode_count: epCount, category: v.category,
|
||||||
|
file_sha256: fh, merkle_root: 'mr-' + fh, perceptual_hash: 'ph-' + fh,
|
||||||
|
episodes, cp_media_id: v.cpId, cp_name: v.cpName,
|
||||||
|
})
|
||||||
|
setSubmitting(false)
|
||||||
|
if (res.ok) {
|
||||||
|
message.success(`送审成功,流水号 ${res.data.data.review_id}(原片走审核渠道,哈希上链)`)
|
||||||
|
onChanged()
|
||||||
|
} else message.error(res.data.message || '送审失败')
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card title="内容提供商工作台 · 送审申报" size="small">
|
||||||
|
<Form form={form} layout="inline" initialValues={{
|
||||||
|
title: '长安少年行', category: 'WD', episodes: 6,
|
||||||
|
cpId: 'XAQJSL-2026-001', cpName: '西安曲江丝路文化传播有限公司',
|
||||||
|
}}>
|
||||||
|
<Form.Item label="作品" name="title" rules={[{ required: true }]}><Input style={{ width: 160 }} /></Form.Item>
|
||||||
|
<Form.Item label="类目" name="category">
|
||||||
|
<Select style={{ width: 110 }} options={Object.entries(catLabel).map(([v, l]) => ({ value: v, label: l }))} />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item label="集数" name="episodes"><Input type="number" style={{ width: 80 }} /></Form.Item>
|
||||||
|
<Form.Item label="CP" name="cpName"><Input style={{ width: 220 }} /></Form.Item>
|
||||||
|
<Form.Item name="cpId" hidden><Input /></Form.Item>
|
||||||
|
<Form.Item>
|
||||||
|
<Button type="primary" icon={<SendOutlined />} loading={submitting} onClick={submit}>
|
||||||
|
送审(原片送审核 + 哈希上链)
|
||||||
|
</Button>
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
<Text type="secondary" style={{ fontSize: 12 }}>
|
||||||
|
送审后到「审核监管工作台」的"待审队列"领取审核。
|
||||||
|
</Text>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============ 审核监管工作台 ============
|
||||||
|
function ReviewerDesk({ tick, onChanged }) {
|
||||||
|
const [pending, setPending] = useState([])
|
||||||
|
const [toIssue, setToIssue] = useState([])
|
||||||
|
const [toIngest, setToIngest] = useState([])
|
||||||
|
const [toPublish, setToPublish] = useState([])
|
||||||
|
|
||||||
|
async function load() {
|
||||||
|
const [p, i, ing, pub] = await Promise.all([
|
||||||
|
call('reviewer', 'GET', '/content/reviews?status=pending'),
|
||||||
|
call('regulator', 'GET', '/content/reviews?status=approved'),
|
||||||
|
call('reviewer', 'GET', '/content/list?status=approved'),
|
||||||
|
call('reviewer', 'GET', '/content/list?status=in_library'),
|
||||||
|
])
|
||||||
|
setPending(p.data?.data?.reviews || [])
|
||||||
|
setToIssue(i.data?.data?.reviews || [])
|
||||||
|
setToIngest(ing.data?.data?.contents || [])
|
||||||
|
setToPublish(pub.data?.data?.contents || [])
|
||||||
|
}
|
||||||
|
useEffect(() => { load() }, [tick])
|
||||||
|
|
||||||
|
async function review(reviewID, approved) {
|
||||||
|
const res = await call('reviewer', 'POST', '/content/csps-result', { review_id: reviewID, approved, reviewer_id: 'sxiptv-审核01' })
|
||||||
|
if (res.ok) { message.success(approved ? 'CSPS 审核通过' : '已驳回'); onChanged() }
|
||||||
|
else message.error(res.data.message)
|
||||||
|
}
|
||||||
|
async function issue(reviewID) {
|
||||||
|
const res = await call('regulator', 'POST', '/content/issue', { review_id: reviewID, issuer: '陕西IPTV运营公司' })
|
||||||
|
if (res.ok) { message.success(`发码成功:${res.data.data.ma_code}`); onChanged() }
|
||||||
|
else message.error(res.data.message)
|
||||||
|
}
|
||||||
|
async function ingest(r) {
|
||||||
|
const res = await call('reviewer', 'POST', '/content/ingest', { ma_code: r.ma_code, content_twin_id: r.content_twin_id, media_asset_id: 'SXMEDIA-' + r.ma_code.slice(-4), lib_name: '陕西IPTV媒体资源库' })
|
||||||
|
if (res.ok) { message.success('已入媒资库'); onChanged() }
|
||||||
|
else message.error(res.data.message)
|
||||||
|
}
|
||||||
|
async function publish(r) {
|
||||||
|
const cert = `CERT|${r.ma_code}|x|x` // 演示证书;真实证书在发码时返回
|
||||||
|
const res = await call('reviewer', 'POST', '/content/publish', { ma_code: r.ma_code, certificate: cert })
|
||||||
|
if (res.ok) { message.success('已发布给运营商'); onChanged() }
|
||||||
|
else message.error(res.data.message + '(提示:发布需发码时的原始证书,演示可用全流程页)')
|
||||||
|
}
|
||||||
|
|
||||||
|
const reviewCols = [
|
||||||
|
{ title: '流水号', dataIndex: 'review_id' },
|
||||||
|
{ title: '作品', dataIndex: 'title' },
|
||||||
|
{ title: '类目', dataIndex: 'category', render: (c) => <Tag>{catLabel[c] || c}</Tag> },
|
||||||
|
{ title: 'CP', dataIndex: 'cp_name', ellipsis: true },
|
||||||
|
{ title: '操作', render: (_, r) => (
|
||||||
|
<Space>
|
||||||
|
<Button size="small" type="primary" onClick={() => review(r.review_id, true)}>审核通过</Button>
|
||||||
|
<Button size="small" danger onClick={() => review(r.review_id, false)}>驳回</Button>
|
||||||
|
</Space>
|
||||||
|
) },
|
||||||
|
]
|
||||||
|
const issueCols = [
|
||||||
|
{ title: '流水号', dataIndex: 'review_id' },
|
||||||
|
{ title: '作品', dataIndex: 'title' },
|
||||||
|
{ title: '类目', dataIndex: 'category', render: (c) => <Tag color="blue">{catLabel[c] || c}</Tag> },
|
||||||
|
{ title: '操作', render: (_, r) => <Button size="small" type="primary" onClick={() => issue(r.review_id)}>发码签发</Button> },
|
||||||
|
]
|
||||||
|
const contentCols = (action, label, color) => [
|
||||||
|
{ title: 'MA 码', dataIndex: 'ma_code', render: (v) => <Text code copyable>{v}</Text> },
|
||||||
|
{ title: '作品', dataIndex: 'title' },
|
||||||
|
{ title: '状态', dataIndex: 'status', render: (s) => <Tag>{s}</Tag> },
|
||||||
|
{ title: '操作', render: (_, r) => <Button size="small" type="primary" onClick={() => action(r)}>{label}</Button> },
|
||||||
|
]
|
||||||
|
|
||||||
|
const queue = (title, count, table) => (
|
||||||
|
<Card size="small" title={<Space>{title}<Badge count={count} showZero color={count ? '#1677ff' : '#ccc'} /></Space>} style={{ marginBottom: 12 }}>
|
||||||
|
{table}
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Button icon={<ReloadOutlined />} size="small" onClick={load} style={{ marginBottom: 12 }}>刷新队列</Button>
|
||||||
|
{queue('① 待审队列(CSPS 合规审核)', pending.length,
|
||||||
|
<Table rowKey="review_id" size="small" pagination={false} columns={reviewCols} dataSource={pending}
|
||||||
|
locale={{ emptyText: <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description="暂无待审" /> }} />)}
|
||||||
|
{queue('② 待发码队列(审核通过 → 发码)', toIssue.length,
|
||||||
|
<Table rowKey="review_id" size="small" pagination={false} columns={issueCols} dataSource={toIssue}
|
||||||
|
locale={{ emptyText: <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description="暂无待发码" /> }} />)}
|
||||||
|
{queue('③ 待入库队列(已发码 → 入媒资库)', toIngest.length,
|
||||||
|
<Table rowKey="ma_code" size="small" pagination={false}
|
||||||
|
columns={contentCols(ingest, '入媒资库', 'green')} dataSource={toIngest}
|
||||||
|
locale={{ emptyText: <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description="暂无待入库" /> }} />)}
|
||||||
|
{queue('④ 待发布队列(已入库 → 发布运营商)', toPublish.length,
|
||||||
|
<Table rowKey="ma_code" size="small" pagination={false}
|
||||||
|
columns={contentCols(publish, '发布', 'orange')} dataSource={toPublish}
|
||||||
|
locale={{ emptyText: <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description="暂无待发布" /> }} />)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============ 运营商工作台 ============
|
||||||
|
function OperatorDesk({ tick, onChanged }) {
|
||||||
|
const [toInject, setToInject] = useState([])
|
||||||
|
async function load() {
|
||||||
|
const res = await call('operator', 'GET', '/content/list?status=published')
|
||||||
|
setToInject(res.data?.data?.contents || [])
|
||||||
|
}
|
||||||
|
useEffect(() => { load() }, [tick])
|
||||||
|
|
||||||
|
async function inject(r, tamper) {
|
||||||
|
const fh = tamper ? 'TAMPERED-' + r.file_hash : r.file_hash
|
||||||
|
const res = await call('operator', 'POST', '/content/inject', {
|
||||||
|
content_twin_id: r.content_twin_id, ma_code: r.ma_code, file_sha256: fh,
|
||||||
|
operator_id: 'CT-SX-IPTV', cdn_endpoint: 'cdn://ct-sx/vod/' + r.ma_code.slice(-4),
|
||||||
|
})
|
||||||
|
if (res.ok) { message.success(`注入成功 ${res.data.data.distribution_id}`); onChanged() }
|
||||||
|
else message.warning('注入校验:' + (res.data.message || '哈希不匹配被拒'))
|
||||||
|
}
|
||||||
|
|
||||||
|
const cols = [
|
||||||
|
{ title: 'MA 码', dataIndex: 'ma_code', render: (v) => <Text code>{v}</Text> },
|
||||||
|
{ title: '作品', dataIndex: 'title' },
|
||||||
|
{ title: '操作', render: (_, r) => (
|
||||||
|
<Space>
|
||||||
|
<Button size="small" type="primary" onClick={() => inject(r, false)}>CDN 注入(正确)</Button>
|
||||||
|
<Button size="small" danger onClick={() => inject(r, true)}>模拟篡改注入</Button>
|
||||||
|
</Space>
|
||||||
|
) },
|
||||||
|
]
|
||||||
|
return (
|
||||||
|
<Card size="small" title={<Space>运营商工作台 · 待注入队列<Badge count={toInject.length} showZero /></Space>}
|
||||||
|
extra={<Button icon={<ReloadOutlined />} size="small" onClick={load}>刷新</Button>}>
|
||||||
|
<Table rowKey="ma_code" size="small" pagination={false} columns={cols} dataSource={toInject}
|
||||||
|
locale={{ emptyText: <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description="暂无待注入(需先在审核台发布)" /> }} />
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============ 总览看板 ============
|
||||||
|
function Overview({ tick }) {
|
||||||
|
const [counts, setCounts] = useState({})
|
||||||
|
async function load() {
|
||||||
|
const statuses = ['approved', 'in_library', 'published', 'revoked']
|
||||||
|
const results = await Promise.all([
|
||||||
|
call('regulator', 'GET', '/content/reviews?status=pending'),
|
||||||
|
call('regulator', 'GET', '/content/reviews?status=approved'),
|
||||||
|
...statuses.map((s) => call('regulator', 'GET', '/content/list?status=' + s)),
|
||||||
|
])
|
||||||
|
setCounts({
|
||||||
|
pending: results[0].data?.data?.reviews?.length || 0,
|
||||||
|
toIssue: results[1].data?.data?.reviews?.length || 0,
|
||||||
|
toIngest: results[2].data?.data?.contents?.length || 0,
|
||||||
|
toPublish: results[3].data?.data?.contents?.length || 0,
|
||||||
|
published: results[4].data?.data?.contents?.length || 0,
|
||||||
|
revoked: results[5].data?.data?.contents?.length || 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
useEffect(() => { load() }, [tick])
|
||||||
|
|
||||||
|
const items = [
|
||||||
|
{ label: '待审', v: counts.pending, c: '#faad14' },
|
||||||
|
{ label: '待发码', v: counts.toIssue, c: '#1677ff' },
|
||||||
|
{ label: '待入库', v: counts.toIngest, c: '#52c41a' },
|
||||||
|
{ label: '待发布', v: counts.toPublish, c: '#fa8c16' },
|
||||||
|
{ label: '已发布(流通中)', v: counts.published, c: '#13c2c2' },
|
||||||
|
{ label: '已下架', v: counts.revoked, c: '#f5222d' },
|
||||||
|
]
|
||||||
|
return (
|
||||||
|
<Card size="small" title="全局看板(各环节在途数量)" extra={<Button icon={<ReloadOutlined />} size="small" onClick={load}>刷新</Button>}>
|
||||||
|
<Space size="large" wrap>
|
||||||
|
{items.map((it) => (
|
||||||
|
<Card key={it.label} size="small" style={{ width: 130, textAlign: 'center', borderTop: `3px solid ${it.c}` }}>
|
||||||
|
<div style={{ fontSize: 28, fontWeight: 700, color: it.c }}>{it.v ?? 0}</div>
|
||||||
|
<div style={{ color: '#888' }}>{it.label}</div>
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
|
</Space>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============ 监管片库 ============
|
||||||
|
function LibraryDesk({ tick, onChanged }) {
|
||||||
|
const [filter, setFilter] = useState('all')
|
||||||
|
const [rows, setRows] = useState([])
|
||||||
|
const [loading, setLoading] = useState(false)
|
||||||
|
const [detail, setDetail] = useState(null) // {maCode, mappings, episodes}
|
||||||
|
|
||||||
|
async function load() {
|
||||||
|
setLoading(true)
|
||||||
|
const status = filter === 'all' ? '' : filter
|
||||||
|
const res = await call('regulator', 'GET', '/content/list?status=' + status)
|
||||||
|
setRows(res.data?.data?.contents || [])
|
||||||
|
setLoading(false)
|
||||||
|
}
|
||||||
|
useEffect(() => { load() }, [tick, filter])
|
||||||
|
|
||||||
|
function confirmTakedown(r) {
|
||||||
|
Modal.confirm({
|
||||||
|
title: '违规应急下架',
|
||||||
|
content: `确认对《${r.title}》(${r.ma_code}) 执行全网下架?将解析三方编码秒级同步。`,
|
||||||
|
okText: '确认下架', okType: 'danger', cancelText: '取消',
|
||||||
|
onOk: async () => {
|
||||||
|
const res = await api.takedown(r.ma_code, '监管片库应急下架')
|
||||||
|
if (res.ok) {
|
||||||
|
message.success('已全网下架,受影响 CDN: ' + (res.data.data.cdn_endpoints || []).join(', '))
|
||||||
|
onChanged()
|
||||||
|
} else message.error(res.data.message || '下架失败')
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function viewDetail(r) {
|
||||||
|
const [m, e] = await Promise.all([api.mappings(r.ma_code), api.episodes(r.ma_code)])
|
||||||
|
setDetail({
|
||||||
|
content: r,
|
||||||
|
mappings: m.data?.data?.mappings || [],
|
||||||
|
cdn: m.data?.data?.cdn_endpoints || [],
|
||||||
|
episodes: e.data?.data?.episodes || [],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function takedownEpisode(maCode, episode) {
|
||||||
|
Modal.confirm({
|
||||||
|
title: `集级下架 · 第 ${episode} 集`,
|
||||||
|
content: `只下架《${maCode}#E${String(episode).padStart(2, '0')}》本集,整剧其他集继续流通。确认?`,
|
||||||
|
okText: '下架本集', okType: 'danger', cancelText: '取消',
|
||||||
|
onOk: async () => {
|
||||||
|
const res = await api.takedownEpisode(maCode, episode, '监管片库集级下架')
|
||||||
|
if (res.ok) {
|
||||||
|
message.success(`第 ${episode} 集已下架`)
|
||||||
|
await viewDetail(detail.content) // 刷新弹窗
|
||||||
|
onChanged()
|
||||||
|
} else message.error(res.data.message || '下架失败')
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function doRestore(r) {
|
||||||
|
const res = await api.restore(r.ma_code)
|
||||||
|
if (res.ok) { message.success('《' + r.title + '》已恢复上架'); onChanged() }
|
||||||
|
else message.error(res.data.message || '恢复失败')
|
||||||
|
}
|
||||||
|
|
||||||
|
async function restoreEpisode(maCode, episode) {
|
||||||
|
const res = await api.restoreEpisode(maCode, episode)
|
||||||
|
if (res.ok) {
|
||||||
|
message.success('第 ' + episode + ' 集已恢复上架')
|
||||||
|
await viewDetail(detail.content)
|
||||||
|
onChanged()
|
||||||
|
} else message.error(res.data.message || '恢复失败')
|
||||||
|
}
|
||||||
|
|
||||||
|
const cols = [
|
||||||
|
{ title: 'MA 码', dataIndex: 'ma_code', render: (v) => <Text code copyable>{v}</Text> },
|
||||||
|
{ title: '作品', dataIndex: 'title' },
|
||||||
|
{ title: '集数', dataIndex: 'episode_count', width: 70 },
|
||||||
|
{ title: '状态', dataIndex: 'status', width: 110, render: (s) => {
|
||||||
|
const m = statusMeta[s] || { label: s, color: 'default' }
|
||||||
|
return <Tag color={m.color}>{m.label}</Tag>
|
||||||
|
} },
|
||||||
|
{ title: '操作', width: 240, render: (_, r) => (
|
||||||
|
<Space>
|
||||||
|
<Button size="small" onClick={() => viewDetail(r)}>详情</Button>
|
||||||
|
{r.status === 'revoked' ? (
|
||||||
|
<Button size="small" type="primary" ghost onClick={() => doRestore(r)}>恢复上架</Button>
|
||||||
|
) : (
|
||||||
|
<Button size="small" danger icon={<StopOutlined />} onClick={() => confirmTakedown(r)}>
|
||||||
|
应急下架
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</Space>
|
||||||
|
) },
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
size="small"
|
||||||
|
title={<Space>监管片库<Badge count={rows.length} showZero color="#1677ff" /></Space>}
|
||||||
|
extra={
|
||||||
|
<Space>
|
||||||
|
<Segmented value={filter} onChange={setFilter} options={[
|
||||||
|
{ label: '全部', value: 'all' },
|
||||||
|
{ label: '流通中', value: 'published' },
|
||||||
|
{ label: '在库', value: 'in_library' },
|
||||||
|
{ label: '待入库', value: 'approved' },
|
||||||
|
{ label: '已下架', value: 'revoked' },
|
||||||
|
]} />
|
||||||
|
<Button icon={<ReloadOutlined />} size="small" onClick={load}>刷新</Button>
|
||||||
|
</Space>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Table rowKey="ma_code" size="small" loading={loading} columns={cols} dataSource={rows}
|
||||||
|
pagination={{ pageSize: 8 }}
|
||||||
|
locale={{ emptyText: <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description="片库暂无内容" /> }} />
|
||||||
|
|
||||||
|
<Modal open={!!detail} onCancel={() => setDetail(null)} footer={null} width={760}
|
||||||
|
title={detail ? `片库详情 · ${detail.content.title}` : ''}>
|
||||||
|
{detail && (
|
||||||
|
<>
|
||||||
|
<Descriptions bordered size="small" column={1} style={{ marginBottom: 12 }}>
|
||||||
|
<Descriptions.Item label="MA 码">{detail.content.ma_code}</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="状态">
|
||||||
|
<Tag color={(statusMeta[detail.content.status] || {}).color}>
|
||||||
|
{(statusMeta[detail.content.status] || {}).label || detail.content.status}
|
||||||
|
</Tag>
|
||||||
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="整剧哈希">{detail.content.file_hash || '-'}</Descriptions.Item>
|
||||||
|
</Descriptions>
|
||||||
|
<Card size="small" title="三方编码映射" style={{ marginBottom: 12 }}>
|
||||||
|
<Table rowKey={(r, i) => i} size="small" pagination={false}
|
||||||
|
dataSource={detail.mappings}
|
||||||
|
columns={[
|
||||||
|
{ title: '角色', dataIndex: 'party' },
|
||||||
|
{ title: '编码', dataIndex: 'party_id' },
|
||||||
|
{ title: '名称', dataIndex: 'party_name', render: (v) => v || '-' },
|
||||||
|
{ title: 'CDN', dataIndex: 'cdn_endpoint', render: (v) => v || '-' },
|
||||||
|
]} />
|
||||||
|
</Card>
|
||||||
|
<Card size="small" title={`集级哈希(${detail.episodes.length} 集)· 可单集下架`}>
|
||||||
|
<Table rowKey="episode" size="small" pagination={false}
|
||||||
|
dataSource={detail.episodes}
|
||||||
|
columns={[
|
||||||
|
{ title: '集', dataIndex: 'episode', width: 50 },
|
||||||
|
{ title: '子标识', render: (_, r) => <Text code>{`${detail.content.ma_code}#E${String(r.episode).padStart(2, '0')}`}</Text> },
|
||||||
|
{ title: '哈希', dataIndex: 'hash_value', ellipsis: true },
|
||||||
|
{ title: '状态', width: 80, render: (_, r) => r.revoked ? <Tag color="red">已下架</Tag> : <Tag color="green">流通中</Tag> },
|
||||||
|
{ title: '操作', width: 110, render: (_, r) => (
|
||||||
|
r.revoked
|
||||||
|
? <Button size="small" type="primary" ghost onClick={() => restoreEpisode(detail.content.ma_code, r.episode)}>恢复本集</Button>
|
||||||
|
: <Button size="small" danger onClick={() => takedownEpisode(detail.content.ma_code, r.episode)}>下架本集</Button>
|
||||||
|
) },
|
||||||
|
]} />
|
||||||
|
</Card>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Modal>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function RoleDesk() {
|
||||||
|
const [tick, bump] = useTick()
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div style={{ marginBottom: 16 }}><Overview tick={tick} /></div>
|
||||||
|
<Tabs
|
||||||
|
type="card"
|
||||||
|
items={[
|
||||||
|
{ key: 'cp', label: '🟢 内容提供商', children: <CPDesk onChanged={bump} /> },
|
||||||
|
{ key: 'reviewer', label: '🔵 审核监管(CSPS/媒资)', children: <ReviewerDesk tick={tick} onChanged={bump} /> },
|
||||||
|
{ key: 'operator', label: '🟠 运营商', children: <OperatorDesk tick={tick} onChanged={bump} /> },
|
||||||
|
{ key: 'library', label: '🔴 监管片库(下架处置)', children: <LibraryDesk tick={tick} onChanged={bump} /> },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||