jasybeaar commited on
Commit
ef6d9bf
Β·
1 Parent(s): a8e4ef1

Update backend.py

Browse files
Files changed (1) hide show
  1. backend.py +82 -110
backend.py CHANGED
@@ -3,9 +3,8 @@ 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()
@@ -19,92 +18,90 @@ app.add_middleware(
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
49
- def generate_response_plan(root_cause_analysis: str) -> str:
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}"
68
  )
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
79
- def forensic_url_analysis(url_or_content: str) -> str:
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,
90
- enrich_incident,
91
- analyze_root_cause,
92
- generate_response_plan,
93
- write_incident_report,
94
- analyze_branch_diff,
95
- forensic_url_analysis,
96
- ]
97
-
98
- prompt = hub.pull("hwchase17/react")
99
- agent = create_react_agent(llm, tools, prompt)
100
- agent_executor = AgentExecutor(
101
- agent=agent,
102
- tools=tools,
103
- verbose=True,
104
- handle_parsing_errors=True,
105
- max_iterations=8,
106
- )
107
-
108
  # ── Request models ─────────────────────────────────────────────────
109
 
110
  class Query(BaseModel):
@@ -124,66 +121,41 @@ class ChatRequest(BaseModel):
124
 
125
  @app.get("/health")
126
  def health():
127
- return {"status": "ok", "model": "qwen3", "agent": "multi-step"}
128
 
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):
166
- """OpenAI-compatible endpoint β€” routes through full agent pipeline."""
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
  })
 
3
  from fastapi.responses import JSONResponse
4
  from pydantic import BaseModel
5
  from langchain_ollama import OllamaLLM
6
+ from langchain.prompts import PromptTemplate
7
+ from langchain.chains import LLMChain
 
8
  import time, uuid
9
 
10
  app = FastAPI()
 
18
 
19
  llm = OllamaLLM(model="qwen3", temperature=0.2)
20
 
21
+ QWEN_PERSONA = (
22
+ "You are Qwen, the AutoPulse Bot β€” an expert AI safety analyst for autonomous vehicle fleets, "
23
+ "powered by Qwen3 running on AMD Instinct GPU."
24
+ )
25
+
26
+ def run_chain(system: str, input_text: str) -> str:
27
+ prompt = PromptTemplate.from_template("{system}\n\n{input}")
28
+ chain = LLMChain(llm=llm, prompt=prompt)
29
+ return chain.invoke({"system": system, "input": input_text})["text"]
30
 
31
+ def step1_intake(description: str) -> str:
32
+ return run_chain(
33
+ f"{QWEN_PERSONA} You are the Intake Agent. Extract and classify this AV incident. "
34
+ f"Return: vehicle_id, timestamp, location, incident_type, initial_severity (P1/P2/P3).",
35
+ f"Incident: {description}"
 
36
  )
37
 
38
+ def step2_enrich(intake: str) -> str:
39
+ return run_chain(
40
+ f"{QWEN_PERSONA} You are the Enrichment Agent. Identify which AV subsystems are affected "
41
+ f"(GNSS, LiDAR, perception, planning, control) and what sensor or software failures may be involved.",
42
+ f"Intake summary: {intake}"
 
43
  )
44
 
45
+ def step3_root_cause(enriched: str) -> str:
46
+ return run_chain(
47
+ f"{QWEN_PERSONA} You are the Risk Agent. Identify the most probable root causes ranked by confidence. "
48
+ f"Reference ISO 26262, SAE J3016, or NHTSA AV Policy where relevant.",
49
+ f"Enriched incident: {enriched}"
 
50
  )
51
 
52
+ def step4_response_plan(root_cause: str) -> str:
53
+ return run_chain(
54
+ f"{QWEN_PERSONA} You are the Safety Response Agent. Generate: "
55
+ f"(1) immediate response actions, (2) short-term fixes, (3) long-term prevention measures.",
56
+ f"Root cause analysis: {root_cause}"
 
57
  )
58
 
59
+ def step5_report(intake: str, enriched: str, root_cause: str, plan: str) -> str:
60
+ return run_chain(
61
+ f"{QWEN_PERSONA} You are the Documentation Agent. "
62
+ f"Start EXACTLY with: 'Hi, I'm Qwen the AutoPulse Bot. I am now looking through your submissions on issues and I will diagnose.'\n\n"
63
+ f"Write a formal incident report in Markdown with sections: "
 
 
64
  f"Executive Summary, Timeline, Affected Subsystems, Root Causes, Compliance Flags, Response Plan, Recommendations.\n\n"
65
+ f"End with '## Qwen's Personal Recommendation' β€” give your own expert insight based on your Qwen3 knowledge, "
66
+ f"be specific and technical.",
67
+ f"INTAKE:\n{intake}\n\nENRICHED:\n{enriched}\n\nROOT CAUSE:\n{root_cause}\n\nRESPONSE PLAN:\n{plan}"
 
68
  )
69
 
70
+ def full_triage_pipeline(incident: str) -> str:
71
+ print(f"\n[Qwen] Step 1: Intake...")
72
+ intake = step1_intake(incident)
73
+ print(f"[Qwen] Step 2: Enrichment...")
74
+ enriched = step2_enrich(intake)
75
+ print(f"[Qwen] Step 3: Root Cause Analysis...")
76
+ root_cause = step3_root_cause(enriched)
77
+ print(f"[Qwen] Step 4: Response Plan...")
78
+ plan = step4_response_plan(root_cause)
79
+ print(f"[Qwen] Step 5: Writing Report...")
80
+ report = step5_report(intake, enriched, root_cause, plan)
81
+ print(f"[Qwen] Pipeline complete.")
82
+ return report
83
+
84
+ def branch_debug_pipeline(diff_input: str) -> str:
85
+ print(f"\n[Qwen] Running Branch Debug...")
86
+ return run_chain(
87
+ f"{QWEN_PERSONA} You are the Code Forensics Agent. "
88
+ f"Start with: 'Hi, I'm Qwen the AutoPulse Bot. Analyzing your branch diff now.'\n\n"
89
+ f"Analyze this git diff and failure description. Rank root cause suspects by file path, "
90
+ f"line range, mechanism, and confidence (high/medium/low). "
91
+ f"End with '## Qwen's Personal Recommendation'.",
92
+ diff_input
93
  )
94
 
95
+ def forensic_pipeline(content: str) -> str:
96
+ print(f"\n[Qwen] Running Forensic Analysis...")
97
+ return run_chain(
98
+ f"{QWEN_PERSONA} You are the Forensic Analysis Agent. "
99
+ f"Start with: 'Hi, I'm Qwen the AutoPulse Bot. Running forensic analysis now.'\n\n"
100
+ f"Analyze this content for suspicious patterns, security vulnerabilities, or safety issues. "
101
+ f"Flag anomalies with severity. End with '## Qwen's Personal Recommendation'.",
102
+ content
103
  )
104
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
  # ── Request models ─────────────────────────────────────────────────
106
 
107
  class Query(BaseModel):
 
121
 
122
  @app.get("/health")
123
  def health():
124
+ return {"status": "ok", "model": "qwen3", "agent": "Qwen the AutoPulse Bot", "gpu": "AMD Instinct"}
125
 
126
  @app.post("/triage")
127
  def triage(query: Query):
128
+ result = full_triage_pipeline(query.input)
129
+ return {"output": result}
 
 
 
 
 
 
 
 
130
 
131
  @app.post("/branch-debug")
132
  def branch_debug(query: Query):
133
+ result = branch_debug_pipeline(query.input)
134
+ return {"output": result}
 
 
 
135
 
136
  @app.post("/forensic")
137
  def forensic(query: Query):
138
+ result = forensic_pipeline(query.input)
139
+ return {"output": result}
 
 
 
140
 
141
  @app.post("/analyze")
142
  def analyze(query: Query):
143
+ result = full_triage_pipeline(query.input)
144
+ return {"output": result}
 
145
 
146
  @app.post("/v1/chat/completions")
147
  def chat_completions(req: ChatRequest):
 
148
  user_messages = [m.content for m in req.messages if m.role == "user"]
149
  user_input = user_messages[-1] if user_messages else ""
150
+ result = full_triage_pipeline(user_input)
 
 
 
 
 
 
 
 
 
151
  return JSONResponse({
152
  "id": f"chatcmpl-{uuid.uuid4().hex}",
153
  "object": "chat.completion",
154
  "created": int(time.time()),
155
+ "model": "qwen3-autopulse-bot",
156
  "choices": [{
157
  "index": 0,
158
+ "message": {"role": "assistant", "content": result},
159
  "finish_reason": "stop"
160
  }]
161
  })