Rahul-8799 commited on
Commit
69f88d2
Β·
verified Β·
1 Parent(s): a97c801

Create utils/langgraph_pipeline.py

Browse files
Files changed (1) hide show
  1. utils/langgraph_pipeline.py +179 -0
utils/langgraph_pipeline.py ADDED
@@ -0,0 +1,179 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import uuid, zipfile, re
2
+ from pathlib import Path
3
+ from typing import TypedDict, List, Dict, Any, Tuple
4
+
5
+ from langgraph.graph import StateGraph, END
6
+ from langchain_core.messages import HumanMessage, AIMessage
7
+ from langchain_core.messages.base import BaseMessage
8
+
9
+ from agents import (
10
+ product_manager_agent,
11
+ project_manager_agent,
12
+ software_architect_agent,
13
+ software_engineer_agent,
14
+ quality_assurance_agent,
15
+ ui_designer_agent,
16
+ )
17
+
18
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
19
+ # 1) State definitions
20
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
21
+ class InputState(TypedDict):
22
+ messages: List[BaseMessage]
23
+ chat_log: List[Dict[str, Any]]
24
+
25
+ class OutputState(TypedDict):
26
+ pm_output: str
27
+ proj_output: str
28
+ arch_output: str
29
+ ui_design_output: str
30
+ dev_output: str
31
+ qa_output: str
32
+ chat_log: List[Dict[str, Any]]
33
+
34
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
35
+ # 2) Wrap agents so they see full history
36
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
37
+ def wrap_agent(agent_run, output_key: str):
38
+ def node(state: Dict[str, Any]) -> Dict[str, Any]:
39
+ history = state["messages"]
40
+ log = state["chat_log"]
41
+ result = agent_run({"messages": history, "chat_log": log})
42
+ return {
43
+ "messages": history + result["messages"],
44
+ "chat_log": result["chat_log"],
45
+ output_key: result[output_key],
46
+ }
47
+ return node
48
+
49
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
50
+ # 3) Bridge β†’ ProductManager
51
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
52
+ def bridge_to_pm(state: Dict[str, Any]) -> Dict[str, Any]:
53
+ history = state["messages"]
54
+ log = state["chat_log"]
55
+ if not history or not isinstance(history[-1], HumanMessage):
56
+ raise ValueError("bridge_to_pm expected a HumanMessage at history end")
57
+ prompt = history[-1].content
58
+ spec_prompt = (
59
+ f"# Stakeholder Prompt\n\n"
60
+ f"\"{prompt}\"\n\n"
61
+ "Generate a structured product specification including:\n"
62
+ "- Goals\n"
63
+ "- Key features\n"
64
+ "- User stories\n"
65
+ "- Success metrics\n"
66
+ )
67
+ return {
68
+ "messages": [AIMessage(content=spec_prompt)],
69
+ "chat_log": log + [{"role": "System", "content": spec_prompt}],
70
+ }
71
+
72
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
73
+ # 4) Build & compile the LangGraph
74
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
75
+ graph = StateGraph(input=InputState, output=OutputState)
76
+
77
+ graph.add_node("BridgePM", bridge_to_pm)
78
+ graph.add_node("ProductManager", wrap_agent(product_manager_agent.run, "pm_output"))
79
+ graph.add_node("ProjectManager", wrap_agent(project_manager_agent.run, "proj_output"))
80
+ graph.add_node("SoftwareArchitect",wrap_agent(software_architect_agent.run, "arch_output"))
81
+ graph.add_node("UIDesigner", wrap_agent(ui_designer_agent.run, "ui_design_output"))
82
+ graph.add_node("SoftwareEngineer", wrap_agent(software_engineer_agent.run, "dev_output"))
83
+ graph.add_node("QualityAssurance", wrap_agent(quality_assurance_agent.run, "qa_output"))
84
+
85
+ graph.set_entry_point("BridgePM")
86
+ graph.add_edge("BridgePM", "ProductManager")
87
+ graph.add_edge("ProductManager", "ProjectManager")
88
+ graph.add_edge("ProjectManager", "SoftwareArchitect")
89
+ graph.add_edge("SoftwareArchitect","UIDesigner")
90
+ graph.add_edge("UIDesigner", "SoftwareEngineer")
91
+ graph.add_edge("SoftwareEngineer", "QualityAssurance")
92
+ graph.add_edge("QualityAssurance", END)
93
+
94
+ compiled_graph = graph.compile()
95
+
96
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
97
+ # 5) Parse spec into sections
98
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
99
+ def parse_spec(spec: str) -> Dict[str, List[str]]:
100
+ sections: Dict[str, List[str]] = {}
101
+ for m in re.finditer(r"##\s*(.+?)\n((?:- .+\n?)+)", spec):
102
+ name = m.group(1).strip()
103
+ items = [line[2:].strip() for line in m.group(2).splitlines() if line.startswith("- ")]
104
+ sections[name] = items
105
+ return sections
106
+
107
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
108
+ # 6) Run pipeline, generate site, zip, return (chat_log, zip_path)
109
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
110
+ def run_pipeline_and_save(prompt: str) -> Tuple[List[Dict[str, Any]], str]:
111
+ # a) invoke agents
112
+ initial_state = {"messages": [HumanMessage(content=prompt)], "chat_log": []}
113
+ final_state = compiled_graph.invoke(initial_state)
114
+
115
+ chat_log = final_state["chat_log"]
116
+ qa_output = final_state["qa_output"]
117
+
118
+ # b) parse spec
119
+ spec = parse_spec(qa_output)
120
+ features = spec.get("Key features", [])
121
+ testimonials = spec.get("User stories", [])
122
+
123
+ # c) build HTML
124
+ title = prompt.title()
125
+ domain = prompt.replace(" ", "").lower() + ".com"
126
+ cards_html = "\n".join(f"<div class='card'><h3>{f}</h3></div>" for f in features)
127
+ test_html = "\n".join(f"<blockquote>{t}</blockquote>" for t in testimonials)
128
+
129
+ html_code = f"""<!DOCTYPE html>
130
+ <html lang="en">
131
+ <head>
132
+ <meta charset="UTF-8">
133
+ <meta name="viewport" content="width=device-width,initial-scale=1">
134
+ <title>{title}</title>
135
+ <link rel="stylesheet" href="styles.css">
136
+ </head>
137
+ <body>
138
+ <header><h1>{title}</h1></header>
139
+ <section id="features">
140
+ <h2>Features</h2>
141
+ <div class="cards">
142
+ {cards_html}
143
+ </div>
144
+ </section>
145
+ <section id="testimonials">
146
+ <h2>Testimonials</h2>
147
+ {test_html or '<p>No testimonials provided.</p>'}
148
+ </section>
149
+ <section id="contact">
150
+ <h2>Contact Us</h2>
151
+ <p>Email: info@{domain}</p>
152
+ </section>
153
+ </body>
154
+ </html>"""
155
+
156
+ # d) basic CSS
157
+ css_code = """
158
+ body { font-family: Arial, sans-serif; margin: 1em; line-height: 1.5; }
159
+ header { text-align: center; margin-bottom: 2em; }
160
+ .cards { display: grid; grid-template-columns: repeat(auto-fit,minmax(150px,1fr)); gap: 1em; }
161
+ .card { background: #f9f9f9; padding: 1em; border-radius: 8px; box-shadow: 0 2px 5px rgba(0,0,0,0.1); text-align: center; }
162
+ blockquote { font-style: italic; margin: 1em; padding: 0.5em; background: #eef; border-left: 4px solid #99f; }
163
+ """
164
+
165
+ # e) write & zip
166
+ site_id = uuid.uuid4().hex
167
+ out_dir = Path("output")
168
+ site_dir = out_dir / f"site_{site_id}"
169
+ site_dir.mkdir(parents=True, exist_ok=True)
170
+
171
+ (site_dir / "index.html").write_text(html_code, encoding="utf-8")
172
+ (site_dir / "styles.css").write_text(css_code, encoding="utf-8")
173
+
174
+ zip_path = out_dir / f"site_{site_id}.zip"
175
+ with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zf:
176
+ for f in site_dir.iterdir():
177
+ zf.write(f, arcname=f.name)
178
+
179
+ return chat_log, str(zip_path)