CoolFace
Apppublic

lucyber/interview_evaluate

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
interview_assessment.py238 linesDownload Raw Back to root
1import streamlit as st
2import re
3import tempfile
4import os
5from transformers import pipeline
6
7# ========================= CONFIG =========================
8st.set_page_config(page_title="AI Interview Assessment", layout="wide")
9
10HF_PHI3_MODEL = "mistralai/Mistral-7B-Instruct-v0.2"
11HF_WHISPER_MODEL = "openai/whisper-large-v3"
12
13INTERVIEW_QUESTIONS = [
14    "Can you share any specific challenges you faced while working on certification and how you overcame them?",
15    "Can you describe your experience with transfer learning in TensorFlow? How did it benefit your projects?",
16    "Describe a complex TensorFlow model you have built and the steps you took to ensure its accuracy and efficiency.",
17    "Explain how to implement dropout in a TensorFlow model and the effect it has on training.",
18    "Describe the process of building a convolutional neural network (CNN) using TensorFlow for image classification."
19]
20
21CRITERIA = (
22    "Kriteria Penilaian:\n"
23    "0 - not answer the question\n"
24    "1 - the answer is not relevan for question\n"
25    "2 - Understand for general question\n"
26    "3 - Understand with practice solution\n"
27    "4 - Deep understanding with inovative solution\n"
28)
29
30# ========================= PIPELINE CACHE =========================
31@st.cache_resource
32def get_asr_pipeline():
33    return pipeline(
34        task="automatic-speech-recognition",
35        model=HF_WHISPER_MODEL
36    )
37
38@st.cache_resource
39def get_llm_pipeline():
40    return pipeline(
41        task="text-generation",
42        model=HF_PHI3_MODEL
43    )
44
45# ========================= FUNCTIONS =========================
46def transcribe_via_hf(video_bytes):
47    """
48    Transkripsi video/audio menggunakan Whisper lokal di HF Space.
49    """
50    asr = get_asr_pipeline()
51
52    # Simpan input video sementara
53    with tempfile.NamedTemporaryFile(delete=False, suffix=".mp4") as tmp_in:
54        tmp_in.write(video_bytes)
55        tmp_in.flush()
56        tmp_in_path = tmp_in.name
57
58    # Simpan output audio sementara
59    with tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as tmp_out:
60        tmp_out_path = tmp_out.name
61
62    # Convert to WAV mono 16k
63    try:
64        subprocess.run(
65            [
66                "ffmpeg", "-y", "-i", tmp_in_path,
67                "-ac", "1", "-ar", "16000",
68                tmp_out_path
69            ],
70            stdout=subprocess.PIPE,
71            stderr=subprocess.PIPE,
72            check=True
73        )
74    except Exception as e:
75        return f"ERROR FFMPEG CONVERT: {e}"
76
77    # Transcribe WAV
78    try:
79        result = asr(tmp_out_path)
80        if isinstance(result, dict):
81            return result.get("text", "")
82        elif isinstance(result, list) and isinstance(result[0], dict):
83            return result[0].get("text", "")
84        return str(result)
85    except Exception as e:
86        return f"ERROR TRANSCRIBE: {e}"
87    finally:
88        try: os.remove(tmp_in_path)
89        except: pass
90        try: os.remove(tmp_out_path)
91        except: pass
92
93
94def phi3_api(prompt):
95    """
96    Generate text menggunakan Phi-3 lokal (pipeline HF).
97    """
98    llm = get_llm_pipeline()
99
100    try:
101        out = llm(prompt, max_new_tokens=200, do_sample=False)
102        if isinstance(out, list) and len(out) > 0:
103            return out[0]["generated_text"]
104        return str(out)
105    except Exception as e:
106        return f"ERROR: {e}"
107
108
109def prompt_for_classification(question, answer):
110    return (
111        "You are an expert HR interviewer and technical evaluator. Your task is to objectively assess the "
112        "candidate's response based solely on the provided transcript. You must classify the answer using a strict "
113        "0 until 4 scoring rubric.\n\n"
114
115        f"{CRITERIA}\n\n"
116
117        "Evaluation Rules:\n"
118        "- Evaluate ONLY based on the candidate's answer.\n"
119        "- Do NOT add missing information, assumptions, or corrections.\n"
120        "- Judge relevance, accuracy, clarity, and depth based on the rubric.\n"
121        "- Your explanation must be concise and directly tied to the rubric.\n"
122        "- You MUST follow the output format exactly.\n\n"
123
124        f"Question:\n{question}\n\n"
125        f"Candidate Answer (Transcript):\n{answer}\n\n"
126
127        "Required Output Format:\n"
128        "KLASIFIKASI: <angka>\n"
129        "ALASAN: <teks>\n"
130    )
131
132def parse_model_output(text):
133    score_match = re.search(r"KLASIFIKASI[:\- ]*([0-4])", text, re.IGNORECASE)
134    if not score_match:
135        score_match = re.search(r"\b([0-4])\b", text)
136
137    score = int(score_match.group(1)) if score_match else None
138
139    reason_match = re.search(r"ALASAN[:\-]\s*(.+)", text, re.IGNORECASE | re.DOTALL)
140    reason = reason_match.group(1).strip() if reason_match else text
141
142    return score, reason
143
144
145# ========================= SESSION INIT =========================
146for key, default in {
147    "page": "input",
148    "results": [],
149    "nama": "",
150    "processing_done": False
151}.items():
152    st.session_state.setdefault(key, default)
153
154
155# ========================= PAGE INPUT =========================
156if st.session_state.page == "input":
157    st.title("๐ŸŽฅ AI-Powered Interview Assessment System")
158    st.write("Upload **5 video interview** lalu klik mulai analisis.")
159
160    with st.form("upload_form"):
161        nama = st.text_input("Nama Pelamar")
162        uploaded = st.file_uploader(
163            "Upload 5 Video (1 โ†’ 5)",
164            type=["mp4", "mov", "mkv", "webm"],
165            accept_multiple_files=True
166        )
167        submit = st.form_submit_button("Mulai Proses Analisis")
168
169    if submit:
170        if not nama:
171            st.error("Nama wajib diisi.")
172        elif not uploaded or len(uploaded) != 5:
173            st.error("Harap upload tepat 5 video.")
174        else:
175            st.session_state.nama = nama
176            st.session_state.uploaded = uploaded
177            st.session_state.results = []
178            st.session_state.page = "result"
179            st.session_state.processing_done = True
180            st.rerun()
181
182
183# ========================= PAGE RESULT =========================
184if st.session_state.processing_done and st.session_state.page == "result":
185    st.title("๐Ÿ“‹ Hasil Penilaian Interview")
186    st.write(f"**Nama Pelamar:** {st.session_state.nama}")
187
188    progress = st.empty()
189
190    if len(st.session_state.results) == 0:
191        for idx, vid in enumerate(st.session_state.uploaded):
192            progress.info(f"Memproses Video {idx+1}...")
193
194            bytes_data = vid.read()
195            transcript = transcribe_via_hf(bytes_data)
196            prompt = prompt_for_classification(INTERVIEW_QUESTIONS[idx], transcript)
197            raw_output = phi3_api(prompt)
198            score, reason = parse_model_output(raw_output)
199
200            st.session_state.results.append({
201                "question": INTERVIEW_QUESTIONS[idx],
202                "transcript": transcript,
203                "score": score,
204                "reason": reason,
205                "raw_model": raw_output
206            })
207
208            progress.success(f"Video {idx+1} selesai โœ”")
209
210    scores = [r["score"] for r in st.session_state.results if r["score"] is not None]
211
212    if len(scores) == 5:
213        final_score = sum(scores) / 5
214        st.markdown(f"### โญ Skor Akhir: **{final_score:.2f} / 4**")
215    else:
216        st.error("Skor tidak semua berhasil diproses. Cek raw output model.")
217
218    st.markdown("---")
219
220    for i, r in enumerate(st.session_state.results):
221        st.subheader(f"๐ŸŽฌ Video {i+1}")
222        st.write(f"**Pertanyaan:** {r['question']}")
223        st.write(f"**Transkrip:** {r['transcript']}")
224        st.write(f"**Skor:** {r['score']}")
225        st.write(f"**Alasan:** {r['reason']}")
226
227        with st.expander("Raw Output Model"):
228            st.code(r["raw_model"])
229
230        st.markdown("---")
231
232    if st.button("๐Ÿ”™ Kembali"):
233        st.session_state.page = "input"
234        st.session_state.processing_done = False
235        st.session_state.results = []
236        st.session_state.nama = ""
237        st.rerun()
238