jasybeaar commited on
Commit
001934a
Β·
1 Parent(s): f6a499f

Update backend.py

Browse files
Files changed (1) hide show
  1. backend.py +58 -117
backend.py CHANGED
@@ -1,21 +1,15 @@
1
- ---
2
-
3
- ```python
4
- from fastapi import FastAPI, HTTPException, Depends, Response, status
5
  from fastapi.middleware.cors import CORSMiddleware
6
- from fastapi.responses import JSONResponse, HTMLResponse, FileResponse
7
  from pydantic import BaseModel
8
  from langchain_ollama import OllamaLLM
9
  from langchain.agents import AgentExecutor, create_react_agent
10
  from langchain.tools import tool
11
  from langchain import hub
12
  import time, uuid
13
- import pdfkit
14
- import os
15
 
16
  app = FastAPI()
17
 
18
- # Allow CORS
19
  app.add_middleware(
20
  CORSMiddleware,
21
  allow_origins=["*"],
@@ -23,38 +17,32 @@ app.add_middleware(
23
  allow_headers=["*"],
24
  )
25
 
26
- # Initialize LLM
27
  llm = OllamaLLM(model="qwen3", temperature=0.2)
28
 
29
  # ── Tools ──────────────────────────────────────────────────────────
30
 
31
  @tool
32
  def intake_incident(description: str) -> str:
33
- """Step 1: Intake and classify an AV incident. Extract vehicle ID, timestamp, location, and incident
34
- type."""
35
  return llm.invoke(
36
  f"You are an AV intake agent. Extract and classify this incident. "
37
- f"Return: vehicle_id, timestamp, location, incident_type, initial_severity (P1/P2/P3).\n\nIncident:
38
- {description}"
39
  )
40
 
41
  @tool
42
  def enrich_incident(intake_summary: str) -> str:
43
- """Step 2: Enrich the incident with AV domain knowledge. Identify affected subsystems (GNSS, LiDAR,
44
- perception, planning, control)."""
45
  return llm.invoke(
46
- f"You are an AV enrichment agent. Given this intake summary, identify which AV subsystems are
47
- affected "
48
  f"and what sensor or software failures may be involved.\n\nIntake: {intake_summary}"
49
  )
50
 
51
  @tool
52
  def analyze_root_cause(enriched_summary: str) -> str:
53
- """Step 3: Perform root cause analysis on an enriched AV incident summary. Flag compliance issues."""
54
  return llm.invoke(
55
  f"You are an AV root cause analysis agent. Analyze the enriched incident and identify "
56
- f"the most probable root causes ranked by confidence. Reference ISO 26262, SAE J3016, or NHTSA AV
57
- Policy where relevant.\n\nEnriched summary: {enriched_summary}"
58
  )
59
 
60
  @tool
@@ -62,22 +50,18 @@ def generate_response_plan(root_cause_analysis: str) -> str:
62
  """Step 4: Generate a recommended response and remediation plan based on root cause analysis."""
63
  return llm.invoke(
64
  f"You are an AV safety response agent. Based on this root cause analysis, generate: "
65
- f"(1) immediate response actions, (2) short-term fixes, (3) long-term prevention
66
- measures.\n\nAnalysis: {root_cause_analysis}"
67
  )
68
 
69
  @tool
70
  def write_incident_report(full_analysis: str) -> str:
71
- """Writes a formal AV incident report in HTML format with Qwen personality."""
72
  return llm.invoke(
73
  f"You are Qwen, the AutoPulse Bot. Start your report EXACTLY with this greeting:\n"
74
- f"'Hi, I'm Qwen the AutoPulse Bot. I am now looking through your submissions on issues and I will
75
- diagnose.'\n\n"
76
- f"Then write a formal incident report in HTML with sections: "
77
- f"Executive Summary, Timeline, Affected Subsystems, Root Causes, Compliance Flags, Response Plan,
78
- Recommendations.\n\n"
79
- f"At the very end, add a section called '## Qwen's Personal Recommendation' where you give your own
80
- "
81
  f"expert suggestion based on your knowledge of AV systems, drawing from your own reasoning β€” "
82
  f"not just repeating the analysis above. Be specific, technical, and insightful.\n\n"
83
  f"Analysis to report on: {full_analysis}"
@@ -85,12 +69,10 @@ Recommendations.\n\n"
85
 
86
  @tool
87
  def analyze_branch_diff(diff_and_failure: str) -> str:
88
- """Analyzes a git diff and failure description to rank root cause suspects by file, line, and
89
- confidence."""
90
  return llm.invoke(
91
  f"You are a code forensics agent. Analyze this git diff and failure description. "
92
- f"Rank root cause suspects by file path, line range, mechanism, and confidence
93
- (high/medium/low).\n\n{diff_and_failure}"
94
  )
95
 
96
  @tool
@@ -98,11 +80,10 @@ def forensic_url_analysis(url_or_content: str) -> str:
98
  """Performs forensic analysis on a URL or file content for security and safety issues."""
99
  return llm.invoke(
100
  f"You are a forensic analysis agent. Analyze this content for suspicious patterns, "
101
- f"security vulnerabilities, or safety issues. Flag anomalies with severity.\n\nContent:
102
- {url_or_content}"
103
  )
104
 
105
- # ── Agent Setup ────────────────────────────────────────────────────
106
 
107
  tools = [
108
  intake_incident,
@@ -124,7 +105,7 @@ agent_executor = AgentExecutor(
124
  max_iterations=8,
125
  )
126
 
127
- # ── Request Models ─────────────────────────────────────────────────
128
 
129
  class Query(BaseModel):
130
  input: str
@@ -148,49 +129,37 @@ def health():
148
  @app.post("/triage")
149
  def triage(query: Query):
150
  """Full 5-step agentic triage pipeline."""
151
- try:
152
- result = agent_executor.invoke({
153
- "input": (
154
- f"Run the full AV incident triage pipeline for this incident: {query.input}\n\n"
155
- f"Steps: (1) intake_incident, (2) enrich_incident, (3) analyze_root_cause, "
156
- f"(4) generate_response_plan, (5) write_incident_report. "
157
- f"Pass the output of each step into the next."
158
- )
159
- })
160
- return HTMLResponse(result["output"])
161
- except Exception as e:
162
- raise HTTPException(status_code=500, detail=str(e))
163
 
164
  @app.post("/branch-debug")
165
  def branch_debug(query: Query):
166
  """Agentic branch diff root cause analysis."""
167
- try:
168
- result = agent_executor.invoke({
169
- "input": f"Use analyze_branch_diff to find root causes in this diff and failure: {query.input}"
170
- })
171
- return HTMLResponse(result["output"])
172
- except Exception as e:
173
- raise HTTPException(status_code=500, detail=str(e))
174
 
175
  @app.post("/forensic")
176
  def forensic(query: Query):
177
  """Agentic forensic analysis."""
178
- try:
179
- result = agent_executor.invoke({
180
- "input": f"Use forensic_url_analysis to analyze this content for issues: {query.input}"
181
- })
182
- return HTMLResponse(result["output"])
183
- except Exception as e:
184
- raise HTTPException(status_code=500, detail=str(e))
185
 
186
  @app.post("/analyze")
187
  def analyze(query: Query):
188
  """General agentic analysis endpoint."""
189
- try:
190
- result = agent_executor.invoke({"input": query.input})
191
- return HTMLResponse(result["output"])
192
- except Exception as e:
193
- raise HTTPException(status_code=500, detail=str(e))
194
 
195
  @app.post("/v1/chat/completions")
196
  def chat_completions(req: ChatRequest):
@@ -198,51 +167,23 @@ def chat_completions(req: ChatRequest):
198
  user_messages = [m.content for m in req.messages if m.role == "user"]
199
  user_input = user_messages[-1] if user_messages else ""
200
 
201
- try:
202
- result = agent_executor.invoke({
203
- "input": (
204
- f"Run the full AV incident triage pipeline: "
205
- f"(1) intake_incident, (2) enrich_incident, (3) analyze_root_cause, "
206
- f"(4) generate_response_plan, (5) write_incident_report. "
207
- f"Input: {user_input}"
208
- )
209
- })
210
- return JSONResponse({
211
- "id": f"chatcmpl-{uuid.uuid4().hex}",
212
- "object": "chat.completion",
213
- "created": int(time.time()),
214
- "model": req.model,
215
- "choices": [{
216
- "index": 0,
217
- "message": {"role": "assistant", "content": result["output"]},
218
- "finish_reason": "stop"
219
- }]
220
- })
221
- except Exception as e:
222
- raise HTTPException(status_code=500, detail=str(e))
223
-
224
- @app.get("/download/{report_id}")
225
- def download_report(report_id: str):
226
- """Download report as PDF."""
227
- # For simplicity, assume report is stored in a cache or DB
228
- html_content = get_report(report_id) # Replace with actual logic
229
- pdf = pdfkit.from_string(html_content, output_path="report.pdf")
230
- return FileResponse("report.pdf", filename=f"report_{report_id}.pdf")
231
-
232
- def get_report(report_id: str):
233
- """Mock function to fetch report content (replace with real DB/cache logic)."""
234
- return "## Incident Report\n\n### Executive Summary\n\nThis is a sample report."
235
-
236
- # ── Optional: Dashboard Endpoint ──
237
- @app.get("/reports")
238
- def list_reports():
239
- """List all reports (mock implementation)."""
240
- return {"reports": ["report_123", "report_456"]}
241
-
242
- # ── Run the app ──
243
- if __name__ == "__main__":
244
- import uvicorn
245
- uvicorn.run(app, host="0.0.0.0", port=8000)
246
- ```
247
-
248
- ---
 
1
+ from fastapi import FastAPI
 
 
 
2
  from fastapi.middleware.cors import CORSMiddleware
3
+ from fastapi.responses import JSONResponse
4
  from pydantic import BaseModel
5
  from langchain_ollama import OllamaLLM
6
  from langchain.agents import AgentExecutor, create_react_agent
7
  from langchain.tools import tool
8
  from langchain import hub
9
  import time, uuid
 
 
10
 
11
  app = FastAPI()
12
 
 
13
  app.add_middleware(
14
  CORSMiddleware,
15
  allow_origins=["*"],
 
17
  allow_headers=["*"],
18
  )
19
 
 
20
  llm = OllamaLLM(model="qwen3", temperature=0.2)
21
 
22
  # ── Tools ──────────────────────────────────────────────────────────
23
 
24
  @tool
25
  def intake_incident(description: str) -> str:
26
+ """Step 1: Intake and classify an AV incident. Extract vehicle ID, timestamp, location, and incident type."""
 
27
  return llm.invoke(
28
  f"You are an AV intake agent. Extract and classify this incident. "
29
+ f"Return: vehicle_id, timestamp, location, incident_type, initial_severity (P1/P2/P3).\n\nIncident: {description}"
 
30
  )
31
 
32
  @tool
33
  def enrich_incident(intake_summary: str) -> str:
34
+ """Step 2: Enrich the incident with AV domain knowledge. Identify affected subsystems (GNSS, LiDAR, perception, planning, control)."""
 
35
  return llm.invoke(
36
+ f"You are an AV enrichment agent. Given this intake summary, identify which AV subsystems are affected "
 
37
  f"and what sensor or software failures may be involved.\n\nIntake: {intake_summary}"
38
  )
39
 
40
  @tool
41
  def analyze_root_cause(enriched_summary: str) -> str:
42
+ """Step 3: Perform root cause analysis on an enriched AV incident summary."""
43
  return llm.invoke(
44
  f"You are an AV root cause analysis agent. Analyze the enriched incident and identify "
45
+ f"the most probable root causes ranked by confidence. Reference ISO 26262, SAE J3016, or NHTSA AV Policy where relevant.\n\nEnriched summary: {enriched_summary}"
 
46
  )
47
 
48
  @tool
 
50
  """Step 4: Generate a recommended response and remediation plan based on root cause analysis."""
51
  return llm.invoke(
52
  f"You are an AV safety response agent. Based on this root cause analysis, generate: "
53
+ f"(1) immediate response actions, (2) short-term fixes, (3) long-term prevention measures.\n\nAnalysis: {root_cause_analysis}"
 
54
  )
55
 
56
  @tool
57
  def write_incident_report(full_analysis: str) -> str:
58
+ """Writes a formal AV incident report in Markdown format with Qwen personality."""
59
  return llm.invoke(
60
  f"You are Qwen, the AutoPulse Bot. Start your report EXACTLY with this greeting:\n"
61
+ f"'Hi, I'm Qwen the AutoPulse Bot. I am now looking through your submissions on issues and I will diagnose.'\n\n"
62
+ f"Then write a formal incident report in Markdown with sections: "
63
+ f"Executive Summary, Timeline, Affected Subsystems, Root Causes, Compliance Flags, Response Plan, Recommendations.\n\n"
64
+ f"At the very end, add a section called '## Qwen's Personal Recommendation' where you give your own "
 
 
 
65
  f"expert suggestion based on your knowledge of AV systems, drawing from your own reasoning β€” "
66
  f"not just repeating the analysis above. Be specific, technical, and insightful.\n\n"
67
  f"Analysis to report on: {full_analysis}"
 
69
 
70
  @tool
71
  def analyze_branch_diff(diff_and_failure: str) -> str:
72
+ """Analyzes a git diff and failure description to rank root cause suspects by file, line, and confidence."""
 
73
  return llm.invoke(
74
  f"You are a code forensics agent. Analyze this git diff and failure description. "
75
+ f"Rank root cause suspects by file path, line range, mechanism, and confidence (high/medium/low).\n\n{diff_and_failure}"
 
76
  )
77
 
78
  @tool
 
80
  """Performs forensic analysis on a URL or file content for security and safety issues."""
81
  return llm.invoke(
82
  f"You are a forensic analysis agent. Analyze this content for suspicious patterns, "
83
+ f"security vulnerabilities, or safety issues. Flag anomalies with severity.\n\nContent: {url_or_content}"
 
84
  )
85
 
86
+ # ── Agent setup ────────────────────────────────────────────────────
87
 
88
  tools = [
89
  intake_incident,
 
105
  max_iterations=8,
106
  )
107
 
108
+ # ── Request models ─────────────────────────────────────────────────
109
 
110
  class Query(BaseModel):
111
  input: str
 
129
  @app.post("/triage")
130
  def triage(query: Query):
131
  """Full 5-step agentic triage pipeline."""
132
+ result = agent_executor.invoke({
133
+ "input": (
134
+ f"Run the full AV incident triage pipeline for this incident: {query.input}\n\n"
135
+ f"Steps: (1) intake_incident, (2) enrich_incident, (3) analyze_root_cause, "
136
+ f"(4) generate_response_plan, (5) write_incident_report. "
137
+ f"Pass the output of each step into the next."
138
+ )
139
+ })
140
+ return {"output": result["output"]}
 
 
 
141
 
142
  @app.post("/branch-debug")
143
  def branch_debug(query: Query):
144
  """Agentic branch diff root cause analysis."""
145
+ result = agent_executor.invoke({
146
+ "input": f"Use analyze_branch_diff to find root causes in this diff and failure: {query.input}"
147
+ })
148
+ return {"output": result["output"]}
 
 
 
149
 
150
  @app.post("/forensic")
151
  def forensic(query: Query):
152
  """Agentic forensic analysis."""
153
+ result = agent_executor.invoke({
154
+ "input": f"Use forensic_url_analysis to analyze this content for issues: {query.input}"
155
+ })
156
+ return {"output": result["output"]}
 
 
 
157
 
158
  @app.post("/analyze")
159
  def analyze(query: Query):
160
  """General agentic analysis endpoint."""
161
+ result = agent_executor.invoke({"input": query.input})
162
+ return {"output": result["output"]}
 
 
 
163
 
164
  @app.post("/v1/chat/completions")
165
  def chat_completions(req: ChatRequest):
 
167
  user_messages = [m.content for m in req.messages if m.role == "user"]
168
  user_input = user_messages[-1] if user_messages else ""
169
 
170
+ result = agent_executor.invoke({
171
+ "input": (
172
+ f"Run the full AV incident triage pipeline: "
173
+ f"(1) intake_incident, (2) enrich_incident, (3) analyze_root_cause, "
174
+ f"(4) generate_response_plan, (5) write_incident_report. "
175
+ f"Input: {user_input}"
176
+ )
177
+ })
178
+
179
+ return JSONResponse({
180
+ "id": f"chatcmpl-{uuid.uuid4().hex}",
181
+ "object": "chat.completion",
182
+ "created": int(time.time()),
183
+ "model": req.model,
184
+ "choices": [{
185
+ "index": 0,
186
+ "message": {"role": "assistant", "content": result["output"]},
187
+ "finish_reason": "stop"
188
+ }]
189
+ })