Skip to content

Commit 9695a14

Browse files
committed
add a CLI to run AI Search operation
1 parent 857d16a commit 9695a14

File tree

3 files changed

+167
-0
lines changed

3 files changed

+167
-0
lines changed

.env.template

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ COSMOSDB_PARTITION_KEY="/id"
4545
SQL_DATABASE_URI="sqlite:///template_langgraph.db"
4646
# SQL_DATABASE_URI="postgresql://user:password@localhost:5432/db"
4747

48+
# Azure AI Search Settings
49+
AI_SEARCH_ENDPOINT="https://xxx.search.windows.net/"
50+
AI_SEARCH_KEY="xxx"
51+
AI_SEARCH_INDEX_NAME="kabuto"
52+
4853
# ---------
4954
# Utilities
5055
# ---------

scripts/ai_search_operator.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import logging
2+
3+
import typer
4+
from dotenv import load_dotenv
5+
6+
from template_langgraph.loggers import get_logger
7+
from template_langgraph.tools.ai_search_tool import AiSearchClientWrapper
8+
from template_langgraph.utilities.csv_loaders import CsvLoaderWrapper
9+
from template_langgraph.utilities.pdf_loaders import PdfLoaderWrapper
10+
11+
# Initialize the Typer application
12+
app = typer.Typer(
13+
add_completion=False,
14+
help="AI Search operator CLI",
15+
)
16+
17+
# Set up logging
18+
logger = get_logger(__name__)
19+
20+
21+
@app.command()
22+
def add_documents(
23+
verbose: bool = typer.Option(
24+
False,
25+
"--verbose",
26+
"-v",
27+
help="Enable verbose output",
28+
),
29+
):
30+
# Set up logging
31+
if verbose:
32+
logger.setLevel(logging.DEBUG)
33+
34+
# Load documents from PDF files
35+
pdf_documents = PdfLoaderWrapper().load_pdf_docs()
36+
logger.info(f"Loaded {len(pdf_documents)} documents from PDF.")
37+
38+
# Load documents from CSV files
39+
csv_documents = CsvLoaderWrapper().load_csv_docs()
40+
logger.info(f"Loaded {len(csv_documents)} documents from CSV.")
41+
42+
# Combine all documents
43+
documents = pdf_documents + csv_documents
44+
logger.info(f"Total documents to add: {len(documents)}")
45+
46+
# Add documents to AI Search
47+
ai_search_client = AiSearchClientWrapper()
48+
ids = ai_search_client.add_documents(
49+
documents=documents,
50+
)
51+
logger.info(f"Added {len(ids)} documents to AI Search.")
52+
for id in ids:
53+
logger.debug(f"Added document ID: {id}")
54+
55+
56+
@app.command()
57+
def similarity_search(
58+
query: str = typer.Option(
59+
"禅モード",
60+
"--query",
61+
"-q",
62+
help="Query to search in the AI Search index",
63+
),
64+
k: int = typer.Option(
65+
5,
66+
"--k",
67+
"-k",
68+
help="Number of results to return from the similarity search",
69+
),
70+
verbose: bool = typer.Option(
71+
False,
72+
"--verbose",
73+
"-v",
74+
help="Enable verbose output",
75+
),
76+
):
77+
# Set up logging
78+
if verbose:
79+
logger.setLevel(logging.DEBUG)
80+
81+
logger.info(f"Searching AI Search with query: {query}")
82+
83+
# Perform similarity search
84+
ai_search_client = AiSearchClientWrapper()
85+
documents = ai_search_client.similarity_search(
86+
query=query,
87+
k=k, # Number of results to return
88+
)
89+
logger.info(f"Found {len(documents)} results for query: {query}")
90+
91+
# Log the results
92+
for i, document in enumerate(documents, start=1):
93+
logger.debug("-" * 40)
94+
logger.debug(f"#{i}: {document.model_dump_json(indent=2)}")
95+
96+
97+
if __name__ == "__main__":
98+
load_dotenv(
99+
override=True,
100+
verbose=True,
101+
)
102+
app()
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
from functools import lru_cache
2+
3+
from langchain_community.vectorstores.azuresearch import AzureSearch
4+
from langchain_core.documents import Document
5+
from pydantic_settings import BaseSettings, SettingsConfigDict
6+
7+
from template_langgraph.llms.azure_openais import AzureOpenAiWrapper
8+
9+
10+
class Settings(BaseSettings):
11+
ai_search_key: str = "<your-ai-search-key>"
12+
ai_search_endpoint: str = "<your-ai-search-endpoint>"
13+
ai_search_index_name: str = "<your-ai-index-name>"
14+
15+
model_config = SettingsConfigDict(
16+
env_file=".env",
17+
env_ignore_empty=True,
18+
extra="ignore",
19+
)
20+
21+
22+
@lru_cache
23+
def get_ai_search_settings() -> Settings:
24+
"""Get AI Search settings."""
25+
return Settings()
26+
27+
28+
class AiSearchClientWrapper:
29+
def __init__(
30+
self,
31+
settings: Settings = None,
32+
):
33+
if settings is None:
34+
settings = get_ai_search_settings()
35+
self.vector_store: AzureSearch = AzureSearch(
36+
azure_search_endpoint=settings.ai_search_endpoint,
37+
azure_search_key=settings.ai_search_key,
38+
index_name=settings.ai_search_index_name,
39+
embedding_function=AzureOpenAiWrapper().embedding_model.embed_query,
40+
)
41+
42+
def add_documents(
43+
self,
44+
documents: list[Document],
45+
) -> list[str]:
46+
"""Add documents to a Cosmos DB container."""
47+
return self.vector_store.add_documents(
48+
documents=documents,
49+
)
50+
51+
def similarity_search(
52+
self,
53+
query: str,
54+
k: int = 5,
55+
) -> list[Document]:
56+
"""Perform a similarity search in the Cosmos DB index."""
57+
return self.vector_store.similarity_search(
58+
query=query,
59+
k=k, # Number of results to return
60+
)

0 commit comments

Comments
 (0)