Files
kefu/deploy/contact-recovery-20260918/prepare_contact_recovery_package.py
T
2026-09-21 10:34:06 +08:00

64 lines
4.6 KiB
Python

"""Prepare v1.4.28 package QA only; never build or alter product files."""
from pathlib import Path
import ast
import hashlib
import json
import shutil
folder = Path(__file__).resolve().parent
baseline = folder.parent / 'review-voice-20260918'
root = Path('C:/wechat_rpa')
old_sha = '1ef5f2155992423cdb0ac3d3c0f29bcbd5f401baae13d359a98292d02c036fff'
old = root / 'releases/甄AI客服-安装包-v1.4.27.exe'
assert hashlib.sha256(old.read_bytes()).hexdigest() == old_sha
mapping = {
'build_review_voice_v1_4_27.ps1': 'build_contact_recovery_v1_4_28.ps1',
'build_windows_cached_review_voice.ps1': 'build_windows_cached_contact_recovery.ps1',
'validate_review_voice_v1_4_27.ps1': 'validate_contact_recovery_v1_4_28.ps1',
'verify_review_voice_frozen.py': 'verify_contact_recovery_frozen.py',
'run_review_voice_frozen_regressions.py': 'run_contact_recovery_frozen_regressions.py',
'run_isolated_review_voice.py': 'run_isolated_contact_recovery.py',
'verify_review_voice_nsis.py': 'verify_contact_recovery_nsis.py',
'verify_frozen_review_voice_notifications.py': 'verify_frozen_contact_recovery_notifications.py',
'verify_frozen_offline_asr.py': 'verify_frozen_offline_asr.py',
}
for source_name, destination_name in mapping.items():
content = (baseline / source_name).read_text(encoding='utf-8-sig')
for before, after in mapping.items():
content = content.replace(before, after)
content = content.replace('1.4.27', '1.4.28').replace('1.4.26', '1.4.27')
content = content.replace('a558c24f7db00ec907be46f8ce67f2d9d7bb1f60992306bfa64020e294818a38', old_sha)
content = content.replace('review-voice', 'contact-recovery').replace('review and voice release', 'contact recovery release')
if source_name == 'build_review_voice_v1_4_27.ps1':
marker = "$taskPython = Join-Path $taskRoot '.build-venv\\Scripts\\python.exe'"
content = content.replace(marker, "if (([IO.DriveInfo]::new('C:\\')).AvailableFreeSpace -lt 3500000000) { throw 'At least 3.5 GB free disk space required; do not delete user data to build' }\n" + marker)
content = content.replace("rapidocr_onnxruntime; from Crypto.Cipher import AES", "rapidocr_onnxruntime,faster_whisper,ctranslate2,av,pysilk; from Crypto.Cipher import AES")
if source_name in {'build_review_voice_v1_4_27.ps1', 'verify_review_voice_frozen.py', 'run_review_voice_frozen_regressions.py'}:
content = content.replace("'wechat_gui_qt','app_version'", "'wechat_gui_qt','app_version','contact_reply_guard','contact_relation'")
if source_name == 'validate_review_voice_v1_4_27.ps1':
marker = "& $taskPython -B (Join-Path $PSScriptRoot 'verify_contact_recovery_nsis.py')"
content = content.replace(marker, "& $taskPython -I -S (Join-Path $PSScriptRoot 'verify_frozen_offline_asr.py')\nif ($LASTEXITCODE -ne 0) { throw 'Actual frozen offline ASR verification failed' }\n" + marker)
destination = folder / destination_name
if destination.exists():
raise FileExistsError(destination)
destination.write_text(content, encoding='utf-8-sig' if destination.suffix == '.ps1' else 'utf-8')
if destination.suffix == '.py':
ast.parse(content, filename=str(destination))
plan = json.loads((baseline / 'review-voice-release-plan.json').read_text(encoding='utf-8-sig'))
plan.update(finalized=False, version='1.4.28', previousVersion='1.4.27', previousInstallerSha256=old_sha)
plan['frozenModules'].append('contact_relation')
plan['windowsTestModules'] = ['test_protocol_contact_recovery', 'test_contact_relation_snapshot', *plan['windowsTestModules']]
plan['notes'] = 'Prepare only. Root must finish, test and freeze contact re-add reception fixes before finalized=true. Reuse installed ASR dependencies/assets; no downloads. No live messages, settings, queues, installation or uploads.'
(folder / 'contact-recovery-release-plan.json').write_text(json.dumps(plan, ensure_ascii=False, indent=2), encoding='utf-8')
for extension in ('wav', 'silk', 'amr'):
shutil.copy2(baseline / f'synthetic-chinese.{extension}', folder / f'synthetic-chinese.{extension}')
report = dict(prepared=True, built=False, productFilesChanged=False, version='1.4.28', previousInstaller=str(old),
previousInstallerBytes=old.stat().st_size, previousInstallerSha256=old_sha,
freeDiskBytes=shutil.disk_usage(root).free, requiredFreeDiskBytes=3500000000,
dependenciesInstalled=False, modelsDownloaded=False, installed=False,
realMessagesSent=0, files=list(mapping.values()))
(folder / 'package-preparation.json').write_text(json.dumps(report, ensure_ascii=False, indent=2), encoding='utf-8')
print(json.dumps(report, ensure_ascii=False))