Files
kefu/deploy/knowledge-v4-review/package.py
T
2026-09-21 10:34:06 +08:00

56 lines
5.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from pathlib import Path
import json, hashlib, tarfile
root = Path('C:/kefu')
name = 'knowledge-v4-review-20260916'
release = root/'deploy'/name; release.mkdir(exist_ok=True)
old = 'knowledge-v3-field-fix-20260916'
previous = root/'deploy'/old
p = root/'wechat_rpa/KNOWLEDGE.md'
s = p.read_text(encoding='utf-8')
section = '''
## 全量审核(2026-09-16)
知识与审核页支持指定账号或全部授权账号的一键审核,覆盖全部页面,不受当前搜索、状态筛选与勾选影响。对象是已经整理出的待审核知识草稿;原始聊天需先整理为草稿。审核通过只进入待发布,不发布、不启用客服检索、不调用模型。
流程:选择范围 → 预览待审/可通过/需处理数量与按账号统计 → 一次确认范围已完成必要审核 → 后台分批执行。预览以草稿 ID、租户、版本及更新时间固定快照,有效期 30 分钟;同一用户新预览使旧预览失效。之后新增、修改、删除、已驳回或已发布条目均不会被旧快照误审核。
SQL 检查必填及长度、适用条件、有效期、来源存在及最新版本。每批最多 100 条,状态、审核历史、审计、结果及进度在同一短事务内提交。后台在独立线程运行,不受模型网络调用阻塞;关闭页面、进程重启后按已提交进度继续,支持暂停、继续、停止。失败事务不会半批提交。
每批重查操作者的审核、知识读取、原文权限和账号授权。权限撤回或用户停用会暂停为需处理状态;某个账号授权撤回则跳过该账号。任务只对创建者可见,结果清单再次按当前账号权限分页过滤。未通过知识保持原状态并列出原因,可直接打开对应账号的知识详情。
表:knowledge_review_job、knowledge_review_target;应用启动自动创建。回滚旧应用保留这些表及任务进度,旧版不执行新审核队列,已完成审核保留为待发布。
接口(均要求 knowledge:read、knowledge:review、im:content:read):POST /api/v2/knowledge/review-tasks/preview?account_id=-1;GET /review-tasks;GET /review-tasks/{id};GET /review-tasks/{id}/results;POST /review-tasks/{id}/{start|pause|resume|cancel}。start 需 confirmed=true,重复提交不会重复入队,results 默认每页 30、最大 100。
验证:92 项后端回归,前端类型检查、生产构建、隔离浏览器跨页及跨账号流程。50 万条虚构知识预览 6.547 秒,连续 10 批共通过 1000 条、平均每 100 条 0.066 秒,Python tracemalloc 峰值 0.127 MB(不含 SQLite 原生内存和系统缓存),预览响应 636 字节;性能是本地模拟数据结果。线上部署验证不提交审核任务,不修改真实知识审核状态。
'''
if '## 全量审核(2026-09-16)' not in s:
p.write_text(s+section, encoding='utf-8', newline='\n')
files = [root/'wechat_rpa'/f for f in ['knowledge_review.py','knowledge_store.py','knowledge_api.py','knowledge_worker.py','test_knowledge_review.py','KNOWLEDGE.md']]
files += [root/'admin-web/apps/web-antd/src'/f for f in ['api/knowledge.ts','views/knowledge/center.vue','views/knowledge/review-all.vue']]
files += [f for f in (root/'admin-web/apps/web-antd/dist').rglob('*') if f.is_file()]
manifest = []
with tarfile.open(release/'payload.tar.gz','w:gz') as tf:
for path in files:
relative = path.relative_to(root).as_posix(); data=path.read_bytes()
tf.add(path, arcname=relative)
manifest.append({'path':relative,'bytes':len(data),'sha256':hashlib.sha256(data).hexdigest()})
(release/'manifest.json').write_text(json.dumps(manifest,ensure_ascii=False,indent=2),encoding='utf-8')
for filename in ['01-stage.sh','02-backup-build.sh','03-deploy.sh','04-verify.sh','Dockerfile.overlay','rollback.sh']:
text = (previous/filename).read_text(encoding='utf-8').replace(old,name)
if filename == '01-stage.sh':
text = text.replace('sha256:15bf0aa7a0041b5b79cee60c3fc21e888ca87d3268abf183e5644ac5efd784de', 'sha256:b8221de05e2ab92afc66ab8b725ed24600da3e717a543998ae17a6611a011acf')
text = text.replace('/home/ps/knowledge-v3-20260916/manifest.json', f'/home/ps/{old}/manifest.json')
text = text.replace('verified third release', 'verified model-field fix release')
if filename == '02-backup-build.sh':
text = text.replace('test_knowledge_model_output test_model_gateway', 'test_knowledge_model_output test_knowledge_review test_model_gateway')
if filename == '03-deploy.sh':
text = text.replace('Third-version', 'Full-review version')
if filename == '04-verify.sh':
text = text.replace("'knowledge_job','knowledge_watch']", "'knowledge_job','knowledge_watch','knowledge_review_job','knowledge_review_target']")
text = text.replace("('/api/v2/knowledge/overview',401,'GET'),", "('/api/v2/knowledge/overview',401,'GET'),('/api/v2/knowledge/review-tasks',401,'GET'),('/api/v2/knowledge/review-tasks/preview',401,'POST'),")
text = text.replace("assert after['enabled_tenants']==", "assert after['counts']['knowledge_review_job']==0 and after['counts']['knowledge_review_target']==0, 'Deployment must not submit reviews'\nassert after['enabled_tenants']==")
(release/filename).write_text(text,encoding='utf-8',newline='\n')
print(json.dumps({'files':len(manifest),'payload_bytes':(release/'payload.tar.gz').stat().st_size,'release':str(release)}))