doc-to-vector-dataset-generator について
文書をベクトル検索用データセットに整えるスキルです。抽出、整形、意味単位の分割、メタデータ付与、重複除去、検証、JSONL出力を扱います。
主な機能
- 01PDF、DOCX、HTMLからテキスト抽出
- 02テキスト整形と意味単位の分割
- 03メタデータの付与
- 04類似重複の除去
- 05チャンク品質の検証
- 06JSONLデータセットの出力
活用シーン
- 01ベクトル検索向け文書チャンクの準備
- 02チャンクへの出典と言語メタデータの追加
- 03低品質または重複チャンクの除外
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ patricio0312rev/ skills --skill doc-to-vector-dataset-generatorインストール後、Claude Code で/doc-to-vector-dataset-generatorを入力して読み込まれたか確認します。
詳細
ドキュメントからベクトルデータセットを生成
ドキュメントを高品質なベクトル検索データセットに変換します。
パイプラインの手順
- テキストを抽出します(PDF、DOCX、HTML)
- テキストをクリーニングします(ノイズを除去し、正規化)
- 戦略的にチャンク分割します(意味的な境界)
- メタデータを追加します(ソース、タイムスタンプ、分類)
- 重複を排除します(類似重複の検出)
- 品質をチェックします(長さ、コンテンツの検証)
- JSONL にエクスポートします(1 行につき 1 チャンク)
テキスト抽出
# PDF extraction
import pymupdf
def extract_pdf(filepath: str) -> str:
doc = pymupdf.open(filepath)
text = ""
for page in doc:
text += page.get_text()
return text
# Markdown extraction
def extract_markdown(filepath: str) -> str:
with open(filepath) as f:
return f.read()
テキストのクリーニング
import re
def clean_text(text: str) -> str:
# Remove extra whitespace
text = re.sub(r'\s+', ' ', text)
# Remove page numbers
text = re.sub(r'Page \d+', '', text)
# Remove URLs (optional)
text = re.sub(r'http\S+', '', text)
# Normalize unicode
text = text.encode('utf-8', 'ignore').decode('utf-8')
return text.strip()
意味に基づくチャンク分割
def semantic_chunk(text: str, max_chunk_size: int = 1000) -> List[str]:
"""Chunk at semantic boundaries (paragraphs, sentences)"""
# Split by paragraphs first
paragraphs = text.split('\n\n')
chunks = []
current_chunk = ""
for para in paragraphs:
if len(current_chunk) + len(para) <= max_chunk_size:
current_chunk += para + "\n\n"
else:
if current_chunk:
chunks.append(current_chunk.strip())
current_chunk = para + "\n\n"
if current_chunk:
chunks.append(current_chunk.strip())
return chunks
メタデータの抽出
def extract_metadata(filepath: str, chunk: str, chunk_idx: int) -> dict:
return {
"source": filepath,
"chunk_id": f"{hash(filepath)}_{chunk_idx}",
"chunk_index": chunk_idx,
"char_count": len(chunk),
"word_count": len(chunk.split()),
"created_at": datetime.now().isoformat(),
# Content classification
"has_code": bool(re.search(r'```|def |class |function', chunk)),
"has_table": bool(re.search(r'\|.*\|', chunk)),
"language": detect_language(chunk),
}
重複排除
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
def deduplicate_chunks(chunks: List[dict], threshold: float = 0.95) -> List[dict]:
"""Remove near-duplicate chunks"""
texts = [c["text"] for c in chunks]
# Compute TF-IDF vectors
vectorizer = TfidfVectorizer()
vectors = vectorizer.fit_transform(texts)
# Compute pairwise similarity
similarity_matrix = cosine_similarity(vectors)
# Find duplicates
to_remove = set()
for i in range(len(chunks)):
if i in to_remove:
continue
for j in range(i+1, len(chunks)):
if similarity_matrix[i][j] > threshold:
to_remove.add(j)
# Return unique chunks
return [c for i, c in enumerate(chunks) if i not in to_remove]
品質チェック
def quality_check(chunk: dict) -> bool:
"""Validate chunk quality"""
text = chunk["text"]
# Min length check
if len(text) < 50:
return False
# Max length check
if len(text) > 5000:
return False
# Content check (not just numbers/symbols)
alpha_ratio = sum(c.isalpha() for c in text) / len(text)
if alpha_ratio < 0.5:
return False
# Language check (English only)
if chunk["metadata"]["language"] != "en":
return False
return True
JSONL エクスポート
import json
def export_jsonl(chunks: List[dict], output_path: str):
"""Export chunks as JSONL (one JSON object per line)"""
with open(output_path, 'w') as f:
for chunk in chunks:
f.write(json.dumps(chunk) + '\n')
# Example output format
{
"text": "Chunk text content here...",
"metadata": {
"source": "docs/auth.md",
"chunk_id": "abc123_0",
"chunk_index": 0,
"char_count": 542,
"word_count": 89,
"has_code": true
}
}
完全なパイプライン
def process_documents(input_dir: str, output_path: str):
all_chunks = []
# Process each document
for filepath in glob(f"{input_dir}/**/*.md"):
# Extract and clean
text = extract_markdown(filepath)
text = clean_text(text)
# Chunk
chunks = semantic_chunk(text)
# Add metadata
for i, chunk in enumerate(chunks):
chunk_obj = {
"text": chunk,
"metadata": extract_metadata(filepath, chunk, i)
}
# Quality check
if quality_check(chunk_obj):
all_chunks.append(chunk_obj)
# Deduplicate
unique_chunks = deduplicate_chunks(all_chunks)
# Export
export_jsonl(unique_chunks, output_path)
print(f"Processed {len(unique_chunks)} chunks")
ベストプラクティス
- 意味的な境界でチャンク分割します
- フィルタリング用の豊富なメタデータを用意します
- 重複を積極的に排除します
- 品質チェックで不適切なデータを防ぎます
- ストリーミングには JSONL 形式を使用します
- データセットをバージョン管理します
出力チェックリスト
- すべての形式からテキストを抽出
- クリーニングパイプラインを実装
- 意味に基づくチャンク分割戦略
- メタデータスキーマを定義
- 重複排除ロジック
- 品質検証チェック
- JSONL エクスポート形式
- データセットの統計情報を記録
コメント
Markdown 対応