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"<>> \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)