颠覆传统,清理软件,删除无用文件,节省空间,编写程序,保留长期搁置的旧文档,定期随机翻阅,唤醒过去未成型的创意构思。

发布时间:2026/7/21 12:53:54
颠覆传统,清理软件,删除无用文件,节省空间,编写程序,保留长期搁置的旧文档,定期随机翻阅,唤醒过去未成型的创意构思。 实际应用场景描述在心理健康与创新能力的研究中有一个常见的观点创新往往源于对过去经验的重新组合与联想。我们在日常工作和学习中会产生大量未完成的文档——灵感碎片、半途而废的方案、草图笔记。传统清理软件如CCleaner、SpaceSniffer等的核心逻辑是删除低频文件以释放空间这虽然节省了存储空间却可能无意中清除了未来创新所需的认知种子。本程序旨在颠覆这一逻辑不删除旧文档而是通过定期随机召回Random Recall机制将长期搁置的文件重新呈现在用户面前模拟心理顿悟的过程——当旧想法与新语境碰撞时往往能激发出意想不到的创新构思。同时通过智能归档而非删除来管理存储空间。引入痛点1. 传统清理软件的盲区它们只关注文件大小与访问频率完全忽略文件的语义价值与创新潜力。2. 创意坟墓问题硬盘中堆积了大量被遗忘的半成品文档它们不是垃圾而是未被激活的灵感。3. 认知偏差人们倾向于认为新信息更有价值而忽视了对旧有知识的重新编码Re-encoding所带来的创新收益。4. 空间焦虑用户既想保留旧文件又担心存储空间不足陷入两难。核心逻辑讲解程序的核心是一个三层过滤与召回引擎1. 语义价值评估层通过文件元数据修改时间、类型、内容摘要给文件打上创意价值分而非简单地按时间排序。2. 随机漫步召回层使用加权随机算法让高价值但长期未访问的文件有更高概率被翻牌模拟人类记忆的随机联想机制。3. 智能归档压缩层对超过一定阈值如365天未修改的文件进行透明压缩ZIP释放空间但不删除保留随时解压访问的能力。关键设计哲学- 不删除No-Deletion所有文件至少保留元数据索引- 随机性Serendipity模仿心理学中的偶遇学习Incidental Learning- 渐进式压缩Progressive Archival空间不够时先压缩再提示而非直接删除代码模块化实现项目结构creative_archive/├── README.md├── core/│ ├── scanner.py # 文件系统扫描与元数据提取│ ├── evaluator.py # 创意价值评估引擎│ ├── recall.py # 随机召回机制│ └── archiver.py # 智能压缩归档├── utils/│ ├── config.py # 配置管理│ └── logger.py # 日志记录├── main.py # 主入口└── requirements.txt # 依赖声明requirements.txt# 核心依赖PyMuPDF1.23.0 # PDF文本提取备选文档解析python-docx0.8.11 # .docx文件解析openpyxl3.1.0 # .xlsx文件解析markdown3.5.0 # Markdown解析# 工具库schedule1.2.0 # 定时任务rich13.0.0 # 终端美化输出pyyaml6.0 # 配置文件解析tqdm4.66.0 # 进度条utils/config.py配置管理模块 —— 统一管理程序的可变参数通过读取 config.yaml 实现外部化配置避免硬编码from pathlib import Pathimport yamlDEFAULT_CONFIG {scan_paths: [~/Documents, ~/Desktop], # 扫描目录ignore_patterns: [*.tmp, *.log, .git/*], # 忽略规则recall: {max_files: 10, # 每次召回展示的最大文件数min_idle_days: 90, # 最少搁置天数低于此值不进入召回池weights: {idle_time: 0.4, # 搁置时间权重file_type: 0.3, # 文件类型权重文档 代码 其他content_richness: 0.3 # 内容丰富度权重}},archive: {idle_threshold_days: 365, # 超过此天数自动归档压缩archive_dir: ~/.creative_archive/vault}}def load_config(config_path: str config.yaml) - dict:加载配置文件缺失时返回默认配置path Path(config_path)if path.exists():with open(path, r, encodingutf-8) as f:user_cfg yaml.safe_load(f) or {}# 深层合并简单实现return {**DEFAULT_CONFIG, **user_cfg}return DEFAULT_CONFIGutils/logger.py日志模块 —— 统一输出格式支持彩色终端与文件双写import loggingfrom rich.logging import RichHandlerdef setup_logger(name: str CreativeArchive, level: str INFO) - logging.Logger:logger logging.getLogger(name)logger.setLevel(getattr(logging, level.upper(), logging.INFO))# 终端彩色输出console_handler RichHandler(rich_tracebacksTrue)console_handler.setFormatter(logging.Formatter(%(message)s))logger.addHandler(console_handler)# 文件日志持久化运行记录file_handler logging.FileHandler(creative_archive.log, encodingutf-8)file_handler.setFormatter(logging.Formatter([%(asctime)s] %(levelname)-7s %(name)s - %(message)s))logger.addHandler(file_handler)return loggercore/scanner.py文件系统扫描器 —— 递归遍历目标目录提取文件元数据关键设计使用生成器generator逐批产出避免一次性加载大量文件导致内存膨胀import osimport hashlibfrom pathlib import Pathfrom datetime import datetimefrom typing import Iterator, Dict, Anyimport fnmatchfrom utils.logger import setup_loggerlogger setup_logger(Scanner)class FileMetadata:文件元数据结构体 —— 封装扫描阶段采集的所有信息def __init__(self, path: str):self.path Path(path)self.name self.path.nameself.suffix self.path.suffix.lower()self.size self.path.stat().st_sizeself.mtime datetime.fromtimestamp(self.path.stat().st_mtime)self.atime datetime.fromtimestamp(self.path.stat().st_atime)self.ctime datetime.fromtimestamp(self.path.stat().st_ctime)self.content_hash self._calc_hash()def _calc_hash(self, chunk_size: int 8192) - str:计算文件SHA-256哈希用于内容去重大文件分块读取h hashlib.sha256()try:with open(self.path, rb) as f:while chunk : f.read(chunk_size):h.update(chunk)return h.hexdigest()except (PermissionError, OSError):return # 无法读取的文件返回空哈希def days_idle(self) - int:计算文件搁置天数 —— 自最后一次修改至今的天数delta datetime.now() - self.mtimereturn delta.daysdef to_dict(self) - Dict[str, Any]:序列化为字典便于后续存储与传输return {path: str(self.path),name: self.name,suffix: self.suffix,size: self.size,mtime: self.mtime.isoformat(),atime: self.atime.isoformat(),days_idle: self.days_idle(),content_hash: self.content_hash}def scan_directory(root: str,ignore_patterns: list[str] None) - Iterator[FileMetadata]:递归扫描目录逐文件产出元数据ignore_patterns: 类似 .gitignore 的匹配规则列表root_path Path(root).expanduser().resolve()if not root_path.exists():logger.warning(f路径不存在跳过: {root})returnignore_patterns ignore_patterns or []for entry in root_path.rglob(*):if not entry.is_file():continue# 忽略规则匹配relative str(entry.relative_to(root_path))if any(fnmatch.fnmatch(relative, pat) for pat in ignore_patterns):continuetry:yield FileMetadata(str(entry))except (PermissionError, OSError) as e:logger.debug(f无法读取文件 {entry}: {e})continuecore/evaluator.py创意价值评估引擎 —— 为每份文档计算创意唤醒分设计思路模仿心理学中的记忆激活扩散模型Spreading Activationfrom typing import Dict, Any, Listfrom datetime import datetimefrom core.scanner import FileMetadatafrom utils.logger import setup_loggerlogger setup_logger(Evaluator)# 文件类型创意价值映射 —— 基于经验设定的基础分# 文档类文字密度高 代码类结构化强 媒体类已固化TYPE_SCORES {# 文档 —— 高创意唤醒潜力.docx: 0.9, .doc: 0.85, .pdf: 0.7,.txt: 0.6, .md: 0.8, .rtf: 0.5,# 表格/演示 —— 中等.xlsx: 0.65, .pptx: 0.6, .csv: 0.5,# 代码 —— 结构化高创意唤醒中等.py: 0.55, .js: 0.5, .java: 0.45, .cpp: 0.4,# 媒体 —— 低但非删除.png: 0.2, .jpg: 0.15, .mp4: 0.1,}# 小文件1KB通常是占位符或碎片降低权重SIZE_PENALTY_THRESHOLD 1024 # 1KBdef evaluate_file(meta: FileMetadata, config: Dict[str, Any]) - Dict[str, Any]:对单个文件进行多维度评分返回评估结果字典评分维度1. 搁置时间分idle_score —— 越久未动召回价值越高2. 文件类型分type_score —— 文本类高于二进制类3. 内容丰富度分richness —— 文件越大合理范围内信息密度越高4. 最终加权得分final_score—— 各维度加权求和weights config.get(recall, {}).get(weights, {})# ---- 维度1搁置时间分0~1 归一化180天为满分拐点 ----days meta.days_idle()idle_score min(days / 180.0, 1.0) # 180天以上均为满分# ---- 维度2文件类型分 ----type_score TYPE_SCORES.get(meta.suffix, 0.3) # 未知类型给基础分0.3# ---- 维度3内容丰富度分 ----size_kb meta.size / 1024if size_kb 1:richness 0.1 # 极小文件可能是碎片elif size_kb 100:richness min(size_kb / 100.0, 1.0) # 100KB 以下线性增长else:richness 1.0 # 大于100KB认为内容充分# ---- 加权汇总 ----final_score (idle_score * weights.get(idle_time, 0.4) type_score * weights.get(file_type, 0.3) richness * weights.get(content_richness, 0.3))return {**meta.to_dict(),idle_score: round(idle_score, 3),type_score: round(type_score, 3),richness: round(richness, 3),final_score: round(final_score, 4)}def batch_evaluate(files: List[FileMetadata],config: Dict[str, Any]) - List[Dict[str, Any]]:批量评估文件返回按分数降序排列的评估结果列表results [evaluate_file(f, config) for f in files]results.sort(keylambda x: x[final_score], reverseTrue)logger.info(f评估完成: {len(results)} 个文件进入召回池)return resultscore/recall.py随机召回引擎 —— 加权随机挑选被遗忘的创意核心算法加权轮盘赌Weighted Roulette Wheel Selection配合探索-利用平衡策略Epsilon-Greedy 的变体import randomfrom typing import List, Dict, Any, Optionalfrom datetime import datetime, timedeltafrom utils.logger import setup_loggerlogger setup_logger(Recall)def build_recall_pool(evaluated_files: List[Dict[str, Any]],min_idle_days: int 90,max_idle_days: Optional[int] None) - List[Dict[str, Any]]:构建召回候选池 —— 过滤不符合条件的文件条件1. 搁置天数 min_idle_days太新的文件不需要唤醒2. 如果指定了 max_idle_days则不超过该值用于分桶测试pool []for f in evaluated_files:if f[days_idle] min_idle_days:continueif max_idle_days and f[days_idle] max_idle_days:continuepool.append(f)logger.info(f召回池构建完成: {len(pool)} 个候选文件最小搁置 {min_idle_days} 天)return pooldef weighted_random_pick(pool: List[Dict[str, Any]],n: int 10,temperature: float 1.0) - List[Dict[str, Any]]:加权随机召回 —— 核心算法temperature: 温度参数- 1.0 完全按分数加权- 1.0 增加随机性更多探索- 1.0 偏向高分文件更多利用实现方式对分数做 softmax 变换后按概率采样不放回if not pool:return []n min(n, len(pool))scores [f[final_score] for f in pool]# Softmax 变换import mathexp_scores [math.exp(s / temperature) for s in scores]total sum(exp_scores)probabilities [es / total for es in exp_scores]# 不放回加权采样selected_indices []indices list(range(len(pool)))probs probabilities.copy()for _ in range(n):if not indices:breakchosen random.choices(indices, weightsprobs, k1)[0]selected_indices.append(chosen)# 移除已选重新归一化idx_in_probs indices.index(chosen)indices.pop(idx_in_probs)probs.pop(idx_in_probs)if probs:norm sum(probs)probs [p / norm for p in probs]return [pool[i] for i in selected_indices]def display_recall(files: List[Dict[str, Any]]) - None:格式化展示召回结果 —— 使用 rich 库输出美观的终端表格from rich.table import Tablefrom rich.console import Consolefrom rich.text import Textconsole Console()# 标题console.print(\n *60, styledim)console.print( 创意唤醒 —— 被遗忘的文件召回, stylebold cyan)console.print(*60, styledim)table Table(show_headerTrue, header_stylebold magenta, boxNone)table.add_column(#, width4, justifycenter)table.add_column(文件名, stylegreen, no_wrapFalse)table.add_column(搁置天数, justifycenter, styleyellow)table.add_column(创意唤醒分, justifycenter, stylecyan)table.add_column(路径, styledim, no_wrapFalse)for i, f in enumerate(files, 1):# 分数可视化score_bar █ * int(f[final_score] * 20)score_text Text(f{f[final_score]:.2f} {score_bar}, stylecyan)idle_text Text(f{f[days_idle]}天, styleyellow)table.add_row(str(i),f[name][:40] (... if len(f[name]) 40 else ),idle_text,score_text,f[path][:60] (... if len(f[path]) 60 else ))console.print(table)console.print(*60, styledim)console.print(f\n 共召回 {len(files)} 个文件试着打开看看\n, stylebold green)core/archiver.py智能归档模块 —— 对长期未访问的大文件进行透明压缩策略不删除只压缩。用户可随时解压恢复import zipfileimport osfrom pathlib import Pathfrom typing import List, Dict, Anyfrom datetime import datetimefrom utils.logger import setup_loggerlogger setup_logger(Archiver)def should_archive(meta_dict: Dict[str, Any], threshold_days: int 365) - bool:判断文件是否需要归档搁置超过阈值天数return meta_dict[days_idle] threshold_daysdef compress_to_vault(files: List[Dict[str, Any]],vault_dir: str ~/.creative_archive/vault) - Dict[str, Any]:将符合条件的文件压缩到保险库vault中返回归档报告成功数、跳过数、释放空间vault_path Path(vault_dir).expanduser()vault_path.mkdir(parentsTrue, exist_okTrue)# 按日期命名归档包避免冲突timestamp datetime.now().strftime(%Y%m%d_%H%M%S)archive_path vault_path / farchive_{timestamp}.ziparchived_count 0skipped_count 0freed_bytes 0archived_files []with zipfile.ZipFile(archive_path, w, zipfile.ZIP_DEFLATED) as zf:for f in files:src Path(f[path])if not src.exists():skipped_count 1continue# 使用相对路径存储避免解压时路径冲突arcname farchive_{timestamp}/{src.name}zf.write(src, arcnamearcname)freed_bytes f[size]archived_files.append({original_path: f[path],archived_as: arcname,size: f[size]})archived_count 1logger.debug(f已归档: {src.name})# 归档成功后删除原文件保留索引记录for af in archived_files:try:Path(af[original_path]).unlink()except OSError as e:logger.warning(f删除原文件失败 {af[original_path]}: {e})report {archive_path: str(archive_path),archived_count: archived_count,skipped_count: skipped_count,freed_mb: round(freed_bytes / (1024 * 1024), 2),files: archived_files}logger.info(f归档完成: {archived_count} 个文件 → {archive_path} f(释放 {report[freed_mb]} MB))return reportdef restore_from_vault(archive_path: str, restore_dir: str .) - int:从保险库恢复文件 —— 解压归档包到指定目录count 0with zipfile.ZipFile(archive_path, r) as zf:zf.extractall(restore_dir)count len(zf.namelist())logger.info(f恢复完成: {count} 个文件 → {restore_dir})return countmain.py主程序入口 —— 编排扫描→评估→召回→归档的完整流水线支持两种模式1. 单次运行--run-once立即执行一次完整流程2. 定时运行默认按 schedule 配置周期性执行import argparseimport sysfrom pathlib import Pathfrom datetime import datetimefrom utils.config import load_configfrom utils.logger import setup_loggerfrom core.scanner import scan_directoryfrom core.evaluator import batch_evaluatefrom core.recall import build_recall_pool, weighted_random_pick, display_recallfrom core.archiver import should_archive, compress_to_vaultlogger setup_logger(Main)def collect_all_files(config: dict) - list:从所有配置路径收集文件元数据all_files []scan_paths config.get(scan_paths, [])ignore_patterns config.get(ignore_patterns, [])for p in scan_paths:logger.info(f开始扫描: {p})count_before len(all_files)for meta in scan_directory(p, ignore_patterns):all_files.append(meta)new_count len(all_files) - count_beforelogger.info(f → 发现 {new_count} 个文件)return all_filesdef run_pipeline(config: dict, max_recall: int None) - None:执行完整流水线# Step 1: 扫描files collect_all_files(config)if not files:logger.warning(未发现任何文件请检查 scan_paths 配置)returnlogger.info(f扫描完成共发现 {len(files)} 个文件)# Step 2: 评估evaluated batch_evaluate(files, config)# Step 3: 构建召回池recall_cfg config.get(recall, {})pool build_recall_pool(evaluated,min_idle_daysrecall_cfg.get(min_idle_days, 90))if not pool:logger.info(召回池为空所有文件都太年轻本次无需召回)else:# Step 4: 随机召回n max_recall or recall_cfg.get(max_files, 10)picked weighted_random_pick(pool, nn, temperature1.2)display_recall(picked)# Step 5: 智能归档空间管理archive_cfg config.get(archive, {})threshold archive_cfg.get(idle_threshold_days, 365)to_archive [f for f in evaluated if should_archive(f, threshold)]if to_archive:logger.info(f发现 {len(to_archive)} 个文件超过 {threshold} 天准备归档...)report compress_to_vault(to_archive,vault_dirarchive_cfg.get(archive_dir, ~/.creative_archive/vault))logger.info(f归档报告: 释放 {report[freed_mb]} MB 空间)else:logger.info(暂无需要归档的文件)def main():parser argparse.ArgumentParser(descriptionCreative Archive —— 不删文件唤醒创意)parser.add_argument(--run-once, actionstore_true,help立即执行一次完整流水线默认启动定时任务)parser.add_argument(--config, defaultconfig.yaml,help配置文件路径默认: config.yaml)parser.add_argument(--max-recall, typeint, defaultNone,help每次召回的最大文件数覆盖配置文件)args parser.parse_args()config load_config(args.config)if args.run_once:logger.info(单次运行模式)run_pipeline(config, args.max_recall)else:# 定时模式每天执行一次import scheduleimport timelogger.info(定时运行模式每天 09:00 执行召回)schedule.every().day.at(09:00).do(run_pipeline, config, args.max_recall)while True:schedule.run_pending()time.sleep(60)if __name__ __main__:main()README.md# Creative Archive — 创意唤醒归档工具 *Innovation is the re-ordering of existing elements.* — attributed to various sources## 是什么Creative Archive 是一个 Python 命令行工具它**不删除任何文件**而是通过智能评估 加权随机召回 透明压缩归档帮助你在清理存储空间的同时**定期翻看被遗忘的旧文档**唤醒沉睡的创意构思。## 核心设计原则| 原则 | 说明 ||------|------|| **No-Deletion不删除** | 所有文件至少保留压缩副本索引永不丢失 || **Serendipity偶遇性** | 加权随机召回模拟人类记忆的随机联想 || **Progressive Archival渐进归档** | 空间不足时压缩而非删除随时可恢复 |## 安装bash克隆或下载本仓库cd creative_archive安装依赖推荐虚拟环境python -m venv .venvsource .venv/bin/activate # Windows: .venv\Scripts\activatepip install -r requirements.txt## 配置编辑 config.yaml首次运行会自动生成默认配置yamlscan_paths:- ~/Documents- ~/Desktopignore_patterns:- *.tmp- *.log- .git/*recall:max_files: 10min_idle_days: 90weights:idle_time: 0.4file_type: 0.3content_richness: 0.3archive:idle_threshold_days: 365archive_dir: ~/.creative_archive/vault## 使用bash立即执行一次完整流程python main.py --run-once启动定时任务每天 09:00 自动召回python main.py指定召回数量python main.py --run-once --max-recall 5## 模块说明| 模块 | 职责 ||------|------|| core/scanner.py | 递归扫描文件系统提取文件元数据 || core/evaluator.py | 多维度创意价值评分引擎 || core/recall.py | 加权随机召回 终端可视化展示 || core/archiver.py | 透明压缩归档与恢复 || utils/config.py | 配置加载与默认值管理 || utils/logger.py | 彩色日志与文件双写 |## 输出示例 创意唤醒 —— 被遗忘的文件召回文件名 搁置天数 创意唤醒分 路径1 老项目的脑洞笔记.docx 412天 0.82 ████████████████ /Users/...2 未完成的API设计.md 301天 0.76 ██████████████ /Users/...... 共召回 10 个文件试着打开看看## 恢复归档文件pythonfrom core.archiver import restore_from_vaultrestore_from_vault(~/.creative_archive/vault/archive_20250615_143022.zip)## 许可MIT License —— 自由使用、修改、分发。核心知识点卡片┌─────────────────────────────────────────────────────────┐│ 知识点卡片 #1加权随机采样 │├─────────────────────────────────────────────────────────┤│ 概念Softmax 加权随机不放回采样 ││ 场景需要按概率分布选人/选文件且不允许重复 ││ 核心公式P(i) exp(s_i / T) / Σ exp(s_j / T) ││ 温度 T 的作用 ││ T 1 → 更均匀探索 T 1 → 更集中利用 ││ 代码位置core/recall.py → weighted_random_pick() │└─────────────────────────────────────────────────────────┘┌──────────────────────────────────────────利用AI解决实际问题如果你觉得这个工具好用欢迎关注长安牧笛