Spaces:
Sleeping
Sleeping
| # requirements.txt | |
| # gradio | |
| # openai>=1.0.0 | |
| # sentence-transformers | |
| import gradio as gr | |
| from openai import OpenAI, AuthenticationError | |
| from sentence_transformers import SentenceTransformer, util | |
| import os | |
| import time | |
| # --- Load Resume and Build Embedding Index --- | |
| embedder = SentenceTransformer('all-MiniLM-L6-v2') | |
| RESUME_PATH = "resume.txt" | |
| def load_resume_chunks(path=RESUME_PATH): | |
| with open(path, "r") as f: | |
| content = f.read() | |
| chunks = [chunk.strip() for chunk in content.split("\n\n") if chunk.strip()] | |
| embeddings = embedder.encode(chunks, convert_to_tensor=True) | |
| return chunks, embeddings | |
| resume_chunks, resume_embeddings = load_resume_chunks() | |
| def get_relevant_resume_chunks(query, top_k=3): | |
| query_embedding = embedder.encode(query, convert_to_tensor=True) | |
| scores = util.cos_sim(query_embedding, resume_embeddings)[0] | |
| top_results = scores.argsort(descending=True)[:top_k] | |
| return [resume_chunks[i] for i in top_results] | |
| def extract_projects_section(path=RESUME_PATH): | |
| with open(path, "r") as f: | |
| content = f.read() | |
| start = content.find("Project:") | |
| end = content.find("Publication", start) | |
| if start != -1 and end != -1: | |
| return content[start:end].strip() | |
| return "" | |
| # --- Audio Bot Logic --- | |
| def audio_bot(api_key, audio_filepath, chat_history): | |
| if not api_key: | |
| chat_history.append((None, "Error: OpenAI API key is missing.")) | |
| return chat_history, chat_history, None, None | |
| try: | |
| client = OpenAI(api_key=api_key) | |
| except Exception as e: | |
| chat_history.append((None, f"Error initializing OpenAI client: {e}")) | |
| return chat_history, chat_history, None, None | |
| if audio_filepath is None: | |
| chat_history.append((None, "Error: No audio recorded.")) | |
| return chat_history, chat_history, None, None | |
| messages = [] | |
| for user_msg, ai_msg in chat_history: | |
| if user_msg: | |
| messages.append({"role": "user", "content": user_msg}) | |
| if ai_msg: | |
| messages.append({"role": "assistant", "content": ai_msg}) | |
| try: | |
| with open(audio_filepath, "rb") as audio_file: | |
| transcription = client.audio.transcriptions.create( | |
| model="whisper-1", | |
| file=audio_file | |
| ) | |
| user_text = transcription.text | |
| print(f"User said: {user_text}") | |
| # Check if the user is asking about projects | |
| if "project" in user_text.lower(): | |
| projects_info = extract_projects_section() | |
| system_prompt = f""" | |
| You are Thejas Haridas — a Data Scientist, ML/AI Engineer, and Data Analyst. | |
| Answer all questions in first person, as if you are Thejas Haridas himself. | |
| Only use the following projects to answer questions about your work: | |
| Always respond only in English. | |
| {projects_info} | |
| """ | |
| else: | |
| # Get relevant resume info and similarity scores | |
| query_embedding = embedder.encode(user_text, convert_to_tensor=True) | |
| scores = util.cos_sim(query_embedding, resume_embeddings)[0] | |
| top_results = scores.argsort(descending=True)[:5] # Increase top_k to 5 | |
| relevant_info = "\n\n".join([resume_chunks[i] for i in top_results]) | |
| max_score = float(scores[top_results[0]]) | |
| system_prompt = f""" | |
| You are Thejas Haridas — a Data Scientist, ML/AI Engineer, and Data Analyst. | |
| Answer all questions in first person, as if you are Thejas Haridas himself. | |
| Use the following relevant background info to answer questions: | |
| Always respond only in English. | |
| {relevant_info} | |
| """ | |
| messages.insert(0, {"role": "system", "content": system_prompt}) | |
| messages.append({"role": "user", "content": user_text}) | |
| response = client.chat.completions.create( | |
| model="gpt-4o-mini", | |
| messages=messages | |
| ) | |
| ai_text = response.choices[0].message.content | |
| print(f"AI responded: {ai_text}") | |
| chat_history.append((user_text, ai_text)) | |
| # Convert response to speech | |
| output_audio_filepath = f"ai_response_{int(time.time())}.mp3" | |
| speech_response = client.audio.speech.create( | |
| model="tts-1", | |
| voice="nova", | |
| input=ai_text | |
| ) | |
| speech_response.stream_to_file(output_audio_filepath) | |
| return chat_history, chat_history, output_audio_filepath, None | |
| except AuthenticationError: | |
| error_msg = "Error: Invalid OpenAI API key." | |
| chat_history.append((user_text if 'user_text' in locals() else "Audio input", error_msg)) | |
| return chat_history, chat_history, None, None | |
| except Exception as e: | |
| error_msg = f"An error occurred: {e}" | |
| print(error_msg) | |
| chat_history.append((user_text if 'user_text' in locals() else "Audio input", error_msg)) | |
| return chat_history, chat_history, None, None | |
| finally: | |
| if audio_filepath and os.path.exists(audio_filepath): | |
| os.remove(audio_filepath) | |
| # --- Gradio UI --- | |
| with gr.Blocks(theme=gr.themes.Soft(), title="Conversational Resume Bot") as demo: | |
| gr.Markdown("# 🤖 Talk to Thejas Haridas (AI Resume Bot)") | |
| gr.Markdown("Use your voice to ask questions about Thejas Haridas' background and experience.") | |
| chat_history_state = gr.State([]) | |
| with gr.Row(): | |
| api_key_input = gr.Textbox( | |
| label="OpenAI API Key", | |
| placeholder="Enter your OpenAI API key here...", | |
| type="password" | |
| ) | |
| with gr.Row(): | |
| gr.Markdown("⚠️ **After recording, please click the ▶️ play button once before submitting, or the audio won't be saved.**") | |
| with gr.Row(): | |
| audio_input = gr.Audio( | |
| sources=["microphone"], | |
| type="filepath", | |
| label="Record your message", | |
| streaming=False, # <-- Add this line to ensure file is saved on submit | |
| interactive=True | |
| ) | |
| with gr.Row(): | |
| submit_button = gr.Button("Submit Audio") | |
| with gr.Column(): | |
| chatbot_output = gr.Chatbot(label="Conversation", height=400, avatar_images=("./user_avatar.png", "./bot_avatar.png")) | |
| audio_output = gr.Audio(label="AI Response", autoplay=True, interactive=False, format="mp3") | |
| submit_button.click( | |
| fn=audio_bot, | |
| inputs=[api_key_input, audio_input, chat_history_state], | |
| outputs=[chatbot_output, chat_history_state, audio_output, audio_input] # Add audio_input here | |
| ) | |
| gr.Markdown("---") | |
| gr.Markdown("Made with ❤️ by Thejas Haridas using Gradio and OpenAI.") | |
| if __name__ == "__main__": | |
| if not os.path.exists("user_avatar.png"): | |
| with open("user_avatar.png", "w"): pass | |
| if not os.path.exists("bot_avatar.png"): | |
| with open("bot_avatar.png", "w"): pass | |
| demo.launch(debug=True, share=True) | |