mirror of
https://github.com/OMGeeky/gpt-pilot.git
synced 2026-01-03 18:04:57 +01:00
setup storing steps to db and init user stories implementation
This commit is contained in:
@@ -1 +1,5 @@
|
||||
# copilot
|
||||
# copilot
|
||||
|
||||
python main.py app_id=uuid step=step
|
||||
|
||||
all steps in const/common.py in const STEPS
|
||||
@@ -1 +1,8 @@
|
||||
APP_TYPES = ['Web App', 'Script', 'Mobile App (unavailable)', 'Chrome Extension (unavailable)']
|
||||
APP_TYPES = ['Web App', 'Script', 'Mobile App (unavailable)', 'Chrome Extension (unavailable)']
|
||||
ROLES = {
|
||||
'product_owner': ['project_summary', 'user_stories', 'user_tasks'],
|
||||
'architect': ['architecture'],
|
||||
'tech_lead': ['development_planing'],
|
||||
'full_stack_developer': ['create_scripts', 'coding']
|
||||
}
|
||||
STEPS = ['project_summary', 'user_stories', 'user_tasks', 'development_planing', 'create_scripts', 'coding']
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
MIN_TOKENS_FOR_GPT_RESPONSE = 60
|
||||
MAX_GPT_MODEL_TOKENS = 4096
|
||||
MAX_GPT_MODEL_TOKENS = 4096
|
||||
MAX_QUESTIONS = 3
|
||||
END_RESPONSE = "EVERYTHING_CLEAR"
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
SYS_MESSAGE = {
|
||||
"tdd_engineer": {
|
||||
"role": "system",
|
||||
"content": "You are an experienced software engineer who is proficient in node.js and who practices TDD (Test "
|
||||
"Driven Development). Usually, you look at the code that already exists and a written test - then "
|
||||
"you think step by step and modify the function that's being tested to make the test pass."
|
||||
},
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
import psycopg2
|
||||
import json
|
||||
from psycopg2 import sql
|
||||
from psycopg2.extras import RealDictCursor
|
||||
from const import db
|
||||
from logger.logger import logger
|
||||
|
||||
@@ -13,7 +14,9 @@ def create_connection():
|
||||
database=db.DB_NAME,
|
||||
port=db.DB_PORT,
|
||||
user=db.DB_USER,
|
||||
password=db.DB_PASSWORD)
|
||||
password=db.DB_PASSWORD,
|
||||
cursor_factory=RealDictCursor
|
||||
)
|
||||
return conn
|
||||
|
||||
|
||||
@@ -38,6 +41,7 @@ def create_tables():
|
||||
CREATE TABLE apps (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_id UUID NOT NULL,
|
||||
app_id UUID NOT NULL UNIQUE,
|
||||
app_type VARCHAR(255) NOT NULL,
|
||||
status VARCHAR(255) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
@@ -50,7 +54,7 @@ def create_tables():
|
||||
"""
|
||||
CREATE TABLE progress_steps (
|
||||
id SERIAL PRIMARY KEY,
|
||||
app_id INTEGER NOT NULL,
|
||||
app_id UUID NOT NULL,
|
||||
step VARCHAR(255) NOT NULL,
|
||||
data TEXT,
|
||||
completed BOOLEAN NOT NULL,
|
||||
@@ -58,7 +62,7 @@ def create_tables():
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (app_id)
|
||||
REFERENCES apps (id)
|
||||
REFERENCES apps (app_id)
|
||||
ON UPDATE CASCADE ON DELETE CASCADE
|
||||
)
|
||||
""")
|
||||
@@ -78,7 +82,7 @@ def create_tables():
|
||||
conn.close()
|
||||
|
||||
|
||||
def save_app(user_id, app_type):
|
||||
def save_app(user_id, app_id, app_type):
|
||||
conn = create_connection()
|
||||
cursor = conn.cursor()
|
||||
|
||||
@@ -89,9 +93,8 @@ def save_app(user_id, app_type):
|
||||
(str(user_id),))
|
||||
|
||||
# Now save the app
|
||||
cursor.execute("INSERT INTO apps (user_id, app_type, status) VALUES (%s, %s, 'started') RETURNING id",
|
||||
(str(user_id), app_type))
|
||||
app_id = cursor.fetchone()[0]
|
||||
cursor.execute("INSERT INTO apps (user_id, app_id, app_type, status) VALUES (%s, %s, %s, 'started') RETURNING id",
|
||||
(str(user_id), (str(app_id)), app_type))
|
||||
|
||||
conn.commit()
|
||||
cursor.close()
|
||||
@@ -99,7 +102,7 @@ def save_app(user_id, app_type):
|
||||
|
||||
logger.info('User saved')
|
||||
|
||||
return app_id
|
||||
return
|
||||
|
||||
|
||||
def save_progress(app_id, step, data):
|
||||
@@ -120,5 +123,34 @@ def save_progress(app_id, step, data):
|
||||
conn.close()
|
||||
|
||||
|
||||
def get_apps_by_id(app_id):
|
||||
conn = create_connection()
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute("SELECT * FROM apps WHERE app_id = %s", (str(app_id),))
|
||||
apps = cursor.fetchall()
|
||||
|
||||
cursor.close()
|
||||
conn.close()
|
||||
|
||||
return apps
|
||||
|
||||
|
||||
def get_progress_steps(app_id, step=None):
|
||||
conn = create_connection()
|
||||
cursor = conn.cursor()
|
||||
|
||||
if step:
|
||||
cursor.execute("SELECT * FROM progress_steps WHERE app_id = %s AND step = %s", (app_id, step))
|
||||
else:
|
||||
cursor.execute("SELECT * FROM progress_steps WHERE app_id = %s", (app_id,))
|
||||
steps = cursor.fetchall()
|
||||
|
||||
cursor.close()
|
||||
conn.close()
|
||||
|
||||
return steps
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
create_tables()
|
||||
|
||||
113
euclid/main.py
113
euclid/main.py
@@ -2,35 +2,114 @@
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
import uuid
|
||||
import json
|
||||
from dotenv import load_dotenv
|
||||
from termcolor import colored
|
||||
|
||||
from database.database import save_progress, save_app
|
||||
from utils.utils import get_arguments, execute_step, split_into_bullets, find_role_from_step
|
||||
from database.database import save_progress, save_app, get_progress_steps
|
||||
from logger.logger import logger
|
||||
from prompts.prompts import ask_for_app_type,ask_for_main_app_definition, get_additional_info_from_openai,\
|
||||
generate_messages_from_description, execute_chat_prompt
|
||||
from prompts.prompts import ask_for_app_type, ask_for_main_app_definition, get_additional_info_from_openai, \
|
||||
get_additional_info_from_user, generate_messages_from_description, execute_chat_prompt
|
||||
from utils.llm_connection import get_prompt
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
logger.info('Starting')
|
||||
def init():
|
||||
load_dotenv()
|
||||
|
||||
arguments = get_arguments()
|
||||
|
||||
logger.info(f"Starting with args: {arguments}")
|
||||
|
||||
return arguments
|
||||
|
||||
|
||||
def get_project_description(args):
|
||||
current_step = 'project_summary'
|
||||
# If this app_id already did this step, just get all data from DB and don't ask user again
|
||||
steps = get_progress_steps(args['app_id'], current_step)
|
||||
if steps and not execute_step(args['step'], current_step):
|
||||
first_step = steps[0]
|
||||
data = json.loads(first_step['data'])
|
||||
|
||||
summary = data.get('summary')
|
||||
app_data = data.get('app_data')
|
||||
args.update(app_data)
|
||||
|
||||
message = f"Project summary already done for this app_id: {args['app_id']}. Moving to next step..."
|
||||
print(colored(message, "green"))
|
||||
logger.info(message)
|
||||
|
||||
return summary
|
||||
|
||||
# PROJECT DESCRIPTION
|
||||
app_type = ask_for_app_type()
|
||||
|
||||
user_id = str(uuid.uuid4())
|
||||
app_id = save_app(user_id, app_type)
|
||||
save_app(args['user_id'], args['app_id'], app_type)
|
||||
|
||||
description = ask_for_main_app_definition()
|
||||
|
||||
messages = get_additional_info_from_openai(generate_messages_from_description(description, app_type))
|
||||
high_level_messages = get_additional_info_from_openai(generate_messages_from_description(description, app_type))
|
||||
|
||||
summary = execute_chat_prompt('summary.pt',
|
||||
{'conversation': '\n'.join([f"{msg['role']}: {msg['content']}" for msg in messages])},
|
||||
'summarize',
|
||||
'Project summary')
|
||||
high_level_summary = execute_chat_prompt('utils/summary.prompt',
|
||||
{'conversation': '\n'.join(
|
||||
[f"{msg['role']}: {msg['content']}" for msg in high_level_messages])},
|
||||
current_step)
|
||||
|
||||
save_progress(app_id, 'main_description', {"messages": messages, "summary": summary})
|
||||
app_data = {'app_id': args['app_id'], 'app_type': app_type}
|
||||
args['app_type'] = app_type
|
||||
|
||||
stories = execute_chat_prompt('user_stories.pt',
|
||||
{'summary': summary, 'app_type': app_type},
|
||||
'user_stories',
|
||||
'User stories')
|
||||
save_progress(args['app_id'], current_step,
|
||||
{"messages": high_level_messages, "summary": high_level_summary, "app_data": app_data})
|
||||
|
||||
return high_level_summary
|
||||
# PROJECT DESCRIPTION END
|
||||
|
||||
|
||||
def get_user_stories(summary, args):
|
||||
current_step = 'user_stories'
|
||||
role = find_role_from_step(current_step)
|
||||
# If this app_id already did this step, just get all data from DB and don't ask user again
|
||||
steps = get_progress_steps(args['app_id'], current_step)
|
||||
if steps and not execute_step(args['step'], current_step):
|
||||
first_step = steps[0]
|
||||
data = json.loads(first_step['data'])
|
||||
|
||||
summary = data.get('summary')
|
||||
app_data = data.get('app_data')
|
||||
args.update(app_data)
|
||||
|
||||
message = f"User stories already done for this app_id: {args['app_id']}. Moving to next step..."
|
||||
print(colored(message, "green"))
|
||||
logger.info(message)
|
||||
return summary, args
|
||||
|
||||
# USER STORIES
|
||||
print(colored(f"Generating user stories...\n", "green"))
|
||||
logger.info(f"Generating user stories...")
|
||||
|
||||
user_stories = execute_chat_prompt('user_stories/specs.prompt',
|
||||
{'summary': summary, 'app_type': args['app_type']},
|
||||
current_step)
|
||||
|
||||
logger.info(split_into_bullets(user_stories))
|
||||
user_stories = get_additional_info_from_user(split_into_bullets(user_stories), role)
|
||||
|
||||
logger.info(f"Final user stories: {user_stories}")
|
||||
|
||||
save_progress(args['app_id'], current_step, {"user_stories": user_stories})
|
||||
|
||||
return user_stories
|
||||
# USER STORIES END
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = init()
|
||||
|
||||
high_level_summary = get_project_description(args)
|
||||
|
||||
user_stories = get_user_stories(high_level_summary, args)
|
||||
|
||||
# get architecture plan
|
||||
|
||||
# development
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
I want you to create the application (let's call it Euclid) that can be described like this:
|
||||
```
|
||||
{{ description }}
|
||||
```
|
||||
|
||||
We are going to create this app together, step by step. Here is an overview of tasks that you need to do to create this app from scratch:
|
||||
|
||||
1. break down the app's functionality. Here, you need to list out all the possible features of the app regardless of if a user can interact with the feature (like enabling user to do something) or if it's a technical feature that needs to exist to make the app work (like having a database to store the data).
|
||||
|
||||
2. Break down all the different user journeys that a user might experience while interacting with Euclid. Each journey needs to be described in as much detail as possible because that will be the fundamental base upon which you will break down the details of how the code structure will look like.
|
||||
|
||||
|
||||
# how to start the app
|
||||
# how to open the results with the command line so that user sees what's going on
|
||||
2. Break down the plan for iteratively working on Euclid. Throughout the process of coding Euclid, we will create functionality screen by screen, I will test it and tell you how it works. Then, you will change the code or move onto the next screen. In this task, you will need to list out low level user experience from the start when the app is run all the way throughout all user journeys. This will basically be a plan for coding later on.
|
||||
|
||||
3. Break down high level components that show how the codebase needs to be structured. For example, do we need frontend and what kind - mobile app, HTML website, etc. How the backend needs to look like; do we need to have a database and what database is best to use for this project? Do we need some other technologies like sockets, cronjob or something else? What secret keys do we need to use for this project and how the environment variables will be handled?
|
||||
|
||||
4. Break down how will the user start the app and what will be the first screen. Then, I'll try running the app and see if it works and I will give you the feedback. We will iterate on this step until we have the first screen working.
|
||||
|
||||
5. Break down how the files and folders will be structured to support all the outlined user journeys and components. You will need to think step by step through each user journey and through each component and create the project structure. The project structure needs to contain every file and folder that will be eventually created with names along with a comment on what will be contained in each file or folder. In this step, you won't need to create code, just the project structure.
|
||||
|
||||
# exporting of functions - how to make sure we export them
|
||||
# what is with the code that's not necessarily a function - how to handle that
|
||||
# we should save all comments from GPT
|
||||
# how can we know what's a working database URL???
|
||||
6. Loop through each file that you listed in the previous task, think step by step through all components and user journeys and list all functions that will need to be created in each file that will eventually make the app work. In this task, you will just need to create names and descriptions of what each function will need to do. With each function, make sure that you determine the input arguments and the return value (if there is any)
|
||||
|
||||
# trebamo imati procese za provjeru da li postoji node, mongo, da li je Mongo uključen, etc.
|
||||
7. Since we will be building this app with TDD, in this task, you will need to loop through each function that you listed in the previous task, think step by step through all components and user journeys and list all tests that will test every functionality of the app Euclid. You will start from the high level tests (integration or end-to-end tests) like testing if user can click on a specific element or if backend returns correct data. Then, you will go down all the way to unit tests for each specific function and list the tests needed. For each test, you will just need to create the test name and a description of what it needs to test.
|
||||
# u ovom trenu treba prvo posložiti strukturu podataka, a onda tek pisati testove
|
||||
# treba se error handling složiti tako da, ako se dogodi error, da možemo GPT-u pokazati točno gdje je error i što kaže
|
||||
8. Write the tests and the code. This task will be an iterative task where you will think step by step from the low level, unit, tests all the way up to the high level integration and end-to-end tests. You will create test by test and after each test, you will create the code for it. I will run the test to check if it passes and show you the error. Will will do this iteratively until all tests pass and all code is written. By the end of this task, the Eucild app should be working.
|
||||
|
||||
9. Finally, you will write all other necessary files and scripts that will make the app actually work like script to run the app, script that initializes the database, script that installs all the dependencies, and everything else that a developer needs to run to make the Euclid app work.
|
||||
|
||||
Ok, now, let's start with breaking down the task #1. Think step by step and break down the user journeys for the described app.
|
||||
|
||||
|
||||
{% if old_user_flows %}
|
||||
You've listed the following user flows:
|
||||
{% for flow in old_user_flows %}
|
||||
{{ flow }}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
I want to modify the user flows so that these flows are included:
|
||||
{% for flow in new_user_flows %}
|
||||
{{ flow }}
|
||||
{% endfor %}
|
||||
|
||||
Now, rewrite the user flows so that they include the new flows. Keep in mind that the new user flows have a higher priority than the old ones so if any of the old user flows conflict with the new ones, the new ones should be used.
|
||||
{% else %}
|
||||
|
||||
|
||||
Ok, now, think step by step and break down the user flows for the described app. What are all flows that user can take that this app should support?
|
||||
{% endif %}
|
||||
@@ -1,12 +0,0 @@
|
||||
{% set description = description.strip() %}
|
||||
You are an AI engineer trying to understand a project description in order to build it. I want you to create {{app_type}}, however, the current description most likely needs more details for a comprehensive understanding:
|
||||
|
||||
```{{ description }}```
|
||||
|
||||
If needed, please ask specific and targeted questions to get more information about the project. The questions should be oriented towards understanding the project's requirements, functionalities, target audience, user interactions, desired look and feel, and any other aspect that may be unclear from the initial description.
|
||||
|
||||
In your response don't write any explanations, comments, your thoughts or anything like that. I want your response to be only one question at a time. I will ask you again when I am ready for next question.
|
||||
|
||||
Ask maximum of {{maximum_questions}} questions and after that I want you to respond with "Thank you!".
|
||||
|
||||
If everything is clear before asking those {{maximum_questions}} questions, just respond with "Thank you!".
|
||||
7
euclid/prompts/components/single_question.prompt
Normal file
7
euclid/prompts/components/single_question.prompt
Normal file
@@ -0,0 +1,7 @@
|
||||
**IMPORTANT**
|
||||
I want your response to be only one question at a time. I will ask you again when I am ready for next question.
|
||||
|
||||
Ask maximum of {{MAX_QUESTIONS}} questions and after that I want you to respond with "{{END_RESPONSE}}".
|
||||
|
||||
If everything is clear before asking those {{MAX_QUESTIONS}} questions, you write the response in the following format:
|
||||
"{{END_RESPONSE}}"
|
||||
@@ -1,6 +1,6 @@
|
||||
I want you to create the application (let's call it Euclid) that can be described like this:
|
||||
I want you to create the {{app_type}} (let's call it Euclid) that can be described like this:
|
||||
```
|
||||
{{ prompt }}
|
||||
{{ description }}
|
||||
```
|
||||
|
||||
I'm going to show you an overview of tasks that you need to do to lead the process of creating this app and for each task, I will tell you an example of how would you solve this task for the example app.
|
||||
@@ -20,7 +20,5 @@ Here is an overview of the tasks that you need to do:
|
||||
- `user runs the CLI command in which they specify the keyword youtube channel needs to contain and the location where the CSV file will be saved to`
|
||||
|
||||
Let's start with the task #1 Getting additional answers. Think about the description for the app Euclid and ask questions that you would like to get cleared before going onto breaking down the user stories.
|
||||
**IMPORTANT**
|
||||
If everything is clear, you write the response in the following format:
|
||||
EVERYTHING_CLEAR
|
||||
App recap: {{recap of the app after all clerifications}}
|
||||
|
||||
{{single_question}}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
I want you to create the application (let's call it Euclid) that can be described like this:
|
||||
```
|
||||
{{prompt}}
|
||||
```
|
||||
|
||||
First, you need to break down what needs to be done to create this app step by step. You will break it down by 8 axes:
|
||||
1. Type of the app - is it a mobile app, a script, a chrome extension or a web app
|
||||
2. User flows which outline how the user will use the app. Here, you will need to outline all possible flows that a user might want to take.
|
||||
3. Steps to run the app - how to initialize the project, install dependencies, set up the database, run or build the app and other things like cronjob, etc.
|
||||
4. Tests that need to written to verify if the app is running (remember, you always practice TDD so you will create tests first and then the code)
|
||||
5. Files that need to be created to make the app run
|
||||
6. Functions that need to exist in the files
|
||||
7. Dependencies that need to be installed to make the app run
|
||||
8. Values in the config file that cannot be hardcoded in the app
|
||||
@@ -4,8 +4,9 @@ from inquirer.themes import GreenPassion
|
||||
from termcolor import colored
|
||||
|
||||
from const import common
|
||||
from const.prompts import SYS_MESSAGE
|
||||
from const.llm import MAX_QUESTIONS, END_RESPONSE
|
||||
from utils.llm_connection import create_gpt_chat_completion, get_prompt
|
||||
from utils.utils import capitalize_first_word_with_underscores, get_sys_message, find_role_from_step
|
||||
from logger.logger import logger
|
||||
|
||||
|
||||
@@ -90,8 +91,7 @@ def get_additional_info_from_openai(messages):
|
||||
response = create_gpt_chat_completion(messages, 'additional_info')
|
||||
|
||||
if response is not None:
|
||||
# Check if the response is "Thank you!"
|
||||
if response.strip() == "Thank you!":
|
||||
if response.strip() == END_RESPONSE:
|
||||
print(response)
|
||||
return messages
|
||||
|
||||
@@ -104,34 +104,74 @@ def get_additional_info_from_openai(messages):
|
||||
else:
|
||||
is_complete = True
|
||||
|
||||
logger.info('Getting additional info done')
|
||||
logger.info('Getting additional info from openai done')
|
||||
|
||||
return messages
|
||||
|
||||
|
||||
def get_additional_info_from_user(messages, role):
|
||||
updated_messages = []
|
||||
|
||||
for message in messages:
|
||||
|
||||
while True:
|
||||
print(colored(f"Please check this message and say what needs to be changed. If everything is ok just type 'DONE'.", "yellow"))
|
||||
answer = ask_user(message)
|
||||
if answer.lower() == 'done':
|
||||
break
|
||||
response = create_gpt_chat_completion(
|
||||
generate_messages_from_custom_conversation(role, [get_prompt('utils/update.prompt'), message, answer], 'user'),
|
||||
'additional_info')
|
||||
|
||||
message = response
|
||||
|
||||
updated_messages.append(message)
|
||||
|
||||
logger.info('Getting additional info from user done')
|
||||
|
||||
return "\n\n".join(updated_messages)
|
||||
|
||||
|
||||
def generate_messages_from_description(description, app_type):
|
||||
prompt = get_prompt('clarification.pt', {'description': description, 'app_type': app_type, 'maximum_questions': 3})
|
||||
prompt = get_prompt('high_level_questions/specs.prompt', {
|
||||
'description': description,
|
||||
'app_type': app_type,
|
||||
'MAX_QUESTIONS': MAX_QUESTIONS
|
||||
})
|
||||
|
||||
return [
|
||||
SYS_MESSAGE['tdd_engineer'],
|
||||
get_sys_message('product_owner'),
|
||||
{"role": "user", "content": prompt},
|
||||
]
|
||||
|
||||
|
||||
def execute_chat_prompt(prompt_file, prompt_data, chat_completion_type, print_msg):
|
||||
def generate_messages_from_custom_conversation(role, messages, start_role='user'):
|
||||
result = [get_sys_message(role)]
|
||||
|
||||
for i, message in enumerate(messages):
|
||||
if i % 2 == 0:
|
||||
result.append({"role": start_role, "content": message})
|
||||
else:
|
||||
result.append({"role": "assistant" if start_role == "user" else "user", "content": message})
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def execute_chat_prompt(prompt_file, prompt_data, chat_type):
|
||||
# Generate a prompt for the completion type.
|
||||
prompt = get_prompt(prompt_file, prompt_data)
|
||||
|
||||
# Pass the prompt to the API.
|
||||
messages = [
|
||||
SYS_MESSAGE['tdd_engineer'],
|
||||
get_sys_message(find_role_from_step(chat_type)),
|
||||
{"role": "user", "content": prompt},
|
||||
]
|
||||
|
||||
response = create_gpt_chat_completion(messages, chat_completion_type)
|
||||
response = create_gpt_chat_completion(messages, chat_type)
|
||||
|
||||
print_msg = capitalize_first_word_with_underscores(chat_type)
|
||||
print(colored(f"{print_msg}:\n", "green"))
|
||||
print(f"{response}")
|
||||
logger.info(f"{print_msg}: {response}")
|
||||
logger.info(f"{print_msg}: {response}\n")
|
||||
|
||||
return response
|
||||
return response
|
||||
@@ -1,2 +0,0 @@
|
||||
Based on the following conversation, write a summary of the project:
|
||||
{{conversation}}
|
||||
@@ -1,3 +0,0 @@
|
||||
Here is the summary of the project I want to create:
|
||||
{{summary}}
|
||||
I want you to help me create it. For start I want you to break down each user story that user can do within {{app_type}} that you can think of from description above.
|
||||
2
euclid/prompts/utils/summary.prompt
Normal file
2
euclid/prompts/utils/summary.prompt
Normal file
@@ -0,0 +1,2 @@
|
||||
Based on the following conversation, write a summary:
|
||||
{{conversation}}
|
||||
1
euclid/prompts/utils/update.prompt
Normal file
1
euclid/prompts/utils/update.prompt
Normal file
@@ -0,0 +1 @@
|
||||
I will show you some of your message to which I want make some updates. Please just modify your last message per my instructions.
|
||||
@@ -6,18 +6,23 @@ import json
|
||||
from typing import List
|
||||
from jinja2 import Environment, FileSystemLoader
|
||||
|
||||
from const.llm import MIN_TOKENS_FOR_GPT_RESPONSE, MAX_GPT_MODEL_TOKENS
|
||||
from const.prompts import SYS_MESSAGE
|
||||
from const.llm import MIN_TOKENS_FOR_GPT_RESPONSE, MAX_GPT_MODEL_TOKENS, MAX_QUESTIONS, END_RESPONSE
|
||||
from logger.logger import logger
|
||||
from termcolor import colored
|
||||
from utils.utils import get_prompt_components
|
||||
|
||||
|
||||
def connect_to_llm():
|
||||
pass
|
||||
|
||||
|
||||
def get_prompt(prompt_name, data):
|
||||
logger.debug(f"Getting prompt for {prompt_name} with data {data}") # logging here
|
||||
def get_prompt(prompt_name, data=None):
|
||||
if data is None:
|
||||
data = {}
|
||||
|
||||
data.update(get_prompt_components())
|
||||
|
||||
logger.debug(f"Getting prompt for {prompt_name}") # logging here
|
||||
# Create a file system loader with the directory of the templates
|
||||
file_loader = FileSystemLoader('prompts')
|
||||
|
||||
@@ -33,19 +38,6 @@ def get_prompt(prompt_name, data):
|
||||
return output
|
||||
|
||||
|
||||
def get_user_flows(description):
|
||||
prompt = get_prompt('breakdown_1_user_flows.prompt', {'description': description})
|
||||
|
||||
messages = [
|
||||
SYS_MESSAGE['tdd_engineer'],
|
||||
# app type
|
||||
#
|
||||
{"role": "user", "content": prompt},
|
||||
]
|
||||
|
||||
create_gpt_chat_completion(messages, 'user_flows')
|
||||
|
||||
|
||||
def get_tokens_in_messages(messages: List[str]) -> int:
|
||||
tokenizer = Tokenizer()
|
||||
tokenized_messages = [tokenizer.encode(message) for message in messages]
|
||||
@@ -126,21 +118,5 @@ def stream_gpt_completion(data, req_type):
|
||||
return new_code
|
||||
|
||||
|
||||
def get_clarifications(description):
|
||||
prompt = get_prompt('clarification.pt', {'description': description})
|
||||
|
||||
messages = [
|
||||
SYS_MESSAGE['tdd_engineer'],
|
||||
{"role": "user", "content": prompt},
|
||||
]
|
||||
|
||||
response = create_gpt_chat_completion(messages, 'get_clarifications')
|
||||
|
||||
if response is not None:
|
||||
messages.append({'role': 'assistant', 'content': response})
|
||||
|
||||
return messages, response
|
||||
|
||||
|
||||
def postprocessing(gpt_response, req_type):
|
||||
return gpt_response
|
||||
|
||||
@@ -1,48 +1,151 @@
|
||||
# utils/utils.py
|
||||
import inquirer
|
||||
from inquirer.themes import GreenPassion
|
||||
|
||||
import sys
|
||||
import os
|
||||
import platform
|
||||
import distro
|
||||
import uuid
|
||||
import re
|
||||
from jinja2 import Environment, FileSystemLoader
|
||||
|
||||
from const.llm import MAX_QUESTIONS, END_RESPONSE
|
||||
from const.common import ROLES, STEPS
|
||||
|
||||
|
||||
def break_down_user_flows(description):
|
||||
return 'false'
|
||||
user_flows = parse_description_into_user_flows(description)
|
||||
for flow_index, user_flow in enumerate(user_flows):
|
||||
is_correct = False
|
||||
while not is_correct:
|
||||
print(f"User Flow {flow_index + 1}: {user_flow}")
|
||||
is_correct = ask_for_user_flow_confirmation(flow_index)
|
||||
save_progress(app_id, f'user_flow_{flow_index + 1}', user_flow)
|
||||
def get_arguments():
|
||||
# The first element in sys.argv is the name of the script itself.
|
||||
# Any additional elements are the arguments passed from the command line.
|
||||
args = sys.argv[1:]
|
||||
|
||||
# Create an empty dictionary to store the key-value pairs.
|
||||
arguments = {}
|
||||
|
||||
# Loop through the arguments and parse them as key-value pairs.
|
||||
for arg in args:
|
||||
if '=' in arg:
|
||||
key, value = arg.split('=', 1)
|
||||
arguments[key] = value
|
||||
else:
|
||||
# Handle arguments without '=' (e.g., positional arguments).
|
||||
pass
|
||||
|
||||
if 'user_id' not in arguments:
|
||||
arguments['user_id'] = str(uuid.uuid4())
|
||||
|
||||
if 'app_id' not in arguments:
|
||||
arguments['app_id'] = str(uuid.uuid4())
|
||||
|
||||
if 'step' not in arguments:
|
||||
arguments['step'] = None
|
||||
|
||||
print(f"If you wish to continue with this project in future run 'python main.py app_id={arguments['app_id']}")
|
||||
return arguments
|
||||
|
||||
|
||||
def ask_for_user_flow_confirmation(flow_index):
|
||||
questions = [
|
||||
inquirer.List('confirmation',
|
||||
message=f"Does user flow {flow_index + 1} meet your requirements? (Yes/No)",
|
||||
choices=['Yes', 'No'],
|
||||
)
|
||||
]
|
||||
def capitalize_first_word_with_underscores(s):
|
||||
# Split the string into words based on underscores.
|
||||
words = s.split('_')
|
||||
|
||||
answers = inquirer.prompt(questions, theme=GreenPassion())
|
||||
# Capitalize the first word and leave the rest unchanged.
|
||||
words[0] = words[0].capitalize()
|
||||
|
||||
if answers is None:
|
||||
print("No input provided!")
|
||||
return
|
||||
# Join the words back into a string with underscores.
|
||||
capitalized_string = '_'.join(words)
|
||||
|
||||
if answers['confirmation'] == 'Yes':
|
||||
return True
|
||||
else:
|
||||
return modify_user_flow(flow_index)
|
||||
return capitalized_string
|
||||
|
||||
|
||||
def modify_user_flow(flow_index):
|
||||
questions = [
|
||||
inquirer.Text('correction', message=f"Please provide corrections for user flow {flow_index + 1}.")
|
||||
]
|
||||
def get_prompt_components():
|
||||
# This function reads and renders all prompts inside /prompts/components and returns them in dictionary
|
||||
|
||||
answers = inquirer.prompt(questions, theme=GreenPassion())
|
||||
if answers is None:
|
||||
print("No input provided!")
|
||||
return False
|
||||
# Create an empty dictionary to store the file contents.
|
||||
prompts_components = {}
|
||||
data = {
|
||||
'MAX_QUESTIONS': MAX_QUESTIONS,
|
||||
'END_RESPONSE': END_RESPONSE
|
||||
}
|
||||
|
||||
user_flows[flow_index] = answers['correction']
|
||||
return False
|
||||
# Create a FileSystemLoader
|
||||
file_loader = FileSystemLoader('prompts/components')
|
||||
|
||||
# Create the Jinja2 environment
|
||||
env = Environment(loader=file_loader)
|
||||
|
||||
# Get the list of template names
|
||||
template_names = env.list_templates()
|
||||
|
||||
# For each template, load and store its content
|
||||
for template_name in template_names:
|
||||
# Get the filename without extension as the dictionary key.
|
||||
file_key = os.path.splitext(template_name)[0]
|
||||
|
||||
# Load the template and render it with no variables
|
||||
file_content = env.get_template(template_name).render(data)
|
||||
|
||||
# Store the file content in the dictionary
|
||||
prompts_components[file_key] = file_content
|
||||
|
||||
return prompts_components
|
||||
|
||||
|
||||
def get_sys_message(role):
|
||||
# Create a FileSystemLoader
|
||||
file_loader = FileSystemLoader('prompts/system_messages')
|
||||
|
||||
# Create the Jinja2 environment
|
||||
env = Environment(loader=file_loader)
|
||||
|
||||
# Load the template
|
||||
template = env.get_template(f'{role}.prompt')
|
||||
|
||||
# Render the template with no variables
|
||||
content = template.render()
|
||||
|
||||
return {
|
||||
"role": "system",
|
||||
"content": content
|
||||
}
|
||||
|
||||
|
||||
def find_role_from_step(target):
|
||||
for role, values in ROLES.items():
|
||||
if target in values:
|
||||
return role
|
||||
|
||||
return 'product_owner'
|
||||
|
||||
|
||||
def get_os_info():
|
||||
os_info = {
|
||||
"OS": platform.system(),
|
||||
"OS Version": platform.version(),
|
||||
"Architecture": platform.architecture()[0],
|
||||
"Machine": platform.machine(),
|
||||
"Node": platform.node(),
|
||||
"Release": platform.release(),
|
||||
}
|
||||
|
||||
if os_info["OS"] == "Linux":
|
||||
os_info["Distribution"] = ' '.join(distro.linux_distribution(full_distribution_name=True))
|
||||
elif os_info["OS"] == "Windows":
|
||||
os_info["Win32 Version"] = ' '.join(platform.win32_ver())
|
||||
elif os_info["OS"] == "Mac":
|
||||
os_info["Mac Version"] = platform.mac_ver()[0]
|
||||
|
||||
# Convert the dictionary to a readable text format
|
||||
output = "\n".join(f"{key}: {value}" for key, value in os_info.items())
|
||||
return output
|
||||
|
||||
|
||||
def execute_step(matching_step, current_step):
|
||||
matching_step_index = STEPS.index(matching_step) if matching_step in STEPS else None
|
||||
current_step_index = STEPS.index(current_step) if current_step in STEPS else None
|
||||
|
||||
return matching_step_index is not None and current_step_index is not None and current_step_index >= matching_step_index
|
||||
|
||||
|
||||
def split_into_bullets(text):
|
||||
pattern = re.compile(r'\n*\d+\.\s\*\*')
|
||||
split_text = re.split(pattern, text)
|
||||
split_text = [bullet for bullet in split_text if bullet] # Remove any empty strings from the list
|
||||
return split_text
|
||||
|
||||
Reference in New Issue
Block a user