Add files
Browse files- .gitignore +45 -0
- DB.py +49 -0
- DockerFile +16 -0
- Embedder.py +31 -0
- Evaluator.py +40 -0
- LICENSE +21 -0
- Models.py +38 -0
- Parser.py +18 -0
- README copy.md +2 -0
- Scheduler.py +85 -0
- __init__.py +0 -0
- app.py +193 -0
- requirements.txt +18 -0
.gitignore
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Environment variables
|
| 2 |
+
.env
|
| 3 |
+
.env.local
|
| 4 |
+
.env.development.local
|
| 5 |
+
.env.test.local
|
| 6 |
+
.env.production.local
|
| 7 |
+
|
| 8 |
+
# Python
|
| 9 |
+
__pycache__/
|
| 10 |
+
*.py[cod]
|
| 11 |
+
*$py.class
|
| 12 |
+
*.so
|
| 13 |
+
.Python
|
| 14 |
+
build/
|
| 15 |
+
develop-eggs/
|
| 16 |
+
dist/
|
| 17 |
+
downloads/
|
| 18 |
+
eggs/
|
| 19 |
+
.eggs/
|
| 20 |
+
lib/
|
| 21 |
+
lib64/
|
| 22 |
+
parts/
|
| 23 |
+
sdist/
|
| 24 |
+
var/
|
| 25 |
+
wheels/
|
| 26 |
+
*.egg-info/
|
| 27 |
+
.installed.cfg
|
| 28 |
+
*.egg
|
| 29 |
+
MANIFEST
|
| 30 |
+
|
| 31 |
+
# Virtual environments
|
| 32 |
+
.venv/
|
| 33 |
+
venv/
|
| 34 |
+
ENV/
|
| 35 |
+
env/
|
| 36 |
+
|
| 37 |
+
# IDE
|
| 38 |
+
.vscode/
|
| 39 |
+
.idea/
|
| 40 |
+
*.swp
|
| 41 |
+
*.swo
|
| 42 |
+
|
| 43 |
+
# OS
|
| 44 |
+
.DS_Store
|
| 45 |
+
Thumbs.db
|
DB.py
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from dotenv import load_dotenv
|
| 3 |
+
import psycopg2
|
| 4 |
+
import mysql.connector as sql
|
| 5 |
+
|
| 6 |
+
load_dotenv()
|
| 7 |
+
|
| 8 |
+
class DB:
|
| 9 |
+
def __init__(self):
|
| 10 |
+
self.string = os.getenv("Connection_String")
|
| 11 |
+
self.collection = os.getenv("Collection_Name")
|
| 12 |
+
self.host = os.getenv("Host")
|
| 13 |
+
self.port = os.getenv("Port")
|
| 14 |
+
self.user = os.getenv("User")
|
| 15 |
+
self.password = os.getenv("Password")
|
| 16 |
+
self.db = os.getenv("DB_Name")
|
| 17 |
+
|
| 18 |
+
def connect_PS(self):
|
| 19 |
+
self.connection_PS = psycopg2.connect(self.string)
|
| 20 |
+
self.cursor_PS = self.connection_PS.cursor()
|
| 21 |
+
|
| 22 |
+
def connect_MS(self):
|
| 23 |
+
self.connection_MS = sql.connect(
|
| 24 |
+
host = self.host,
|
| 25 |
+
port = self.port,
|
| 26 |
+
user = self.user,
|
| 27 |
+
password = self.password,
|
| 28 |
+
database = self.db
|
| 29 |
+
)
|
| 30 |
+
self.cursor_MS = self.connection_MS.cursor()
|
| 31 |
+
|
| 32 |
+
def insert(self, data):
|
| 33 |
+
insert_query = f"INSERT INTO users(name,email,date,time,password,score) VALUES %s"
|
| 34 |
+
self.cursor_MS.execute(insert_query, (data,))
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def clear(self):
|
| 38 |
+
self.cursor_PS.execute(f"DELETE FROM {self.collection}")
|
| 39 |
+
self.connection_PS.commit()
|
| 40 |
+
|
| 41 |
+
def close_PS(self):
|
| 42 |
+
self.cursor_PS.close()
|
| 43 |
+
self.connection_PS.close()
|
| 44 |
+
|
| 45 |
+
def close_MS(self):
|
| 46 |
+
self.cursor_MS.close()
|
| 47 |
+
self.connection_MS.close()
|
| 48 |
+
|
| 49 |
+
|
DockerFile
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Read the doc: https://huggingface.co/docs/hub/spaces-sdks-docker
|
| 2 |
+
# you will also find guides on how best to write your Dockerfile
|
| 3 |
+
|
| 4 |
+
FROM python:3.9
|
| 5 |
+
|
| 6 |
+
RUN useradd -m -u 1000 user
|
| 7 |
+
USER user
|
| 8 |
+
ENV PATH="/home/user/.local/bin:$PATH"
|
| 9 |
+
|
| 10 |
+
WORKDIR /app
|
| 11 |
+
|
| 12 |
+
COPY --chown=user ./requirements.txt requirements.txt
|
| 13 |
+
RUN pip install --no-cache-dir --upgrade -r requirements.txt
|
| 14 |
+
|
| 15 |
+
COPY --chown=user . /app
|
| 16 |
+
CMD ["gunicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
|
Embedder.py
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from langchain_google_genai import GoogleGenerativeAIEmbeddings
|
| 2 |
+
from dotenv import load_dotenv
|
| 3 |
+
from langchain_postgres import PGVector
|
| 4 |
+
from langchain_core.documents import Document
|
| 5 |
+
import os
|
| 6 |
+
import json
|
| 7 |
+
|
| 8 |
+
load_dotenv()
|
| 9 |
+
class Embed:
|
| 10 |
+
def __init__(self):
|
| 11 |
+
API = os.getenv("API_KEY")
|
| 12 |
+
self.embeddings = GoogleGenerativeAIEmbeddings(google_api_key = API,
|
| 13 |
+
model="models/text-embedding-004")
|
| 14 |
+
|
| 15 |
+
def create_db(self,String,Name):
|
| 16 |
+
self.db = PGVector(self.embeddings,connection = String,collection_name = Name,use_jsonb = True)
|
| 17 |
+
|
| 18 |
+
def create_document(self,n,resume):
|
| 19 |
+
json_res = json.loads(resume)
|
| 20 |
+
return Document(
|
| 21 |
+
page_content = f"{resume}",
|
| 22 |
+
metadata = {"id": n, "name": json_res["name"] , "email": json_res["email"]}
|
| 23 |
+
)
|
| 24 |
+
def add_docs(self,documents):
|
| 25 |
+
self.db.add_documents(documents=documents)
|
| 26 |
+
|
| 27 |
+
def match(self,skills,select):
|
| 28 |
+
result = self.db.similarity_search(skills,k = select)
|
| 29 |
+
return result
|
| 30 |
+
|
| 31 |
+
|
Evaluator.py
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from Models import Model
|
| 2 |
+
from dotenv import load_dotenv
|
| 3 |
+
import os
|
| 4 |
+
|
| 5 |
+
load_dotenv()
|
| 6 |
+
|
| 7 |
+
class InterviewEvaluator(Model):
|
| 8 |
+
def __init__(self,model,tech=None,non_tech=None):
|
| 9 |
+
PROMPT = os.getenv("Eval_prompt")
|
| 10 |
+
super().__init__(PROMPT,model)
|
| 11 |
+
self.tech_questions = [
|
| 12 |
+
"What is a stack data structure?",
|
| 13 |
+
"What is a queue data structure?",
|
| 14 |
+
"What is object-oriented programming?",
|
| 15 |
+
"What is an API?",
|
| 16 |
+
"What is a database index?"
|
| 17 |
+
]
|
| 18 |
+
self.non_tech_questions = [
|
| 19 |
+
"Can you introduce yourself?",
|
| 20 |
+
"What are your strengths?",
|
| 21 |
+
"How do you handle stress or pressure?",
|
| 22 |
+
"Why do you want to work with our organization?",
|
| 23 |
+
"Describe a challenge you faced and how you overcame it."
|
| 24 |
+
]
|
| 25 |
+
|
| 26 |
+
def ask(self,id):
|
| 27 |
+
if id:
|
| 28 |
+
return self.tech_questions
|
| 29 |
+
else:
|
| 30 |
+
return self.non_tech_questions
|
| 31 |
+
|
| 32 |
+
def edit(self,questions,id):
|
| 33 |
+
if id:
|
| 34 |
+
self.tech_questions = questions
|
| 35 |
+
else:
|
| 36 |
+
self.non_tech_questions = questions
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
def score_candid(self,candidate_output):
|
| 40 |
+
return self.send(candidate_output)
|
LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MIT License
|
| 2 |
+
|
| 3 |
+
Copyright (c) 2026 Karthik Reddy
|
| 4 |
+
|
| 5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 6 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 7 |
+
in the Software without restriction, including without limitation the rights
|
| 8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 9 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 10 |
+
furnished to do so, subject to the following conditions:
|
| 11 |
+
|
| 12 |
+
The above copyright notice and this permission notice shall be included in all
|
| 13 |
+
copies or substantial portions of the Software.
|
| 14 |
+
|
| 15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 21 |
+
SOFTWARE.
|
Models.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from dotenv import load_dotenv
|
| 3 |
+
from google import genai
|
| 4 |
+
import json
|
| 5 |
+
|
| 6 |
+
load_dotenv()
|
| 7 |
+
class Model:
|
| 8 |
+
def __init__(self,PROMPT,model_inp):
|
| 9 |
+
API_KEY = os.getenv("GOOGLE_API_KEY")
|
| 10 |
+
self.client = genai.Client(api_key=API_KEY)
|
| 11 |
+
self.chat = self.client.chats.create(model = model_inp)
|
| 12 |
+
response = self.chat.send_message(PROMPT)
|
| 13 |
+
|
| 14 |
+
def json(self,text):
|
| 15 |
+
if not text.strip():
|
| 16 |
+
return ""
|
| 17 |
+
|
| 18 |
+
s_idx = text.find("{")
|
| 19 |
+
e_idx = text.rfind("}") + 1
|
| 20 |
+
|
| 21 |
+
if s_idx == -1 or e_idx == -1 :
|
| 22 |
+
return ""
|
| 23 |
+
|
| 24 |
+
try:
|
| 25 |
+
output = json.loads(text[s_idx:e_idx])
|
| 26 |
+
except Exception as e:
|
| 27 |
+
raise ValueError(f"Error Parsing {e}")
|
| 28 |
+
|
| 29 |
+
return output if output else ""
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def send(self,content):
|
| 33 |
+
response = self.chat.send_message(content)
|
| 34 |
+
result = self.json(response.text)
|
| 35 |
+
return result
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
|
Parser.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from langchain_community.document_loaders import PyPDFLoader
|
| 2 |
+
|
| 3 |
+
class Parser():
|
| 4 |
+
def __init__(self):
|
| 5 |
+
pass
|
| 6 |
+
def parse(self,file_path):
|
| 7 |
+
loader = PyPDFLoader(file_path)
|
| 8 |
+
pages = loader.load_and_split()
|
| 9 |
+
no_of_pages = pages[0].metadata["total_pages"]
|
| 10 |
+
content = []
|
| 11 |
+
for i in range(no_of_pages):
|
| 12 |
+
content.append(pages[i].page_content)
|
| 13 |
+
|
| 14 |
+
return {
|
| 15 |
+
"content": content,
|
| 16 |
+
"no_of_pages": no_of_pages
|
| 17 |
+
}
|
| 18 |
+
|
README copy.md
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# AxionAI
|
| 2 |
+
AI platform that automates resume screening, interview scheduling, and candidate analysis - boosting efficiency while keeping humans in control of key decisions.
|
Scheduler.py
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import pandas as pd
|
| 2 |
+
import smtplib
|
| 3 |
+
import ssl
|
| 4 |
+
import os
|
| 5 |
+
from email.mime.text import MIMEText
|
| 6 |
+
from email.mime.multipart import MIMEMultipart
|
| 7 |
+
from dotenv import load_dotenv
|
| 8 |
+
from datetime import datetime, timedelta
|
| 9 |
+
|
| 10 |
+
load_dotenv()
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
class Schedule:
|
| 14 |
+
def __init__(self):
|
| 15 |
+
self.server = "smtp.gmail.com"
|
| 16 |
+
self.port = 587
|
| 17 |
+
self.sender = "axionai101@gmail.com"
|
| 18 |
+
self.password = os.getenv("app_password")
|
| 19 |
+
|
| 20 |
+
def defaults(self,start_date,start_time,slot_length):
|
| 21 |
+
self.date = start_date
|
| 22 |
+
self.time = start_time
|
| 23 |
+
self.slot_length = slot_length
|
| 24 |
+
|
| 25 |
+
def schedule_slots(self, file_path):
|
| 26 |
+
self.df = pd.read_csv(file_path)
|
| 27 |
+
|
| 28 |
+
# Combine date and time into datetime object
|
| 29 |
+
start_datetime = datetime.strptime(
|
| 30 |
+
f"{self.date} {self.time}", "%Y-%m-%d %H:%M"
|
| 31 |
+
)
|
| 32 |
+
|
| 33 |
+
slots = []
|
| 34 |
+
|
| 35 |
+
for i in range(len(self.df)):
|
| 36 |
+
slot_start = start_datetime + timedelta(minutes=i * self.slot_length)
|
| 37 |
+
slot_end = slot_start + timedelta(minutes=self.slot_length)
|
| 38 |
+
|
| 39 |
+
slot_str = f"{slot_start.strftime('%Y-%m-%d %H:%M')} - {slot_end.strftime('%H:%M')}"
|
| 40 |
+
slots.append(slot_str)
|
| 41 |
+
|
| 42 |
+
self.df["Slot"] = slots
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
def send_emails(self):
|
| 46 |
+
names = self.df["Name"]
|
| 47 |
+
emails = self.df["Email"]
|
| 48 |
+
slots = self.df["Slot"]
|
| 49 |
+
for name,email,slot in zip(names,emails,slots):
|
| 50 |
+
message = MIMEMultipart("alternative")
|
| 51 |
+
message["Subject"] = "Interview Invitation – First Round Cleared"
|
| 52 |
+
message["From"] = self.sender
|
| 53 |
+
message["To"] = email
|
| 54 |
+
html = f"""
|
| 55 |
+
<html>
|
| 56 |
+
<body>
|
| 57 |
+
<p>
|
| 58 |
+
Dear {name},<br><br>
|
| 59 |
+
We are pleased to inform you that you have successfully cleared the first round of the interview process.<br><br>
|
| 60 |
+
|
| 61 |
+
You are hereby invited to attend the next round of interviews, scheduled as per the details below:<br><br>
|
| 62 |
+
|
| 63 |
+
<strong>Date:</strong> {self.date}<br>
|
| 64 |
+
<strong>Time:</strong> {slot}<br>
|
| 65 |
+
|
| 66 |
+
Please ensure that you are available and join the interview on time. Further instructions, if any, will be shared with you prior to the interview.<br><br>
|
| 67 |
+
|
| 68 |
+
We wish you the very best and look forward to speaking with you.<br><br>
|
| 69 |
+
|
| 70 |
+
Best regards,<br>
|
| 71 |
+
<strong>Hiring Team</strong>
|
| 72 |
+
</p>
|
| 73 |
+
|
| 74 |
+
</body>
|
| 75 |
+
</html>
|
| 76 |
+
"""
|
| 77 |
+
part = MIMEText(html, "html")
|
| 78 |
+
message.attach(part)
|
| 79 |
+
context = ssl.create_default_context()
|
| 80 |
+
with smtplib.SMTP(self.server, self.port) as server:
|
| 81 |
+
server.starttls(context=context)
|
| 82 |
+
server.login(self.sender, self.password)
|
| 83 |
+
server.sendmail(self.sender, email, message.as_string())
|
| 84 |
+
|
| 85 |
+
|
__init__.py
ADDED
|
File without changes
|
app.py
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from flask import Flask , request , jsonify
|
| 2 |
+
from flask_cors import CORS
|
| 3 |
+
import logging
|
| 4 |
+
from Models import Model
|
| 5 |
+
from Parser import Parser
|
| 6 |
+
from DB import DB
|
| 7 |
+
from Embedder import Embed
|
| 8 |
+
from Scheduler import Schedule
|
| 9 |
+
from Evaluator import InterviewEvaluator
|
| 10 |
+
from dotenv import load_dotenv
|
| 11 |
+
import json
|
| 12 |
+
import os
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
load_dotenv()
|
| 16 |
+
app = Flask(__name__)
|
| 17 |
+
CORS(app)
|
| 18 |
+
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
|
| 19 |
+
|
| 20 |
+
model_4b = os.getenv("4b")
|
| 21 |
+
model_27b = os.getenv("27b")
|
| 22 |
+
db = DB()
|
| 23 |
+
|
| 24 |
+
embedder = Embed()
|
| 25 |
+
embedder.create_db(db.string,db.collection)
|
| 26 |
+
logging.info("Embedder Loaded Successfully")
|
| 27 |
+
|
| 28 |
+
evaluator = InterviewEvaluator(model_4b)
|
| 29 |
+
logging.info("Evaluator Loaded Successfully")
|
| 30 |
+
|
| 31 |
+
PROMPT = os.getenv("Prompt")
|
| 32 |
+
JD_Prompt = os.getenv("JD_Prompt")
|
| 33 |
+
Summary = os.getenv("Summary_Prompt")
|
| 34 |
+
parser = Parser()
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
@app.route("/",methods = ["GET","POST"])
|
| 38 |
+
def default_route():
|
| 39 |
+
return jsonify({
|
| 40 |
+
"output" : "Backend Running Successfully"
|
| 41 |
+
})
|
| 42 |
+
|
| 43 |
+
@app.route("/parse",methods = ["POST"])
|
| 44 |
+
def parse():
|
| 45 |
+
db.connect_PS()
|
| 46 |
+
logging.info("Database Connected Successfully")
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
structure_model = Model(PROMPT,model_27b)
|
| 50 |
+
logging.info("Model Loaded Successfully")
|
| 51 |
+
|
| 52 |
+
logging.info("Parsing Resumes")
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
files = os.listdir("./resume")
|
| 56 |
+
contents = []
|
| 57 |
+
documents = []
|
| 58 |
+
for file_path in files:
|
| 59 |
+
if file_path.endswith(".pdf"):
|
| 60 |
+
path = r"./resume/" + file_path
|
| 61 |
+
print(path)
|
| 62 |
+
result = parser.parse(path)
|
| 63 |
+
content = result["content"][0]
|
| 64 |
+
contents.append(content)
|
| 65 |
+
|
| 66 |
+
if contents:
|
| 67 |
+
logging.info("Resumes Parsed Successfully")
|
| 68 |
+
for i in range(len(contents)):
|
| 69 |
+
structured = structure_model.send(contents[i])
|
| 70 |
+
doc = embedder.create_document(i, json.dumps(structured))
|
| 71 |
+
documents.append(doc)
|
| 72 |
+
|
| 73 |
+
embedder.add_docs(documents)
|
| 74 |
+
logging.info("Resumes Embeddings Added Successfully")
|
| 75 |
+
else:
|
| 76 |
+
logging.error('No Resumes Found/Parsed')
|
| 77 |
+
|
| 78 |
+
db.close_PS()
|
| 79 |
+
return jsonify({
|
| 80 |
+
"output" : "Resumes Parsed and Embedded Successfully"
|
| 81 |
+
})
|
| 82 |
+
|
| 83 |
+
@app.route("/match", methods = ["POST"])
|
| 84 |
+
def match():
|
| 85 |
+
db.connect_PS()
|
| 86 |
+
data = request.get_json()
|
| 87 |
+
JD = data.get("job_description")
|
| 88 |
+
k = data.get("candidates")
|
| 89 |
+
out = Model(JD_Prompt, model_4b).send(JD)
|
| 90 |
+
summarizer = Model(Summary,model_4b)
|
| 91 |
+
|
| 92 |
+
result = embedder.match(json.dumps(out),k)
|
| 93 |
+
output = []
|
| 94 |
+
for i in result:
|
| 95 |
+
content = {}
|
| 96 |
+
content["Name"] = i.metadata["name"]
|
| 97 |
+
content["Email"] = i.metadata["email"]
|
| 98 |
+
content["content"] = summarizer.send(json.dumps(i.page_content))
|
| 99 |
+
output.append(content)
|
| 100 |
+
db.close_PS()
|
| 101 |
+
return jsonify(output)
|
| 102 |
+
|
| 103 |
+
@app.route("/interview", methods = ["GET"])
|
| 104 |
+
def interview():
|
| 105 |
+
# 0 for non_tech and 1 for tech questions
|
| 106 |
+
data = request.get_json()
|
| 107 |
+
q_id = data.get("id")
|
| 108 |
+
questions = evaluator.ask(q_id)
|
| 109 |
+
return jsonify(questions)
|
| 110 |
+
|
| 111 |
+
@app.route("/interview",methods=["POST"])
|
| 112 |
+
def edit():
|
| 113 |
+
data = request.get_json()
|
| 114 |
+
# 0 for non_tech and 1 for tech questions
|
| 115 |
+
q_id = data.get("id")
|
| 116 |
+
questions = data.get("questions")
|
| 117 |
+
evaluator.edit(questions,q_id)
|
| 118 |
+
return jsonify({"output" : "Questions Edited Successfully"})
|
| 119 |
+
|
| 120 |
+
@app.route("/evaluate",methods = ["POST"])
|
| 121 |
+
def score():
|
| 122 |
+
db.connect_MS()
|
| 123 |
+
data = request.get_json()
|
| 124 |
+
candid = data.get("user_output")
|
| 125 |
+
email = data.get("email")
|
| 126 |
+
password = data.get("password")
|
| 127 |
+
result = evaluator.score_candid(candid)
|
| 128 |
+
score = result["score"]
|
| 129 |
+
query = f"Update score = {score} from users where Email = {email} and password = {password}"
|
| 130 |
+
db.cursor_MS.execute(query)
|
| 131 |
+
db.connection_MS.commit()
|
| 132 |
+
db.close_MS()
|
| 133 |
+
return jsonify(result)
|
| 134 |
+
|
| 135 |
+
|
| 136 |
+
def create_user():
|
| 137 |
+
db.connect_MS()
|
| 138 |
+
df = scheduler.df
|
| 139 |
+
for name,email,date,time in zip(df["Name"],df["Email"],scheduler.date,df["Slot"]):
|
| 140 |
+
password = name[:5] + email[:5]
|
| 141 |
+
db.insert([name,email,date,time,password,0.0])
|
| 142 |
+
|
| 143 |
+
db.connection_MS.commit()
|
| 144 |
+
db.close_MS()
|
| 145 |
+
|
| 146 |
+
|
| 147 |
+
@app.route("/schedule", methods = ["POST"])
|
| 148 |
+
def email():
|
| 149 |
+
data = request.get_json()
|
| 150 |
+
date = data.get("date")
|
| 151 |
+
time = data.get("time")
|
| 152 |
+
slot_length = data.get("length")
|
| 153 |
+
|
| 154 |
+
scheduler = Schedule()
|
| 155 |
+
scheduler.defaults(date,time,slot_length)
|
| 156 |
+
scheduler.schedule_slots("./test.csv")
|
| 157 |
+
create_user()
|
| 158 |
+
scheduler.send_emails()
|
| 159 |
+
return jsonify({"output" : "Emails Sent Successfully"})
|
| 160 |
+
|
| 161 |
+
@app.route("/login-user",methods=["GET"])
|
| 162 |
+
def login_u():
|
| 163 |
+
db.connect_MS()
|
| 164 |
+
data = request.get_json()
|
| 165 |
+
email = data.get("email")
|
| 166 |
+
password = data.get("pass")
|
| 167 |
+
query = f"SELECT * FROM users WHERE email = {email} AND password = {password}"
|
| 168 |
+
|
| 169 |
+
result = db.cursor_MS.execute(query).fetchone()
|
| 170 |
+
db.close_MS()
|
| 171 |
+
if result:
|
| 172 |
+
return jsonify({"user": "True"})
|
| 173 |
+
else:
|
| 174 |
+
return jsonify({"user": "False"})
|
| 175 |
+
|
| 176 |
+
@app.route("/login-org",methods=["GET"])
|
| 177 |
+
def login_o():
|
| 178 |
+
db.connect_MS()
|
| 179 |
+
data = request.get_json()
|
| 180 |
+
email = data.get("email")
|
| 181 |
+
password = data.get("pass")
|
| 182 |
+
query = f"SELECT * FROM org WHERE email = {email} AND password = {password}"
|
| 183 |
+
|
| 184 |
+
result = db.cursor_MS.execute(query).fetchone()
|
| 185 |
+
db.close_MS()
|
| 186 |
+
if result:
|
| 187 |
+
return jsonify({"user": "True"})
|
| 188 |
+
else:
|
| 189 |
+
return jsonify({"user": "False"})
|
| 190 |
+
|
| 191 |
+
|
| 192 |
+
if __name__ == "__main__":
|
| 193 |
+
app.run(debug=True)
|
requirements.txt
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
flask
|
| 2 |
+
flask-cors
|
| 3 |
+
python-dotenv
|
| 4 |
+
numpy
|
| 5 |
+
langchain
|
| 6 |
+
langchain-google-genai
|
| 7 |
+
langchain-community
|
| 8 |
+
langchain
|
| 9 |
+
pypdf
|
| 10 |
+
langchain-postgres
|
| 11 |
+
psycopg2
|
| 12 |
+
langchain-core
|
| 13 |
+
langchain-cohere
|
| 14 |
+
sqlalchemy
|
| 15 |
+
google
|
| 16 |
+
pandas
|
| 17 |
+
mysql-connector-python
|
| 18 |
+
gunicorn
|