Mr-Thop commited on
Commit
cdfb101
·
1 Parent(s): 0d1a380

Add files

Browse files
Files changed (13) hide show
  1. .gitignore +45 -0
  2. DB.py +49 -0
  3. DockerFile +16 -0
  4. Embedder.py +31 -0
  5. Evaluator.py +40 -0
  6. LICENSE +21 -0
  7. Models.py +38 -0
  8. Parser.py +18 -0
  9. README copy.md +2 -0
  10. Scheduler.py +85 -0
  11. __init__.py +0 -0
  12. app.py +193 -0
  13. 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