XinYu27
commited on
Feat: Integrate Gradio frontend
Browse filesAdded initial frontend development
- src/app.py +149 -19
src/app.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1 |
import gradio as gr
|
2 |
from typing import Dict
|
|
|
3 |
|
4 |
# from src.application.services import InterviewAnalyzer
|
5 |
# from src.infrastructure.llm import LangchainService
|
@@ -46,27 +47,156 @@ from typing import Dict
|
|
46 |
|
47 |
# Testing to setup the simple interface
|
48 |
class GradioInterface:
|
49 |
-
def
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
# Create Gradio interface
|
57 |
-
interface = gr.Interface(
|
58 |
-
fn=process_submission,
|
59 |
-
inputs=[
|
60 |
-
gr.Video(label="Interview Recording"),
|
61 |
-
gr.File(label="Resume"),
|
62 |
-
gr.Textbox(label="Job Requirements", lines=5),
|
63 |
-
],
|
64 |
-
outputs=gr.JSON(label="Analysis Results"),
|
65 |
-
title="HR Interview Analysis System",
|
66 |
-
description="Upload interview recording and resume to analyze candidate performance",
|
67 |
)
|
68 |
|
69 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
70 |
|
71 |
|
72 |
def launch_app():
|
|
|
1 |
import gradio as gr
|
2 |
from typing import Dict
|
3 |
+
import pandas as pd
|
4 |
|
5 |
# from src.application.services import InterviewAnalyzer
|
6 |
# from src.infrastructure.llm import LangchainService
|
|
|
47 |
|
48 |
# Testing to setup the simple interface
|
49 |
class GradioInterface:
|
50 |
+
def __init__(self):
|
51 |
+
# DataFrame to List All Users' Feedbacks
|
52 |
+
self.candidate_feedback = pd.DataFrame(columns=["Name", "Score", "Feedback"])
|
53 |
+
|
54 |
+
def validate_file_format(self, file_path: str, valid_extensions: list) -> bool:
|
55 |
+
return isinstance(file_path, str) and any(
|
56 |
+
file_path.endswith(ext) for ext in valid_extensions
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
57 |
)
|
58 |
|
59 |
+
def process_video(self, video_path: str) -> str:
|
60 |
+
# Process transcript from the video
|
61 |
+
return "### Transcript\nExample of transcript of the interview video."
|
62 |
+
|
63 |
+
def process_resume(self, resume_path: str) -> str:
|
64 |
+
# Resume Parsing
|
65 |
+
return "### Resume Analysis\n- **Skills**: NLP, Machine Learning, Computer Vision\n- **Experience**: 5 years."
|
66 |
+
|
67 |
+
def analyze_emotions(self, video_path: str) -> str:
|
68 |
+
# Emotion Analysis
|
69 |
+
return "### Emotion Analysis\n- **Overall Emotion**: Positive\n- **Details**: Candidate displayed confidence and engagement."
|
70 |
+
|
71 |
+
def get_feedback(self, name: str, score: int, feedback: str) -> pd.DataFrame:
|
72 |
+
return pd.DataFrame({"Name": [name], "Score": [score], "Feedback": [feedback]})
|
73 |
+
|
74 |
+
def save_report(self):
|
75 |
+
# Save report
|
76 |
+
report_path = "report_path.docx"
|
77 |
+
with open(report_path, "w") as f:
|
78 |
+
# Pass fields to include in report here
|
79 |
+
f.write("Example report")
|
80 |
+
return report_path
|
81 |
+
|
82 |
+
def create_interface(self) -> gr.Blocks:
|
83 |
+
def process_submission(
|
84 |
+
video_path, resume_path, interview_questions, job_requirements
|
85 |
+
):
|
86 |
+
# Validate inputs and formats
|
87 |
+
if not video_path:
|
88 |
+
return (
|
89 |
+
"Please upload an interview video.",
|
90 |
+
None,
|
91 |
+
None,
|
92 |
+
self.candidate_feedback,
|
93 |
+
)
|
94 |
+
if not resume_path:
|
95 |
+
return (
|
96 |
+
"Please upload a resume (PDF).",
|
97 |
+
None,
|
98 |
+
None,
|
99 |
+
self.candidate_feedback,
|
100 |
+
)
|
101 |
+
if not interview_questions:
|
102 |
+
return (
|
103 |
+
"Please provide interview questions.",
|
104 |
+
None,
|
105 |
+
None,
|
106 |
+
self.candidate_feedback,
|
107 |
+
)
|
108 |
+
if not job_requirements:
|
109 |
+
return (
|
110 |
+
"Please provide job requirements.",
|
111 |
+
None,
|
112 |
+
None,
|
113 |
+
self.candidate_feedback,
|
114 |
+
)
|
115 |
+
if not self.validate_file_format(video_path, [".mp4", ".avi", ".mkv"]):
|
116 |
+
return "Invalid video format.", None, None, self.candidate_feedback
|
117 |
+
if not self.validate_file_format(resume_path, [".pdf"]):
|
118 |
+
return (
|
119 |
+
"Please submit resume in PDF format.",
|
120 |
+
None,
|
121 |
+
None,
|
122 |
+
self.candidate_feedback,
|
123 |
+
)
|
124 |
+
|
125 |
+
# Mock outputs for this submission
|
126 |
+
video_transcript = self.process_video(video_path)
|
127 |
+
emotion_analysis = self.analyze_emotions(video_path)
|
128 |
+
resume_analysis = self.process_resume(resume_path)
|
129 |
+
# Example of Feedback
|
130 |
+
feedback_list = self.get_feedback(
|
131 |
+
name="Johnson",
|
132 |
+
score=88,
|
133 |
+
feedback="Outstanding technical and soft skills.",
|
134 |
+
)
|
135 |
+
# Append the new candidate feedback to the DataFrame
|
136 |
+
self.candidate_feedback = pd.concat(
|
137 |
+
[self.candidate_feedback, feedback_list], ignore_index=True
|
138 |
+
)
|
139 |
+
|
140 |
+
# Return both the individual result and the list result
|
141 |
+
return (
|
142 |
+
video_transcript,
|
143 |
+
emotion_analysis,
|
144 |
+
resume_analysis,
|
145 |
+
self.candidate_feedback,
|
146 |
+
)
|
147 |
+
|
148 |
+
# Build the interface using Blocks
|
149 |
+
with gr.Blocks() as demo:
|
150 |
+
gr.Markdown("## HR Interview Analysis System")
|
151 |
+
|
152 |
+
# Inputs section
|
153 |
+
with gr.Row():
|
154 |
+
video_input = gr.Video(label="Upload Interview Video")
|
155 |
+
resume_input = gr.File(label="Upload Resume (PDF)")
|
156 |
+
with gr.Row():
|
157 |
+
question_input = gr.Textbox(
|
158 |
+
label="Interview Questions",
|
159 |
+
lines=5,
|
160 |
+
placeholder="Enter the interview question here",
|
161 |
+
)
|
162 |
+
requirements_input = gr.Textbox(
|
163 |
+
label="Job Requirements",
|
164 |
+
lines=5,
|
165 |
+
placeholder="Enter the job requirements here",
|
166 |
+
)
|
167 |
+
|
168 |
+
submit_button = gr.Button("Submit")
|
169 |
+
|
170 |
+
with gr.Tabs():
|
171 |
+
with gr.Tab("Result"):
|
172 |
+
transcript_output = gr.Markdown(label="Video Transcript")
|
173 |
+
emotion_output = gr.Markdown(label="Emotion Analysis")
|
174 |
+
resume_output = gr.Markdown(label="Resume Analysis")
|
175 |
+
|
176 |
+
with gr.Tab("List of Candidates"):
|
177 |
+
feedback_output = gr.Dataframe(
|
178 |
+
label="Candidate Feedback Lists", interactive=False
|
179 |
+
)
|
180 |
+
|
181 |
+
save_button = gr.Button("Save Report")
|
182 |
+
save_button.click(
|
183 |
+
fn=self.save_report,
|
184 |
+
inputs=[],
|
185 |
+
outputs=gr.File(label="Download Report"),
|
186 |
+
)
|
187 |
+
# Connect the button to the function
|
188 |
+
submit_button.click(
|
189 |
+
fn=process_submission,
|
190 |
+
inputs=[video_input, resume_input, question_input, requirements_input],
|
191 |
+
outputs=[
|
192 |
+
transcript_output,
|
193 |
+
emotion_output,
|
194 |
+
resume_output,
|
195 |
+
feedback_output,
|
196 |
+
],
|
197 |
+
)
|
198 |
+
|
199 |
+
return demo
|
200 |
|
201 |
|
202 |
def launch_app():
|