File size: 4,327 Bytes
fb05e78
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
"""
ベクトルストア構築ユーティリティ
"""

import logging
import os
from typing import List, Optional

from dotenv import load_dotenv
from langchain_chroma import Chroma
from langchain_core.documents import Document
from langchain_openai import OpenAIEmbeddings

from .embedding_storage import save_embeddings
from .loader import load_chunks_from_json, display_document_info

logger = logging.getLogger(__name__)

# .envファイルからAPIキーを読み込む
load_dotenv(dotenv_path=".env")


def build_vector_store(
    docs_path: str = 'data/processed/chunks.json',
    persist_dir: str = 'data/vector_store',
    model_name: str = 'text-embedding-3-small',
    save_embeddings_to_file: bool = True,
    embeddings_dir: str = 'data/embeddings'
) -> None:
    """
    ドキュメントチャンクからベクトルストアを構築し、必要に応じて埋め込みも保存する

    Args:
        docs_path: ドキュメントチャンクが格納されたJSONファイルのパス
        persist_dir: ベクトルストアを保存するディレクトリ
        model_name: 使用するOpenAI埋め込みモデル名
        save_embeddings_to_file: 埋め込みを別ファイルに保存するかどうか
        embeddings_dir: 埋め込みを保存するディレクトリ
    """
    logger.debug("OPENAI_API_KEY set: %s", bool(os.getenv("OPENAI_API_KEY")))
    logger.info("全てのインポートが成功しました")
    
    # チャンクJSONからドキュメントを読み込む
    docs_list = load_chunks_from_json(docs_path)
    
    # ドキュメント情報を表示
    display_document_info(docs_list)
    
    # OpenAI埋め込みを初期化
    embeddings = OpenAIEmbeddings(model=model_name)
    logger.info(f"埋め込みモデル初期化済み: {model_name}")
    
    # ドキュメントが存在する場合のみベクトルストアを作成
    if docs_list:
        # 全ドキュメントの埋め込みを生成
        texts = [doc.page_content for doc in docs_list]
        logger.info(f"{len(texts)}件のドキュメントに対して埋め込みを生成中...")
        vectors = embeddings.embed_documents(texts)
        
        # 埋め込みをファイルに保存する場合
        if save_embeddings_to_file:
            embeddings_file = save_embeddings(
                documents=docs_list,
                vectors=vectors,
                model_name=model_name,
                embeddings_dir=embeddings_dir
            )
            logger.info(f"埋め込みを保存しました: {embeddings_file}")
        
        # 生成した埋め込みでChromaベクトルストアを作成
        # Chromaは内部でストレージを管理するためfrom_documentsを利用
        db = Chroma.from_documents(docs_list, embeddings, persist_directory=persist_dir)
        logger.info(f"ベクトルストアを作成し保存しました: {persist_dir}")
        logger.info(f"{len(docs_list)}件のドキュメントチャンクをインデックス化しました")
    else:
        logger.error("インデックス化するドキュメントがありません。chunks.jsonファイルを確認してください。")
        raise ValueError("入力ファイルにドキュメントが見つかりません")


def search_vector_store(
    query: str,
    persist_dir: str = 'data/vector_store',
    k: int = 5,
    model_name: str = 'text-embedding-3-small'
) -> List[Document]:
    """
    ベクトルストアから関連ドキュメントを検索する

    Args:
        query: 検索クエリ
        persist_dir: ベクトルストアが保存されているディレクトリ
        k: 取得するドキュメント数
        model_name: 使用するOpenAI埋め込みモデル名

    Returns:
        関連ドキュメントのリスト
    """
    # OpenAI埋め込みを初期化
    embeddings = OpenAIEmbeddings(model=model_name)
    
    # 保存済みベクトルストアを読み込む
    db = Chroma(persist_directory=persist_dir, embedding_function=embeddings)
    
    # レトリーバーを作成
    retriever = db.as_retriever(
        search_type='similarity',
        search_kwargs={'k': k}
    )
    
    # 関連ドキュメントを取得
    docs = retriever.invoke(query)
    
    return docs