File size: 4,443 Bytes
1ae5927
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
# rag_gemini_chroma_v1_0_1_fixed.py
import os
from typing import Any
from dotenv import load_dotenv
from langchain.agents import create_agent
from langchain_huggingface import HuggingFaceEmbeddings
from langgraph.graph.state import CompiledStateGraph
from pydantic import SecretStr

from huggingface_hub import snapshot_download

# Core types and prompt
from langchain_core.documents import Document

# Document loaders, text splitters, vectorstore (community / ecosystem packages)
from langchain_chroma import Chroma

# Google Gemini provider and embeddings package
from langchain_google_genai import ChatGoogleGenerativeAI

from langchain.tools import tool

import config

# Instead, LCEL (Runnable components) is used for chain composition.

def get_chroma_store(
    chroma_persist_directory: str = config.chroma_persist_directory,
    huggingface_embedding_model_repo_path: str = config.huggingface_embedding_model_repo_path,
    huggingface_vector_embedding_database_repo_path: str = config.huggingface_vector_embedding_database_repo_path,
) -> Chroma:
    """
    Load an existing Chroma store if present, otherwise create from docs and persist.
    
    This version uses lazy loading and batch processing to prevent memory issues.
    """

    embedding_model = HuggingFaceEmbeddings(model_name=huggingface_embedding_model_repo_path)

    # 3) Check for existing Chroma DB and load it
    if os.path.exists(chroma_persist_directory) and os.path.isdir(chroma_persist_directory):
        print(f"✅ Loading existing Chroma DB from: {chroma_persist_directory}")
    else:
        print("📥 No local Chroma DB found. Pulling from Hugging Face dataset...")
        
        # Create local directory
        os.makedirs(chroma_persist_directory, exist_ok=True)
        
        # Download all files from the Hugging Face dataset
        snapshot_download(  # pyright: ignore[reportUnusedCallResult]
            repo_id=huggingface_vector_embedding_database_repo_path,
            repo_type="dataset",
            local_dir=chroma_persist_directory,
            ignore_patterns=["*.md", "*.json"],  # Optional: skip non-DB files like README,
        )
        
        print(f"✅ Pulled and persisted Chroma DB to: {chroma_persist_directory}")
        
    return Chroma(
        embedding_function=embedding_model,
        persist_directory=chroma_persist_directory
    )
    

def create_rag_agent(
    google_llm_model_name: str = config.google_llm_model_name,
    temperature: float = 0.3
) -> CompiledStateGraph[Any]:
    load_dotenv()  # pyright: ignore[reportUnusedCallResult]

    gemini_api_key = os.getenv("GEMINI_API_KEY")
    if not gemini_api_key:
        raise ValueError("Missing GEMINI_API_KEY in environment")

    vector_store = get_chroma_store()

    # 6) Create Gemini chat model (LLM)
    llm = ChatGoogleGenerativeAI(model=google_llm_model_name, temperature=temperature, google_api_key=SecretStr(gemini_api_key))

    # 7) Prompt template
    # Note: The prompt input variables must match the dict passed to the model
    system_prompt = """
        You are provided with a list of sample text that comes from various different user manuals. 
        Your task is to respond to the user using the samples provided to the best of your abilities. 
        The context text is in the following paragraph.

        """
    
    # Helper to format documents for the prompt
    def format_docs(docs: list[Document]) -> str:
        """Formats a list of documents into a single string."""
        return "\n".join(doc.page_content for doc in docs)

    # 8) Build RAG chain using LCEL (LangChain Expression Language)
    # The chain structure is:
    # { 'context': retriever | format_docs, 'input': RunnablePassthrough() } | prompt | llm

    @tool #fonksiyonun hem cevap (content) hem de kaynak/detay (artifact) döndüreceğini belirtir.
    def retrieve_context(query: str) -> str:
        '''Sorguyu yanıtlamaya yardımcı olacak bilgileri getir.'''
        retrieved_docs = vector_store.similarity_search(query, k=5)
        return format_docs(retrieved_docs)

    rag_agent = create_agent(llm, [retrieve_context], system_prompt=system_prompt)

    return rag_agent

if __name__ == "__main__":
    rag_agent = create_rag_agent()
    result: dict[str, Any] | Any = rag_agent.invoke( 
        {"messages": [{"role": "user", "content": "I want to replace the batteries of a sony brand remote. What can I do?"}]}
    )