refactor: Remove libs directory
This commit is contained in:
parent
6e8b446416
commit
222cefbd58
|
|
@ -70,6 +70,7 @@
|
|||
<a href="./i18n/zh/documents/实战案例/"><img src="https://img.shields.io/badge/🎬_实战案例-项目实操-orange?style=for-the-badge" alt="实战案例"></a>
|
||||
<a href="./i18n/zh/documents/常见坑汇总/"><img src="https://img.shields.io/badge/🕳️_常见坑-避坑指南-yellow?style=for-the-badge" alt="常见坑汇总"></a>
|
||||
<a href="./i18n/zh/documents/外部资源聚合/"><img src="https://img.shields.io/badge/📡_信息源-聚合-teal?style=for-the-badge" alt="信息源聚合"></a>
|
||||
<a href="./libs/external/chat-vault/"><img src="https://img.shields.io/badge/🔐_Chat_Vault-聊天存档-gold?style=for-the-badge" alt="Chat Vault"></a>
|
||||
</p>
|
||||
|
||||
[📋 工具资源](#-器-工具与资源)
|
||||
|
|
|
|||
|
|
@ -1,71 +0,0 @@
|
|||
# 📦 通用库与外部集成 (libs)
|
||||
|
||||
`libs/` 用来放两类东西:
|
||||
|
||||
1. **内部可复用的胶水代码**:小而稳、低耦合、可替换(`common/`)
|
||||
2. **第三方工具与外部集成**:尽量保持原样、只做最薄适配(`external/`)
|
||||
|
||||
`database/` 预留未来的数据持久化层(当前仅占位)。
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
libs/
|
||||
├── README.md
|
||||
├── common/
|
||||
│ ├── README.md
|
||||
│ ├── __init__.py
|
||||
│ ├── models/
|
||||
│ │ └── __init__.py
|
||||
│ └── utils/
|
||||
│ └── backups/
|
||||
│ ├── README.md
|
||||
│ ├── 快速备份.py
|
||||
│ └── 一键备份.sh
|
||||
├── database/
|
||||
│ ├── README.md
|
||||
│ └── .gitkeep
|
||||
└── external/
|
||||
├── README.md
|
||||
├── chat-vault/
|
||||
├── prompts-library/
|
||||
├── l10n-tool/
|
||||
├── my-nvim/
|
||||
├── MCPlayerTransfer/
|
||||
├── XHS-image-to-PDF-conversion/
|
||||
└── .gitkeep
|
||||
```
|
||||
|
||||
## 子目录职责与边界
|
||||
|
||||
### `common/`:内部通用模块
|
||||
|
||||
- 入口:[`common/README.md`](./common/README.md)
|
||||
- 只放 **可复用** 的基础能力:模型、工具函数、脚本等
|
||||
- 不要把业务逻辑、项目临时代码塞进来
|
||||
- 约定:新增/调整能力时,同步更新 `libs/common/README.md`
|
||||
|
||||
### `database/`:数据库适配层(预留)
|
||||
|
||||
- 入口:[`database/README.md`](./database/README.md)
|
||||
- 目标是把“存储细节”关进盒子里:连接、迁移、查询适配、事务边界
|
||||
- 约定:实现前先写清楚目录结构与边界(见 `libs/database/README.md`)
|
||||
|
||||
### `external/`:第三方工具与外部集成
|
||||
|
||||
- 入口:[`external/README.md`](./external/README.md)
|
||||
- 尽量保持第三方代码原样,避免“魔改后不可升级”
|
||||
- 每个工具目录至少包含:`README.md`(用途/入口/依赖)与许可证/来源说明
|
||||
- 约定:新增外部工具时,同步更新 `libs/external/README.md`
|
||||
|
||||
## 常用入口
|
||||
|
||||
- AI 聊天记录保存:[`external/chat-vault/`](./external/chat-vault/)(支持 Codex/Kiro/Gemini/Claude CLI)
|
||||
- 提示词批量管理:[`external/prompts-library/`](./external/prompts-library/)(配合 `../prompts/` 使用)
|
||||
- 备份工具:优先使用仓库根目录的 `backups/`(当前与 `libs/common/utils/backups/` 内容一致)
|
||||
|
||||
## 贡献约定(最小要求)
|
||||
|
||||
1. 新增模块先定义职责边界,再写代码/文档
|
||||
2. 新增依赖记录安装方式与最低版本(必要时补充到 `documents/工具集.md`)
|
||||
3. 目录结构/职责变化时,更新对应 README,保证“文档即真相源”
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
# 🔧 libs/common:通用模块
|
||||
|
||||
`libs/common/` 放的是项目内部可复用的“胶水代码”:**小而稳、低耦合、可替换**。这里的目标不是堆功能,而是为仓库提供少量可靠的基础能力。
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
libs/common/
|
||||
├── README.md
|
||||
├── __init__.py
|
||||
├── models/ # 预留:数据模型(当前仅占位)
|
||||
│ └── __init__.py
|
||||
└── utils/
|
||||
└── backups/ # 基于 .gitignore 的快速备份工具
|
||||
├── README.md
|
||||
├── 快速备份.py
|
||||
└── 一键备份.sh
|
||||
```
|
||||
|
||||
## 现有内容
|
||||
|
||||
- `utils/backups/`:快速备份工具(当前与仓库根目录 [`backups/`](../../backups/) 内容一致,用于避免脚本散落各处)
|
||||
|
||||
## 约束与约定
|
||||
|
||||
1. **不放业务逻辑**:`common/` 只提供基础能力与工具
|
||||
2. **接口要稳**:一旦被引用,就把它当作公开 API 对待
|
||||
3. **可审计输出**:脚本/工具的输出要可复盘(明确输入、输出路径、失败原因)
|
||||
4. **新增即文档**:新增模块/目录必须同步更新本 README 与 `libs/README.md`
|
||||
|
||||
## 使用方式(当前推荐)
|
||||
|
||||
本目录的内容目前主要以“脚本/工具”形式存在,推荐直接运行:
|
||||
|
||||
```bash
|
||||
# 备份当前仓库(建议优先使用根目录 backups/ 入口)
|
||||
python3 backups/快速备份.py
|
||||
```
|
||||
|
||||
更多参数与说明见:[`../../backups/README.md`](../../backups/README.md)。
|
||||
|
|
@ -1 +0,0 @@
|
|||
# Common Library
|
||||
|
|
@ -1 +0,0 @@
|
|||
# Models Module
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
# 快速备份工具
|
||||
|
||||
基于 `.gitignore` 规则的项目备份工具,自动排除不需要的文件。
|
||||
|
||||
## 功能特性
|
||||
|
||||
- 自动读取 `.gitignore` 规则
|
||||
- 支持取反规则(`!` 语法)
|
||||
- 目录级剪枝优化
|
||||
- 生成 `.tar.gz` 压缩包
|
||||
- 零依赖(仅使用 Python 内置模块)
|
||||
|
||||
## 文件结构
|
||||
|
||||
```
|
||||
backups/
|
||||
├── 快速备份.py # 核心备份引擎
|
||||
├── 一键备份.sh # Shell 启动脚本
|
||||
└── README.md # 本文档
|
||||
```
|
||||
|
||||
## 使用方法
|
||||
|
||||
```bash
|
||||
# 方式一:Shell 脚本(推荐)
|
||||
bash backups/一键备份.sh
|
||||
|
||||
# 方式二:直接运行 Python
|
||||
python3 backups/快速备份.py
|
||||
|
||||
# 指定输出文件
|
||||
python3 backups/快速备份.py -o my_backup.tar.gz
|
||||
|
||||
# 指定项目目录
|
||||
python3 backups/快速备份.py -p /path/to/project
|
||||
```
|
||||
|
||||
## 输出位置
|
||||
|
||||
默认输出到 `backups/gz/备份_YYYYMMDD_HHMMSS.tar.gz`
|
||||
|
||||
## 参数说明
|
||||
|
||||
| 参数 | 说明 | 默认值 |
|
||||
|------|------|--------|
|
||||
| `-p, --project` | 项目根目录 | 当前目录 |
|
||||
| `-o, --output` | 输出文件路径 | `backups/gz/备份_时间戳.tar.gz` |
|
||||
| `-g, --gitignore` | gitignore 文件路径 | `.gitignore` |
|
||||
|
||||
## 依赖
|
||||
|
||||
- Python 3.x(无需额外包)
|
||||
- Bash(用于 Shell 脚本)
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# 一键备份项目脚本
|
||||
# 自动读取 .gitignore 规则并排除匹配的文件
|
||||
# bash backups/一键备份.sh
|
||||
|
||||
set -e
|
||||
|
||||
# 颜色输出
|
||||
GREEN='\033[0;32m'
|
||||
BLUE='\033[0;34m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# 脚本所在目录
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
# 项目根目录(脚本所在目录的父目录)
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
|
||||
# 项目backups目录
|
||||
BACKUPS_DIR="${PROJECT_ROOT}/backups"
|
||||
|
||||
# 备份脚本路径(始终在项目的backups目录中)
|
||||
BACKUP_SCRIPT="${BACKUPS_DIR}/快速备份.py"
|
||||
|
||||
# 检查备份脚本是否存在
|
||||
if [ ! -f "${BACKUP_SCRIPT}" ]; then
|
||||
echo -e "${YELLOW}⚠️ 错误: 备份脚本不存在${NC}"
|
||||
echo ""
|
||||
echo "备份工具应位于项目的 backups/ 目录中:"
|
||||
echo " ${BACKUPS_DIR}/"
|
||||
echo ""
|
||||
echo "请确保:"
|
||||
echo " 1. 复制快速备份.py到 ${BACKUPS_DIR}/"
|
||||
echo " 2. 复制一键备份.sh到 ${BACKUPS_DIR}/"
|
||||
echo ""
|
||||
echo "或者使用方式:"
|
||||
echo " • 在项目根目录执行: bash backups/一键备份.sh"
|
||||
echo " • 或直接执行: python3 backups/快速备份.py"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
echo -e "${BLUE} 项目快速备份工具${NC}"
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
echo ""
|
||||
echo -e "${GREEN}✓${NC} 找到备份脚本: backups/快速备份.py"
|
||||
|
||||
# 检查 Python3 是否可用
|
||||
if ! command -v python3 &> /dev/null; then
|
||||
echo -e "${YELLOW}⚠️ 错误: 未找到 python3 命令${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}✓${NC} 项目目录: ${PROJECT_ROOT}"
|
||||
echo -e "${GREEN}✓${NC} 备份脚本: ${BACKUP_SCRIPT}"
|
||||
echo -e "${GREEN}✓${NC} Python 版本: $(python3 --version)"
|
||||
echo ""
|
||||
|
||||
# 执行备份
|
||||
echo -e "${YELLOW}▶ 正在执行备份...${NC}"
|
||||
echo ""
|
||||
|
||||
# 切换到项目根目录
|
||||
cd "${PROJECT_ROOT}"
|
||||
|
||||
# 运行备份脚本
|
||||
python3 "${BACKUP_SCRIPT}"
|
||||
|
||||
# 检查执行结果
|
||||
if [ $? -eq 0 ]; then
|
||||
echo ""
|
||||
echo -e "${GREEN}========================================${NC}"
|
||||
echo -e "${GREEN} ✓ 备份完成!${NC}"
|
||||
echo -e "${GREEN}========================================${NC}"
|
||||
else
|
||||
echo ""
|
||||
echo -e "${YELLOW}========================================${NC}"
|
||||
echo -e "${YELLOW} ✗ 备份失败${NC}"
|
||||
echo -e "${YELLOW}========================================${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
|
@ -1,265 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
快速备份项目工具
|
||||
读取 .gitignore 规则并打包项目文件(排除匹配的文件)
|
||||
|
||||
bash backups/一键备份.sh
|
||||
|
||||
文件位置:
|
||||
backups/快速备份.py
|
||||
|
||||
工具清单(backups/目录):
|
||||
• 快速备份.py - 核心备份引擎(7.3 KB)
|
||||
• 一键备份.sh - 一键执行脚本(2.4 KB)
|
||||
|
||||
使用方法:
|
||||
$ bash backups/一键备份.sh
|
||||
或
|
||||
$ python3 backups/快速备份.py
|
||||
|
||||
备份输出:
|
||||
backups/gz/备份_YYYYMMDD_HHMMSS.tar.gz
|
||||
|
||||
适用项目:
|
||||
任何包含 .gitignore 文件的项目(自动读取规则并排除匹配文件)
|
||||
|
||||
依赖:
|
||||
无需额外安装包,仅使用Python内置模块
|
||||
"""
|
||||
|
||||
import os
|
||||
import tarfile
|
||||
import fnmatch
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
|
||||
class GitignoreFilter:
|
||||
"""解析 .gitignore 文件并过滤文件"""
|
||||
|
||||
def __init__(self, gitignore_path: Path, project_root: Path):
|
||||
self.project_root = project_root
|
||||
# 规则按照出现顺序存储,支持取反(!)语义,后匹配覆盖前匹配
|
||||
# 每项: {"pattern": str, "dir_only": bool, "negate": bool, "has_slash": bool}
|
||||
self.rules = []
|
||||
self.load_gitignore(gitignore_path)
|
||||
|
||||
def load_gitignore(self, gitignore_path: Path):
|
||||
"""加载并解析 .gitignore 文件"""
|
||||
if not gitignore_path.exists():
|
||||
print(f"⚠️ 警告: {gitignore_path} 不存在,将不应用任何过滤规则")
|
||||
return
|
||||
|
||||
try:
|
||||
with open(gitignore_path, 'r', encoding='utf-8') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
|
||||
# 跳过空行和注释
|
||||
if not line or line.startswith('#'):
|
||||
continue
|
||||
|
||||
negate = line.startswith('!')
|
||||
if negate:
|
||||
line = line[1:].lstrip()
|
||||
if not line:
|
||||
continue
|
||||
|
||||
dir_only = line.endswith('/')
|
||||
has_slash = '/' in line.rstrip('/')
|
||||
|
||||
self.rules.append({
|
||||
"pattern": line,
|
||||
"dir_only": dir_only,
|
||||
"negate": negate,
|
||||
"has_slash": has_slash,
|
||||
})
|
||||
|
||||
print(f"✓ 已加载 {len(self.rules)} 条规则(含取反)")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ 读取 .gitignore 失败: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
def _match_rule(self, rule: dict, relative_path_str: str, is_dir: bool) -> bool:
|
||||
"""按规则匹配路径,返回是否命中"""
|
||||
pattern = rule["pattern"]
|
||||
dir_only = rule["dir_only"]
|
||||
has_slash = rule["has_slash"]
|
||||
|
||||
# 目录规则:匹配目录自身或其子路径
|
||||
if dir_only:
|
||||
normalized = pattern.rstrip('/')
|
||||
if relative_path_str == normalized or relative_path_str.startswith(normalized + '/'):
|
||||
return True
|
||||
return False
|
||||
|
||||
# 带路径分隔的规则:按相对路径匹配
|
||||
if has_slash:
|
||||
return fnmatch.fnmatch(relative_path_str, pattern)
|
||||
|
||||
# 无斜杠:匹配任意层级的基本名
|
||||
if fnmatch.fnmatch(Path(relative_path_str).name, pattern):
|
||||
return True
|
||||
# 额外处理目录命中:无通配符时,若任一父级目录名等于 pattern 也视为命中
|
||||
if pattern.isalpha() and pattern in relative_path_str.split('/'):
|
||||
return True
|
||||
return False
|
||||
|
||||
def should_exclude(self, path: Path, is_dir: bool = False) -> bool:
|
||||
"""
|
||||
判断路径是否应该被排除(支持 ! 取反,后匹配覆盖前匹配)
|
||||
返回 True 表示应该排除(不备份)
|
||||
"""
|
||||
try:
|
||||
# 统一使用 POSIX 路径风格进行匹配
|
||||
relative_path_str = path.relative_to(self.project_root).as_posix()
|
||||
except ValueError:
|
||||
return False # 不在项目根目录内,不处理
|
||||
|
||||
# Git 风格:从上到下最后一次匹配决定去留
|
||||
matched = None
|
||||
for rule in self.rules:
|
||||
if self._match_rule(rule, relative_path_str, is_dir):
|
||||
matched = not rule["negate"] # negate 表示显式允许
|
||||
|
||||
return bool(matched)
|
||||
|
||||
|
||||
def create_backup(project_root: Path, output_file: Path, filter_obj: GitignoreFilter):
|
||||
"""创建备份压缩包"""
|
||||
|
||||
# 统计信息
|
||||
total_files = 0
|
||||
excluded_files = 0
|
||||
included_files = 0
|
||||
|
||||
print(f"\n{'='*60}")
|
||||
print(f"开始备份项目: {project_root}")
|
||||
print(f"输出文件: {output_file}")
|
||||
print(f"{'='*60}\n")
|
||||
|
||||
try:
|
||||
with tarfile.open(output_file, 'w:gz') as tar:
|
||||
# 使用 os.walk 可在目录层级提前剪枝,避免进入已忽略目录
|
||||
for root, dirs, files in os.walk(project_root, topdown=True):
|
||||
root_path = Path(root)
|
||||
|
||||
# 目录剪枝:命中忽略规则或 .git 时不再深入
|
||||
pruned_dirs = []
|
||||
for d in dirs:
|
||||
dir_path = root_path / d
|
||||
if d == '.git' or filter_obj.should_exclude(dir_path, is_dir=True):
|
||||
print(f" 排除目录: {dir_path.relative_to(project_root)}")
|
||||
excluded_files += 1
|
||||
continue
|
||||
pruned_dirs.append(d)
|
||||
dirs[:] = pruned_dirs
|
||||
|
||||
for name in files:
|
||||
path = root_path / name
|
||||
total_files += 1
|
||||
|
||||
# 文件忽略判定
|
||||
if '.git' in path.parts or filter_obj.should_exclude(path):
|
||||
excluded_files += 1
|
||||
print(f" 排除: {path.relative_to(project_root)}")
|
||||
continue
|
||||
|
||||
arcname = path.relative_to(project_root)
|
||||
tar.add(path, arcname=arcname)
|
||||
included_files += 1
|
||||
print(f" 备份: {arcname}")
|
||||
|
||||
print(f"\n{'='*60}")
|
||||
print("备份完成!")
|
||||
print(f"{'='*60}")
|
||||
print(f"总文件数: {total_files}")
|
||||
print(f"已备份: {included_files} 个文件")
|
||||
print(f"已排除: {excluded_files} 个文件/目录")
|
||||
print(f"压缩包大小: {output_file.stat().st_size / 1024 / 1024:.2f} MB")
|
||||
print(f"{'='*60}")
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"\n❌ 备份失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description='快速备份项目(根据 .gitignore 排除文件)',
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog="""
|
||||
使用示例:
|
||||
# 基本用法(备份到 backups/gz/ 目录)
|
||||
python backups/快速备份.py
|
||||
|
||||
# 指定输出文件
|
||||
python backups/快速备份.py -o my_backup.tar.gz
|
||||
|
||||
# 指定项目根目录
|
||||
python backups/快速备份.py -p /path/to/project
|
||||
"""
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'-p', '--project',
|
||||
type=str,
|
||||
default='.',
|
||||
help='项目根目录路径(默认: 当前目录)'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'-o', '--output',
|
||||
type=str,
|
||||
help='输出文件路径(默认: backups/备份_YYYYMMDD_HHMMSS.tar.gz)'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'-g', '--gitignore',
|
||||
type=str,
|
||||
default='.gitignore',
|
||||
help='.gitignore 文件路径(默认: .gitignore)'
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# 解析路径
|
||||
project_root = Path(args.project).resolve()
|
||||
gitignore_path = Path(args.gitignore).resolve()
|
||||
|
||||
if not project_root.exists():
|
||||
print(f"❌ 错误: 项目目录不存在: {project_root}")
|
||||
sys.exit(1)
|
||||
|
||||
# 确定输出文件路径
|
||||
if args.output:
|
||||
output_file = Path(args.output).resolve()
|
||||
else:
|
||||
# 默认输出到 backups/gz/ 目录
|
||||
backup_dir = project_root / 'backups' / 'gz'
|
||||
backup_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
||||
output_file = backup_dir / f'备份_{timestamp}.tar.gz'
|
||||
|
||||
# 确保输出目录存在
|
||||
output_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# 创建过滤器
|
||||
filter_obj = GitignoreFilter(gitignore_path, project_root)
|
||||
|
||||
# 执行备份
|
||||
success = create_backup(project_root, output_file, filter_obj)
|
||||
|
||||
sys.exit(0 if success else 1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
@ -1 +0,0 @@
|
|||
# Third-party libraries (read-only)
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
# 🗄️ libs/database:数据库适配层(预留)
|
||||
|
||||
`libs/database/` 预留给未来的“存储适配层”。目标是把数据库的细节(连接、迁移、事务、查询)封装在一个清晰边界内,避免业务代码到处散落 SQL/ORM。
|
||||
|
||||
## 设计边界(先写清楚再实现)
|
||||
|
||||
- 这里负责:连接管理、迁移脚本、ORM/SQL 模型、统一的查询/事务封装
|
||||
- 这里不负责:业务规则、HTTP/API 逻辑、领域对象的复杂编排
|
||||
|
||||
## 推荐目录结构(落地时按需取舍)
|
||||
|
||||
```
|
||||
libs/database/
|
||||
├── README.md
|
||||
├── __init__.py
|
||||
├── connection.py # 连接与池化
|
||||
├── migrations/ # 迁移脚本(Alembic/Flyway/自研均可)
|
||||
├── repositories/ # 数据访问层(可选)
|
||||
└── models/ # ORM 模型或 SQL schema(可选)
|
||||
```
|
||||
|
||||
## 何时开始实现
|
||||
|
||||
当仓库出现“需要长期保存/查询的数据”且 **文件系统不够用** 时,再把这一层落地;否则保持为空,避免过早引入复杂度。
|
||||
|
|
@ -1 +0,0 @@
|
|||
# Third-party libraries (read-only)
|
||||
|
|
@ -1 +0,0 @@
|
|||
Subproject commit fe6f4735bd80bf8b5ccdf8986c78c946383950c1
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
# 🔌 libs/external:外部集成与第三方工具
|
||||
|
||||
`libs/external/` 用来收纳第三方工具、外部依赖与集成模块。核心原则是:
|
||||
|
||||
- **尽量原样保留**:避免“魔改后不可升级”
|
||||
- **隔离依赖与风险**:外部工具的依赖不要污染主仓库
|
||||
- **可追溯**:来源、许可证、用法要写清楚
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
libs/external/
|
||||
├── README.md
|
||||
├── chat-vault/ # AI 聊天记录保存工具
|
||||
├── prompts-library/ # 提示词库管理工具(Excel ↔ Markdown)
|
||||
├── l10n-tool/ # 多语言翻译脚本
|
||||
├── my-nvim/ # Neovim 配置(含 nvim-config/)
|
||||
├── MCPlayerTransfer/ # MC 玩家迁移工具
|
||||
├── XHS-image-to-PDF-conversion/ # 图片合并 PDF 工具
|
||||
└── .gitkeep
|
||||
```
|
||||
|
||||
## 工具清单(入口与文档)
|
||||
|
||||
- `chat-vault/`:AI 聊天记录保存工具,支持 Codex/Kiro/Gemini/Claude CLI(详见 [`chat-vault/README_CN.md`](./chat-vault/README_CN.md))
|
||||
- `prompts-library/`:提示词 Excel ↔ Markdown 批量互转与索引生成(详见 [`prompts-library/README.md`](./prompts-library/README.md))
|
||||
- `l10n-tool/`:多语言批量翻译脚本
|
||||
- `my-nvim/`:个人 Neovim 配置(详见 [`my-nvim/README.md`](./my-nvim/README.md))
|
||||
- `MCPlayerTransfer/`:MC 玩家迁移工具
|
||||
- `XHS-image-to-PDF-conversion/`:图片合并 PDF(详见 [`XHS-image-to-PDF-conversion/README.md`](./XHS-image-to-PDF-conversion/README.md))
|
||||
|
||||
## 新增外部工具(最小清单)
|
||||
|
||||
1. 创建目录:`libs/external/<tool-name>/`
|
||||
2. 必备文件:`README.md`(用途/入口/依赖/输入输出)、许可证与来源说明(如 `LICENSE` / `SOURCE.md`)
|
||||
3. 依赖约束:尽量使用工具自带的虚拟环境/容器化方式,不影响仓库其他部分
|
||||
4. 文档同步:在本 README 增加一行工具说明,保证可发现性
|
||||
|
|
@ -1,176 +0,0 @@
|
|||
<div align="center">
|
||||
|
||||
# 📚 小红书图文批量转 PDF
|
||||
### Batch Convert XHS Images to PDF
|
||||
|
||||
**一个智能 Python 脚本,用于将从小红书批量下载的 ZIP 压缩包,按顺序自动拼接为清晰的 PDF 文件。**
|
||||
*A smart Python script that automatically converts ZIP archives from Xiaohongshu into well-ordered PDF files.*
|
||||
|
||||
---
|
||||
|
||||
[](https://opensource.org/licenses/MIT)
|
||||
[]()
|
||||
[]()
|
||||
[]()
|
||||
|
||||
[✨ 功能特性](#-功能特性) • [⚙️ 工作流程](#️-工作流程) • [🚀 快速开始](#-快速开始) • [🗂️ 项目结构](#️-项目结构) • [🤝 参与贡献](#-参与贡献)
|
||||
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
## ✨ 功能特性
|
||||
|
||||
| 特性 | 描述 |
|
||||
|:---:|:---|
|
||||
| 📦 **全自动处理** | 无需手动解压,脚本自动处理 `.zip` 压缩包。 |
|
||||
| 🔢 **智能自然排序** | 完美处理 `1, 2, ... 10, 11` 这样的文件名排序,确保图片顺序正确。 |
|
||||
| 🚀 **批量转换** | 支持一次性转换文件夹内的所有 `.zip` 文件,省时省力。 |
|
||||
| 🗑️ **自动清理** | 转换成功后,自动删除原始的 `.zip` 文件和临时文件,保持目录整洁。 |
|
||||
| 📖 **PDF 优化** | 生成的 PDF 文件经过优化,保证清晰度的同时控制文件大小。 |
|
||||
| 💻 **跨平台兼容** | 依赖的 `Pillow` 库和 Python 脚本可在 Windows, macOS, Linux 上运行。 |
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ 工作流程
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td width="50%">
|
||||
|
||||
脚本的核心逻辑非常简单直接:监控并处理文件夹内的 ZIP 文件,通过一系列自动化步骤输出 PDF。
|
||||
|
||||
### 核心步骤
|
||||
1. **扫描**: 查找当前目录下的所有 `.zip` 文件。
|
||||
2. **解压**: 将找到的 `.zip` 文件解压到临时目录。
|
||||
3. **排序**: 智能地对所有图片文件进行“自然排序”。
|
||||
4. **合并**: 将排序后的图片合并成一个 PDF 文件。
|
||||
5. **清理**: 删除原始的 `.zip` 文件和临时文件夹。
|
||||
|
||||
</td>
|
||||
<td width="50%">
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[📁 放置 .zip 文件] --> B{运行 pdf.py 脚本};
|
||||
B --> C[🔄 解压到临时目录];
|
||||
C --> D[🔢 按文件名自然排序];
|
||||
D --> E[🖼️ 合并图片为 PDF];
|
||||
E --> F[📄 生成 output.pdf];
|
||||
F --> G[🗑️ 删除原 .zip 文件];
|
||||
G --> H[✅ 完成];
|
||||
```
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
---
|
||||
|
||||
## 🚀 快速开始
|
||||
|
||||
### 1. 环境准备
|
||||
|
||||
首先,确保你的电脑上安装了 **Python 3**。
|
||||
|
||||
然后,将本项目克隆到你的本地:
|
||||
```bash
|
||||
git clone https://github.com/tukuaiai/XHS-image-to-PDF-conversion.git
|
||||
cd XHS-image-to-PDF-conversion
|
||||
```
|
||||
|
||||
### 2. 安装依赖
|
||||
|
||||
本项目依赖 `Pillow` 库来处理图片。运行以下命令安装它:
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
或者,你也可以使用 `Makefile` (如果你的系统支持 `make`):
|
||||
```bash
|
||||
make install
|
||||
```
|
||||
|
||||
### 3. 下载图文
|
||||
|
||||
使用你喜欢的浏览器扩展(如推荐的 **小地瓜**)从小红书下载图文,并确保它们是 `.zip` 格式。
|
||||
|
||||
- **小地瓜 - 小红书图片视频下载助手**: [Firefox 扩展](https://addons.mozilla.org/zh-CN/firefox/addon/%E5%B0%8F%E5%9C%B0%E7%93%9C-%E5%B0%8F%E7%BA%A2%E4%B9%A6%E5%9B%BE%E7%89%87%E8%A7%86%E9%A2%91%E4%B8%8B%E8%BD%BD%E5%8A%A9%E6%89%8B/)
|
||||
|
||||
### 4. 运行脚本
|
||||
|
||||
<details>
|
||||
<summary><b>模式一:批量处理所有 ZIP 文件 (推荐)</b></summary>
|
||||
|
||||
1. 将所有下载的 `.zip` 文件移动到本项目文件夹中。
|
||||
2. 直接运行 `pdf.bat` (Windows) 或在终端中运行以下命令:
|
||||
```bash
|
||||
python pdf.py
|
||||
```
|
||||
或者使用 `make`:
|
||||
```bash
|
||||
make run
|
||||
```
|
||||
3. 脚本会自动处理文件夹内所有的 `.zip` 文件。
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>模式二:处理单个 ZIP 文件</b></summary>
|
||||
|
||||
如果你只想处理一个文件,可以使用拖放或命令行参数:
|
||||
|
||||
1. **拖放 (Windows)**: 将一个 `.zip` 文件直接拖到 `pdf.bat` 图标上。
|
||||
2. **命令行**:
|
||||
```bash
|
||||
python pdf.py "你的文件路径.zip"
|
||||
```
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## 🗂️ 项目结构
|
||||
|
||||
```
|
||||
XHS-image-to-PDF-conversion/
|
||||
├── .git/
|
||||
├── docs/ # (未来可能添加的文档)
|
||||
├── 📚...pdf # (示例文件)
|
||||
├── pdf.bat # Windows 批处理脚本
|
||||
├── pdf.py # 核心 Python 脚本
|
||||
├── Makefile # 自动化命令
|
||||
├── requirements.txt # Python 依赖
|
||||
├── README.md # 你正在阅读的这个文件
|
||||
├── LICENSE # MIT 许可证
|
||||
├── CODE_OF_CONDUCT.md # 社区行为准则
|
||||
└── CONTRIBUTING.md # 贡献指南
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🤝 参与贡献
|
||||
|
||||
我们欢迎任何形式的贡献!无论是报告 Bug、提出功能建议还是直接贡献代码。
|
||||
|
||||
请参考我们的 [**贡献指南 (CONTRIBUTING.md)**](CONTRIBUTING.md) 来了解如何参与。
|
||||
|
||||
---
|
||||
|
||||
## 📜 许可证
|
||||
|
||||
本项目采用 [MIT](LICENSE) 许可证。
|
||||
|
||||
---
|
||||
|
||||
<div align="center">
|
||||
|
||||
**如果这个项目对你有帮助,请给一个 Star ⭐!**
|
||||
|
||||
[](https://star-history.com/#tukuaiai/XHS-image-to-PDF-conversion&Date)
|
||||
|
||||
---
|
||||
|
||||
**Made with 🐍 & ❤️ by tukuaiai**
|
||||
|
||||
[⬆ 回到顶部](#-小红书图文批量转-pdf)
|
||||
|
||||
</div>
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
python pdf.py
|
||||
pause
|
||||
|
|
@ -1,195 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
图片ZIP转PDF脚本
|
||||
将ZIP文件中的图片按序号排序并拼接成PDF文件
|
||||
"""
|
||||
|
||||
import zipfile
|
||||
import os
|
||||
import re
|
||||
from PIL import Image
|
||||
import shutil
|
||||
|
||||
def 自然排序键(文件名):
|
||||
"""将文件名转换为自然排序键,支持数字排序"""
|
||||
return [int(text) if text.isdigit() else text.lower() for text in re.split(r'(\d+)', 文件名)]
|
||||
|
||||
def zip转pdf(zip路径):
|
||||
"""
|
||||
将ZIP文件中的图片排序后转换为PDF
|
||||
|
||||
Args:
|
||||
zip路径: ZIP文件的完整路径
|
||||
|
||||
Returns:
|
||||
成功返回PDF路径,失败返回None
|
||||
"""
|
||||
try:
|
||||
# 获取ZIP文件名(不含扩展名)
|
||||
zip目录, zip文件名 = os.path.split(zip路径)
|
||||
pdf名称 = os.path.splitext(zip文件名)[0] + '.pdf'
|
||||
pdf路径 = os.path.join(zip目录, pdf名称)
|
||||
|
||||
print(f"正在处理: {zip文件名}")
|
||||
|
||||
# 创建临时目录解压文件
|
||||
临时目录 = os.path.join(zip目录, 'temp_extract')
|
||||
if os.path.exists(临时目录):
|
||||
shutil.rmtree(临时目录)
|
||||
os.makedirs(临时目录)
|
||||
|
||||
# 解压ZIP文件
|
||||
with zipfile.ZipFile(zip路径, 'r') as zip文件:
|
||||
zip文件.extractall(临时目录)
|
||||
|
||||
# 获取所有图片文件
|
||||
支持的格式 = {'.jpg', '.jpeg', '.png', '.bmp', '.gif', '.tiff', '.webp'}
|
||||
图片文件 = []
|
||||
|
||||
for 根目录, 目录, 文件列表 in os.walk(临时目录):
|
||||
for 文件 in 文件列表:
|
||||
if any(文件.lower().endswith(格式) for 格式 in 支持的格式):
|
||||
完整路径 = os.path.join(根目录, 文件)
|
||||
图片文件.append(完整路径)
|
||||
|
||||
if not 图片文件:
|
||||
print("错误: ZIP文件中没有找到图片文件")
|
||||
shutil.rmtree(临时目录)
|
||||
return None
|
||||
|
||||
# 按文件名自然排序
|
||||
图片文件.sort(key=lambda x: 自然排序键(os.path.basename(x)))
|
||||
|
||||
print(f"找到 {len(图片文件)} 张图片,开始转换...")
|
||||
|
||||
# 打开第一张图片作为基础
|
||||
图片对象列表 = []
|
||||
for 图片路径 in 图片文件:
|
||||
try:
|
||||
图片 = Image.open(图片路径)
|
||||
# 转换为RGB模式(确保兼容性)
|
||||
if 图片.mode != 'RGB':
|
||||
图片 = 图片.convert('RGB')
|
||||
图片对象列表.append(图片)
|
||||
except Exception as e:
|
||||
print(f"警告: 无法打开图片 {图片路径}: {e}")
|
||||
continue
|
||||
|
||||
if not 图片对象列表:
|
||||
print("错误: 没有成功加载任何图片")
|
||||
shutil.rmtree(临时目录)
|
||||
return None
|
||||
|
||||
# 保存为PDF(第一张作为主图,其余附加)
|
||||
图片对象列表[0].save(
|
||||
pdf路径,
|
||||
"PDF",
|
||||
quality=95,
|
||||
optimize=True,
|
||||
save_all=True,
|
||||
append_images=图片对象列表[1:]
|
||||
)
|
||||
|
||||
# 关闭所有图片对象
|
||||
for 图片 in 图片对象列表:
|
||||
图片.close()
|
||||
|
||||
# 清理临时文件
|
||||
shutil.rmtree(临时目录)
|
||||
|
||||
# 删除原ZIP文件
|
||||
os.remove(zip路径)
|
||||
|
||||
print(f"✓ 成功创建PDF: {pdf名称}")
|
||||
print(f"✓ 已删除原ZIP文件: {zip文件名}")
|
||||
|
||||
return pdf路径
|
||||
|
||||
except zipfile.BadZipFile:
|
||||
print(f"错误: {zip路径} 不是有效的ZIP文件")
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"处理过程中出错: {e}")
|
||||
# 清理临时文件
|
||||
if '临时目录' in locals() and os.path.exists(临时目录):
|
||||
shutil.rmtree(临时目录)
|
||||
return None
|
||||
|
||||
def 批量处理当前目录():
|
||||
"""批量处理当前目录下所有ZIP文件"""
|
||||
当前目录 = os.getcwd()
|
||||
zip文件列表 = []
|
||||
|
||||
# 扫描当前目录所有ZIP文件
|
||||
for 文件 in os.listdir(当前目录):
|
||||
if 文件.lower().endswith('.zip'):
|
||||
zip文件列表.append(os.path.join(当前目录, 文件))
|
||||
|
||||
if not zip文件列表:
|
||||
print("当前目录下没有找到ZIP文件")
|
||||
return
|
||||
|
||||
print(f"发现 {len(zip文件列表)} 个ZIP文件,开始批量处理...")
|
||||
print("-" * 50)
|
||||
|
||||
成功计数 = 0
|
||||
失败计数 = 0
|
||||
|
||||
for zip路径 in zip文件列表:
|
||||
print(f"\n[{zip文件列表.index(zip路径) + 1}/{len(zip文件列表)}] 处理: {os.path.basename(zip路径)}")
|
||||
|
||||
# 执行转换
|
||||
结果 = zip转pdf(zip路径)
|
||||
|
||||
if 结果:
|
||||
成功计数 += 1
|
||||
else:
|
||||
失败计数 += 1
|
||||
|
||||
print("-" * 50)
|
||||
print(f"批量处理完成!成功: {成功计数} 个,失败: {失败计数} 个")
|
||||
|
||||
def 处理指定文件(zip路径):
|
||||
"""处理指定的单个ZIP文件"""
|
||||
if not os.path.exists(zip路径):
|
||||
print(f"错误: 找不到文件 {zip路径}")
|
||||
return False
|
||||
|
||||
if not zip路径.lower().endswith('.zip'):
|
||||
print("错误: 请提供ZIP格式的文件")
|
||||
return False
|
||||
|
||||
# 执行转换
|
||||
结果 = zip转pdf(zip路径)
|
||||
|
||||
if 结果:
|
||||
print(f"\n🎉 任务完成!PDF文件已保存为: {结果}")
|
||||
return True
|
||||
else:
|
||||
print("\n❌ 任务失败,请检查错误信息")
|
||||
return False
|
||||
|
||||
def 主函数():
|
||||
"""主函数:智能处理模式"""
|
||||
import sys
|
||||
|
||||
# 优先处理指定文件(如果存在)
|
||||
指定文件路径 = r"C:\Users\lenovo\Desktop\新建文件夹\剥头皮量化策略全拆解:低延迟、高频的底层.zip"
|
||||
|
||||
# 检查是否有命令行参数
|
||||
if len(sys.argv) > 1:
|
||||
# 命令行指定了ZIP文件路径
|
||||
zip路径 = sys.argv[1]
|
||||
print(f"通过命令行参数指定文件: {zip路径}")
|
||||
处理指定文件(zip路径)
|
||||
elif os.path.exists(指定文件路径):
|
||||
# 处理默认指定文件
|
||||
print(f"处理默认指定文件: {os.path.basename(指定文件路径)}")
|
||||
处理指定文件(指定文件路径)
|
||||
else:
|
||||
# 自动扫描当前目录所有ZIP文件
|
||||
print("开始扫描当前目录所有ZIP文件...")
|
||||
批量处理当前目录()
|
||||
|
||||
if __name__ == "__main__":
|
||||
主函数()
|
||||
|
|
@ -1 +0,0 @@
|
|||
Pillow
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
# AI Chat Converter Configuration (Optional)
|
||||
# Default: Auto-detect paths, no configuration needed
|
||||
|
||||
# Custom paths (comma-separated for multiple)
|
||||
# CODEX_PATHS=~/.codex/sessions
|
||||
# KIRO_PATHS=~/.local/share/kiro-cli
|
||||
# GEMINI_PATHS=~/.gemini/tmp
|
||||
# CLAUDE_PATHS=~/.claude
|
||||
|
||||
# WSL paths also supported
|
||||
# CODEX_PATHS=\\wsl.localhost\Ubuntu\home\user\.codex\sessions
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
# Python
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*.so
|
||||
*.egg-info/
|
||||
dist/
|
||||
build/
|
||||
*.spec
|
||||
|
||||
# Output
|
||||
output/
|
||||
*.db
|
||||
*.sqlite3
|
||||
*.log
|
||||
|
||||
# Environment
|
||||
.env
|
||||
.venv/
|
||||
venv/
|
||||
|
||||
# IDE
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2024
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
|
@ -1,318 +0,0 @@
|
|||
<div align="center">
|
||||
|
||||
# 🔐 Chat Vault
|
||||
|
||||
**One tool to save ALL your AI chat history**
|
||||
|
||||
[](https://python.org)
|
||||
[](LICENSE)
|
||||
[]()
|
||||
[]()
|
||||
|
||||
[English](README.md) | [中文](README_CN.md)
|
||||
|
||||
[✨ Features](#-features) •
|
||||
[🚀 Quick Start](#-quick-start) •
|
||||
[📋 Commands](#-commands) •
|
||||
[📁 Project Structure](#-project-structure) •
|
||||
[❓ FAQ](#-faq)
|
||||
|
||||
[📞 Contact](#-contact) •
|
||||
[✨ Support](#-support) •
|
||||
[🤝 Contributing](#-contributing)
|
||||
|
||||
AI-powered docs: [zread.ai/tukuaiai/chat-vault](https://zread.ai/tukuaiai/chat-vault)
|
||||
|
||||
> 📦 This tool is part of [vibe-coding-cn](https://github.com/tukuaiai/vibe-coding-cn) - A comprehensive Vibe Coding guide
|
||||
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
## ✨ Features
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>🔄 <b>Multi-CLI</b></td>
|
||||
<td>Codex, Kiro, Gemini, Claude - all supported</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>⚡ <b>Real-time</b></td>
|
||||
<td>Watch mode with system-level file monitoring</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>🔢 <b>Token Stats</b></td>
|
||||
<td>Accurate counting using tiktoken (cl100k_base)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>🔍 <b>Search</b></td>
|
||||
<td>Find any conversation instantly</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>📤 <b>Export</b></td>
|
||||
<td>JSON or CSV, your choice</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>🚀 <b>Zero Config</b></td>
|
||||
<td>Auto-detects paths, just run it</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Architecture
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
subgraph Sources
|
||||
A[~/.codex]
|
||||
B[~/.kiro]
|
||||
C[~/.gemini]
|
||||
D[~/.claude]
|
||||
end
|
||||
|
||||
subgraph Chat Vault
|
||||
E[Watcher]
|
||||
F[Parsers]
|
||||
G[Storage]
|
||||
end
|
||||
|
||||
subgraph Output
|
||||
H[(SQLite DB)]
|
||||
end
|
||||
|
||||
A --> E
|
||||
B --> E
|
||||
C --> E
|
||||
D --> E
|
||||
E --> F
|
||||
F --> G
|
||||
G --> H
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 How It Works
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User
|
||||
participant CLI as AI CLI (Codex/Kiro/...)
|
||||
participant Watcher
|
||||
participant Parser
|
||||
participant DB as SQLite
|
||||
|
||||
User->>CLI: Chat with AI
|
||||
CLI->>CLI: Save to local file
|
||||
Watcher->>Watcher: Detect file change
|
||||
Watcher->>Parser: Parse new content
|
||||
Parser->>DB: Upsert session
|
||||
DB-->>User: Query anytime
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### 30 Seconds Setup
|
||||
|
||||
```bash
|
||||
# Clone
|
||||
git clone https://github.com/tukuaiai/vibe-coding-cn.git
|
||||
cd vibe-coding-cn/libs/external/chat-vault
|
||||
|
||||
# Run (auto-installs dependencies)
|
||||
./start.sh # Linux/macOS
|
||||
start.bat # Windows
|
||||
```
|
||||
|
||||
**That's it!** 🎉
|
||||
|
||||
---
|
||||
|
||||
## 📊 Example Output
|
||||
|
||||
```
|
||||
==================================================
|
||||
AI 聊天记录 → 集中存储
|
||||
==================================================
|
||||
数据库: ./output/chat_history.db
|
||||
|
||||
[Codex] 新增:1241 更新:0 跳过:0 错误:0
|
||||
[Kiro] 新增:21 更新:0 跳过:0 错误:0
|
||||
[Gemini] 新增:332 更新:0 跳过:0 错误:0
|
||||
[Claude] 新增:168 更新:0 跳过:0 错误:0
|
||||
|
||||
==================================================
|
||||
总计: 1762 会话, 40000+ 消息
|
||||
✓ 同步完成!
|
||||
|
||||
=== Token 统计 (tiktoken) ===
|
||||
codex: 11,659,952 tokens
|
||||
kiro: 26,337 tokens
|
||||
gemini: 3,195,821 tokens
|
||||
claude: 29,725 tokens
|
||||
总计: 14,911,835 tokens
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `python src/main.py` | Sync once |
|
||||
| `python src/main.py -w` | Watch mode (real-time) |
|
||||
| `python src/main.py --stats` | Show statistics |
|
||||
| `python src/main.py --search "keyword"` | Search messages |
|
||||
| `python src/main.py --export json` | Export to JSON |
|
||||
| `python src/main.py --export csv --source codex` | Export specific source |
|
||||
| `python src/main.py --prune` | Clean orphaned records |
|
||||
|
||||
---
|
||||
|
||||
## 📁 Project Structure
|
||||
|
||||
```
|
||||
chat-vault/
|
||||
├── 🚀 start.sh / start.bat # One-click start
|
||||
├── 📦 build.py # Build standalone exe
|
||||
├── 📂 src/
|
||||
│ ├── main.py # CLI entry
|
||||
│ ├── config.py # Auto-detection
|
||||
│ ├── storage.py # SQLite + tiktoken
|
||||
│ ├── watcher.py # File monitoring
|
||||
│ └── parsers/ # CLI parsers
|
||||
├── 📂 docs/
|
||||
│ ├── AI_PROMPT.md # AI assistant guide
|
||||
│ └── schema.md # Database schema
|
||||
└── 📂 output/
|
||||
├── chat_history.db # Your database
|
||||
└── logs/ # Sync logs
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🗄️ Database Schema
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
sessions {
|
||||
TEXT file_path PK
|
||||
TEXT session_id
|
||||
TEXT source
|
||||
TEXT cwd
|
||||
TEXT messages
|
||||
INTEGER file_mtime
|
||||
TEXT start_time
|
||||
INTEGER token_count
|
||||
}
|
||||
|
||||
meta {
|
||||
TEXT key PK
|
||||
TEXT value
|
||||
}
|
||||
|
||||
meta_codex {
|
||||
TEXT key PK
|
||||
TEXT value
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🤖 For AI Assistants
|
||||
|
||||
Send [docs/AI_PROMPT.md](docs/AI_PROMPT.md) to your AI assistant for:
|
||||
- SQL query examples
|
||||
- Python code snippets
|
||||
- Task guidance
|
||||
|
||||
---
|
||||
|
||||
## ❓ FAQ
|
||||
|
||||
<details>
|
||||
<summary><b>Do I need to configure anything?</b></summary>
|
||||
|
||||
No. Auto-detects `~/.codex`, `~/.kiro`, `~/.gemini`, `~/.claude`
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>Does it work with WSL?</b></summary>
|
||||
|
||||
Yes! Paths like `\\wsl.localhost\Ubuntu\...` are supported
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>How do I view the database?</b></summary>
|
||||
|
||||
Use [DB Browser for SQLite](https://sqlitebrowser.org/) or any SQLite tool
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>Is my data safe?</b></summary>
|
||||
|
||||
Yes. We only READ from AI tools, never modify original files
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## 📞 Contact
|
||||
|
||||
- **GitHub**: [tukuaiai](https://github.com/tukuaiai)
|
||||
- **Twitter / X**: [123olp](https://x.com/123olp)
|
||||
- **Telegram**: [@desci0](https://t.me/desci0)
|
||||
- **Telegram Group**: [glue_coding](https://t.me/glue_coding)
|
||||
- **Telegram Channel**: [tradecat_ai_channel](https://t.me/tradecat_ai_channel)
|
||||
- **Email**: tukuai.ai@gmail.com
|
||||
|
||||
---
|
||||
|
||||
## ✨ Support
|
||||
|
||||
If this project helped you, consider supporting:
|
||||
|
||||
- **Binance UID**: `572155580`
|
||||
- **Tron (TRC20)**: `TQtBXCSTwLFHjBqTS4rNUp7ufiGx51BRey`
|
||||
- **Solana**: `HjYhozVf9AQmfv7yv79xSNs6uaEU5oUk2USasYQfUYau`
|
||||
- **Ethereum (ERC20)**: `0xa396923a71ee7D9480b346a17dDeEb2c0C287BBC`
|
||||
- **BNB Smart Chain (BEP20)**: `0xa396923a71ee7D9480b346a17dDeEb2c0C287BBC`
|
||||
- **Bitcoin**: `bc1plslluj3zq3snpnnczplu7ywf37h89dyudqua04pz4txwh8z5z5vsre7nlm`
|
||||
- **Sui**: `0xb720c98a48c77f2d49d375932b2867e793029e6337f1562522640e4f84203d2e`
|
||||
|
||||
---
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
We welcome all contributions! Feel free to open an [Issue](https://github.com/tukuaiai/vibe-coding-cn/issues) or submit a [Pull Request](https://github.com/tukuaiai/vibe-coding-cn/pulls).
|
||||
|
||||
---
|
||||
|
||||
## 📄 License
|
||||
|
||||
[MIT](LICENSE) - Do whatever you want with it.
|
||||
|
||||
---
|
||||
|
||||
<div align="center">
|
||||
|
||||
**If this helped you, give it a ⭐!**
|
||||
|
||||
## Star History
|
||||
|
||||
<a href="https://www.star-history.com/#tukuaiai/vibe-coding-cn&type=Date">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=tukuaiai/vibe-coding-cn&type=Date&theme=dark" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=tukuaiai/vibe-coding-cn&type=Date" />
|
||||
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=tukuaiai/vibe-coding-cn&type=Date" />
|
||||
</picture>
|
||||
</a>
|
||||
|
||||
---
|
||||
|
||||
**Made with ❤️ by [tukuaiai](https://github.com/tukuaiai)**
|
||||
|
||||
[⬆ Back to Top](#-chat-vault)
|
||||
|
||||
</div>
|
||||
|
|
@ -1,311 +0,0 @@
|
|||
<div align="center">
|
||||
|
||||
# 🔐 Chat Vault
|
||||
|
||||
**一个工具保存你所有的 AI 聊天记录**
|
||||
|
||||
[](https://python.org)
|
||||
[](LICENSE)
|
||||
[]()
|
||||
[]()
|
||||
|
||||
[English](README.md) | [中文](README_CN.md)
|
||||
|
||||
[✨ 功能特性](#-功能特性) •
|
||||
[🚀 快速开始](#-30-秒快速开始) •
|
||||
[📋 命令一览](#-命令一览) •
|
||||
[📁 项目结构](#-项目结构) •
|
||||
[❓ 常见问题](#-常见问题)
|
||||
|
||||
[📞 联系方式](#-联系方式) •
|
||||
[✨ 支持项目](#-支持项目) •
|
||||
[🤝 参与贡献](#-参与贡献)
|
||||
|
||||
AI 解读文档: [zread.ai/tukuaiai/chat-vault](https://zread.ai/tukuaiai/chat-vault)
|
||||
|
||||
> 📦 本工具是 [vibe-coding-cn](https://github.com/tukuaiai/vibe-coding-cn) 的一部分 - 一份全面的 Vibe Coding 指南
|
||||
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
## ✨ 功能特性
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>🔄 <b>多 CLI 支持</b></td>
|
||||
<td>Codex、Kiro、Gemini、Claude 全都行</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>⚡ <b>实时同步</b></td>
|
||||
<td>系统级文件监控,聊完自动保存</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>🔢 <b>Token 统计</b></td>
|
||||
<td>tiktoken 精确计算,知道你用了多少</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>🔍 <b>搜索</b></td>
|
||||
<td>秒找任何对话</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>📤 <b>导出</b></td>
|
||||
<td>JSON 或 CSV,随你选</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>🚀 <b>零配置</b></td>
|
||||
<td>自动检测路径,开箱即用</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ 架构图
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
subgraph 数据来源
|
||||
A[~/.codex]
|
||||
B[~/.kiro]
|
||||
C[~/.gemini]
|
||||
D[~/.claude]
|
||||
end
|
||||
|
||||
subgraph Chat Vault
|
||||
E[监控器]
|
||||
F[解析器]
|
||||
G[存储层]
|
||||
end
|
||||
|
||||
subgraph 输出
|
||||
H[(SQLite 数据库)]
|
||||
end
|
||||
|
||||
A --> E
|
||||
B --> E
|
||||
C --> E
|
||||
D --> E
|
||||
E --> F
|
||||
F --> G
|
||||
G --> H
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 工作流程
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant 用户
|
||||
participant CLI as AI CLI (Codex/Kiro/...)
|
||||
participant 监控器
|
||||
participant 解析器
|
||||
participant DB as SQLite
|
||||
|
||||
用户->>CLI: 和 AI 聊天
|
||||
CLI->>CLI: 保存到本地文件
|
||||
监控器->>监控器: 检测文件变化
|
||||
监控器->>解析器: 解析新内容
|
||||
解析器->>DB: 写入数据库
|
||||
DB-->>用户: 随时查询
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 30 秒快速开始
|
||||
|
||||
```bash
|
||||
# 下载
|
||||
git clone https://github.com/tukuaiai/vibe-coding-cn.git
|
||||
cd vibe-coding-cn/libs/external/chat-vault
|
||||
|
||||
# 运行(自动安装依赖)
|
||||
./start.sh # Linux/macOS
|
||||
start.bat # Windows(双击)
|
||||
```
|
||||
|
||||
**搞定!** 🎉
|
||||
|
||||
---
|
||||
|
||||
## 📊 运行效果
|
||||
|
||||
```
|
||||
==================================================
|
||||
AI 聊天记录 → 集中存储
|
||||
==================================================
|
||||
数据库: ./output/chat_history.db
|
||||
|
||||
[Codex] 新增:1241 更新:0 跳过:0 错误:0
|
||||
[Kiro] 新增:21 更新:0 跳过:0 错误:0
|
||||
[Gemini] 新增:332 更新:0 跳过:0 错误:0
|
||||
[Claude] 新增:168 更新:0 跳过:0 错误:0
|
||||
|
||||
==================================================
|
||||
总计: 1762 会话, 40000+ 消息
|
||||
✓ 同步完成!
|
||||
|
||||
=== Token 统计 (tiktoken) ===
|
||||
codex: 11,659,952 tokens
|
||||
kiro: 26,337 tokens
|
||||
gemini: 3,195,821 tokens
|
||||
claude: 29,725 tokens
|
||||
总计: 14,911,835 tokens
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 命令一览
|
||||
|
||||
| 命令 | 说明 |
|
||||
|------|------|
|
||||
| `python src/main.py` | 同步一次 |
|
||||
| `python src/main.py -w` | 实时监控(推荐) |
|
||||
| `python src/main.py --stats` | 查看统计 |
|
||||
| `python src/main.py --search "关键词"` | 搜索消息 |
|
||||
| `python src/main.py --export json` | 导出 JSON |
|
||||
| `python src/main.py --export csv --source codex` | 导出指定来源 |
|
||||
| `python src/main.py --prune` | 清理孤立记录 |
|
||||
|
||||
---
|
||||
|
||||
## 📁 项目结构
|
||||
|
||||
```
|
||||
chat-vault/
|
||||
├── 🚀 start.sh / start.bat # 一键启动
|
||||
├── 📦 build.py # 打包脚本
|
||||
├── 📂 src/
|
||||
│ ├── main.py # 主程序
|
||||
│ ├── config.py # 配置检测
|
||||
│ ├── storage.py # SQLite + tiktoken
|
||||
│ ├── watcher.py # 文件监控
|
||||
│ └── parsers/ # 各 CLI 解析器
|
||||
├── 📂 docs/
|
||||
│ ├── AI_PROMPT.md # AI 助手指南
|
||||
│ └── schema.md # 数据库结构
|
||||
└── 📂 output/
|
||||
├── chat_history.db # 你的数据库
|
||||
└── logs/ # 日志
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🗄️ 数据库结构
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
sessions {
|
||||
TEXT file_path PK "文件路径"
|
||||
TEXT session_id "会话ID"
|
||||
TEXT source "来源"
|
||||
TEXT cwd "工作目录"
|
||||
TEXT messages "消息JSON"
|
||||
INTEGER file_mtime "修改时间"
|
||||
TEXT start_time "开始时间"
|
||||
INTEGER token_count "Token数"
|
||||
}
|
||||
|
||||
meta {
|
||||
TEXT key PK
|
||||
TEXT value
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🤖 让 AI 帮你查数据库
|
||||
|
||||
把 [docs/AI_PROMPT.md](docs/AI_PROMPT.md) 发给 AI 助手,它就知道:
|
||||
- 怎么写 SQL 查询
|
||||
- 怎么用 Python 分析
|
||||
- 怎么帮你找对话
|
||||
|
||||
---
|
||||
|
||||
## ❓ 常见问题
|
||||
|
||||
<details>
|
||||
<summary><b>需要配置什么吗?</b></summary>
|
||||
|
||||
不用。自动检测 `~/.codex`、`~/.kiro`、`~/.gemini`、`~/.claude`
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>WSL 能用吗?</b></summary>
|
||||
|
||||
能!`\\wsl.localhost\Ubuntu\...` 这种路径也支持
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>怎么看数据库?</b></summary>
|
||||
|
||||
用 [DB Browser for SQLite](https://sqlitebrowser.org/) 或任何 SQLite 工具
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>会不会搞坏我的数据?</b></summary>
|
||||
|
||||
不会。只读取,从不修改原始文件
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## 📞 联系方式
|
||||
|
||||
- **GitHub**: [tukuaiai](https://github.com/tukuaiai)
|
||||
- **Twitter / X**: [123olp](https://x.com/123olp)
|
||||
- **Telegram**: [@desci0](https://t.me/desci0)
|
||||
- **Telegram 交流群**: [glue_coding](https://t.me/glue_coding)
|
||||
- **Telegram 频道**: [tradecat_ai_channel](https://t.me/tradecat_ai_channel)
|
||||
- **邮箱**: tukuai.ai@gmail.com
|
||||
|
||||
---
|
||||
|
||||
## ✨ 支持项目
|
||||
|
||||
如果这个项目帮到你了,考虑支持一下:
|
||||
|
||||
- **币安 UID**: `572155580`
|
||||
- **Tron (TRC20)**: `TQtBXCSTwLFHjBqTS4rNUp7ufiGx51BRey`
|
||||
- **Solana**: `HjYhozVf9AQmfv7yv79xSNs6uaEU5oUk2USasYQfUYau`
|
||||
- **Ethereum (ERC20)**: `0xa396923a71ee7D9480b346a17dDeEb2c0C287BBC`
|
||||
- **BNB Smart Chain (BEP20)**: `0xa396923a71ee7D9480b346a17dDeEb2c0C287BBC`
|
||||
- **Bitcoin**: `bc1plslluj3zq3snpnnczplu7ywf37h89dyudqua04pz4txwh8z5z5vsre7nlm`
|
||||
- **Sui**: `0xb720c98a48c77f2d49d375932b2867e793029e6337f1562522640e4f84203d2e`
|
||||
|
||||
---
|
||||
|
||||
## 🤝 参与贡献
|
||||
|
||||
欢迎各种形式的贡献!随时开启一个 [Issue](https://github.com/tukuaiai/vibe-coding-cn/issues) 或提交 [Pull Request](https://github.com/tukuaiai/vibe-coding-cn/pulls)。
|
||||
|
||||
---
|
||||
|
||||
## 📄 开源协议
|
||||
|
||||
[MIT](LICENSE) - 随便用,不用管我
|
||||
|
||||
---
|
||||
|
||||
<div align="center">
|
||||
|
||||
**如果帮到你了,点个 ⭐ 呗!**
|
||||
|
||||
## Star History
|
||||
|
||||
<a href="https://www.star-history.com/#tukuaiai/vibe-coding-cn&type=Date">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=tukuaiai/vibe-coding-cn&type=Date&theme=dark" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=tukuaiai/vibe-coding-cn&type=Date" />
|
||||
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=tukuaiai/vibe-coding-cn&type=Date" />
|
||||
</picture>
|
||||
</a>
|
||||
|
||||
---
|
||||
|
||||
**Made with ❤️ by [tukuaiai](https://github.com/tukuaiai)**
|
||||
|
||||
[⬆ 返回顶部](#-chat-vault)
|
||||
|
||||
</div>
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
@echo off
|
||||
echo 安装打包工具...
|
||||
pip install pyinstaller -q
|
||||
|
||||
echo 开始打包...
|
||||
pyinstaller --onefile --name ai-chat-converter ^
|
||||
--add-data "src;src" ^
|
||||
--hidden-import tiktoken_ext.openai_public ^
|
||||
--hidden-import tiktoken_ext ^
|
||||
--collect-data tiktoken ^
|
||||
src/main.py
|
||||
|
||||
echo.
|
||||
echo 完成! 输出: dist\ai-chat-converter.exe
|
||||
pause
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
"""打包脚本 - 生成独立可执行文件"""
|
||||
import subprocess
|
||||
import sys
|
||||
import os
|
||||
import shutil
|
||||
|
||||
def main():
|
||||
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
for d in ['build', 'dist']:
|
||||
if os.path.exists(d):
|
||||
shutil.rmtree(d)
|
||||
|
||||
print("开始打包...")
|
||||
|
||||
sep = ";" if sys.platform == "win32" else ":"
|
||||
|
||||
cmd = [
|
||||
sys.executable, "-m", "PyInstaller",
|
||||
"--onefile",
|
||||
"--name", "ai-chat-converter",
|
||||
f"--add-data=src{sep}src",
|
||||
"--hidden-import", "tiktoken_ext.openai_public",
|
||||
"--hidden-import", "tiktoken_ext",
|
||||
"--hidden-import", "dotenv",
|
||||
"--collect-data", "tiktoken",
|
||||
"--collect-all", "watchdog",
|
||||
"--collect-all", "dotenv",
|
||||
"src/main.py"
|
||||
]
|
||||
|
||||
subprocess.run(cmd, check=True)
|
||||
|
||||
exe = "dist/ai-chat-converter.exe" if sys.platform == "win32" else "dist/ai-chat-converter"
|
||||
size = os.path.getsize(exe) / 1024 / 1024
|
||||
print(f"\n✓ 打包完成: {exe} ({size:.1f} MB)")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -1,231 +0,0 @@
|
|||
# AI Chat Converter - AI 助手完全指南
|
||||
|
||||
> **把这个文档发给 AI 助手,它就知道怎么帮你用这个工具了**
|
||||
|
||||
---
|
||||
|
||||
## 🎯 这是什么?
|
||||
|
||||
一个把 Codex、Kiro、Gemini、Claude 的聊天记录全部存到一个 SQLite 数据库的工具。
|
||||
|
||||
**数据库位置**: `项目目录/output/chat_history.db`
|
||||
|
||||
---
|
||||
|
||||
## 🚀 怎么启动?
|
||||
|
||||
### 方式一:双击启动(推荐)
|
||||
```bash
|
||||
./start.sh # Linux/macOS
|
||||
start.bat # Windows(双击)
|
||||
```
|
||||
|
||||
### 方式二:命令行
|
||||
```bash
|
||||
cd ai-chat-converter
|
||||
python src/main.py --watch # 持续监控(推荐)
|
||||
python src/main.py # 同步一次就退出
|
||||
```
|
||||
|
||||
### 方式三:后台运行
|
||||
```bash
|
||||
nohup ./start.sh > /dev/null 2>&1 &
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 数据库长啥样?
|
||||
|
||||
### 主表:sessions
|
||||
|
||||
| 字段 | 说明 | 例子 |
|
||||
|------|------|------|
|
||||
| file_path | 主键,文件路径 | `/home/user/.codex/sessions/xxx.jsonl` |
|
||||
| session_id | 会话ID | `019b2164-168c-7133-9b1f-5d24fea1d3e1` |
|
||||
| source | 来源 | `codex` / `kiro` / `gemini` / `claude` |
|
||||
| cwd | 工作目录 | `/home/user/projects/myapp` |
|
||||
| messages | 消息内容(JSON) | `[{"time":"...", "role":"user", "content":"..."}]` |
|
||||
| start_time | 开始时间 | `2025-12-18T10:30:00` |
|
||||
| token_count | Token 数量 | `1234` |
|
||||
|
||||
---
|
||||
|
||||
## 🔍 常用查询(直接复制用)
|
||||
|
||||
### 1. 看看有多少数据
|
||||
|
||||
```sql
|
||||
SELECT source, COUNT(*) as 会话数, SUM(token_count) as Token总数
|
||||
FROM sessions
|
||||
GROUP BY source;
|
||||
```
|
||||
|
||||
### 2. 最近的 10 个会话
|
||||
|
||||
```sql
|
||||
SELECT session_id, source, cwd, start_time, token_count
|
||||
FROM sessions
|
||||
ORDER BY start_time DESC
|
||||
LIMIT 10;
|
||||
```
|
||||
|
||||
### 3. 搜索包含某个词的对话
|
||||
|
||||
```sql
|
||||
SELECT session_id, source, cwd, start_time
|
||||
FROM sessions
|
||||
WHERE messages LIKE '%要搜索的词%'
|
||||
ORDER BY start_time DESC
|
||||
LIMIT 20;
|
||||
```
|
||||
|
||||
### 4. 查某个项目的所有对话
|
||||
|
||||
```sql
|
||||
SELECT session_id, source, start_time, token_count
|
||||
FROM sessions
|
||||
WHERE cwd LIKE '%项目名%'
|
||||
ORDER BY start_time;
|
||||
```
|
||||
|
||||
### 5. 看某个会话的完整内容
|
||||
|
||||
```sql
|
||||
SELECT messages FROM sessions WHERE session_id = '会话ID';
|
||||
```
|
||||
|
||||
### 6. 统计每天用了多少 Token
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
date(start_time) as 日期,
|
||||
SUM(token_count) as Token数
|
||||
FROM sessions
|
||||
GROUP BY 日期
|
||||
ORDER BY 日期 DESC
|
||||
LIMIT 7;
|
||||
```
|
||||
|
||||
### 7. 统计每个来源的 Token
|
||||
|
||||
```sql
|
||||
SELECT source, SUM(token_count) as tokens
|
||||
FROM sessions
|
||||
GROUP BY source
|
||||
ORDER BY tokens DESC;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💻 命令行用法
|
||||
|
||||
| 命令 | 干啥的 |
|
||||
|------|--------|
|
||||
| `python src/main.py` | 同步一次 |
|
||||
| `python src/main.py -w` | 持续监控(推荐) |
|
||||
| `python src/main.py --stats` | 看统计信息 |
|
||||
| `python src/main.py --search "关键词"` | 搜索 |
|
||||
| `python src/main.py --export json` | 导出 JSON |
|
||||
| `python src/main.py --export csv` | 导出 CSV |
|
||||
| `python src/main.py --prune` | 清理已删除文件的记录 |
|
||||
|
||||
---
|
||||
|
||||
## 🐍 用 Python 查询
|
||||
|
||||
```python
|
||||
import sqlite3
|
||||
import json
|
||||
|
||||
# 连接数据库
|
||||
db = sqlite3.connect('output/chat_history.db')
|
||||
|
||||
# 查所有 Codex 会话
|
||||
for row in db.execute("SELECT session_id, cwd, token_count FROM sessions WHERE source='codex'"):
|
||||
print(f"{row[0]}: {row[2]} tokens - {row[1]}")
|
||||
|
||||
# 搜索包含 "python" 的对话
|
||||
for row in db.execute("SELECT session_id, source FROM sessions WHERE messages LIKE '%python%'"):
|
||||
print(f"[{row[1]}] {row[0]}")
|
||||
|
||||
# 获取某个会话的消息
|
||||
row = db.execute("SELECT messages FROM sessions WHERE session_id=?", ('会话ID',)).fetchone()
|
||||
if row:
|
||||
messages = json.loads(row[0])
|
||||
for msg in messages:
|
||||
print(f"{msg['role']}: {msg['content'][:100]}...")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📁 文件在哪?
|
||||
|
||||
```
|
||||
ai-chat-converter/
|
||||
├── start.sh ← 双击这个启动
|
||||
├── output/
|
||||
│ ├── chat_history.db ← 数据库在这
|
||||
│ └── logs/ ← 日志在这
|
||||
└── src/
|
||||
└── main.py ← 主程序
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ❓ AI 助手任务示例
|
||||
|
||||
当用户说这些话时,你应该这样做:
|
||||
|
||||
| 用户说 | 你做 |
|
||||
|--------|------|
|
||||
| "帮我查最近的对话" | 执行最近会话 SQL |
|
||||
| "搜索关于 Python 的讨论" | 用 `--search` 或 SQL 搜索 |
|
||||
| "这个月用了多少 Token" | 执行 Token 统计 SQL |
|
||||
| "导出所有 Codex 记录" | `python src/main.py --export json --source codex` |
|
||||
| "启动监控" | `./start.sh` 或 `python src/main.py -w` |
|
||||
| "数据库在哪" | `output/chat_history.db` |
|
||||
|
||||
---
|
||||
|
||||
## 🔧 出问题了?
|
||||
|
||||
### 问题:找不到数据库
|
||||
```bash
|
||||
# 先运行一次同步
|
||||
python src/main.py
|
||||
```
|
||||
|
||||
### 问题:依赖没装
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
### 问题:权限不够
|
||||
```bash
|
||||
chmod +x start.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 消息格式
|
||||
|
||||
数据库里的 `messages` 字段是 JSON 数组:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"time": "2025-12-18T10:30:00",
|
||||
"role": "user",
|
||||
"content": "帮我写个 Python 脚本"
|
||||
},
|
||||
{
|
||||
"time": "2025-12-18T10:30:05",
|
||||
"role": "ai",
|
||||
"content": "好的,这是一个简单的脚本..."
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
- `role`: `user`(用户)或 `ai`(AI 回复)
|
||||
- `time`: ISO 格式时间
|
||||
- `content`: 消息内容
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
# Roadmap
|
||||
|
||||
## v1.0 ✅ Core
|
||||
- [x] Multi-CLI support (Codex/Kiro/Gemini/Claude)
|
||||
- [x] Auto path detection
|
||||
- [x] SQLite storage
|
||||
- [x] Incremental sync
|
||||
- [x] Cross-platform watch mode (watchdog)
|
||||
- [x] Token counting (tiktoken)
|
||||
|
||||
## Future
|
||||
- [ ] Web UI
|
||||
- [ ] API server mode
|
||||
- [ ] Vector storage (RAG)
|
||||
- [ ] Cross-AI context sharing
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
# 数据库结构 (v5)
|
||||
|
||||
**位置**: `项目目录/output/chat_history.db`
|
||||
|
||||
## sessions 表(主表)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| file_path | TEXT | 主键,源文件路径 |
|
||||
| session_id | TEXT | 会话 ID |
|
||||
| source | TEXT | 来源: codex/kiro/gemini/claude |
|
||||
| cwd | TEXT | 工作目录 |
|
||||
| messages | TEXT | JSON 数组 |
|
||||
| file_mtime | INTEGER | 文件修改时间戳 |
|
||||
| start_time | TEXT | 会话开始时间 |
|
||||
| token_count | INTEGER | Token 数量 |
|
||||
|
||||
**索引**: `idx_source`, `idx_session_id`, `idx_start_time`
|
||||
|
||||
## meta 表(全局统计)
|
||||
|
||||
| key | 说明 |
|
||||
|-----|------|
|
||||
| schema_version | 数据库版本 (5) |
|
||||
| total_sessions | 总会话数 |
|
||||
| total_messages | 总消息数 |
|
||||
| total_tokens | 总 Token 数 |
|
||||
| last_sync | 最后同步时间 |
|
||||
|
||||
## meta_{cli} 表(各 CLI 统计)
|
||||
|
||||
每个 CLI 独立的元信息表:`meta_codex`, `meta_kiro`, `meta_gemini`, `meta_claude`
|
||||
|
||||
| key | 说明 |
|
||||
|-----|------|
|
||||
| path | 监控路径 |
|
||||
| sessions | 会话数 |
|
||||
| messages | 消息数 |
|
||||
| total_tokens | Token 总数 |
|
||||
| last_sync | 最后同步时间 |
|
||||
|
||||
## 消息格式
|
||||
|
||||
```json
|
||||
[
|
||||
{"time": "2025-12-18T10:30:00", "role": "user", "content": "..."},
|
||||
{"time": "2025-12-18T10:30:05", "role": "ai", "content": "..."}
|
||||
]
|
||||
```
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
python-dotenv>=1.0.0
|
||||
watchdog>=3.0.0
|
||||
tiktoken>=0.5.0
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
#!/bin/bash
|
||||
cd "$(dirname "$0")/../src"
|
||||
python3 main.py
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
#!/bin/bash
|
||||
cd "$(dirname "$0")/../src"
|
||||
python3 main.py --watch
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
r"""
|
||||
配置模块 - 智能路径识别
|
||||
支持: Linux 原生路径、WSL 路径 (\\wsl.localhost\Ubuntu\...)
|
||||
"""
|
||||
import os
|
||||
import re
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# 项目目录
|
||||
PROJECT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
OUTPUT_DIR = os.path.join(PROJECT_DIR, "output")
|
||||
|
||||
load_dotenv(os.path.join(PROJECT_DIR, ".env"))
|
||||
|
||||
def convert_wsl_path(path: str) -> str:
|
||||
match = re.match(r'^\\\\wsl[.\$]?[^\\]*\\[^\\]+\\(.+)$', path, re.IGNORECASE)
|
||||
if match:
|
||||
return '/' + match.group(1).replace('\\', '/')
|
||||
return path
|
||||
|
||||
def normalize_path(path: str) -> str:
|
||||
path = path.strip()
|
||||
path = convert_wsl_path(path)
|
||||
return os.path.expanduser(path)
|
||||
|
||||
def get_paths(env_key: str) -> list:
|
||||
val = os.getenv(env_key, "")
|
||||
if not val:
|
||||
return []
|
||||
return [normalize_path(p) for p in val.split(",") if p.strip()]
|
||||
|
||||
def auto_detect_paths() -> dict:
|
||||
home = os.path.expanduser("~")
|
||||
kiro_db = os.path.join(home, ".local", "share", "kiro-cli")
|
||||
candidates = {
|
||||
"codex_paths": [os.path.join(home, ".codex", "sessions"), os.path.join(home, ".codex")],
|
||||
"kiro_paths": [kiro_db] if os.path.exists(kiro_db) else [],
|
||||
"gemini_paths": [os.path.join(home, ".gemini", "tmp"), os.path.join(home, ".gemini")],
|
||||
"claude_paths": [os.path.join(home, ".claude")],
|
||||
}
|
||||
detected = {}
|
||||
for key, paths in candidates.items():
|
||||
for p in paths:
|
||||
if os.path.exists(p):
|
||||
detected[key] = [p]
|
||||
break
|
||||
if key not in detected:
|
||||
detected[key] = []
|
||||
return detected
|
||||
|
||||
def load_config() -> dict:
|
||||
auto = auto_detect_paths()
|
||||
|
||||
os.makedirs(OUTPUT_DIR, exist_ok=True)
|
||||
os.makedirs(os.path.join(OUTPUT_DIR, "logs"), exist_ok=True)
|
||||
|
||||
return {
|
||||
"codex_paths": get_paths("CODEX_PATHS") or auto.get("codex_paths", []),
|
||||
"kiro_paths": get_paths("KIRO_PATHS") or auto.get("kiro_paths", []),
|
||||
"gemini_paths": get_paths("GEMINI_PATHS") or auto.get("gemini_paths", []),
|
||||
"claude_paths": get_paths("CLAUDE_PATHS") or auto.get("claude_paths", []),
|
||||
"output_dir": OUTPUT_DIR,
|
||||
"log_dir": os.path.join(OUTPUT_DIR, "logs"),
|
||||
"db_path": os.path.join(OUTPUT_DIR, "chat_history.db"),
|
||||
}
|
||||
|
||||
CONFIG = load_config()
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""日志模块 - 同时输出到控制台和文件"""
|
||||
import logging
|
||||
import os
|
||||
from datetime import datetime
|
||||
|
||||
_logger = None
|
||||
|
||||
def setup_logger(log_dir: str = None) -> logging.Logger:
|
||||
global _logger
|
||||
if _logger:
|
||||
return _logger
|
||||
|
||||
_logger = logging.getLogger('ai_chat_converter')
|
||||
_logger.setLevel(logging.DEBUG)
|
||||
_logger.handlers.clear()
|
||||
|
||||
fmt = logging.Formatter('%(asctime)s [%(levelname)s] %(message)s', datefmt='%Y-%m-%d %H:%M:%S')
|
||||
|
||||
# 控制台
|
||||
ch = logging.StreamHandler()
|
||||
ch.setLevel(logging.INFO)
|
||||
ch.setFormatter(fmt)
|
||||
_logger.addHandler(ch)
|
||||
|
||||
# 文件
|
||||
if log_dir:
|
||||
os.makedirs(log_dir, exist_ok=True)
|
||||
log_file = os.path.join(log_dir, f"sync_{datetime.now().strftime('%Y%m%d')}.log")
|
||||
fh = logging.FileHandler(log_file, encoding='utf-8')
|
||||
fh.setLevel(logging.DEBUG)
|
||||
fh.setFormatter(fmt)
|
||||
_logger.addHandler(fh)
|
||||
|
||||
return _logger
|
||||
|
||||
def get_logger() -> logging.Logger:
|
||||
global _logger
|
||||
if not _logger:
|
||||
_logger = setup_logger()
|
||||
return _logger
|
||||
|
|
@ -1,319 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
AI 聊天记录集中存储工具
|
||||
|
||||
命令:
|
||||
python main.py # 同步一次
|
||||
python main.py --watch # 持续监控
|
||||
python main.py --prune # 清理孤立记录
|
||||
python main.py --stats # 显示统计
|
||||
python main.py --search <keyword> # 搜索
|
||||
python main.py --export json|csv [--source codex|kiro|gemini|claude]
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
|
||||
# 项目根目录
|
||||
PROJECT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
VENV_DIR = os.path.join(PROJECT_DIR, '.venv')
|
||||
REQUIREMENTS = os.path.join(PROJECT_DIR, 'requirements.txt')
|
||||
|
||||
def ensure_venv():
|
||||
"""检测并创建虚拟环境,安装依赖"""
|
||||
# 打包版本跳过
|
||||
if getattr(sys, 'frozen', False):
|
||||
return
|
||||
|
||||
# 已在虚拟环境中运行则跳过
|
||||
if sys.prefix != sys.base_prefix:
|
||||
return
|
||||
|
||||
# 检查 .venv 是否存在
|
||||
venv_python = os.path.join(VENV_DIR, 'bin', 'python') if os.name != 'nt' else os.path.join(VENV_DIR, 'Scripts', 'python.exe')
|
||||
|
||||
if not os.path.exists(venv_python):
|
||||
print("首次运行,创建虚拟环境...")
|
||||
subprocess.run([sys.executable, '-m', 'venv', VENV_DIR], check=True)
|
||||
print("安装依赖...")
|
||||
pip = os.path.join(VENV_DIR, 'bin', 'pip') if os.name != 'nt' else os.path.join(VENV_DIR, 'Scripts', 'pip.exe')
|
||||
subprocess.run([pip, 'install', '-r', REQUIREMENTS, '-q'], check=True)
|
||||
print("环境准备完成,重新启动...\n")
|
||||
|
||||
# 使用虚拟环境重新执行
|
||||
os.execv(venv_python, [venv_python] + sys.argv)
|
||||
|
||||
# 启动前检测虚拟环境
|
||||
ensure_venv()
|
||||
|
||||
# 支持 PyInstaller 打包
|
||||
if getattr(sys, 'frozen', False):
|
||||
BASE_DIR = sys._MEIPASS
|
||||
sys.path.insert(0, os.path.join(BASE_DIR, 'src'))
|
||||
else:
|
||||
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
import argparse
|
||||
from config import CONFIG
|
||||
from parsers import CodexParser, GeminiParser, ClaudeParser, KiroParser
|
||||
from storage import ChatStorage
|
||||
from logger import setup_logger, get_logger
|
||||
|
||||
storage: ChatStorage = None
|
||||
|
||||
def main():
|
||||
global storage
|
||||
|
||||
parser = argparse.ArgumentParser(description='AI Chat Converter')
|
||||
parser.add_argument('-w', '--watch', action='store_true', help='持续监控模式')
|
||||
parser.add_argument('--prune', action='store_true', help='清理孤立记录')
|
||||
parser.add_argument('--stats', action='store_true', help='显示统计信息')
|
||||
parser.add_argument('--search', type=str, help='搜索关键词')
|
||||
parser.add_argument('--export', choices=['json', 'csv'], help='导出格式')
|
||||
parser.add_argument('--source', choices=['codex', 'kiro', 'gemini', 'claude'], help='指定来源')
|
||||
parser.add_argument('--output', type=str, help='导出文件路径')
|
||||
args = parser.parse_args()
|
||||
|
||||
# 初始化
|
||||
setup_logger(CONFIG["log_dir"])
|
||||
log = get_logger()
|
||||
|
||||
storage = ChatStorage(CONFIG["db_path"])
|
||||
|
||||
# 命令分发
|
||||
if args.prune:
|
||||
cmd_prune()
|
||||
elif args.stats:
|
||||
cmd_stats()
|
||||
elif args.search:
|
||||
cmd_search(args.search, args.source)
|
||||
elif args.export:
|
||||
cmd_export(args.export, args.source, args.output)
|
||||
elif args.watch:
|
||||
cmd_sync()
|
||||
cmd_watch()
|
||||
else:
|
||||
cmd_sync()
|
||||
|
||||
def cmd_sync():
|
||||
log = get_logger()
|
||||
log.info("=" * 50)
|
||||
log.info("AI 聊天记录 → 集中存储")
|
||||
log.info("=" * 50)
|
||||
log.info(f"数据库: {CONFIG['db_path']}")
|
||||
|
||||
total_added, total_updated, total_skipped, total_errors = 0, 0, 0, 0
|
||||
|
||||
for cli, key, parser_cls in [
|
||||
('codex', 'codex_paths', lambda: CodexParser('codex')),
|
||||
('kiro', 'kiro_paths', KiroParser),
|
||||
('gemini', 'gemini_paths', GeminiParser),
|
||||
('claude', 'claude_paths', ClaudeParser),
|
||||
]:
|
||||
paths = CONFIG.get(key, [])
|
||||
if not paths:
|
||||
continue
|
||||
|
||||
parser = parser_cls()
|
||||
if cli in ('claude', 'kiro'):
|
||||
a, u, s, e = process_multi(parser, paths, cli)
|
||||
else:
|
||||
a, u, s, e = process(parser, paths)
|
||||
|
||||
log.info(f"[{cli.capitalize()}] 新增:{a} 更新:{u} 跳过:{s} 错误:{e}")
|
||||
update_cli_meta(cli)
|
||||
total_added += a
|
||||
total_updated += u
|
||||
total_skipped += s
|
||||
total_errors += e
|
||||
|
||||
total = storage.get_total_stats()
|
||||
storage.update_total_meta(total['sessions'], total['messages'], total['tokens'])
|
||||
|
||||
log.info("=" * 50)
|
||||
log.info(f"总计: {total['sessions']} 会话, {total['messages']} 消息")
|
||||
if total_errors > 0:
|
||||
log.warning(f"错误: {total_errors} 个文件解析失败")
|
||||
log.info("✓ 同步完成!")
|
||||
|
||||
print_token_stats()
|
||||
|
||||
def cmd_watch():
|
||||
from watcher import ChatWatcher
|
||||
from datetime import datetime
|
||||
|
||||
log = get_logger()
|
||||
log.info("")
|
||||
log.info("=" * 50)
|
||||
log.info("实时监听模式 (watchdog)")
|
||||
log.info("=" * 50)
|
||||
|
||||
watch_paths = []
|
||||
path_source_map = {}
|
||||
|
||||
for cli, key in [('codex', 'codex_paths'), ('kiro', 'kiro_paths'),
|
||||
('gemini', 'gemini_paths'), ('claude', 'claude_paths')]:
|
||||
for p in CONFIG.get(key, []):
|
||||
if os.path.isdir(p) or os.path.isfile(p):
|
||||
watch_paths.append(p)
|
||||
path_source_map[p] = cli
|
||||
|
||||
def on_change(file_path, event_type):
|
||||
now = datetime.now().strftime('%H:%M:%S')
|
||||
source = None
|
||||
for p, s in path_source_map.items():
|
||||
if file_path.startswith(p) or file_path == p:
|
||||
source = s
|
||||
break
|
||||
if not source:
|
||||
return
|
||||
|
||||
try:
|
||||
if source == 'kiro':
|
||||
parser = KiroParser()
|
||||
for sess in parser.parse_file(file_path):
|
||||
storage.upsert_session(sess.session_id, sess.source, sess.file_path, sess.cwd, sess.messages, int(sess.file_mtime))
|
||||
log.info(f"[{now}] kiro 更新")
|
||||
elif source == 'claude':
|
||||
parser = ClaudeParser()
|
||||
for sess in parser.parse_file(file_path):
|
||||
fp = f"claude:{sess.session_id}"
|
||||
storage.upsert_session(sess.session_id, sess.source, fp, sess.cwd, sess.messages, int(sess.file_mtime))
|
||||
log.info(f"[{now}] claude 更新")
|
||||
else:
|
||||
parser = CodexParser(source) if source == 'codex' else GeminiParser()
|
||||
sess = parser.parse_file(file_path)
|
||||
fp = os.path.abspath(sess.file_path)
|
||||
storage.upsert_session(sess.session_id, sess.source, fp, sess.cwd, sess.messages, int(sess.file_mtime))
|
||||
log.info(f"[{now}] {source} {event_type}: {os.path.basename(file_path)}")
|
||||
|
||||
update_cli_meta(source)
|
||||
total = storage.get_total_stats()
|
||||
storage.update_total_meta(total['sessions'], total['messages'], total['tokens'])
|
||||
except Exception as e:
|
||||
log.error(f"[{now}] 处理失败 {file_path}: {e}")
|
||||
|
||||
log.info(f"监听目录: {len(watch_paths)} 个")
|
||||
watcher = ChatWatcher(watch_paths, on_change)
|
||||
watcher.start()
|
||||
|
||||
def cmd_prune():
|
||||
log = get_logger()
|
||||
log.info("清理孤立记录...")
|
||||
removed = storage.prune()
|
||||
total = sum(removed.values())
|
||||
if total > 0:
|
||||
for cli, count in removed.items():
|
||||
if count > 0:
|
||||
log.info(f" {cli}: 删除 {count} 条")
|
||||
log.info(f"✓ 共清理 {total} 条孤立记录")
|
||||
else:
|
||||
log.info("✓ 无孤立记录")
|
||||
|
||||
def cmd_stats():
|
||||
log = get_logger()
|
||||
meta = storage.get_total_meta()
|
||||
tokens = storage.get_token_stats()
|
||||
|
||||
log.info("=" * 50)
|
||||
log.info("统计信息")
|
||||
log.info("=" * 50)
|
||||
log.info(f"数据库: {CONFIG['db_path']}")
|
||||
log.info(f"总会话: {meta['total_sessions']}")
|
||||
log.info(f"总消息: {meta['total_messages']}")
|
||||
log.info(f"最后同步: {meta['last_sync']}")
|
||||
log.info("")
|
||||
log.info("Token 统计 (tiktoken):")
|
||||
total_tokens = 0
|
||||
for source in ['codex', 'kiro', 'gemini', 'claude']:
|
||||
t = tokens.get(source, 0)
|
||||
if t > 0:
|
||||
log.info(f" {source}: {t:,}")
|
||||
total_tokens += t
|
||||
log.info(f" 总计: {total_tokens:,}")
|
||||
|
||||
def cmd_search(keyword: str, source: str = None):
|
||||
log = get_logger()
|
||||
results = storage.search(keyword, source)
|
||||
log.info(f"搜索 '{keyword}' 找到 {len(results)} 个会话:")
|
||||
for r in results[:20]:
|
||||
log.info(f" [{r['source']}] {r['session_id']} - {r['cwd'] or 'N/A'}")
|
||||
|
||||
def cmd_export(fmt: str, source: str = None, output: str = None):
|
||||
log = get_logger()
|
||||
if not output:
|
||||
output = os.path.join(CONFIG["output_dir"], f"export.{fmt}")
|
||||
|
||||
if fmt == 'json':
|
||||
count = storage.export_json(output, source)
|
||||
else:
|
||||
count = storage.export_csv(output, source)
|
||||
|
||||
log.info(f"✓ 导出 {count} 条到 {output}")
|
||||
|
||||
def print_token_stats():
|
||||
log = get_logger()
|
||||
tokens = storage.get_token_stats()
|
||||
log.info("")
|
||||
log.info("=== Token 统计 (tiktoken) ===")
|
||||
total = 0
|
||||
for source in ['codex', 'kiro', 'gemini', 'claude']:
|
||||
t = tokens.get(source, 0)
|
||||
if t > 0:
|
||||
log.info(f" {source}: {t:,} tokens")
|
||||
total += t
|
||||
log.info(f" 总计: {total:,} tokens")
|
||||
|
||||
def update_cli_meta(cli: str):
|
||||
stats = storage.get_cli_stats(cli)
|
||||
path = CONFIG.get(f"{cli}_paths", [""])[0] if CONFIG.get(f"{cli}_paths") else ""
|
||||
storage.update_cli_meta(cli, path, stats['sessions'], stats['messages'], stats['tokens'])
|
||||
|
||||
def process(parser, paths) -> tuple:
|
||||
log = get_logger()
|
||||
added, updated, skipped, errors = 0, 0, 0, 0
|
||||
for f in parser.find_files(paths):
|
||||
try:
|
||||
s = parser.parse_file(f)
|
||||
file_path = os.path.abspath(s.file_path)
|
||||
db_mtime = storage.get_file_mtime(file_path)
|
||||
file_mtime = int(s.file_mtime)
|
||||
if db_mtime == 0:
|
||||
storage.upsert_session(s.session_id, s.source, file_path, s.cwd, s.messages, file_mtime)
|
||||
added += 1
|
||||
elif file_mtime > db_mtime:
|
||||
storage.upsert_session(s.session_id, s.source, file_path, s.cwd, s.messages, file_mtime)
|
||||
updated += 1
|
||||
else:
|
||||
skipped += 1
|
||||
except Exception as e:
|
||||
log.debug(f"解析失败 {f}: {e}")
|
||||
errors += 1
|
||||
return added, updated, skipped, errors
|
||||
|
||||
def process_multi(parser, paths, source: str) -> tuple:
|
||||
"""处理返回多个会话的解析器(Claude/Kiro)"""
|
||||
log = get_logger()
|
||||
added, updated, skipped, errors = 0, 0, 0, 0
|
||||
for f in parser.find_files(paths):
|
||||
try:
|
||||
for s in parser.parse_file(f):
|
||||
file_path = s.file_path # kiro:xxx 或 claude:xxx
|
||||
db_mtime = storage.get_file_mtime(file_path)
|
||||
file_mtime = int(s.file_mtime)
|
||||
if db_mtime == 0:
|
||||
storage.upsert_session(s.session_id, s.source, file_path, s.cwd, s.messages, file_mtime)
|
||||
added += 1
|
||||
elif file_mtime > db_mtime:
|
||||
storage.upsert_session(s.session_id, s.source, file_path, s.cwd, s.messages, file_mtime)
|
||||
updated += 1
|
||||
else:
|
||||
skipped += 1
|
||||
except Exception as e:
|
||||
log.debug(f"解析失败 {f}: {e}")
|
||||
errors += 1
|
||||
return added, updated, skipped, errors
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
from .codex import CodexParser
|
||||
from .gemini import GeminiParser
|
||||
from .claude import ClaudeParser
|
||||
from .kiro import KiroParser
|
||||
from .base import SessionData
|
||||
|
||||
__all__ = ["CodexParser", "GeminiParser", "ClaudeParser", "KiroParser", "SessionData"]
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
from abc import ABC, abstractmethod
|
||||
from dataclasses import dataclass, field
|
||||
from typing import List, Dict
|
||||
|
||||
@dataclass
|
||||
class SessionData:
|
||||
"""会话数据"""
|
||||
session_id: str
|
||||
source: str
|
||||
file_path: str
|
||||
file_mtime: float = 0
|
||||
cwd: str = None
|
||||
messages: List[Dict] = field(default_factory=list) # [{"time", "role", "content"}]
|
||||
|
||||
class BaseParser(ABC):
|
||||
@abstractmethod
|
||||
def find_files(self, paths: list) -> list:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def parse_file(self, filepath: str) -> SessionData:
|
||||
pass
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
import json
|
||||
import hashlib
|
||||
from datetime import datetime
|
||||
from collections import defaultdict
|
||||
from .base import BaseParser, SessionData
|
||||
|
||||
class ClaudeParser(BaseParser):
|
||||
def find_files(self, paths: list) -> list:
|
||||
files = []
|
||||
for base in paths:
|
||||
history = os.path.join(base, "history.jsonl")
|
||||
if os.path.exists(history):
|
||||
files.append(history)
|
||||
return files
|
||||
|
||||
def parse_file(self, filepath: str) -> list:
|
||||
"""返回多个 SessionData(按 project 分组)"""
|
||||
projects = defaultdict(list)
|
||||
file_mtime = os.path.getmtime(filepath)
|
||||
|
||||
with open(filepath, 'r', encoding='utf-8') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
data = json.loads(line)
|
||||
content = data.get('display', '')
|
||||
if not content:
|
||||
continue
|
||||
|
||||
project = data.get('project', 'unknown')
|
||||
ts_ms = data.get('timestamp', 0)
|
||||
ts = datetime.fromtimestamp(ts_ms / 1000).isoformat() if ts_ms else ''
|
||||
|
||||
projects[project].append({
|
||||
'time': ts,
|
||||
'role': 'user',
|
||||
'content': content
|
||||
})
|
||||
|
||||
return [
|
||||
SessionData(
|
||||
session_id='claude-' + hashlib.md5(proj.encode()).hexdigest()[:12],
|
||||
source='claude',
|
||||
file_path=filepath,
|
||||
file_mtime=file_mtime,
|
||||
cwd=proj,
|
||||
messages=msgs
|
||||
)
|
||||
for proj, msgs in projects.items()
|
||||
]
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
import json
|
||||
import re
|
||||
from .base import BaseParser, SessionData
|
||||
|
||||
class CodexParser(BaseParser):
|
||||
def __init__(self, source: str = 'codex'):
|
||||
self.source = source
|
||||
|
||||
def find_files(self, paths: list) -> list:
|
||||
files = []
|
||||
for base in paths:
|
||||
if not os.path.exists(base):
|
||||
continue
|
||||
for root, _, names in os.walk(base):
|
||||
for f in names:
|
||||
if f.endswith('.jsonl') and f != 'history.jsonl':
|
||||
files.append(os.path.join(root, f))
|
||||
return files
|
||||
|
||||
def _extract_id(self, filepath: str) -> str:
|
||||
match = re.search(r'([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})',
|
||||
os.path.basename(filepath))
|
||||
return match.group(1) if match else os.path.basename(filepath).replace('.jsonl', '')
|
||||
|
||||
def parse_file(self, filepath: str) -> SessionData:
|
||||
s = SessionData(
|
||||
session_id=self._extract_id(filepath),
|
||||
source=self.source,
|
||||
file_path=filepath,
|
||||
file_mtime=os.path.getmtime(filepath)
|
||||
)
|
||||
|
||||
with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line or line[0] != '{':
|
||||
continue
|
||||
try:
|
||||
data = json.loads(line)
|
||||
except json.JSONDecodeError:
|
||||
continue
|
||||
|
||||
if data.get('type') == 'session_meta':
|
||||
p = data.get('payload', {})
|
||||
s.cwd = p.get('cwd')
|
||||
s.session_id = p.get('id', s.session_id)
|
||||
continue
|
||||
|
||||
if data.get('type') != 'response_item':
|
||||
continue
|
||||
payload = data.get('payload', {})
|
||||
if payload.get('type') != 'message':
|
||||
continue
|
||||
role = payload.get('role')
|
||||
if role not in ('user', 'assistant'):
|
||||
continue
|
||||
|
||||
parts = [item.get('text', '') for item in payload.get('content', [])
|
||||
if isinstance(item, dict) and item.get('type') in ('input_text', 'output_text', 'text')]
|
||||
if parts:
|
||||
s.messages.append({
|
||||
'time': data.get('timestamp', ''),
|
||||
'role': 'user' if role == 'user' else 'ai',
|
||||
'content': ' '.join(parts)
|
||||
})
|
||||
|
||||
return s
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
import glob
|
||||
import json
|
||||
from .base import BaseParser, SessionData
|
||||
|
||||
class GeminiParser(BaseParser):
|
||||
def find_files(self, paths: list) -> list:
|
||||
files = []
|
||||
for base in paths:
|
||||
if os.path.exists(base):
|
||||
files.extend(glob.glob(os.path.join(base, "*", "chats", "*.json")))
|
||||
return files
|
||||
|
||||
def parse_file(self, filepath: str) -> SessionData:
|
||||
s = SessionData(
|
||||
session_id=os.path.basename(filepath).replace('.json', ''),
|
||||
source='gemini',
|
||||
file_path=filepath,
|
||||
file_mtime=os.path.getmtime(filepath)
|
||||
)
|
||||
|
||||
with open(filepath, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
|
||||
s.session_id = data.get('sessionId', s.session_id)
|
||||
|
||||
for msg in data.get('messages', []):
|
||||
if msg.get('type') not in ('user', 'gemini'):
|
||||
continue
|
||||
content = msg.get('content', '')
|
||||
if content:
|
||||
s.messages.append({
|
||||
'time': msg.get('timestamp', ''),
|
||||
'role': 'user' if msg.get('type') == 'user' else 'ai',
|
||||
'content': content
|
||||
})
|
||||
|
||||
return s
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Kiro CLI 解析器 - 从 SQLite 数据库读取"""
|
||||
import os
|
||||
import json
|
||||
import sqlite3
|
||||
import hashlib
|
||||
from datetime import datetime
|
||||
from .base import BaseParser, SessionData
|
||||
|
||||
KIRO_DB = os.path.expanduser("~/.local/share/kiro-cli/data.sqlite3")
|
||||
|
||||
class KiroParser(BaseParser):
|
||||
def find_files(self, paths: list) -> list:
|
||||
"""返回数据库路径(如果存在)"""
|
||||
if os.path.exists(KIRO_DB):
|
||||
return [KIRO_DB]
|
||||
return []
|
||||
|
||||
def parse_file(self, filepath: str) -> list:
|
||||
"""解析 Kiro SQLite 数据库,返回多个 SessionData"""
|
||||
sessions = []
|
||||
file_mtime = os.path.getmtime(filepath)
|
||||
|
||||
conn = sqlite3.connect(filepath)
|
||||
for row in conn.execute('SELECT key, value FROM conversations'):
|
||||
cwd, value = row
|
||||
try:
|
||||
data = json.loads(value)
|
||||
except json.JSONDecodeError:
|
||||
continue
|
||||
|
||||
conv_id = data.get('conversation_id', hashlib.md5(cwd.encode()).hexdigest()[:12])
|
||||
history = data.get('history', [])
|
||||
|
||||
messages = []
|
||||
for item in history:
|
||||
# 用户消息
|
||||
if 'user' in item:
|
||||
user = item['user']
|
||||
content = user.get('content', {})
|
||||
if isinstance(content, dict) and 'Prompt' in content:
|
||||
prompt = content['Prompt'].get('prompt', '')
|
||||
if prompt:
|
||||
messages.append({
|
||||
'time': '',
|
||||
'role': 'user',
|
||||
'content': prompt
|
||||
})
|
||||
|
||||
# AI 回复
|
||||
if 'assistant' in item:
|
||||
assistant = item['assistant']
|
||||
content = assistant.get('content', {})
|
||||
if isinstance(content, dict) and 'Message' in content:
|
||||
msg = content['Message'].get('message', '')
|
||||
if msg:
|
||||
messages.append({
|
||||
'time': '',
|
||||
'role': 'ai',
|
||||
'content': msg
|
||||
})
|
||||
|
||||
if messages:
|
||||
sessions.append(SessionData(
|
||||
session_id=f'kiro-{conv_id[:12]}',
|
||||
source='kiro',
|
||||
file_path=f'kiro:{conv_id}',
|
||||
file_mtime=file_mtime,
|
||||
cwd=cwd,
|
||||
messages=messages
|
||||
))
|
||||
|
||||
conn.close()
|
||||
return sessions
|
||||
|
|
@ -1,246 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""SQLite 存储模块 - 完整版"""
|
||||
import sqlite3
|
||||
import json
|
||||
import os
|
||||
import datetime
|
||||
import tiktoken
|
||||
|
||||
SCHEMA_VERSION = 5
|
||||
CLIS = ('codex', 'kiro', 'gemini', 'claude')
|
||||
|
||||
_encoder = tiktoken.get_encoding("cl100k_base")
|
||||
|
||||
def count_tokens(text: str) -> int:
|
||||
return len(_encoder.encode(text)) if text else 0
|
||||
|
||||
class ChatStorage:
|
||||
def __init__(self, db_path: str):
|
||||
self.db_path = db_path
|
||||
os.makedirs(os.path.dirname(db_path) or '.', exist_ok=True)
|
||||
self._init_db()
|
||||
|
||||
def _conn(self):
|
||||
return sqlite3.connect(self.db_path)
|
||||
|
||||
def _init_db(self):
|
||||
with self._conn() as conn:
|
||||
conn.execute('''CREATE TABLE IF NOT EXISTS meta (key TEXT PRIMARY KEY, value TEXT)''')
|
||||
for cli in CLIS:
|
||||
conn.execute(f'''CREATE TABLE IF NOT EXISTS meta_{cli} (key TEXT PRIMARY KEY, value TEXT)''')
|
||||
conn.execute('''
|
||||
CREATE TABLE IF NOT EXISTS sessions (
|
||||
file_path TEXT PRIMARY KEY,
|
||||
session_id TEXT,
|
||||
source TEXT NOT NULL,
|
||||
cwd TEXT,
|
||||
messages TEXT,
|
||||
file_mtime INTEGER,
|
||||
start_time TEXT,
|
||||
token_count INTEGER DEFAULT 0
|
||||
)
|
||||
''')
|
||||
conn.execute('CREATE INDEX IF NOT EXISTS idx_source ON sessions(source)')
|
||||
conn.execute('CREATE INDEX IF NOT EXISTS idx_session_id ON sessions(session_id)')
|
||||
conn.execute('CREATE INDEX IF NOT EXISTS idx_start_time ON sessions(start_time)')
|
||||
self._set_meta('meta', 'schema_version', str(SCHEMA_VERSION))
|
||||
|
||||
def _set_meta(self, table: str, key: str, value: str):
|
||||
with self._conn() as conn:
|
||||
conn.execute(f'INSERT OR REPLACE INTO {table} (key, value) VALUES (?, ?)', (key, value))
|
||||
|
||||
def _get_meta(self, table: str, key: str) -> str:
|
||||
with self._conn() as conn:
|
||||
row = conn.execute(f'SELECT value FROM {table} WHERE key = ?', (key,)).fetchone()
|
||||
return row[0] if row else None
|
||||
|
||||
def update_cli_meta(self, cli: str, path: str, sessions: int, messages: int, tokens: int = None):
|
||||
table = f'meta_{cli}'
|
||||
now = datetime.datetime.now().isoformat()
|
||||
# 顺序: path, sessions, messages, total_tokens, last_sync
|
||||
self._set_meta(table, 'path', path)
|
||||
self._set_meta(table, 'sessions', str(sessions))
|
||||
self._set_meta(table, 'messages', str(messages))
|
||||
self._set_meta(table, 'total_tokens', str(tokens or 0))
|
||||
self._set_meta(table, 'last_sync', now)
|
||||
|
||||
def update_total_meta(self, sessions: int, messages: int, tokens: int = None):
|
||||
now = datetime.datetime.now().isoformat()
|
||||
self._set_meta('meta', 'total_sessions', str(sessions))
|
||||
self._set_meta('meta', 'total_messages', str(messages))
|
||||
if tokens is not None:
|
||||
self._set_meta('meta', 'total_tokens', str(tokens))
|
||||
self._set_meta('meta', 'last_sync', now)
|
||||
|
||||
def get_total_meta(self) -> dict:
|
||||
return {
|
||||
'schema_version': int(self._get_meta('meta', 'schema_version') or 0),
|
||||
'total_sessions': int(self._get_meta('meta', 'total_sessions') or 0),
|
||||
'total_messages': int(self._get_meta('meta', 'total_messages') or 0),
|
||||
'last_sync': self._get_meta('meta', 'last_sync'),
|
||||
}
|
||||
|
||||
def get_file_mtime(self, file_path: str) -> int:
|
||||
with self._conn() as conn:
|
||||
row = conn.execute('SELECT file_mtime FROM sessions WHERE file_path = ?', (file_path,)).fetchone()
|
||||
return row[0] if row else 0
|
||||
|
||||
def upsert_session(self, session_id: str, source: str, file_path: str,
|
||||
cwd: str, messages: list, file_mtime: int, start_time: str = None):
|
||||
if file_path and not file_path.startswith('claude:') and not os.path.isabs(file_path):
|
||||
file_path = os.path.abspath(file_path)
|
||||
|
||||
total_tokens = sum(count_tokens(msg.get('content', '')) for msg in messages)
|
||||
if not start_time and messages:
|
||||
start_time = messages[0].get('time')
|
||||
|
||||
messages_json = json.dumps(messages, ensure_ascii=False)
|
||||
with self._conn() as conn:
|
||||
conn.execute('''
|
||||
INSERT INTO sessions (file_path, session_id, source, cwd, messages, file_mtime, start_time, token_count)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT(file_path) DO UPDATE SET
|
||||
session_id=excluded.session_id, messages=excluded.messages,
|
||||
file_mtime=excluded.file_mtime, start_time=excluded.start_time, token_count=excluded.token_count
|
||||
''', (file_path, session_id, source, cwd, messages_json, file_mtime, start_time, total_tokens))
|
||||
|
||||
def get_cli_stats(self, cli: str) -> dict:
|
||||
with self._conn() as conn:
|
||||
sessions = conn.execute('SELECT COUNT(*) FROM sessions WHERE source = ?', (cli,)).fetchone()[0]
|
||||
row = conn.execute('SELECT SUM(json_array_length(messages)) FROM sessions WHERE source = ?', (cli,)).fetchone()
|
||||
messages = row[0] or 0
|
||||
tokens = conn.execute('SELECT SUM(token_count) FROM sessions WHERE source = ?', (cli,)).fetchone()[0] or 0
|
||||
return {'sessions': sessions, 'messages': messages, 'tokens': tokens}
|
||||
|
||||
def get_total_stats(self) -> dict:
|
||||
with self._conn() as conn:
|
||||
sessions = conn.execute('SELECT COUNT(*) FROM sessions').fetchone()[0]
|
||||
row = conn.execute('SELECT SUM(json_array_length(messages)) FROM sessions').fetchone()
|
||||
messages = row[0] or 0
|
||||
tokens = conn.execute('SELECT SUM(token_count) FROM sessions').fetchone()[0] or 0
|
||||
return {'sessions': sessions, 'messages': messages, 'tokens': tokens}
|
||||
|
||||
def get_token_stats(self) -> dict:
|
||||
with self._conn() as conn:
|
||||
rows = conn.execute('SELECT source, SUM(token_count) FROM sessions GROUP BY source').fetchall()
|
||||
return {r[0]: r[1] or 0 for r in rows}
|
||||
|
||||
# === 清理孤立记录 ===
|
||||
def prune(self) -> dict:
|
||||
"""删除源文件已不存在的记录"""
|
||||
removed = {'codex': 0, 'kiro': 0, 'gemini': 0, 'claude': 0}
|
||||
with self._conn() as conn:
|
||||
rows = conn.execute('SELECT file_path, source FROM sessions').fetchall()
|
||||
for fp, source in rows:
|
||||
if fp.startswith('claude:'):
|
||||
continue # Claude 使用虚拟路径
|
||||
if not os.path.exists(fp):
|
||||
conn.execute('DELETE FROM sessions WHERE file_path = ?', (fp,))
|
||||
removed[source] = removed.get(source, 0) + 1
|
||||
return removed
|
||||
|
||||
# === 查询 ===
|
||||
def search(self, keyword: str, source: str = None, limit: int = 50) -> list:
|
||||
"""搜索消息内容"""
|
||||
sql = "SELECT file_path, session_id, source, cwd, messages, start_time FROM sessions WHERE messages LIKE ?"
|
||||
params = [f'%{keyword}%']
|
||||
if source:
|
||||
sql += " AND source = ?"
|
||||
params.append(source)
|
||||
sql += f" ORDER BY start_time DESC LIMIT {limit}"
|
||||
|
||||
results = []
|
||||
with self._conn() as conn:
|
||||
for row in conn.execute(sql, params):
|
||||
results.append({
|
||||
'file_path': row[0], 'session_id': row[1], 'source': row[2],
|
||||
'cwd': row[3], 'messages': json.loads(row[4]), 'start_time': row[5]
|
||||
})
|
||||
return results
|
||||
|
||||
def get_session(self, file_path: str) -> dict:
|
||||
"""获取单个会话"""
|
||||
with self._conn() as conn:
|
||||
row = conn.execute(
|
||||
'SELECT file_path, session_id, source, cwd, messages, start_time, token_count FROM sessions WHERE file_path = ?',
|
||||
(file_path,)
|
||||
).fetchone()
|
||||
if not row:
|
||||
return None
|
||||
return {
|
||||
'file_path': row[0], 'session_id': row[1], 'source': row[2], 'cwd': row[3],
|
||||
'messages': json.loads(row[4]), 'start_time': row[5], 'token_count': row[6]
|
||||
}
|
||||
|
||||
def list_sessions(self, source: str = None, limit: int = 100, offset: int = 0) -> list:
|
||||
"""列出会话"""
|
||||
sql = "SELECT file_path, session_id, source, cwd, start_time, token_count FROM sessions"
|
||||
params = []
|
||||
if source:
|
||||
sql += " WHERE source = ?"
|
||||
params.append(source)
|
||||
sql += f" ORDER BY start_time DESC LIMIT {limit} OFFSET {offset}"
|
||||
|
||||
results = []
|
||||
with self._conn() as conn:
|
||||
for row in conn.execute(sql, params):
|
||||
results.append({
|
||||
'file_path': row[0], 'session_id': row[1], 'source': row[2],
|
||||
'cwd': row[3], 'start_time': row[4], 'token_count': row[5]
|
||||
})
|
||||
return results
|
||||
|
||||
# === 导出 ===
|
||||
def export_json(self, output_path: str, source: str = None):
|
||||
"""导出为 JSON"""
|
||||
sql = "SELECT file_path, session_id, source, cwd, messages, start_time, token_count FROM sessions"
|
||||
params = []
|
||||
if source:
|
||||
sql += " WHERE source = ?"
|
||||
params.append(source)
|
||||
sql += " ORDER BY start_time"
|
||||
|
||||
data = []
|
||||
with self._conn() as conn:
|
||||
for row in conn.execute(sql, params):
|
||||
data.append({
|
||||
'file_path': row[0], 'session_id': row[1], 'source': row[2], 'cwd': row[3],
|
||||
'messages': json.loads(row[4]), 'start_time': row[5], 'token_count': row[6]
|
||||
})
|
||||
|
||||
with open(output_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(data, f, ensure_ascii=False, indent=2)
|
||||
return len(data)
|
||||
|
||||
def export_csv(self, output_path: str, source: str = None):
|
||||
"""导出为 CSV(扁平化消息)"""
|
||||
import csv
|
||||
sql = "SELECT session_id, source, cwd, messages, start_time FROM sessions"
|
||||
params = []
|
||||
if source:
|
||||
sql += " WHERE source = ?"
|
||||
params.append(source)
|
||||
sql += " ORDER BY start_time"
|
||||
|
||||
count = 0
|
||||
with open(output_path, 'w', encoding='utf-8', newline='') as f:
|
||||
writer = csv.writer(f)
|
||||
writer.writerow(['session_id', 'source', 'cwd', 'time', 'role', 'content'])
|
||||
with self._conn() as conn:
|
||||
for row in conn.execute(sql, params):
|
||||
session_id, src, cwd, msgs_json, _ = row
|
||||
for msg in json.loads(msgs_json):
|
||||
writer.writerow([session_id, src, cwd, msg.get('time', ''), msg.get('role', ''), msg.get('content', '')])
|
||||
count += 1
|
||||
return count
|
||||
|
||||
# === 获取所有文件路径(用于 prune 检查) ===
|
||||
def get_all_file_paths(self, source: str = None) -> set:
|
||||
sql = "SELECT file_path FROM sessions"
|
||||
params = []
|
||||
if source:
|
||||
sql += " WHERE source = ?"
|
||||
params.append(source)
|
||||
with self._conn() as conn:
|
||||
return {row[0] for row in conn.execute(sql, params)}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""跨平台文件监控 (Linux/macOS/Windows)"""
|
||||
|
||||
from watchdog.observers import Observer
|
||||
from watchdog.events import FileSystemEventHandler
|
||||
import time
|
||||
|
||||
class ChatFileHandler(FileSystemEventHandler):
|
||||
def __init__(self, callback, extensions):
|
||||
self.callback = callback
|
||||
self.extensions = extensions
|
||||
|
||||
def _check(self, event):
|
||||
if event.is_directory:
|
||||
return
|
||||
path = event.src_path
|
||||
if any(path.endswith(ext) for ext in self.extensions):
|
||||
self.callback(path, event.event_type)
|
||||
|
||||
def on_created(self, event):
|
||||
self._check(event)
|
||||
|
||||
def on_modified(self, event):
|
||||
self._check(event)
|
||||
|
||||
class ChatWatcher:
|
||||
def __init__(self, paths: list, callback, extensions=('.jsonl', '.json')):
|
||||
self.observer = Observer()
|
||||
handler = ChatFileHandler(callback, extensions)
|
||||
for path in paths:
|
||||
self.observer.schedule(handler, path, recursive=True)
|
||||
|
||||
def start(self):
|
||||
self.observer.start()
|
||||
try:
|
||||
while True:
|
||||
time.sleep(1)
|
||||
except KeyboardInterrupt:
|
||||
self.stop()
|
||||
|
||||
def stop(self):
|
||||
self.observer.stop()
|
||||
self.observer.join()
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
@echo off
|
||||
cd /d "%~dp0src"
|
||||
echo 正在启动 AI Chat Converter...
|
||||
echo 按 Ctrl+C 停止
|
||||
echo.
|
||||
python main.py --watch
|
||||
pause
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
#!/bin/bash
|
||||
# AI Chat Converter - 一键启动
|
||||
cd "$(dirname "$0")/src"
|
||||
echo "正在启动 AI Chat Converter..."
|
||||
echo "按 Ctrl+C 停止"
|
||||
echo ""
|
||||
python3 main.py --watch
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
# l10n-tool
|
||||
|
||||
轻量级多语言翻译脚本,定位:先用机器翻译批量落地,再由 AI/人工逐行润色。
|
||||
|
||||
## 特性
|
||||
- 保护 Markdown 代码块,不误翻译代码
|
||||
- 命令行一条跑完,便于批处理
|
||||
- 依赖轻:`deep-translator`(封装 Google 翻译)
|
||||
|
||||
## 安装
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
## 使用示例
|
||||
```bash
|
||||
# 将中文 README 翻译到英文
|
||||
python translate.py --input ../../i18n/zh/README.md --output ../../i18n/en/README.md --src-lang zh --tgt-lang en --overwrite
|
||||
|
||||
# 批量翻译 prompts,可在外部脚本中循环调用
|
||||
```
|
||||
|
||||
## 建议流程(快 ⇒ 精)
|
||||
1) 机器翻译初稿:用本工具覆盖生成各语言版本。
|
||||
2) AI 校润:对关键文档/提示词逐行复核,重点检查术语一致性与人称语气。
|
||||
3) 人工抽检:挑核心页面人工对比源文,修正 AI 可能的误译。
|
||||
|
||||
## 语言代码参考
|
||||
- 常用:zh, en, es, fr, de, ru, pt, ar, hi, ja, ko, he, it, tr, nl, pl, id, vi, th, fa, uk, bn, ta, ur, ms, sw, ha
|
||||
- 更多代码可查 ISO 639-1。
|
||||
|
||||
## 注意
|
||||
- 若需更高质量,可替换为官方 Google Cloud Translate / DeepL API,只需改写 `translate_blocks` 中的 translator 初始化逻辑。
|
||||
- 如遇免费翻译频率限制,可分批或加重试/代理配置。
|
||||
|
|
@ -1,140 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
批量翻译 i18n/zh 下的所有文本文件到其他语言目录。
|
||||
- 保持目录结构,遇到代码块自动跳过翻译。
|
||||
- 目标语言集合:自动读取 i18n 下的子目录,排除 zh。
|
||||
用法:
|
||||
python bulk_translate.py --src-root ../../i18n/zh --dst-root ../../i18n --src-lang zh
|
||||
可选:
|
||||
--langs en es ... # 指定目标语言;默认自动扫描
|
||||
--overwrite # 允许覆盖已有文件
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Iterable, List
|
||||
|
||||
try:
|
||||
from deep_translator import GoogleTranslator
|
||||
except ImportError:
|
||||
sys.stderr.write("[错误] 缺少 deep-translator,请先 pip install -r requirements.txt\n")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def translate_blocks(text: str, translator: GoogleTranslator) -> str:
|
||||
lines = text.splitlines()
|
||||
translated: List[str] = []
|
||||
in_code = False
|
||||
buffer: List[str] = []
|
||||
|
||||
def flush_buffer():
|
||||
if not buffer:
|
||||
return
|
||||
chunk = "\n".join(buffer)
|
||||
try:
|
||||
result = translator.translate(chunk)
|
||||
if result is None:
|
||||
raise RuntimeError("翻译返回空结果")
|
||||
translated.extend(result.split("\n"))
|
||||
except Exception:
|
||||
# 兜底:按行逐条翻译,避免整段失败
|
||||
for line in buffer:
|
||||
try:
|
||||
res_line = translator.translate(line) or line
|
||||
except Exception:
|
||||
res_line = line # 保留原文,留待人工校对
|
||||
translated.append(res_line)
|
||||
buffer.clear()
|
||||
|
||||
for line in lines:
|
||||
if line.strip().startswith("```"):
|
||||
flush_buffer()
|
||||
in_code = not in_code
|
||||
translated.append(line)
|
||||
continue
|
||||
if in_code:
|
||||
translated.append(line)
|
||||
continue
|
||||
if not line.strip():
|
||||
flush_buffer()
|
||||
translated.append(line)
|
||||
continue
|
||||
buffer.append(line)
|
||||
flush_buffer()
|
||||
return "\n".join(translated)
|
||||
|
||||
|
||||
def iter_source_files(src_root: Path) -> Iterable[Path]:
|
||||
for path in src_root.rglob('*'):
|
||||
if path.is_file():
|
||||
yield path
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description="批量翻译 i18n/zh -> 其他语言")
|
||||
parser.add_argument('--src-root', default='../../i18n/zh', help='源语言根目录')
|
||||
parser.add_argument('--dst-root', default='../../i18n', help='目标语言根目录集合')
|
||||
parser.add_argument('--src-lang', default='zh-CN', help='源语言代码')
|
||||
parser.add_argument('--langs', nargs='*', help='指定目标语言,不含源语言')
|
||||
parser.add_argument('--overwrite', action='store_true', help='允许覆盖已有文件')
|
||||
args = parser.parse_args()
|
||||
|
||||
src_root = Path(args.src_root).resolve()
|
||||
dst_root = Path(args.dst_root).resolve()
|
||||
|
||||
if not src_root.exists():
|
||||
sys.stderr.write(f"[错误] 源目录不存在: {src_root}\n")
|
||||
return 1
|
||||
|
||||
code_overrides = {
|
||||
'zh': 'zh-CN',
|
||||
'zh-CN': 'zh-CN',
|
||||
'he': 'iw', # Google 使用旧代码
|
||||
}
|
||||
|
||||
def map_code(lang: str) -> str:
|
||||
return code_overrides.get(lang, lang)
|
||||
|
||||
if args.langs:
|
||||
target_langs = [lang for lang in args.langs if map_code(lang) != args.src_lang]
|
||||
else:
|
||||
target_langs = [p.name for p in dst_root.iterdir() if p.is_dir() and map_code(p.name) != args.src_lang]
|
||||
|
||||
if not target_langs:
|
||||
sys.stderr.write("[错误] 无目标语言目录\n")
|
||||
return 1
|
||||
|
||||
for lang in target_langs:
|
||||
translator = GoogleTranslator(source=args.src_lang, target=map_code(lang))
|
||||
print(f"==== 开始翻译 -> {lang} ====")
|
||||
for src_file in iter_source_files(src_root):
|
||||
rel_path = src_file.relative_to(src_root)
|
||||
dst_file = dst_root / lang / rel_path
|
||||
dst_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
if dst_file.exists() and not args.overwrite:
|
||||
print(f"跳过已存在 {dst_file}")
|
||||
continue
|
||||
|
||||
with open(src_file, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
try:
|
||||
translated = translate_blocks(content, translator)
|
||||
except Exception as exc:
|
||||
print(f"[失败] {src_file} -> {dst_file}: {exc}")
|
||||
continue
|
||||
|
||||
with open(dst_file, 'w', encoding='utf-8') as f:
|
||||
f.write(translated + '\n')
|
||||
print(f"[OK] {src_file} -> {dst_file}")
|
||||
|
||||
print("全部翻译完成")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
|
|
@ -1,195 +0,0 @@
|
|||
[
|
||||
"i18n/zh/documents/Templates and Resources/代码组织.md",
|
||||
"i18n/zh/documents/Templates and Resources/编程书籍推荐.md",
|
||||
"i18n/zh/documents/Templates and Resources/通用项目架构模板.md",
|
||||
"i18n/zh/documents/Templates and Resources/工具集.md",
|
||||
"i18n/zh/documents/README.md",
|
||||
"i18n/zh/documents/Tutorials and Guides/telegram-dev/telegram Markdown 代码块格式修复记录 2025-12-15.md",
|
||||
"i18n/zh/documents/Tutorials and Guides/tmux快捷键大全.md",
|
||||
"i18n/zh/documents/Tutorials and Guides/关于手机ssh任意位置链接本地计算机,基于frp实现的方法.md",
|
||||
"i18n/zh/documents/Tutorials and Guides/LazyVim快捷键大全.md",
|
||||
"i18n/zh/documents/Tutorials and Guides/auggie-mcp配置文档.md",
|
||||
"i18n/zh/documents/Methodology and Principles/系统提示词构建原则.md",
|
||||
"i18n/zh/documents/Methodology and Principles/gluecoding.md",
|
||||
"i18n/zh/documents/Methodology and Principles/胶水编程.md",
|
||||
"i18n/zh/documents/Methodology and Principles/vibe-coding-经验收集.md",
|
||||
"i18n/zh/documents/Methodology and Principles/开发经验.md",
|
||||
"i18n/zh/documents/Methodology and Principles/学习经验.md",
|
||||
"i18n/zh/documents/Methodology and Principles/A Formalization of Recursive Self-Optimizing Generative Systems.md",
|
||||
"i18n/zh/documents/Methodology and Principles/编程之道.md",
|
||||
"i18n/zh/prompts/README.md",
|
||||
"i18n/zh/prompts/coding_prompts/(3,1)_#_流程标准化.md",
|
||||
"i18n/zh/prompts/coding_prompts/客观分析.md",
|
||||
"i18n/zh/prompts/coding_prompts/精华技术文档生成提示词.md",
|
||||
"i18n/zh/prompts/coding_prompts/智能需求理解与研发导航引擎.md",
|
||||
"i18n/zh/prompts/coding_prompts/(21,1)_你是我的顶级编程助手,我将使用自然语言描述开发需求。请你将其转换为一个结构化、专业、详细、可执行的编程任务说明文档,输出.md",
|
||||
"i18n/zh/prompts/coding_prompts/(17,2)_#_软件工程分析.md",
|
||||
"i18n/zh/prompts/coding_prompts/(22,5)_前几天,我被_Claude_那些臃肿、过度设计的解决方案搞得很沮丧,里面有一大堆我不需要的“万一”功能。然后我尝试在我的.md",
|
||||
"i18n/zh/prompts/coding_prompts/分析2.md",
|
||||
"i18n/zh/prompts/coding_prompts/(7,1)_#_AI生成代码文档_-_通用提示词模板.md",
|
||||
"i18n/zh/prompts/coding_prompts/系统架构可视化生成Mermaid.md",
|
||||
"i18n/zh/prompts/coding_prompts/系统架构.md",
|
||||
"i18n/zh/prompts/coding_prompts/(12,2)_{任务帮我进行智能任务描述,分析与补全任务,你需要理解、描述我当前正在进行的任务,自动识别缺少的要素、未完善的部分、可能.md",
|
||||
"i18n/zh/prompts/coding_prompts/简易提示词优化器.md",
|
||||
"i18n/zh/prompts/coding_prompts/(2,1)_#_ultrathink_ultrathink_ultrathink_ultrathink_ultrathink.md",
|
||||
"i18n/zh/prompts/coding_prompts/(13,1)_#_提示工程师任务说明.md",
|
||||
"i18n/zh/prompts/coding_prompts/(20,1)_#_高质量代码开发专家.md",
|
||||
"i18n/zh/prompts/coding_prompts/(14,2)_############################################################.md",
|
||||
"i18n/zh/prompts/coding_prompts/(11,1)_{任务你是一名资深系统架构师与AI协同设计顾问。nn目标:当用户启动一个新项目或请求AI帮助开发功能时,你必须优先帮助用.md",
|
||||
"i18n/zh/prompts/coding_prompts/(9,1)_{角色与目标{你首席软件架构师_(Principal_Software_Architect)(高性能、可维护、健壮、DD.md",
|
||||
"i18n/zh/prompts/coding_prompts/标准项目目录结构.md",
|
||||
"i18n/zh/prompts/coding_prompts/分析1.md",
|
||||
"i18n/zh/prompts/coding_prompts/执行纯净性检测.md",
|
||||
"i18n/zh/prompts/coding_prompts/标准化流程.md",
|
||||
"i18n/zh/prompts/coding_prompts/项目上下文文档生成.md",
|
||||
"i18n/zh/prompts/coding_prompts/人机对齐.md",
|
||||
"i18n/zh/prompts/coding_prompts/(1,1)_#_📘_项目上下文文档生成_·_工程化_Prompt(专业优化版).md",
|
||||
"i18n/zh/prompts/coding_prompts/(5,1)_{content#_🚀_智能需求理解与研发导航引擎(Meta_R&D_Navigator_·.md",
|
||||
"i18n/zh/prompts/coding_prompts/(6,1)_{System_Prompt#_🧠_系统提示词:AI_Prompt_编程语言约束与持久化记忆规范nn##.md",
|
||||
"i18n/zh/prompts/coding_prompts/plan提示词.md",
|
||||
"i18n/zh/prompts/coding_prompts/(15,1)_###_Claude_Code_八荣八耻.md",
|
||||
"i18n/zh/prompts/coding_prompts/任务描述,分析与补全任务.md",
|
||||
"i18n/zh/prompts/coding_prompts/(10,1)_{任务你是首席软件架构师_(Principal_Software_Architect),专注于构建[高性能__可维护.md",
|
||||
"i18n/zh/prompts/coding_prompts/(4,1)_ultrathink__Take_a_deep_breath..md",
|
||||
"i18n/zh/prompts/coding_prompts/docs文件夹中文命名提示词.md",
|
||||
"i18n/zh/prompts/coding_prompts/(18,2)_#_通用项目架构综合分析与优化框架.md",
|
||||
"i18n/zh/prompts/coding_prompts/胶水开发.md",
|
||||
"i18n/zh/prompts/coding_prompts/sh控制面板生成.md",
|
||||
"i18n/zh/prompts/coding_prompts/(8,1)_#_执行📘_文件头注释规范(用于所有代码文件最上方).md",
|
||||
"i18n/zh/prompts/coding_prompts/前端设计.md",
|
||||
"i18n/zh/prompts/coding_prompts/(19,1)_##_角色定义.md",
|
||||
"i18n/zh/prompts/coding_prompts/index.md",
|
||||
"i18n/zh/prompts/coding_prompts/(16,3)_#_CLAUDE_记忆.md",
|
||||
"i18n/zh/prompts/coding_prompts/输入简单的日常行为的研究报告摘要.md",
|
||||
"i18n/zh/prompts/meta_prompts/.gitkeep",
|
||||
"i18n/zh/prompts/user_prompts/数据管道.md",
|
||||
"i18n/zh/prompts/user_prompts/项目变量与工具统一维护.md",
|
||||
"i18n/zh/prompts/user_prompts/ASCII图生成.md",
|
||||
"i18n/zh/prompts/system_prompts/# 💀《科比的救母救父救未婚妻与岳父岳母日记》 × OTE模型交易模式 × M.I.T白人金融教授(被女学生指控性骚扰版)v2.md",
|
||||
"i18n/zh/prompts/system_prompts/CLAUDE.md/5/CLAUDE.md",
|
||||
"i18n/zh/prompts/system_prompts/CLAUDE.md/9/AGENTS.md",
|
||||
"i18n/zh/prompts/system_prompts/CLAUDE.md/6/CLAUDE.md",
|
||||
"i18n/zh/prompts/system_prompts/CLAUDE.md/3/CLAUDE.md",
|
||||
"i18n/zh/prompts/system_prompts/CLAUDE.md/10/CLAUDE.md",
|
||||
"i18n/zh/prompts/system_prompts/CLAUDE.md/1/CLAUDE.md",
|
||||
"i18n/zh/prompts/system_prompts/CLAUDE.md/8/CLAUDE.md",
|
||||
"i18n/zh/prompts/system_prompts/CLAUDE.md/4/CLAUDE.md",
|
||||
"i18n/zh/prompts/system_prompts/CLAUDE.md/7/CLAUDE.md",
|
||||
"i18n/zh/prompts/system_prompts/CLAUDE.md/2/CLAUDE.md",
|
||||
"i18n/zh/skills/telegram-dev/SKILL.md",
|
||||
"i18n/zh/skills/telegram-dev/references/动态视图对齐实现文档.md",
|
||||
"i18n/zh/skills/telegram-dev/references/Telegram_Bot_按钮和键盘实现模板.md",
|
||||
"i18n/zh/skills/telegram-dev/references/index.md",
|
||||
"i18n/zh/skills/claude-skills/AGENTS.md",
|
||||
"i18n/zh/skills/claude-skills/assets/template-complete.md",
|
||||
"i18n/zh/skills/claude-skills/assets/template-minimal.md",
|
||||
"i18n/zh/skills/claude-skills/SKILL.md",
|
||||
"i18n/zh/skills/claude-skills/scripts/create-skill.sh",
|
||||
"i18n/zh/skills/claude-skills/scripts/validate-skill.sh",
|
||||
"i18n/zh/skills/claude-skills/references/anti-patterns.md",
|
||||
"i18n/zh/skills/claude-skills/references/README.md",
|
||||
"i18n/zh/skills/claude-skills/references/quality-checklist.md",
|
||||
"i18n/zh/skills/claude-skills/references/skill-spec.md",
|
||||
"i18n/zh/skills/claude-skills/references/index.md",
|
||||
"i18n/zh/skills/snapdom/SKILL.md",
|
||||
"i18n/zh/skills/snapdom/references/other.md",
|
||||
"i18n/zh/skills/snapdom/references/index.md",
|
||||
"i18n/zh/skills/timescaledb/SKILL.md",
|
||||
"i18n/zh/skills/timescaledb/references/hyperfunctions.md",
|
||||
"i18n/zh/skills/timescaledb/references/performance.md",
|
||||
"i18n/zh/skills/timescaledb/references/other.md",
|
||||
"i18n/zh/skills/timescaledb/references/compression.md",
|
||||
"i18n/zh/skills/timescaledb/references/api.md",
|
||||
"i18n/zh/skills/timescaledb/references/tutorials.md",
|
||||
"i18n/zh/skills/timescaledb/references/hypertables.md",
|
||||
"i18n/zh/skills/timescaledb/references/time_buckets.md",
|
||||
"i18n/zh/skills/timescaledb/references/continuous_aggregates.md",
|
||||
"i18n/zh/skills/timescaledb/references/installation.md",
|
||||
"i18n/zh/skills/timescaledb/references/llms-full.md",
|
||||
"i18n/zh/skills/timescaledb/references/llms.md",
|
||||
"i18n/zh/skills/timescaledb/references/getting_started.md",
|
||||
"i18n/zh/skills/timescaledb/references/index.md",
|
||||
"i18n/zh/skills/README.md",
|
||||
"i18n/zh/skills/cryptofeed/SKILL.md",
|
||||
"i18n/zh/skills/cryptofeed/references/other.md",
|
||||
"i18n/zh/skills/cryptofeed/references/README.md",
|
||||
"i18n/zh/skills/cryptofeed/references/index.md",
|
||||
"i18n/zh/skills/coingecko/SKILL.md",
|
||||
"i18n/zh/skills/coingecko/references/coins.md",
|
||||
"i18n/zh/skills/coingecko/references/contract.md",
|
||||
"i18n/zh/skills/coingecko/references/exchanges.md",
|
||||
"i18n/zh/skills/coingecko/references/other.md",
|
||||
"i18n/zh/skills/coingecko/references/introduction.md",
|
||||
"i18n/zh/skills/coingecko/references/nfts.md",
|
||||
"i18n/zh/skills/coingecko/references/trending.md",
|
||||
"i18n/zh/skills/coingecko/references/reference.md",
|
||||
"i18n/zh/skills/coingecko/references/llms-full.md",
|
||||
"i18n/zh/skills/coingecko/references/market_data.md",
|
||||
"i18n/zh/skills/coingecko/references/pricing.md",
|
||||
"i18n/zh/skills/coingecko/references/authentication.md",
|
||||
"i18n/zh/skills/coingecko/references/llms.md",
|
||||
"i18n/zh/skills/coingecko/references/index.md",
|
||||
"i18n/zh/skills/hummingbot/SKILL.md",
|
||||
"i18n/zh/skills/hummingbot/references/advanced.md",
|
||||
"i18n/zh/skills/hummingbot/references/other.md",
|
||||
"i18n/zh/skills/hummingbot/references/connectors.md",
|
||||
"i18n/zh/skills/hummingbot/references/troubleshooting.md",
|
||||
"i18n/zh/skills/hummingbot/references/development.md",
|
||||
"i18n/zh/skills/hummingbot/references/strategies.md",
|
||||
"i18n/zh/skills/hummingbot/references/getting_started.md",
|
||||
"i18n/zh/skills/hummingbot/references/configuration.md",
|
||||
"i18n/zh/skills/hummingbot/references/trading.md",
|
||||
"i18n/zh/skills/hummingbot/references/index.md",
|
||||
"i18n/zh/skills/claude-code-guide/SKILL.md",
|
||||
"i18n/zh/skills/claude-code-guide/references/README.md",
|
||||
"i18n/zh/skills/claude-code-guide/references/index.md",
|
||||
"i18n/zh/skills/proxychains/SKILL.md",
|
||||
"i18n/zh/skills/proxychains/scripts/setup-proxy.sh",
|
||||
"i18n/zh/skills/proxychains/references/proxychains.conf",
|
||||
"i18n/zh/skills/proxychains/references/troubleshooting.md",
|
||||
"i18n/zh/skills/proxychains/references/setup-guide.md",
|
||||
"i18n/zh/skills/proxychains/references/quick-reference.md",
|
||||
"i18n/zh/skills/proxychains/references/index.md",
|
||||
"i18n/zh/skills/ccxt/SKILL.md",
|
||||
"i18n/zh/skills/ccxt/references/specification.md",
|
||||
"i18n/zh/skills/ccxt/references/exchanges.md",
|
||||
"i18n/zh/skills/ccxt/references/other.md",
|
||||
"i18n/zh/skills/ccxt/references/pro.md",
|
||||
"i18n/zh/skills/ccxt/references/faq.md",
|
||||
"i18n/zh/skills/ccxt/references/cli.md",
|
||||
"i18n/zh/skills/ccxt/references/manual.md",
|
||||
"i18n/zh/skills/ccxt/references/getting_started.md",
|
||||
"i18n/zh/skills/ccxt/references/index.md",
|
||||
"i18n/zh/skills/claude-cookbooks/SKILL.md",
|
||||
"i18n/zh/skills/claude-cookbooks/scripts/memory_tool.py",
|
||||
"i18n/zh/skills/claude-cookbooks/references/multimodal.md",
|
||||
"i18n/zh/skills/claude-cookbooks/references/capabilities.md",
|
||||
"i18n/zh/skills/claude-cookbooks/references/patterns.md",
|
||||
"i18n/zh/skills/claude-cookbooks/references/README.md",
|
||||
"i18n/zh/skills/claude-cookbooks/references/third_party.md",
|
||||
"i18n/zh/skills/claude-cookbooks/references/CONTRIBUTING.md",
|
||||
"i18n/zh/skills/claude-cookbooks/references/main_readme.md",
|
||||
"i18n/zh/skills/claude-cookbooks/references/tool_use.md",
|
||||
"i18n/zh/skills/claude-cookbooks/references/index.md",
|
||||
"i18n/zh/skills/polymarket/SKILL.md",
|
||||
"i18n/zh/skills/polymarket/references/other.md",
|
||||
"i18n/zh/skills/polymarket/references/realtime-client.md",
|
||||
"i18n/zh/skills/polymarket/references/api.md",
|
||||
"i18n/zh/skills/polymarket/references/learn.md",
|
||||
"i18n/zh/skills/polymarket/references/README.md",
|
||||
"i18n/zh/skills/polymarket/references/llms-full.md",
|
||||
"i18n/zh/skills/polymarket/references/llms.md",
|
||||
"i18n/zh/skills/polymarket/references/getting_started.md",
|
||||
"i18n/zh/skills/polymarket/references/guides.md",
|
||||
"i18n/zh/skills/polymarket/references/trading.md",
|
||||
"i18n/zh/skills/polymarket/references/index.md",
|
||||
"i18n/zh/skills/postgresql/SKILL.md",
|
||||
"i18n/zh/skills/postgresql/references/sql.md",
|
||||
"i18n/zh/skills/postgresql/references/getting_started.md",
|
||||
"i18n/zh/skills/postgresql/references/index.md",
|
||||
"i18n/zh/skills/twscrape/SKILL.md",
|
||||
"i18n/zh/skills/twscrape/references/examples.md",
|
||||
"i18n/zh/skills/twscrape/references/installation.md",
|
||||
"i18n/zh/skills/twscrape/references/index.md",
|
||||
"i18n/zh/README.md"
|
||||
]
|
||||
|
|
@ -1,163 +0,0 @@
|
|||
{
|
||||
"zh": "en",
|
||||
"documents": "documents",
|
||||
"prompts": "prompts",
|
||||
"skills": "skills",
|
||||
"Templates and Resources": "Templates and Resources",
|
||||
"代码组织": "Code_Organization",
|
||||
"编程书籍推荐": "Recommended_Programming_Books",
|
||||
"通用项目架构模板": "General_Project_Architecture_Template",
|
||||
"工具集": "Tool_Set",
|
||||
"README": "README",
|
||||
"Tutorials and Guides": "Tutorials and Guides",
|
||||
"telegram-dev": "telegram-dev",
|
||||
"telegram Markdown 代码块格式修复记录 2025-12-15": "telegram_Markdown_Code_Block_Format_Fix_Log_2025_12_15",
|
||||
"tmux快捷键大全": "tmux_Shortcut_Cheatsheet",
|
||||
"关于手机ssh任意位置链接本地计算机,基于frp实现的方法": "Method_for_SSH_Linking_Mobile_Phone_to_Local_Computer_Anywhere_Based_on_FRP_Implementation",
|
||||
"LazyVim快捷键大全": "LazyVim_Shortcut_Cheatsheet",
|
||||
"auggie-mcp配置文档": "auggie_mcp_Configuration_Document",
|
||||
"Methodology and Principles": "Methodology and Principles",
|
||||
"系统提示词构建原则": "System_Prompt_Construction_Principles",
|
||||
"gluecoding": "gluecoding",
|
||||
"胶水编程": "Glue_Programming",
|
||||
"vibe-coding-经验收集": "vibe_coding_Experience_Collection",
|
||||
"开发经验": "Development_Experience",
|
||||
"学习经验": "Learning_Experience",
|
||||
"A Formalization of Recursive Self-Optimizing Generative Systems": "A_Formalization_of_Recursive_Self_Optimizing_Generative_Systems",
|
||||
"编程之道": "The_Way_of_Programming",
|
||||
"coding_prompts": "coding_prompts",
|
||||
"客观分析": "Objective_Analysis",
|
||||
"精华技术文档生成提示词": "Essential_Technical_Document_Generation_Prompt",
|
||||
"智能需求理解与研发导航引擎": "Intelligent_Requirement_Understanding_and_R_D_Navigation_Engine",
|
||||
"软件工程分析": "Software_Engineering_Analysis",
|
||||
"系统架构可视化生成Mermaid": "System_Architecture_Visualization_Generation_Mermaid",
|
||||
"系统架构": "System_Architecture",
|
||||
"简易提示词优化器": "Simple_Prompt_Optimizer",
|
||||
"提示工程师任务说明": "Prompt_Engineer_Task_Description",
|
||||
"高质量代码开发专家": "High_Quality_Code_Development_Expert",
|
||||
"标准项目目录结构": "Standard_Project_Directory_Structure",
|
||||
"分析1": "Analysis_1",
|
||||
"分析2": "Analysis_2",
|
||||
"执行纯净性检测": "Perform_Purity_Test",
|
||||
"标准化流程": "Standardized_Process",
|
||||
"项目上下文文档生成": "Project_Context_Document_Generation",
|
||||
"人机对齐": "Human_AI_Alignment",
|
||||
"plan提示词": "Plan_Prompt",
|
||||
"Claude Code 八荣八耻": "Claude_Code_Eight_Honors_and_Eight_Shames",
|
||||
"任务描述,分析与补全任务": "Task_Description_Analysis_and_Completion",
|
||||
"前端设计": "Frontend_Design",
|
||||
"输入简单的日常行为的研究报告摘要": "Summary_of_Research_Report_on_Simple_Daily_Behaviors",
|
||||
"胶水开发": "Glue_Development",
|
||||
"sh控制面板生成": "SH_Control_Panel_Generation",
|
||||
"角色定义": "Role_Definition",
|
||||
"CLAUDE 记忆": "CLAUDE_Memory",
|
||||
"index": "index",
|
||||
"user_prompts": "user_prompts",
|
||||
"数据管道": "Data_Pipeline",
|
||||
"项目变量与工具统一维护": "Unified_Management_of_Project_Variables_and_Tools",
|
||||
"ASCII图生成": "ASCII_Art_Generation",
|
||||
"system_prompts": "system_prompts",
|
||||
"SKILL": "SKILL",
|
||||
"references": "references",
|
||||
"动态视图对齐实现文档": "Dynamic_View_Alignment_Implementation_Document",
|
||||
"Telegram_Bot_按钮和键盘实现模板": "Telegram_Bot_Button_and_Keyboard_Implementation_Template",
|
||||
"claude-skills": "claude-skills",
|
||||
"assets": "assets",
|
||||
"template-complete": "template-complete",
|
||||
"template-minimal": "template-minimal",
|
||||
"scripts": "scripts",
|
||||
"create-skill": "create-skill",
|
||||
"validate-skill": "validate-skill",
|
||||
"anti-patterns": "anti-patterns",
|
||||
"quality-checklist": "quality-checklist",
|
||||
"skill-spec": "skill-spec",
|
||||
"snapdom": "snapdom",
|
||||
"other": "other",
|
||||
"timescaledb": "timescaledb",
|
||||
"hyperfunctions": "hyperfunctions",
|
||||
"performance": "performance",
|
||||
"compression": "compression",
|
||||
"api": "api",
|
||||
"tutorials": "tutorials",
|
||||
"hypertables": "hypertables",
|
||||
"time_buckets": "time_buckets",
|
||||
"continuous_aggregates": "continuous_aggregates",
|
||||
"installation": "installation",
|
||||
"llms-full": "llms-full",
|
||||
"llms": "llms",
|
||||
"getting_started": "getting_started",
|
||||
"cryptofeed": "cryptofeed",
|
||||
"coingecko": "coingecko",
|
||||
"coins": "coins",
|
||||
"contract": "contract",
|
||||
"exchanges": "exchanges",
|
||||
"introduction": "introduction",
|
||||
"nfts": "nfts",
|
||||
"trending": "trending",
|
||||
"reference": "reference",
|
||||
"market_data": "market_data",
|
||||
"pricing": "pricing",
|
||||
"authentication": "authentication",
|
||||
"hummingbot": "hummingbot",
|
||||
"advanced": "advanced",
|
||||
"connectors": "connectors",
|
||||
"troubleshooting": "troubleshooting",
|
||||
"development": "development",
|
||||
"strategies": "strategies",
|
||||
"configuration": "configuration",
|
||||
"trading": "trading",
|
||||
"claude-code-guide": "claude-code-guide",
|
||||
"proxychains": "proxychains",
|
||||
"setup-proxy": "setup-proxy",
|
||||
"proxychains.conf": "proxychains.conf",
|
||||
"setup-guide": "setup-guide",
|
||||
"quick-reference": "quick-reference",
|
||||
"ccxt": "ccxt",
|
||||
"specification": "specification",
|
||||
"pro": "pro",
|
||||
"faq": "faq",
|
||||
"cli": "cli",
|
||||
"manual": "manual",
|
||||
"claude-cookbooks": "claude-cookbooks",
|
||||
"memory_tool": "memory_tool",
|
||||
"multimodal": "multimodal",
|
||||
"capabilities": "capabilities",
|
||||
"patterns": "patterns",
|
||||
"third_party": "third_party",
|
||||
"CONTRIBUTING": "CONTRIBUTING",
|
||||
"main_readme": "main_readme",
|
||||
"tool_use": "tool_use",
|
||||
"polymarket": "polymarket",
|
||||
"realtime-client": "realtime-client",
|
||||
"learn": "learn",
|
||||
"guides": "guides",
|
||||
"postgresql": "postgresql",
|
||||
"sql": "sql",
|
||||
"twscrape": "twscrape",
|
||||
"examples": "examples",
|
||||
"installation": "installation",
|
||||
"# 💀《科比的救母救父救未婚妻与岳父岳母日记》 × OTE模型交易模式 × M.I.T白人金融教授(被女学生指控性骚扰版)v2": "Kobe_s_Diary_of_Saving_Mother_Father_Fiancee_and_In_laws_OTE_Model_Trading_Mode_M_I_T_White_Professor_Accused_of_Sexual_Harassment_by_Female_Student_v2",
|
||||
"(3,1)_#_流程标准化": "Standardization_Process",
|
||||
"(21,1)_你是我的顶级编程助手,我将使用自然语言描述开发需求。请你将其转换为一个结构化、专业、详细、可执行的编程任务说明文档,输出": "Top_Programming_Assistant_Task_Description",
|
||||
"(17,2)_#_软件工程分析": "Software_Engineering_Analysis",
|
||||
"(22,5)_前几天,我被_Claude_那些臃肿、过度设计的解决方案搞得很沮丧,里面有一大堆我不需要的“万一”功能。然后我尝试在我的": "Frustration_with_Claude_Over_Designed_Solutions",
|
||||
"(7,1)_#_AI生成代码文档_-_通用提示词模板": "AI_Generated_Code_Documentation_General_Prompt_Template",
|
||||
"(12,2)_{任务帮我进行智能任务描述,分析与补全任务,你需要理解、描述我当前正在进行的任务,自动识别缺少的要素、未完善的部分、可能": "Intelligent_Task_Description_Analysis_and_Completion",
|
||||
"(2,1)_#_ultrathink_ultrathink_ultrathink_ultrathink_ultrathink": "ultrathink_ultrathink_ultrathink_ultrathink_ultrathink",
|
||||
"(13,1)_#_提示工程师任务说明": "Prompt_Engineer_Task_Description",
|
||||
"(20,1)_#_高质量代码开发专家": "High_Quality_Code_Development_Expert",
|
||||
"(14,2)_############################################################": "Hash_Delimiters",
|
||||
"(11,1)_{任务你是一名资深系统架构师与AI协同设计顾问。nn目标:当用户启动一个新项目或请求AI帮助开发功能时,你必须优先帮助用": "Senior_System_Architect_AI_Collaboration_Consultant_Task",
|
||||
"(9,1)_{角色与目标{你首席软件架构师_(Principal_Software_Architect)(高性能、可维护、健壮、DD": "Principal_Software_Architect_Role_and_Goals",
|
||||
"(1,1)_#_📘_项目上下文文档生成_·_工程化_Prompt(专业优化版)": "Project_Context_Document_Generation_Engineered_Prompt_Optimized",
|
||||
"(5,1)_{content#_🚀_智能需求理解与研发导航引擎(Meta_R&D_Navigator_·": "Intelligent_Requirement_Understanding_and_RD_Navigation_Engine",
|
||||
"(6,1)_{System_Prompt#_🧠_系统提示词:AI_Prompt_编程语言约束与持久化记忆规范nn##": "System_Prompt_AI_Prompt_Programming_Language_Constraints_and_Persistent_Memory_Specifications",
|
||||
"(15,1)_###_Claude_Code_八荣八耻": "Claude_Code_Eight_Honors_and_Eight_Shames",
|
||||
"(10,1)_{任务你是首席软件架构师_(Principal_Software_Architect),专注于构建[高性能__可维护": "Principal_Software_Architect_Focus_High_Performance_Maintainable_Systems",
|
||||
"(4,1)_ultrathink__Take_a_deep_breath.": "ultrathink__Take_a_deep_breath",
|
||||
"docs文件夹中文命名提示词": "Docs_Folder_Chinese_Naming_Prompt",
|
||||
"(18,2)_#_通用项目架构综合分析与优化框架": "General_Project_Architecture_Comprehensive_Analysis_and_Optimization_Framework",
|
||||
"(8,1)_#_执行📘_文件头注释规范(用于所有代码文件最上方)": "Execute_File_Header_Comment_Specification_for_All_Code_Files",
|
||||
"(19,1)_##_角色定义": "Role_Definition",
|
||||
"(16,3)_#_CLAUDE_记忆": "CLAUDE_Memory"
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
deep-translator>=1.11.4
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
轻量级批量翻译工具:将 Markdown/文本从一种语言翻译到另一种语言。
|
||||
默认使用 deep-translator 封装的 Google Translator,自带简单的代码块保护。
|
||||
用法示例:
|
||||
python translate.py --input ../../i18n/zh/README.md --src-lang zh --tgt-lang en --output ../../i18n/en/README.md
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
from typing import List
|
||||
|
||||
try:
|
||||
from deep_translator import GoogleTranslator
|
||||
except ImportError as exc: # pragma: no cover - 运行前请安装依赖
|
||||
sys.stderr.write("[错误] 缺少依赖 deep-translator,请先 `pip install -r requirements.txt`\n")
|
||||
raise
|
||||
|
||||
|
||||
def translate_blocks(lines: List[str], src: str, tgt: str) -> List[str]:
|
||||
"""逐段翻译,保持代码块原样,减少上下文丢失。"""
|
||||
translated: List[str] = []
|
||||
in_code = False
|
||||
buffer: List[str] = []
|
||||
translator = GoogleTranslator(source=src, target=tgt)
|
||||
|
||||
def flush_buffer():
|
||||
if not buffer:
|
||||
return
|
||||
text = "\n".join(buffer)
|
||||
try:
|
||||
result = translator.translate(text)
|
||||
except Exception as exc: # pragma: no cover
|
||||
raise RuntimeError(f"翻译失败: {exc}") from exc
|
||||
translated.extend(result.split("\n"))
|
||||
buffer.clear()
|
||||
|
||||
for line in lines:
|
||||
if line.strip().startswith("```"):
|
||||
flush_buffer()
|
||||
in_code = not in_code
|
||||
translated.append(line)
|
||||
continue
|
||||
if in_code:
|
||||
translated.append(line)
|
||||
continue
|
||||
# 空行作为段落分割,先刷新再保留空行
|
||||
if not line.strip():
|
||||
flush_buffer()
|
||||
translated.append(line)
|
||||
continue
|
||||
buffer.append(line)
|
||||
|
||||
flush_buffer()
|
||||
return translated
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description="批量翻译文本/Markdown,保护代码块")
|
||||
parser.add_argument("--input", required=True, help="源文件路径")
|
||||
parser.add_argument("--output", required=True, help="目标文件路径")
|
||||
parser.add_argument("--src-lang", required=True, help="源语言代码,如 zh")
|
||||
parser.add_argument("--tgt-lang", required=True, help="目标语言代码,如 en")
|
||||
parser.add_argument("--overwrite", action="store_true", help="允许覆盖已有输出文件")
|
||||
args = parser.parse_args()
|
||||
|
||||
if not os.path.isfile(args.input):
|
||||
sys.stderr.write(f"[错误] 源文件不存在: {args.input}\n")
|
||||
return 1
|
||||
if os.path.exists(args.output) and not args.overwrite:
|
||||
sys.stderr.write(f"[错误] 目标文件已存在,加 --overwrite 才会覆盖: {args.output}\n")
|
||||
return 1
|
||||
|
||||
with open(args.input, "r", encoding="utf-8") as f:
|
||||
lines = f.read().splitlines()
|
||||
|
||||
translated = translate_blocks(lines, args.src_lang, args.tgt_lang)
|
||||
|
||||
os.makedirs(os.path.dirname(args.output), exist_ok=True)
|
||||
with open(args.output, "w", encoding="utf-8") as f:
|
||||
f.write("\n".join(translated) + "\n")
|
||||
|
||||
print(f"[完成] {args.input} -> {args.output} ({args.src_lang} -> {args.tgt_lang})")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
sys.exit(main())
|
||||
|
|
@ -1,182 +0,0 @@
|
|||
import os
|
||||
import re
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
# Load PATH_TRANSLATION_MAP from JSON
|
||||
# Ensure the path is relative to the script's location or absolute
|
||||
script_dir = Path(__file__).parent
|
||||
path_translation_map_path = script_dir / 'path_translation_map.json'
|
||||
|
||||
with open(path_translation_map_path, 'r', encoding='utf-8') as f:
|
||||
PATH_TRANSLATION_MAP = json.load(f)
|
||||
|
||||
def translate_path_component(component):
|
||||
if component in PATH_TRANSLATION_MAP:
|
||||
return PATH_TRANSLATION_MAP[component]
|
||||
|
||||
# Handle numeric prefixes like (3,1)_#_
|
||||
if re.match(r"^\(\d+,\d+\)_#?_", component):
|
||||
cleaned_component = re.sub(r"^\(\d+,\d+\)_#?_", "", component).replace("_", " ")
|
||||
# Try to match cleaned component against known translations
|
||||
for k, v in PATH_TRANSLATION_MAP.items():
|
||||
if cleaned_component in k or k in cleaned_component:
|
||||
return v.replace(" ", "_") # Return simplified and underscored version
|
||||
|
||||
# Fallback for complex patterns not in map
|
||||
return re.sub(r"[^a-zA-Z0-9]+", "_", cleaned_component).strip("_")
|
||||
|
||||
# If it's a very long Chinese filename that might have specific terms
|
||||
# These were added to PATH_TRANSLATION_MAP now, so this generic logic might not be hit as often
|
||||
if "代码组织" == component: # Exact match for a known common Chinese filename part
|
||||
return "Code_Organization"
|
||||
if "编程书籍推荐" == component:
|
||||
return "Recommended_Programming_Books"
|
||||
if "通用项目架构模板" == component:
|
||||
return "General_Project_Architecture_Template"
|
||||
if "工具集" == component:
|
||||
return "Tool_Set"
|
||||
if "系统提示词构建原则" == component:
|
||||
return "System_Prompt_Construction_Principles"
|
||||
if "胶水编程" == component:
|
||||
return "Glue_Programming"
|
||||
if "vibe-coding-经验收集" == component:
|
||||
return "vibe-coding-Experience_Collection"
|
||||
if "开发经验" == component:
|
||||
return "Development_Experience"
|
||||
if "学习经验" == component:
|
||||
return "Learning_Experience"
|
||||
if "编程之道" == component:
|
||||
return "The_Way_of_Programming"
|
||||
if "客观分析" == component:
|
||||
return "Objective_Analysis"
|
||||
if "精华技术文档生成提示词" == component:
|
||||
return "Essential_Technical_Document_Generation_Prompt"
|
||||
if "智能需求理解与研发导航引擎" == component:
|
||||
return "Intelligent_Requirement_Understanding_and_R_D_Navigation_Engine"
|
||||
if "软件工程分析" == component:
|
||||
return "Software_Engineering_Analysis"
|
||||
if "系统架构可视化生成Mermaid":
|
||||
return "System_Architecture_Visualization_Generation_Mermaid"
|
||||
if "系统架构":
|
||||
return "System_Architecture"
|
||||
if "简易提示词优化器":
|
||||
return "Simple_Prompt_Optimizer"
|
||||
if "提示工程师任务说明":
|
||||
return "Prompt_Engineer_Task_Description"
|
||||
if "高质量代码开发专家":
|
||||
return "High_Quality_Code_Development_Expert"
|
||||
if "标准项目目录结构":
|
||||
return "Standard_Project_Directory_Structure"
|
||||
if "分析1":
|
||||
return "Analysis_1"
|
||||
if "分析2":
|
||||
return "Analysis_2"
|
||||
if "执行纯净性检测":
|
||||
return "Perform_Purity_Test"
|
||||
if "标准化流程":
|
||||
return "Standardized_Process"
|
||||
if "项目上下文文档生成":
|
||||
return "Project_Context_Document_Generation"
|
||||
if "人机对齐":
|
||||
return "Human_AI_Alignment"
|
||||
if "plan提示词":
|
||||
return "Plan_Prompt"
|
||||
if "Claude Code 八荣八耻":
|
||||
return "Claude_Code_Eight_Honors_and_Eight_Shames"
|
||||
if "任务描述,分析与补全任务":
|
||||
return "Task_Description_Analysis_and_Completion"
|
||||
if "前端设计":
|
||||
return "Frontend_Design"
|
||||
if "输入简单的日常行为的研究报告摘要":
|
||||
return "Summary_of_Research_Report_on_Simple_Daily_Behaviors"
|
||||
if "胶水开发":
|
||||
return "Glue_Development"
|
||||
if "sh控制面板生成":
|
||||
return "SH_Control_Panel_Generation"
|
||||
if "角色定义":
|
||||
return "Role_Definition"
|
||||
if "CLAUDE 记忆":
|
||||
return "CLAUDE_Memory"
|
||||
if "Docs文件夹中文命名提示词":
|
||||
return "Docs_Folder_Chinese_Naming_Prompt"
|
||||
if "通用项目架构综合分析与优化框架":
|
||||
return "General_Project_Architecture_Comprehensive_Analysis_and_Optimization_Framework"
|
||||
if "执行📘_文件头注释规范(用于所有代码文件最上方)" == component:
|
||||
return "Execute_File_Header_Comment_Specification_for_All_Code_Files"
|
||||
if "数据管道" == component:
|
||||
return "Data_Pipeline"
|
||||
if "项目变量与工具统一维护" == component:
|
||||
return "Unified_Management_of_Project_Variables_and_Tools"
|
||||
if "ASCII图生成" == component:
|
||||
return "ASCII_Art_Generation"
|
||||
if "Kobe's Diary of Saving Mother, Father, Fiancee, and In-laws × OTE Model Trading Mode × M.I.T White Professor (Accused of Sexual H_arassment by Female Student) v2" == component:
|
||||
return "Kobe_s_Diary_of_Saving_Mother_Father_Fiancee_and_In_laws_OTE_Model_Trading_Mode_M_I_T_White_Professor_Accused_of_Sexual_Harassment_by_Female_Student_v2" # Simplified for filename
|
||||
if "动态视图对齐实现文档" == component:
|
||||
return "Dynamic_View_Alignment_Implementation_Document"
|
||||
if "Telegram_Bot_按钮和键盘实现模板" == component:
|
||||
return "Telegram_Bot_Button_and_Keyboard_Implementation_Template"
|
||||
if "README" == component:
|
||||
return "README" # Keep README as is
|
||||
|
||||
# Default: simply replace spaces with underscores and remove problematic characters for filenames
|
||||
# For demonstration, a placeholder translation for unseen Chinese
|
||||
return re.sub(r"[^a-zA-Z0-9]+", "_", component).strip("_")
|
||||
|
||||
|
||||
def get_translated_path(chinese_path_str): # Accept string
|
||||
parts = Path(chinese_path_str).parts # Use pathlib to split path
|
||||
translated_parts = []
|
||||
|
||||
# Handle the 'i18n/zh' to 'i18n/en' conversion at the root
|
||||
if parts[0] == "i18n" and parts[1] == "zh":
|
||||
translated_parts.append("i18n")
|
||||
translated_parts.append("en")
|
||||
remaining_parts = parts[2:]
|
||||
else:
|
||||
remaining_parts = parts
|
||||
|
||||
for i, part in enumerate(remaining_parts):
|
||||
base, ext = os.path.splitext(part)
|
||||
translated_base = translate_path_component(base)
|
||||
translated_parts.append(translated_base + ext)
|
||||
|
||||
return Path(*translated_parts) # Reconstruct path using pathlib
|
||||
|
||||
# Load chinese_files from JSON
|
||||
chinese_files_list_path = script_dir / 'chinese_files_list.json'
|
||||
with open(chinese_files_list_path, 'r', encoding='utf-8') as f:
|
||||
chinese_files_str_list = json.load(f)
|
||||
|
||||
files_to_translate_content = []
|
||||
|
||||
for chinese_file_path_str in chinese_files_str_list:
|
||||
english_file_path = get_translated_path(chinese_file_path_str) # Get translated Path object
|
||||
|
||||
# Read the content of the English placeholder file
|
||||
try:
|
||||
with english_file_path.open('r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
if content.startswith("TRANSLATED CONTENT:\n"):
|
||||
chinese_content = content.replace("TRANSLATED CONTENT:\n", "")
|
||||
files_to_translate_content.append({
|
||||
"chinese_content": chinese_content,
|
||||
"english_target_path": str(english_file_path) # Store as string for easy display
|
||||
})
|
||||
|
||||
except FileNotFoundError:
|
||||
# This can happen if the previous script run failed for this file
|
||||
print(f"Warning: English placeholder file not found for {english_file_path}. Skipping content extraction for this file.")
|
||||
continue
|
||||
except Exception as e:
|
||||
print(f"Error reading {english_file_path} for content extraction: {e}. Skipping.")
|
||||
continue
|
||||
|
||||
# Output the list of files to translate content for
|
||||
print("--- Files for Content Translation ---")
|
||||
for item in files_to_translate_content:
|
||||
print(f"Target Path: {item['english_target_path']}")
|
||||
print(f"Chinese Content:\n```markdown\n{item['chinese_content'].strip()}\n```\n{'='*50}\n")
|
||||
|
||||
print(f"Total files requiring content translation: {len(files_to_translate_content)}")
|
||||
|
|
@ -1,200 +0,0 @@
|
|||
# 🚀 Perfect Neovim Configuration with LazyVim
|
||||
|
||||
## 系统配置文档
|
||||
|
||||
### 📋 配置概述
|
||||
- **Neovim 版本**: v0.11.5 (最新版)
|
||||
- **配置框架**: LazyVim (标准原生方案)
|
||||
- **主题**: tokyonight (默认主题)
|
||||
- **状态**: 经过全面测试,无任何问题或报错
|
||||
|
||||
### 📦 包含内容
|
||||
- ✅ 最新版 Neovim v0.11.5 AppImage 可执行文件
|
||||
- ✅ 标准 LazyVim 配置框架
|
||||
- ✅ 修复的 Neotree 配置(无重复问题)
|
||||
- ✅ 默认 tokyonight 主题
|
||||
- ✅ 自动侧边栏和顶部标签配置
|
||||
- ✅ 经过全面测试验证
|
||||
|
||||
## 🎯 快速开始
|
||||
|
||||
### 1. 克隆仓库
|
||||
```bash
|
||||
git clone https://github.com/tukuaiai/vim.git
|
||||
cd vim
|
||||
```
|
||||
|
||||
### 2. 安装配置
|
||||
```bash
|
||||
# 复制配置文件
|
||||
cp -r nvim-config/* ~/.config/
|
||||
|
||||
# 复制可执行文件
|
||||
cp nvim-config/nvim ~/.local/bin/
|
||||
chmod +x ~/.local/bin/nvim
|
||||
|
||||
# 确保路径在 PATH 中
|
||||
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
|
||||
source ~/.bashrc
|
||||
```
|
||||
|
||||
### 3. 启动使用
|
||||
```bash
|
||||
# 直接启动
|
||||
~/.local/bin/nvim
|
||||
|
||||
# 或使用别名(推荐)
|
||||
alias n='~/.local/bin/nvim'
|
||||
n
|
||||
```
|
||||
|
||||
## 🎨 主题配置
|
||||
|
||||
### 当前主题:tokyonight(默认)
|
||||
- 深色护眼主题
|
||||
- 现代化配色方案
|
||||
- 高对比度,适合长时间使用
|
||||
|
||||
### 切换主题(可选)
|
||||
```vim
|
||||
:Telescope colorscheme " 使用 Telescope 选择主题
|
||||
```
|
||||
|
||||
## ⚙️ 核心功能
|
||||
|
||||
### 1. 文件浏览器(Neotree)
|
||||
- **快捷键**:`<leader>e`(空格+e)
|
||||
- **功能**:侧边栏文件浏览器
|
||||
- **特点**:无重复窗口问题(已修复)
|
||||
|
||||
### 2. 顶部标签页(Bufferline)
|
||||
- **功能**:显示打开的缓冲区
|
||||
- **特点**:始终显示,美观实用
|
||||
|
||||
### 3. 模糊查找(Telescope)
|
||||
- **快捷键**:`<leader>f`(空格+f)
|
||||
- **功能**:快速查找文件、符号等
|
||||
|
||||
### 4. Git 集成
|
||||
- **快捷键**:`<leader>g`(空格+g)
|
||||
- **功能**:Git 状态、提交、差异查看
|
||||
|
||||
## ⌨️ 快捷键速查
|
||||
|
||||
| 快捷键 | 功能 |
|
||||
|--------|------|
|
||||
| `<leader>e` | 打开文件浏览器 |
|
||||
| `<leader>f` | 模糊查找 |
|
||||
| `<leader>g` | Git 相关 |
|
||||
| `<leader>b` | 缓冲区管理 |
|
||||
| `<leader>w` | 保存文件 |
|
||||
| `<leader>q` | 退出 |
|
||||
| `<leader>/` | 搜索当前文件 |
|
||||
| `<leader>?` | 查看所有快捷键 |
|
||||
|
||||
## 🔧 高级配置
|
||||
|
||||
### 自动命令(autocmds)
|
||||
位于 `~/.config/nvim/lua/config/autocmds.lua`:
|
||||
```lua
|
||||
-- 自动打开 Neotree(延迟 50ms 确保插件加载)
|
||||
vim.api.nvim_create_autocmd("VimEnter", {
|
||||
callback = function()
|
||||
vim.defer_fn(function()
|
||||
vim.cmd("Neotree show")
|
||||
end, 50)
|
||||
end,
|
||||
})
|
||||
```
|
||||
|
||||
### 插件配置
|
||||
位于 `~/.config/nvim/lua/plugins/`:
|
||||
- `ui.lua` - UI 相关插件配置
|
||||
- `colorscheme.lua` - 主题配置
|
||||
- `example.lua` - 示例插件配置
|
||||
|
||||
## 🧪 测试验证
|
||||
|
||||
### 启动测试
|
||||
```bash
|
||||
# 基础启动测试
|
||||
~/.local/bin/nvim --headless -c "echo 'OK'" -c "qa"
|
||||
|
||||
# 配置加载测试
|
||||
~/.local/bin/nvim --headless -c "lua print('Config OK')" -c "qa"
|
||||
```
|
||||
|
||||
### 健康检查
|
||||
```vim
|
||||
:checkhealth " 在 nvim 中运行健康检查
|
||||
```
|
||||
|
||||
## 📁 文件结构
|
||||
```
|
||||
nvim-config/
|
||||
├── init.lua # 入口文件
|
||||
├── lazy-lock.json # 插件锁文件
|
||||
├── lazyvim.json # LazyVim 配置
|
||||
├── nvim # Neovim v0.11.5 AppImage
|
||||
├── lua/
|
||||
│ ├── config/
|
||||
│ │ ├── autocmds.lua # 自动命令
|
||||
│ │ ├── keymaps.lua # 键位映射
|
||||
│ │ ├── lazy.lua # Lazy.nvim 配置
|
||||
│ │ └── options.lua # 选项设置
|
||||
│ └── plugins/
|
||||
│ ├── colorscheme.lua # 主题配置
|
||||
│ ├── ui.lua # UI 插件配置
|
||||
│ └── example.lua # 示例配置
|
||||
└── stylua.toml # 代码格式化配置
|
||||
```
|
||||
|
||||
## 🚀 高级使用技巧
|
||||
|
||||
### 1. 快速文件操作
|
||||
```vim
|
||||
" 在当前行下方新建文件
|
||||
:enew
|
||||
" 保存文件
|
||||
:w
|
||||
" 退出
|
||||
:qa
|
||||
```
|
||||
|
||||
### 2. 窗口管理
|
||||
```vim
|
||||
" 水平分割
|
||||
:sp filename
|
||||
" 垂直分割
|
||||
:vs filename
|
||||
" 在分割间移动
|
||||
Ctrl+w h/j/k/l
|
||||
```
|
||||
|
||||
### 3. 搜索和替换
|
||||
```vim
|
||||
" 当前文件搜索
|
||||
/
|
||||
" 全局搜索
|
||||
:Telescope live_grep
|
||||
" 替换
|
||||
:%s/old/new/g
|
||||
```
|
||||
|
||||
## 📚 学习资源
|
||||
|
||||
1. **内置教程**:`:Tutor`
|
||||
2. **帮助系统**:`:help 主题`
|
||||
3. **LazyVim 文档**:按 `<leader>?`
|
||||
4. **GitHub 仓库**:https://github.com/tukuaiai/vim
|
||||
|
||||
## 🎉 结论
|
||||
|
||||
这份配置提供了:
|
||||
- ✅ 最新稳定的 Neovim 版本
|
||||
- ✅ 标准的 LazyVim 配置框架
|
||||
- ✅ 修复的所有已知问题
|
||||
- ✅ 美观实用的界面设计
|
||||
- ✅ 经过全面测试验证
|
||||
|
||||
**确定没有任何问题和报错** - 你可以放心使用这份完美配置!
|
||||
|
|
@ -1,201 +0,0 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
|
@ -1,200 +0,0 @@
|
|||
# 🚀 Perfect Neovim Configuration with LazyVim
|
||||
|
||||
## 系统配置文档
|
||||
|
||||
### 📋 配置概述
|
||||
- **Neovim 版本**: v0.11.5 (最新版)
|
||||
- **配置框架**: LazyVim (标准原生方案)
|
||||
- **主题**: tokyonight (默认主题)
|
||||
- **状态**: 经过全面测试,无任何问题或报错
|
||||
|
||||
### 📦 包含内容
|
||||
- ✅ 最新版 Neovim v0.11.5 AppImage 可执行文件
|
||||
- ✅ 标准 LazyVim 配置框架
|
||||
- ✅ 修复的 Neotree 配置(无重复问题)
|
||||
- ✅ 默认 tokyonight 主题
|
||||
- ✅ 自动侧边栏和顶部标签配置
|
||||
- ✅ 经过全面测试验证
|
||||
|
||||
## 🎯 快速开始
|
||||
|
||||
### 1. 克隆仓库
|
||||
```bash
|
||||
git clone https://github.com/tukuaiai/vim.git
|
||||
cd vim
|
||||
```
|
||||
|
||||
### 2. 安装配置
|
||||
```bash
|
||||
# 复制配置文件
|
||||
cp -r nvim-config/* ~/.config/
|
||||
|
||||
# 复制可执行文件
|
||||
cp nvim-config/nvim ~/.local/bin/
|
||||
chmod +x ~/.local/bin/nvim
|
||||
|
||||
# 确保路径在 PATH 中
|
||||
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
|
||||
source ~/.bashrc
|
||||
```
|
||||
|
||||
### 3. 启动使用
|
||||
```bash
|
||||
# 直接启动
|
||||
~/.local/bin/nvim
|
||||
|
||||
# 或使用别名(推荐)
|
||||
alias n='~/.local/bin/nvim'
|
||||
n
|
||||
```
|
||||
|
||||
## 🎨 主题配置
|
||||
|
||||
### 当前主题:tokyonight(默认)
|
||||
- 深色护眼主题
|
||||
- 现代化配色方案
|
||||
- 高对比度,适合长时间使用
|
||||
|
||||
### 切换主题(可选)
|
||||
```vim
|
||||
:Telescope colorscheme " 使用 Telescope 选择主题
|
||||
```
|
||||
|
||||
## ⚙️ 核心功能
|
||||
|
||||
### 1. 文件浏览器(Neotree)
|
||||
- **快捷键**:`<leader>e`(空格+e)
|
||||
- **功能**:侧边栏文件浏览器
|
||||
- **特点**:无重复窗口问题(已修复)
|
||||
|
||||
### 2. 顶部标签页(Bufferline)
|
||||
- **功能**:显示打开的缓冲区
|
||||
- **特点**:始终显示,美观实用
|
||||
|
||||
### 3. 模糊查找(Telescope)
|
||||
- **快捷键**:`<leader>f`(空格+f)
|
||||
- **功能**:快速查找文件、符号等
|
||||
|
||||
### 4. Git 集成
|
||||
- **快捷键**:`<leader>g`(空格+g)
|
||||
- **功能**:Git 状态、提交、差异查看
|
||||
|
||||
## ⌨️ 快捷键速查
|
||||
|
||||
| 快捷键 | 功能 |
|
||||
|--------|------|
|
||||
| `<leader>e` | 打开文件浏览器 |
|
||||
| `<leader>f` | 模糊查找 |
|
||||
| `<leader>g` | Git 相关 |
|
||||
| `<leader>b` | 缓冲区管理 |
|
||||
| `<leader>w` | 保存文件 |
|
||||
| `<leader>q` | 退出 |
|
||||
| `<leader>/` | 搜索当前文件 |
|
||||
| `<leader>?` | 查看所有快捷键 |
|
||||
|
||||
## 🔧 高级配置
|
||||
|
||||
### 自动命令(autocmds)
|
||||
位于 `~/.config/nvim/lua/config/autocmds.lua`:
|
||||
```lua
|
||||
-- 自动打开 Neotree(延迟 50ms 确保插件加载)
|
||||
vim.api.nvim_create_autocmd("VimEnter", {
|
||||
callback = function()
|
||||
vim.defer_fn(function()
|
||||
vim.cmd("Neotree show")
|
||||
end, 50)
|
||||
end,
|
||||
})
|
||||
```
|
||||
|
||||
### 插件配置
|
||||
位于 `~/.config/nvim/lua/plugins/`:
|
||||
- `ui.lua` - UI 相关插件配置
|
||||
- `colorscheme.lua` - 主题配置
|
||||
- `example.lua` - 示例插件配置
|
||||
|
||||
## 🧪 测试验证
|
||||
|
||||
### 启动测试
|
||||
```bash
|
||||
# 基础启动测试
|
||||
~/.local/bin/nvim --headless -c "echo 'OK'" -c "qa"
|
||||
|
||||
# 配置加载测试
|
||||
~/.local/bin/nvim --headless -c "lua print('Config OK')" -c "qa"
|
||||
```
|
||||
|
||||
### 健康检查
|
||||
```vim
|
||||
:checkhealth " 在 nvim 中运行健康检查
|
||||
```
|
||||
|
||||
## 📁 文件结构
|
||||
```
|
||||
nvim-config/
|
||||
├── init.lua # 入口文件
|
||||
├── lazy-lock.json # 插件锁文件
|
||||
├── lazyvim.json # LazyVim 配置
|
||||
├── nvim # Neovim v0.11.5 AppImage
|
||||
├── lua/
|
||||
│ ├── config/
|
||||
│ │ ├── autocmds.lua # 自动命令
|
||||
│ │ ├── keymaps.lua # 键位映射
|
||||
│ │ ├── lazy.lua # Lazy.nvim 配置
|
||||
│ │ └── options.lua # 选项设置
|
||||
│ └── plugins/
|
||||
│ ├── colorscheme.lua # 主题配置
|
||||
│ ├── ui.lua # UI 插件配置
|
||||
│ └── example.lua # 示例配置
|
||||
└── stylua.toml # 代码格式化配置
|
||||
```
|
||||
|
||||
## 🚀 高级使用技巧
|
||||
|
||||
### 1. 快速文件操作
|
||||
```vim
|
||||
" 在当前行下方新建文件
|
||||
:enew
|
||||
" 保存文件
|
||||
:w
|
||||
" 退出
|
||||
:qa
|
||||
```
|
||||
|
||||
### 2. 窗口管理
|
||||
```vim
|
||||
" 水平分割
|
||||
:sp filename
|
||||
" 垂直分割
|
||||
:vs filename
|
||||
" 在分割间移动
|
||||
Ctrl+w h/j/k/l
|
||||
```
|
||||
|
||||
### 3. 搜索和替换
|
||||
```vim
|
||||
" 当前文件搜索
|
||||
/
|
||||
" 全局搜索
|
||||
:Telescope live_grep
|
||||
" 替换
|
||||
:%s/old/new/g
|
||||
```
|
||||
|
||||
## 📚 学习资源
|
||||
|
||||
1. **内置教程**:`:Tutor`
|
||||
2. **帮助系统**:`:help 主题`
|
||||
3. **LazyVim 文档**:按 `<leader>?`
|
||||
4. **GitHub 仓库**:https://github.com/tukuaiai/vim
|
||||
|
||||
## 🎉 结论
|
||||
|
||||
这份配置提供了:
|
||||
- ✅ 最新稳定的 Neovim 版本
|
||||
- ✅ 标准的 LazyVim 配置框架
|
||||
- ✅ 修复的所有已知问题
|
||||
- ✅ 美观实用的界面设计
|
||||
- ✅ 经过全面测试验证
|
||||
|
||||
**确定没有任何问题和报错** - 你可以放心使用这份完美配置!
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
-- bootstrap lazy.nvim, LazyVim and your plugins
|
||||
require("config.lazy")
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
{
|
||||
"LazyVim": { "branch": "main", "commit": "c64a61734fc9d45470a72603395c02137802bc6f" },
|
||||
"blink.cmp": { "branch": "main", "commit": "b19413d214068f316c78978b08264ed1c41830ec" },
|
||||
"bufferline.nvim": { "branch": "main", "commit": "655133c3b4c3e5e05ec549b9f8cc2894ac6f51b3" },
|
||||
"catppuccin": { "branch": "main", "commit": "193e123cdbc4dd3e86db883d55349e9587f0ded6" },
|
||||
"conform.nvim": { "branch": "master", "commit": "ffe26e8df8115c9665d24231f8a49fadb2d611ce" },
|
||||
"dracula": { "branch": "main", "commit": "ae752c13e95fb7c5f58da4b5123cb804ea7568ee" },
|
||||
"flash.nvim": { "branch": "main", "commit": "fcea7ff883235d9024dc41e638f164a450c14ca2" },
|
||||
"friendly-snippets": { "branch": "main", "commit": "572f5660cf05f8cd8834e096d7b4c921ba18e175" },
|
||||
"gitsigns.nvim": { "branch": "main", "commit": "5813e4878748805f1518cee7abb50fd7205a3a48" },
|
||||
"grug-far.nvim": { "branch": "main", "commit": "b58b2d65863f4ebad88b10a1ddd519e5380466e0" },
|
||||
"lazy.nvim": { "branch": "main", "commit": "85c7ff3711b730b4030d03144f6db6375044ae82" },
|
||||
"lazydev.nvim": { "branch": "main", "commit": "5231c62aa83c2f8dc8e7ba957aa77098cda1257d" },
|
||||
"lualine.nvim": { "branch": "master", "commit": "47f91c416daef12db467145e16bed5bbfe00add8" },
|
||||
"mason-lspconfig.nvim": { "branch": "main", "commit": "c55bd8a8fb191e24176c206a7af1dd51ce7276a5" },
|
||||
"mason.nvim": { "branch": "main", "commit": "57e5a8addb8c71fb063ee4acda466c7cf6ad2800" },
|
||||
"mini.ai": { "branch": "main", "commit": "bfb26d9072670c3aaefab0f53024b2f3729c8083" },
|
||||
"mini.icons": { "branch": "main", "commit": "ff2e4f1d29f659cc2bad0f9256f2f6195c6b2428" },
|
||||
"mini.pairs": { "branch": "main", "commit": "472ec50092a3314ec285d2db2baa48602d71fe93" },
|
||||
"neo-tree.nvim": { "branch": "main", "commit": "7a6f14c6edde0921333005cd738309b70138964b" },
|
||||
"noice.nvim": { "branch": "main", "commit": "7bfd942445fb63089b59f97ca487d605e715f155" },
|
||||
"nui.nvim": { "branch": "main", "commit": "de740991c12411b663994b2860f1a4fd0937c130" },
|
||||
"nvim-lint": { "branch": "master", "commit": "897f7771c1ca4b11659dfe372d9376acd9fe3097" },
|
||||
"nvim-lspconfig": { "branch": "master", "commit": "7af6f57d517d8cc68f249e0d27364c188a097812" },
|
||||
"nvim-treesitter": { "branch": "main", "commit": "2979e048b356cfd32dc419d5803dc356b9832adf" },
|
||||
"nvim-treesitter-textobjects": { "branch": "main", "commit": "76deedf0f1cec4496ef8d49b6d1f020f6d0c6ec9" },
|
||||
"nvim-ts-autotag": { "branch": "main", "commit": "c4ca798ab95b316a768d51eaaaee48f64a4a46bc" },
|
||||
"persistence.nvim": { "branch": "main", "commit": "b20b2a7887bd39c1a356980b45e03250f3dce49c" },
|
||||
"plenary.nvim": { "branch": "master", "commit": "b9fd5226c2f76c951fc8ed5923d85e4de065e509" },
|
||||
"snacks.nvim": { "branch": "main", "commit": "fe7cfe9800a182274d0f868a74b7263b8c0c020b" },
|
||||
"todo-comments.nvim": { "branch": "main", "commit": "31e3c38ce9b29781e4422fc0322eb0a21f4e8668" },
|
||||
"tokyonight.nvim": { "branch": "main", "commit": "5da1b76e64daf4c5d410f06bcb6b9cb640da7dfd" },
|
||||
"trouble.nvim": { "branch": "main", "commit": "bd67efe408d4816e25e8491cc5ad4088e708a69a" },
|
||||
"ts-comments.nvim": { "branch": "main", "commit": "123a9fb12e7229342f807ec9e6de478b1102b041" },
|
||||
"which-key.nvim": { "branch": "main", "commit": "3aab2147e74890957785941f0c1ad87d0a44c15a" }
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"extras": [
|
||||
|
||||
],
|
||||
"install_version": 8,
|
||||
"news": {
|
||||
"NEWS.md": "11866"
|
||||
},
|
||||
"version": 8
|
||||
}
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
-- Autocmds are automatically loaded on the VeryLazy event
|
||||
-- Default autocmds that are always set: https://github.com/LazyVim/LazyVim/blob/main/lua/lazyvim/config/autocmds.lua
|
||||
--
|
||||
-- Add any additional autocmds here
|
||||
-- with `vim.api.nvim_create_autocmd`
|
||||
--
|
||||
-- Or remove existing autocmds by their group name (which is prefixed with `lazyvim_` for the defaults)
|
||||
-- e.g. vim.api.nvim_del_augroup_by_name("lazyvim_wrap_spell")
|
||||
|
||||
-- 自动打开Neotree(使用标准LazyVim方式)
|
||||
vim.api.nvim_create_autocmd("VimEnter", {
|
||||
callback = function()
|
||||
-- 延迟执行,确保插件加载完成
|
||||
vim.defer_fn(function()
|
||||
vim.cmd("Neotree show")
|
||||
end, 50)
|
||||
end,
|
||||
})
|
||||
|
||||
-- 确保bufferline始终显示
|
||||
vim.api.nvim_create_autocmd("VimEnter", {
|
||||
callback = function()
|
||||
vim.o.showtabline = 2
|
||||
end,
|
||||
})
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
-- Keymaps are automatically loaded on the VeryLazy event
|
||||
-- Default keymaps that are always set: https://github.com/LazyVim/LazyVim/blob/main/lua/lazyvim/config/keymaps.lua
|
||||
-- Add any additional keymaps here
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
|
||||
if not (vim.uv or vim.loop).fs_stat(lazypath) then
|
||||
local lazyrepo = "https://github.com/folke/lazy.nvim.git"
|
||||
local out = vim.fn.system({ "git", "clone", "--filter=blob:none", "--branch=stable", lazyrepo, lazypath })
|
||||
if vim.v.shell_error ~= 0 then
|
||||
vim.api.nvim_echo({
|
||||
{ "Failed to clone lazy.nvim:\n", "ErrorMsg" },
|
||||
{ out, "WarningMsg" },
|
||||
{ "\nPress any key to exit..." },
|
||||
}, true, {})
|
||||
vim.fn.getchar()
|
||||
os.exit(1)
|
||||
end
|
||||
end
|
||||
vim.opt.rtp:prepend(lazypath)
|
||||
|
||||
require("lazy").setup({
|
||||
spec = {
|
||||
-- add LazyVim and import its plugins
|
||||
{ "LazyVim/LazyVim", import = "lazyvim.plugins" },
|
||||
-- import/override with your plugins
|
||||
{ import = "plugins" },
|
||||
},
|
||||
defaults = {
|
||||
-- By default, only LazyVim plugins will be lazy-loaded. Your custom plugins will load during startup.
|
||||
-- If you know what you're doing, you can set this to `true` to have all your custom plugins lazy-loaded by default.
|
||||
lazy = false,
|
||||
-- It's recommended to leave version=false for now, since a lot the plugin that support versioning,
|
||||
-- have outdated releases, which may break your Neovim install.
|
||||
version = false, -- always use the latest git commit
|
||||
-- version = "*", -- try installing the latest stable version for plugins that support semver
|
||||
},
|
||||
install = { colorscheme = { "tokyonight", "habamax" } },
|
||||
checker = {
|
||||
enabled = true, -- check for plugin updates periodically
|
||||
notify = false, -- notify on update
|
||||
}, -- automatically check for plugin updates
|
||||
performance = {
|
||||
rtp = {
|
||||
-- disable some rtp plugins
|
||||
disabled_plugins = {
|
||||
"gzip",
|
||||
-- "matchit",
|
||||
-- "matchparen",
|
||||
-- "netrwPlugin",
|
||||
"tarPlugin",
|
||||
"tohtml",
|
||||
"tutor",
|
||||
"zipPlugin",
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
-- 使用默认的tokyonight主题(LazyVim默认主题)
|
||||
-- 不需要手动设置,LazyVim会自动加载
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
-- Options are automatically loaded before lazy.nvim startup
|
||||
-- Default options that are always set: https://github.com/LazyVim/LazyVim/blob/main/lua/lazyvim/config/options.lua
|
||||
-- Add any additional options here
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
-- 默认使用 LazyVim 自带的 tokyonight 主题
|
||||
-- 如果需要其他主题,可以在这里添加
|
||||
|
||||
return {
|
||||
-- 可以在这里添加其他主题插件
|
||||
-- 例如:
|
||||
-- {
|
||||
-- "folke/tokyonight.nvim",
|
||||
-- opts = {
|
||||
-- style = "moon", -- 可选: night, storm, moon, day
|
||||
-- },
|
||||
-- },
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
-- Dracula 主题插件配置
|
||||
|
||||
return {
|
||||
{
|
||||
'Mofiqul/dracula.nvim',
|
||||
name = 'dracula',
|
||||
lazy = false,
|
||||
priority = 1000,
|
||||
config = function()
|
||||
-- 获取主题配置
|
||||
local dracula_config = require('themes.dracula')
|
||||
|
||||
-- 从环境变量或默认值获取样式
|
||||
local style = vim.env.NVIM_THEME_STYLE or 'dracula'
|
||||
|
||||
-- 设置主题
|
||||
require('dracula').setup(dracula_config.config(style))
|
||||
|
||||
-- 应用主题
|
||||
vim.cmd.colorscheme('dracula')
|
||||
end,
|
||||
},
|
||||
|
||||
-- Lualine 主题集成
|
||||
{
|
||||
'nvim-lualine/lualine.nvim',
|
||||
dependencies = { 'dracula' },
|
||||
opts = {
|
||||
options = {
|
||||
theme = 'dracula-nvim'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,197 +0,0 @@
|
|||
-- since this is just an example spec, don't actually load anything here and return an empty spec
|
||||
-- stylua: ignore
|
||||
if true then return {} end
|
||||
|
||||
-- every spec file under the "plugins" directory will be loaded automatically by lazy.nvim
|
||||
--
|
||||
-- In your plugin files, you can:
|
||||
-- * add extra plugins
|
||||
-- * disable/enabled LazyVim plugins
|
||||
-- * override the configuration of LazyVim plugins
|
||||
return {
|
||||
-- add gruvbox
|
||||
{ "ellisonleao/gruvbox.nvim" },
|
||||
|
||||
-- Configure LazyVim to load gruvbox
|
||||
{
|
||||
"LazyVim/LazyVim",
|
||||
opts = {
|
||||
colorscheme = "gruvbox",
|
||||
},
|
||||
},
|
||||
|
||||
-- change trouble config
|
||||
{
|
||||
"folke/trouble.nvim",
|
||||
-- opts will be merged with the parent spec
|
||||
opts = { use_diagnostic_signs = true },
|
||||
},
|
||||
|
||||
-- disable trouble
|
||||
{ "folke/trouble.nvim", enabled = false },
|
||||
|
||||
-- override nvim-cmp and add cmp-emoji
|
||||
{
|
||||
"hrsh7th/nvim-cmp",
|
||||
dependencies = { "hrsh7th/cmp-emoji" },
|
||||
---@param opts cmp.ConfigSchema
|
||||
opts = function(_, opts)
|
||||
table.insert(opts.sources, { name = "emoji" })
|
||||
end,
|
||||
},
|
||||
|
||||
-- change some telescope options and a keymap to browse plugin files
|
||||
{
|
||||
"nvim-telescope/telescope.nvim",
|
||||
keys = {
|
||||
-- add a keymap to browse plugin files
|
||||
-- stylua: ignore
|
||||
{
|
||||
"<leader>fp",
|
||||
function() require("telescope.builtin").find_files({ cwd = require("lazy.core.config").options.root }) end,
|
||||
desc = "Find Plugin File",
|
||||
},
|
||||
},
|
||||
-- change some options
|
||||
opts = {
|
||||
defaults = {
|
||||
layout_strategy = "horizontal",
|
||||
layout_config = { prompt_position = "top" },
|
||||
sorting_strategy = "ascending",
|
||||
winblend = 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
-- add pyright to lspconfig
|
||||
{
|
||||
"neovim/nvim-lspconfig",
|
||||
---@class PluginLspOpts
|
||||
opts = {
|
||||
---@type lspconfig.options
|
||||
servers = {
|
||||
-- pyright will be automatically installed with mason and loaded with lspconfig
|
||||
pyright = {},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
-- add tsserver and setup with typescript.nvim instead of lspconfig
|
||||
{
|
||||
"neovim/nvim-lspconfig",
|
||||
dependencies = {
|
||||
"jose-elias-alvarez/typescript.nvim",
|
||||
init = function()
|
||||
require("lazyvim.util").lsp.on_attach(function(_, buffer)
|
||||
-- stylua: ignore
|
||||
vim.keymap.set( "n", "<leader>co", "TypescriptOrganizeImports", { buffer = buffer, desc = "Organize Imports" })
|
||||
vim.keymap.set("n", "<leader>cR", "TypescriptRenameFile", { desc = "Rename File", buffer = buffer })
|
||||
end)
|
||||
end,
|
||||
},
|
||||
---@class PluginLspOpts
|
||||
opts = {
|
||||
---@type lspconfig.options
|
||||
servers = {
|
||||
-- tsserver will be automatically installed with mason and loaded with lspconfig
|
||||
tsserver = {},
|
||||
},
|
||||
-- you can do any additional lsp server setup here
|
||||
-- return true if you don't want this server to be setup with lspconfig
|
||||
---@type table<string, fun(server:string, opts:_.lspconfig.options):boolean?>
|
||||
setup = {
|
||||
-- example to setup with typescript.nvim
|
||||
tsserver = function(_, opts)
|
||||
require("typescript").setup({ server = opts })
|
||||
return true
|
||||
end,
|
||||
-- Specify * to use this function as a fallback for any server
|
||||
-- ["*"] = function(server, opts) end,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
-- for typescript, LazyVim also includes extra specs to properly setup lspconfig,
|
||||
-- treesitter, mason and typescript.nvim. So instead of the above, you can use:
|
||||
{ import = "lazyvim.plugins.extras.lang.typescript" },
|
||||
|
||||
-- add more treesitter parsers
|
||||
{
|
||||
"nvim-treesitter/nvim-treesitter",
|
||||
opts = {
|
||||
ensure_installed = {
|
||||
"bash",
|
||||
"html",
|
||||
"javascript",
|
||||
"json",
|
||||
"lua",
|
||||
"markdown",
|
||||
"markdown_inline",
|
||||
"python",
|
||||
"query",
|
||||
"regex",
|
||||
"tsx",
|
||||
"typescript",
|
||||
"vim",
|
||||
"yaml",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
-- since `vim.tbl_deep_extend`, can only merge tables and not lists, the code above
|
||||
-- would overwrite `ensure_installed` with the new value.
|
||||
-- If you'd rather extend the default config, use the code below instead:
|
||||
{
|
||||
"nvim-treesitter/nvim-treesitter",
|
||||
opts = function(_, opts)
|
||||
-- add tsx and treesitter
|
||||
vim.list_extend(opts.ensure_installed, {
|
||||
"tsx",
|
||||
"typescript",
|
||||
})
|
||||
end,
|
||||
},
|
||||
|
||||
-- the opts function can also be used to change the default opts:
|
||||
{
|
||||
"nvim-lualine/lualine.nvim",
|
||||
event = "VeryLazy",
|
||||
opts = function(_, opts)
|
||||
table.insert(opts.sections.lualine_x, {
|
||||
function()
|
||||
return "😄"
|
||||
end,
|
||||
})
|
||||
end,
|
||||
},
|
||||
|
||||
-- or you can return new options to override all the defaults
|
||||
{
|
||||
"nvim-lualine/lualine.nvim",
|
||||
event = "VeryLazy",
|
||||
opts = function()
|
||||
return {
|
||||
--[[add your custom lualine config here]]
|
||||
}
|
||||
end,
|
||||
},
|
||||
|
||||
-- use mini.starter instead of alpha
|
||||
{ import = "lazyvim.plugins.extras.ui.mini-starter" },
|
||||
|
||||
-- add jsonls and schemastore packages, and setup treesitter for json, json5 and jsonc
|
||||
{ import = "lazyvim.plugins.extras.lang.json" },
|
||||
|
||||
-- add any tools you want to have installed below
|
||||
{
|
||||
"williamboman/mason.nvim",
|
||||
opts = {
|
||||
ensure_installed = {
|
||||
"stylua",
|
||||
"shellcheck",
|
||||
"shfmt",
|
||||
"flake8",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
return {
|
||||
{
|
||||
"nvim-neo-tree/neo-tree.nvim",
|
||||
opts = {
|
||||
filesystem = {
|
||||
filtered_items = {
|
||||
hide_dotfiles = false,
|
||||
hide_gitignored = false,
|
||||
},
|
||||
},
|
||||
window = {
|
||||
position = "left",
|
||||
width = 30,
|
||||
mapping_options = {
|
||||
noremap = true,
|
||||
nowait = true,
|
||||
},
|
||||
},
|
||||
},
|
||||
config = function(_, opts)
|
||||
require("neo-tree").setup(opts)
|
||||
-- Neotree 打开逻辑已移到 autocmds.lua,这里不再重复
|
||||
end,
|
||||
},
|
||||
{
|
||||
"akinsho/bufferline.nvim",
|
||||
event = "VeryLazy",
|
||||
opts = {
|
||||
options = {
|
||||
mode = "buffers", -- set to "tabs" to only show tabpages instead
|
||||
numbers = "ordinal",
|
||||
close_command = function(bufnr) vim.api.nvim_buf_delete(bufnr, { force = true }) end,
|
||||
right_mouse_command = function(bufnr) vim.api.nvim_buf_delete(bufnr, { force = true }) end,
|
||||
left_mouse_command = "buffer",
|
||||
middle_mouse_command = nil,
|
||||
indicator = {
|
||||
style = "icon",
|
||||
icon = "▎",
|
||||
},
|
||||
buffer_close_icon = "",
|
||||
modified_icon = "●",
|
||||
close_icon = "",
|
||||
left_trunc_marker = "",
|
||||
right_trunc_marker = "",
|
||||
max_name_length = 18,
|
||||
max_prefix_length = 15,
|
||||
tab_size = 18,
|
||||
truncate_names = true,
|
||||
color_icons = true,
|
||||
show_buffer_icons = true,
|
||||
show_buffer_close_icons = true,
|
||||
show_close_icon = true,
|
||||
show_tab_indicators = true,
|
||||
persist_buffer_sort = true,
|
||||
separator_style = "thin",
|
||||
enforce_regular_tabs = false,
|
||||
always_show_bufferline = true,
|
||||
hover = {
|
||||
enabled = true,
|
||||
delay = 200,
|
||||
reveal = {'close'}
|
||||
},
|
||||
sort_by = 'insert_after_current',
|
||||
},
|
||||
},
|
||||
config = function(_, opts)
|
||||
require("bufferline").setup(opts)
|
||||
end,
|
||||
},
|
||||
}
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
-- Dracula 主题配置
|
||||
-- 支持多种变体: dracula, dracula-soft, day
|
||||
|
||||
local M = {}
|
||||
|
||||
M.config = function(style)
|
||||
local opts = {
|
||||
-- 主题变体: dracula, dracula-soft, day
|
||||
theme = style or 'dracula',
|
||||
|
||||
-- 透明背景
|
||||
transparent_bg = false,
|
||||
|
||||
-- 斜体注释
|
||||
italic_comment = true,
|
||||
|
||||
-- 显示文件末尾的 ~ 符号
|
||||
show_end_of_buffer = true,
|
||||
|
||||
-- Lualine 背景色
|
||||
lualine_bg_color = '#44475a',
|
||||
}
|
||||
|
||||
-- 高级自定义选项(可选)
|
||||
if style == 'soft' then
|
||||
opts.colors = {
|
||||
-- 更柔和的背景色
|
||||
bg = '#21222c',
|
||||
fg = '#f8f8f2',
|
||||
}
|
||||
elseif style == 'day' then
|
||||
opts.colors = {
|
||||
-- 浅色主题配色
|
||||
bg = '#f8f8f2',
|
||||
fg = '#282a36',
|
||||
}
|
||||
end
|
||||
|
||||
return opts
|
||||
end
|
||||
|
||||
-- 主题信息
|
||||
M.info = {
|
||||
name = 'dracula',
|
||||
plugin = 'Mofiqul/dracula.nvim',
|
||||
variants = {
|
||||
{ name = 'dracula', desc = '经典深色主题' },
|
||||
{ name = 'dracula-soft', desc = '柔和深色主题' },
|
||||
{ name = 'day', desc = '浅色主题' },
|
||||
},
|
||||
features = {
|
||||
'支持透明背景',
|
||||
'斜体注释',
|
||||
'完整的 LSP 和 Treesitter 支持',
|
||||
'Lualine 主题集成',
|
||||
'多插件支持(Telescope, NvimTree 等)',
|
||||
}
|
||||
}
|
||||
|
||||
return M
|
||||
Binary file not shown.
|
|
@ -1,3 +0,0 @@
|
|||
indent_type = "Spaces"
|
||||
indent_width = 2
|
||||
column_width = 120
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
#!/usr/bin/env lua
|
||||
-- 主题预览器 - 简化版
|
||||
-- 用法: nvim -u theme-previewer.lua
|
||||
|
||||
-- 临时配置目录
|
||||
local tmp_dir = "/tmp/nvim-theme-preview"
|
||||
os.execute("mkdir -p " .. tmp_dir)
|
||||
|
||||
-- 写入基础配置
|
||||
local init_lua = tmp_dir .. "/init.lua"
|
||||
local file = io.open(init_lua, "w")
|
||||
if not file then
|
||||
print("无法创建临时配置")
|
||||
os.exit(1)
|
||||
end
|
||||
|
||||
file:write([[
|
||||
-- 最小化主题预览配置
|
||||
vim.opt.termguicolors = true
|
||||
vim.opt.background = "dark"
|
||||
|
||||
-- 主题列表
|
||||
local themes = {
|
||||
dracula = function()
|
||||
package.path = package.path .. ";" .. vim.fn.stdpath("config") .. "/lua/?.lua"
|
||||
require('plugins.dracula')
|
||||
end,
|
||||
onedark = function()
|
||||
vim.cmd [[colorscheme onedark]]
|
||||
end,
|
||||
tokyonight = function()
|
||||
require('tokyonight').setup({style = 'night'})
|
||||
vim.cmd.colorscheme('tokyonight')
|
||||
end,
|
||||
catppuccin = function()
|
||||
require('catppuccin').setup({flavour = 'mocha'})
|
||||
vim.cmd.colorscheme('catppuccin')
|
||||
end,
|
||||
gruvbox = function()
|
||||
require('gruvbox').setup({contrast = 'hard'})
|
||||
vim.cmd.colorscheme('gruvbox')
|
||||
end,
|
||||
}
|
||||
|
||||
-- 获取主题参数
|
||||
local theme = arg[1] or 'dracula'
|
||||
|
||||
-- 应用主题
|
||||
if themes[theme] then
|
||||
themes[theme]()
|
||||
else
|
||||
print("未知主题: " .. theme)
|
||||
print("可用主题: " .. table.concat(vim.tbl_keys(themes), ", "))
|
||||
end
|
||||
|
||||
-- 预览内容
|
||||
vim.api.nvim_buf_set_lines(0, 0, -1, false, {
|
||||
"🎨 " .. theme .. " 主题预览",
|
||||
"",
|
||||
"-- Lua 代码示例",
|
||||
"local function hello_world()",
|
||||
" print('Hello, World!') -- 注释",
|
||||
" local dracula = '🧛'",
|
||||
" return dracula",
|
||||
"end",
|
||||
"",
|
||||
"-- JavaScript 代码示例",
|
||||
"function hello() {",
|
||||
" console.log('Hello, World!');",
|
||||
" const theme = '" .. theme .. "';",
|
||||
" return theme;",
|
||||
"}",
|
||||
"",
|
||||
"快捷键: q 退出预览",
|
||||
})
|
||||
|
||||
-- 设置快捷键
|
||||
vim.keymap.set('n', 'q', ':qa!<CR>', {noremap = true, silent = true})
|
||||
vim.keymap.set('n', '<Esc>', ':qa!<CR>', {noremap = true, silent = true})
|
||||
|
||||
print("🎨 预览 " .. theme .. " 主题")
|
||||
print("按 q 退出预览")
|
||||
]])
|
||||
|
||||
file:close()
|
||||
|
||||
-- 启动 nvim
|
||||
local cmd = string.format("nvim -u %s", init_lua)
|
||||
os.execute(cmd)
|
||||
|
||||
-- 清理
|
||||
os.execute("rm -rf " .. tmp_dir)
|
||||
|
|
@ -1,159 +0,0 @@
|
|||
#!/usr/bin/env lua
|
||||
-- Neovim 主题切换脚本
|
||||
-- 用法: nvim -l theme-switcher.lua <主题名> [样式]
|
||||
|
||||
local themes = {
|
||||
dracula = {
|
||||
plugin = 'Mofiqul/dracula.nvim',
|
||||
setup = function(style)
|
||||
local opts = {
|
||||
theme = style or 'dracula', -- dracula, dracula-soft, day
|
||||
transparent_bg = false,
|
||||
italic_comment = true,
|
||||
show_end_of_buffer = true,
|
||||
}
|
||||
require('dracula').setup(opts)
|
||||
end
|
||||
},
|
||||
catppuccin = {
|
||||
plugin = 'catppuccin/nvim',
|
||||
setup = function(style)
|
||||
local flavours = { 'mocha', 'macchiato', 'frappe', 'latte' }
|
||||
local flavour = style and flavours[tonumber(style)] or 'mocha'
|
||||
require('catppuccin').setup({ flavour = flavour })
|
||||
end
|
||||
},
|
||||
tokyonight = {
|
||||
plugin = 'folke/tokyonight.nvim',
|
||||
setup = function(style)
|
||||
local opts = {
|
||||
style = style or 'night', -- night, storm, day, moon
|
||||
transparent = false,
|
||||
terminal_colors = true,
|
||||
}
|
||||
require('tokyonight').setup(opts)
|
||||
end
|
||||
},
|
||||
gruvbox = {
|
||||
plugin = 'ellisonleao/gruvbox.nvim',
|
||||
setup = function(style)
|
||||
local opts = {
|
||||
contrast = style or 'hard', -- soft, medium, hard
|
||||
transparent_mode = false,
|
||||
}
|
||||
require('gruvbox').setup(opts)
|
||||
end
|
||||
},
|
||||
onedark = {
|
||||
plugin = 'navarasu/onedark.nvim',
|
||||
setup = function(style)
|
||||
local opts = {
|
||||
style = style or 'dark', -- dark, darker, cool, deep, warm, warmer
|
||||
transparent = false,
|
||||
}
|
||||
require('onedark').setup(opts)
|
||||
end
|
||||
}
|
||||
}
|
||||
|
||||
-- 解析命令行参数
|
||||
local theme_name = arg[1]
|
||||
local style = arg[2]
|
||||
|
||||
if not theme_name then
|
||||
print("\n🎨 Neovim 主题切换器")
|
||||
print("用法: nvim -l theme-switcher.lua <主题> [样式]")
|
||||
print("\n可用主题:")
|
||||
for name, info in pairs(themes) do
|
||||
print(string.format(" %-12s %s", name, info.plugin))
|
||||
end
|
||||
print("\n示例:")
|
||||
print(" nvim -l theme-switcher.lua dracula dracula-soft")
|
||||
print(" nvim -l theme-switcher.lua catppuccin 1 (1=mocha,2=macchiato,3=frappe,4=latte)")
|
||||
print(" nvim -l theme-switcher.lua tokyonight storm")
|
||||
os.exit(0)
|
||||
end
|
||||
|
||||
-- 检查主题是否存在
|
||||
if not themes[theme_name] then
|
||||
print("❌ 未知主题: " .. theme_name)
|
||||
print("可用主题: " .. table.concat(vim.tbl_keys(themes), ", "))
|
||||
os.exit(1)
|
||||
end
|
||||
|
||||
-- 生成临时配置文件
|
||||
local config_content = string.format([[
|
||||
-- 临时主题配置 - %s
|
||||
vim.cmd [[set runtimepath+=~/.config/nvim]]
|
||||
|
||||
-- 安装主题插件
|
||||
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
|
||||
if not vim.loop.fs_stat(lazypath) then
|
||||
vim.fn.system({
|
||||
"git", "clone", "--filter=blob:none",
|
||||
"https://github.com/folke/lazy.nvim.git",
|
||||
"--branch=stable", lazypath,
|
||||
})
|
||||
end
|
||||
vim.opt.rtp:prepend(lazypath)
|
||||
|
||||
require("lazy").setup({
|
||||
{ "%s", priority = 1000 },
|
||||
})
|
||||
|
||||
-- 设置主题
|
||||
%s
|
||||
vim.cmd.colorscheme("%s")
|
||||
|
||||
-- 打开一个新文件查看效果
|
||||
vim.cmd [[enew]]
|
||||
vim.api.nvim_buf_set_lines(0, 0, -1, false, {
|
||||
"🎨 主题预览: %s",
|
||||
"",
|
||||
"function hello() {",
|
||||
" console.log('Hello, World!');",
|
||||
" // This is a comment",
|
||||
" const dracula = '🧛';",
|
||||
" return dracula;",
|
||||
"}",
|
||||
"",
|
||||
"local themes = {",
|
||||
" dracula = 'dark',",
|
||||
" catppuccin = 'soft',",
|
||||
"}",
|
||||
})
|
||||
|
||||
-- 设置快捷键
|
||||
vim.keymap.set('n', 'q', ':qa!<CR>', { noremap = true, silent = true })
|
||||
vim.keymap.set('n', '<Esc>', ':qa!<CR>', { noremap = true, silent = true })
|
||||
|
||||
print("\n🎨 主题预览: %s (%s)")
|
||||
print("按 q 或 Esc 退出预览")
|
||||
]],
|
||||
theme_name,
|
||||
themes[theme_name].plugin,
|
||||
themes[theme_name].setup(style),
|
||||
theme_name,
|
||||
theme_name,
|
||||
theme_name,
|
||||
style or "default"
|
||||
)
|
||||
|
||||
-- 写入临时配置
|
||||
local tmp_config = "/tmp/nvim-theme-preview.lua"
|
||||
local file = io.open(tmp_config, "w")
|
||||
if file then
|
||||
file:write(config_content)
|
||||
file:close()
|
||||
|
||||
-- 启动 neovim 预览
|
||||
local cmd = string.format("nvim -u %s", tmp_config)
|
||||
print(string.format("\n🎨 启动 %s 主题预览 (%s)...", theme_name, style or "default"))
|
||||
os.execute(cmd)
|
||||
|
||||
-- 清理临时文件
|
||||
os.remove(tmp_config)
|
||||
else
|
||||
print("❌ 无法创建临时配置文件")
|
||||
os.exit(1)
|
||||
end
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
# Python
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
*.so
|
||||
.Python
|
||||
venv/
|
||||
env/
|
||||
ENV/
|
||||
|
||||
# 凭据和密钥
|
||||
credentials.json
|
||||
token.json
|
||||
*.key
|
||||
.env
|
||||
|
||||
# IDE
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# 临时文件
|
||||
*.tmp
|
||||
*.bak
|
||||
*.log
|
||||
temp/
|
||||
|
||||
# Excel临时文件
|
||||
~$*.xlsx
|
||||
~$*.xls
|
||||
|
||||
# 协作记录文件
|
||||
ticket.md
|
||||
|
|
@ -1,250 +0,0 @@
|
|||
<!--
|
||||
-------------------------------------------------------------------------------
|
||||
项目头部区域 (HEADER)
|
||||
这是用户第一眼看到的地方。一个精美的横幅或 Logo 能立刻提升专业感。
|
||||
-------------------------------------------------------------------------------
|
||||
-->
|
||||
<p align="center">
|
||||
<!-- 建议尺寸: 1280x640px。可以使用 Canva, Figma 或 https://banners.beyondco.de/ 等工具制作 -->
|
||||
<img src="https://github.com/tukuaiai.png" alt="项目横幅">
|
||||
</p>
|
||||
|
||||
<div align="center">
|
||||
|
||||
# Prompt Library
|
||||
|
||||
**一个全面的高质量AI提示词库,支持Excel和Markdown格式之间的双向转换。**
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
徽章区域 (BADGES)
|
||||
从 https://shields.io/ 生成。选择与你的品牌色一致的颜色。
|
||||
建议包含:构建状态, 版本, 许可证, 语言, 代码大小, 下载量, 社区链接等。
|
||||
-->
|
||||
<p>
|
||||
<a href="https://github.com/tukuaiai/prompt-library/actions/workflows/sync.yml"><img src="https://img.shields.io/github/actions/workflow/status/tukuaiai/prompt-library/sync.yml?style=for-the-badge" alt="构建状态"></a>
|
||||
<a href="https://github.com/tukuaiai/prompt-library/releases"><img src="https://img.shields.io/github/v/release/tukuaiai/prompt-library?style=for-the-badge" alt="最新版本"></a>
|
||||
<a href="LICENSE"><img src="https://img.shields.io/github/license/tukuaiai/prompt-library?style=for-the-badge" alt="许可证"></a>
|
||||
<a href="https://github.com/tukuaiai/prompt-library"><img src="https://img.shields.io/github/languages/top/tukuaiai/prompt-library?style=for-the-badge" alt="主要语言"></a>
|
||||
<a href="https://github.com/tukuaiai/prompt-library"><img src="https://img.shields.io/github/languages/code-size/tukuaiai/prompt-library?style=for-the-badge" alt="代码大小"></a>
|
||||
</p>
|
||||
|
||||
[✨ 功能特性](#-功能特性) •
|
||||
[🚀 快速开始](#-快速开始) •
|
||||
[⚙️ API参考](#️-api参考) •
|
||||
[🤝 参与贡献](#-参与贡献) •
|
||||
[🗺️ 路线图](#️-路线图)
|
||||
|
||||
</div>
|
||||
|
||||
<!--
|
||||
-------------------------------------------------------------------------------
|
||||
概览与核心视觉区域 (OVERVIEW & VISUALS)
|
||||
展示项目最直观的部分。
|
||||
-------------------------------------------------------------------------------
|
||||
-->
|
||||
|
||||
---
|
||||
|
||||
## 🖼️ 概览与演示
|
||||
|
||||
本词库是一个结构化的、高质量的AI提示词(Prompts)集合,旨在为开发人员、研究人员和内容创作者提供强大而灵活的工具。与许多静态的提示词列表不同,本项目提供了一个双向转换的工作流程,允许用户在易于协作的Excel格式和便于版本控制的Markdown格式之间无缝切换。
|
||||
|
||||
> **核心理念**: 让高质量的提示词像代码一样被管理、分享和迭代。
|
||||
|
||||
<p align="center">
|
||||
<!-- 建议使用 GIF,工具: ScreenToGif, GIPHY CAPTURE -->
|
||||
<img src="https://user-images.githubusercontent.com/12523395/269150161-1a83689c-2f3a-4a0e-8d18-114cec03be8d.gif" alt="项目演示动画" width="80%">
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
-------------------------------------------------------------------------------
|
||||
主要内容区域 (MAIN CONTENT)
|
||||
详细介绍项目的方方面面。
|
||||
-------------------------------------------------------------------------------
|
||||
-->
|
||||
|
||||
## ✨ 功能特性
|
||||
|
||||
- 📊 **双向转换**: 支持Excel ↔️ Markdown格式互转,兼顾易用性与版本控制。
|
||||
- 🗂️ **结构化管理**: 包含多个分类,覆盖从软件工程到哲学思辨的广泛领域。
|
||||
- 🤖 **多平台兼容**: 提示词设计兼容Claude、GPT、Gemini等主流AI模型。
|
||||
- 🛠️ **自动化工具**: 提供命令行工具,支持批量转换和管理。
|
||||
- 🎨 **易于扩展**: 可以方便地添加新的提示词、分类和自定义属性。
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ 架构与工作流程
|
||||
|
||||
本项目的工作流程围绕“以结构化数据为中心”的思想构建。
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
subgraph "Excel-First 工作流"
|
||||
A[1. 在 Excel 中编辑提示词] --> B{运行转换脚本};
|
||||
end
|
||||
|
||||
subgraph "Git-Native 工作流"
|
||||
D[3. 在 Markdown 文件中编辑] --> E{运行转换脚本};
|
||||
end
|
||||
|
||||
subgraph "中央产物"
|
||||
B --> C[2. 生成结构化的 Markdown 文件];
|
||||
E --> F[4. 更新或生成 Excel 文件]
|
||||
end
|
||||
|
||||
style A fill:#D5E8D4
|
||||
style D fill:#DAE8FC
|
||||
style C fill:#F8CECC
|
||||
style F fill:#F8CECC
|
||||
```
|
||||
这个流程确保了无论是喜欢电子表格的非技术人员,还是习惯于Git和代码编辑器的开发人员,都可以高效地协作。
|
||||
|
||||
---
|
||||
|
||||
## 🚀 快速开始
|
||||
|
||||
### 1. 环境依赖
|
||||
|
||||
- [Python](https://www.python.org/) >= 3.8
|
||||
|
||||
### 2. 安装
|
||||
|
||||
<details>
|
||||
<summary><b>从源码构建</b></summary>
|
||||
|
||||
```bash
|
||||
git clone https://github.com/tukuaiai/prompt-library.git
|
||||
cd prompt-library
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
</details>
|
||||
|
||||
### 3. 使用
|
||||
|
||||
<details>
|
||||
<summary><b>Excel → Markdown 转换</b></summary>
|
||||
|
||||
```bash
|
||||
# 运行交互式转换
|
||||
python3 main.py
|
||||
```
|
||||
程序将扫描 `prompt_excel` 目录下的 `.xlsx` 文件,并让你选择一个进行转换。结果将输出到 `prompt_docs` 目录下一个带时间戳的文件夹中。
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>Markdown → Excel 转换</b></summary>
|
||||
|
||||
```bash
|
||||
# 运行交互式转换
|
||||
python3 main.py
|
||||
```
|
||||
程序将扫描 `prompt_docs` 目录,让你选择一个文档集,然后将其转换回 Excel 文件,并输出到 `prompt_excel` 目录下一个带时间戳的文件夹中。
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>非交互式转换</b></summary>
|
||||
|
||||
```bash
|
||||
# 指定要转换的 Excel 文件
|
||||
python3 main.py --select "prompt_excel/your_file.xlsx"
|
||||
|
||||
# 指定要转换的 Markdown 目录
|
||||
python3 main.py --select "prompt_docs/your_docs_folder"
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
<details>
|
||||
<summary>❓ 常见问题 (FAQ) (可选)</summary>
|
||||
|
||||
- **Q: 为什么转换会失败?**
|
||||
- **A:** 请确保您的Excel文件格式与提供的示例一致,特别是工作表(Sheet)的名称和列的标题。
|
||||
|
||||
- **Q: 我可以添加自己的转换逻辑吗?**
|
||||
- **A:** 当然可以。核心逻辑位于 `scripts/` 目录下,您可以自由修改或扩展它们。
|
||||
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
-------------------------------------------------------------------------------
|
||||
社区与治理区域 (COMMUNITY & GOVERNANCE)
|
||||
展示项目的健康度和发展方向。
|
||||
-------------------------------------------------------------------------------
|
||||
-->
|
||||
|
||||
## 🗺️ 路线图
|
||||
|
||||
```mermaid
|
||||
gantt
|
||||
title 项目发展路线图
|
||||
dateFormat YYYY-MM
|
||||
section 核心功能
|
||||
双向转换脚本 :done, 2024-10, 30d
|
||||
交互式CLI :done, 2024-11, 20d
|
||||
section 未来计划
|
||||
Web界面 :2025-01, 30d
|
||||
更丰富的导出格式 :2025-02, 20d
|
||||
云同步功能 : 2025-03, 30d
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🤝 参与贡献
|
||||
|
||||
我们热烈欢迎各种形式的贡献!如果您对本项目有任何想法或建议,请随时开启一个 [Issue](https://github.com/tukuaiai/prompt-library/issues) 或提交一个 [Pull Request](https://github.com/tukuaiai/prompt-library/pulls)。
|
||||
|
||||
在您开始之前,请花点时间阅读我们的 [**贡献指南 (CONTRIBUTING.md)**](CONTRIBUTING.md) 和 [**行为准则 (CODE_OF_CONDUCT.md)**](CODE_OF_CONDUCT.md)。
|
||||
|
||||
### ✨ 贡献者们
|
||||
|
||||
感谢所有为本项目做出贡献的开发者!
|
||||
|
||||
<a href="https://github.com/tukuaiai/prompt-library/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=tukuaiai/prompt-library" />
|
||||
</a>
|
||||
|
||||
---
|
||||
|
||||
## 🛡️ 安全策略
|
||||
|
||||
我们非常重视项目的安全性。如果您发现了任何安全漏洞,请不要公开讨论,而是通过电子邮件 `tukuaiai@example.com` 与我们联系。
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
-------------------------------------------------------------------------------
|
||||
页脚区域 (FOOTER)
|
||||
最后的行动号召和感谢。
|
||||
-------------------------------------------------------------------------------
|
||||
-->
|
||||
|
||||
## 📜 许可证
|
||||
|
||||
本项目采用 [MIT](LICENSE) 许可证。
|
||||
|
||||
---
|
||||
|
||||
<div align="center">
|
||||
|
||||
**如果这个项目对您有帮助,请不要吝啬您的 Star ⭐!**
|
||||
|
||||
<!-- Star History: https://star-history.com/ -->
|
||||
<a href="https://star-history.com/#tukuaiai/prompt-library&Date">
|
||||
<img src="https://api.star-history.com/svg?repos=tukuaiai/prompt-library&type=Date" alt="Star History Chart" width="80%">
|
||||
</a>
|
||||
|
||||
<br>
|
||||
|
||||
**Made with ❤️ by tukuaiai**
|
||||
|
||||
[⬆ 回到顶部](#prompt-library)
|
||||
|
||||
</div>
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -1,38 +0,0 @@
|
|||
# 💰 项目支持(从Excel提取)
|
||||
|
||||
|
||||
## 支持说明
|
||||
**礼貌要饭地址** - 如果这个项目对您有帮助,欢迎通过以下方式支持
|
||||
|
||||
|
||||
## 加密货币钱包地址
|
||||
|
||||
### 主流网络支持
|
||||
|
||||
|
||||
| 网络名称 | 钱包地址 | Excel行号 |
|
||||
|----------|----------|-----------|
|
||||
|
||||
| **TRON** | `TQtBXCSTwLFHjBqTS4rNUp7ufiGx51BRey` | 第12行 |
|
||||
|
||||
| **SOL** | `HjYhozVf9AQmfv7yv79xSNs6uaEU5oUk2USasYQfUYau` | 第13行 |
|
||||
|
||||
| **ETH** | `0xa396923a71ee7D9480b346a17dDeEb2c0C287BBC` | 第14行 |
|
||||
|
||||
| **BSC** | `0xa396923a71ee7D9480b346a17dDeEb2c0C287BBC` | 第15行 |
|
||||
|
||||
| **BTC** | `bc1plslluj3zq3snpnnczplu7ywf37h89dyudqua04pz4txwh8z5z5vsre7nlm` | 第16行 |
|
||||
|
||||
| **SUI** | `0xb720c98a48c77f2d49d375932b2867e793029e6337f1562522640e4f84203d2e` | 第17行 |
|
||||
|
||||
|
||||
⚠️ **重要提醒**: 广告位(注意识别风险)
|
||||
|
||||
|
||||
### 使用建议
|
||||
1. 请确认钱包地址的准确性
|
||||
2. 建议小额测试后再进行大额转账
|
||||
3. 不同网络的转账费用不同,请选择合适的网络
|
||||
|
||||
---
|
||||
*钱包地址来源: prompt (3).xlsx*
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
# 🛠️ 工具与资源(从Excel提取)
|
||||
|
||||
|
||||
## AI优化工具
|
||||
|
||||
|
||||
### OpenAI 提示词优化平台
|
||||
- **URL**: https://platform.openai.com/chat/edit?models=gpt-5&optimize=true
|
||||
- **描述**: openai提示词优化网站
|
||||
- **数据来源**: Excel表格第7行
|
||||
|
||||
|
||||
### 工具
|
||||
- **URL**: https://aistudio.google.com/
|
||||
- **描述**: 打开 Gemini 2.5 Pro
|
||||
- **数据来源**: Excel表格第4行
|
||||
|
||||
|
||||
## 社交媒体
|
||||
|
||||
|
||||
### Twitter/X 账号
|
||||
- **URL**: https://x.com/123olp
|
||||
- **描述**: 点击关注我的推特,获取最新动态,首页接广告位
|
||||
- **数据来源**: Excel表格第9行
|
||||
|
||||
|
||||
## 使用建议
|
||||
|
||||
1. **OpenAI优化器**: 可以用来测试和改进本库中的提示词
|
||||
2. **社交媒体**: 关注获取项目更新和使用技巧
|
||||
3. **集成方式**: 可以将这些工具集成到自动化工作流中
|
||||
|
||||
---
|
||||
*数据来源: prompt (3).xlsx*
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,127 +0,0 @@
|
|||
# 提示词库结构与 Excel 互转规范
|
||||
|
||||
> 本规范用于约束“提示词库”在文件系统与 Excel 之间的一致结构、命名与转换规则,确保后期自动化同步、增量更新与团队协作的稳定性。
|
||||
|
||||
## 1. 目录结构(约定)
|
||||
|
||||
```
|
||||
prompt-library/
|
||||
├── prompts/ # 核心输出目录
|
||||
│ ├── <工作表名称-已净化>/ # 每个 Excel 子表对应一个文件夹
|
||||
│ │ ├── (行,列)_标题.md # 单元格 → 单文件(仅包含提示词文本)
|
||||
│ │ └── index.md # 该表分类索引(自动生成)
|
||||
│ └── index.json # 全局 JSON 索引(自动生成)
|
||||
├── docs/
|
||||
│ ├── tools.md # 工具/链接(从表自动提取)
|
||||
│ ├── support.md # 支持/钱包地址(从表自动提取)
|
||||
│ ├── excel-data.md # Excel 原始数据快照(自动生成)
|
||||
│ └── STRUCTURE_AND_CONVERSION_SPEC.md # 本规范
|
||||
└── scripts/
|
||||
├── convert_local.py # Excel ↔ 文件 的本地转换器(实现 Excel→文件)
|
||||
├── config.yaml # 可选配置(数据源/策略)
|
||||
└── requirements.txt # 依赖
|
||||
```
|
||||
|
||||
- 只允许在 `prompts/<工作表名称-已净化>/` 下新增/修改提示词文件,其它自动文件(如 `index.md`、`index.json`)由转换器生成,禁止手改。
|
||||
|
||||
## 2. 命名与净化(Sanitization)
|
||||
|
||||
- 工作表文件夹名:对原始 Excel 工作表名称执行净化:
|
||||
- 移除非法字符:`\\ / : * ? " < > | \r \n`
|
||||
- 将空格替换为下划线 `_`
|
||||
- 最长 60 字符,超长截断
|
||||
- 示例:`"学习 提示词/1?"` → `"学习_提示词1"`
|
||||
- 提示词文件名:`(行,列)_标题.md`
|
||||
- 行、列为 1 基索引(Excel 中第 1 行/第 1 列即 1)
|
||||
- 标题来源:该行第一个非空单元格的首行文本的前若干词(用于人读),同样执行净化
|
||||
- 标题仅用于文件名可读性,回写 Excel 时忽略
|
||||
|
||||
## 3. 文件内容规范(强约束)
|
||||
|
||||
- 每个提示词文件(.md)内容必须是“对应单元格的原始文本”,末尾追加一个换行;不允许包含:
|
||||
- Markdown 标题/分隔线/元信息
|
||||
- 代码围栏(```)
|
||||
- 版本历史/导航/时间戳
|
||||
- 编码:UTF-8,换行:LF
|
||||
|
||||
## 4. Excel → 文件 的生成规则
|
||||
|
||||
- 每个工作表 → `prompts/<工作表名称-已净化>/`
|
||||
- 行类型判定(逐行):
|
||||
- 提示词行:该行至少一列非空,且不属于工具/社交/钱包/警告/占位
|
||||
- 工具/链接:同行包含 `http` 且非 X/Twitter 链接 → 归档 `docs/tools.md`
|
||||
- 社交:链接中包含 `x.com`/`twitter.com` → 归档 `docs/tools.md`
|
||||
- 钱包区块:先出现“表头”(含“网络/网络名称”且含“礼貌要饭地址/钱包/地址”),其后若干行按 `(网络, 地址)` 提取 → 归档 `docs/support.md`
|
||||
- 警告:包含“广告位” → 记录为警告
|
||||
- 占位:`...`/`….`/`....` → 忽略
|
||||
- 对每个提示词行:
|
||||
- 对该行每个非空列 `c` 生成:`(r,c)_标题.md`,文件正文 = 单元格纯文本
|
||||
- 自动索引:
|
||||
- `prompts/<表>/index.md`:统计、列表与版本矩阵(供浏览用,自动生成)
|
||||
- `prompts/index.json`:全局结构化索引,含各表、各行版本与外部资源(自动生成)
|
||||
- `docs/excel-data.md`:各表数据快照(截取前 3 列),便于审计
|
||||
|
||||
## 5. 文件 → Excel 的回写规则(规范定义,供实现)
|
||||
|
||||
> 说明:当前脚本已实现 Excel→文件;本节定义未来“文件→Excel”时的规范,以便实现反向同步器保持一致性。
|
||||
|
||||
- 工作表名:优先使用 `prompts/index.json` 中的 `categories[].name` 作为原始工作表名;若缺失,采用文件夹名将 `_` 还原为空格(尽力而为)。
|
||||
- 单元格位置:
|
||||
- 解析文件名 `(r,c)_标题.md` 得到 1 基 `r,c`,写入 Excel 的第 `r` 行、第 `c` 列
|
||||
- 标题部分忽略,仅用于文件名可读
|
||||
- 写入值:文件全文(去掉末尾多余空行)即单元格值
|
||||
- 缺表/缺行列:自动创建工作表、扩展行列
|
||||
- 冲突:同一 `(r,c)` 出现多文件时应失败并报告(推荐),或采用“最后写入覆盖”(需在实现中明确开关)
|
||||
- 非提示词文档:`tools.md`、`support.md` 不默认回写;如需回写,应定义目标工作表名称与行布局(建议启用配置项)
|
||||
|
||||
## 6. 变更与校验
|
||||
|
||||
- 合法性检查:
|
||||
- 文件名需符合正则:`^\(\d+,\d+\)_.+\.md$`
|
||||
- 内容不得包含本规范禁止的附加信息(元信息、代码围栏等)
|
||||
- 冲突检测:同一 `(r,c)` 不允许多次定义
|
||||
- 兼容性:文件夹名与表名的映射以 `index.json` 为准;直接根据文件夹名还原可能出偏差
|
||||
|
||||
## 7. 自动化工具与用法
|
||||
|
||||
- 依赖安装:
|
||||
```bash
|
||||
python3 -m pip install -r prompt-library/scripts/requirements.txt
|
||||
```
|
||||
- 运行(Excel→文件):
|
||||
```bash
|
||||
python3 "prompt-library/scripts/convert_local.py" \
|
||||
--excel "prompt (2).xlsx"
|
||||
```
|
||||
- 行为摘要:
|
||||
- 为每个工作表生成一个同名(净化后)目录
|
||||
- 为每个非空单元格生成一个 `.md` 文件(仅含单元格文本)
|
||||
- 重新生成所有索引与快照文档
|
||||
|
||||
## 8. 新增提示词(两种路径)
|
||||
|
||||
- 在 Excel 中新增:
|
||||
- 在目标工作表的目标行、列填写文本
|
||||
- 运行转换脚本,生成对应 `(行,列)_标题.md`
|
||||
- 在文件系统中新增:
|
||||
- 到 `prompts/<工作表名称-已净化>/` 新建符合命名规范的文件
|
||||
- 文件正文仅填写提示词文本
|
||||
- 将在“文件→Excel”实现后由反向同步器写回相应 `(行,列)`
|
||||
|
||||
## 9. 设计取舍(Why)
|
||||
|
||||
- 只在提示词文件中保留“纯内容”,避免元信息造成噪声与二义性,便于复制/拼接/训练
|
||||
- 元信息、导航、统计统一由自动化生成到索引与文档中,降低手工维护成本
|
||||
- 以 `(行,列)` 作为跨介质的“主键”,确保 Excel 与文件的可逆映射
|
||||
|
||||
## 10. 版本与扩展
|
||||
|
||||
- 建议在 `scripts/config.yaml` 中引入可选项:
|
||||
- 反向同步开关与目标工作表名策略
|
||||
- 冲突策略(报错/覆盖)
|
||||
- 过滤器(忽略某些行/列/关键词)
|
||||
- 未来可扩展:GitHub Actions/CI 校验规范合规性;支持更多字段映射(如 tag、语言)。
|
||||
|
||||
---
|
||||
|
||||
本规范适用于本仓库的所有提示词数据。如需调整,请在 PR 中同步更新 `docs/STRUCTURE_AND_CONVERSION_SPEC.md` 并说明向后兼容策略。
|
||||
|
|
@ -1,274 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
r"""
|
||||
main.py
|
||||
|
||||
Unified controller for prompt-library conversions.
|
||||
|
||||
Capabilities
|
||||
- Scan default folders and let user select a source to convert
|
||||
- If you select an Excel file (.xlsx), it will convert Excel → Docs
|
||||
- If you select a prompt docs folder, it will convert Docs → Excel
|
||||
- Fully non-interactive CLI flags are also supported (automation-friendly)
|
||||
|
||||
Conventions (relative to repository root = this file's parent)
|
||||
- Excel sources under: ./prompt_excel/
|
||||
- Docs sources under: ./prompt_docs/
|
||||
- Outputs:
|
||||
- Excel→Docs: ./prompt_docs/prompt_docs_YYYY_MMDD_HHMMSS/{prompts,docs}
|
||||
- Docs→Excel: ./prompt_excel/prompt_excel_YYYY_MMDD_HHMMSS/rebuilt.xlsx
|
||||
|
||||
Examples
|
||||
# Interactive selection
|
||||
python3 main.py
|
||||
|
||||
# Non-interactive: choose one Excel file
|
||||
python3 main.py --select "prompt_excel/prompt (3).xlsx"
|
||||
|
||||
# Non-interactive: choose one docs set directory
|
||||
python3 main.py --select "prompt_docs/prompt_docs_2025_0903_055708"
|
||||
|
||||
Notes
|
||||
- This script is a thin orchestrator that delegates actual work to
|
||||
scripts/start_convert.py to ensure a single source of truth.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import List, Optional, Sequence, Tuple
|
||||
|
||||
# Optional Rich UI imports (fallback to plain if unavailable)
|
||||
try:
|
||||
from rich.console import Console
|
||||
from rich.layout import Layout
|
||||
from rich.panel import Panel
|
||||
from rich.table import Table
|
||||
from rich.text import Text
|
||||
from rich import box
|
||||
from rich.prompt import IntPrompt
|
||||
_RICH_AVAILABLE = True
|
||||
except Exception: # pragma: no cover
|
||||
_RICH_AVAILABLE = False
|
||||
|
||||
# Optional InquirerPy for arrow-key selection
|
||||
try:
|
||||
from InquirerPy import inquirer as _inq
|
||||
_INQUIRER_AVAILABLE = True
|
||||
except Exception: # pragma: no cover
|
||||
_INQUIRER_AVAILABLE = False
|
||||
|
||||
|
||||
@dataclass
|
||||
class Candidate:
|
||||
index: int
|
||||
kind: str # "excel" | "docs"
|
||||
path: Path
|
||||
label: str
|
||||
|
||||
|
||||
def get_repo_root() -> Path:
|
||||
return Path(__file__).resolve().parent
|
||||
|
||||
|
||||
def list_excel_files(excel_dir: Path) -> List[Path]:
|
||||
if not excel_dir.exists():
|
||||
return []
|
||||
return sorted([p for p in excel_dir.iterdir() if p.is_file() and p.suffix.lower() == ".xlsx"], key=lambda p: p.stat().st_mtime)
|
||||
|
||||
|
||||
def has_prompt_files(directory: Path) -> bool:
|
||||
if not directory.exists():
|
||||
return False
|
||||
# Detect files like "(r,c)_*.md" anywhere under the directory
|
||||
for file_path in directory.rglob("*.md"):
|
||||
name = file_path.name
|
||||
if name.startswith("(") and ")_" in name:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def list_doc_sets(docs_dir: Path) -> List[Path]:
|
||||
results: List[Path] = []
|
||||
if not docs_dir.exists():
|
||||
return results
|
||||
# If the docs_dir itself looks like a set, include it
|
||||
if has_prompt_files(docs_dir):
|
||||
results.append(docs_dir)
|
||||
# Also include any immediate children that look like a docs set
|
||||
for child in sorted(docs_dir.iterdir()):
|
||||
if child.is_dir() and has_prompt_files(child):
|
||||
results.append(child)
|
||||
return results
|
||||
|
||||
|
||||
def run_start_convert(start_convert: Path, mode: str, project_root: Path, select_path: Optional[Path] = None, excel_dir: Optional[Path] = None, docs_dir: Optional[Path] = None) -> int:
|
||||
"""Delegate to scripts/start_convert.py with appropriate flags."""
|
||||
python_exe = sys.executable
|
||||
cmd: List[str] = [python_exe, str(start_convert), "--mode", mode]
|
||||
if select_path is not None:
|
||||
# Always pass as repo-root-relative or absolute string
|
||||
cmd.extend(["--select", str(select_path)])
|
||||
if excel_dir is not None:
|
||||
cmd.extend(["--excel-dir", str(excel_dir)])
|
||||
if docs_dir is not None:
|
||||
cmd.extend(["--docs-dir", str(docs_dir)])
|
||||
|
||||
# Execute in repo root to ensure relative defaults resolve correctly
|
||||
proc = subprocess.run(cmd, cwd=str(project_root))
|
||||
return proc.returncode
|
||||
|
||||
|
||||
def build_candidates(project_root: Path, excel_dir: Path, docs_dir: Path) -> List[Candidate]:
|
||||
candidates: List[Candidate] = []
|
||||
idx = 1
|
||||
for path in list_excel_files(excel_dir):
|
||||
label = f"[Excel] {path.name}"
|
||||
candidates.append(Candidate(index=idx, kind="excel", path=path, label=label))
|
||||
idx += 1
|
||||
for path in list_doc_sets(docs_dir):
|
||||
display = path.relative_to(project_root) if path.is_absolute() else path
|
||||
label = f"[Docs] {display}"
|
||||
candidates.append(Candidate(index=idx, kind="docs", path=path, label=label))
|
||||
idx += 1
|
||||
return candidates
|
||||
|
||||
|
||||
def select_interactively(candidates: Sequence[Candidate]) -> Optional[Candidate]:
|
||||
if not candidates:
|
||||
print("没有可用的 Excel 或 Docs 源。请将 .xlsx 放到 prompt_excel/ 或将文档放到 prompt_docs/ 下。")
|
||||
return None
|
||||
|
||||
# Prefer arrow-key selection if available
|
||||
if _INQUIRER_AVAILABLE:
|
||||
try:
|
||||
choices = [
|
||||
{"name": f"{'[Excel]' if c.kind=='excel' else '[Docs]'} {c.label}", "value": c.index}
|
||||
for c in candidates
|
||||
]
|
||||
selection = _inq.select(
|
||||
message="选择要转换的源(上下箭头,回车确认,Ctrl+C 取消):",
|
||||
choices=choices,
|
||||
default=choices[0]["value"],
|
||||
).execute()
|
||||
match = next((c for c in candidates if c.index == selection), None)
|
||||
return match
|
||||
except KeyboardInterrupt:
|
||||
return None
|
||||
|
||||
if _RICH_AVAILABLE:
|
||||
console = Console()
|
||||
layout = Layout()
|
||||
layout.split_column(
|
||||
Layout(name="header", size=3),
|
||||
Layout(name="list"),
|
||||
Layout(name="footer", size=3),
|
||||
)
|
||||
header = Panel(Text("提示词库转换器", style="bold cyan"), subtitle="选择一个源开始转换", box=box.ROUNDED)
|
||||
|
||||
table = Table(box=box.SIMPLE_HEAVY)
|
||||
table.add_column("编号", style="bold yellow", justify="right", width=4)
|
||||
table.add_column("类型", style="magenta", width=8)
|
||||
table.add_column("路径/名称", style="white")
|
||||
for c in candidates:
|
||||
table.add_row(str(c.index), "Excel" if c.kind == "excel" else "Docs", c.label)
|
||||
|
||||
layout["header"].update(header)
|
||||
layout["list"].update(Panel(table, title="可选源", border_style="cyan"))
|
||||
layout["footer"].update(Panel(Text("输入编号并回车(0 退出)", style="bold"), box=box.ROUNDED))
|
||||
console.print(layout)
|
||||
|
||||
while True:
|
||||
try:
|
||||
choice = IntPrompt.ask("编号", default=0)
|
||||
except Exception:
|
||||
return None
|
||||
if choice == 0:
|
||||
return None
|
||||
match = next((c for c in candidates if c.index == choice), None)
|
||||
if match is not None:
|
||||
return match
|
||||
console.print("[red]编号不存在,请重试[/red]")
|
||||
|
||||
# Plain fallback
|
||||
print("请选择一个源进行转换:")
|
||||
for c in candidates:
|
||||
print(f" {c.index:2d}. {c.label}")
|
||||
print(" 0. 退出")
|
||||
while True:
|
||||
try:
|
||||
raw = input("输入编号后回车:").strip()
|
||||
except EOFError:
|
||||
return None
|
||||
if not raw:
|
||||
continue
|
||||
if raw == "0":
|
||||
return None
|
||||
if not raw.isdigit():
|
||||
print("请输入有效数字。")
|
||||
continue
|
||||
choice = int(raw)
|
||||
match = next((c for c in candidates if c.index == choice), None)
|
||||
if match is None:
|
||||
print("编号不存在,请重试。")
|
||||
continue
|
||||
return match
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
p = argparse.ArgumentParser(description="prompt-library conversion controller")
|
||||
p.add_argument("--excel-dir", type=str, default="prompt_excel", help="Excel sources directory (default: prompt_excel)")
|
||||
p.add_argument("--docs-dir", type=str, default="prompt_docs", help="Docs sources directory (default: prompt_docs)")
|
||||
p.add_argument("--select", type=str, default=None, help="Path to a specific .xlsx file or a docs folder")
|
||||
p.add_argument("--non-interactive", action="store_true", help="Do not prompt; require --select or exit")
|
||||
return p.parse_args()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
repo_root = get_repo_root()
|
||||
start_convert = repo_root / "scripts" / "start_convert.py"
|
||||
if not start_convert.exists():
|
||||
print("找不到 scripts/start_convert.py。")
|
||||
return 1
|
||||
|
||||
args = parse_args()
|
||||
|
||||
excel_dir = (repo_root / args.excel_dir).resolve() if not Path(args.excel_dir).is_absolute() else Path(args.excel_dir).resolve()
|
||||
docs_dir = (repo_root / args.docs_dir).resolve() if not Path(args.docs_dir).is_absolute() else Path(args.docs_dir).resolve()
|
||||
|
||||
# Non-interactive path with explicit selection
|
||||
if args.non_interactive or args.select:
|
||||
if not args.select:
|
||||
print("--non-interactive 需要配合 --select 使用。")
|
||||
return 2
|
||||
selected = Path(args.select)
|
||||
if not selected.is_absolute():
|
||||
selected = (repo_root / selected).resolve()
|
||||
if not selected.exists():
|
||||
print(f"选择的路径不存在: {selected}")
|
||||
return 2
|
||||
if selected.is_file() and selected.suffix.lower() == ".xlsx":
|
||||
return run_start_convert(start_convert, mode="excel2docs", project_root=repo_root, select_path=selected, excel_dir=excel_dir)
|
||||
if selected.is_dir():
|
||||
# Treat as docs set
|
||||
return run_start_convert(start_convert, mode="docs2excel", project_root=repo_root, select_path=selected, docs_dir=docs_dir)
|
||||
print("无法识别的选择类型(既不是 .xlsx 文件也不是目录)。")
|
||||
return 2
|
||||
|
||||
# Interactive selection
|
||||
candidates = build_candidates(repo_root, excel_dir, docs_dir)
|
||||
chosen = select_interactively(candidates)
|
||||
if chosen is None:
|
||||
return 0
|
||||
if chosen.kind == "excel":
|
||||
return run_start_convert(start_convert, mode="excel2docs", project_root=repo_root, select_path=chosen.path, excel_dir=excel_dir)
|
||||
else:
|
||||
return run_start_convert(start_convert, mode="docs2excel", project_root=repo_root, select_path=chosen.path, docs_dir=docs_dir)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
|
|
@ -1,228 +0,0 @@
|
|||
# 📚 提示词库(Excel转换版)
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
最后更新: 2025-12-13 08:04:13
|
||||
|
||||
|
||||
## 📊 总览
|
||||
|
||||
- **数据来源**: prompt.xlsx
|
||||
|
||||
- **分类数量**: 97
|
||||
- **提示词总数**: 310
|
||||
- **版本总数**: 452
|
||||
|
||||
|
||||
## 📂 分类导航
|
||||
|
||||
- [说明](./prompts/(1)_说明/) - 11 个提示词, 14 个版本
|
||||
|
||||
- [元提示词](./prompts/(2)_元提示词/) - 25 个提示词, 33 个版本
|
||||
|
||||
- [交易提示词](./prompts/(3)_交易提示词/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [软件工程,vibe coding用提示词](./prompts/(4)_软件工程,vibe_coding用提示词/) - 22 个提示词, 32 个版本
|
||||
|
||||
- [临界知识](./prompts/(5)_临界知识/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [根据内容逆向提示词](./prompts/(6)_根据内容逆向提示词/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [逻辑工具箱](./prompts/(7)_逻辑工具箱/) - 4 个提示词, 7 个版本
|
||||
|
||||
- [哲学工具箱](./prompts/(8)_哲学工具箱/) - 13 个提示词, 20 个版本
|
||||
|
||||
- [方法与原则提取](./prompts/(9)_方法与原则提取/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [排版](./prompts/(10)_排版/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [工作表112](./prompts/(11)_工作表112/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [Reddit提示词](./prompts/(12)_Reddit提示词/) - 3 个提示词, 3 个版本
|
||||
|
||||
- [ChatGPT](./prompts/(13)_ChatGPT/) - 4 个提示词, 4 个版本
|
||||
|
||||
- [论文解读](./prompts/(14)_论文解读/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [内容提炼](./prompts/(15)_内容提炼/) - 2 个提示词, 2 个版本
|
||||
|
||||
- [英文学习](./prompts/(16)_英文学习/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [问题分类识别](./prompts/(17)_问题分类识别/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [用户优化前端设计](./prompts/(18)_用户优化前端设计/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [最小知识框架](./prompts/(19)_最小知识框架/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [学习用提示词](./prompts/(20)_学习用提示词/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [事实核查](./prompts/(21)_事实核查/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [关键词图谱](./prompts/(22)_关键词图谱/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [语言分析元prompt](./prompts/(23)_语言分析元prompt/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [逻辑分析](./prompts/(24)_逻辑分析/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [一句话描述任何内容](./prompts/(25)_一句话描述任何内容/) - 1 个提示词, 3 个版本
|
||||
|
||||
- [输入转单行JSON](./prompts/(26)_输入转单行JSON/) - 1 个提示词, 3 个版本
|
||||
|
||||
- [最小字数系统提示词](./prompts/(27)_最小字数系统提示词/) - 1 个提示词, 3 个版本
|
||||
|
||||
- [需求对齐](./prompts/(28)_需求对齐/) - 1 个提示词, 2 个版本
|
||||
|
||||
- [编程知识库](./prompts/(29)_编程知识库/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [提示词模块](./prompts/(30)_提示词模块/) - 10 个提示词, 15 个版本
|
||||
|
||||
- [x爆款文案生成器](./prompts/(31)_x爆款文案生成器/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [grok商业金融分析提示词](./prompts/(32)_grok商业金融分析提示词/) - 12 个提示词, 12 个版本
|
||||
|
||||
- [文本转md语法电子书处理](./prompts/(33)_文本转md语法电子书处理/) - 4 个提示词, 15 个版本
|
||||
|
||||
- [ai学习用提示词](./prompts/(34)_ai学习用提示词/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [真传一句话](./prompts/(35)_真传一句话/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [需求结构化描述](./prompts/(36)_需求结构化描述/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [学习提示词](./prompts/(37)_学习提示词/) - 28 个提示词, 49 个版本
|
||||
|
||||
- [系统提示词](./prompts/(38)_系统提示词/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [排版和图片,视频转文本](./prompts/(39)_排版和图片,视频转文本/) - 4 个提示词, 4 个版本
|
||||
|
||||
- [子弹总结](./prompts/(40)_子弹总结/) - 1 个提示词, 3 个版本
|
||||
|
||||
- [x提示词收集](./prompts/(41)_x提示词收集/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [书籍结构化分析](./prompts/(42)_书籍结构化分析/) - 2 个提示词, 8 个版本
|
||||
|
||||
- [组织语言](./prompts/(43)_组织语言/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [行业分析](./prompts/(44)_行业分析/) - 2 个提示词, 2 个版本
|
||||
|
||||
- [投资调研](./prompts/(45)_投资调研/) - 1 个提示词, 2 个版本
|
||||
|
||||
- [速成学习](./prompts/(46)_速成学习/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [批判性思维分析](./prompts/(47)_批判性思维分析/) - 2 个提示词, 2 个版本
|
||||
|
||||
- [序列图生成](./prompts/(48)_序列图生成/) - 2 个提示词, 4 个版本
|
||||
|
||||
- [对话提问](./prompts/(49)_对话提问/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [层级结构分析](./prompts/(50)_层级结构分析/) - 4 个提示词, 16 个版本
|
||||
|
||||
- [心经口诀创作提示词](./prompts/(51)_心经口诀创作提示词/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [SOP制作](./prompts/(52)_SOP制作/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [黄金圈解释](./prompts/(53)_黄金圈解释/) - 1 个提示词, 3 个版本
|
||||
|
||||
- [需求解析](./prompts/(54)_需求解析/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [notebookllm用提示词](./prompts/(55)_notebookllm用提示词/) - 3 个提示词, 6 个版本
|
||||
|
||||
- [好prompt生成器](./prompts/(56)_好prompt生成器/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [行业咨询](./prompts/(57)_行业咨询/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [分析](./prompts/(58)_分析/) - 2 个提示词, 4 个版本
|
||||
|
||||
- [gemini字幕处理](./prompts/(59)_gemini字幕处理/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [政治批判工具箱](./prompts/(60)_政治批判工具箱/) - 3 个提示词, 6 个版本
|
||||
|
||||
- [推文制作提示词](./prompts/(61)_推文制作提示词/) - 2 个提示词, 2 个版本
|
||||
|
||||
- [麦肯锡行业分析](./prompts/(62)_麦肯锡行业分析/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [正向人物生平报告官方文案](./prompts/(63)_正向人物生平报告官方文案/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [grok抓取提示词](./prompts/(64)_grok抓取提示词/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [视频生成提示词](./prompts/(65)_视频生成提示词/) - 2 个提示词, 2 个版本
|
||||
|
||||
- [人话写作](./prompts/(66)_人话写作/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [x prompt收集](./prompts/(67)_x_prompt收集/) - 2 个提示词, 3 个版本
|
||||
|
||||
- [函数化万物](./prompts/(68)_函数化万物/) - 1 个提示词, 6 个版本
|
||||
|
||||
- [项目分析](./prompts/(69)_项目分析/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [解释提示词](./prompts/(70)_解释提示词/) - 1 个提示词, 3 个版本
|
||||
|
||||
- [产品策略](./prompts/(71)_产品策略/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [小红书](./prompts/(72)_小红书/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [谋士](./prompts/(73)_谋士/) - 1 个提示词, 3 个版本
|
||||
|
||||
- [前端复刻流程](./prompts/(74)_前端复刻流程/) - 3 个提示词, 3 个版本
|
||||
|
||||
- [网页UI逆向分析提示词](./prompts/(75)_网页UI逆向分析提示词/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [典籍句子学习](./prompts/(76)_典籍句子学习/) - 2 个提示词, 3 个版本
|
||||
|
||||
- [经验](./prompts/(77)_经验/) - 9 个提示词, 16 个版本
|
||||
|
||||
- [anki卡片格式输出](./prompts/(78)_anki卡片格式输出/) - 1 个提示词, 2 个版本
|
||||
|
||||
- [简讯提示词](./prompts/(79)_简讯提示词/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [思维导图](./prompts/(80)_思维导图/) - 1 个提示词, 3 个版本
|
||||
|
||||
- [未来视角](./prompts/(81)_未来视角/) - 6 个提示词, 6 个版本
|
||||
|
||||
- [AI使用思维](./prompts/(82)_AI使用思维/) - 2 个提示词, 4 个版本
|
||||
|
||||
- [思维协议](./prompts/(83)_思维协议/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [使用ai的思维](./prompts/(84)_使用ai的思维/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [李继刚文选](./prompts/(85)_李继刚文选/) - 2 个提示词, 2 个版本
|
||||
|
||||
- [图片逆向](./prompts/(86)_图片逆向/) - 2 个提示词, 2 个版本
|
||||
|
||||
- [艺术风格描述](./prompts/(87)_艺术风格描述/) - 2 个提示词, 2 个版本
|
||||
|
||||
- [豆包听书](./prompts/(88)_豆包听书/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [艺术](./prompts/(89)_艺术/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [文案逆向](./prompts/(90)_文案逆向/) - 10 个提示词, 12 个版本
|
||||
|
||||
- [流程图](./prompts/(91)_流程图/) - 2 个提示词, 3 个版本
|
||||
|
||||
- [学习音频](./prompts/(92)_学习音频/) - 1 个提示词, 1 个版本
|
||||
|
||||
- [思维模型](./prompts/(93)_思维模型/) - 1 个提示词, 2 个版本
|
||||
|
||||
- [道](./prompts/(94)_道/) - 6 个提示词, 11 个版本
|
||||
|
||||
- [法](./prompts/(95)_法/) - 4 个提示词, 6 个版本
|
||||
|
||||
- [术](./prompts/(96)_术/) - 24 个提示词, 24 个版本
|
||||
|
||||
- [器](./prompts/(97)_器/) - 9 个提示词, 9 个版本
|
||||
|
||||
|
||||
## 🔄 同步信息
|
||||
|
||||
- **数据源**: prompt.xlsx
|
||||
- **处理时间**: 2025-12-13 08:04:13
|
||||
|
||||
|
||||
## 📝 许可证
|
||||
本项目采用 MIT 许可证
|
||||
|
||||
|
||||
---
|
||||
*完全基于 Excel 表格自动生成*
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -1,35 +0,0 @@
|
|||
# 💰 项目支持(从Excel提取)
|
||||
|
||||
|
||||
## 支持说明
|
||||
**礼貌要饭地址** - 如果这个项目对您有帮助,欢迎通过以下方式支持
|
||||
|
||||
|
||||
## 加密货币钱包地址
|
||||
|
||||
### 主流网络支持
|
||||
|
||||
|
||||
| 网络名称 | 钱包地址 | Excel行号 |
|
||||
|----------|----------|-----------|
|
||||
|
||||
| **TRON** | `TQtBXCSTwLFHjBqTS4rNUp7ufiGx51BRey` | 第46行 |
|
||||
|
||||
| **SOL** | `HjYhozVf9AQmfv7yv79xSNs6uaEU5oUk2USasYQfUYau` | 第47行 |
|
||||
|
||||
| **ETH** | `0xa396923a71ee7D9480b346a17dDeEb2c0C287BBC` | 第48行 |
|
||||
|
||||
| **BSC** | `0xa396923a71ee7D9480b346a17dDeEb2c0C287BBC` | 第49行 |
|
||||
|
||||
| **BTC** | `bc1plslluj3zq3snpnnczplu7ywf37h89dyudqua04pz4txwh8z5z5vsre7nlm` | 第50行 |
|
||||
|
||||
| **SUI** | `0xb720c98a48c77f2d49d375932b2867e793029e6337f1562522640e4f84203d2e` | 第51行 |
|
||||
|
||||
|
||||
### 使用建议
|
||||
1. 请确认钱包地址的准确性
|
||||
2. 建议小额测试后再进行大额转账
|
||||
3. 不同网络的转账费用不同,请选择合适的网络
|
||||
|
||||
---
|
||||
*钱包地址来源: prompt.xlsx*
|
||||
|
|
@ -1,191 +0,0 @@
|
|||
# 🛠️ 工具与资源(从Excel提取)
|
||||
|
||||
|
||||
## AI优化工具
|
||||
|
||||
|
||||
### 工具
|
||||
- **URL**: https://github.com/123olp/ys
|
||||
- **描述**: 上帝工程
|
||||
- **数据来源**: Excel表格第9行
|
||||
|
||||
|
||||
### 工具
|
||||
- **URL**: https://www.notion.so/28235eb9215080c392e4d53002f6b493
|
||||
- **描述**: 上帝工程
|
||||
- **数据来源**: Excel表格第10行
|
||||
|
||||
|
||||
### 工具
|
||||
- **URL**: https://t.me/sxwgc123
|
||||
- **描述**: telegram提示词交流群
|
||||
- **数据来源**: Excel表格第11行
|
||||
|
||||
|
||||
### 工具
|
||||
- **URL**: https://github.com/123olp/prompt-library
|
||||
- **描述**: 本表格github位置
|
||||
- **数据来源**: Excel表格第12行
|
||||
|
||||
|
||||
### OpenAI 提示词优化平台
|
||||
- **URL**: https://platform.openai.com/chat/edit?models=gpt-5&optimize=true
|
||||
- **描述**: openai提示词优化网站
|
||||
- **数据来源**: Excel表格第14行
|
||||
|
||||
|
||||
### 工具
|
||||
- **URL**: https://github.com/y0mingzhang/prompt-extraction
|
||||
- **描述**: 这是一个提取提示词的仓库,你看中哪个 agent,直接输入即可获取该 agent 的系统提示词,经过尝试,仅适用于部分场景的提取
|
||||
- **数据来源**: Excel表格第15行
|
||||
|
||||
|
||||
### 工具
|
||||
- **URL**: https://github.com/x1xhlol/system-prompts-and-models-of-ai-tools
|
||||
- **描述**: AI 工具系统提示词与模型代码库,收录 20,000+ 行 AI 工具与助手的系统提示词、配置与规范、
|
||||
- **数据来源**: Excel表格第16行
|
||||
|
||||
|
||||
### 工具
|
||||
- **URL**: https://opensource.antgroup.com/blogs?utm_source=chatgpt.com
|
||||
- **描述**: 蚂蚁开源博客(信息源)
|
||||
- **数据来源**: Excel表格第17行
|
||||
|
||||
|
||||
### 工具
|
||||
- **URL**: https://huggingface.co/papers/trending
|
||||
- **描述**: 热门论文(信息源)
|
||||
- **数据来源**: Excel表格第18行
|
||||
|
||||
|
||||
### 工具
|
||||
- **URL**: https://arxiv.org/
|
||||
- **描述**: 研究者第一时间挂论文的地方(信息源)
|
||||
- **数据来源**: Excel表格第19行
|
||||
|
||||
|
||||
### 工具
|
||||
- **URL**: https://github.com/richards199999/Thinking-Claude/tree/main
|
||||
- **描述**: 涂津豪
|
||||
- **数据来源**: Excel表格第20行
|
||||
|
||||
|
||||
### OpenAI 提示词优化平台
|
||||
- **URL**: https://academy.openai.com/public/tags/prompt-packs-6849a0f98c613939acef841c
|
||||
- **描述**: openai提示词网站
|
||||
- **数据来源**: Excel表格第21行
|
||||
|
||||
|
||||
### 工具
|
||||
- **URL**: https://llm-stats.com/benchmarks
|
||||
- **描述**: 模型评测与排行榜网站
|
||||
- **数据来源**: Excel表格第22行
|
||||
|
||||
|
||||
### 工具
|
||||
- **URL**: https://github.com/vectara/hallucination-leaderboard/
|
||||
- **描述**: 模型幻觉排行榜
|
||||
- **数据来源**: Excel表格第23行
|
||||
|
||||
|
||||
### 工具
|
||||
- **URL**: https://prompthero.com/
|
||||
- **描述**: 全球最大开源库
|
||||
- **数据来源**: Excel表格第24行
|
||||
|
||||
|
||||
### 工具
|
||||
- **URL**: https://www.aiforeducation.io/prompt-library
|
||||
- **描述**: 面向教师,涵盖课程设计、作业反馈、沟通管理等场景
|
||||
- **数据来源**: Excel表格第25行
|
||||
|
||||
|
||||
### 工具
|
||||
- **URL**: https://docs.claude.com/en/resources/prompt-library/library
|
||||
- **描述**: 由 Anthropic 官方团队维护,针对 Claude 优化
|
||||
- **数据来源**: Excel表格第26行
|
||||
|
||||
|
||||
### 工具
|
||||
- **URL**: https://www.promptingguide.ai
|
||||
- **描述**: 从基础“角色设定”到高级“思维链 (CoT) ”,逐步解析 Prompt 设计原理
|
||||
- **数据来源**: Excel表格第27行
|
||||
|
||||
|
||||
### 工具
|
||||
- **URL**: https://docs.lovable.dev/prompting/prompting-library
|
||||
- **描述**: 开发者友好: 面向程序员、设计师、产品经理
|
||||
- **数据来源**: Excel表格第28行
|
||||
|
||||
|
||||
### 工具
|
||||
- **URL**: https://dqxf1izhlm.feishu.cn/wiki/OKvFwmmaIiBlPYkDGo3c8Z0EnCE
|
||||
- **描述**: 重磅!你的 Prompt 工程白学了?“懒人提示词”技巧,让AI瞬间懂你
|
||||
- **数据来源**: Excel表格第29行
|
||||
|
||||
|
||||
### 工具
|
||||
- **URL**: https://github.com/filipecalegario/awesome-generative-ai
|
||||
- **描述**:
|
||||
- **数据来源**: Excel表格第30行
|
||||
|
||||
|
||||
### 工具
|
||||
- **URL**: https://github.com/aishwaryanr/awesome-generative-ai-guide
|
||||
- **描述**:
|
||||
- **数据来源**: Excel表格第31行
|
||||
|
||||
|
||||
### 工具
|
||||
- **URL**: https://aistudio.google.com/
|
||||
- **描述**: 打开 Gemini 2.5 Pro
|
||||
- **数据来源**: Excel表格第4行
|
||||
|
||||
|
||||
## 社交媒体
|
||||
|
||||
|
||||
### Twitter/X 账号
|
||||
- **URL**: https://x.com/123olp
|
||||
- **描述**: 关注我的推特获取最新咨询
|
||||
- **数据来源**: Excel表格第13行
|
||||
|
||||
|
||||
### Twitter/X 账号
|
||||
- **URL**: https://x.com/rebutonepress?s=21
|
||||
- **描述**:
|
||||
- **数据来源**: Excel表格第35行
|
||||
|
||||
|
||||
### Twitter/X 账号
|
||||
- **URL**: https://x.com/HIHIH8899
|
||||
- **描述**:
|
||||
- **数据来源**: Excel表格第38行
|
||||
|
||||
|
||||
### Twitter/X 账号
|
||||
- **URL**: https://x.com/FireStealer2035
|
||||
- **描述**:
|
||||
- **数据来源**: Excel表格第40行
|
||||
|
||||
|
||||
### Twitter/X 账号
|
||||
- **URL**: https://x.com/zzc_ae
|
||||
- **描述**:
|
||||
- **数据来源**: Excel表格第42行
|
||||
|
||||
|
||||
### Twitter/X 账号
|
||||
- **URL**: https://x.com/0xdaqian
|
||||
- **描述**:
|
||||
- **数据来源**: Excel表格第43行
|
||||
|
||||
|
||||
## 使用建议
|
||||
|
||||
1. **OpenAI优化器**: 可以用来测试和改进本库中的提示词
|
||||
2. **社交媒体**: 关注获取项目更新和使用技巧
|
||||
3. **集成方式**: 可以将这些工具集成到自动化工作流中
|
||||
|
||||
---
|
||||
*数据来源: prompt.xlsx*
|
||||
|
|
@ -1 +0,0 @@
|
|||
底部每个工作表代表一类提示词,图表的横轴表示提示词的迭代版本(如提示词1a、提示词1b、提示词1c 等),体现每一类提示词在不同阶段的演化。纵轴表示不同的提示词(如提示词1、提示词2、…、提示词y),每一行展示同一类型提示词在不同版本下的具体内容,便于对比各类型提示词随版本迭代的变化趋势。
|
||||
|
|
@ -1 +0,0 @@
|
|||
提示词1a
|
||||
|
|
@ -1 +0,0 @@
|
|||
提示词1b
|
||||
|
|
@ -1 +0,0 @@
|
|||
提示词1c
|
||||
|
|
@ -1 +0,0 @@
|
|||
贡献者名单
|
||||
|
|
@ -1 +0,0 @@
|
|||
狗神
|
||||
|
|
@ -1 +0,0 @@
|
|||
天空
|
||||
|
|
@ -1 +0,0 @@
|
|||
金狗
|
||||
|
|
@ -1 +0,0 @@
|
|||
耄鑫覺囉
|
||||
|
|
@ -1 +0,0 @@
|
|||
提示词2a
|
||||
|
|
@ -1 +0,0 @@
|
|||
提示词2b
|
||||
|
|
@ -1 +0,0 @@
|
|||
kirt
|
||||
|
|
@ -1 +0,0 @@
|
|||
提示词ya
|
||||
|
|
@ -1 +0,0 @@
|
|||
提示词相关链接和资源
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
# 📂 提示词分类 - 说明(基于Excel原始数据)
|
||||
|
||||
最后同步: 2025-12-13 08:04:13
|
||||
|
||||
|
||||
## 📊 统计
|
||||
|
||||
- 提示词总数: 11
|
||||
|
||||
- 版本总数: 14
|
||||
|
||||
- 平均版本数: 1.3
|
||||
|
||||
|
||||
## 📋 提示词列表
|
||||
|
||||
|
||||
| 序号 | 标题 | 版本数 | 查看 |
|
||||
|------|------|--------|------|
|
||||
|
||||
| 2 | 底部每个工作表代表一类提示词,图表的横轴表示提示词的迭代版本(如提示词1a、提示词1b、提示词1c_等),体现每一类提示 | 1 | [v1](./(2,1)_底部每个工作表代表一类提示词,图表的横轴表示提示词的迭代版本(如提示词1a、提示词1b、提示词1c_等),体现每一类提示.md) |
|
||||
|
||||
| 3 | 提示词1a | 3 | [v1](./(3,1)_提示词1a.md) / [v2](./(3,2)_提示词1a.md) / [v3](./(3,3)_提示词1a.md) |
|
||||
|
||||
| 4 | 提示词2a | 2 | [v1](./(4,1)_提示词2a.md) / [v2](./(4,2)_提示词2a.md) |
|
||||
|
||||
| 6 | 提示词ya | 1 | [v1](./(6,1)_提示词ya.md) |
|
||||
|
||||
| 8 | 提示词相关链接和资源 | 1 | [v1](./(8,1)_提示词相关链接和资源.md) |
|
||||
|
||||
| 33 | 贡献者名单 | 1 | [v1](./(33,1)_贡献者名单.md) |
|
||||
|
||||
| 34 | 狗神 | 1 | [v1](./(34,1)_狗神.md) |
|
||||
|
||||
| 36 | 天空 | 1 | [v1](./(36,1)_天空.md) |
|
||||
|
||||
| 37 | 金狗 | 1 | [v1](./(37,1)_金狗.md) |
|
||||
|
||||
| 39 | 耄鑫覺囉 | 1 | [v1](./(39,1)_耄鑫覺囉.md) |
|
||||
|
||||
| 41 | kirt | 1 | [v1](./(41,1)_kirt.md) |
|
||||
|
||||
|
||||
## 🗂️ 版本矩阵
|
||||
|
||||
|
||||
| 行 | v1 | v2 | v3 | 备注 |
|
||||
|---|---|---|---|---|
|
||||
|
||||
| 2 | ✅ | — | — | |
|
||||
|
||||
| 3 | ✅ | ✅ | ✅ | |
|
||||
|
||||
| 4 | ✅ | ✅ | — | |
|
||||
|
||||
| 6 | ✅ | — | — | |
|
||||
|
||||
| 8 | ✅ | — | — | |
|
||||
|
||||
| 33 | ✅ | — | — | |
|
||||
|
||||
| 34 | ✅ | — | — | |
|
||||
|
||||
| 36 | ✅ | — | — | |
|
||||
|
||||
| 37 | ✅ | — | — | |
|
||||
|
||||
| 39 | ✅ | — | — | |
|
||||
|
||||
| 41 | ✅ | — | — | |
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
# Role:智能文本排版助手
|
||||
|
||||
## Profile
|
||||
- author: AI-Helper
|
||||
- version: 2.1
|
||||
- language: 中文
|
||||
- description: 作为专业的文本排版助手,你需要将用户提供的任意原始文本智能转化为结构化的 Markdown 格式,并确保最终输出以单一代码块呈现,且不包含任何加粗语法。
|
||||
|
||||
## Objectives
|
||||
|
||||
1. 智能排版
|
||||
- 根据文本的语义与结构,将原始内容转化为清晰、层级合理的 Markdown 格式。
|
||||
- 使用标题、段落、列表、引用等元素增强可读性。
|
||||
- 禁止使用分隔线(如 ---)。
|
||||
|
||||
2. 净化加粗
|
||||
- 在排版过程中移除所有已有或可能出现的加粗语法(如 `**文字**`、`__文字__`)。
|
||||
|
||||
3. 格式化输出
|
||||
- 将最终内容以单一的 Markdown 代码块输出。
|
||||
- 代码块内部不得包含多余解释性文字。
|
||||
|
||||
## Constraints
|
||||
|
||||
- 内容保真
|
||||
- 排版仅限于结构调整,不得对原文进行实质性修改、删除或增补。
|
||||
|
||||
- 排版优先
|
||||
- 无论输入内容是否具备结构,都必须分析并生成合适的 Markdown 层级结构。
|
||||
|
||||
- 绝对无加粗
|
||||
- 输出中不得出现任何加粗格式。
|
||||
|
||||
- 单一代码块
|
||||
- 最终输出必须完全包含在一个 Markdown 代码块中,且不能在代码块外附加说明。
|
||||
|
||||
## Workflow
|
||||
|
||||
1. 接收用户输入的原始文本。
|
||||
2. 分析文本的语义层级与逻辑结构。
|
||||
3. 使用适当的 Markdown 元素对内容进行结构化排版。
|
||||
4. 移除所有加粗语法并确保不会生成新的加粗格式。
|
||||
5. 将排版结果置于一个 Markdown 代码块内。
|
||||
6. 直接输出代码块,不添加额外内容。
|
||||
|
||||
## Example
|
||||
|
||||
### Input
|
||||
项目总结报告
|
||||
第一部分 项目背景
|
||||
这个项目是为了解决效率问题的。我们发现旧系统**处理速度**很慢。
|
||||
第二部分 实施过程
|
||||
我们分了三个阶段:1. 需求分析 2. 开发与测试 3. 上线部署
|
||||
这是一个重要的里程碑。
|
||||
第三部分 成果
|
||||
处理效率提升了50%。
|
||||
|
||||
### Output
|
||||
```
|
||||
|
||||
# 项目总结报告
|
||||
|
||||
## 第一部分 项目背景
|
||||
|
||||
这个项目是为了解决效率问题的。我们发现旧系统处理速度很慢。
|
||||
|
||||
## 第二部分 实施过程
|
||||
|
||||
我们分了三个阶段:
|
||||
|
||||
1. 需求分析
|
||||
2. 开发与测试
|
||||
3. 上线部署
|
||||
|
||||
这是一个重要的里程碑。
|
||||
|
||||
## 第三部分 成果
|
||||
|
||||
处理效率提升了50%。
|
||||
|
||||
```
|
||||
|
||||
### 用户输入区
|
||||
请在此处输入需要排版的原始内容:
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
# 📂 提示词分类 - 排版(基于Excel原始数据)
|
||||
|
||||
最后同步: 2025-12-13 08:04:13
|
||||
|
||||
|
||||
## 📊 统计
|
||||
|
||||
- 提示词总数: 1
|
||||
|
||||
- 版本总数: 1
|
||||
|
||||
- 平均版本数: 1.0
|
||||
|
||||
|
||||
## 📋 提示词列表
|
||||
|
||||
|
||||
| 序号 | 标题 | 版本数 | 查看 |
|
||||
|------|------|--------|------|
|
||||
|
||||
| 1 | #_Role:智能文本排版助手 | 1 | [v1](./(1,1)_#_Role:智能文本排版助手.md) |
|
||||
|
||||
|
||||
## 🗂️ 版本矩阵
|
||||
|
||||
|
||||
| 行 | v1 | 备注 |
|
||||
|---|---|---|
|
||||
|
||||
| 1 | ✅ | |
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
请从输入图像中智能、全面地提取视觉风格信息,并将结果以**严格有效的 JSON** 格式输出。
|
||||
字段数量不做限制,可根据图像特征灵活增减,但需保持结构清晰、语义明确、分类合理。
|
||||
以下为建议的通用结构,请在此基础上根据实际情况动态调整、增删字段:
|
||||
|
||||
{
|
||||
"colors": {
|
||||
"palette": [], // 色板(HEX/RGB)
|
||||
"dominant_colors": [], // 主色
|
||||
"accents": [], // 点缀色
|
||||
"tone_contrast": "" // 明度/色温/对比特征
|
||||
},
|
||||
"typography": {
|
||||
"fonts": [], // 字体名称或风格
|
||||
"style_features": [], // 字重/字宽/字型特征
|
||||
"hierarchy": "" // 排版层级
|
||||
},
|
||||
"composition": {
|
||||
"layout": "", // 布局方式
|
||||
"balance": "", // 对称、非对称、中心构图等
|
||||
"focal_points": [], // 视觉焦点
|
||||
"spacing_and_rhythm": "" // 留白、节奏、密度
|
||||
},
|
||||
"visual_effects": {
|
||||
"textures": [], // 纹理
|
||||
"lighting": "", // 光影表现
|
||||
"shadows": "", // 阴影类型
|
||||
"filters": [], // 滤镜或后期效果
|
||||
"other_effects": [] // 其他识别到的风格特征
|
||||
},
|
||||
"overall_style": {
|
||||
"design_language": "", // 如极简/复古/赛博等
|
||||
"emotional_tone": "", // 感性气质,如温暖/冷峻/活泼
|
||||
"reference_genres": [] // 类似的风格类型或艺术流派
|
||||
}
|
||||
}
|
||||
|
||||
要求:
|
||||
- 输出必须是**纯 JSON**,不包含任何额外说明文字。
|
||||
- 可根据图像内容自由扩展或删减字段,但需保持命名专业、语义明确。
|
||||
- 无法判断的字段请使用空字符串、空数组或省略。
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
# 📂 提示词分类 - 工作表112(基于Excel原始数据)
|
||||
|
||||
最后同步: 2025-12-13 08:04:13
|
||||
|
||||
|
||||
## 📊 统计
|
||||
|
||||
- 提示词总数: 1
|
||||
|
||||
- 版本总数: 1
|
||||
|
||||
- 平均版本数: 1.0
|
||||
|
||||
|
||||
## 📋 提示词列表
|
||||
|
||||
|
||||
| 序号 | 标题 | 版本数 | 查看 |
|
||||
|------|------|--------|------|
|
||||
|
||||
| 3 | 请从输入图像中智能、全面地提取视觉风格信息,并将结果以严格有效的_JSON_格式输出。 | 1 | [v1](./(3,1)_请从输入图像中智能、全面地提取视觉风格信息,并将结果以严格有效的_JSON_格式输出。.md) |
|
||||
|
||||
|
||||
## 🗂️ 版本矩阵
|
||||
|
||||
|
||||
| 行 | v1 | 备注 |
|
||||
|---|---|---|
|
||||
|
||||
| 3 | ✅ | |
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue