Parimal Kalpande commited on
Commit
f09eba4
·
1 Parent(s): 2c970f4
DEPLOYMENT_GUIDE.md ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # DEPLOYMENT SOLUTIONS FOR HUGGING FACE SPACES
2
+
3
+ ## Issues Identified:
4
+ 1. ✅ Missing dependencies - FIXED
5
+ 2. ✅ Missing GROQ_API_KEY - NEEDS CONFIGURATION
6
+ 3. ✅ File paths - FIXED
7
+ 4. ❌ Gradio version bug - NEEDS VERSION DOWNGRADE
8
+
9
+ ## Solution 1: Update Requirements.txt with Compatible Gradio Version
10
+
11
+ Replace your requirements.txt with this:
12
+
13
+ ```
14
+ gradio==4.40.0
15
+ openai-whisper
16
+ pydub
17
+ soundfile
18
+ PyMuPDF
19
+ python-docx
20
+ reportlab
21
+ speechrecognition
22
+ duckduckgo-search
23
+ matplotlib
24
+ regex
25
+ groq
26
+ ```
27
+
28
+ ## Solution 2: Set Environment Variables in HF Spaces
29
+
30
+ In your Hugging Face Space settings, add:
31
+ - Variable name: GROQ_API_KEY
32
+ - Variable value: your_actual_groq_api_key
33
+
34
+ ## Solution 3: Use the Fixed App Version
35
+
36
+ Use app_fixed.py as your main app.py file - it has better error handling.
37
+
38
+ ## Solution 4: Alternative - Simplify the App
39
+
40
+ If the Gradio bug persists, use a simpler version without some advanced features.
41
+
42
+ ## Files Ready for Deployment:
43
+ - ✅ config.py (fixed paths)
44
+ - ✅ requirements.txt (compatible versions)
45
+ - ✅ app_fixed.py (better error handling)
46
+ - ✅ All modules updated with graceful fallbacks
47
+ - ✅ Dockerfile updated
48
+ - ✅ Environment validation script
49
+
50
+ ## Deployment Steps:
51
+ 1. Update requirements.txt with Gradio 4.40.0
52
+ 2. Set GROQ_API_KEY in HF Spaces environment variables
53
+ 3. Upload all files to your HF Space
54
+ 4. The app should work with limited audio features but full interview functionality
app_fixed.py ADDED
@@ -0,0 +1,206 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app_fixed.py
2
+ import gradio as gr
3
+ import os
4
+ import time
5
+ import datetime
6
+ import config
7
+
8
+ # Import modules with error handling
9
+ try:
10
+ from modules.tts_handler import text_to_speech_file
11
+ from modules.stt_handler import transcribe_audio
12
+ from modules.doc_processor import extract_text_from_document
13
+ from modules.llm_handler import generate_question, evaluate_answer
14
+ from modules.report_generator import generate_pdf_report
15
+ TTS_AVAILABLE = True
16
+ except ImportError as e:
17
+ print(f"Warning: Some modules could not be imported: {e}")
18
+ TTS_AVAILABLE = False
19
+
20
+ def start_interview(interview_type, doc_file, name, num_questions):
21
+ if not interview_type or not doc_file:
22
+ return (
23
+ {}, # state
24
+ [["System", "Please select an interview type and upload a document to begin."]], # chatbot
25
+ None, # audio_out
26
+ gr.update(interactive=False), # audio_in
27
+ gr.update(interactive=True) # start_btn
28
+ )
29
+
30
+ try:
31
+ doc_text = extract_text_from_document(doc_file.name)
32
+ if "Error" in doc_text or "Unsupported" in doc_text:
33
+ return (
34
+ {},
35
+ [["System", f"Error: {doc_text}"]],
36
+ None,
37
+ gr.update(interactive=False),
38
+ gr.update(interactive=True)
39
+ )
40
+
41
+ initial_state = {
42
+ "interview_type": interview_type,
43
+ "doc_text": doc_text,
44
+ "name": name if name else "User",
45
+ "question_count": int(num_questions),
46
+ "current_question_num": 1,
47
+ "interview_log": [],
48
+ "start_time": time.time()
49
+ }
50
+
51
+ first_question = generate_question(interview_type, doc_text)
52
+ initial_state["current_question_text"] = first_question
53
+ greeting = f"Hello {initial_state['name']}. We'll go through {int(num_questions)} questions today. Here is your first question:"
54
+
55
+ # Try to generate TTS audio, but don't fail if it's not available
56
+ ai_voice_path = None
57
+ if TTS_AVAILABLE:
58
+ try:
59
+ tts_prompt = f"{greeting} {first_question}"
60
+ ai_voice_path = text_to_speech_file(tts_prompt)
61
+ except Exception as e:
62
+ print(f"TTS generation failed: {e}")
63
+
64
+ return (
65
+ initial_state,
66
+ [["System", f"{greeting}\n\n{first_question}"]],
67
+ ai_voice_path,
68
+ gr.update(interactive=True),
69
+ gr.update(interactive=False)
70
+ )
71
+
72
+ except Exception as e:
73
+ return (
74
+ {},
75
+ [["System", f"An error occurred: {str(e)}"]],
76
+ None,
77
+ gr.update(interactive=False),
78
+ gr.update(interactive=True)
79
+ )
80
+
81
+ def handle_interview_turn(user_audio, chatbot_history, current_state):
82
+ if not current_state or not user_audio:
83
+ return current_state, chatbot_history, None, gr.update(interactive=True), gr.update(visible=False)
84
+
85
+ try:
86
+ user_answer_text = transcribe_audio(user_audio)
87
+ new_history = chatbot_history + [[user_answer_text, None]]
88
+
89
+ evaluation_text = evaluate_answer(current_state["current_question_text"], user_answer_text)
90
+ current_state["interview_log"].append({
91
+ "question": current_state["current_question_text"],
92
+ "answer": user_answer_text,
93
+ "evaluation": evaluation_text
94
+ })
95
+
96
+ if current_state["current_question_num"] >= current_state["question_count"]:
97
+ end_message = "This concludes the interview. Generating your final report now."
98
+ final_history = new_history + [["System", end_message]]
99
+
100
+ # Generate PDF
101
+ pdf_path = generate_pdf_file(current_state)
102
+
103
+ # Try TTS
104
+ ai_voice_path = None
105
+ if TTS_AVAILABLE:
106
+ try:
107
+ ai_voice_path = text_to_speech_file(end_message)
108
+ except Exception as e:
109
+ print(f"TTS generation failed: {e}")
110
+
111
+ return (
112
+ current_state,
113
+ final_history,
114
+ ai_voice_path,
115
+ gr.update(interactive=False),
116
+ gr.update(value=pdf_path, visible=True)
117
+ )
118
+ else:
119
+ current_state["current_question_num"] += 1
120
+ next_question = generate_question(current_state["interview_type"], current_state["doc_text"])
121
+ current_state["current_question_text"] = next_question
122
+ q_num = current_state["current_question_num"]
123
+ transition_message = f"Thank you. Here is question {q_num}:\n\n{next_question}"
124
+ final_history = new_history + [["System", transition_message]]
125
+
126
+ # Try TTS
127
+ ai_voice_path = None
128
+ if TTS_AVAILABLE:
129
+ try:
130
+ ai_voice_path = text_to_speech_file(transition_message)
131
+ except Exception as e:
132
+ print(f"TTS generation failed: {e}")
133
+
134
+ return (
135
+ current_state,
136
+ final_history,
137
+ ai_voice_path,
138
+ gr.update(interactive=True),
139
+ gr.update(visible=False)
140
+ )
141
+
142
+ except Exception as e:
143
+ error_history = chatbot_history + [["System", f"An error occurred: {str(e)}"]]
144
+ return current_state, error_history, None, gr.update(interactive=True), gr.update(visible=False)
145
+
146
+ def generate_pdf_file(state):
147
+ try:
148
+ total_duration_minutes = (time.time() - state.get("start_time", time.time())) / 60
149
+ final_data = {
150
+ "name": state.get("name", "N/A"),
151
+ "type": state.get("interview_type", "N/A"),
152
+ "duration": total_duration_minutes,
153
+ "q_and_a": state.get("interview_log", [])
154
+ }
155
+ file_name = f"Report_{state.get('name', 'User')}_{datetime.datetime.now().strftime('%Y-%m-%d')}.pdf"
156
+ file_path = os.path.join(config.REPORT_FOLDER, file_name)
157
+ generate_pdf_report(final_data, file_path)
158
+ return file_path
159
+ except Exception as e:
160
+ print(f"PDF generation failed: {e}")
161
+ return None
162
+
163
+ with gr.Blocks(theme=gr.themes.Default()) as app:
164
+ state = gr.State(value={})
165
+
166
+ gr.Markdown("# PM Interview Coach")
167
+
168
+ with gr.Row():
169
+ with gr.Column(scale=1):
170
+ gr.Markdown("### Setup")
171
+ user_name = gr.Textbox(label="Your Name", placeholder="Enter your name")
172
+ interview_type_dd = gr.Dropdown(choices=config.INTERVIEW_TYPES, label="Interview Type")
173
+ num_questions_slider = gr.Slider(minimum=1, maximum=10, value=5, step=1, label="Number of Questions")
174
+ doc_uploader = gr.File(label="Upload Resume/CV (.pdf, .docx)", file_types=['.pdf', '.docx'])
175
+ start_btn = gr.Button("Start Interview", variant="primary")
176
+
177
+ with gr.Column(scale=2):
178
+ chatbot = gr.Chatbot(label="Conversation", height=500)
179
+ audio_in = gr.Audio(sources=["microphone"], type="filepath", label="Record Your Answer", interactive=False)
180
+ audio_out = gr.Audio(visible=False, autoplay=True)
181
+ download_pdf_btn = gr.File(label="Download Report", visible=False)
182
+
183
+ # Event handlers
184
+ start_btn.click(
185
+ fn=start_interview,
186
+ inputs=[interview_type_dd, doc_uploader, user_name, num_questions_slider],
187
+ outputs=[state, chatbot, audio_out, audio_in, start_btn]
188
+ )
189
+
190
+ audio_in.stop_recording(
191
+ fn=handle_interview_turn,
192
+ inputs=[audio_in, chatbot, state],
193
+ outputs=[state, chatbot, audio_out, audio_in, download_pdf_btn]
194
+ )
195
+
196
+ if __name__ == "__main__":
197
+ # Create necessary directories
198
+ os.makedirs(config.UPLOAD_FOLDER, exist_ok=True)
199
+ os.makedirs(config.REPORT_FOLDER, exist_ok=True)
200
+
201
+ # Launch the app
202
+ app.launch(
203
+ server_name="0.0.0.0",
204
+ server_port=7860,
205
+ share=False
206
+ )
modules/llm_handler.py CHANGED
@@ -8,12 +8,19 @@ from modules.web_search import search_for_example_answers
8
  # Initialize the Groq client
9
  groq_api_key = os.environ.get("GROQ_API_KEY")
10
  if not groq_api_key:
11
- raise ValueError("GROQ_API_KEY environment variable is required but not set")
12
-
13
- client = Groq(api_key=groq_api_key)
14
- MODEL = "llama3-70b-8192" # Use the more powerful 70B model for detailed analysis
 
 
 
 
15
 
16
  def generate_question(interview_type, document_text):
 
 
 
17
  prompt = f"As an expert {interview_type} interviewer, ask one relevant, open-ended question based on this document:\n\n---\n{document_text}\n---"
18
  try:
19
  chat_completion = client.chat.completions.create(
@@ -24,6 +31,9 @@ def generate_question(interview_type, document_text):
24
  return f"Error generating question from API: {e}"
25
 
26
  def evaluate_answer(question, answer):
 
 
 
27
  # This new prompt demands a much higher level of detail
28
  prompt = f"""
29
  You are a meticulous and insightful interview coach. Your task is to provide a highly detailed evaluation of a candidate's answer.
@@ -80,6 +90,9 @@ def parse_scores_from_evaluation(evaluation_text: str) -> dict:
80
  return scores
81
 
82
  def generate_holistic_feedback(full_interview_log):
 
 
 
83
  # This prompt is also enhanced for more detail
84
  prompt = f"""
85
  You are a senior career strategist reviewing a candidate's full interview performance.
 
8
  # Initialize the Groq client
9
  groq_api_key = os.environ.get("GROQ_API_KEY")
10
  if not groq_api_key:
11
+ print("⚠️ WARNING: GROQ_API_KEY environment variable is not set")
12
+ print(" The application will not work properly without this API key")
13
+ print(" Please set your GROQ API key before running the application")
14
+ client = None
15
+ MODEL = None
16
+ else:
17
+ client = Groq(api_key=groq_api_key)
18
+ MODEL = "llama3-70b-8192" # Use the more powerful 70B model for detailed analysis
19
 
20
  def generate_question(interview_type, document_text):
21
+ if not client:
22
+ return "Error: GROQ_API_KEY not configured. Please set your API key to use this feature."
23
+
24
  prompt = f"As an expert {interview_type} interviewer, ask one relevant, open-ended question based on this document:\n\n---\n{document_text}\n---"
25
  try:
26
  chat_completion = client.chat.completions.create(
 
31
  return f"Error generating question from API: {e}"
32
 
33
  def evaluate_answer(question, answer):
34
+ if not client:
35
+ return "Error: GROQ_API_KEY not configured. Please set your API key to use this feature."
36
+
37
  # This new prompt demands a much higher level of detail
38
  prompt = f"""
39
  You are a meticulous and insightful interview coach. Your task is to provide a highly detailed evaluation of a candidate's answer.
 
90
  return scores
91
 
92
  def generate_holistic_feedback(full_interview_log):
93
+ if not client:
94
+ return "Error: GROQ_API_KEY not configured. Please set your API key to use this feature."
95
+
96
  # This prompt is also enhanced for more detail
97
  prompt = f"""
98
  You are a senior career strategist reviewing a candidate's full interview performance.
modules/web_search.py CHANGED
@@ -1,6 +1,6 @@
1
  # modules/web_search.py
2
 
3
- from ddgs import DDGS
4
 
5
  def search_for_example_answers(query: str, num_results: int = 2):
6
  """
 
1
  # modules/web_search.py
2
 
3
+ from duckduckgo_search import DDGS
4
 
5
  def search_for_example_answers(query: str, num_results: int = 2):
6
  """
requirements.txt CHANGED
@@ -1,4 +1,4 @@
1
- gradio==4.44.0
2
  openai-whisper
3
  pydub
4
  soundfile
@@ -13,4 +13,5 @@ groq
13
  # Removed problematic dependencies for HF Spaces:
14
  # - ollama (local service, not available in HF Spaces)
15
  # - pyaudio (often causes build issues)
16
- # - piper-tts (system dependencies issues)
 
 
1
+ gradio==4.40.0
2
  openai-whisper
3
  pydub
4
  soundfile
 
13
  # Removed problematic dependencies for HF Spaces:
14
  # - ollama (local service, not available in HF Spaces)
15
  # - pyaudio (often causes build issues)
16
+ # - piper-tts (system dependencies issues)
17
+ # Using Gradio 4.40.0 to avoid version 4.44.0 API schema bug
test_simple.py ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # test_simple.py
2
+ import gradio as gr
3
+ import os
4
+
5
+ def simple_greeting(name):
6
+ return f"Hello {name}! The app is working properly."
7
+
8
+ def test_groq_connection():
9
+ groq_key = os.environ.get("GROQ_API_KEY")
10
+ if groq_key:
11
+ return "✅ GROQ API key is configured"
12
+ else:
13
+ return "❌ GROQ API key is missing"
14
+
15
+ # Create a simple interface to test basic functionality
16
+ with gr.Blocks() as demo:
17
+ gr.Markdown("# AI Interview Coach - Connection Test")
18
+
19
+ with gr.Row():
20
+ name_input = gr.Textbox(label="Your Name", placeholder="Enter your name")
21
+ greeting_output = gr.Textbox(label="Greeting", interactive=False)
22
+
23
+ with gr.Row():
24
+ test_btn = gr.Button("Test GROQ Connection")
25
+ status_output = gr.Textbox(label="API Status", interactive=False)
26
+
27
+ name_input.change(simple_greeting, inputs=[name_input], outputs=[greeting_output])
28
+ test_btn.click(test_groq_connection, outputs=[status_output])
29
+
30
+ if __name__ == "__main__":
31
+ demo.launch(server_name="0.0.0.0", server_port=7860)