Rakshitjan commited on
Commit
3883577
·
verified ·
1 Parent(s): 050f34e

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +583 -0
app.py ADDED
@@ -0,0 +1,583 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import sqlite3
3
+ import operator
4
+ from math import ceil
5
+ from fastapi import FastAPI, Query, Body
6
+ from contextlib import asynccontextmanager
7
+ from datetime import datetime
8
+ from collections import defaultdict
9
+ from langchain_openai import ChatOpenAI
10
+ from langchain_core.messages import HumanMessage, SystemMessage
11
+ from typing import Annotated, List, Optional, Dict, Any
12
+ from pydantic import BaseModel, Field
13
+ from typing_extensions import TypedDict
14
+ from langgraph.graph import StateGraph, START, END
15
+ from langgraph.constants import Send
16
+ from fastapi.responses import HTMLResponse
17
+
18
+ # Session State for storing runtime data
19
+ session_state = {
20
+ "report_data": None,
21
+ "final_report": None
22
+ }
23
+
24
+ # Initialize FastAPI app
25
+ app = FastAPI(
26
+ title="JEE Roadmap Planner API",
27
+ description="API for managing and analyzing JEE Roadmaps",
28
+ version="1.0.0"
29
+ )
30
+
31
+ # Models for data input
32
+ class RoadmapData(BaseModel):
33
+ schedule: List[Dict[str, Any]]
34
+ # Add any other fields from the roadmap schema
35
+
36
+ # AGENT 1
37
+ class Section(BaseModel):
38
+ name: str = Field(
39
+ description="Name for this section of the report.",
40
+ )
41
+ description: str = Field(
42
+ description="Brief overview of the main topics and concepts to be covered in this section.",
43
+ )
44
+ data_requirements: str = Field(
45
+ description="Description of the data needed from the roadmap database to write this section.",
46
+ )
47
+
48
+ class Sections(BaseModel):
49
+ sections: List[Section] = Field(
50
+ description="Sections of the report.",
51
+ )
52
+
53
+ # Initialize LLM
54
+ llm = ChatOpenAI(model="gpt-4o-mini")
55
+ planner = llm.with_structured_output(Sections)
56
+
57
+ class State(TypedDict):
58
+ sections: list[Section] # List of report sections
59
+ completed_sections: Annotated[list, operator.add] # All workers write to this key in parallel
60
+ final_report: str # Final report
61
+
62
+ # Combined helper-worker state
63
+ class ProcessorState(TypedDict):
64
+ section: Section
65
+ completed_sections: Annotated[list, operator.add]
66
+
67
+ def orchestrator(state: State):
68
+ """Orchestrator that generates a plan for the report with data requirements"""
69
+
70
+ schema = """CREATE TABLE IF NOT EXISTS roadmap (
71
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
72
+ day_num INTEGER,
73
+ date TEXT, -- [yyyy-mm-dd]
74
+ subject TEXT, -- (Physics, Chemistry or Maths)
75
+ chapter_name TEXT,
76
+ task_type TEXT, -- (Concept Understanding, Question Practice, Revision, Test)
77
+ time TEXT, -- formatted like '0.5 hour', '1 hour', '2 Hours', and so on -- Tells the amount of time required to finish the task
78
+ subtopic TEXT,
79
+ task_completed BOOLEAN, -- 0/1 indicates task completion status
80
+ completion_timestamp TEXT
81
+ )"""
82
+
83
+ # Generate queries
84
+ report_sections = planner.invoke(
85
+ [
86
+ SystemMessage(content=f"""You are responsible for creating a structured plan for a JEE preparation analysis report.
87
+ Audience: The report is intended primarily for students, but must also be insightful to mentors and parents.
88
+ Keep the language motivational and supportive, with actionable insights backed by data.
89
+ Report Format: The report will be composed of exactly 4 concise sections. Your job is to define these sections. Each section must include:
90
+ - **Name**: A short, descriptive title
91
+ - **Description**: What the section analyzes and how it helps the student
92
+ - **Data Requirements**: A plain-English description of what fields and metrics are needed from the roadmap
93
+ database whose schema is given here: {schema}
94
+ DO NOT invent new sections or formats. Use exactly the following four section templates and fill in the
95
+ descriptions and data requirements precisely.
96
+ ---
97
+ ### Study Time Analysis
98
+ **Description**: Analyze how much total time the student planned to spend vs how much they actually completed,
99
+ across different subjects and task types. This will help the student understand where their time is really going.
100
+ **Data Requirements**:
101
+ - Fields: `subject`, `task_type`, `time`, `task_completed`
102
+ - Metrics:
103
+ - Total planned time → SUM of all `time`
104
+ - Total actual time → SUM of `time` where `task_completed = 1`
105
+ - Grouped by both `subject` and `task_type`
106
+ ---
107
+ ### Task Completion Metrics
108
+ **Description**: Measure the student's consistency and follow-through by looking at completion rates across
109
+ subjects and task types.
110
+ **Data Requirements**:
111
+ - Fields: `subject`, `task_type`, `task_completed`
112
+ - Metrics:
113
+ - Total tasks → COUNT of all tasks
114
+ - Completed tasks → COUNT of tasks where `task_completed = 1`
115
+ - Completion percentage per subject and task type
116
+ ---
117
+ ### Study Balance Analysis
118
+ **Description**: Evaluate how the student's study time is distributed across task types (e.g., Practice, Revision, Test)
119
+ within each subject. This highlights over- or under-emphasis on any category.
120
+ **Data Requirements**:
121
+ - Fields: `subject`, `task_type`, `time`
122
+ - Metrics:
123
+ - SUM of `time` for each (subject, task_type) pair where task_completed = 1
124
+ - Relative distribution of time per subject to detect imbalance
125
+ ---
126
+ ### Strengths and Areas for Improvement
127
+ **Description**:
128
+ This section analyzes how the student's effort is distributed — not by estimating how long they spent,
129
+ but by combining how many tasks they completed and how much time those completed tasks represent.
130
+ This helps identify:
131
+ - Subjects and task types where the student is showing strong commitment
132
+ - Areas that may be neglected or inconsistently approached
133
+ **Data Requirements**:
134
+ - Fields: subject, task_type, task_completed, time
135
+ - Metrics (filtered where task_completed = 1):
136
+ - Total Number of completed tasks
137
+ - Total amount of time spent
138
+ - Grouped by subject and task_type
139
+ ---
140
+ Important Constraints:
141
+ - You must include **all the mentioned fields** in the `data_requirements` — no assumptions
142
+ - Use only **aggregate metrics** — no need for per-task or per-day analysis
143
+ - Keep descriptions student-focused, clear, and motivational
144
+ - Do not alter section names or invent new ones
145
+ - Do not output anything outside the strict format above
146
+ Your output will be passed into a structured data pipeline. Return only the filled-out section definitions as described above.
147
+ """),
148
+ HumanMessage(content="""Use the given table structure of the roadmap and decide all the sections of
149
+ the report along with what should be in it and the clearly mention all the data thats required for it
150
+ from the roadmap table"""),
151
+ ]
152
+ )
153
+
154
+ return {"sections": report_sections.sections}
155
+
156
+ def processor(state: ProcessorState):
157
+ """Combined helper and worker - gets data and writes section in one step"""
158
+
159
+ section = state['section']
160
+
161
+ # HELPER PART: Get data for this section
162
+ sql_query = generate_sql_for_report(llm, section.data_requirements)
163
+ rows = get_sql_data_for_report(sql_query)
164
+
165
+ # WORKER PART: Write the section using the data
166
+ section_result = llm.invoke(
167
+ [
168
+ SystemMessage(
169
+ content=f"""Create a concise, data-driven JEE preparation report section that provides actionable insights for students,
170
+ parents, and mentors.
171
+ Requirements:
172
+ 1. Begin directly with key metrics and insights - no introductory preamble
173
+ 2. Use specific numbers, percentages, and ratios to quantify performance
174
+ 3. Include concise tables or bullet points for clarity where appropriate
175
+ 4. Highlight patterns related to:
176
+ - Task completion rates
177
+ - Time allocation efficiency
178
+ - Subject/topic focus distribution
179
+ - Study consistency patterns
180
+ 5. For each observation, provide a brief actionable recommendation focused on student improvement.
181
+ 6. Use professional but motivational tone appropriate for academic context
182
+ 7. Strictly use Markdown for formatting all the tables and the numbers
183
+ 8. Strictly keep each section very focused and write it under 0 to 50 words
184
+ 9. Verify the formatting of all the tables multiple times to ensure the markdown is correct.
185
+ 10. Check all the numbers and calculations made by you multiple times to ensure accuracy
186
+ Base all analysis strictly on the provided data - avoid assumptions beyond what's explicitly given to you.
187
+ Don't assume anything else, even a little bit.
188
+ *Important*
189
+ If you receive an empty data input, understand that the student hasn't done tasks matching the given data description. Also,
190
+ know that this report is for the student to improve themselves, and they have no part in making sure the data is logged for
191
+ this analysis. Deeply analyze the SQL query ->{sql_query} and the data description ->{section.data_requirements} used to
192
+ extract the data and figure out why there was no data available in the roadmap, which the student went through and write
193
+ the section accordingly.
194
+ """
195
+ ),
196
+ HumanMessage(
197
+ content=f"""Here is the section name: {section.name} and description: {section.description}
198
+ Data for writing this section: {rows}"""
199
+ ),
200
+ ]
201
+ )
202
+
203
+ # Return completed section
204
+ return {"completed_sections": [section_result.content]}
205
+
206
+ def synthesizer(state: State):
207
+ """Synthesize full report from sections"""
208
+
209
+ # List of completed sections
210
+ completed_sections = state["completed_sections"]
211
+
212
+ # Format completed section to str to use as context for final sections
213
+ completed_report_sections = "\n\n---\n\n".join(completed_sections)
214
+
215
+ return {"final_report": completed_report_sections}
216
+
217
+ # Assign processors function
218
+ def assign_processors(state: State):
219
+ """Assign a processor to each section in the plan"""
220
+ return [Send("processor", {"section": s}) for s in state["sections"]]
221
+
222
+ def generate_sql_for_report(llm, prompt):
223
+ table_struct = """
224
+ CREATE TABLE IF NOT EXISTS roadmap (
225
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
226
+ day_num INTEGER,
227
+ date TEXT,
228
+ subject TEXT,
229
+ chapter_name TEXT,
230
+ task_type TEXT,
231
+ time TEXT,
232
+ subtopic TEXT,
233
+ task_completed BOOLEAN,
234
+ completion_timestamp TEXT
235
+ )
236
+ """
237
+
238
+ response = llm.invoke(
239
+ [
240
+ SystemMessage(content=f"""You are a helper who runs in the background of an AI agent,
241
+ which helps students for their JEE Preparation. Now your job is to analyze the user's prompt and
242
+ create an SQL query to extract the related Information from an sqlite3 database with the table
243
+ structure: {table_struct}.
244
+ Note: For the time column, the data is formatted like '0.5 hour', '1 hour', '2 hours' and
245
+ so on, it tells the amount of time required to complete that specific task. So make sure
246
+ to create queries that compare just the numbers within the text. For the task_type column,
247
+ the data is either of these (Concept Understanding, Question Practice, Revision or Test)
248
+ You will also make sure multiple times that you give an SQL
249
+ Query that adheres to the given table structure, and you output just the SQL query.
250
+ Do not include anything else like new line statements, ```sql or any other text. Your output
251
+ is going to be directly fed into a Python script to extract the required information. So,
252
+ please follow all the given instructions.
253
+ Verify multiple times that the SQL query is error free for the SQLite3 format."""),
254
+ HumanMessage(content=f"""Keeping the table structure in mind: {table_struct},
255
+ Convert this prompt to an SQL query for the given table: {prompt}. Make sure your
256
+ output is just the SQL query, which can directly be used to extract required content.""")
257
+ ]
258
+ )
259
+ return response.content.strip()
260
+
261
+ def get_sql_data_for_report(sql_query):
262
+ conn = sqlite3.connect("jee_full_roadmap.db")
263
+ cursor = conn.cursor()
264
+
265
+ results = []
266
+ queries = [q.strip() for q in sql_query.strip().split(';') if q.strip()]
267
+
268
+ for query in queries:
269
+ cursor.execute(query)
270
+ columns = [desc[0] for desc in cursor.description]
271
+ rows = cursor.fetchall()
272
+ results.append({
273
+ "query": query,
274
+ "columns": columns,
275
+ "rows": rows
276
+ })
277
+ conn.close()
278
+
279
+ return results
280
+
281
+ def create_db_for_report(roadmap_data):
282
+ try:
283
+ conn = sqlite3.connect("jee_full_roadmap.db")
284
+ cursor = conn.cursor()
285
+
286
+ cursor.execute("DROP TABLE IF EXISTS roadmap")
287
+ cursor.execute("""
288
+ CREATE TABLE roadmap (
289
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
290
+ day_num INTEGER,
291
+ date TEXT,
292
+ subject TEXT,
293
+ chapter_name TEXT,
294
+ task_type TEXT,
295
+ time TEXT,
296
+ subtopic TEXT,
297
+ task_completed BOOLEAN,
298
+ completion_timestamp TEXT
299
+ )
300
+ """)
301
+
302
+ for day in roadmap_data["schedule"]:
303
+ date = day["date"]
304
+ day_num = day["dayNumber"]
305
+ for subj in day["subjects"]:
306
+ subject = subj["name"]
307
+ for task in subj["tasks"]:
308
+ cursor.execute("""
309
+ INSERT INTO roadmap (day_num, date, subject, chapter_name, task_type, time, subtopic, task_completed, completion_timestamp)
310
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
311
+ """, (
312
+ day_num,
313
+ date,
314
+ subject,
315
+ task["ChapterName"],
316
+ task["type"],
317
+ task["time"],
318
+ task["subtopic"],
319
+ task["task_completed"],
320
+ task["completion_timestamp"]
321
+ ))
322
+ conn.commit()
323
+ conn.close()
324
+ print("✅ Database created and data inserted successfully.")
325
+ except Exception as e:
326
+ print(f"⚠️ Error initializing database: {e}")
327
+
328
+ def generate_report(roadmap_data):
329
+ # Build workflow
330
+ workflow_builder = StateGraph(State)
331
+
332
+ # Add the nodes
333
+ workflow_builder.add_node("orchestrator", orchestrator)
334
+ workflow_builder.add_node("processor", processor)
335
+ workflow_builder.add_node("synthesizer", synthesizer)
336
+
337
+ # Add edges to connect nodes
338
+ workflow_builder.add_edge(START, "orchestrator")
339
+ workflow_builder.add_conditional_edges("orchestrator", assign_processors, ["processor"])
340
+ workflow_builder.add_edge("processor", "synthesizer")
341
+ workflow_builder.add_edge("synthesizer", END)
342
+
343
+ # Compile the workflow
344
+ workflow = workflow_builder.compile()
345
+
346
+ # Initialize database
347
+ create_db_for_report(roadmap_data)
348
+
349
+ # Invoke
350
+ state = workflow.invoke({})
351
+
352
+ session_state['final_report'] = state["final_report"]
353
+
354
+ return state["final_report"]
355
+
356
+ # AGENT 3
357
+ def get_chapters_and_subtopics(roadmap_data):
358
+ ch_subt = {
359
+ "Physics": {},
360
+ "Chemistry": {},
361
+ "Maths": {}
362
+ }
363
+
364
+ for day in roadmap_data["schedule"]:
365
+ for subject in day['subjects']:
366
+ sub = ch_subt[subject['name']]
367
+ for task in subject['tasks']:
368
+ sub[task['ChapterName']] = []
369
+
370
+ for day in roadmap_data["schedule"]:
371
+ for subject in day['subjects']:
372
+ sub = ch_subt[subject['name']]
373
+ for task in subject['tasks']:
374
+ if task['subtopic'] not in sub[task['ChapterName']]:
375
+ sub[task['ChapterName']].append(task['subtopic'])
376
+
377
+ return ch_subt
378
+
379
+ def create_roadmap_db(roadmap_data):
380
+ try:
381
+ conn = sqlite3.connect("jee_roadmap.db")
382
+ cursor = conn.cursor()
383
+
384
+ cursor.execute("DROP TABLE IF EXISTS roadmap")
385
+ cursor.execute("""
386
+ CREATE TABLE IF NOT EXISTS roadmap (
387
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
388
+ day_num INTEGER,
389
+ date TEXT,
390
+ subject TEXT,
391
+ chapter_name TEXT,
392
+ task_type TEXT,
393
+ time TEXT,
394
+ subtopic TEXT
395
+ )
396
+ """)
397
+
398
+ for day in roadmap_data["schedule"]:
399
+ date = day["date"]
400
+ day_num = day["dayNumber"]
401
+ for subj in day["subjects"]:
402
+ subject = subj["name"]
403
+ for task in subj["tasks"]:
404
+ cursor.execute("""
405
+ INSERT INTO roadmap (day_num, date, subject, chapter_name, task_type, time, subtopic)
406
+ VALUES (?, ?, ?, ?, ?, ?, ?)
407
+ """, (
408
+ day_num,
409
+ date,
410
+ subject,
411
+ task["ChapterName"],
412
+ task["type"],
413
+ task["time"],
414
+ task["subtopic"]
415
+ ))
416
+
417
+ conn.commit()
418
+ conn.close()
419
+ print("✅ Database created and data inserted successfully.")
420
+ return True
421
+ except Exception as e:
422
+ print(f"⚠️ Error initializing database: {e}")
423
+ return False
424
+
425
+ # Function to convert NL query to SQL
426
+ def generate_sql_from_nl(prompt, ch_subt):
427
+ table_struct = """CREATE TABLE IF NOT EXISTS roadmap (
428
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
429
+ day_num INTEGER,
430
+ date TEXT, -- [yyyy-mm-dd]
431
+ subject TEXT, -- [Physics, Chemistry or Maths]
432
+ chapter_name TEXT,
433
+ task_type TEXT, -- (Concept Understanding, Question Practice, Revision, Test)
434
+ time TEXT, -- formatted like '0.5 hour', '1 hour', '2 Hours', and so on
435
+ subtopic TEXT
436
+ )"""
437
+
438
+ response = llm.invoke(
439
+ [
440
+ SystemMessage(
441
+ content=f"""You are an helper who runs in the background of an AI agent,
442
+ which helps students for their JEE Preparation. Now your Job is to analyze the users prompt and
443
+ create an SQL query to extract the related Information from an sqlite3 database with the table
444
+ structure: {table_struct}.
445
+ Note:
446
+ - For the time column, the data is formatted like '0.5 hour', '1 hour', '2 hours' and
447
+ so on. So make sure to create queries that compare just the numbers within the text.
448
+ - If the student mention about any chapters or subtopics, browse through this json file {ch_subt},
449
+ find the one with the closest match to the users query and use only those exact names of Chapers
450
+ and Subtopics present in this file to create SQL the query.
451
+ - For date related queries, refer today's date {datetime.now().date()}
452
+ - If the user ask's you general questions, Return a Dummy query like {"SELECT * FROM your_table WHERE FALSE;"}
453
+ You will also make sure multiple times that you give an SQL
454
+ Query that adheres to the given table structure, and you Output just the SQL query.
455
+ Do not include anyting else like new line statements, ```sql or any other text. Your output
456
+ is going to be directly fed into a Python script to extract the required information. So,
457
+ please follow all the given Instructions.
458
+ """
459
+ ),
460
+ HumanMessage(
461
+ content=f"""Keeping the table structure in mind: {table_struct},
462
+ Convert this prompt to an SQL query for the given table: {prompt}. Make sure your
463
+ output is just the SQL query, which can directly be used to extract required content"""
464
+ ),
465
+ ]
466
+ )
467
+
468
+ return response.content.strip()
469
+
470
+ # Function to fetch data from SQLite
471
+ def fetch_data_from_sql(sql_query):
472
+ conn = sqlite3.connect("jee_roadmap.db")
473
+ cursor = conn.cursor()
474
+ cursor.execute(sql_query)
475
+ columns = [desc[0] for desc in cursor.description]
476
+ rows = cursor.fetchall()
477
+ data = {
478
+ "query": sql_query,
479
+ "columns": columns,
480
+ "rows": rows
481
+ }
482
+ conn.close()
483
+ return data
484
+
485
+ # Function to convert SQL output to natural language
486
+ def generate_nl_from_sql_output(prompt, data):
487
+ response = llm.invoke(
488
+ [
489
+ SystemMessage(
490
+ content=f"""You are an helpful AI chatbot working under the roadmap
491
+ section of an AI Agent, whose role is to aid students in their preparation for the JEE examination.
492
+ You are going to play a very crucial role of a Roadmap Assistant, who helps the student out with whatever query
493
+ they have related to their roadmap, the data required to answer the users query is already extracted
494
+ from the Roadmap table of a SQLite3 database and given to you here {data}. Analyse the users query deeply and
495
+ reply to it with the relevant information from the given data in a supportive manner. If you get empty data
496
+ as an input, deeply analyze the user's prompt and the sql query and give a suitable reply. If you find the
497
+ user's prompt to be conversational in nature, please respond accordingly."""
498
+ ),
499
+ HumanMessage(
500
+ content=f"""Answer to this users query using the data given to you, while keeping
501
+ your role in mind: {prompt}"""
502
+ ),
503
+ ]
504
+ )
505
+
506
+ return response.content.strip()
507
+
508
+ # Main function for chatbot
509
+ def answer_user_query(prompt, roadmap_data):
510
+ ch_subt = get_chapters_and_subtopics(roadmap_data)
511
+ query = generate_sql_from_nl(prompt, ch_subt)
512
+ data = fetch_data_from_sql(query)
513
+ return generate_nl_from_sql_output(prompt, data)
514
+
515
+
516
+ @app.get("/", response_class=HTMLResponse)
517
+ def root():
518
+ return """
519
+ <html>
520
+ <head><title>Sstudize Agents</title></head>
521
+ <body style="font-family: Arial, sans-serif; text-align: center; margin-top: 50px;">
522
+ <h1>Welcome to Sstudize Agents!</h1>
523
+ <p>Select an agent:</p>
524
+ <ul style="list-style-type: none;">
525
+ <li><a href="/docs#/default/agent1_agent1_post">Agent 1: Task Analysis</a></li>
526
+ <li><a href="/docs#/default/agent3_agent3_post">Agent 3: Chatbot Assistant</a></li>
527
+ </ul>
528
+ </body>
529
+ </html>
530
+ """
531
+
532
+
533
+ # --- AGENT 1: Task Analysis (Task Analysis Page) ---
534
+ @app.post("/agent1")
535
+ def agent1(roadmap_data: RoadmapData = Body(..., description="Complete roadmap data in JSON format")):
536
+ """
537
+ Agent 1 - Task Analysis: Builds a performance report based on provided roadmap data.
538
+ """
539
+ try:
540
+ # Store the roadmap data
541
+ session_state["report_data"] = roadmap_data.dict()
542
+
543
+ # Generate performance report
544
+ report = generate_report(session_state["report_data"])
545
+
546
+ return {
547
+ "status": "success",
548
+ "final_report": report
549
+ }
550
+ except Exception as e:
551
+ return {"status": "error", "message": str(e)}
552
+
553
+
554
+ # --- AGENT 3: Roadmap Chatbot (Roadmap Chatbot Page) ---
555
+ @app.post("/agent3")
556
+ def agent3(
557
+ query: str = Body(..., description="User's message to the chatbot"),
558
+ roadmap_data: RoadmapData = Body(..., description="Complete roadmap data in JSON format")
559
+ ):
560
+ """
561
+ Agent 3 - Roadmap Chatbot Assistant: Answers user questions about the roadmap in a chat-like style.
562
+ """
563
+ try:
564
+ # Create DB from provided roadmap data
565
+ db_created = create_roadmap_db(roadmap_data.dict())
566
+ if not db_created:
567
+ return {"status": "error", "message": "Failed to create database from roadmap data"}
568
+
569
+ # Generate response to user query
570
+ response = answer_user_query(query, roadmap_data.dict())
571
+
572
+ return {
573
+ "status": "success",
574
+ "chat_response": {
575
+ "user": query,
576
+ "assistant": response
577
+ }
578
+ }
579
+ except Exception as e:
580
+ return {
581
+ "status": "error",
582
+ "message": f"Error processing query: {str(e)}"
583
+ }