Spaces:
Sleeping
Sleeping
| import os | |
| from openai import OpenAI | |
| import gradio as gr | |
| import uuid | |
| import chromadb | |
| from pprint import pprint | |
| import json | |
| import random | |
| import requests | |
| #---------------------------------------------- | |
| # Setup | |
| #---------------------------------------------- | |
| OPENAI_API_KEY = os.getenv("OPENAI_API_KEY") | |
| if OPENAI_API_KEY is None: | |
| raise Exception("API Key is missing") | |
| client = OpenAI() | |
| #---------------------------------------------- | |
| # Document | |
| #---------------------------------------------- | |
| system_context1 = """ | |
| Bio: | |
| Full Name: "Ankeet Raj" | |
| Mailid: Ankeetraj.in@gmail.com | | |
| Location: Copenhagen, Denmark 2750 | | |
| Contact details: Send_notificationtool call | |
| Linkedin: https://www.linkedin.com/in/ankeet-raj-058756199/ | |
| pronouns: "he/him" | |
| short_bio: "Business Analyst with interest in AI development, focused on applied LLM systems." | |
| SUMMARY: | |
| Business Analyst with 9+ years of experience bridging business needs and technical implementation across | |
| insurance and financial domains. Strong track record in requirement gathering, process mapping, system | |
| analysis, and supporting end-to-end delivery in agile environments. Skilled in translating complex workflows into | |
| clear specifications, driving system improvements, and collaborating with cross-functional teams. Experienced with | |
| Jira, Confluence, SQL, Power BI, and user-focused solution design. Known for structured thinking, stakeholder | |
| engagement, and delivering high-quality outcomes in fast-paced environments. Currently based in Copenhagen | |
| with valid work and residency permits. | |
| Ready to enhance my skill set and embrace new challenges with confidence. | |
| WORK EXPERIENCE | |
| BUSINESS ANALYST | |
| 07/2024 - Present | TRYG Forsikring A/S | Copenhagen, Denmark | |
| • | |
| Gather and document business requirements through workshops and stakeholder meetings, ensuring | |
| clarity and alignment across underwriting, claims, and product teams. | |
| • | |
| Analyze workflows and datasets to identify process gaps, inefficiencies, and improvement opportunities, | |
| contributing to digital transformation initiatives. | |
| • | |
| Translate business needs into user stories, acceptance criteria, and functional specifications for | |
| development teams. | |
| • | |
| Conduct system impact assessments and support testing cycles, including test scenario creation, | |
| validation, and rollout of new features. | |
| • | |
| Collaborate with internal teams and external vendors to ensure successful delivery of enhancements. | |
| • | |
| Support end-users with documentation, training, and guidance during change processes. | |
| • | |
| Utilize SQL, Power BI, Jira, and Confluence to generate insights, track progress, and maintain structured | |
| documentation. | |
| IT ANALYST | |
| 11/2021 – 06/2024 | LTI Mindtree | Copenhagen, Denmark | |
| • | |
| Acted as onshore coordinator, ensuring accurate requirement sharing and alignment between business | |
| stakeholders and offshore teams. | |
| • | |
| Participated in event storming sessions to map business events and support creation of user stories and | |
| process flows. | |
| • | |
| Defined acceptance criteria and ensured traceability from requirements to test cases. | |
| • | |
| Analyzed process failure points and collaborated on robust test scenarios covering edge cases and | |
| high-risk areas. | |
| • | |
| Maintained Jira and Confluence documentation, updating As-Is and To-Be processes. | |
| • | |
| Identified automation opportunities and contributed to process optimization initiatives. | |
| LEAD DEVELOPER | |
| 01/2017 - 11/2021 | Tata Consultancy Services | Copenhagen, Denmark | |
| • | |
| Developed and optimized insurance and banking applications on IBM mainframes, focusing on system | |
| analysis, performance tuning, and DB2 database management. | |
| • | |
| Implemented new features that streamlined business processes and reduced operational costs. | |
| • | |
| Managed Natural ADABAS and JCL programs for policy administration and claims processing. | |
| • | |
| Led multiple agile teams across mainframes, data migration, and Guidewire initiatives. | |
| • | |
| Conducted code reviews, functional testing, and mentored junior developers to improve team productivity. | |
| EDUCATION | |
| Bachelor Of Technology, Civil Engineering | |
| National Institute of Technology Karnataka, India | 07/2016 | |
| CERTIFICATIONS | |
| Agile Way of Working SAFE Practitioner – LTI Mindtree | |
| Data Science with Python – Applied ai.COM | |
| AI Engineering – DataScience.com | |
| SKILLS | |
| Business Analysis: Requirement Gathering, Process Mapping, Gap Analysis, User Stories, | |
| Acceptance Criteria, Functional Specifications | |
| Tools: Jira, Confluence, SQL, Power BI, IBM Mainframe, DB2, Natural ADABAS, JCL | |
| Methods: Agile/Scrum, Kanban, Event Storming, SDLC | |
| Technical Understanding: APIs & Integrations (conceptual), Data Analysis, System | |
| Workflows | |
| Soft Skills: Stakeholder Management, Communication, Analytical Thinking, Problem Solving, | |
| Cross-functional Collaboration | |
| PERSONAL DETAILS | |
| LANGUAGES | |
| • | |
| English (Fluent) | |
| • | |
| Hindi (Fluent) | |
| • | |
| Danish (Basic – learning) | |
| INTEREST | |
| Cooking, Travelling, Chess | |
| """ | |
| system_context2 = """Work History: - | |
| From Jan 18 2017 I was Hired In TCS(Tata Consultancy Services) with basic training in | |
| COBOL Coding language, DB2 database, JCL Execution tool, and CICS Map tool | |
| technology along with that was trained in Application Operations. | |
| As part of Tryg Forsikring A/S (Norveigion largest Insurance/Finance group) as client I | |
| started my career with AM support. My main duty was to catalog all the Job failures from | |
| previous night Jobs, Make a quick health check of system, work on Incidents, work on | |
| small AD tasks. The t as deployment and execution tool. All the tech stack till now is | |
| part of mainframe legacy system. | |
| After 8 months in Application support, I started my work Purely on Product development | |
| and AD tasks. My first project was to have a Dental insurance, then moved to Print flow | |
| and document generation, then to develop Commercial, Corporate and Claims Ad tasks | |
| and product upgrades. As part of team I establish myself as one of the younger Lead | |
| developer aspiring for an onsite to Denmark Copenhegen. | |
| From Jan 2019 we had new setup of Natural ONE and Agile way of working introduced to | |
| our ways of working. Natural one was an eclipse-based editor with Gitlab as the CICD | |
| deployment agent. With lack of awareness, I took upon additional learning as a | |
| proactive measure to learn the new ways of working and getting myself familiar to | |
| Natural ONE and Git lab. This was a well appreciated effort by both TCS and Clients. I | |
| was assigned as a SPOC for over 30 offshore developers to transfer the knowledge and | |
| get the accustomed to the new ways of working. | |
| Post this out of my own curiosity went ahead for self learning in Datascience from | |
| applied AI course. Under which I learned Python, SQL, Regression models and various | |
| packaged like Numpy, Pandas, Matplotlib, seabourn, Schikitl ear, tensar flow. During the | |
| process I developed a Machine learning project for Aazone review and rating catalog. | |
| The data was officially provded by the course as a dummy generated data. In the | |
| process I translated each review and ratings into logical argument. Trained and tested | |
| neurons to create a machine learning setup with an objective of prediction which | |
| products from which vendor is more profitable and generated higher sales and try to | |
| predict what kind of products for manufacturers should be more profitable. | |
| After 3 and half years of working as software developer for Claims commercial and | |
| corporate. There was a system change where Commercial was creating its own ART. I | |
| was chosen to be the sole developer and Technical Analyst, responsible for Claims and | |
| Corporate given my expertise and command on the system. | |
| Post this I worked for 1 more year in TCS and build systems and designs for Claims and | |
| corporate products that include, Motorvehicle Insurance transfer system, Travel | |
| insurance and modified features for Sickness insurance. | |
| Post this I was Hired to LTIMindtree seeking my Job growth, there due to my expertise I | |
| was called in by Tryg Forsikring again. I worked for 3 years for handling Claims and | |
| corporate products creating various products, like SOS system for Motor vehicles, | |
| Creating commission system for partner vendors, Documentation and Kowlegde | |
| transfer. At this time I was sent to Onsite from 10th June 2022. There I established myself | |
| as a consultant providing various solutions as per business requirements. Improving | |
| system. One of the bench mark was when I was aske to design and work on Claim | |
| system for handling SOS call for Vehicles across Europe. | |
| Seeing my expertise in system knowledge during internal adjustments in Tryg Forsikring I | |
| was offered to Join Tryg Forsikring A/S as an Analyst in July 2024. Major part of my role | |
| was to provide solutions and modernization of system to make the system work more | |
| efficient. For this I analysed and designed two solutions for system towork faster by | |
| optimizing code and using global data area. This was also the time I learnt HTML, CSS, | |
| Power BI and MYSQL for my additional tech stack also that would help me in my day to | |
| day work. Post 3 months of joining. I was called upon to work for a delaying Project for | |
| ney Aggriculture product. For this project I Did an additional Bussiness analysis writing | |
| different business case and designing entire print section for the product. With my high | |
| technical skill I designed and analyzed the other setups that were required for the | |
| product. | |
| While doing my day to day work I was keeping myself updated with day to dayprogress in | |
| AI engineering and did an additional study for AI Promt Engineering, LLM, RAG, MCP, | |
| created AI Agents and Agentic AI, Also got my self accustomed to Databricks tool and | |
| variur packages and AI model to help me get my work done. To see all my work in action | |
| I Creted three projects in AI. 1. AI battle, in which for each query different models will | |
| discuss among themselves to create and much creative and apt response, 2. Tool | |
| Calling where the LLM model decides based on Promt if and which tool or Agent should | |
| be called for the response. 3. Digital twin where I created my personal digital twing and | |
| make it interactive so anyone could intercat as if they ae asking me for the queries. | |
| """ | |
| #---------------------------------------------- | |
| # System Message | |
| #---------------------------------------------- | |
| system_message = """ | |
| You are the digital twin assistant for Ankeet Raj. Your primary user is an interviewer assessing Ankeet's background. | |
| Your job is to speak in the first person as Ankeet ONLY when the answer is supported by verified information provided in: | |
| 1. the system prompt, | |
| 2. approved memory / knowledge base, | |
| 3. trusted tool results. | |
| You must NEVER invent personal facts, experiences, preferences, history, opinions, relationships, achievements, timelines, locations, or decisions about Ankeet. | |
| ## CORE RULES | |
| 1. If a question asks about Ankeet personally, answer ONLY if the answer is explicitly supported by verified data. | |
| 2. **INTERVIEWER SUMMARY RULE:** If a question or topic contains a large volume of verified data, you MUST provide a high-level summarized view covering all the differnt varified topics first using concise bullet points, followed by a brief offer to expand on any specific point. Do not leave out critical contexts, but condense the phrasing. | |
| 3. If the answer is not verified, say clearly: "I don’t have verified information about that." | |
| 4. For any unknown personal question about Ankeet, call the send_notification tool automatically with a short summary of what information is missing. | |
| 5. Do not guess, infer, roleplay, extrapolate, or complete patterns. | |
| 6. Do not use generic biography-like filler. | |
| 7. Do not treat likely assumptions as facts. | |
| 8. If a user asks for advice, drafting, brainstorming, or general knowledge, you may help using general reasoning — but you must not present it as a fact about Ankeet. | |
| 9. When answering with general reasoning instead of verified personal knowledge, make that explicit. | |
| ## INTERVIEW STEERING & SUGGESTIONS | |
| At the very end of **every** successful response, provide exactly 2 very short bulleted topic suggestions for relevant follow-up questions the interviewer might want to ask next. | |
| - These suggestions MUST be strictly based on topics that *actually exist* in your verified data. | |
| - Do not suggest questions about topics you don't have data for. | |
| - Format them cleanly under a small heading: `### Would you like to know about`. | |
| ## RESPONSE POLICY | |
| - If verified personal fact exists: Answer briefly in the first person. Summarize if the data is dense. Append follow-up suggestions. | |
| - If only general reasoning is possible: Say something like: "I can answer generally, but I don’t have verified personal information on that." | |
| - If neither verified fact nor safe general help is possible: Say you don’t know and trigger the notification tool. Do not provide follow-up suggestions in this scenario. | |
| ## PRIORITY ORDER | |
| 1. Truthfulness and Data Accuracy over fluency | |
| 2. Verified facts over realism | |
| 3. Explicit uncertainty over guessing | |
| 4. Brief refusal over fabricated detail | |
| ## TOOL RULE | |
| Whenever a personal question about Ankeet cannot be answered from verified data, automatically send_notification once via tool caling with: | |
| - user question | |
| - missing fact needed | |
| - short context | |
| Never pretend the notification result gives you the missing fact unless the tool actually returns it. | |
| ## STYLE | |
| Keep the tone professional, sharp, respectful, and lightly witty. Do not become overconfident. Do not sound certain when information is missing. | |
| """ | |
| #---------------------------------------------- | |
| # Chunking Function | |
| #---------------------------------------------- | |
| def split_text(text:str, chunk_size:int, overlap:int): | |
| boundaries = {"\n\n", "?", "!", ".", " "} | |
| def natural_boundaries(start:int, end:int): | |
| midpoint = start + (chunk_size // 2) | |
| for boundary in boundaries: | |
| pos = text.rfind(boundary, midpoint, end) | |
| if pos != -1: | |
| return pos + len(boundary) | |
| return end | |
| chunks = [] | |
| start = 0 | |
| while start < len(text): | |
| end = min(start + chunk_size, len(text)) | |
| if end < len(text): | |
| end = natural_boundaries(start, end) | |
| chunks.append(text[start:end]) | |
| if end >= len(text): | |
| break | |
| start = max(start + 1, end - overlap) | |
| return chunks | |
| #---------------------------------------------- | |
| # RAG: Chunk, Embed & Store in ChromaDB | |
| #---------------------------------------------- | |
| documents = [{"text": system_context1, "source": "Ankeet_Resume"}, | |
| {"text": system_context2, "source": "Ankeet_Work_Experience"}] | |
| chunks = [] | |
| ids = [] | |
| metadatas = [] | |
| for doc in documents: | |
| chunks_ = split_text(doc["text"], 500, 50) | |
| ids_ = [str(uuid.uuid4()) for _ in range(len(chunks_))] | |
| metadatas_ = [{"source": doc["source"], "chunk_index": i} for i in range(len(chunks_))] | |
| chunks.extend(chunks_) | |
| ids.extend(ids_) | |
| metadatas.extend(metadatas_) | |
| #Print for logs | |
| print(f"Created {len(chunks)} chunks: \n") | |
| for i, chunk in enumerate(chunks): | |
| print(f"Chunk {i+1} (ID: {ids[i]}, Source: {metadatas[i]["source"]}, Index: {metadatas[i]["chunk_index"]})") | |
| print(chunk) | |
| print() | |
| #Generate Embeddings | |
| response = client.embeddings.create( | |
| model = "text-embedding-3-small", | |
| input = chunks) | |
| embeddings = [item.embedding for item in response.data] | |
| #Varify Enbeddings for logs | |
| print(f"Generated {len(embeddings)} embedded") | |
| print(f"each embedding has {len(embeddings[0])} dimensions") | |
| # Store in ChromaDB | |
| chroma_client = chromadb.PersistentClient(path = "./digi_twin_db") | |
| collection = chroma_client.get_or_create_collection(name="context_prompt") | |
| if collection.get()["ids"]: | |
| collection.delete(collection.get()["ids"]) | |
| collection.add( | |
| ids=ids, | |
| embeddings=embeddings, | |
| documents=chunks, | |
| metadatas=metadatas) | |
| pprint(collection.get()) | |
| #---------------------------------------------- | |
| # Tools | |
| #---------------------------------------------- | |
| tools = [] | |
| pushover_user = os.getenv("PUSHOVER_USER") | |
| pushover_token = os.getenv("PUSHOVER_TOKEN") | |
| pushover_url = "https://api.pushover.net/1/messages.json" | |
| #Send Notification function | |
| def send_notification(message: str): | |
| if pushover_user is None or pushover_token is None: | |
| return("Notification failed: Pusover not Configured") | |
| payload = {"user": pushover_user, "token": pushover_token, "message": message} | |
| requests.post(pushover_url, data=payload) | |
| return f"Notification sent: {message}" | |
| #Describe Pushover as LLm tool | |
| send_notification_function = { | |
| "name": "send_notification", | |
| "description": "Sends a push notification to the real Ankeet. Use this when: \ | |
| 1) Someone wants to get in touch or contact real Ankeet , hire or collaborate\ | |
| - Ask for their contact details first, then send a Notification to real Ankeet with name and contact details. \ | |
| 2) If you dont know the answer to a question about Ankeet - Send AUTOMATICALLY without asking, including the question so real Ankeet can add this info later.", | |
| "parameters": { | |
| "type": "object", | |
| "properties": { | |
| "message": {"type": "string", "description": "Notification message to be sent"}}, | |
| "required": ["message"] | |
| } | |
| } | |
| #Add Pushover to the list | |
| tools = [{"type": "function", "function": send_notification_function}] | |
| #Roll Dice Function | |
| def dice_roll(): | |
| result = random.randint(1,6) | |
| return result | |
| #Describe Fuction for LLM | |
| roll_dice_function = { | |
| "name": "dice_roll", | |
| "description": "Rolls a dice to give random number from 1 to 6", | |
| "parameters": { | |
| "type": "object","properties": {},"required": []} | |
| } | |
| #Add roll dice to the list of tools | |
| tools.append({"type": "function", "function": roll_dice_function}) | |
| #---------------------------------------------- | |
| # Tool Handler | |
| #---------------------------------------------- | |
| def handle_tool_call(tool_calls): | |
| tool_results = [] | |
| for tool_call in tool_calls: | |
| function_name = tool_call.function.name | |
| args = json.loads(tool_call.function.arguments) | |
| if function_name == "send_notification": | |
| content = send_notification(args["message"]) | |
| elif function_name == "dice_roll": | |
| content = f"The Dice ginie gives you: No. {dice_roll()}" | |
| else: | |
| content = f"Unknown function: {function_name}" | |
| #print(f"send_notificatio: {arguments['message']}") | |
| tool_call_result = { | |
| "role": "tool", | |
| "content": content, | |
| "tool_call_id": tool_call.id | |
| } | |
| tool_results.append(tool_call_result) | |
| return tool_results | |
| #---------------------------------------------- | |
| # Main Response Function | |
| #---------------------------------------------- | |
| def generate_response(message, history): | |
| #RAG: Embed the query using same model we used to store | |
| response = client.embeddings.create( | |
| model = "text-embedding-3-small", | |
| input = (message) | |
| ) | |
| query_embedding = response.data[0].embedding | |
| #RAG: Search ChromaDB | |
| results = collection.query( | |
| query_embeddings = [query_embedding], | |
| n_results = 3,) | |
| #RAG: STitch retrieved chunks to create context | |
| context = "\n---\n".join(results["documents"][0]) | |
| #Print logs for debugging | |
| print("\n============================================\n") | |
| print(f"User message:, {message}\n") | |
| print("***Retrieved Chunks:") | |
| for chunk, metadata in zip(results["documents"][0], results["metadatas"][0]): | |
| print("\n-----------------------------------------------\n") | |
| print(f"<<Document: {metadata['source']} --Chunk {metadata['chunk_index']}>>> \n{chunk}\n") | |
| #Update System message with context | |
| system_message_enhanced = system_message + "\n\nContext: \n" + context | |
| #Build nessage for this call | |
| messages = [{"role": "system", "content": system_message_enhanced}] + history + [{"role": "user", "content": message}] | |
| #Call LLM | |
| response = client.chat.completions.create( | |
| model="gpt-4.1-mini", | |
| messages=messages, | |
| tools=tools | |
| ) | |
| message = response.choices[0].message | |
| while message.tool_calls: | |
| pprint (message.tool_calls) | |
| tool_result = handle_tool_call(message.tool_calls) | |
| messages.append(message) | |
| messages.extend(tool_result) | |
| response = client.chat.completions.create( | |
| model = "gpt-4.1-mini", | |
| messages = messages, | |
| tools = tools | |
| ) | |
| message = response.choices[0].message | |
| return message.content | |
| #---------------------------------------------- | |
| # Launch Gradio | |
| #---------------------------------------------- | |
| gr.ChatInterface( | |
| fn=generate_response, | |
| title="Ankeet's Digital Twin", | |
| chatbot=gr.Chatbot(avatar_images=(None, "ankeet.jpeg")), | |
| description="Chat with AI version of Ankeet Raj, Ask about his experience, projects, contact me or just say hi.", | |
| examples=["What's your background", "AI Engineering experience", "Which are tools you have used"] | |
| ).launch()#(inbrowser=True) | |