├── README.md ├── config.ini ├── pycodeagi-gpt4.py ├── pycodeagi.py └── requirements.txt /README.md: -------------------------------------------------------------------------------- 1 | # pyCodeAGI 2 | A small AGI experiment to generate a Python app given what app the user wants to build. The project just started, so please keep an eye on the updates. 3 | 4 | It's very early, but run the script to try out the AGI. 5 | 6 | Of course, it uses [LangChainAI](https://github.com/hwchase17/langchain). AGI concept adopted from [@yoheinakajima](https://twitter.com/yoheinakajima)'s [BabyAGI](https://github.com/yoheinakajima/babyagi). 7 | -------------------------------------------------------------------------------- /config.ini: -------------------------------------------------------------------------------- 1 | [API_KEYS] 2 | OPENAI-API_KEY = paste-your-openai-key-here -------------------------------------------------------------------------------- /pycodeagi-gpt4.py: -------------------------------------------------------------------------------- 1 | import ast 2 | import configparser 3 | import os 4 | import re 5 | from typing import List, Dict, Any 6 | 7 | from langchain import LLMChain 8 | from langchain.chains.base import Chain 9 | from langchain.chat_models import ChatOpenAI 10 | from langchain.prompts.chat import ( 11 | ChatPromptTemplate, 12 | SystemMessagePromptTemplate, 13 | HumanMessagePromptTemplate, 14 | ) 15 | from langchain.prompts.prompt import PromptTemplate 16 | from pydantic import BaseModel 17 | 18 | # Read API keys from config file 19 | config = configparser.ConfigParser() 20 | config.read('config.ini') 21 | os.environ["OPENAI_API_KEY"] = config.get('API_KEYS', 'OPENAI-API_KEY') 22 | 23 | output_file = "output_steps.txt" 24 | code_file = "app.py" 25 | 26 | 27 | class GeneratePyCodeChain(LLMChain): 28 | """ 29 | The main LLM Chain class that runs every step. 30 | """ 31 | 32 | @classmethod 33 | def create_chain(cls, verbose: bool = False) -> LLMChain: 34 | system_template = (""" 35 | You are code generation AI proficient in Python and Streamlit.\n 36 | Your goal is to build a Python app.\n 37 | You will use Streamlit for building the app user interface.\n 38 | Assume all required libraries are installed.\n 39 | {instructions}.""") 40 | system_prompt_template = PromptTemplate(template=system_template, input_variables=["instructions"]) 41 | system_message_prompt = SystemMessagePromptTemplate(prompt=system_prompt_template) 42 | 43 | user_template = "{tasks}" 44 | user_prompt_template = PromptTemplate(template=user_template, input_variables=["tasks"]) 45 | user_message_prompt = HumanMessagePromptTemplate(prompt=user_prompt_template) 46 | 47 | prompt = ChatPromptTemplate.from_messages([system_message_prompt, user_message_prompt]) 48 | llm = ChatOpenAI(model_name="gpt-4", 49 | temperature=0.35, 50 | request_timeout=240) 51 | chain_instance = cls(prompt=prompt, llm=llm) 52 | return chain_instance 53 | 54 | 55 | class PyCodeAGI(Chain, BaseModel): 56 | """ 57 | Our AGI that performs the MAGIC! 58 | """ 59 | llm_chain: GeneratePyCodeChain 60 | 61 | class Config: 62 | """Configuration for this pydantic object.""" 63 | arbitrary_types_allowed = True 64 | 65 | @property 66 | def input_keys(self) -> List[str]: 67 | return ["objective"] 68 | 69 | @property 70 | def output_keys(self) -> List[str]: 71 | return [] 72 | 73 | def _call(self, inputs: Dict[str, Any]) -> Dict[str, Any]: 74 | objective = inputs["objective"] 75 | 76 | print("\n" + "\033[93m" + "\n" + "*****OBJECTIVE*****" + "\033[0m") 77 | print(objective.strip()) 78 | with open(output_file, "a") as f: 79 | f.write(f"Objective: \n {objective.strip()}\n\n") 80 | 81 | print("\033[93m" + "*****DESCRIPTION*****" + "\033[0m") 82 | instructions = f"Users will interact with the web app built using Streamlit and Python." 83 | tasks = f""" 84 | Create a concise description for the Python app: {objective}\n 85 | Use your expertise to envision the app's purpose and functionality. 86 | """ 87 | self.llm_chain.llm.max_tokens = 200 88 | description = self.llm_chain.run(instructions=instructions, tasks=tasks) 89 | print(description.strip()) 90 | with open(output_file, "a") as f: 91 | f.write(f"Description: \n {description.strip()}\n\n") 92 | 93 | print("\033[93m" + "*****ARCHITECTURE*****" + "\033[0m") 94 | instructions = f""" 95 | You are given the app name and description.\n 96 | App Name:\n 97 | {objective}\n 98 | Description: \n 99 | {description} 100 | """ 101 | tasks = f""" 102 | Create a concise app architecture you can use to build the UX flow.\n 103 | Outline the components and structure of the code.\n 104 | Present the app architecture in an ordered list. 105 | """ 106 | self.llm_chain.llm.max_tokens = 350 107 | architecture = self.llm_chain.run(instructions=instructions, tasks=tasks) 108 | print(architecture.strip()) 109 | with open(output_file, "a") as f: 110 | f.write(f"Architecture: \n {architecture.strip()}\n\n") 111 | 112 | print("\033[93m" + "*****UX FLOW*****" + "\033[0m") 113 | instructions = f""" 114 | You are given the app name, description and architecture.\n 115 | App Name:\n 116 | {objective}\n 117 | Description: \n 118 | {description}\n 119 | Architecture:\n 120 | {architecture} 121 | """ 122 | tasks = f""" 123 | Create a concise UX flow that you can use to build code flow.\n 124 | Present the UX flow an ordered list. 125 | """ 126 | self.llm_chain.llm.max_tokens = 700 127 | uxflow = self.llm_chain.run(instructions=instructions, tasks=tasks) 128 | print(uxflow.strip()) 129 | with open(output_file, "a") as f: 130 | f.write(f"UX Flow: \n {uxflow.strip()}\n\n") 131 | 132 | print("\033[93m" + "*****CODE FLOW*****" + "\033[0m") 133 | instructions = f""" 134 | You are given the app name, description, architecture and UX flow.\n 135 | App Name:\n 136 | {objective}\n 137 | Description: \n 138 | {description}\n 139 | Architecture:\n 140 | {architecture}\n 141 | UX Flow:\n 142 | {uxflow} 143 | """ 144 | tasks = f""" 145 | Create a concise code flow you can use to write code.\n 146 | Outline the code components and structure.\n 147 | Present the code flow in an ordered list. 148 | """ 149 | self.llm_chain.llm.max_tokens = 700 150 | codeflow = self.llm_chain.run(instructions=instructions, tasks=tasks) 151 | print(codeflow.strip()) 152 | with open(output_file, "a") as f: 153 | f.write(f"Code Flow: \n {codeflow.strip()}\n\n") 154 | 155 | print("\033[93m" + "*****APP CODE*****" + "\033[0m") 156 | instructions = f""" 157 | You are given the app name, description, architecture, UX flow and code flow.\n 158 | App Name:\n 159 | {objective}\n 160 | Description: \n 161 | {description}\n 162 | Architecture:\n 163 | {architecture}\n 164 | UX Flow:\n 165 | {uxflow} 166 | Code Flow:\n 167 | {codeflow} 168 | """ 169 | # GPT4 may not follow some coding guidelines and may hallucinate. 170 | # Instruct the model specific guidelines to follow. 171 | tasks = f""" 172 | Write the Python code for the app in a single python file.\n 173 | Use SQLite python module for data storage .\n 174 | Exclude environment setup, testing, debugging, and deployment tasks.\n 175 | Build sample datasets with at least five items.\n 176 | Follow these coding guidelines: 177 | - Check and create database tables first in the main function.\n 178 | - Use pd.loc to append new rows to the DataFrame.\n 179 | ---Example: event_data.loc[len(event_data)] = sample_events.loc[0]\n 180 | - When building date sliders:\n 181 | ---First Convert dates using to_pydatetime() 182 | ---Then use their min and max values in st.slider 183 | - Use pd.to_datetime() on selected date ranges when filtering calendar events. 184 | - Save all data in a SQLite database. 185 | """ 186 | 187 | self.llm_chain.llm.max_tokens = 5000 188 | appcode = self.llm_chain.run(instructions=instructions, tasks=tasks) 189 | print(appcode.strip()) 190 | with open(output_file, "a") as f: 191 | f.write(f"App Code: \n {appcode.strip()}") 192 | 193 | print("\033[93m" + "\n*****SAVING CODE TO FILE*****\n" + "\033[0m") 194 | code_match = re.search(r'```python(.*?)```', appcode.strip(), re.DOTALL) 195 | code_content = code_match.group(1).strip() 196 | try: 197 | ast.parse(code_content) 198 | print("Generated code is AWESOME!") 199 | with open(code_file, "w") as f: 200 | f.write(code_content) 201 | print(f"Code saved to {code_file}.") 202 | except SyntaxError as e: 203 | print("OOPS! Something wrong with the code") 204 | print(f"\nSyntax Error: {e}\n") 205 | print("Try running the code generator again!") 206 | 207 | print("\033[93m" + "\n*****THANK YOU*****\n" + "\033[0m") 208 | 209 | return {} 210 | 211 | @classmethod 212 | def create_llm_chain(cls, verbose: bool = False) -> "PyCodeAGI": 213 | llm_chain = GeneratePyCodeChain.create_chain(verbose=verbose) 214 | return cls(llm_chain=llm_chain) 215 | 216 | 217 | if __name__ == "__main__": 218 | # Delete output files 219 | if os.path.exists(output_file): 220 | os.remove(output_file) 221 | 222 | if os.path.exists(code_file): 223 | os.remove(code_file) 224 | 225 | # Get the user input 226 | print("\n" + "\033[93m" + "\n" + "Welcome to pyCodeAGI" + "\033[0m") 227 | print("\nA simple agent that builds a Python app for you!\n") 228 | print("The agent will use Streamlit to turn your Python app into a web app!\n") 229 | print(u'\u2193' + " Lets get started " + u'\u2193' + "\n") 230 | objective = input(f"What app do you want me to build: ") 231 | 232 | # Initialize our agent 233 | pycode_agi = PyCodeAGI.create_llm_chain() 234 | 235 | # Run the agent and witness the MAGIC! 236 | pycode_agi({"objective": objective}) 237 | -------------------------------------------------------------------------------- /pycodeagi.py: -------------------------------------------------------------------------------- 1 | import configparser 2 | import os 3 | from typing import List, Dict, Any 4 | 5 | from langchain import LLMChain 6 | from langchain import OpenAI 7 | from langchain.chains.base import Chain 8 | from langchain.prompts.prompt import PromptTemplate 9 | from pydantic import BaseModel 10 | 11 | # Read API keys from config file 12 | config = configparser.ConfigParser() 13 | config.read('config.ini') 14 | os.environ["OPENAI_API_KEY"] = config.get('API_KEYS', 'OPENAI-API_KEY') 15 | 16 | 17 | class GeneratePyCodeChain(LLMChain): 18 | """ 19 | The main LLM Chain class that runs every step. 20 | """ 21 | @classmethod 22 | def create_chain(cls, verbose: bool = False) -> LLMChain: 23 | prompt_template = (""" 24 | You are code generation AI proficient in Python.\n 25 | Your task is to build a '{objective}' console-based Python app.\n 26 | {maincontent}.\n 27 | {outcome}:""") 28 | prompt = PromptTemplate(template=prompt_template, input_variables=["objective", "maincontent", "outcome"]) 29 | 30 | llm = OpenAI(model_name="text-davinci-003", 31 | temperature=0.3) 32 | 33 | chain_instance = cls(prompt=prompt, llm=llm) 34 | return chain_instance 35 | 36 | 37 | class PyCodeAGI(Chain, BaseModel): 38 | """ 39 | Our AGI that performs the MAGIC! 40 | """ 41 | llm_chain: GeneratePyCodeChain 42 | 43 | class Config: 44 | """Configuration for this pydantic object.""" 45 | arbitrary_types_allowed = True 46 | 47 | @property 48 | def input_keys(self) -> List[str]: 49 | return ["objective"] 50 | 51 | @property 52 | def output_keys(self) -> List[str]: 53 | return [] 54 | 55 | def _call(self, inputs: Dict[str, Any]) -> Dict[str, Any]: 56 | objective = inputs["objective"] 57 | print("\033[93m" + "*****OBJECTIVE*****" + "\033[0m") 58 | print(objective.strip()) 59 | 60 | print("\033[93m" + "*****DESCRIPTION*****" + "\033[0m") 61 | maincontent = """ 62 | Your task is to create a concise description for the console-based Python app.\n 63 | Users will interact with the app in a console terminal.\n 64 | Use your expertise to envision the app's purpose and functionality. 65 | """ 66 | outcome = "Description" 67 | self.llm_chain.llm.max_tokens = 200 68 | description = self.llm_chain.run(objective=objective, 69 | maincontent=maincontent, 70 | outcome=outcome) 71 | print(description.strip()) 72 | 73 | print("\033[93m" + "*****ARCHITECTURE*****" + "\033[0m") 74 | maincontent = f""" 75 | Based on the provided app description, create a detailed app architecture.\n 76 | Outline the components and structure of the code.\n 77 | Present the app architecture in an ordered list.\n 78 | Description: {description} 79 | """ 80 | outcome = "Architecture" 81 | self.llm_chain.llm.max_tokens = 350 82 | architecture = self.llm_chain.run(objective=objective, 83 | maincontent=maincontent, 84 | outcome=outcome) 85 | print(architecture.strip()) 86 | 87 | print("\033[93m" + "*****UX FLOW*****" + "\033[0m") 88 | maincontent = f""" 89 | Based on the app description and architecture outline the app UX flow.\n 90 | Present the UX flow an ordered list.\n 91 | Description: {description}\n 92 | Architecture: {architecture}""" 93 | outcome = "UX Flow" 94 | self.llm_chain.llm.max_tokens = 400 95 | uxflow = self.llm_chain.run(objective=objective, 96 | maincontent=maincontent, 97 | outcome=outcome) 98 | print(uxflow.strip()) 99 | 100 | print("\033[93m" + "*****CODE FLOW*****" + "\033[0m") 101 | maincontent = f""" 102 | Based on the app description, architecture and UX flow, create a detailed code flow.\n 103 | Outline the code components and structure.\n 104 | Present the code flow in an ordered list.\n 105 | Description: {description}\n 106 | Architecture: {architecture}\n 107 | UX Flow: {uxflow}""" 108 | outcome = "Code Flow" 109 | self.llm_chain.llm.max_tokens = 400 110 | codeflow = self.llm_chain.run(objective=objective, 111 | maincontent=maincontent, 112 | outcome=outcome) 113 | print(codeflow.strip()) 114 | 115 | print("\033[93m" + "*****CODING STEPS*****" + "\033[0m") 116 | maincontent = f""" 117 | You are provided with the app description, architecture, UX flow, and code flow.\n 118 | Create an ordered list of coding steps required to build the app.\n 119 | Exclude environment setup, testing, debugging, and deployment steps.\n 120 | Description: {description}\n 121 | Architecture: {architecture}\n 122 | UX Flow: {uxflow}\n 123 | Code Flow: {codeflow}""" 124 | outcome = "Coding Steps" 125 | self.llm_chain.llm.max_tokens = 400 126 | codingsteps = self.llm_chain.run(objective=objective, 127 | maincontent=maincontent, 128 | outcome=outcome) 129 | print(codingsteps.strip()) 130 | 131 | print("\033[93m" + "*****APP CODE*****" + "\033[0m") 132 | maincontent = f""" 133 | With access to the Python terminal, your task is to write the Python code for the app.\n 134 | You are given the app description, architecture, code flow, and tasks.\n 135 | Write the Python code with a main function to execute the app in a console terminal.\n 136 | Avoid using database for backend storage, instead use in-memory options. 137 | Exclude environment setup, testing, debugging, and deployment tasks.\n 138 | Description: {description}\n 139 | Architecture: {architecture}\n 140 | UX Flow: {uxflow}\n 141 | Code Flow: {codeflow}\n 142 | Coding Steps: {codingsteps}'""" 143 | outcome = "App Code" 144 | self.llm_chain.llm.max_tokens = 3000 145 | appcode = self.llm_chain.run(objective=objective, 146 | maincontent=maincontent, 147 | outcome=outcome) 148 | print(appcode.strip()) 149 | 150 | print("\033[93m" + "\n*****THANK YOU*****\n" + "\033[0m") 151 | 152 | return {} 153 | 154 | @classmethod 155 | def create_llm_chain(cls, verbose: bool = False) -> "PyCodeAGI": 156 | llm_chain = GeneratePyCodeChain.create_chain(verbose=verbose) 157 | return cls(llm_chain=llm_chain) 158 | 159 | 160 | objective = "calculator app" 161 | 162 | # Initialize our agent 163 | pycode_agi = PyCodeAGI.create_llm_chain() 164 | # Run the agent and witness the MAGIC! 165 | pycode_agi({"objective": objective}) -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | langchain~=0.0.139 2 | openai~=0.27.4 3 | pydantic~=1.10.7 4 | streamlit~=1.22.0 5 | pandas~=2.0.1 6 | numpy~=1.24.2 --------------------------------------------------------------------------------