Simon Strandgaard commited on
Commit
767b265
·
1 Parent(s): f568402

Snapshot of PlanExe commit b29887f39d24be34e48668484d67a50342995f8a

Browse files
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
- # TODO: Eliminate hardcoded paths
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('002-project_plan.json')
137
- wbs_level1_json = load_json('004-wbs_level1.json')
138
- wbs_level2_json = load_json('005-wbs_level2.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 = "003-make_assumptions.json"
7
- DISTILL_ASSUMPTIONS_RAW = "004-distill_assumptions.json"
8
- PRE_PROJECT_ASSESSMENT_RAW = "005-pre_project_assessment_raw.json"
9
- PRE_PROJECT_ASSESSMENT = "006-pre_project_assessment.json"
10
- PROJECT_PLAN = "007-project_plan.json"
11
- SWOT_RAW = "008-swot_analysis_raw.json"
12
- SWOT_MARKDOWN = "009-swot_analysis.md"
13
- EXPERTS_RAW = "010-experts_raw.json"
14
- EXPERTS_CLEAN = "011-experts.json"
15
- EXPERT_CRITICISM_RAW_TEMPLATE = "012-{}-expert_criticism_raw.json"
16
- EXPERT_CRITICISM_MARKDOWN = "013-expert_criticism.md"
17
- WBS_LEVEL1_RAW = "014-wbs_level1_raw.json"
18
- WBS_LEVEL1 = "015-wbs_level1.json"
19
- WBS_LEVEL2_RAW = "016-wbs_level2_raw.json"
20
- WBS_LEVEL2 = "017-wbs_level2.json"
21
- WBS_PROJECT_LEVEL1_AND_LEVEL2 = "018-wbs_project_level1_and_level2.json"
22
- PITCH = "019-pitch.json"
23
- TASK_DEPENDENCIES_RAW = "020-task_dependencies_raw.json"
24
- TASK_DURATIONS_RAW_TEMPLATE = "021-{}-task_durations_raw.json"
25
- TASK_DURATIONS = "022-task_durations.json"
26
- WBS_LEVEL3_RAW_TEMPLATE = "023-{}-wbs_level3_raw.json"
27
- WBS_LEVEL3 = "024-wbs_level3.json"
28
- WBS_PROJECT_LEVEL1_AND_LEVEL2_AND_LEVEL3_FULL = "025-wbs_project_level1_and_level2_and_level3.json"
29
- WBS_PROJECT_LEVEL1_AND_LEVEL2_AND_LEVEL3_CSV = "026-wbs_project_level1_and_level2_and_level3.csv"
 
 
 
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.plan.create_pitch import CreatePitch
 
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.PITCH)))
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
- 'pitch': CreatePitchTask(run_id=self.run_id, speedvsdetail=self.speedvsdetail, llm_model=self.llm_model),
 
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
- #!/usr/bin/env python3
 
 
 
 
 
 
2
  import json
3
- import os
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
- class PlanExeReport:
14
- def __init__(self, input_path: str):
15
- """Initialize the report generator with either a zip file or directory path."""
16
- self.input_path = Path(input_path)
17
  self.report_data = {}
18
- self.temp_dir = None
19
- self.working_dir = None
20
 
21
- def __enter__(self):
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(self.working_dir / filename, 'r') as f:
45
  return json.load(f)
46
  except FileNotFoundError:
47
- print(f"Warning: {filename} not found")
48
  return None
49
  except json.JSONDecodeError:
50
- print(f"Warning: {filename} contains invalid JSON")
51
  return None
52
 
53
- def read_markdown_file(self, filename: str) -> Optional[str]:
54
  """Read a markdown file and return its contents."""
55
  try:
56
- with open(self.working_dir / filename, 'r') as f:
57
  return f.read()
58
  except FileNotFoundError:
59
- print(f"Warning: {filename} not found")
60
  return None
61
 
62
- def read_csv_file(self, filename: str) -> Optional[pd.DataFrame]:
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(self.working_dir / filename, 'r') as f:
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(self.working_dir / filename, delimiter=delimiter)
83
  return df
84
  except:
85
  # If that fails, try with more options
86
  try:
87
- df = pd.read_csv(self.working_dir / filename, delimiter=delimiter,
88
  on_bad_lines='skip', engine='python')
89
- print(f"Warning: Some lines in {filename} were skipped due to parsing errors")
90
  return df
91
  except Exception as e:
92
- print(f"Error reading CSV file {filename}: {str(e)}")
93
  return None
94
 
95
  except FileNotFoundError:
96
- print(f"Warning: {filename} not found")
97
  return None
98
  except Exception as e:
99
- print(f"Error reading CSV file {filename}: {str(e)}")
100
  return None
101
 
102
- def gather_data(self):
103
- """Gather data from all important files."""
104
- # Project Pitch
105
- pitch_data = self.read_json_file('019-pitch.json')
106
- if pitch_data:
107
- self.report_data['pitch'] = pitch_data
108
-
109
- # SWOT Analysis
110
- swot_md = self.read_markdown_file('009-swot_analysis.md')
111
  if swot_md:
112
  self.report_data['swot'] = swot_md
113
-
114
- # Expert Criticism
115
- expert_md = self.read_markdown_file('013-expert_criticism.md')
 
116
  if expert_md:
117
  self.report_data['expert_criticism'] = expert_md
118
-
119
- # Project Plan
120
- plan_df = self.read_csv_file('026-wbs_project_level1_and_level2_and_level3.csv')
 
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
- pitch = self.report_data['pitch']
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: Optional[str] = None) -> 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
- print(f"Report generated successfully: {output_path}")
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
- with PlanExeReport(input_path) as report_generator:
302
- report_path = report_generator.save_report(args.output)
 
 
 
 
 
 
303
 
304
- if not args.no_browser:
305
- # Try to open the report in the default browser
306
- try:
307
- import webbrowser
308
- url = f'file://{report_path.absolute()}'
309
- print(f"Opening report in browser: {url}")
310
- if not webbrowser.open(url):
311
- print(f"Could not open browser automatically.")
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" {report_path}")
 
 
 
 
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()