mcpField
D
doc-to-vector-dataset-generator

doc-to-vector-dataset-generator

github.com/patricio0312revデータ・データベース63214 回インストール41 週間前に更新
リポジトリ

doc-to-vector-dataset-generator について

文書をベクトル検索用データセットに整えるスキルです。抽出、整形、意味単位の分割、メタデータ付与、重複除去、検証、JSONL出力を扱います。

主な機能

  1. 01PDF、DOCX、HTMLからテキスト抽出
  2. 02テキスト整形と意味単位の分割
  3. 03メタデータの付与
  4. 04類似重複の除去
  5. 05チャンク品質の検証
  6. 06JSONLデータセットの出力

活用シーン

  1. 01ベクトル検索向け文書チャンクの準備
  2. 02チャンクへの出典と言語メタデータの追加
  3. 03低品質または重複チャンクの除外

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/patricio0312rev/skills --skill doc-to-vector-dataset-generator

インストール後、Claude Code で/doc-to-vector-dataset-generatorを入力して読み込まれたか確認します。

詳細

ドキュメントからベクトルデータセットを生成

ドキュメントを高品質なベクトル検索データセットに変換します。

パイプラインの手順

  1. テキストを抽出します(PDF、DOCX、HTML)
  2. テキストをクリーニングします(ノイズを除去し、正規化)
  3. 戦略的にチャンク分割します(意味的な境界)
  4. メタデータを追加します(ソース、タイムスタンプ、分類)
  5. 重複を排除します(類似重複の検出)
  6. 品質をチェックします(長さ、コンテンツの検証)
  7. 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 エクスポート形式
  • データセットの統計情報を記録

コメント