| import os, json |
| from langchain_community.vectorstores import FAISS |
| from langchain_community.embeddings import HuggingFaceEmbeddings |
| from langchain.chains import RetrievalQAWithSourcesChain |
| from langchain_community.chat_models import ChatOllama |
| from langchain_community.llms import HuggingFaceHub |
| from langchain.callbacks.base import BaseCallbackHandler |
| from langchain_core.language_models.base import BaseLanguageModel |
| import logging |
| from langchain.globals import set_debug |
|
|
| |
| set_debug(True) |
| _lc_logger = logging.getLogger("langchain") |
| if not any(isinstance(h, logging.FileHandler) and getattr(h, "baseFilename", "").endswith("langchain_debug.jsonl") for h in _lc_logger.handlers): |
| _fh = logging.FileHandler("langchain_debug.jsonl", mode="a", encoding="utf-8") |
| _fh.setFormatter(logging.Formatter("%(message)s")) |
| _lc_logger.addHandler(_fh) |
| _lc_logger.setLevel(logging.DEBUG) |
|
|
| EMBED_MODEL = "sentence-transformers/all-MiniLM-L6-v2" |
|
|
|
|
| def load_index(index_dir: str = "data"): |
| embeddings = HuggingFaceEmbeddings(model_name=EMBED_MODEL) |
| store = FAISS.load_local(index_dir, embeddings, allow_dangerous_deserialization=True) |
| with open(os.path.join(index_dir, "segments.json")) as f: |
| segments = json.load(f) |
| return store, segments |
|
|
|
|
| class JSONLCallbackHandler(BaseCallbackHandler): |
| """Write simple LangChain events to a JSONL file so UI can display them.""" |
| def __init__(self, path: str = "langchain_debug.jsonl"): |
| self.path = path |
| |
| open(self.path, "w").close() |
|
|
| def _write(self, record): |
| import json, time |
| record["ts"] = time.time() |
| with open(self.path, "a", encoding="utf-8") as f: |
| f.write(json.dumps(record) + "\n") |
|
|
| def on_chain_start(self, serialized, inputs, **kwargs): |
| self._write({"event": "chain_start", "name": serialized.get("name"), "inputs": inputs}) |
|
|
| def on_chain_end(self, outputs, **kwargs): |
| self._write({"event": "chain_end", "outputs": outputs}) |
|
|
| def on_llm_start(self, serialized, prompts, **kwargs): |
| self._write({"event": "llm_start", "prompts": prompts}) |
|
|
| def on_llm_end(self, response, **kwargs): |
| self._write({"event": "llm_end", "response": str(response)}) |
|
|
| def on_retriever_end(self, documents, **kwargs): |
| from langchain.docstore.document import Document |
| preview = [doc.page_content[:200] if isinstance(doc, Document) else str(doc) for doc in documents] |
| self._write({"event": "retriever_end", "documents": preview}) |
|
|
|
|
| def get_model(model_name: str, hf_token: str = None, callbacks: list = None) -> BaseLanguageModel: |
| """Return a model instance based on the model name. |
| |
| Args: |
| model_name: Name of the model to use |
| hf_token: Hugging Face API token (required for flan-t5-base) |
| callbacks: List of callbacks to use |
| """ |
| if model_name == "flan-t5-base": |
| if not hf_token: |
| raise ValueError( |
| "Hugging Face API token is required for flan-t5-base. " |
| "Please provide your Hugging Face token in the UI or use a local model." |
| ) |
| return HuggingFaceHub( |
| repo_id="google/flan-t5-base", |
| huggingfacehub_api_token=hf_token, |
| model_kwargs={"temperature": 0.1, "max_length": 512}, |
| callbacks=callbacks |
| ) |
| else: |
| return ChatOllama(model=model_name, callbacks=callbacks) |
|
|
|
|
| def build_chain(store, model_name: str = "phi3", hf_token: str = None): |
| """Return a RetrievalQA chain using the specified model. |
| |
| Args: |
| store: Vector store with document embeddings |
| model_name: Name of the model to use |
| hf_token: Hugging Face API token (required for flan-t5-base) |
| """ |
| callback = JSONLCallbackHandler() |
| llm = get_model(model_name, hf_token, [callback]) |
| return RetrievalQAWithSourcesChain.from_chain_type( |
| llm=llm, |
| retriever=store.as_retriever(k=4, callbacks=[callback]), |
| return_source_documents=True, |
| verbose=True, |
| ) |
|
|