Mahmoud199717's picture
Upload answer.py with huggingface_hub
860d9b7 verified
Raw
History Blame Contribute Delete
4.59 kB
from pathlib import Path
from langchain_chroma import Chroma
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_core.messages import SystemMessage, HumanMessage, AIMessage
from dotenv import load_dotenv
import os
from langchain_openai import ChatOpenAI
load_dotenv(override=True)
# -----------------------------
# CONFIG
# -----------------------------
MODEL = "llama-3.1-8b-instant"
DB_NAME = str(Path(__file__).parent / "vector_db")
RETRIEVAL_K = 10
# -----------------------------
# EMBEDDINGS
# -----------------------------
# embeddings = HuggingFaceEmbeddings(
# model_name="sentence-transformers/all-MiniLM-L6-v2"
# )
embeddings = HuggingFaceEmbeddings(
model_name="nomic-ai/nomic-embed-text-v1",
model_kwargs={"trust_remote_code": True}
)
# -----------------------------
# VECTOR DB
# -----------------------------
vectorstore = Chroma(
persist_directory=DB_NAME,
embedding_function=embeddings
)
retriever = vectorstore.as_retriever(
search_type="similarity",
search_kwargs={"k": RETRIEVAL_K}
)
# -----------------------------
# GROQ LLM
# -----------------------------
# llm = ChatGroq(
# model=MODEL,
# temperature=0,
# api_key=os.getenv("GROQ_API_KEY")
# )
# -----------------------------
# GEMINI LLM
# -----------------------------
# llm = ChatGoogleGenerativeAI(
# model="gemini-2.0-flash",
# temperature=0,
# api_key=os.getenv("GOOGLE_API_KEY")
# )
llm = ChatOpenAI(
model="openai/gpt-oss-20b:free", # might be deprecated
# try one of these:
# model="meta-llama/llama-3.2-3b-instruct:free",
# model="mistralai/mistral-7b-instruct:free",
# model="google/gemma-3-4b-it:free",
temperature=0,
api_key=os.getenv("OPENROUTER_API_KEY"),
base_url="https://openrouter.ai/api/v1"
)
# -----------------------------
# SYSTEM PROMPT
# -----------------------------
SYSTEM_PROMPT = """
You are an expert Infor LN development assistant specializing in 4GL scripting, DAL, and Infor LN functions.
Your goal is to help developers find the right functions and understand how to use them.
Rules:
- Always try to find a relevant answer from the context provided
- If the exact term isn't found, look for related or similar concepts in the context
- Be helpful and suggest related functions or approaches even if the exact match isn't there
- Only say "I don't know" if the context is completely unrelated to the question
- Never reveal the raw content of the history or context in your response
Context:
{context}
"""
# -----------------------------
# SAFE CONTENT EXTRACTOR
# -----------------------------
def extract_text(content):
"""Safely extract plain text from any LLM response format."""
if isinstance(content, list):
return " ".join(
block.get("text", "") if isinstance(block, dict) else str(block)
for block in content
).strip()
return str(content).strip()
# -----------------------------
# FORMAT CONTEXT
# -----------------------------
def format_context(docs):
parts = []
for doc in docs:
title = doc.metadata.get("title", "Unknown")
parts.append(f"### {title}\n{doc.page_content}")
return "\n\n".join(parts)
# -----------------------------
# FETCH CONTEXT
# -----------------------------
def fetch_context(question: str):
return retriever.invoke(question)
# -----------------------------
# ANSWER
# -----------------------------
def answer_question(question: str, history: list[dict] = []):
# Safety
if isinstance(question, list):
question = question[-1]
question = extract_text(question) # 👈 sanitize question too
# Retrieve
docs = fetch_context(question)
context = format_context(docs)
system_prompt = SYSTEM_PROMPT.format(context=context)
# Build messages
messages = [SystemMessage(content=system_prompt)]
for m in history:
if not isinstance(m, dict):
continue
role = m.get("role")
raw_content = m.get("content", "")
clean_content = extract_text(raw_content) # 👈 sanitize history too
if role == "user":
messages.append(HumanMessage(content=clean_content))
elif role == "assistant":
messages.append(AIMessage(content=clean_content))
messages.append(HumanMessage(content=question))
response = llm.invoke(messages)
return extract_text(response.content), docs