Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
2f0314e
level-1: Varshit Pratap Singh Bhadauria
temporalzone Apr 15, 2026
923214c
level-2: Varshit Pratap Singh Bhadauria
temporalzone Apr 15, 2026
ce40cf7
fix: added test output and LLM output for level-2
temporalzone Apr 15, 2026
4ba4db1
fix: level 2 proper bot format
temporalzone Apr 15, 2026
8d5a207
final fix level 2
temporalzone Apr 15, 2026
17604ef
final final level 2 fix
temporalzone Apr 15, 2026
78c97b1
FINAL LEVEL 2 FIX
temporalzone Apr 15, 2026
6cf6e33
level-2: Varshit Pratap Singh Bhadauria
temporalzone Apr 15, 2026
0d7d16c
fix: add level2.md submission file
temporalzone Apr 15, 2026
15bc910
fix: add level2.md submission file
temporalzone Apr 15, 2026
5d91214
fix: update level2.md with actual outputs
temporalzone Apr 15, 2026
11fc75a
changed file location
temporalzone Apr 16, 2026
f9c4ed1
level-5: Varshit Pratap Singh Bhadauria
temporalzone May 8, 2026
6ef12c3
Add secured Level 6 dashboard and graph files
temporalzone May 8, 2026
28c13f2
Add requirements.txt for Streamlit Cloud
temporalzone May 8, 2026
67a75b4
Update app.py
temporalzone May 8, 2026
74c6f48
Update app.py
temporalzone May 8, 2026
95a25b8
Use Streamlit secrets for Neo4j credentials
temporalzone May 8, 2026
40ea0f1
Add Streamlit import to app.py
temporalzone May 8, 2026
5ed64d9
Add Neo4j import to app.py
temporalzone May 8, 2026
9dc3ac2
Add pandas import to app.py
temporalzone May 8, 2026
3298259
Update CSV file paths for data loading
temporalzone May 8, 2026
b43e274
Rename work_df to workers_df for clarity
temporalzone May 8, 2026
f0100fd
Refactor Neo4j connection and data loading
temporalzone May 8, 2026
0a95ae6
Complete Level 6 Dashboard and README
temporalzone May 8, 2026
18832da
Add README file for Level 6
temporalzone May 8, 2026
abb741e
Merge branch 'level-5-varshit-pratap-singh-bhadauria' of https://gith…
temporalzone May 8, 2026
7a82c5e
Update Level 5 answers and schema
temporalzone May 8, 2026
40fdb54
Delete submissions/varshit-pratap-singh-bhadauria/level5/schema.md
temporalzone May 8, 2026
c7c4f5c
Delete submissions/varshit-pratap-singh-bhadauria/level5/answers.md
temporalzone May 8, 2026
5d699ca
Add final answers.md for Level 5
temporalzone May 9, 2026
8c9f300
Resolve conflict by keeping the new answers.md file
temporalzone May 9, 2026
9500df4
Address L5 review: add specific hours to Q3, fix markdown escaping, r…
temporalzone May 12, 2026
060cb30
Force update answers.md for L5 review
temporalzone May 12, 2026
c0cc151
Address L6 review: fix imports, add 6 self-test checks, clean README
temporalzone May 12, 2026
1e3d8c4
Fix count retrieval for various entities in app.py
temporalzone May 12, 2026
d8ee7d4
Update DASHBOARD_URL to new Streamlit app link
temporalzone May 12, 2026
9cd5979
Added one-pager task files
temporalzone May 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions contributors/varshit-pratap-singh-bhadauria.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "Varshit Pratap Singh Bhadauria",
"github": "temporalzone",
"program": "B.Tech CSE",
"campus": "Amity Noida",
"skills": ["python", "java", "javascript", "react", "django", "flask", "rest-apis", "sqlite", "mysql", "git", "dsa", "jwt-auth"],
"interests": ["agents", "AI", "api-integration", "backend", "automation"],
"track": "A: Agent Builders",
"my_twin": "My digital twin would correlate sleep cycles, screen time, and focus sessions to detect productivity patterns I can't see manually. I want it to predict low-performance windows before they happen — not just track, but intervene with data-backed recommendations. This is exactly the kind of agent I want to build."
}
5 changes: 4 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file not shown.
Binary file not shown.
Binary file not shown.
53 changes: 53 additions & 0 deletions submissions/varshit-pratap-singh-bhadauria/level 2/HOW_I_DID_IT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Level 2 Submission — Varshit Pratap Singh Bhadauria

## What I Did

### Step 1: Ran LPI Sandbox
Command run kiya: `npm run test-client`

Output:
=== LPI Sandbox Test Client ===
[PASS] smile_overview({})
[PASS] smile_phase_detail({"phase":"reality-emulation"})
[PASS] list_topics({})
[PASS] query_knowledge({"query":"explainable AI"})
[PASS] get_case_studies({})
[PASS] get_case_studies({"query":"smart buildings"})
[PASS] get_insights({"scenario":"personal health digital twin","tier":"free"})
[PASS] get_methodology_step({"phase":"concurrent-engineering"})
=== Results ===
Passed: 8/8
Failed: 0/8
All tools working. Your LPI Sandbox is ready.

### Step 2: Installed Ollama — Model: qwen2.5:1.5b

Command: `ollama run qwen2.5:1.5b "What is the SMILE methodology in digital twins?"`

LLM Output:
The SMILE methodology stands for Simulation, Model, Input, Output,
Execution — used in digital twin development to help organizations
gain insight into their systems. It involves simulation, modeling,
input identification, output generation, and execution of real-world
scenarios.

### Step 3: What Surprised Me About SMILE

1. The local LLM incorrectly expanded SMILE as "Simulation, Model,
Input, Output, Execution" — proving that general-purpose models
hallucinate domain-specific knowledge about digital twins.

2. The actual SMILE methodology (Sustainable Methodology for Impact
Lifecycle Enablement) focuses on 6 structured phases — which the
LPI tools explained far more accurately than the LLM.

3. This proved why grounding AI agents with domain-specific tools
like LPI is critical — LLMs alone cannot be trusted for specialized
digital twin knowledge without retrieval-augmented context.

## Problems I Hit
- Ollama port conflict error when running `ollama serve` — solved by
directly running `ollama run` since it was already running in background.

## Model Choice
Used qwen2.5:1.5b — lightweight model, runs locally without GPU, no API key needed.
36 changes: 36 additions & 0 deletions submissions/varshit-pratap-singh-bhadauria/level 2/level2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Level 2 Submission — Varshit Pratap Singh Bhadauria

## Test Client Output
=== LPI Sandbox Test Client ===
[PASS] smile_overview({})
[PASS] smile_phase_detail({"phase":"reality-emulation"})
[PASS] list_topics({})
[PASS] query_knowledge({"query":"explainable AI"})
[PASS] get_case_studies({})
[PASS] get_case_studies({"query":"smart buildings"})
[PASS] get_insights({"scenario":"personal health digital twin","tier":"free"})
[PASS] get_methodology_step({"phase":"concurrent-engineering"})
Passed: 8/8 | Failed: 0/8
All tools working. Your LPI Sandbox is ready.

## LLM Output
Model: qwen2.5:1.5b
Command: ollama run qwen2.5:1.5b "What is the SMILE methodology in digital twins?"

The SMILE methodology stands for Simulation, Model, Input, Output,
Execution and it is an approach used in digital twin development to
help organizations gain insight into their systems or processes.

## 3 Things That Surprised Me About SMILE
1. The local LLM completely hallucinated SMILE's definition — calling
it "Simulation, Model, Input, Output, Execution" when it actually
stands for Sustainable Methodology for Impact Lifecycle Enablement,
proving LLMs cannot be trusted for domain-specific knowledge.

2. SMILE has 6 structured phases for digital twin implementation —
far more comprehensive than I expected, covering everything from
Reality Emulation to full lifecycle management.

3. Grounding AI agents with domain-specific tools like LPI is
critical — without retrieval-augmented context, even capable LLMs
produce confident but completely wrong answers about digital twins.
80 changes: 80 additions & 0 deletions submissions/varshit-pratap-singh-bhadauria/level5/answers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Level 5: Graph Thinking Answers

## Q1. Model It (20 pts)
Here is the graph schema capturing the relationships between the factory entities based on the production, capacity, and worker data.

**6 Node Labels:**
1. Project
2. Product
3. Station
4. Worker
5. Week
6. Etapp

**8 Relationship Types:**
1. (Project)-[:PRODUCES {quantity, unit_factor}]->(Product)
2. (Project)-[:SCHEDULED_AT {planned_hours, actual_hours}]->(Station)
3. (Week)-[:HAS_CAPACITY {total_capacity, total_planned, deficit}]->(Station)
4. (Project)-[:BELONGS_TO]->(Etapp)
5. (Project)-[:ACTIVE_IN]->(Week)
6. (Worker)-[:PRIMARY_STATION]->(Station)
7. (Worker)-[:CAN_COVER]->(Station)
8. (Product)-[:REQUIRES]->(Station)

### Visual Diagram:
```mermaid
graph TD
Project((Project))
Product((Product))
Station((Station))
Worker((Worker))
Week((Week))
Etapp((Etapp))

Project -- "PRODUCES {quantity, unit_factor}" --> Product
Project -- "SCHEDULED_AT {planned_hours, actual_hours}" --> Station
Project -- "BELONGS_TO" --> Etapp
Project -- "ACTIVE_IN" --> Week
Worker -- "PRIMARY_STATION" --> Station
Worker -- "CAN_COVER" --> Station
Week -- "HAS_CAPACITY {total_capacity, total_planned, deficit}" --> Station
Product -- "REQUIRES" --> Station

Q2. Why Not Just SQL? (20 pts)
SQL Version:
SELECT w.name, p.project_name
FROM workers w
JOIN worker_coverage wc ON w.worker_id = wc.worker_id
JOIN stations s ON wc.station_code = s.station_code
JOIN production pr ON s.station_code = pr.station_code
JOIN projects p ON pr.project_id = p.project_id
WHERE s.station_code = '016' AND w.name != 'Per Gustafsson';
Cypher Version:
MATCH (w:Worker)-[:CAN_COVER]->(s:Station {station_code: '016'})<-[:SCHEDULED_AT]-(p:Project)
WHERE w.name <> 'Per Gustafsson'
RETURN w.name AS Backup_Worker, p.project_name AS Affected_Project
Why the graph version is better: The graph version makes it immediately obvious how workers, stations, and projects are connected without requiring expensive mapping tables or complex JOIN logic. In Cypher, you visually draw the path (Worker -> Station <- Project).

Q3. Spot the Bottleneck (20 pts)
Identifying the overload: According to the capacity data, Weeks 1 and 2 have the largest capacity deficits (-132 and -125 hours). The production data shows the 011 FS IQB and 012 Förmontering IQB stations have highly concurrent schedules across almost all projects during these weeks, causing the massive bottleneck.
Cypher Query:
MATCH (p:Project)-[r:SCHEDULED_AT]->(s:Station)
WHERE r.actual_hours > (r.planned_hours * 1.10)
RETURN s.station_name, collect(p.project_name) AS Over_Budget_Projects
Modeling this alert: We can add a status: 'Bottleneck' property directly to the [:SCHEDULED_AT] relationship when actual hours exceed planned capacity, or create a dynamic (:Bottleneck) node linked to the specific (Station) and (Week).
For example, in Week 1, the factory had a capacity deficit of -132 hours. A major bottleneck was Station 014 (Svets o montage), where multiple projects went over their scheduled time. Project P03 planned for 42.0 hours but actually took 48.0 hours, and Project P08 planned for 40.0 hours but actually took 44.0 hours.

Q4. Vector + Graph Hybrid (20 pts)
What to embed: Embed the unstructured text of the "project descriptions" and "product requirements".
Hybrid Query:
CALL db.index.vector.queryNodes('project_embeddings', 5, $search_embedding) YIELD node AS p, score
MATCH (p)-[r:SCHEDULED_AT]->(s:Station)
WHERE ((r.actual_hours - r.planned_hours) / r.planned_hours) < 0.05
RETURN p.project_name, score, s.station_name
Why this is more useful: Keyword filtering is rigid. Vector search understands the semantic meaning to find similar past scopes (e.g., matching "hospital" to the existing "Sjukhus Linköping" project), while the graph enforces hard factual constraints (like ensuring historical variance is < 5%).

Q5. Your L6 Plan (20 pts)
Node Labels: Project, Product, Station, Worker, Week
Relationship Types: (Project)-[:PRODUCES]->(Product) (Project)-[:SCHEDULED_AT]->(Station) (Worker)-[:WORKS_AT]->(Station) (Worker)-[:CAN_COVER]->(Station) (Week)-[:HAS_CAPACITY]->(Station)
Dashboard Panels: Project Overview: A table showing all projects with planned vs actual hours. Station Load: An interactive Plotly bar chart visualizing hours per station. Worker Coverage: A matrix showing which workers can cover which stations.
Cypher Queries: Project Overview: MATCH (p:Project)-[r:SCHEDULED_AT]->(s:Station) RETURN p.project_name, sum(r.planned_hours), sum(r.actual_hours) Station Load: MATCH (s:Station)<-[r:SCHEDULED_AT]-(p:Project) RETURN s.station_name, r.week, r.planned_hours, r.actual_hours Worker Coverage: MATCH (w:Worker)-[:CAN_COVER]->(s:Station) RETURN w.name, collect(s.station_name)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.env
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
https://lpi-developer-kit-l6.streamlit.app/
15 changes: 15 additions & 0 deletions submissions/varshit-pratap-singh-bhadauria/level6/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Level 6: Factory Knowledge Graph Dashboard

This project is a Streamlit dashboard powered by a Neo4j knowledge graph. It replaces a 46-sheet Excel workbook for a steel fabrication company.

## Files Included:
- `seed_graph.py`: Standalone, idempotent script used to parse CSV data and populate the Neo4j Aura cloud database.
- `app.py`: The Streamlit application containing the dashboard UI and Cypher queries.
- `DASHBOARD_URL.txt`: Contains the public link to the deployed Streamlit Cloud dashboard.

## Dashboard Features:
- Project Overview
- Station Load Visualization
- Capacity Tracker
- Worker Coverage Matrix
- Automated Self-Test Page
155 changes: 155 additions & 0 deletions submissions/varshit-pratap-singh-bhadauria/level6/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import streamlit as st
import pandas as pd
import plotly.express as px
from neo4j import GraphDatabase

# Using your local Neo4j Desktop credentials
URI = st.secrets["NEO4J_URI"]
USERNAME = st.secrets["NEO4J_USERNAME"]
PASSWORD = st.secrets["NEO4J_PASSWORD"] # <--- PUT YOUR NEO4J DESKTOP PASSWORD HERE

# Connect to Neo4j
@st.cache_resource
def get_db_driver():
return GraphDatabase.driver(URI, auth=(USERNAME, PASSWORD))

driver = get_db_driver()

def run_query(query):
with driver.session() as session:
result = session.run(query)
# Handle empty results gracefully
if not result.peek():
return pd.DataFrame()
return pd.DataFrame([r.values() for r in result], columns=result.keys())

# --- Sidebar Navigation ---
st.sidebar.title("Factory Dashboard")
page = st.sidebar.radio("Go to", ["Project Overview", "Station Load", "Capacity Tracker", "Worker Coverage", "Self-Test"])

# --- Page 1: Project Overview ---
if page == "Project Overview":
st.title("Project Overview")
query = """
MATCH (p:Project)-[sched:SCHEDULED_AT]->(s:Station)
OPTIONAL MATCH (p)-[:PRODUCES]->(prod:Product)
RETURN p.name AS Project,
sum(sched.planned_hours) AS Total_Planned,
sum(sched.actual_hours) AS Total_Actual,
collect(DISTINCT prod.type) AS Products
"""
df = run_query(query)
if not df.empty:
df['Variance %'] = ((df['Total_Actual'] - df['Total_Planned']) / df['Total_Planned'] * 100).round(2)
st.dataframe(df)
else:
st.write("No data found.")

# --- Page 2: Station Load ---
elif page == "Station Load":
st.title("Station Load")
query = """
MATCH (p:Project)-[sched:SCHEDULED_AT]->(s:Station)
RETURN s.name AS Station, sched.week AS Week,
sum(sched.planned_hours) AS Planned,
sum(sched.actual_hours) AS Actual
"""
df = run_query(query)
if not df.empty:
# Highlight where actual > planned
df['Overloaded'] = df['Actual'] > df['Planned']

# Interactive Plotly Chart
fig = px.bar(df, x="Station", y=["Planned", "Actual"], barmode="group",
color="Overloaded", color_discrete_map={True: 'red', False: 'green'},
title="Planned vs Actual Hours per Station")
st.plotly_chart(fig)

# --- Page 3: Capacity Tracker ---
elif page == "Capacity Tracker":
st.title("Capacity Tracker")
query = """
MATCH (wk:Week)-[hc:HAS_CAPACITY]->(c:Capacity)
RETURN wk.id AS Week,
(hc.own + hc.hired + hc.overtime) AS Total_Capacity,
hc.deficit AS Deficit
ORDER BY Week
"""
df = run_query(query)
if not df.empty:
# Display deficit weeks in red using Streamlit styling
def color_deficit(val):
color = 'red' if val < 0 else 'green'
return f'color: {color}'
st.dataframe(df.style.map(color_deficit, subset=['Deficit']))

# --- Page 4: Worker Coverage ---
elif page == "Worker Coverage":
st.title("Worker Coverage")
query = """
MATCH (w:Worker)-[:CAN_COVER]->(s:Station)
WITH s, count(w) as Worker_Count, collect(w.name) as Workers
RETURN s.name AS Station, Worker_Count, Workers
ORDER BY Worker_Count ASC
"""
df = run_query(query)
if not df.empty:
# Highlight Single Point of Failure (Worker_Count == 1)
def highlight_spof(val):
color = 'red' if val == 1 else ''
return f'background-color: {color}'
st.markdown("**Stations in RED have only 1 certified worker (Single Point of Failure)!**")
st.dataframe(df.style.map(highlight_spof, subset=['Worker_Count']))

### --- Page 5: Self-Test (Mandatory) ---
elif page == "Self-Test":
st.title("Self-Test")
st.markdown("Running automated checks...")

# 1. Check Projects (Min 8)
df_proj = run_query("MATCH (n:Project) RETURN count(n) as count")
proj_count = int(df_proj['count'].sum()) if not df_proj.empty else 0
if proj_count >= 8:
st.success(f"✅ Projects: {proj_count} (Min 8)")
else:
st.error(f"❌ Projects: {proj_count} (Min 8)")

# 2. Check Products (Min 7)
df_prod = run_query("MATCH (n:Product) RETURN count(n) as count")
prod_count = int(df_prod['count'].sum()) if not df_prod.empty else 0
if prod_count >= 7:
st.success(f"✅ Products: {prod_count} (Min 7)")
else:
st.error(f"❌ Products: {prod_count} (Min 7)")

# 3. Check Stations (Min 9)
df_stat = run_query("MATCH (n:Station) RETURN count(n) as count")
stat_count = int(df_stat['count'].sum()) if not df_stat.empty else 0
if stat_count >= 9:
st.success(f"✅ Stations: {stat_count} (Min 9)")
else:
st.error(f"❌ Stations: {stat_count} (Min 9)")

# 4. Check Workers (Min 13)
df_work = run_query("MATCH (n:Worker) RETURN count(n) as count")
work_count = int(df_work['count'].sum()) if not df_work.empty else 0
if work_count >= 13:
st.success(f"✅ Workers: {work_count} (Min 13)")
else:
st.error(f"❌ Workers: {work_count} (Min 13)")

# 5. Check Weeks (Min 8)
df_week = run_query("MATCH (n:Week) RETURN count(n) as count")
week_count = int(df_week['count'].sum()) if not df_week.empty else 0
if week_count >= 8:
st.success(f"✅ Weeks: {week_count} (Min 8)")
else:
st.error(f"❌ Weeks: {week_count} (Min 8)")

# 6. Check Etapps (Min 2)
df_etapp = run_query("MATCH (n:Etapp) RETURN count(n) as count")
etapp_count = int(df_etapp['count'].sum()) if not df_etapp.empty else 0
if etapp_count >= 2:
st.success(f"✅ Etapps: {etapp_count} (Min 2)")
else:
st.error(f"❌ Etapps: {etapp_count} (Min 2)")
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
week,own_staff_count,hired_staff_count,own_hours,hired_hours,overtime_hours,total_capacity,total_planned,deficit
w1,10,2,400,80,0,480,612,-132
w2,10,2,400,80,40,520,645,-125
w3,10,2,400,80,0,480,398,82
w4,10,2,400,80,20,500,550,-50
w5,10,2,400,80,30,510,480,30
w6,9,2,360,80,0,440,520,-80
w7,10,2,400,80,40,520,600,-80
w8,10,2,400,80,20,500,470,30
Loading
Loading