Spaces:
Paused
Paused
File size: 9,809 Bytes
72f831c 7502aed bef6630 7814b36 7502aed bef6630 7814b36 72f831c 7502aed bef6630 7502aed bef6630 7814b36 bef6630 7814b36 7502aed 0c4a8eb ab83281 0c4a8eb 7502aed 7814b36 7502aed 25c6eb9 7814b36 7502aed bef6630 7814b36 7502aed bef6630 ab83281 25c6eb9 ab83281 7814b36 25c6eb9 7814b36 25c6eb9 7814b36 25c6eb9 7814b36 25c6eb9 7502aed 25c6eb9 7814b36 25c6eb9 7814b36 25c6eb9 7502aed 7814b36 25c6eb9 7502aed bef6630 0c4a8eb 7502aed 7814b36 0c4a8eb 7814b36 ab83281 7814b36 25c6eb9 7814b36 25c6eb9 7502aed 25c6eb9 7502aed 7814b36 7502aed 7814b36 7502aed 7814b36 7502aed ab83281 7502aed 7814b36 7502aed ab83281 7814b36 0c4a8eb 7814b36 7502aed 7814b36 25c6eb9 7502aed 25c6eb9 ab83281 7814b36 7502aed 7814b36 7502aed 7814b36 7502aed 7814b36 7502aed ab83281 7502aed ab83281 7814b36 0c4a8eb 7814b36 0c4a8eb 7502aed 7814b36 7502aed 7814b36 7502aed 7814b36 7502aed 7814b36 7502aed 7814b36 7502aed |
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 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 |
# codingo/chatbot/chatbot.py
"""Interactive chatbot using Microsoft Phi-2 for efficient, quality responses"""
import os
import shutil
from typing import List
import torch
import re
os.environ.setdefault("HF_HOME", "/tmp/huggingface")
os.environ.setdefault("TRANSFORMERS_CACHE", "/tmp/huggingface/transformers")
os.environ.setdefault("HUGGINGFACE_HUB_CACHE", "/tmp/huggingface/hub")
_model = None
_tokenizer = None
_chatbot_embedder = None
_chatbot_collection = None
_knowledge_chunks = []
_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"
# Phi-2: 2.7B params, great performance, fits easily on T4
MODEL_NAME = "microsoft/phi-2"
def _init_model():
global _model, _tokenizer
if _model is not None and _tokenizer is not None:
return
print("Loading Phi-2 model...")
from transformers import AutoModelForCausalLM, AutoTokenizer
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"Using device: {device}")
# Load tokenizer
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME, trust_remote_code=True)
tokenizer.pad_token = tokenizer.eos_token
# Load model
model = AutoModelForCausalLM.from_pretrained(
MODEL_NAME,
torch_dtype=torch.float16,
device_map="auto",
trust_remote_code=True
)
model.eval()
_model = model
_tokenizer = tokenizer
print("Phi-2 loaded successfully!")
def _init_vector_store():
global _chatbot_embedder, _chatbot_collection, _knowledge_chunks
if _chatbot_embedder is not None and _chatbot_collection is not None:
return
print("Initializing vector store...")
from langchain.text_splitter import RecursiveCharacterTextSplitter
from sentence_transformers import SentenceTransformer
import chromadb
from chromadb.config import Settings
# Load knowledge base
try:
with open(_knowledge_base_path, encoding="utf-8") as f:
raw_text = f.read()
print(f"Loaded knowledge base: {len(raw_text)} characters")
except FileNotFoundError:
print("Knowledge base not found!")
raw_text = "Codingo is an AI recruitment platform."
# Split into chunks
splitter = RecursiveCharacterTextSplitter(chunk_size=400, chunk_overlap=50)
docs = [doc.strip() for doc in splitter.split_text(raw_text) if doc.strip()]
_knowledge_chunks = docs # Store for reference
# Create embeddings
embedder = SentenceTransformer("all-MiniLM-L6-v2")
embeddings = embedder.encode(docs, show_progress_bar=False)
# Create ChromaDB collection (in-memory)
client = chromadb.Client(Settings(anonymized_telemetry=False, is_persistent=False))
try:
client.delete_collection("chatbot")
except:
pass
collection = client.create_collection("chatbot")
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
print(f"Vector store ready with {len(docs)} chunks!")
def extract_faq_answer(query: str, docs: List[str]) -> str:
"""Try to find direct FAQ answers"""
query_lower = query.lower()
for doc in docs:
# Look for Q&A patterns
if "Q:" in doc and "A:" in doc:
lines = doc.split('\n')
for i, line in enumerate(lines):
if line.strip().startswith('Q:'):
question = line[2:].strip().lower()
# Check similarity
if any(word in question for word in query_lower.split() if len(word) > 3):
# Find the answer
for j in range(i+1, min(i+5, len(lines))):
if lines[j].strip().startswith('A:'):
return lines[j][2:].strip()
return None
def get_chatbot_response(query: str) -> str:
try:
if not query or not query.strip():
return "Hello! I'm LUNA AI, your Codingo assistant. I can help you with questions about our AI recruitment platform, job matching, CV tips, and more!"
print(f"\nProcessing: '{query}'")
# Clear GPU cache
if torch.cuda.is_available():
torch.cuda.empty_cache()
# Initialize
_init_vector_store()
_init_model()
# Search for relevant context
query_embedding = _chatbot_embedder.encode([query])[0]
results = _chatbot_collection.query(
query_embeddings=[query_embedding.tolist()],
n_results=3
)
retrieved_docs = results.get("documents", [[]])[0] if results else []
print(f"Found {len(retrieved_docs)} relevant chunks")
# Try to find FAQ answer first
faq_answer = extract_faq_answer(query, retrieved_docs)
if faq_answer:
print("Found FAQ match!")
return faq_answer
# Build context from retrieved docs
context = "\n".join(retrieved_docs[:2]) if retrieved_docs else ""
# Create an instruction-following prompt for Phi-2
prompt = f"""Instruct: You are LUNA AI, a helpful assistant for Codingo recruitment platform.
Use the following information to answer the user's question:
{context}
User Question: {query}
Output: Based on the information provided, """
# Tokenize with appropriate length
inputs = _tokenizer(
prompt,
return_tensors="pt",
truncation=True,
max_length=800,
padding=True
)
inputs = {k: v.to(_model.device) for k, v in inputs.items()}
# Generate response
with torch.no_grad():
outputs = _model.generate(
**inputs,
max_new_tokens=200,
temperature=0.7,
do_sample=True,
top_p=0.9,
repetition_penalty=1.15,
pad_token_id=_tokenizer.pad_token_id,
eos_token_id=_tokenizer.eos_token_id,
early_stopping=True
)
# Decode response
full_response = _tokenizer.decode(outputs[0], skip_special_tokens=True)
# Extract only the generated part
response = full_response.split("Output:")[-1].strip()
# Clean up common artifacts
response = response.replace("Based on the information provided,", "").strip()
# Remove the original prompt if it appears
if prompt in response:
response = response.replace(prompt, "").strip()
# Ensure quality response
if len(response) < 20 or response.lower() == query.lower():
# Generate a contextual response
query_lower = query.lower()
if "hello" in query_lower or "hi" in query_lower:
return "Hello! Welcome to Codingo! I'm LUNA AI, here to help you navigate our AI-powered recruitment platform. You can ask me about creating profiles, job matching, improving your CV, or any of our features!"
elif "what" in query_lower and "codingo" in query_lower:
return "Codingo is an innovative AI-driven recruitment platform that transforms how companies hire and how candidates find jobs. We use advanced algorithms to match skills with opportunities, provide instant CV feedback, and streamline the entire hiring process."
elif "how" in query_lower and ("work" in query_lower or "use" in query_lower):
return "Here's how Codingo works: As a candidate, you create a profile, upload your resume, and add portfolio links. Our AI then analyzes your skills and matches you with suitable jobs. You'll receive personalized recommendations and CV improvement tips. For employers, we offer smart candidate filtering and automated screening insights!"
elif "feature" in query_lower or "special" in query_lower:
return "What makes Codingo special is our combination of AI-powered job matching, real-time CV analysis, bias-aware algorithms, and focus on tech professionals. We support various roles from developers to designers, making the hiring process smarter, faster, and fairer for everyone."
else:
# Use context to create a response
if retrieved_docs:
return f"Let me help you with that! {retrieved_docs[0][:250]}..."
else:
return "I'd be happy to help you learn more about Codingo! Could you please ask about specific features like job matching, CV tips, supported job types, or how our platform works?"
print(f"Generated: {response[:100]}...")
return response
except Exception as e:
print(f"Error: {e}")
import traceback
traceback.print_exc()
return "I apologize for the technical issue. Please feel free to ask me about Codingo's features, job matching process, or how to get started!"
# Test the chatbot
if __name__ == "__main__":
print("Testing Codingo Chatbot...")
test_queries = [
"Hello!",
"What is Codingo?",
"How does it work?",
"What job types do you support?",
"How can I improve my match score?",
"Is Codingo free?",
"Tell me about CV tips"
]
for q in test_queries:
response = get_chatbot_response(q)
print(f"\nUser: {q}")
print(f"LUNA: {response}")
print("-" * 80) |