# ============================================ # app.py - For HuggingFace Spaces Deployment # Simple & Clean UI (No Purple) # ============================================ import os import gradio as gr from langchain_openai import OpenAIEmbeddings, ChatOpenAI from langchain_chroma import Chroma from langchain_core.prompts import ChatPromptTemplate from langchain_core.runnables import RunnablePassthrough from langchain_core.output_parsers import StrOutputParser # Get API key from HuggingFace Secrets OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY") if not OPENAI_API_KEY: raise ValueError("Please set OPENAI_API_KEY in HuggingFace Secrets") # Path to your vector store VECTOR_STORE_PATH = "./chroma_db" # Load vector store embeddings = OpenAIEmbeddings(model="text-embedding-ada-002", openai_api_key=OPENAI_API_KEY) try: vector_store = Chroma( persist_directory=VECTOR_STORE_PATH, embedding_function=embeddings ) print(f"â Loaded {vector_store._collection.count()} vectors") except Exception as e: print(f"â ī¸ Vector store not found: {e}") vector_store = None if vector_store: retriever = vector_store.as_retriever(search_kwargs={"k": 4}) prompt_template = ChatPromptTemplate.from_messages([ ("system", """You are an AI assistant answering questions about Stephen Manickam's resume and CV. Use the context below to answer accurately and helpfully. If the information is not in the context, say "I don't see that in the resume" rather than making up information. Be concise, professional, and friendly. Context: {context} """), ("human", "{question}") ]) llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0.2, openai_api_key=OPENAI_API_KEY) def format_docs(docs): return "\n\n".join(doc.page_content for doc in docs) rag_chain = ( {"context": retriever | format_docs, "question": RunnablePassthrough()} | prompt_template | llm | StrOutputParser() ) def respond(message, history): if not message.strip(): return "Please enter a question." try: return rag_chain.invoke(message) except Exception as e: return f"Error: {str(e)}" else: def respond(message, history): return "Vector store not found. Please upload your resume first." # ============================================ # Simple & Clean CSS (No Purple, Neutral Colors) # ============================================ custom_css = """ /* Main container - clean white background */ .gradio-container { background: #f8fafc !important; } /* Header styling */ .header-title { text-align: center; font-size: 2.5rem !important; font-weight: 600 !important; color: #1e293b !important; margin-bottom: 0.5rem !important; } .header-subtitle { text-align: center; color: #64748b !important; font-size: 1.1rem !important; margin-bottom: 2rem !important; } /* Chat bubble styling */ .user-message { background: #3b82f6 !important; color: white !important; border-radius: 20px !important; padding: 12px 18px !important; margin: 8px 0 !important; } .bot-message { background: #ffffff !important; color: #1e293b !important; border: 1px solid #e2e8f0 !important; border-radius: 20px !important; padding: 12px 18px !important; margin: 8px 0 !important; } /* Input box styling */ input[type="text"], textarea { border-radius: 30px !important; border: 1px solid #cbd5e1 !important; padding: 12px 20px !important; font-size: 1rem !important; transition: all 0.2s ease !important; background: white !important; } input[type="text"]:focus, textarea:focus { border-color: #3b82f6 !important; box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1) !important; outline: none !important; } /* Button styling */ button { border-radius: 30px !important; background: #3b82f6 !important; color: white !important; border: none !important; padding: 10px 24px !important; font-weight: 500 !important; transition: background 0.2s ease !important; } button:hover { background: #2563eb !important; } /* Secondary buttons (examples) */ .gr-button-secondary { background: white !important; color: #3b82f6 !important; border: 1px solid #cbd5e1 !important; } .gr-button-secondary:hover { background: #f1f5f9 !important; border-color: #3b82f6 !important; } /* Accordion styling */ .accordion-header { background: white !important; border-radius: 12px !important; border: 1px solid #e2e8f0 !important; } /* Footer styling */ .footer { text-align: center; color: #94a3b8 !important; font-size: 0.85rem !important; margin-top: 2rem !important; padding: 1rem !important; border-top: 1px solid #e2e8f0 !important; } """ # Create the interface with gr.Blocks(css=custom_css, title="Stephen Manickam - Resume Q&A Assistant") as demo: gr.HTML("""
Ask me anything about Stephen's education, work experience, skills, projects, and achievements