waveshaker commited on
Commit
27d0379
·
verified ·
1 Parent(s): d3f9627

Upload 7 files

Browse files
old/dataset/1_caption_remove_space.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+
3
+ # 获取当前工作目录
4
+ current_dir = os.getcwd()
5
+
6
+ # 遍历当前目录下的所有文件
7
+ for filename in os.listdir(current_dir):
8
+ # 检查是否为 txt 文件
9
+ if filename.endswith('.txt'):
10
+ filepath = os.path.join(current_dir, filename)
11
+
12
+ # 读取文件内容并去掉换行符
13
+ try:
14
+ with open(filepath, 'r', encoding='utf-8') as f:
15
+ # 读取所有行,并用空字符连接,达到去掉换行符的效果
16
+ content = ''.join(line.strip() for line in f)
17
+
18
+ # 写回原文件
19
+ with open(filepath, 'w', encoding='utf-8') as f:
20
+ f.write(content)
21
+
22
+ print(f'已处理: {filename}')
23
+ except Exception as e:
24
+ print(f'处理 {filename} 失败: {e}')
old/dataset/2_img_compressor.bat ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @echo off
2
+ setlocal enabledelayedexpansion
3
+
4
+ echo ========================================================
5
+ echo 警告:此操作将批量将当前目录及子目录下的所有 .png 图片
6
+ echo 转换为 .jpg 格式,并【永久删除】原始的 .png 文件!
7
+ echo ========================================================
8
+ set /p "choice=确定要继续吗?(Y/N): "
9
+
10
+ if /i "%choice%" NEQ "Y" (
11
+ echo 操作已取消。
12
+ pause
13
+ exit /b
14
+ )
15
+
16
+ for /R %%f in (*.png) do (
17
+ ffmpeg -i "%%f" -q:v 2 "%%~dpnf.jpg"
18
+ if exist "%%~dpnf.jpg" (
19
+ del "%%f"
20
+ )
21
+ )
22
+
23
+ echo Conversion complete.
24
+ pause
old/dataset/3_mask_clean_metadata.py ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from PIL import Image
3
+
4
+
5
+ def remove_all_png_metadata_in_current_dir():
6
+ # 获取当前脚本所在的目录
7
+ current_dir = os.getcwd()
8
+ print(f"正在处理目录: {current_dir}\n" + "-" * 40)
9
+
10
+ success_count = 0
11
+
12
+ # 遍历当前目录及所有子目录
13
+ for root, dirs, files in os.walk(current_dir):
14
+ for file in files:
15
+ if file.lower().endswith(".png"):
16
+ file_path = os.path.join(root, file)
17
+ try:
18
+ with Image.open(file_path) as img:
19
+ # 读取图片像素数据,彻底与原图的元数据对象断开连接
20
+ data = list(img.getdata())
21
+ clean_img = Image.new(img.mode, img.size)
22
+ clean_img.putdata(data)
23
+
24
+ # 覆盖保存为干净的 PNG
25
+ clean_img.save(file_path, "PNG")
26
+
27
+ print(f"成功清除: {file_path}")
28
+ success_count += 1
29
+ except Exception as e:
30
+ print(f"处理失败 [{file}]: {e}")
31
+
32
+ print("-" * 40)
33
+ print(f"处理完成!共清理了 {success_count} 张 PNG 图片的元数据。")
34
+
35
+
36
+ if __name__ == "__main__":
37
+ # 提示用户,防止误操作覆盖重要数据
38
+ confirm = input(
39
+ "此脚本将直接【覆盖】当前目录下所有 PNG 文件并移除其元数据,是否继续?(y/n): "
40
+ )
41
+ if confirm.lower() == "y":
42
+ remove_all_png_metadata_in_current_dir()
43
+ else:
44
+ print("操作已取消。")
old/dataset/4_gen_par_yaml_update_md.py ADDED
@@ -0,0 +1,175 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import glob
3
+ import pandas as pd
4
+ from datasets import Dataset, Features, Image, Value
5
+ from huggingface_hub import HfApi, DatasetCard
6
+ import tempfile
7
+
8
+ # ==========================================
9
+ # 配置区:填写你的 Hugging Face 仓库 ID
10
+ # ==========================================
11
+ REPO_ID = "waveshaker/dataset_collections"
12
+ REPO_TYPE = "dataset"
13
+ HF_TOKEN = "***" # 如果只传 README,依然需要 Write 权限的 Token
14
+ # ==========================================
15
+
16
+ def generate_parquet_for_folder(directory):
17
+ """扫描文件夹,直接生成包含图片的 train.parquet"""
18
+ jpg_files = glob.glob(os.path.join(directory, "*.jpg")) + glob.glob(os.path.join(directory, "*.jpeg"))
19
+ if not jpg_files:
20
+ return False
21
+
22
+ parquet_path = os.path.join(directory, "train.parquet")
23
+ data_rows = []
24
+
25
+ print(f" 📦 正在打包图片: {os.path.basename(directory)}")
26
+
27
+ for jpg_path in jpg_files:
28
+ file_name = os.path.basename(jpg_path)
29
+ base_name = os.path.splitext(file_name)[0]
30
+
31
+ txt_path = os.path.join(directory, f"{base_name}.txt")
32
+ text_content = ""
33
+ if os.path.exists(txt_path):
34
+ with open(txt_path, "r", encoding="utf-8") as f:
35
+ text_content = f.read().strip()
36
+
37
+ try:
38
+ with open(jpg_path, "rb") as f:
39
+ image_bytes = {"bytes": f.read(), "path": None}
40
+ except Exception as e:
41
+ print(f" ⚠️ 跳过损坏图片 {file_name}: {e}")
42
+ continue
43
+
44
+ data_rows.append({
45
+ "image": image_bytes,
46
+ "file_name": file_name,
47
+ "text": text_content
48
+ })
49
+
50
+ if not data_rows:
51
+ return False
52
+
53
+ df = pd.DataFrame(data_rows)
54
+ features = Features({
55
+ "image": Image(),
56
+ "file_name": Value("string"),
57
+ "text": Value("string")
58
+ })
59
+ ds = Dataset.from_pandas(df, features=features)
60
+ ds.to_parquet(parquet_path)
61
+ print(f" ✅ 已生成: {os.path.basename(parquet_path)} ({len(data_rows)} 条数据)")
62
+ return True
63
+
64
+ def get_region_priority(config_name, path_str):
65
+ priority = {"CN": 1, "KR": 2, "JP": 3, "FICTIONAL": 4, "WE": 5}
66
+ path_prefix = path_str.split('/')[0].upper() if path_str else ""
67
+ if not path_prefix:
68
+ for key in priority.keys():
69
+ if key.lower() in config_name.lower():
70
+ return priority[key]
71
+ return 99
72
+ return priority.get(path_prefix, 99)
73
+
74
+ def main():
75
+ api = HfApi(token=HF_TOKEN)
76
+ current_dir = os.getcwd()
77
+
78
+ # 1. 交互输入地区前缀
79
+ print("\n" + "="*50)
80
+ print("请选择该数据集的地区/分类前缀:")
81
+ print("1. CN | 2. KR | 3. JP | 4. Fictional | 5. WE | 6. 自定义")
82
+ choice = input("\n👉 请输入数字或直接输入前缀 (默认回车为 KR): ").strip().upper()
83
+ if not choice: choice = "2"
84
+ mapping = {"1": "CN", "2": "KR", "3": "JP", "4": "FICTIONAL", "5": "WE"}
85
+ region_prefix = mapping.get(choice, choice).replace(" ", "_").replace("-", "_")
86
+ print(f"✅ 已选择前缀: {region_prefix}\n" + "="*50 + "\n")
87
+
88
+ local_folder_name = os.path.basename(current_dir).replace(" ", "_").replace("-", "_")
89
+
90
+ # 2. 拉取云端 YAML
91
+ print(f"☁️ 正在读取云端 {REPO_ID} 的现有配置...")
92
+ try:
93
+ remote_readme_path = api.hf_hub_download(repo_id=REPO_ID, filename="README.md", repo_type=REPO_TYPE)
94
+ with open(remote_readme_path, "r", encoding="utf-8") as f:
95
+ content = f.read()
96
+ card = DatasetCard(content)
97
+ print(" ✅ 成功读取云端 README。")
98
+ except Exception as e:
99
+ print(f" ⚠️ 找不到云端 README,将新建: {e}")
100
+ card = DatasetCard("")
101
+
102
+ yaml_data = card.data if card.data else {}
103
+ if "configs" not in yaml_data: yaml_data["configs"] = []
104
+
105
+ yaml_data["dataset_info"] = {
106
+ "features": [
107
+ {"name": "image", "dtype": "image"},
108
+ {"name": "file_name", "dtype": "string"},
109
+ {"name": "text", "dtype": "string"}
110
+ ]
111
+ }
112
+
113
+ existing_config_names = [c.get("config_name") for c in yaml_data["configs"]]
114
+
115
+ # 3. 本地打包并新增配置
116
+ new_configs_added = False
117
+
118
+ print(f"🔍 正在扫描本地目录: {current_dir}")
119
+ for sub_folder_name in os.listdir(current_dir):
120
+ sub_folder_path = os.path.join(current_dir, sub_folder_name)
121
+
122
+ if os.path.isdir(sub_folder_path) and not sub_folder_name.startswith('.'):
123
+ if generate_parquet_for_folder(sub_folder_path):
124
+
125
+ config_name = f"{local_folder_name}_{sub_folder_name}".lower()
126
+ path_str = f"{region_prefix}/{local_folder_name}/{sub_folder_name}/train.parquet"
127
+
128
+ if config_name not in existing_config_names:
129
+ yaml_data["configs"].append({
130
+ "config_name": config_name,
131
+ "data_files": [{"split": "train", "path": path_str}]
132
+ })
133
+ new_configs_added = True
134
+ print(f" ➕ 已添加配置: {config_name}")
135
+
136
+ # 4. 排序
137
+ def sort_key(config):
138
+ data_files = config.get("data_files", [])
139
+ path = data_files[0].get("path", "") if data_files else ""
140
+ config_name = config.get("config_name", "")
141
+ priority = get_region_priority(config_name, path)
142
+ return (priority, config_name)
143
+
144
+ yaml_data["configs"] = sorted(yaml_data["configs"], key=sort_key)
145
+ print("\n🔄 已根据 [CN > KR > JP > Fictional > WE] 的顺序对 YAML 进行了重排序。")
146
+
147
+ # 5. 保存并仅推送 README.md
148
+ if new_configs_added:
149
+ card.data = yaml_data
150
+
151
+ with tempfile.NamedTemporaryFile(mode='w', encoding='utf-8', suffix='.md', delete=False) as temp_readme:
152
+ temp_readme.write(str(card))
153
+ temp_readme_path = temp_readme.name
154
+
155
+ print("\n🚀 开始推送最新的 README.md 到 Hugging Face...")
156
+ try:
157
+ api.upload_file(
158
+ path_or_fileobj=temp_readme_path,
159
+ path_in_repo="README.md",
160
+ repo_id=REPO_ID,
161
+ repo_type=REPO_TYPE,
162
+ commit_message="Auto-update README YAML configs"
163
+ )
164
+ print("\n🎉 README.md 已成功更新到云端!")
165
+ print("👉 别忘了用你的上传脚本把本地新生成的 train.parquet 和图片传上去哦。")
166
+ except Exception as e:
167
+ print(f"\n❌ README.md 上传失败: {e}")
168
+ finally:
169
+ os.remove(temp_readme_path)
170
+ else:
171
+ print("\n✅ 云端 YAML 已经包含了当前目录的配置,无需更新 README。")
172
+ print("👉 你只需要用你的上传脚本把本地文件传上去即可。")
173
+
174
+ if __name__ == "__main__":
175
+ main()
old/dataset/5_upload2data.py ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from huggingface_hub import HfApi
3
+
4
+ # ==========================================
5
+ # 配置区
6
+ # ==========================================
7
+ api = HfApi(token="***")
8
+
9
+ repo_id = "waveshaker/character_loras" # 你的仓库名
10
+ repo_type = "dataset" # 如果你的仓库是模型仓库,请改为 "model"
11
+ # ==========================================
12
+
13
+ def main():
14
+ current_dir = os.getcwd()
15
+
16
+ # 1. 交互输入地区前缀 (已按最新要求重排序)
17
+ print("="*50)
18
+ print("请选择这批数据上传到哪个地区前缀下:")
19
+ print("1. CN | 2. KR | 3. JP | 4. Fictional | 5. WE | 6. 自定义")
20
+ choice = input("\n👉 请输入数字或直接输入前缀 (默认回车为 KR): ").strip().upper()
21
+
22
+ # 默认回车选 KR (2)
23
+ if not choice:
24
+ choice = "2"
25
+
26
+ # 映射字典同步更新
27
+ mapping = {"1": "CN", "2": "KR", "3": "JP", "4": "Fictional", "5": "WE"}
28
+ region_prefix = mapping.get(choice, choice).replace(" ", "_")
29
+
30
+ # 2. 自动获取当前所在的母文件夹名字
31
+ local_folder_name = os.path.basename(current_dir).replace(" ", "_")
32
+
33
+ print(f"\n✅ 地区前缀: {region_prefix}")
34
+ print(f"✅ 母文件夹名: {local_folder_name}")
35
+ print("="*50 + "\n")
36
+
37
+ # 3. 遍历并上传所有子文件夹
38
+ for sub_folder_name in os.listdir(current_dir):
39
+ sub_folder_path = os.path.join(current_dir, sub_folder_name)
40
+
41
+ # 过滤掉非文件夹和隐藏文件
42
+ if os.path.isdir(sub_folder_path) and not sub_folder_name.startswith('.'):
43
+
44
+ # 动态构建云端路径: 例如 KR/YuJinNyang_KR2/1_clothing
45
+ path_in_repo = f"{region_prefix}/{local_folder_name}/{sub_folder_name}"
46
+
47
+ print(f"📦 开始上传: {sub_folder_name}")
48
+ print(f"📂 目标路径: {path_in_repo}")
49
+
50
+ try:
51
+ api.upload_folder(
52
+ folder_path=sub_folder_path,
53
+ repo_id=repo_id,
54
+ repo_type=repo_type,
55
+ path_in_repo=path_in_repo,
56
+ # 动态 commit 信息
57
+ commit_message=f"Update files for {path_in_repo}",
58
+ # 👇 核心白名单:只上传这四种格式,完美过滤掉 .py 等垃圾文件
59
+ allow_patterns=["*.jpg", "*.jpeg", "*.txt", "*.png", "*.parquet"]
60
+ )
61
+ print(f"🎉 {sub_folder_name} 上传完成!\n")
62
+ except Exception as e:
63
+ print(f"❌ {sub_folder_name} 上传失败: {e}\n")
64
+
65
+ print("✅ 所有子文件夹处理完毕!")
66
+
67
+ if __name__ == "__main__":
68
+ main()
old/dataset/aio.bat ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @echo off
2
+ chcp 65001 >nul
3
+ title 5合1 数据集自动化流水线
4
+ color 07
5
+
6
+ echo ====================================================
7
+ echo 欢迎使用 LoRA 数据集 5合1 自动化流水线
8
+ echo 正在启动...
9
+ echo ====================================================
10
+ echo.
11
+
12
+ :: 检查 Python 是否安装
13
+ python --version >nul 2>&1
14
+ if %errorlevel% neq 0 (
15
+ echo [错误] 未检测到 Python!请先安装 Python 并配置环境变量。
16
+ pause
17
+ exit /b
18
+ )
19
+
20
+ :: 核心修改:调用 C 盘的绝对路径脚本,但工作目录保持在当前文件夹
21
+ python "F:\tool\aio.py"
22
+
23
+ echo.
24
+ echo ====================================================
25
+ echo 任务执行结束!
26
+ echo ====================================================
27
+ pause
old/dataset/aio.py ADDED
@@ -0,0 +1,302 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import glob
3
+ import subprocess
4
+ import pandas as pd
5
+ from datasets import Dataset, Features, Image as HFImage, Value
6
+ from huggingface_hub import HfApi, DatasetCard
7
+ import tempfile
8
+ from PIL import Image
9
+
10
+ # ==========================================
11
+ # 配置区
12
+ # ==========================================
13
+ REPO_ID = "waveshaker/dataset_collections"
14
+ REPO_TYPE = "dataset"
15
+ HF_TOKEN = "" # 请填入你的 Token
16
+ # ==========================================
17
+
18
+ def clean_txt_newlines(current_dir):
19
+ """1. 递归清理所有 txt 文件中的换行符"""
20
+ print("\n" + "="*50)
21
+ print("🧹 [任务 1/5] 正在清理所有 TXT 文件中的换行符...")
22
+ print("="*50)
23
+
24
+ txt_files = glob.glob(os.path.join(current_dir, "**", "*.txt"), recursive=True)
25
+ if not txt_files:
26
+ print(" ✅ 没有找到需要处理的 TXT 文件。")
27
+ return
28
+
29
+ cleaned_count = 0
30
+ for txt_path in txt_files:
31
+ # 跳过根目录下的 txt(可能是说明文档)
32
+ if os.path.dirname(txt_path) == current_dir:
33
+ continue
34
+
35
+ try:
36
+ with open(txt_path, 'r', encoding='utf-8') as f:
37
+ content = ''.join(line.strip() for line in f)
38
+
39
+ with open(txt_path, 'w', encoding='utf-8') as f:
40
+ f.write(content)
41
+ cleaned_count += 1
42
+ except Exception as e:
43
+ print(f" ⚠️ 处理 {os.path.basename(txt_path)} 失败: {e}")
44
+
45
+ print(f" 🎉 TXT 清理完成!共处理了 {cleaned_count} 个文件。")
46
+
47
+ def remove_mask_metadata(current_dir):
48
+ """2. 递归剥离 masklabel.png 的元数据,保护隐私"""
49
+ print("\n" + "="*50)
50
+ print("🛡️ [任务 2/5] 正在剥离 Mask 蒙版图 (masklabel.png) 的元数据...")
51
+ print("="*50)
52
+
53
+ png_files = glob.glob(os.path.join(current_dir, "**", "*.png"), recursive=True)
54
+ mask_files = [f for f in png_files if "masklabel" in os.path.basename(f).lower()]
55
+
56
+ if not mask_files:
57
+ print(" ✅ 没有找到 masklabel.png 文件,跳过此步骤。")
58
+ return
59
+
60
+ success_count = 0
61
+ for file_path in mask_files:
62
+ try:
63
+ with Image.open(file_path) as img:
64
+ # 读取像素数据,彻底断开原元数据
65
+ data = list(img.getdata())
66
+ clean_img = Image.new(img.mode, img.size)
67
+ clean_img.putdata(data)
68
+ # 覆盖保存
69
+ clean_img.save(file_path, "PNG")
70
+ success_count += 1
71
+ print(f" 🔒 已清理元数据: {os.path.basename(file_path)}")
72
+ except Exception as e:
73
+ print(f" ⚠️ 处理失败 [{os.path.basename(file_path)}]: {e}")
74
+
75
+ print(f" 🎉 元数据清理完成!共处理了 {success_count} 张 Mask 图。")
76
+
77
+ def convert_png_to_jpg(current_dir):
78
+ """3. 批量转换常规 png 为 jpg,并删除原 png(绝对跳过 masklabel)"""
79
+ print("\n" + "="*50)
80
+ print("🎬 [任务 3/5] 正在批量转换常规 PNG 为 JPG...")
81
+ print("="*50)
82
+
83
+ png_files = glob.glob(os.path.join(current_dir, "**", "*.png"), recursive=True)
84
+ if not png_files:
85
+ print(" ✅ 没有找到需要转换的 PNG 文件。")
86
+ return
87
+
88
+ converted_count = 0
89
+ for png_path in png_files:
90
+ # 🚨 核心过滤:跳过 masklabel 文件,保证蒙版依然是 png
91
+ if "masklabel" in png_path.lower():
92
+ continue
93
+
94
+ jpg_path = os.path.splitext(png_path)[0] + ".jpg"
95
+
96
+ try:
97
+ subprocess.run(
98
+ ["ffmpeg", "-y", "-i", png_path, "-q:v", "2", jpg_path],
99
+ stdout=subprocess.DEVNULL,
100
+ stderr=subprocess.DEVNULL,
101
+ check=True
102
+ )
103
+ os.remove(png_path)
104
+ converted_count += 1
105
+ print(f" 🔄 转换: {os.path.basename(png_path)} -> {os.path.basename(jpg_path)}")
106
+ except subprocess.CalledProcessError:
107
+ print(f" ⚠️ 转换失败: {png_path}")
108
+ except FileNotFoundError:
109
+ print(" ❌ 错误: 找不到 ffmpeg!请确保已安装并配置了环境变量。")
110
+ return
111
+
112
+ print(f" 🎉 转换完成!共转换 {converted_count} 张图片。")
113
+
114
+ def generate_parquet_and_update_yaml(api, current_dir, region_prefix):
115
+ """4. 本地打包生成 parquet,拉取云端 YAML,追加并重排"""
116
+ print("\n" + "="*50)
117
+ print("📦 [任务 4/5] 正在本地打包 Parquet 并更新 YAML 配置...")
118
+ print("="*50)
119
+
120
+ local_folder_name = os.path.basename(current_dir).replace(" ", "_").replace("-", "_")
121
+
122
+ print(f" ☁️ 正在读取云端 {REPO_ID} 的现有配置...")
123
+ try:
124
+ remote_readme_path = api.hf_hub_download(repo_id=REPO_ID, filename="README.md", repo_type=REPO_TYPE)
125
+ with open(remote_readme_path, "r", encoding="utf-8") as f:
126
+ content = f.read()
127
+ card = DatasetCard(content)
128
+ print(" ✅ 成功读取云端 README。")
129
+ except Exception as e:
130
+ print(f" ⚠️ 找不到云端 README,将新建: {e}")
131
+ card = DatasetCard("")
132
+
133
+ yaml_data = card.data if card.data else {}
134
+ if "configs" not in yaml_data: yaml_data["configs"] = []
135
+
136
+ yaml_data["dataset_info"] = {
137
+ "features": [
138
+ {"name": "image", "dtype": "image"},
139
+ {"name": "file_name", "dtype": "string"},
140
+ {"name": "text", "dtype": "string"}
141
+ ]
142
+ }
143
+
144
+ existing_config_names = [c.get("config_name") for c in yaml_data["configs"]]
145
+ new_configs_added = False
146
+ valid_folders = []
147
+
148
+ for sub_folder_name in os.listdir(current_dir):
149
+ sub_folder_path = os.path.join(current_dir, sub_folder_name)
150
+
151
+ if os.path.isdir(sub_folder_path) and not sub_folder_name.startswith('.'):
152
+ jpg_files = glob.glob(os.path.join(sub_folder_path, "*.jpg")) + glob.glob(os.path.join(sub_folder_path, "*.jpeg"))
153
+ if not jpg_files:
154
+ continue
155
+
156
+ print(f" 📦 正在打包: {sub_folder_name}")
157
+ data_rows = []
158
+
159
+ for jpg_path in jpg_files:
160
+ file_name = os.path.basename(jpg_path)
161
+ base_name = os.path.splitext(file_name)[0]
162
+ txt_path = os.path.join(sub_folder_path, f"{base_name}.txt")
163
+
164
+ text_content = ""
165
+ if os.path.exists(txt_path):
166
+ with open(txt_path, "r", encoding="utf-8") as f:
167
+ text_content = f.read().strip()
168
+
169
+ try:
170
+ with open(jpg_path, "rb") as f:
171
+ image_bytes = {"bytes": f.read(), "path": None}
172
+ except Exception as e:
173
+ print(f" ⚠️ 跳过损坏图片 {file_name}: {e}")
174
+ continue
175
+
176
+ data_rows.append({
177
+ "image": image_bytes,
178
+ "file_name": file_name,
179
+ "text": text_content
180
+ })
181
+
182
+ if data_rows:
183
+ df = pd.DataFrame(data_rows)
184
+ features = Features({
185
+ "image": HFImage(), # 👈 这里加上了 HF
186
+ "file_name": Value("string"),
187
+ "text": Value("string")
188
+ })
189
+ ds = Dataset.from_pandas(df, features=features)
190
+ ds.to_parquet(os.path.join(sub_folder_path, "train.parquet"))
191
+ valid_folders.append(sub_folder_name)
192
+ print(f" ✅ 生成 train.parquet ({len(data_rows)} 条数据)")
193
+
194
+ config_name = f"{local_folder_name}_{sub_folder_name}".lower()
195
+ path_str = f"{region_prefix}/{local_folder_name}/{sub_folder_name}/train.parquet"
196
+
197
+ if config_name not in existing_config_names:
198
+ yaml_data["configs"].append({
199
+ "config_name": config_name,
200
+ "data_files": [{"split": "train", "path": path_str}]
201
+ })
202
+ new_configs_added = True
203
+ print(f" ➕ 已添加配置: {config_name}")
204
+
205
+ def get_priority(config):
206
+ data_files = config.get("data_files", [])
207
+ path = data_files[0].get("path", "") if data_files else ""
208
+ # 直接使用原始大小写,确保与云端路径完全一致
209
+ priority_dict = {"CN": 1, "KR": 2, "JP": 3, "Fictional": 4, "WE": 5}
210
+ path_prefix = path.split('/')[0] if path else ""
211
+ return priority_dict.get(path_prefix, 99)
212
+
213
+ yaml_data["configs"] = sorted(yaml_data["configs"], key=lambda c: (get_priority(c), c.get("config_name", "")))
214
+ print(" 🔄 已根据 [CN > KR > JP > Fictional > WE] 的顺序重排 YAML。")
215
+
216
+ if new_configs_added:
217
+ card.data = yaml_data
218
+ with tempfile.NamedTemporaryFile(mode='w', encoding='utf-8', suffix='.md', delete=False) as temp_readme:
219
+ temp_readme.write(str(card))
220
+ return temp_readme.name, valid_folders
221
+ return None, valid_folders
222
+
223
+ def upload_files_and_readme(api, current_dir, region_prefix, temp_readme_path, valid_folders):
224
+ """5. 上传文件及 README"""
225
+ print("\n" + "="*50)
226
+ print("🚀 [任务 5/5] 正在上传文件到 Hugging Face...")
227
+ print("="*50)
228
+
229
+ local_folder_name = os.path.basename(current_dir).replace(" ", "_").replace("-", "_")
230
+
231
+ for sub_folder_name in valid_folders:
232
+ sub_folder_path = os.path.join(current_dir, sub_folder_name)
233
+ path_in_repo = f"{region_prefix}/{local_folder_name}/{sub_folder_name}"
234
+
235
+ print(f" 📦 开始上传: {sub_folder_name} -> {path_in_repo}")
236
+ try:
237
+ api.upload_folder(
238
+ folder_path=sub_folder_path,
239
+ repo_id=REPO_ID,
240
+ repo_type=REPO_TYPE,
241
+ path_in_repo=path_in_repo,
242
+ commit_message=f"Update files for {path_in_repo}",
243
+ # 上传过滤:保留 masklabel.png,jpg,txt,parquet
244
+ allow_patterns=["*.jpg", "*.jpeg", "*.txt", "*.png", "*.parquet"]
245
+ )
246
+ print(f" 🎉 {sub_folder_name} 上传完成!")
247
+ except Exception as e:
248
+ print(f" ❌ {sub_folder_name} 上传失败: {e}")
249
+
250
+ if temp_readme_path:
251
+ print("\n 📝 正在推送最新的 README.md...")
252
+ try:
253
+ api.upload_file(
254
+ path_or_fileobj=temp_readme_path,
255
+ path_in_repo="README.md",
256
+ repo_id=REPO_ID,
257
+ repo_type=REPO_TYPE,
258
+ commit_message="Auto-update README YAML configs"
259
+ )
260
+ print(" 🎉 README.md 已成功更新到云端!")
261
+ except Exception as e:
262
+ print(f" ❌ README.md 上传失败: {e}")
263
+ finally:
264
+ os.remove(temp_readme_path)
265
+
266
+ def main():
267
+ api = HfApi(token=HF_TOKEN)
268
+ current_dir = os.getcwd()
269
+
270
+ print("\n" + "="*50)
271
+ print("🌟 欢迎使用 5合1 数据集自动化流水线 🌟")
272
+ print("="*50)
273
+
274
+ print("请选择该数据集的地区/分类前缀:")
275
+ print("1. CN | 2. KR | 3. JP | 4. Fictional | 5. WE | 6. 自定义")
276
+ choice = input("\n👉 请输入数字或直接输入前缀 (默认回车为 KR): ").strip().upper()
277
+ if not choice: choice = "2"
278
+ mapping = {"1": "CN", "2": "KR", "3": "JP", "4": "Fictional", "5": "WE"}
279
+ region_prefix = mapping.get(choice, choice).replace(" ", "_").replace("-", "_")
280
+ print(f"\n✅ 已选择前缀: {region_prefix}")
281
+
282
+ # 任务 1:清理 txt 换行符
283
+ clean_txt_newlines(current_dir)
284
+
285
+ # 任务 2:清理 Mask 元数据
286
+ remove_mask_metadata(current_dir)
287
+
288
+ # 任务 3:转换 PNG -> JPG
289
+ convert_png_to_jpg(current_dir)
290
+
291
+ # 任务 4:打包 Parquet 并更新 YAML
292
+ temp_readme_path, valid_folders = generate_parquet_and_update_yaml(api, current_dir, region_prefix)
293
+
294
+ # 任务 5:上传
295
+ upload_files_and_readme(api, current_dir, region_prefix, temp_readme_path, valid_folders)
296
+
297
+ print("\n" + "="*50)
298
+ print("🎉 5合1 全流程处理完毕!")
299
+ print("="*50)
300
+
301
+ if __name__ == "__main__":
302
+ main()