Simon Strandgaard
commited on
Commit
·
767b265
1
Parent(s):
f568402
Snapshot of PlanExe commit b29887f39d24be34e48668484d67a50342995f8a
Browse files- src/markdown_util/__init__.py +0 -0
- src/markdown_util/fix_bullet_lists.py +50 -0
- src/markdown_util/tests/__init__.py +0 -0
- src/markdown_util/tests/test_fix_bullet_lists.py +60 -0
- src/pitch/__init__.py +0 -0
- src/pitch/convert_pitch_to_markdown.py +174 -0
- src/{plan → pitch}/create_pitch.py +6 -5
- src/pitch/test_data/lunar_base-pitch.json +23 -0
- src/pitch/test_data/lunar_base-project_plan.json +114 -0
- src/pitch/test_data/lunar_base-wbs_level1.json +5 -0
- src/pitch/test_data/lunar_base-wbs_level2.json +184 -0
- src/plan/data/simple_plan_prompts.jsonl +1 -0
- src/plan/estimate_wbs_task_durations.py +1 -0
- src/plan/filenames.py +28 -25
- src/plan/run_plan_pipeline.py +87 -3
- src/report/README.md +79 -0
- src/report/__init__.py +0 -0
- src/{report_generator.py → report/report_generator.py} +79 -100
src/markdown_util/__init__.py
ADDED
File without changes
|
src/markdown_util/fix_bullet_lists.py
ADDED
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Often the markdown files have bullet lists that are not properly formatted.
|
3 |
+
There bullet list must have 2 newlines before the list starts and 2 newlines after the list ends.
|
4 |
+
This script fixes the bullet lists in the markdown files.
|
5 |
+
|
6 |
+
The following input lacks the required 2 newlines before the list starts:
|
7 |
+
```markdown
|
8 |
+
Lorem ipsum:
|
9 |
+
- Item A
|
10 |
+
- Item B
|
11 |
+
- Item C
|
12 |
+
```
|
13 |
+
|
14 |
+
The fixed output:
|
15 |
+
|
16 |
+
```markdown
|
17 |
+
Lorem ipsum:
|
18 |
+
|
19 |
+
- Item A
|
20 |
+
- Item B
|
21 |
+
- Item C
|
22 |
+
```
|
23 |
+
"""
|
24 |
+
|
25 |
+
def fix_bullet_lists(markdown_text: str) -> str:
|
26 |
+
"""
|
27 |
+
Fix the bullet lists in the markdown text that lacks the required 2 newlines before the list starts.
|
28 |
+
"""
|
29 |
+
lines = markdown_text.split('\n')
|
30 |
+
fixed_lines = []
|
31 |
+
in_list = False
|
32 |
+
|
33 |
+
for i, line in enumerate(lines):
|
34 |
+
if line.startswith('- '):
|
35 |
+
if not in_list:
|
36 |
+
if i > 0 and lines[i-1].strip() != '':
|
37 |
+
fixed_lines.append('')
|
38 |
+
in_list = True
|
39 |
+
fixed_lines.append(line)
|
40 |
+
else:
|
41 |
+
if in_list:
|
42 |
+
if line.strip() != '':
|
43 |
+
fixed_lines.append('')
|
44 |
+
in_list = False
|
45 |
+
fixed_lines.append(line)
|
46 |
+
|
47 |
+
if in_list:
|
48 |
+
fixed_lines.append('')
|
49 |
+
|
50 |
+
return '\n'.join(fixed_lines)
|
src/markdown_util/tests/__init__.py
ADDED
File without changes
|
src/markdown_util/tests/test_fix_bullet_lists.py
ADDED
@@ -0,0 +1,60 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import unittest
|
2 |
+
from src.markdown_util.fix_bullet_lists import fix_bullet_lists
|
3 |
+
|
4 |
+
class TestFixBulletLists(unittest.TestCase):
|
5 |
+
def test_fix_bullet_lists(self):
|
6 |
+
input_text = """Lorem ipsum:
|
7 |
+
- Item A
|
8 |
+
- Item B
|
9 |
+
- Item C"""
|
10 |
+
expected_output = """Lorem ipsum:
|
11 |
+
|
12 |
+
- Item A
|
13 |
+
- Item B
|
14 |
+
- Item C
|
15 |
+
"""
|
16 |
+
self.assertEqual(fix_bullet_lists(input_text), expected_output)
|
17 |
+
|
18 |
+
def test_no_bullet_list(self):
|
19 |
+
input_text = """Lorem ipsum:
|
20 |
+
Lorem ipsum dolor sit amet."""
|
21 |
+
expected_output = """Lorem ipsum:
|
22 |
+
Lorem ipsum dolor sit amet."""
|
23 |
+
self.assertEqual(fix_bullet_lists(input_text), expected_output)
|
24 |
+
|
25 |
+
def test_already_fixed(self):
|
26 |
+
input_text = """Lorem ipsum:
|
27 |
+
|
28 |
+
- Item A
|
29 |
+
- Item B
|
30 |
+
- Item C
|
31 |
+
|
32 |
+
Lorem ipsum dolor sit amet."""
|
33 |
+
expected_output = """Lorem ipsum:
|
34 |
+
|
35 |
+
- Item A
|
36 |
+
- Item B
|
37 |
+
- Item C
|
38 |
+
|
39 |
+
Lorem ipsum dolor sit amet."""
|
40 |
+
self.assertEqual(fix_bullet_lists(input_text), expected_output)
|
41 |
+
|
42 |
+
def test_multiple_lists(self):
|
43 |
+
input_text = """Lorem ipsum:
|
44 |
+
- Item A
|
45 |
+
- Item B
|
46 |
+
|
47 |
+
Lorem ipsum:
|
48 |
+
- Item C
|
49 |
+
- Item D"""
|
50 |
+
expected_output = """Lorem ipsum:
|
51 |
+
|
52 |
+
- Item A
|
53 |
+
- Item B
|
54 |
+
|
55 |
+
Lorem ipsum:
|
56 |
+
|
57 |
+
- Item C
|
58 |
+
- Item D
|
59 |
+
"""
|
60 |
+
self.assertEqual(fix_bullet_lists(input_text), expected_output)
|
src/pitch/__init__.py
ADDED
File without changes
|
src/pitch/convert_pitch_to_markdown.py
ADDED
@@ -0,0 +1,174 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Convert the raw json pitch to a markdown document.
|
3 |
+
|
4 |
+
PROMPT> python -m src.pitch.convert_pitch_to_markdown
|
5 |
+
"""
|
6 |
+
import os
|
7 |
+
import json
|
8 |
+
import time
|
9 |
+
import logging
|
10 |
+
from math import ceil
|
11 |
+
from typing import Optional
|
12 |
+
from dataclasses import dataclass
|
13 |
+
from llama_index.core.llms.llm import LLM
|
14 |
+
from llama_index.core.llms import ChatMessage, MessageRole
|
15 |
+
from src.format_json_for_use_in_query import format_json_for_use_in_query
|
16 |
+
from src.markdown_util.fix_bullet_lists import fix_bullet_lists
|
17 |
+
|
18 |
+
logger = logging.getLogger(__name__)
|
19 |
+
|
20 |
+
CONVERT_PITCH_TO_MARKDOWN_SYSTEM_PROMPT = """
|
21 |
+
You are a content formatter designed to transform project pitches into compelling and easily scannable Markdown documents. Your ONLY task is to generate the Markdown document itself, and NOTHING ELSE.
|
22 |
+
|
23 |
+
# Output Requirements:
|
24 |
+
- ABSOLUTELY NO INTRODUCTORY OR CONCLUDING TEXT. Do NOT add any extra sentences or paragraphs before or after the Markdown document.
|
25 |
+
- Enclose the ENTIRE Markdown document within the following delimiters:
|
26 |
+
- **Start Delimiter:** [START_MARKDOWN]
|
27 |
+
- **End DelIMITER:** [END_MARKDOWN]
|
28 |
+
- Use ONLY the provided text. Do NOT add any external information.
|
29 |
+
|
30 |
+
# Markdown Formatting Instructions:
|
31 |
+
- **Headings:** Use only two levels of headings:
|
32 |
+
- Top-level heading for the document title: `# Top Level Heading`
|
33 |
+
- Second-level headings for section titles: `## Section Title`
|
34 |
+
- DO NOT use any heading levels beyond these two.
|
35 |
+
- **Document Structure:**
|
36 |
+
- The input JSON may contain minimal content or multiple topics.
|
37 |
+
- If multiple topics are present, organize them into logical sections. Suggested section names include (but are not limited to): Introduction, Project Overview, Goals and Objectives, Risks and Mitigation Strategies, Metrics for Success, Stakeholder Benefits, Ethical Considerations, Collaboration Opportunities, and Long-term Vision.
|
38 |
+
- If the input JSON is minimal, include only the sections that are directly supported by the provided content. Do not invent or add sections that are not referenced in the input.
|
39 |
+
- **Lists:** Format lists with Markdown bullet points using a hyphen followed by a space:
|
40 |
+
```markdown
|
41 |
+
- Item 1
|
42 |
+
- Item 2
|
43 |
+
- Item 3
|
44 |
+
```
|
45 |
+
- **Strategic Bolding:** Bold key project elements, critical actions, and desired outcomes to enhance scannability. For example, bold terms such as **innovation**, **efficiency**, **sustainability**, and **collaboration**. Ensure that each section contains at least one bolded key term where applicable.
|
46 |
+
- **Expansion:** Expand on the provided content with additional explanatory paragraphs where needed, but do NOT add information that is not present in the input.
|
47 |
+
- **Delimiters Enforcement:** Ensure that the entire Markdown document is wrapped exactly within [START_MARKDOWN] and [END_MARKDOWN] with no additional text outside these delimiters.
|
48 |
+
- Ensure that all topics present in the input JSON are covered and organized in a clear, readable format.
|
49 |
+
"""
|
50 |
+
|
51 |
+
@dataclass
|
52 |
+
class ConvertPitchToMarkdown:
|
53 |
+
system_prompt: Optional[str]
|
54 |
+
user_prompt: str
|
55 |
+
response: str
|
56 |
+
markdown: str
|
57 |
+
metadata: dict
|
58 |
+
|
59 |
+
@classmethod
|
60 |
+
def execute(cls, llm: LLM, user_prompt: str) -> 'ConvertPitchToMarkdown':
|
61 |
+
"""
|
62 |
+
Invoke LLM with a json document that is the raw pitch.
|
63 |
+
"""
|
64 |
+
if not isinstance(llm, LLM):
|
65 |
+
raise ValueError("Invalid LLM instance.")
|
66 |
+
if not isinstance(user_prompt, str):
|
67 |
+
raise ValueError("Invalid query.")
|
68 |
+
|
69 |
+
system_prompt = CONVERT_PITCH_TO_MARKDOWN_SYSTEM_PROMPT.strip()
|
70 |
+
chat_message_list = [
|
71 |
+
ChatMessage(
|
72 |
+
role=MessageRole.SYSTEM,
|
73 |
+
content=system_prompt,
|
74 |
+
),
|
75 |
+
ChatMessage(
|
76 |
+
role=MessageRole.USER,
|
77 |
+
content=user_prompt,
|
78 |
+
)
|
79 |
+
]
|
80 |
+
|
81 |
+
logger.debug(f"User Prompt:\n{user_prompt}")
|
82 |
+
|
83 |
+
logger.debug("Starting LLM chat interaction.")
|
84 |
+
start_time = time.perf_counter()
|
85 |
+
chat_response = llm.chat(chat_message_list)
|
86 |
+
end_time = time.perf_counter()
|
87 |
+
duration = int(ceil(end_time - start_time))
|
88 |
+
response_byte_count = len(chat_response.message.content.encode('utf-8'))
|
89 |
+
logger.info(f"LLM chat interaction completed in {duration} seconds. Response byte count: {response_byte_count}")
|
90 |
+
|
91 |
+
metadata = dict(llm.metadata)
|
92 |
+
metadata["llm_classname"] = llm.class_name()
|
93 |
+
metadata["duration"] = duration
|
94 |
+
metadata["response_byte_count"] = response_byte_count
|
95 |
+
|
96 |
+
response_content = chat_response.message.content
|
97 |
+
|
98 |
+
start_delimiter = "[START_MARKDOWN]"
|
99 |
+
end_delimiter = "[END_MARKDOWN]"
|
100 |
+
|
101 |
+
start_index = response_content.find(start_delimiter)
|
102 |
+
end_index = response_content.find(end_delimiter)
|
103 |
+
|
104 |
+
if start_index != -1 and end_index != -1:
|
105 |
+
markdown_content = response_content[start_index + len(start_delimiter):end_index].strip()
|
106 |
+
else:
|
107 |
+
markdown_content = response_content # Use the entire content if delimiters are missing
|
108 |
+
logger.warning("Output delimiters not found in LLM response.")
|
109 |
+
|
110 |
+
# The bullet lists are supposed to be preceeded by 2 newlines.
|
111 |
+
# However often there is just 1 newline.
|
112 |
+
# This fix makes sure there are 2 newlines before bullet lists.
|
113 |
+
markdown_content = fix_bullet_lists(markdown_content)
|
114 |
+
|
115 |
+
json_response = {}
|
116 |
+
json_response['response_content'] = response_content
|
117 |
+
json_response['markdown'] = markdown_content
|
118 |
+
|
119 |
+
result = ConvertPitchToMarkdown(
|
120 |
+
system_prompt=system_prompt,
|
121 |
+
user_prompt=user_prompt,
|
122 |
+
response=json_response,
|
123 |
+
markdown=markdown_content,
|
124 |
+
metadata=metadata,
|
125 |
+
)
|
126 |
+
logger.debug("CleanupPitch instance created successfully.")
|
127 |
+
return result
|
128 |
+
|
129 |
+
def to_dict(self, include_metadata=True, include_system_prompt=True, include_user_prompt=True) -> dict:
|
130 |
+
d = self.response.copy()
|
131 |
+
d['markdown'] = self.markdown
|
132 |
+
if include_metadata:
|
133 |
+
d['metadata'] = self.metadata
|
134 |
+
if include_system_prompt:
|
135 |
+
d['system_prompt'] = self.system_prompt
|
136 |
+
if include_user_prompt:
|
137 |
+
d['user_prompt'] = self.user_prompt
|
138 |
+
return d
|
139 |
+
|
140 |
+
def save_raw(self, file_path: str) -> None:
|
141 |
+
with open(file_path, 'w') as f:
|
142 |
+
f.write(json.dumps(self.to_dict(), indent=2))
|
143 |
+
|
144 |
+
def save_markdown(self, file_path: str) -> None:
|
145 |
+
with open(file_path, "w", encoding="utf-8") as f:
|
146 |
+
f.write(self.markdown)
|
147 |
+
|
148 |
+
if __name__ == "__main__":
|
149 |
+
from src.llm_factory import get_llm
|
150 |
+
|
151 |
+
basepath = os.path.join(os.path.dirname(__file__), 'test_data')
|
152 |
+
|
153 |
+
def load_json(relative_path: str) -> dict:
|
154 |
+
path = os.path.join(basepath, relative_path)
|
155 |
+
print(f"loading file: {path}")
|
156 |
+
with open(path, 'r', encoding='utf-8') as f:
|
157 |
+
the_json = json.load(f)
|
158 |
+
return the_json
|
159 |
+
|
160 |
+
pitch_json = load_json('lunar_base-pitch.json')
|
161 |
+
|
162 |
+
model_name = "ollama-llama3.1"
|
163 |
+
# model_name = "ollama-qwen2.5-coder"
|
164 |
+
llm = get_llm(model_name)
|
165 |
+
|
166 |
+
query = format_json_for_use_in_query(pitch_json)
|
167 |
+
print(f"Query: {query}")
|
168 |
+
result = ConvertPitchToMarkdown.execute(llm, query)
|
169 |
+
|
170 |
+
print("\nResponse:")
|
171 |
+
json_response = result.to_dict(include_system_prompt=False, include_user_prompt=False)
|
172 |
+
print(json.dumps(json_response, indent=2))
|
173 |
+
|
174 |
+
print(f"\n\nMarkdown:\n{result.markdown}")
|
src/{plan → pitch}/create_pitch.py
RENAMED
@@ -1,5 +1,7 @@
|
|
1 |
"""
|
2 |
Create a pitch for this project.
|
|
|
|
|
3 |
"""
|
4 |
import os
|
5 |
import json
|
@@ -123,8 +125,7 @@ WBS Level 2:
|
|
123 |
if __name__ == "__main__":
|
124 |
from llama_index.llms.ollama import Ollama
|
125 |
|
126 |
-
|
127 |
-
basepath = '/Users/neoneye/Desktop/planexe_data'
|
128 |
|
129 |
def load_json(relative_path: str) -> dict:
|
130 |
path = os.path.join(basepath, relative_path)
|
@@ -133,9 +134,9 @@ if __name__ == "__main__":
|
|
133 |
the_json = json.load(f)
|
134 |
return the_json
|
135 |
|
136 |
-
plan_json = load_json('
|
137 |
-
wbs_level1_json = load_json('
|
138 |
-
wbs_level2_json = load_json('
|
139 |
|
140 |
model_name = "llama3.1:latest"
|
141 |
# model_name = "qwen2.5-coder:latest"
|
|
|
1 |
"""
|
2 |
Create a pitch for this project.
|
3 |
+
|
4 |
+
PROMPT> python -m src.pitch.create_pitch
|
5 |
"""
|
6 |
import os
|
7 |
import json
|
|
|
125 |
if __name__ == "__main__":
|
126 |
from llama_index.llms.ollama import Ollama
|
127 |
|
128 |
+
basepath = os.path.join(os.path.dirname(__file__), 'test_data')
|
|
|
129 |
|
130 |
def load_json(relative_path: str) -> dict:
|
131 |
path = os.path.join(basepath, relative_path)
|
|
|
134 |
the_json = json.load(f)
|
135 |
return the_json
|
136 |
|
137 |
+
plan_json = load_json('lunar_base-project_plan.json')
|
138 |
+
wbs_level1_json = load_json('lunar_base-wbs_level1.json')
|
139 |
+
wbs_level2_json = load_json('lunar_base-wbs_level2.json')
|
140 |
|
141 |
model_name = "llama3.1:latest"
|
142 |
# model_name = "qwen2.5-coder:latest"
|
src/pitch/test_data/lunar_base-pitch.json
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"pitch": "Imagine a future where humanity isn't confined to Earth, where the Moon isn't just a distant beacon but a thriving hub of scientific discovery and resource utilization! We're not just dreaming; we're building that future. Our project is to establish a permanent, manned lunar base within the next 10 years, a stepping stone to interplanetary exploration and a testament to human ingenuity. With a dedicated team, a robust $250 billion budget, and cutting-edge technology, we're poised to make this giant leap for mankind a reality!",
|
3 |
+
"why_this_pitch_works": "This pitch starts with a compelling vision, immediately grabbing attention. It clearly states the project's purpose and highlights the ambitious yet achievable nature of the goal. The mention of the budget and team size adds credibility, while the reference to 'giant leap for mankind' evokes a sense of historical significance and inspires excitement.",
|
4 |
+
"target_audience": "Government space agencies (NASA, ESA, JAXA, Roscosmos), private space exploration companies (SpaceX, Blue Origin), investors, scientific community, and the general public.",
|
5 |
+
"call_to_action": "Join us in shaping the future of space exploration! Explore our detailed project plan, funding opportunities, and collaboration options on our website [insert website address here]. Let's build this lunar base together!",
|
6 |
+
"risks_and_mitigation": "We acknowledge the inherent risks of space exploration, including launch failures, radiation exposure, and equipment malfunctions. Our mitigation strategies include redundant launch systems, advanced radiation shielding, rigorous testing protocols, comprehensive medical support, and lunar dust mitigation strategies. We've also identified operational, systematic, and business risks, and developed plans to address each category.",
|
7 |
+
"metrics_for_success": "Beyond establishing a functional lunar base, success will be measured by the volume of scientific research conducted, the efficiency of lunar resource utilization (e.g., propellant production), the long-term health and well-being of the lunar crew, the number of collaborative partnerships established, and the public engagement and educational impact generated by the project.",
|
8 |
+
"stakeholder_benefits": "For astronauts, this project offers the opportunity to be pioneers in a new frontier. Engineers will contribute to groundbreaking technological advancements. Space agencies will expand their capabilities and influence. Investors will gain access to a rapidly growing space economy. The scientific community will unlock unprecedented research opportunities. And the public will witness a new era of human exploration and discovery.",
|
9 |
+
"ethical_considerations": "We are committed to responsible space exploration, adhering to the Outer Space Treaty and minimizing our environmental impact on the lunar surface. We will prioritize the safety and well-being of our astronauts and ensure transparency in our operations. We will also consider the long-term implications of lunar resource utilization and strive for sustainable practices.",
|
10 |
+
"collaboration_opportunities": "We actively seek partnerships with organizations specializing in areas such as advanced materials, robotics, life support systems, and space medicine. We welcome collaborations with universities and research institutions to advance scientific knowledge and develop innovative technologies. We also encourage public engagement through educational programs and citizen science initiatives.",
|
11 |
+
"long_term_vision": "Our lunar base is not just an end in itself; it's a crucial stepping stone towards establishing a permanent human presence in space. It will serve as a platform for developing and testing technologies for future missions to Mars and beyond, ultimately paving the way for a multi-planetary future for humanity.",
|
12 |
+
"metadata": {
|
13 |
+
"context_window": 3900,
|
14 |
+
"num_output": 8192,
|
15 |
+
"is_chat_model": true,
|
16 |
+
"is_function_calling_model": false,
|
17 |
+
"model_name": "google/gemini-2.0-flash-001",
|
18 |
+
"system_role": "system",
|
19 |
+
"llm_classname": "OpenRouter_LLM",
|
20 |
+
"duration": 8
|
21 |
+
},
|
22 |
+
"query": "The project plan:\n{\"goal_statement\":\"Establish a permanent manned base on the moon.\",\"smart_criteria\":{\"specific\":\"Establish a permanent manned lunar base capable of supporting long-term habitation and research.\",\"measurable\":\"The successful establishment of a lunar base with operational life support systems, power generation, and research facilities.\",\"achievable\":\"Achievable given the allocated budget of $250 billion USD, a 10-year timeline, and a core team of 1000 personnel, including 20 astronauts and 300 engineers.\",\"relevant\":\"Establishing a permanent lunar base will enable long-term scientific research, resource utilization, and expansion of human presence in space.\",\"time_bound\":\"The base should be fully operational within 10 years.\"},\"dependencies\":[\"Establish at least 3 potential landing sites on the moon.\",\"Model radiation exposure levels on the lunar surface.\",\"Define the internal volume of the initial habitat module.\"],\"resources_required\":[\"Lunar Reconnaissance Orbiter data\",\"Advanced composite materials\",\"Lunar regolith\",\"Radiation shielding\",\"Medical equipment\",\"Medications\",\"Backup return vehicle\",\"Spacesuits\"],\"related_goals\":[\"Conduct long-term scientific research on the moon.\",\"Utilize lunar resources for propellant production.\",\"Expand human presence in space.\"],\"tags\":[\"moon base\",\"manned mission\",\"lunar exploration\",\"space colonization\"],\"risk_assessment_and_mitigation_strategies\":{\"key_risks\":[\"Launch failure\",\"Radiation exposure\",\"Lunar hazard\",\"Equipment failure\",\"Medical emergencies\",\"Lunar dust contamination\"],\"diverse_risks\":[\"Operational risks\",\"Systematic risks\",\"Business risks\"],\"mitigation_plans\":[\"Implement redundant launch systems and rigorous testing protocols.\",\"Develop radiation shielding strategies for the habitat module and spacesuits.\",\"Conduct thorough site surveys to identify and mitigate lunar hazards.\",\"Maintain backup systems and conduct regular maintenance checks.\",\"Develop comprehensive medical protocols and equip the habitat module with a fully stocked medical bay.\",\"Develop a lunar dust mitigation strategy for the habitat module and spacesuits.\"]},\"stakeholder_analysis\":{\"primary_stakeholders\":[\"Astronauts\",\"Engineers\",\"Mission Control\",\"Life Support Systems Engineer\",\"Construction Manager\"],\"secondary_stakeholders\":[\"NASA\",\"ESA\",\"JAXA\",\"Roscosmos\",\"Private companies\",\"The public\",\"Aerospace medicine specialists\"],\"engagement_strategies\":[\"Provide regular updates and progress reports to primary stakeholders.\",\"Engage secondary stakeholders through public forums, press releases, and collaborative projects.\",\"Consult with aerospace medicine specialists to develop comprehensive medical protocols.\"]},\"regulatory_and_compliance_requirements\":{\"permits_and_licenses\":[\"Outer Space Treaty compliance\",\"National space laws compliance\"],\"compliance_standards\":[\"Environmental standards\",\"Safety standards\",\"Industry-specific standards\"],\"regulatory_bodies\":[\"United Nations Office for Outer Space Affairs\"],\"compliance_actions\":[\"Minimize environmental impact through site selection and waste management protocols.\",\"Ensure compliance with the Outer Space Treaty and national space laws.\",\"Implement safety protocols for astronauts and equipment.\"]}}\n\nWork Breakdown Structure:\n{\"wbs_project\":{\"id\":\"6e20eb7b-c268-40f4-8080-115fb4c5454b\",\"description\":\"Lunar Base\",\"extra_fields\":{\"final_deliverable\":\"Operational Base\"},\"task_children\":[{\"id\":\"890d6738-aa20-42e6-a472-c59a188a9cad\",\"description\":\"Project Initiation & Planning\",\"task_children\":[{\"id\":\"8bcefb17-013c-45cf-8482-b6a4de629efb\",\"description\":\"Define Project Scope and Objectives\"},{\"id\":\"b76e3b08-02b2-4490-bf69-8c86febf29a9\",\"description\":\"Secure Funding and Resources\"},{\"id\":\"9ca53d3d-16ed-4349-93f1-767ee4e9ee4b\",\"description\":\"Establish Project Team and Governance\"},{\"id\":\"6e16a6a9-5880-41b5-a92b-ef9edfd9b5e3\",\"description\":\"Develop Detailed Project Plan\"},{\"id\":\"0f9dbae8-654a-4efc-9f4d-3bd946c48bd1\",\"description\":\"Conduct Risk Assessment\"}]},{\"id\":\"2b65c62b-9149-44ef-a6e2-a5fc28667ce7\",\"description\":\"Site Selection & Lunar Reconnaissance\",\"task_children\":[{\"id\":\"13ba1269-63a4-4a6d-9e7d-39581278e338\",\"description\":\"Analyze Lunar Reconnaissance Orbiter Data\"},{\"id\":\"9a85ae94-1c9d-413a-b39f-712f1ec1b672\",\"description\":\"Identify Potential Landing Sites\"},{\"id\":\"4261937b-4fc4-4feb-bccd-bb048b25af67\",\"description\":\"Model Radiation Exposure Levels\"},{\"id\":\"a11410e6-3300-4242-b59d-965a0099dffa\",\"description\":\"Assess Lunar Hazards\"},{\"id\":\"f23c4fc4-f432-4802-9d38-44762fd045f5\",\"description\":\"Select Optimal Landing Site\"}]},{\"id\":\"8430c5f9-c0df-42bf-940e-473a4b039f95\",\"description\":\"Habitat Module Design & Development\",\"task_children\":[{\"id\":\"6355f874-61d0-4b64-bc1c-7a726702fa2a\",\"description\":\"Define Habitat Module Internal Volume\"},{\"id\":\"58bb4dd4-f8ab-4022-a3ae-decd734df008\",\"description\":\"Design Life Support Systems\"},{\"id\":\"aefc27c5-e531-4b98-b975-9d94246aab9d\",\"description\":\"Develop Radiation Shielding\"},{\"id\":\"18c839b3-c13e-4889-9204-ea91cfc85533\",\"description\":\"Design Power Generation System\"},{\"id\":\"4d5e1093-c97e-4236-9953-2a001f85b824\",\"description\":\"Develop Habitat Module Prototype\"}]},{\"id\":\"9da53cb2-533c-458f-8c09-5b0a2de809e3\",\"description\":\"Equipment & Resource Procurement\",\"task_children\":[{\"id\":\"8ea81b95-9789-4d28-a617-006b8b0f4ddb\",\"description\":\"Procure Advanced Composite Materials\"},{\"id\":\"e46984fd-d43a-494e-ae0f-964036115c30\",\"description\":\"Acquire Medical Equipment and Medications\"},{\"id\":\"72708542-1833-4132-a8e4-06a01264f5f3\",\"description\":\"Develop Backup Return Vehicle\"},{\"id\":\"3b7f2306-282b-4db0-acbe-015f47b2c02c\",\"description\":\"Manufacture Spacesuits\"},{\"id\":\"44a22ae3-972e-45a4-8d33-3c7fb2b48129\",\"description\":\"Secure Lunar Regolith Samples\"}]},{\"id\":\"8d633161-907e-4cc2-9d4d-ab6761f9c269\",\"description\":\"Launch & Lunar Transportation\",\"task_children\":[{\"id\":\"262f8926-186c-48c4-97e5-6043894dbe9a\",\"description\":\"Prepare Launch Vehicle\"},{\"id\":\"6d094c7f-bbd1-4b98-bbdb-5060c175efdb\",\"description\":\"Transport Habitat Module to Launch Site\"},{\"id\":\"f6c8009d-9e6d-415c-96cf-71d704c27a3e\",\"description\":\"Conduct Launch Operations\"},{\"id\":\"74b8c707-7fd7-4186-9f34-fbaa4c405458\",\"description\":\"Perform Lunar Transfer Orbit Maneuvers\"},{\"id\":\"3a603c57-9623-4551-97d1-369231f4ad06\",\"description\":\"Execute Lunar Landing\"}]},{\"id\":\"d4043460-f75b-47af-a038-3e27d5269c67\",\"description\":\"Base Construction & Setup\",\"task_children\":[{\"id\":\"dd0d2912-64f6-4a19-83d9-9bf398841ebf\",\"description\":\"Deploy Habitat Module\"},{\"id\":\"4724b64a-dd67-4d5f-8ef1-8d3702e46caf\",\"description\":\"Install Life Support Systems\"},{\"id\":\"56eacb38-081f-4d4b-8b48-4b819fc6745f\",\"description\":\"Establish Power Generation\"},{\"id\":\"02edd7c0-3c5d-4765-809b-7f1435fc8f16\",\"description\":\"Set Up Research Facilities\"},{\"id\":\"93f51791-4db6-45b0-a26a-b1851a68b852\",\"description\":\"Implement Lunar Dust Mitigation Strategy\"}]},{\"id\":\"fdcca24a-3673-444e-85e8-8ef06b17ff1b\",\"description\":\"Base Operation & Maintenance\",\"task_children\":[{\"id\":\"77dbba2b-fd2d-41e9-8b7f-fffecfbdb1a4\",\"description\":\"Conduct Scientific Research\"},{\"id\":\"06f7c01c-c693-48fd-8068-f1c19a0f9f32\",\"description\":\"Maintain Life Support Systems\"},{\"id\":\"0382ccbd-e3b9-4d90-90a6-3b69450005ac\",\"description\":\"Monitor Radiation Levels\"},{\"id\":\"d07a7414-2283-4597-ae0f-8db50e87b1c2\",\"description\":\"Perform Equipment Maintenance\"},{\"id\":\"5e24afc6-84c3-4668-b456-ee43991167cf\",\"description\":\"Manage Waste and Resources\"}]}]}}"
|
23 |
+
}
|
src/pitch/test_data/lunar_base-project_plan.json
ADDED
@@ -0,0 +1,114 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"goal_statement": "Establish a permanent manned base on the moon.",
|
3 |
+
"smart_criteria": {
|
4 |
+
"specific": "Establish a permanent manned lunar base capable of supporting long-term habitation and research.",
|
5 |
+
"measurable": "The successful establishment of a lunar base with operational life support systems, power generation, and research facilities.",
|
6 |
+
"achievable": "Achievable given the allocated budget of $250 billion USD, a 10-year timeline, and a core team of 1000 personnel, including 20 astronauts and 300 engineers.",
|
7 |
+
"relevant": "Establishing a permanent lunar base will enable long-term scientific research, resource utilization, and expansion of human presence in space.",
|
8 |
+
"time_bound": "The base should be fully operational within 10 years."
|
9 |
+
},
|
10 |
+
"dependencies": [
|
11 |
+
"Establish at least 3 potential landing sites on the moon.",
|
12 |
+
"Model radiation exposure levels on the lunar surface.",
|
13 |
+
"Define the internal volume of the initial habitat module."
|
14 |
+
],
|
15 |
+
"resources_required": [
|
16 |
+
"Lunar Reconnaissance Orbiter data",
|
17 |
+
"Advanced composite materials",
|
18 |
+
"Lunar regolith",
|
19 |
+
"Radiation shielding",
|
20 |
+
"Medical equipment",
|
21 |
+
"Medications",
|
22 |
+
"Backup return vehicle",
|
23 |
+
"Spacesuits"
|
24 |
+
],
|
25 |
+
"related_goals": [
|
26 |
+
"Conduct long-term scientific research on the moon.",
|
27 |
+
"Utilize lunar resources for propellant production.",
|
28 |
+
"Expand human presence in space."
|
29 |
+
],
|
30 |
+
"tags": [
|
31 |
+
"moon base",
|
32 |
+
"manned mission",
|
33 |
+
"lunar exploration",
|
34 |
+
"space colonization"
|
35 |
+
],
|
36 |
+
"risk_assessment_and_mitigation_strategies": {
|
37 |
+
"key_risks": [
|
38 |
+
"Launch failure",
|
39 |
+
"Radiation exposure",
|
40 |
+
"Lunar hazard",
|
41 |
+
"Equipment failure",
|
42 |
+
"Medical emergencies",
|
43 |
+
"Lunar dust contamination"
|
44 |
+
],
|
45 |
+
"diverse_risks": [
|
46 |
+
"Operational risks",
|
47 |
+
"Systematic risks",
|
48 |
+
"Business risks"
|
49 |
+
],
|
50 |
+
"mitigation_plans": [
|
51 |
+
"Implement redundant launch systems and rigorous testing protocols.",
|
52 |
+
"Develop radiation shielding strategies for the habitat module and spacesuits.",
|
53 |
+
"Conduct thorough site surveys to identify and mitigate lunar hazards.",
|
54 |
+
"Maintain backup systems and conduct regular maintenance checks.",
|
55 |
+
"Develop comprehensive medical protocols and equip the habitat module with a fully stocked medical bay.",
|
56 |
+
"Develop a lunar dust mitigation strategy for the habitat module and spacesuits."
|
57 |
+
]
|
58 |
+
},
|
59 |
+
"stakeholder_analysis": {
|
60 |
+
"primary_stakeholders": [
|
61 |
+
"Astronauts",
|
62 |
+
"Engineers",
|
63 |
+
"Mission Control",
|
64 |
+
"Life Support Systems Engineer",
|
65 |
+
"Construction Manager"
|
66 |
+
],
|
67 |
+
"secondary_stakeholders": [
|
68 |
+
"NASA",
|
69 |
+
"ESA",
|
70 |
+
"JAXA",
|
71 |
+
"Roscosmos",
|
72 |
+
"Private companies",
|
73 |
+
"The public",
|
74 |
+
"Aerospace medicine specialists"
|
75 |
+
],
|
76 |
+
"engagement_strategies": [
|
77 |
+
"Provide regular updates and progress reports to primary stakeholders.",
|
78 |
+
"Engage secondary stakeholders through public forums, press releases, and collaborative projects.",
|
79 |
+
"Consult with aerospace medicine specialists to develop comprehensive medical protocols."
|
80 |
+
]
|
81 |
+
},
|
82 |
+
"regulatory_and_compliance_requirements": {
|
83 |
+
"permits_and_licenses": [
|
84 |
+
"Outer Space Treaty compliance",
|
85 |
+
"National space laws compliance"
|
86 |
+
],
|
87 |
+
"compliance_standards": [
|
88 |
+
"Environmental standards",
|
89 |
+
"Safety standards",
|
90 |
+
"Industry-specific standards"
|
91 |
+
],
|
92 |
+
"regulatory_bodies": [
|
93 |
+
"United Nations Office for Outer Space Affairs"
|
94 |
+
],
|
95 |
+
"compliance_actions": [
|
96 |
+
"Minimize environmental impact through site selection and waste management protocols.",
|
97 |
+
"Ensure compliance with the Outer Space Treaty and national space laws.",
|
98 |
+
"Implement safety protocols for astronauts and equipment."
|
99 |
+
]
|
100 |
+
},
|
101 |
+
"metadata": {
|
102 |
+
"context_window": 3900,
|
103 |
+
"num_output": 8192,
|
104 |
+
"is_chat_model": true,
|
105 |
+
"is_function_calling_model": false,
|
106 |
+
"model_name": "google/gemini-2.0-flash-001",
|
107 |
+
"system_role": "system",
|
108 |
+
"llm_classname": "OpenRouter_LLM",
|
109 |
+
"duration": 8,
|
110 |
+
"response_byte_count": 3221
|
111 |
+
},
|
112 |
+
"user_prompt": "Initial plan: Plan:\nManned moon mission, for establishing a permanent base.\n\nToday's date:\n2025-Feb-09\n\nProject start ASAP\n\nAssumptions:\n{\"assumption_list\":[\"The initial budget is $250 billion USD for development, launch, construction, and 2 years of operation.\",\"The mission timeline is 10 years to full operational capacity after base construction.\",\"A core team of 1000 personnel is required, including 20 astronauts and 300 engineers.\",\"The mission is governed by the Outer Space Treaty and national space laws.\",\"Launch failure risk is 1%; radiation exposure risk is 5%; lunar hazard risk is 10%.\",\"Environmental impact will be minimized through site selection and waste management protocols.\",\"Key stakeholders include NASA, ESA, JAXA, Roscosmos, private companies, and the public.\",\"The base requires solar/nuclear power, life support, communication, and ISRU technologies.\"]}\n\nPre-project assessment:\n{\"go_no_go_recommendation\":\"Proceed with Caution. The project is ambitious and lacks specific details, making immediate execution risky. Proceeding with caution requires immediate action on the three critical items listed in the combined summary. Without a clear understanding of the landing site, radiation risks, and habitat requirements, the mission cannot proceed safely or effectively. If these actions are not completed, the project should be halted.\",\"combined_summary\":\"The three most critical, immediate actions are: 1) Establish at least 3 potential landing sites on the moon, prioritizing areas with sunlight for at least 200 hours per Earth day, to maximize solar power generation. This is essential for identifying a viable location for the base. 2) Model radiation exposure levels on the lunar surface, accounting for solar particle events and galactic cosmic rays, using data from the Lunar Reconnaissance Orbiter by 2025-Feb-14 17:00. This is crucial for assessing and mitigating radiation risks to the astronauts. 3) Define the internal volume of the initial habitat module, requiring a minimum of 150 cubic meters to accommodate at least 4 astronauts for a 6-month mission. This is needed to ensure the habitat can support the crew.\",\"feedback\":[{\"title\":\"Define Initial Base Location Criteria\",\"description\":\"To initiate this project, you must:\\n* Establish at least 3 potential landing sites on the moon, prioritizing areas with sunlight for at least 200 hours per Earth day, to maximize solar power generation.\\n* Analyze lunar surface composition data from previous missions (e.g., Chang'e 5, Lunar Reconnaissance Orbiter) at these sites by 2025-Feb-16 12:00, focusing on regolith properties suitable for construction (e.g., high titanium content for radiation shielding).\\n* Determine the proximity of each site to potential water ice deposits, requiring a minimum of 50 kg extractable water ice within a 1 km radius, to support life support systems and potential propellant production.\\n* Assess the slope and terrain roughness of each site, ensuring slopes do not exceed 5 degrees over a 10-meter baseline, to facilitate safe landing and base construction.\"},{\"title\":\"Specify Habitat Module Requirements\",\"description\":\"To initiate this project, you must:\\n* Define the internal volume of the initial habitat module, requiring a minimum of 150 cubic meters to accommodate at least 4 astronauts for a 6-month mission.\\n* Specify the radiation shielding requirements for the habitat module, ensuring it reduces radiation exposure to no more than 50 mSv per year, using a combination of lunar regolith and advanced composite materials.\\n* Determine the power requirements for the habitat module, including life support systems, scientific equipment, and communication systems, estimating a minimum of 10 kW continuous power.\\n* Design the life support systems for the habitat module, including air revitalization, water recycling, and waste management, aiming for a closed-loop system with at least 90% water recycling efficiency.\"},{\"title\":\"Outline Lunar Surface Mobility Plan\",\"description\":\"To initiate this project, you must:\\n* Specify the range and payload capacity of the lunar rover, requiring a minimum range of 100 km and a payload capacity of at least 200 kg for transporting equipment and samples.\\n* Determine the power source for the lunar rover, considering both battery and solar power options, ensuring continuous operation for at least 8 hours per day.\\n* Define the navigation and communication systems for the lunar rover, including GPS-independent navigation and reliable communication with the base and Earth.\\n* Design the rover's wheels and suspension system to handle the lunar terrain, ensuring it can traverse slopes up to 20 degrees and obstacles up to 0.5 meters in height.\"},{\"title\":\"Establish Communication Protocol Requirements\",\"description\":\"To initiate this project, you must:\\n* Define the communication bandwidth requirements between the lunar base and Earth, requiring a minimum data rate of 10 Mbps for real-time video and data transmission.\\n* Specify the communication frequency bands to be used, considering both S-band and X-band options, ensuring minimal interference and reliable communication.\\n* Determine the antenna size and power requirements for the lunar base and Earth-based communication stations, ensuring continuous communication coverage.\\n* Establish a backup communication system, such as a lunar relay satellite, in case of direct communication failure, to be operational by 2026-Dec-31 23:59.\"},{\"title\":\"Assess Radiation Exposure Mitigation\",\"description\":\"To initiate this project, you must:\\n* Model radiation exposure levels on the lunar surface, accounting for solar particle events and galactic cosmic rays, using data from the Lunar Reconnaissance Orbiter by 2025-Feb-14 17:00.\\n* Develop a radiation shielding strategy for the habitat module, incorporating at least 2 meters of lunar regolith or equivalent shielding material, to reduce radiation exposure to ALARA (As Low As Reasonably Achievable) levels.\\n* Implement a radiation monitoring system within the habitat module and on lunar surface suits, providing real-time radiation dose measurements and alerts to astronauts.\\n* Establish emergency protocols for solar particle events, including immediate shelter in a designated radiation-shielded area, ensuring the area provides at least a 10x reduction in radiation exposure.\"},{\"title\":\"Plan for Emergency Medical Support\",\"description\":\"To initiate this project, you must:\\n* Develop a comprehensive medical protocol for treating common space-related illnesses and injuries, including bone loss, muscle atrophy, and radiation sickness, consulting with at least 3 aerospace medicine specialists by 2025-Feb-21 12:00.\\n* Equip the habitat module with a fully stocked medical bay, including advanced diagnostic equipment (e.g., ultrasound, blood analyzer) and a wide range of medications, ensuring all equipment is rated for spaceflight.\\n* Train at least two astronauts in advanced medical procedures, including surgery and emergency care, providing at least 200 hours of training per astronaut.\\n* Establish a real-time telemedicine link with Earth-based medical experts, ensuring continuous access to medical consultation and support.\"},{\"title\":\"Mitigate Lunar Dust Contamination Risks\",\"description\":\"To initiate this project, you must:\\n* Develop a lunar dust mitigation strategy for the habitat module and spacesuits, including airlocks, dust filters, and regular cleaning procedures, aiming to minimize dust exposure to astronauts.\\n* Design spacesuits with enhanced dust sealing and cleaning mechanisms, preventing dust from entering the suit and causing respiratory or mechanical issues.\\n* Implement a dust monitoring system within the habitat module, measuring dust particle concentration and composition, and triggering alerts when dust levels exceed safe limits.\\n* Conduct regular health checks on astronauts to monitor for signs of dust-related health problems, including respiratory irritation and lung damage, performing checks at least once per week.\"},{\"title\":\"Establish Contingency Return Procedures\",\"description\":\"To initiate this project, you must:\\n* Develop a contingency return plan for various emergency scenarios, including equipment failure, medical emergencies, and habitat damage, outlining specific procedures and timelines.\\n* Maintain a backup return vehicle at the lunar base, fully fueled and ready for immediate launch, ensuring it can accommodate all astronauts and essential equipment.\\n* Establish a communication protocol with Earth-based mission control for coordinating emergency return procedures, including real-time data sharing and decision-making.\\n* Conduct regular drills and simulations to practice emergency return procedures, ensuring all astronauts are familiar with the protocols and can respond effectively, performing drills at least once per month.\"}]}",
|
113 |
+
"system_prompt": "You are an expert project planner tasked with creating comprehensive and detailed project plans based on user-provided descriptions. Your output must be a complete JSON object conforming to the provided GoalDefinition schema. Focus on being specific and actionable, generating a plan that is realistic and useful for guiding project development.\n\nYour plans must include:\n- A clear goal statement adhering to the SMART criteria (Specific, Measurable, Achievable, Relevant, Time-bound). Provide specific metrics and timeframes where possible. For the time-bound, only use \"Today\" for simple, short duration tasks.\n -Ensure the SMART criteria is high-level, and based directly on the goal statement, and the user description.\n - The **Specific** criteria should clarify what is to be achieved with the goal, and must directly reflect the goal statement, and must not imply any specific actions or processes.\n - The **Measurable** criteria should define how you will know if the goal has been achieved. It should be a metric or some other way of validating that the goal is complete, and must not include implied actions or steps.\n - The **Achievable** criteria should explain why the goal is achievable given the information provided by the user. It should specify any limitations or benefits.\n - The **Relevant** criteria should specify why this goal is necessary, or what value it provides.\n - The **Time-bound** criteria must specify when the goal must be achieved. For small tasks, this will be \"Today\". For larger tasks, the time-bound should be a general time estimate, and should not specify a specific date or time unless it has been specified by the user.\n- A breakdown of dependencies and required resources for the project. Break down dependencies into actionable sub-tasks where applicable. Dependencies should be high-level, and not overly prescriptive, nor should they imply specific actions. Only include dependencies that are explicitly mentioned in the user description or directly implied from it. Do not include any specific timestamps, volumes, quantities or implied resources in the dependencies section, and do not include inferred actions.\n- A clear identification of related goals and future applications.\n- A detailed risk assessment with specific mitigation strategies. Focus on actionable items to mitigate the risks you have identified, ensuring they are tailored to the project's context.\n - When identifying risks, consider common issues specific to the project's domain (e.g., construction delays, equipment failures, safety hazards, financial issues, security breaches, data losses). For each identified risk, generate a realistic and specific mitigation strategy that is actionable within the project's context. Try to extract risks based on user descriptions. Avoid being too specific, and avoid adding unrealistic risks and mitigation actions. Only include mitigation plans that are explicitly derived from the user description, or are implied from it.\n- A comprehensive stakeholder analysis, identifying primary and secondary stakeholders, and outlining engagement strategies.\n - **Primary Stakeholders:** Identify key roles or individuals directly responsible for executing the project. For small-scale or personal projects, this may simply be the person performing the task (e.g., \"Coffee Brewer\"). For large-scale projects, identify domain-specific roles (e.g., \"Construction Manager,\" \"Life Support Systems Engineer\").\n - **Secondary Stakeholders:** Identify external parties or collaborators relevant to the project. For small-scale projects, this may include suppliers or individuals indirectly affected by the project (e.g., \"Coffee Supplier,\" \"Household Members\"). For large-scale projects, include regulatory bodies, material suppliers, or other external entities.\n - When outlining engagement strategies for stakeholders, consider the nature of the project and their roles. Primary stakeholders should have regular updates and progress reports, and requests for information should be answered promptly. Secondary stakeholders may require updates on key milestones, reports for compliance, or timely notification of significant changes to project scope or timeline. For smaller projects, the engagement strategy and stakeholders can be omitted if they are not explicitly mentioned in the user description, or implied from it.\n - **Note:** Do not assume the availability or involvement of any specific individuals beyond those directly mentioned in the user-provided project description. Generate all information independently from the provided description, and do not rely on any previous data or information from prior runs of this tool. Do not include any default information unless explicitly stated.\n- A detailed overview of regulatory and compliance requirements, such as permits and licenses, and how compliance actions are planned.\n - When considering regulatory and compliance requirements, identify any specific licenses or permits needed, and include compliance actions in the plan, such as \"Apply for permit X\", \"Schedule compliance audit\" and \"Implement compliance plan for Y\", and ensure compliance actions are included in the project timeline. For smaller projects, the regulatory compliance section can be omitted.\n- Tags or keywords that allow users to easily find and categorize the project.\nAdaptive Behavior:\n- Automatically adjust the level of detail and formality based on the scale and complexity of the project. For small-scale or personal projects, keep the plan simple and avoid formal elements. For massive or complex projects, ensure plans include more formal elements, such as project charters or work breakdown structures, and provide detailed actions for project execution.\n- Infer the appropriate stakeholders, risks, and resources based on the project's domain and context. Avoid overly formal or mismatched roles unless explicitly required by the project's context.\n- For smaller tasks, only include resources that need to be purchased or otherwise explicitly acquired. Only include resources that are mentioned in the user description, or implied from it. Do not include personnel or stakeholders as a resource.\n- Only include dependencies that are explicitly mentioned in the user description, or directly implied from it.\nPrioritize feasibility, practicality, and alignment with the user-provided description. Ensure the plan is actionable, with concrete steps where possible and measurable outcomes.\nWhen breaking down dependencies into sub-tasks, specify concrete actions (e.g., \"Procure X\", \"Design Y\", \"Test Z\"), and if possible, include resource requirements (e.g., \"Procure 100 Units of X\") and estimated timeframes where appropriate. However, for very small, simple tasks, the dependencies do not need a time element, and do not have to be overly specific.\n\nHere's an example of the expected output format for a simple project:\n{\n \"goal_statement\": \"Make a cup of coffee.\",\n \"smart_criteria\": {\n \"specific\": \"Prepare a cup of instant coffee, with milk and sugar if available.\",\n \"measurable\": \"The completion of the task can be measured by the existence of a prepared cup of coffee.\",\n \"achievable\": \"The task is achievable in the user's kitchen.\",\n \"relevant\": \"The task will provide the user with a warm drink.\",\n \"time_bound\": \"The task should be completed in 5 minutes.\"\n },\n \"dependencies\": [],\n \"resources_required\": [ \"instant coffee\" ],\n \"related_goals\": [ \"satisfy hunger\", \"enjoy a drink\" ],\n \"tags\": [ \"drink\", \"coffee\", \"simple\" ]\n}"
|
114 |
+
}
|
src/pitch/test_data/lunar_base-wbs_level1.json
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"id": "6e20eb7b-c268-40f4-8080-115fb4c5454b",
|
3 |
+
"project_title": "Lunar Base",
|
4 |
+
"final_deliverable": "Operational Base"
|
5 |
+
}
|
src/pitch/test_data/lunar_base-wbs_level2.json
ADDED
@@ -0,0 +1,184 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[
|
2 |
+
{
|
3 |
+
"id": "890d6738-aa20-42e6-a472-c59a188a9cad",
|
4 |
+
"major_phase_title": "Project Initiation & Planning",
|
5 |
+
"subtasks": [
|
6 |
+
{
|
7 |
+
"id": "8bcefb17-013c-45cf-8482-b6a4de629efb",
|
8 |
+
"description": "Define Project Scope and Objectives"
|
9 |
+
},
|
10 |
+
{
|
11 |
+
"id": "b76e3b08-02b2-4490-bf69-8c86febf29a9",
|
12 |
+
"description": "Secure Funding and Resources"
|
13 |
+
},
|
14 |
+
{
|
15 |
+
"id": "9ca53d3d-16ed-4349-93f1-767ee4e9ee4b",
|
16 |
+
"description": "Establish Project Team and Governance"
|
17 |
+
},
|
18 |
+
{
|
19 |
+
"id": "6e16a6a9-5880-41b5-a92b-ef9edfd9b5e3",
|
20 |
+
"description": "Develop Detailed Project Plan"
|
21 |
+
},
|
22 |
+
{
|
23 |
+
"id": "0f9dbae8-654a-4efc-9f4d-3bd946c48bd1",
|
24 |
+
"description": "Conduct Risk Assessment"
|
25 |
+
}
|
26 |
+
]
|
27 |
+
},
|
28 |
+
{
|
29 |
+
"id": "2b65c62b-9149-44ef-a6e2-a5fc28667ce7",
|
30 |
+
"major_phase_title": "Site Selection & Lunar Reconnaissance",
|
31 |
+
"subtasks": [
|
32 |
+
{
|
33 |
+
"id": "13ba1269-63a4-4a6d-9e7d-39581278e338",
|
34 |
+
"description": "Analyze Lunar Reconnaissance Orbiter Data"
|
35 |
+
},
|
36 |
+
{
|
37 |
+
"id": "9a85ae94-1c9d-413a-b39f-712f1ec1b672",
|
38 |
+
"description": "Identify Potential Landing Sites"
|
39 |
+
},
|
40 |
+
{
|
41 |
+
"id": "4261937b-4fc4-4feb-bccd-bb048b25af67",
|
42 |
+
"description": "Model Radiation Exposure Levels"
|
43 |
+
},
|
44 |
+
{
|
45 |
+
"id": "a11410e6-3300-4242-b59d-965a0099dffa",
|
46 |
+
"description": "Assess Lunar Hazards"
|
47 |
+
},
|
48 |
+
{
|
49 |
+
"id": "f23c4fc4-f432-4802-9d38-44762fd045f5",
|
50 |
+
"description": "Select Optimal Landing Site"
|
51 |
+
}
|
52 |
+
]
|
53 |
+
},
|
54 |
+
{
|
55 |
+
"id": "8430c5f9-c0df-42bf-940e-473a4b039f95",
|
56 |
+
"major_phase_title": "Habitat Module Design & Development",
|
57 |
+
"subtasks": [
|
58 |
+
{
|
59 |
+
"id": "6355f874-61d0-4b64-bc1c-7a726702fa2a",
|
60 |
+
"description": "Define Habitat Module Internal Volume"
|
61 |
+
},
|
62 |
+
{
|
63 |
+
"id": "58bb4dd4-f8ab-4022-a3ae-decd734df008",
|
64 |
+
"description": "Design Life Support Systems"
|
65 |
+
},
|
66 |
+
{
|
67 |
+
"id": "aefc27c5-e531-4b98-b975-9d94246aab9d",
|
68 |
+
"description": "Develop Radiation Shielding"
|
69 |
+
},
|
70 |
+
{
|
71 |
+
"id": "18c839b3-c13e-4889-9204-ea91cfc85533",
|
72 |
+
"description": "Design Power Generation System"
|
73 |
+
},
|
74 |
+
{
|
75 |
+
"id": "4d5e1093-c97e-4236-9953-2a001f85b824",
|
76 |
+
"description": "Develop Habitat Module Prototype"
|
77 |
+
}
|
78 |
+
]
|
79 |
+
},
|
80 |
+
{
|
81 |
+
"id": "9da53cb2-533c-458f-8c09-5b0a2de809e3",
|
82 |
+
"major_phase_title": "Equipment & Resource Procurement",
|
83 |
+
"subtasks": [
|
84 |
+
{
|
85 |
+
"id": "8ea81b95-9789-4d28-a617-006b8b0f4ddb",
|
86 |
+
"description": "Procure Advanced Composite Materials"
|
87 |
+
},
|
88 |
+
{
|
89 |
+
"id": "e46984fd-d43a-494e-ae0f-964036115c30",
|
90 |
+
"description": "Acquire Medical Equipment and Medications"
|
91 |
+
},
|
92 |
+
{
|
93 |
+
"id": "72708542-1833-4132-a8e4-06a01264f5f3",
|
94 |
+
"description": "Develop Backup Return Vehicle"
|
95 |
+
},
|
96 |
+
{
|
97 |
+
"id": "3b7f2306-282b-4db0-acbe-015f47b2c02c",
|
98 |
+
"description": "Manufacture Spacesuits"
|
99 |
+
},
|
100 |
+
{
|
101 |
+
"id": "44a22ae3-972e-45a4-8d33-3c7fb2b48129",
|
102 |
+
"description": "Secure Lunar Regolith Samples"
|
103 |
+
}
|
104 |
+
]
|
105 |
+
},
|
106 |
+
{
|
107 |
+
"id": "8d633161-907e-4cc2-9d4d-ab6761f9c269",
|
108 |
+
"major_phase_title": "Launch & Lunar Transportation",
|
109 |
+
"subtasks": [
|
110 |
+
{
|
111 |
+
"id": "262f8926-186c-48c4-97e5-6043894dbe9a",
|
112 |
+
"description": "Prepare Launch Vehicle"
|
113 |
+
},
|
114 |
+
{
|
115 |
+
"id": "6d094c7f-bbd1-4b98-bbdb-5060c175efdb",
|
116 |
+
"description": "Transport Habitat Module to Launch Site"
|
117 |
+
},
|
118 |
+
{
|
119 |
+
"id": "f6c8009d-9e6d-415c-96cf-71d704c27a3e",
|
120 |
+
"description": "Conduct Launch Operations"
|
121 |
+
},
|
122 |
+
{
|
123 |
+
"id": "74b8c707-7fd7-4186-9f34-fbaa4c405458",
|
124 |
+
"description": "Perform Lunar Transfer Orbit Maneuvers"
|
125 |
+
},
|
126 |
+
{
|
127 |
+
"id": "3a603c57-9623-4551-97d1-369231f4ad06",
|
128 |
+
"description": "Execute Lunar Landing"
|
129 |
+
}
|
130 |
+
]
|
131 |
+
},
|
132 |
+
{
|
133 |
+
"id": "d4043460-f75b-47af-a038-3e27d5269c67",
|
134 |
+
"major_phase_title": "Base Construction & Setup",
|
135 |
+
"subtasks": [
|
136 |
+
{
|
137 |
+
"id": "dd0d2912-64f6-4a19-83d9-9bf398841ebf",
|
138 |
+
"description": "Deploy Habitat Module"
|
139 |
+
},
|
140 |
+
{
|
141 |
+
"id": "4724b64a-dd67-4d5f-8ef1-8d3702e46caf",
|
142 |
+
"description": "Install Life Support Systems"
|
143 |
+
},
|
144 |
+
{
|
145 |
+
"id": "56eacb38-081f-4d4b-8b48-4b819fc6745f",
|
146 |
+
"description": "Establish Power Generation"
|
147 |
+
},
|
148 |
+
{
|
149 |
+
"id": "02edd7c0-3c5d-4765-809b-7f1435fc8f16",
|
150 |
+
"description": "Set Up Research Facilities"
|
151 |
+
},
|
152 |
+
{
|
153 |
+
"id": "93f51791-4db6-45b0-a26a-b1851a68b852",
|
154 |
+
"description": "Implement Lunar Dust Mitigation Strategy"
|
155 |
+
}
|
156 |
+
]
|
157 |
+
},
|
158 |
+
{
|
159 |
+
"id": "fdcca24a-3673-444e-85e8-8ef06b17ff1b",
|
160 |
+
"major_phase_title": "Base Operation & Maintenance",
|
161 |
+
"subtasks": [
|
162 |
+
{
|
163 |
+
"id": "77dbba2b-fd2d-41e9-8b7f-fffecfbdb1a4",
|
164 |
+
"description": "Conduct Scientific Research"
|
165 |
+
},
|
166 |
+
{
|
167 |
+
"id": "06f7c01c-c693-48fd-8068-f1c19a0f9f32",
|
168 |
+
"description": "Maintain Life Support Systems"
|
169 |
+
},
|
170 |
+
{
|
171 |
+
"id": "0382ccbd-e3b9-4d90-90a6-3b69450005ac",
|
172 |
+
"description": "Monitor Radiation Levels"
|
173 |
+
},
|
174 |
+
{
|
175 |
+
"id": "d07a7414-2283-4597-ae0f-8db50e87b1c2",
|
176 |
+
"description": "Perform Equipment Maintenance"
|
177 |
+
},
|
178 |
+
{
|
179 |
+
"id": "5e24afc6-84c3-4668-b456-ee43991167cf",
|
180 |
+
"description": "Manage Waste and Resources"
|
181 |
+
}
|
182 |
+
]
|
183 |
+
}
|
184 |
+
]
|
src/plan/data/simple_plan_prompts.jsonl
CHANGED
@@ -3,6 +3,7 @@
|
|
3 |
{"id": "762b64e2-5ac8-4684-807a-efd3e81d6bc1", "prompt": "Create a detailed report examining the current situation of microplastics within the world's oceans.", "tags": ["ocean", "microplastics", "climate change", "sustainability"]}
|
4 |
{"id": "930c2abc-faa7-4c21-8ae1-f0323cbcd120", "prompt": "Open the first space elevator terminal in Berlin, Germany, connecting Earths surface to orbit.", "tags": ["space", "exploration", "berlin", "germany"]}
|
5 |
{"id": "45763178-8ba8-4a86-adcd-63ed19d4d47b", "prompt": "Establish a humanoid robot factory in Paris, France.", "tags": ["paris", "france", "robots"]}
|
|
|
6 |
{"id": "d70ced0b-d5c7-4b84-88d7-18a5ada2cfee", "prompt": "Construct a new metro line under the city center of Copenhagen, Denmark.", "tags": ["denmark", "copenhagen", "metro"]}
|
7 |
{"id": "f24a6ba9-20ce-40bb-866a-263b87b5ddcc", "prompt": "I want to make a restaurant for puzzle solving happy people. An important part is that humans are solving puzzles with each other. While having something to drink and eat.", "tags": ["restaurant", "puzzle", "food"]}
|
8 |
{"id": "da8da7a6-954c-4f88-91c9-53f98a934868", "prompt": "I want a cup of coffee. I have instant coffee and a cup and water. I don't use sugar, milk. I have done it many times before.", "tags": ["small task", "trivial", "coffee"]}
|
|
|
3 |
{"id": "762b64e2-5ac8-4684-807a-efd3e81d6bc1", "prompt": "Create a detailed report examining the current situation of microplastics within the world's oceans.", "tags": ["ocean", "microplastics", "climate change", "sustainability"]}
|
4 |
{"id": "930c2abc-faa7-4c21-8ae1-f0323cbcd120", "prompt": "Open the first space elevator terminal in Berlin, Germany, connecting Earths surface to orbit.", "tags": ["space", "exploration", "berlin", "germany"]}
|
5 |
{"id": "45763178-8ba8-4a86-adcd-63ed19d4d47b", "prompt": "Establish a humanoid robot factory in Paris, France.", "tags": ["paris", "france", "robots"]}
|
6 |
+
{"id": "67c461a9-3364-42a4-bf8f-643315abfcf6", "prompt": "When I die, I want to become a skeleton, skull and bones. I love zombies.", "tags": ["death", "bones", "post-mortem", "zoombie"]}
|
7 |
{"id": "d70ced0b-d5c7-4b84-88d7-18a5ada2cfee", "prompt": "Construct a new metro line under the city center of Copenhagen, Denmark.", "tags": ["denmark", "copenhagen", "metro"]}
|
8 |
{"id": "f24a6ba9-20ce-40bb-866a-263b87b5ddcc", "prompt": "I want to make a restaurant for puzzle solving happy people. An important part is that humans are solving puzzles with each other. While having something to drink and eat.", "tags": ["restaurant", "puzzle", "food"]}
|
9 |
{"id": "da8da7a6-954c-4f88-91c9-53f98a934868", "prompt": "I want a cup of coffee. I have instant coffee and a cup and water. I don't use sugar, milk. I have done it many times before.", "tags": ["small task", "trivial", "coffee"]}
|
src/plan/estimate_wbs_task_durations.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1 |
"""
|
2 |
https://en.wikipedia.org/wiki/Work_breakdown_structure
|
|
|
3 |
"""
|
4 |
import os
|
5 |
import json
|
|
|
1 |
"""
|
2 |
https://en.wikipedia.org/wiki/Work_breakdown_structure
|
3 |
+
https://en.wikipedia.org/wiki/Program_evaluation_and_review_technique
|
4 |
"""
|
5 |
import os
|
6 |
import json
|
src/plan/filenames.py
CHANGED
@@ -2,29 +2,32 @@ from enum import Enum
|
|
2 |
|
3 |
class FilenameEnum(str, Enum):
|
4 |
INITIAL_PLAN = "001-plan.txt"
|
5 |
-
MAKE_ASSUMPTIONS_RAW = "002-make_assumptions_raw.json"
|
6 |
-
MAKE_ASSUMPTIONS = "
|
7 |
-
DISTILL_ASSUMPTIONS_RAW = "
|
8 |
-
PRE_PROJECT_ASSESSMENT_RAW = "
|
9 |
-
PRE_PROJECT_ASSESSMENT = "
|
10 |
-
PROJECT_PLAN = "
|
11 |
-
SWOT_RAW = "
|
12 |
-
SWOT_MARKDOWN = "
|
13 |
-
EXPERTS_RAW = "
|
14 |
-
EXPERTS_CLEAN = "
|
15 |
-
EXPERT_CRITICISM_RAW_TEMPLATE = "
|
16 |
-
EXPERT_CRITICISM_MARKDOWN = "
|
17 |
-
WBS_LEVEL1_RAW = "
|
18 |
-
WBS_LEVEL1 = "
|
19 |
-
WBS_LEVEL2_RAW = "
|
20 |
-
WBS_LEVEL2 = "
|
21 |
-
WBS_PROJECT_LEVEL1_AND_LEVEL2 = "
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
|
|
|
|
|
|
30 |
PIPELINE_COMPLETE = "999-pipeline_complete.txt"
|
|
|
2 |
|
3 |
class FilenameEnum(str, Enum):
|
4 |
INITIAL_PLAN = "001-plan.txt"
|
5 |
+
MAKE_ASSUMPTIONS_RAW = "002-1-make_assumptions_raw.json"
|
6 |
+
MAKE_ASSUMPTIONS = "002-2-make_assumptions.json"
|
7 |
+
DISTILL_ASSUMPTIONS_RAW = "003-distill_assumptions.json"
|
8 |
+
PRE_PROJECT_ASSESSMENT_RAW = "004-1-pre_project_assessment_raw.json"
|
9 |
+
PRE_PROJECT_ASSESSMENT = "004-2-pre_project_assessment.json"
|
10 |
+
PROJECT_PLAN = "005-project_plan.json"
|
11 |
+
SWOT_RAW = "006-1-swot_analysis_raw.json"
|
12 |
+
SWOT_MARKDOWN = "006-2-swot_analysis.md"
|
13 |
+
EXPERTS_RAW = "007-1-experts_raw.json"
|
14 |
+
EXPERTS_CLEAN = "007-2-experts.json"
|
15 |
+
EXPERT_CRITICISM_RAW_TEMPLATE = "008-1-{}-expert_criticism_raw.json"
|
16 |
+
EXPERT_CRITICISM_MARKDOWN = "008-2-expert_criticism.md"
|
17 |
+
WBS_LEVEL1_RAW = "009-1-wbs_level1_raw.json"
|
18 |
+
WBS_LEVEL1 = "009-2-wbs_level1.json"
|
19 |
+
WBS_LEVEL2_RAW = "010-1-wbs_level2_raw.json"
|
20 |
+
WBS_LEVEL2 = "010-2-wbs_level2.json"
|
21 |
+
WBS_PROJECT_LEVEL1_AND_LEVEL2 = "011-wbs_project_level1_and_level2.json"
|
22 |
+
PITCH_RAW = "012-1-pitch_raw.json"
|
23 |
+
PITCH_CONVERT_TO_MARKDOWN_RAW = "012-2-pitch_to_markdown_raw.json"
|
24 |
+
PITCH_MARKDOWN = "012-3-pitch.md"
|
25 |
+
TASK_DEPENDENCIES_RAW = "013-task_dependencies_raw.json"
|
26 |
+
TASK_DURATIONS_RAW_TEMPLATE = "014-1-{}-task_durations_raw.json"
|
27 |
+
TASK_DURATIONS = "014-2-task_durations.json"
|
28 |
+
WBS_LEVEL3_RAW_TEMPLATE = "015-1-{}-wbs_level3_raw.json"
|
29 |
+
WBS_LEVEL3 = "015-2-wbs_level3.json"
|
30 |
+
WBS_PROJECT_LEVEL1_AND_LEVEL2_AND_LEVEL3_FULL = "015-3-wbs_project_level1_and_level2_and_level3.json"
|
31 |
+
WBS_PROJECT_LEVEL1_AND_LEVEL2_AND_LEVEL3_CSV = "015-4-wbs_project_level1_and_level2_and_level3.csv"
|
32 |
+
REPORT = "016-report.html"
|
33 |
PIPELINE_COMPLETE = "999-pipeline_complete.txt"
|
src/plan/run_plan_pipeline.py
CHANGED
@@ -1,5 +1,10 @@
|
|
1 |
"""
|
2 |
PROMPT> python -m src.plan.run_plan_pipeline
|
|
|
|
|
|
|
|
|
|
|
3 |
"""
|
4 |
from datetime import datetime
|
5 |
import logging
|
@@ -22,7 +27,8 @@ from src.expert.expert_orchestrator import ExpertOrchestrator
|
|
22 |
from src.plan.create_wbs_level1 import CreateWBSLevel1
|
23 |
from src.plan.create_wbs_level2 import CreateWBSLevel2
|
24 |
from src.plan.create_wbs_level3 import CreateWBSLevel3
|
25 |
-
from src.
|
|
|
26 |
from src.plan.identify_wbs_task_dependencies import IdentifyWBSTaskDependencies
|
27 |
from src.plan.estimate_wbs_task_durations import EstimateWBSTaskDurations
|
28 |
from src.wbs.wbs_task import WBSTask, WBSProject
|
@@ -30,6 +36,7 @@ from src.wbs.wbs_populate import WBSPopulate
|
|
30 |
from src.llm_factory import get_llm
|
31 |
from src.format_json_for_use_in_query import format_json_for_use_in_query
|
32 |
from src.utils.get_env_as_string import get_env_as_string
|
|
|
33 |
|
34 |
logger = logging.getLogger(__name__)
|
35 |
DEFAULT_LLM_MODEL = "ollama-llama3.1"
|
@@ -496,7 +503,7 @@ class CreatePitchTask(PlanTask):
|
|
496 |
llm_model = luigi.Parameter(default=DEFAULT_LLM_MODEL)
|
497 |
|
498 |
def output(self):
|
499 |
-
return luigi.LocalTarget(str(self.file_path(FilenameEnum.
|
500 |
|
501 |
def requires(self):
|
502 |
return {
|
@@ -536,6 +543,50 @@ class CreatePitchTask(PlanTask):
|
|
536 |
|
537 |
logger.info("Pitch created and written to %s", self.output().path)
|
538 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
539 |
class IdentifyTaskDependenciesTask(PlanTask):
|
540 |
"""
|
541 |
This task identifies the dependencies between WBS tasks.
|
@@ -820,6 +871,37 @@ class WBSProjectLevel1AndLevel2AndLevel3Task(PlanTask):
|
|
820 |
with self.output()['csv'].open("w") as f:
|
821 |
f.write(csv_representation)
|
822 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
823 |
class FullPlanPipeline(PlanTask):
|
824 |
llm_model = luigi.Parameter(default=DEFAULT_LLM_MODEL)
|
825 |
|
@@ -834,11 +916,13 @@ class FullPlanPipeline(PlanTask):
|
|
834 |
'wbs_level1': CreateWBSLevel1Task(run_id=self.run_id, speedvsdetail=self.speedvsdetail, llm_model=self.llm_model),
|
835 |
'wbs_level2': CreateWBSLevel2Task(run_id=self.run_id, speedvsdetail=self.speedvsdetail, llm_model=self.llm_model),
|
836 |
'wbs_project12': WBSProjectLevel1AndLevel2Task(run_id=self.run_id, speedvsdetail=self.speedvsdetail, llm_model=self.llm_model),
|
837 |
-
'
|
|
|
838 |
'dependencies': IdentifyTaskDependenciesTask(run_id=self.run_id, speedvsdetail=self.speedvsdetail, llm_model=self.llm_model),
|
839 |
'durations': EstimateTaskDurationsTask(run_id=self.run_id, speedvsdetail=self.speedvsdetail, llm_model=self.llm_model),
|
840 |
'wbs_level3': CreateWBSLevel3Task(run_id=self.run_id, speedvsdetail=self.speedvsdetail, llm_model=self.llm_model),
|
841 |
'wbs_project123': WBSProjectLevel1AndLevel2AndLevel3Task(run_id=self.run_id, speedvsdetail=self.speedvsdetail, llm_model=self.llm_model),
|
|
|
842 |
}
|
843 |
|
844 |
def output(self):
|
|
|
1 |
"""
|
2 |
PROMPT> python -m src.plan.run_plan_pipeline
|
3 |
+
|
4 |
+
In order to resume an unfinished run.
|
5 |
+
Insert the run_id of the thing you want to resume.
|
6 |
+
If it's an already finished run, then remove the "999-pipeline_complete.txt" file.
|
7 |
+
PROMPT> RUN_ID=PlanExe_20250216_150332 python -m src.plan.run_plan_pipeline
|
8 |
"""
|
9 |
from datetime import datetime
|
10 |
import logging
|
|
|
27 |
from src.plan.create_wbs_level1 import CreateWBSLevel1
|
28 |
from src.plan.create_wbs_level2 import CreateWBSLevel2
|
29 |
from src.plan.create_wbs_level3 import CreateWBSLevel3
|
30 |
+
from src.pitch.create_pitch import CreatePitch
|
31 |
+
from src.pitch.convert_pitch_to_markdown import ConvertPitchToMarkdown
|
32 |
from src.plan.identify_wbs_task_dependencies import IdentifyWBSTaskDependencies
|
33 |
from src.plan.estimate_wbs_task_durations import EstimateWBSTaskDurations
|
34 |
from src.wbs.wbs_task import WBSTask, WBSProject
|
|
|
36 |
from src.llm_factory import get_llm
|
37 |
from src.format_json_for_use_in_query import format_json_for_use_in_query
|
38 |
from src.utils.get_env_as_string import get_env_as_string
|
39 |
+
from src.report.report_generator import ReportGenerator
|
40 |
|
41 |
logger = logging.getLogger(__name__)
|
42 |
DEFAULT_LLM_MODEL = "ollama-llama3.1"
|
|
|
503 |
llm_model = luigi.Parameter(default=DEFAULT_LLM_MODEL)
|
504 |
|
505 |
def output(self):
|
506 |
+
return luigi.LocalTarget(str(self.file_path(FilenameEnum.PITCH_RAW)))
|
507 |
|
508 |
def requires(self):
|
509 |
return {
|
|
|
543 |
|
544 |
logger.info("Pitch created and written to %s", self.output().path)
|
545 |
|
546 |
+
class ConvertPitchToMarkdownTask(PlanTask):
|
547 |
+
"""
|
548 |
+
Human readable version of the pitch.
|
549 |
+
|
550 |
+
This task depends on:
|
551 |
+
- CreatePitchTask: Creates the pitch JSON.
|
552 |
+
"""
|
553 |
+
llm_model = luigi.Parameter(default=DEFAULT_LLM_MODEL)
|
554 |
+
|
555 |
+
def output(self):
|
556 |
+
return {
|
557 |
+
'raw': luigi.LocalTarget(str(self.file_path(FilenameEnum.PITCH_CONVERT_TO_MARKDOWN_RAW))),
|
558 |
+
'markdown': luigi.LocalTarget(str(self.file_path(FilenameEnum.PITCH_MARKDOWN)))
|
559 |
+
}
|
560 |
+
|
561 |
+
def requires(self):
|
562 |
+
return {
|
563 |
+
'pitch': CreatePitchTask(run_id=self.run_id, speedvsdetail=self.speedvsdetail, llm_model=self.llm_model),
|
564 |
+
}
|
565 |
+
|
566 |
+
def run(self):
|
567 |
+
logger.info("Converting raw pitch to markdown...")
|
568 |
+
|
569 |
+
# Read the project plan JSON.
|
570 |
+
with self.input()['pitch'].open("r") as f:
|
571 |
+
pitch_json = json.load(f)
|
572 |
+
|
573 |
+
# Build the query
|
574 |
+
query = format_json_for_use_in_query(pitch_json)
|
575 |
+
|
576 |
+
# Get the LLM instance.
|
577 |
+
llm = get_llm(self.llm_model)
|
578 |
+
|
579 |
+
# Execute the convertion.
|
580 |
+
converted = ConvertPitchToMarkdown.execute(llm, query)
|
581 |
+
|
582 |
+
# Save the results.
|
583 |
+
json_path = self.output()['raw'].path
|
584 |
+
converted.save_raw(json_path)
|
585 |
+
markdown_path = self.output()['markdown'].path
|
586 |
+
converted.save_markdown(markdown_path)
|
587 |
+
|
588 |
+
logger.info("Converted raw pitch to markdown.")
|
589 |
+
|
590 |
class IdentifyTaskDependenciesTask(PlanTask):
|
591 |
"""
|
592 |
This task identifies the dependencies between WBS tasks.
|
|
|
871 |
with self.output()['csv'].open("w") as f:
|
872 |
f.write(csv_representation)
|
873 |
|
874 |
+
class ReportTask(PlanTask):
|
875 |
+
"""
|
876 |
+
Generate a report html document.
|
877 |
+
|
878 |
+
It depends on:
|
879 |
+
- SWOTAnalysisTask: provides the SWOT analysis as Markdown.
|
880 |
+
- ConvertPitchToMarkdownTask: provides the pitch as Markdown.
|
881 |
+
- WBSProjectLevel1AndLevel2AndLevel3Task: provides the table csv file.
|
882 |
+
- ExpertReviewTask: provides the expert criticism as Markdown.
|
883 |
+
"""
|
884 |
+
llm_model = luigi.Parameter(default=DEFAULT_LLM_MODEL)
|
885 |
+
|
886 |
+
def output(self):
|
887 |
+
return luigi.LocalTarget(str(self.file_path(FilenameEnum.REPORT)))
|
888 |
+
|
889 |
+
def requires(self):
|
890 |
+
return {
|
891 |
+
'swot_analysis': SWOTAnalysisTask(run_id=self.run_id, speedvsdetail=self.speedvsdetail, llm_model=self.llm_model),
|
892 |
+
'pitch_markdown': ConvertPitchToMarkdownTask(run_id=self.run_id, speedvsdetail=self.speedvsdetail, llm_model=self.llm_model),
|
893 |
+
'wbs_project123': WBSProjectLevel1AndLevel2AndLevel3Task(run_id=self.run_id, speedvsdetail=self.speedvsdetail, llm_model=self.llm_model),
|
894 |
+
'expert_review': ExpertReviewTask(run_id=self.run_id, speedvsdetail=self.speedvsdetail, llm_model=self.llm_model)
|
895 |
+
}
|
896 |
+
|
897 |
+
def run(self):
|
898 |
+
rg = ReportGenerator()
|
899 |
+
rg.append_pitch_markdown(self.input()['pitch_markdown']['markdown'].path)
|
900 |
+
rg.append_swot_analysis_markdown(self.input()['swot_analysis']['markdown'].path)
|
901 |
+
rg.append_project_plan_csv(self.input()['wbs_project123']['csv'].path)
|
902 |
+
rg.append_expert_criticism_markdown(self.input()['expert_review'].path)
|
903 |
+
rg.save_report(self.output().path)
|
904 |
+
|
905 |
class FullPlanPipeline(PlanTask):
|
906 |
llm_model = luigi.Parameter(default=DEFAULT_LLM_MODEL)
|
907 |
|
|
|
916 |
'wbs_level1': CreateWBSLevel1Task(run_id=self.run_id, speedvsdetail=self.speedvsdetail, llm_model=self.llm_model),
|
917 |
'wbs_level2': CreateWBSLevel2Task(run_id=self.run_id, speedvsdetail=self.speedvsdetail, llm_model=self.llm_model),
|
918 |
'wbs_project12': WBSProjectLevel1AndLevel2Task(run_id=self.run_id, speedvsdetail=self.speedvsdetail, llm_model=self.llm_model),
|
919 |
+
'pitch_raw': CreatePitchTask(run_id=self.run_id, speedvsdetail=self.speedvsdetail, llm_model=self.llm_model),
|
920 |
+
'pitch_markdown': ConvertPitchToMarkdownTask(run_id=self.run_id, speedvsdetail=self.speedvsdetail, llm_model=self.llm_model),
|
921 |
'dependencies': IdentifyTaskDependenciesTask(run_id=self.run_id, speedvsdetail=self.speedvsdetail, llm_model=self.llm_model),
|
922 |
'durations': EstimateTaskDurationsTask(run_id=self.run_id, speedvsdetail=self.speedvsdetail, llm_model=self.llm_model),
|
923 |
'wbs_level3': CreateWBSLevel3Task(run_id=self.run_id, speedvsdetail=self.speedvsdetail, llm_model=self.llm_model),
|
924 |
'wbs_project123': WBSProjectLevel1AndLevel2AndLevel3Task(run_id=self.run_id, speedvsdetail=self.speedvsdetail, llm_model=self.llm_model),
|
925 |
+
'report': ReportTask(run_id=self.run_id, speedvsdetail=self.speedvsdetail, llm_model=self.llm_model),
|
926 |
}
|
927 |
|
928 |
def output(self):
|
src/report/README.md
ADDED
@@ -0,0 +1,79 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# PlanExe Report Generator
|
2 |
+
|
3 |
+
A tool to generate a beautiful HTML report from PlanExe output files.
|
4 |
+
|
5 |
+
## Features
|
6 |
+
|
7 |
+
- Combines all important PlanExe output files into a single HTML report
|
8 |
+
- Includes:
|
9 |
+
- Project Pitch
|
10 |
+
- SWOT Analysis
|
11 |
+
- Expert Criticism
|
12 |
+
- Complete Project Plan
|
13 |
+
- Automatically opens the report in your default web browser
|
14 |
+
- Responsive design for easy reading
|
15 |
+
- Clean, professional formatting
|
16 |
+
|
17 |
+
## Usage
|
18 |
+
|
19 |
+
### Generate report and open in browser
|
20 |
+
```bash
|
21 |
+
python -m src.report.report_generator /path/to/planexe/output/directory
|
22 |
+
```
|
23 |
+
|
24 |
+
### Generate report without opening it in the browser
|
25 |
+
```bash
|
26 |
+
python -m src.report.report_generator /path/to/planexe/output/directory --no-browser
|
27 |
+
```
|
28 |
+
|
29 |
+
## Report Contents
|
30 |
+
|
31 |
+
The generated report includes:
|
32 |
+
|
33 |
+
1. **Project Pitch**
|
34 |
+
- Summary of the project
|
35 |
+
- Key project points
|
36 |
+
|
37 |
+
2. **SWOT Analysis**
|
38 |
+
- Strengths
|
39 |
+
- Weaknesses
|
40 |
+
- Opportunities
|
41 |
+
- Threats
|
42 |
+
|
43 |
+
3. **Expert Criticism**
|
44 |
+
- Detailed feedback from experts
|
45 |
+
- Potential issues and considerations
|
46 |
+
|
47 |
+
4. **Project Plan**
|
48 |
+
- Complete Work Breakdown Structure (WBS)
|
49 |
+
- Task dependencies
|
50 |
+
- Duration estimates
|
51 |
+
|
52 |
+
## Example
|
53 |
+
|
54 |
+
If your PlanExe output is in `/home/user/my_project/planexe_dir`, run:
|
55 |
+
```bash
|
56 |
+
python -m src.report.report_generator /home/user/my_project/planexe_dir
|
57 |
+
```
|
58 |
+
|
59 |
+
This will:
|
60 |
+
1. Generate a report named `report.html` in the specified directory
|
61 |
+
2. Automatically open the report in your default web browser
|
62 |
+
|
63 |
+
## Troubleshooting
|
64 |
+
|
65 |
+
1. **Missing Files**
|
66 |
+
- The script will warn you about any missing files
|
67 |
+
- The report will still generate with available data
|
68 |
+
|
69 |
+
2. **Browser doesn't open**
|
70 |
+
- The report is still generated
|
71 |
+
- Manually open the HTML file from the output directory
|
72 |
+
|
73 |
+
3. **Invalid JSON**
|
74 |
+
- Check if the JSON files are properly formatted
|
75 |
+
- The script will skip invalid files and continue with valid ones
|
76 |
+
|
77 |
+
## Contributing
|
78 |
+
|
79 |
+
Feel free to submit issues and enhancement requests!
|
src/report/__init__.py
ADDED
File without changes
|
src/{report_generator.py → report/report_generator.py}
RENAMED
@@ -1,69 +1,50 @@
|
|
1 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
import json
|
3 |
-
import
|
4 |
import pandas as pd
|
5 |
from pathlib import Path
|
6 |
from datetime import datetime
|
7 |
import markdown
|
8 |
from typing import Dict, Any, Optional
|
9 |
-
import zipfile
|
10 |
-
import tempfile
|
11 |
-
import shutil
|
12 |
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
self.report_data = {}
|
18 |
-
self.temp_dir = None
|
19 |
-
self.working_dir = None
|
20 |
|
21 |
-
def
|
22 |
-
"""Set up the working directory, extracting zip if necessary."""
|
23 |
-
if self.input_path.is_file() and self.input_path.suffix == '.zip':
|
24 |
-
# Create a temporary directory
|
25 |
-
self.temp_dir = tempfile.mkdtemp()
|
26 |
-
# Extract the zip file
|
27 |
-
with zipfile.ZipFile(self.input_path, 'r') as zip_ref:
|
28 |
-
zip_ref.extractall(self.temp_dir)
|
29 |
-
# Find the actual directory containing the files
|
30 |
-
contents = list(Path(self.temp_dir).iterdir())
|
31 |
-
self.working_dir = contents[0] if len(contents) == 1 and contents[0].is_dir() else Path(self.temp_dir)
|
32 |
-
else:
|
33 |
-
self.working_dir = self.input_path
|
34 |
-
return self
|
35 |
-
|
36 |
-
def __exit__(self, exc_type, exc_val, exc_tb):
|
37 |
-
"""Clean up temporary directory if it exists."""
|
38 |
-
if self.temp_dir:
|
39 |
-
shutil.rmtree(self.temp_dir)
|
40 |
-
|
41 |
-
def read_json_file(self, filename: str) -> Optional[Dict[str, Any]]:
|
42 |
"""Read a JSON file and return its contents."""
|
43 |
try:
|
44 |
-
with open(
|
45 |
return json.load(f)
|
46 |
except FileNotFoundError:
|
47 |
-
|
48 |
return None
|
49 |
except json.JSONDecodeError:
|
50 |
-
|
51 |
return None
|
52 |
|
53 |
-
def read_markdown_file(self,
|
54 |
"""Read a markdown file and return its contents."""
|
55 |
try:
|
56 |
-
with open(
|
57 |
return f.read()
|
58 |
except FileNotFoundError:
|
59 |
-
|
60 |
return None
|
61 |
|
62 |
-
def read_csv_file(self,
|
63 |
"""Read a CSV file and return its contents as a pandas DataFrame."""
|
64 |
try:
|
65 |
# First try to detect the delimiter by reading the first few lines
|
66 |
-
with open(
|
67 |
first_line = f.readline().strip()
|
68 |
|
69 |
# Count potential delimiters
|
@@ -79,45 +60,47 @@ class PlanExeReport:
|
|
79 |
|
80 |
# Try reading with the detected delimiter
|
81 |
try:
|
82 |
-
df = pd.read_csv(
|
83 |
return df
|
84 |
except:
|
85 |
# If that fails, try with more options
|
86 |
try:
|
87 |
-
df = pd.read_csv(
|
88 |
on_bad_lines='skip', engine='python')
|
89 |
-
|
90 |
return df
|
91 |
except Exception as e:
|
92 |
-
|
93 |
return None
|
94 |
|
95 |
except FileNotFoundError:
|
96 |
-
|
97 |
return None
|
98 |
except Exception as e:
|
99 |
-
|
100 |
return None
|
101 |
|
102 |
-
def
|
103 |
-
"""
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
swot_md = self.read_markdown_file(
|
111 |
if swot_md:
|
112 |
self.report_data['swot'] = swot_md
|
113 |
-
|
114 |
-
|
115 |
-
|
|
|
116 |
if expert_md:
|
117 |
self.report_data['expert_criticism'] = expert_md
|
118 |
-
|
119 |
-
|
120 |
-
|
|
|
121 |
if plan_df is not None:
|
122 |
# Clean up the dataframe
|
123 |
# Remove any completely empty rows or columns
|
@@ -207,7 +190,6 @@ class PlanExeReport:
|
|
207 |
html_parts.append(f"""
|
208 |
<h1>PlanExe Project Report</h1>
|
209 |
<p class="timestamp">Generated on: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</p>
|
210 |
-
<p class="source-info">Source: {self.input_path.name}</p>
|
211 |
""")
|
212 |
|
213 |
# Project Pitch
|
@@ -216,11 +198,7 @@ class PlanExeReport:
|
|
216 |
<div class="section">
|
217 |
<h2>Project Pitch</h2>
|
218 |
""")
|
219 |
-
|
220 |
-
if isinstance(pitch, dict):
|
221 |
-
for key, value in pitch.items():
|
222 |
-
html_parts.append(f"<h3>{key.replace('_', ' ').title()}</h3>")
|
223 |
-
html_parts.append(f"<p>{value}</p>")
|
224 |
html_parts.append("</div>")
|
225 |
|
226 |
# SWOT Analysis
|
@@ -259,37 +237,32 @@ class PlanExeReport:
|
|
259 |
|
260 |
return '\n'.join(html_parts)
|
261 |
|
262 |
-
def save_report(self, output_path:
|
263 |
"""Generate and save the report."""
|
264 |
-
self.gather_data()
|
265 |
html_report = self.generate_html_report()
|
266 |
|
267 |
-
if output_path:
|
268 |
-
output_path = Path(output_path).resolve() # Convert to absolute path
|
269 |
-
else:
|
270 |
-
# Generate output filename based on input filename
|
271 |
-
stem = self.input_path.stem
|
272 |
-
if self.input_path.suffix == '.zip':
|
273 |
-
stem = stem.split('_')[0] # Remove timestamp from filename if present
|
274 |
-
output_path = self.input_path.parent.resolve() / f"{stem}_report.html" # Use absolute path
|
275 |
-
|
276 |
-
# Create parent directories if they don't exist
|
277 |
-
output_path.parent.mkdir(parents=True, exist_ok=True)
|
278 |
-
|
279 |
with open(output_path, 'w', encoding='utf-8') as f:
|
280 |
f.write(html_report)
|
281 |
|
282 |
-
|
283 |
-
return output_path
|
284 |
|
285 |
def main():
|
|
|
286 |
import argparse
|
287 |
parser = argparse.ArgumentParser(description='Generate a report from PlanExe output (zip file or directory)')
|
288 |
parser.add_argument('input_path', help='Path to PlanExe output zip file or directory')
|
289 |
-
parser.add_argument('--output', '-o', help='Output filename (optional)')
|
290 |
parser.add_argument('--no-browser', action='store_true', help='Do not open browser automatically')
|
291 |
|
292 |
args = parser.parse_args()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
293 |
|
294 |
# Convert input path to absolute path
|
295 |
input_path = Path(args.input_path).resolve()
|
@@ -298,23 +271,29 @@ def main():
|
|
298 |
print(f"Error: Input path does not exist: {input_path}")
|
299 |
return
|
300 |
|
301 |
-
|
302 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
303 |
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
print(f"Please open this file in your web browser:")
|
313 |
-
print(f" {report_path}")
|
314 |
-
except Exception as e:
|
315 |
-
print(f"Error opening browser: {e}")
|
316 |
print(f"Please open this file in your web browser:")
|
317 |
-
print(f" {
|
|
|
|
|
|
|
|
|
318 |
|
319 |
if __name__ == "__main__":
|
320 |
-
main()
|
|
|
1 |
+
"""
|
2 |
+
This generates the report and afterwards opens it in the browser.
|
3 |
+
PROMPT> python -m src.report.report_generator /path/to/PlanExe_20250216_dir
|
4 |
+
|
5 |
+
This generates the report without opening the browser.
|
6 |
+
PROMPT> python -m src.report.report_generator /path/to/PlanExe_20250216_dir --no-browser
|
7 |
+
"""
|
8 |
import json
|
9 |
+
import logging
|
10 |
import pandas as pd
|
11 |
from pathlib import Path
|
12 |
from datetime import datetime
|
13 |
import markdown
|
14 |
from typing import Dict, Any, Optional
|
|
|
|
|
|
|
15 |
|
16 |
+
logger = logging.getLogger(__name__)
|
17 |
+
|
18 |
+
class ReportGenerator:
|
19 |
+
def __init__(self):
|
20 |
self.report_data = {}
|
|
|
|
|
21 |
|
22 |
+
def read_json_file(self, file_path: Path) -> Optional[Dict[str, Any]]:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
"""Read a JSON file and return its contents."""
|
24 |
try:
|
25 |
+
with open(file_path, 'r') as f:
|
26 |
return json.load(f)
|
27 |
except FileNotFoundError:
|
28 |
+
logging.warning(f"{file_path} not found")
|
29 |
return None
|
30 |
except json.JSONDecodeError:
|
31 |
+
logging.warning(f"{file_path} contains invalid JSON")
|
32 |
return None
|
33 |
|
34 |
+
def read_markdown_file(self, file_path: Path) -> Optional[str]:
|
35 |
"""Read a markdown file and return its contents."""
|
36 |
try:
|
37 |
+
with open(file_path, 'r') as f:
|
38 |
return f.read()
|
39 |
except FileNotFoundError:
|
40 |
+
logging.warning(f"{file_path} not found")
|
41 |
return None
|
42 |
|
43 |
+
def read_csv_file(self, file_path: Path) -> Optional[pd.DataFrame]:
|
44 |
"""Read a CSV file and return its contents as a pandas DataFrame."""
|
45 |
try:
|
46 |
# First try to detect the delimiter by reading the first few lines
|
47 |
+
with open(file_path, 'r') as f:
|
48 |
first_line = f.readline().strip()
|
49 |
|
50 |
# Count potential delimiters
|
|
|
60 |
|
61 |
# Try reading with the detected delimiter
|
62 |
try:
|
63 |
+
df = pd.read_csv(file_path, delimiter=delimiter)
|
64 |
return df
|
65 |
except:
|
66 |
# If that fails, try with more options
|
67 |
try:
|
68 |
+
df = pd.read_csv(file_path, delimiter=delimiter,
|
69 |
on_bad_lines='skip', engine='python')
|
70 |
+
logging.warning(f"Some lines in {file_path} were skipped due to parsing errors")
|
71 |
return df
|
72 |
except Exception as e:
|
73 |
+
logging.error(f"Error reading CSV file {file_path}: {str(e)}")
|
74 |
return None
|
75 |
|
76 |
except FileNotFoundError:
|
77 |
+
logging.error(f"{file_path} not found")
|
78 |
return None
|
79 |
except Exception as e:
|
80 |
+
logging.error(f"Error reading CSV file {file_path}: {str(e)}")
|
81 |
return None
|
82 |
|
83 |
+
def append_pitch_markdown(self, file_path: Path):
|
84 |
+
"""Append the pitch markdown to the report."""
|
85 |
+
pitch_md = self.read_markdown_file(file_path)
|
86 |
+
if pitch_md:
|
87 |
+
self.report_data['pitch'] = pitch_md
|
88 |
+
|
89 |
+
def append_swot_analysis_markdown(self, file_path: Path):
|
90 |
+
"""Append the SWOT markdown to the report."""
|
91 |
+
swot_md = self.read_markdown_file(file_path)
|
92 |
if swot_md:
|
93 |
self.report_data['swot'] = swot_md
|
94 |
+
|
95 |
+
def append_expert_criticism_markdown(self, file_path: Path):
|
96 |
+
"""Append the expert criticism markdown to the report."""
|
97 |
+
expert_md = self.read_markdown_file(file_path)
|
98 |
if expert_md:
|
99 |
self.report_data['expert_criticism'] = expert_md
|
100 |
+
|
101 |
+
def append_project_plan_csv(self, file_path: Path):
|
102 |
+
"""Append the project plan CSV to the report."""
|
103 |
+
plan_df = self.read_csv_file(file_path)
|
104 |
if plan_df is not None:
|
105 |
# Clean up the dataframe
|
106 |
# Remove any completely empty rows or columns
|
|
|
190 |
html_parts.append(f"""
|
191 |
<h1>PlanExe Project Report</h1>
|
192 |
<p class="timestamp">Generated on: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</p>
|
|
|
193 |
""")
|
194 |
|
195 |
# Project Pitch
|
|
|
198 |
<div class="section">
|
199 |
<h2>Project Pitch</h2>
|
200 |
""")
|
201 |
+
html_parts.append(markdown.markdown(self.report_data['pitch']))
|
|
|
|
|
|
|
|
|
202 |
html_parts.append("</div>")
|
203 |
|
204 |
# SWOT Analysis
|
|
|
237 |
|
238 |
return '\n'.join(html_parts)
|
239 |
|
240 |
+
def save_report(self, output_path: Path) -> None:
|
241 |
"""Generate and save the report."""
|
|
|
242 |
html_report = self.generate_html_report()
|
243 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
244 |
with open(output_path, 'w', encoding='utf-8') as f:
|
245 |
f.write(html_report)
|
246 |
|
247 |
+
logger.info(f"Report generated successfully: {output_path}")
|
|
|
248 |
|
249 |
def main():
|
250 |
+
from src.plan.filenames import FilenameEnum
|
251 |
import argparse
|
252 |
parser = argparse.ArgumentParser(description='Generate a report from PlanExe output (zip file or directory)')
|
253 |
parser.add_argument('input_path', help='Path to PlanExe output zip file or directory')
|
|
|
254 |
parser.add_argument('--no-browser', action='store_true', help='Do not open browser automatically')
|
255 |
|
256 |
args = parser.parse_args()
|
257 |
+
|
258 |
+
logging.basicConfig(
|
259 |
+
level=logging.INFO,
|
260 |
+
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
261 |
+
handlers=[
|
262 |
+
logging.StreamHandler()
|
263 |
+
]
|
264 |
+
)
|
265 |
+
|
266 |
|
267 |
# Convert input path to absolute path
|
268 |
input_path = Path(args.input_path).resolve()
|
|
|
271 |
print(f"Error: Input path does not exist: {input_path}")
|
272 |
return
|
273 |
|
274 |
+
output_path = input_path / FilenameEnum.REPORT.value
|
275 |
+
|
276 |
+
report_generator = ReportGenerator()
|
277 |
+
report_generator.append_pitch_markdown(input_path / FilenameEnum.PITCH_MARKDOWN.value)
|
278 |
+
report_generator.append_swot_analysis_markdown(input_path / FilenameEnum.SWOT_MARKDOWN.value)
|
279 |
+
report_generator.append_expert_criticism_markdown(input_path / FilenameEnum.EXPERT_CRITICISM_MARKDOWN.value)
|
280 |
+
report_generator.append_project_plan_csv(input_path / FilenameEnum.WBS_PROJECT_LEVEL1_AND_LEVEL2_AND_LEVEL3_CSV.value)
|
281 |
+
report_generator.save_report(output_path)
|
282 |
|
283 |
+
if not args.no_browser:
|
284 |
+
# Try to open the report in the default browser
|
285 |
+
try:
|
286 |
+
import webbrowser
|
287 |
+
url = f'file://{output_path.absolute()}'
|
288 |
+
print(f"Opening report in browser: {url}")
|
289 |
+
if not webbrowser.open(url):
|
290 |
+
print(f"Could not open browser automatically.")
|
|
|
|
|
|
|
|
|
291 |
print(f"Please open this file in your web browser:")
|
292 |
+
print(f" {output_path}")
|
293 |
+
except Exception as e:
|
294 |
+
print(f"Error opening browser: {e}")
|
295 |
+
print(f"Please open this file in your web browser:")
|
296 |
+
print(f" {output_path}")
|
297 |
|
298 |
if __name__ == "__main__":
|
299 |
+
main()
|