Spaces:
Paused
Paused
File size: 5,268 Bytes
72f831c bef6630 72f831c bef6630 72f831c bef6630 72f831c bef6630 72f831c bef6630 72f831c bef6630 72f831c bef6630 72f831c bef6630 72f831c bef6630 72f831c bef6630 72f831c |
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 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
# codingo/chatbot/chatbot.py
"""Chatbot module for Codingo …
Default model changed to blenderbot-400M-distill; generation uses max_new_tokens; fallback between causal and seq2seq models."""
import os
import shutil
from typing import List
os.environ.setdefault("HF_HOME", "/tmp/huggingface")
os.environ.setdefault("TRANSFORMERS_CACHE", "/tmp/huggingface/transformers")
os.environ.setdefault("HUGGINGFACE_HUB_CACHE", "/tmp/huggingface/hub")
_hf_model = None
_hf_tokenizer = None
_chatbot_embedder = None
_chatbot_collection = None
_current_dir = os.path.dirname(os.path.abspath(__file__))
_knowledge_base_path = os.path.join(_current_dir, "chatbot.txt")
_chroma_db_dir = "/tmp/chroma_db"
DEFAULT_MODEL_NAME = "facebook/blenderbot-400M-distill"
def _init_hf_model() -> None:
from transformers import (
AutoModelForCausalLM,
AutoModelForSeq2SeqLM,
AutoTokenizer,
)
import torch
global _hf_model, _hf_tokenizer
if _hf_model is not None and _hf_tokenizer is not None:
return
model_name = os.getenv("HF_CHATBOT_MODEL", DEFAULT_MODEL_NAME)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
tokenizer = AutoTokenizer.from_pretrained(model_name)
try:
model = AutoModelForCausalLM.from_pretrained(model_name)
except Exception:
model = AutoModelForSeq2SeqLM.from_pretrained(model_name)
model = model.to(device)
if tokenizer.pad_token is None:
tokenizer.pad_token = tokenizer.eos_token
_hf_model = model
_hf_tokenizer = tokenizer
def _init_vector_store() -> None:
global _chatbot_embedder, _chatbot_collection
if _chatbot_embedder is not None and _chatbot_collection is not None:
return
from langchain.text_splitter import RecursiveCharacterTextSplitter
from sentence_transformers import SentenceTransformer
import chromadb
from chromadb.config import Settings
shutil.rmtree("/app/chatbot/chroma_db", ignore_errors=True)
os.makedirs(_chroma_db_dir, exist_ok=True)
try:
with open(_knowledge_base_path, encoding="utf-8") as f:
raw_text = f.read()
except FileNotFoundError:
raw_text = (
"Codingo is an AI-powered recruitment platform designed to "
"streamline job applications, candidate screening, and hiring. "
"We make hiring smarter, faster, and fairer through automation "
"and intelligent recommendations."
)
splitter = RecursiveCharacterTextSplitter(chunk_size=300, chunk_overlap=100)
docs: List[str] = [doc.strip() for doc in splitter.split_text(raw_text) if doc.strip()]
embedder = SentenceTransformer("all-MiniLM-L6-v2")
embeddings = embedder.encode(docs, show_progress_bar=False, batch_size=32)
client = chromadb.Client(Settings(
persist_directory=_chroma_db_dir,
anonymized_telemetry=False,
is_persistent=True,
))
collection = client.get_or_create_collection("chatbot")
try:
existing = collection.get(limit=1)
if not existing.get("documents"):
raise ValueError("Empty Chroma DB")
except Exception:
ids = [f"doc_{i}" for i in range(len(docs))]
collection.add(documents=docs, embeddings=embeddings.tolist(), ids=ids)
_chatbot_embedder = embedder
_chatbot_collection = collection
def get_chatbot_response(query: str) -> str:
if not query or not query.strip():
return "Please type a question about the Codingo platform."
_init_vector_store()
_init_hf_model()
embedder = _chatbot_embedder
collection = _chatbot_collection
model = _hf_model
tokenizer = _hf_tokenizer
import torch
query_embedding = embedder.encode([query])[0]
results = collection.query(query_embeddings=[query_embedding.tolist()], n_results=3)
retrieved_docs = results.get("documents", [[]])[0] if results else []
context = "\n".join(retrieved_docs[:3])
system_instruction = (
"You are LUNA AI, a helpful assistant for the Codingo recruitment "
"platform. Use the provided context to answer questions about "
"Codingo. If the question is not related to Codingo, politely "
"redirect the conversation. Keep responses concise and friendly."
)
prompt = f"{system_instruction}\n\nContext:\n{context}\n\nUser: {query}\nLUNA AI:"
inputs = tokenizer.encode(
prompt, return_tensors="pt", truncation=True, max_length=512, padding=True
).to(model.device)
with torch.no_grad():
output_ids = model.generate(
inputs,
max_new_tokens=150,
num_beams=3,
do_sample=True,
temperature=0.7,
pad_token_id=tokenizer.eos_token_id,
eos_token_id=tokenizer.eos_token_id,
early_stopping=True,
)
response = tokenizer.decode(output_ids[0], skip_special_tokens=True)
if "LUNA AI:" in response:
response = response.split("LUNA AI:")[-1].strip()
elif prompt in response:
response = response.replace(prompt, "").strip()
return (
response
if response
else "I'm here to help you with questions about the Codingo platform. What would you like to know?"
)
|