mirror of
https://github.com/OMGeeky/gpt-pilot.git
synced 2026-02-23 15:49:50 +01:00
Merge branch 'feature/load-app-by-user-workspace'
# Conflicts: # pilot/utils/arguments.py
This commit is contained in:
@@ -23,6 +23,7 @@ from database.models.environment_setup import EnvironmentSetup
|
||||
from database.models.development import Development
|
||||
from database.models.file_snapshot import FileSnapshot
|
||||
from database.models.command_runs import CommandRuns
|
||||
from database.models.user_apps import UserApps
|
||||
from database.models.user_inputs import UserInputs
|
||||
from database.models.files import File
|
||||
|
||||
@@ -84,6 +85,16 @@ def save_app(args):
|
||||
return app
|
||||
|
||||
|
||||
def save_user_app(user_id, app_id, workspace):
|
||||
try:
|
||||
user_app = UserApps.get((UserApps.user == user_id) & (UserApps.app == app_id))
|
||||
user_app.workspace = workspace
|
||||
user_app.save()
|
||||
except DoesNotExist:
|
||||
user_app = UserApps.create(user=user_id, app=app_id, workspace=workspace)
|
||||
|
||||
return user_app
|
||||
|
||||
def save_progress(app_id, step, data):
|
||||
progress_table_map = {
|
||||
'project_description': ProjectDescription,
|
||||
@@ -124,6 +135,14 @@ def get_app(app_id):
|
||||
raise ValueError(f"No app with id: {app_id}")
|
||||
|
||||
|
||||
def get_app_by_user_workspace(user_id, workspace):
|
||||
try:
|
||||
user_app = UserApps.get((UserApps.user == user_id) & (UserApps.workspace == workspace))
|
||||
return user_app.app
|
||||
except DoesNotExist:
|
||||
return None
|
||||
|
||||
|
||||
def get_progress_steps(app_id, step=None):
|
||||
progress_table_map = {
|
||||
'project_description': ProjectDescription,
|
||||
@@ -309,7 +328,7 @@ def get_all_connected_steps(step, previous_step_field_name):
|
||||
|
||||
|
||||
def delete_all_app_development_data(app):
|
||||
models = [DevelopmentSteps, CommandRuns, UserInputs, File, FileSnapshot]
|
||||
models = [DevelopmentSteps, CommandRuns, UserInputs, UserApps, File, FileSnapshot]
|
||||
for model in models:
|
||||
model.delete().where(model.app == app).execute()
|
||||
|
||||
@@ -354,6 +373,7 @@ def create_tables():
|
||||
Development,
|
||||
FileSnapshot,
|
||||
CommandRuns,
|
||||
UserApps,
|
||||
UserInputs,
|
||||
File,
|
||||
])
|
||||
@@ -374,6 +394,7 @@ def drop_tables():
|
||||
Development,
|
||||
FileSnapshot,
|
||||
CommandRuns,
|
||||
UserApps,
|
||||
UserInputs,
|
||||
File,
|
||||
]:
|
||||
@@ -423,7 +444,7 @@ def create_database():
|
||||
|
||||
def tables_exist():
|
||||
tables = [User, App, ProjectDescription, UserStories, UserTasks, Architecture, DevelopmentPlanning,
|
||||
DevelopmentSteps, EnvironmentSetup, Development, FileSnapshot, CommandRuns, UserInputs, File]
|
||||
DevelopmentSteps, EnvironmentSetup, Development, FileSnapshot, CommandRuns, UserApps, UserInputs, File]
|
||||
|
||||
if DATABASE_TYPE == "postgres":
|
||||
for table in tables:
|
||||
|
||||
18
pilot/database/models/user_apps.py
Normal file
18
pilot/database/models/user_apps.py
Normal file
@@ -0,0 +1,18 @@
|
||||
from peewee import *
|
||||
|
||||
from database.models.components.base_models import BaseModel
|
||||
from database.models.app import App
|
||||
from database.models.user import User
|
||||
|
||||
|
||||
class UserApps(BaseModel):
|
||||
id = AutoField()
|
||||
app = ForeignKeyField(App, on_delete='CASCADE')
|
||||
user = ForeignKeyField(User, on_delete='CASCADE')
|
||||
workspace = CharField(null=True)
|
||||
|
||||
class Meta:
|
||||
db_table = 'user_apps'
|
||||
indexes = (
|
||||
(('app', 'user'), True),
|
||||
)
|
||||
@@ -97,7 +97,7 @@ class Project:
|
||||
# TODO END
|
||||
|
||||
self.developer = Developer(self)
|
||||
self.developer.set_up_environment();
|
||||
self.developer.set_up_environment()
|
||||
|
||||
self.developer.start_coding()
|
||||
|
||||
|
||||
@@ -248,7 +248,7 @@ class Developer(Agent):
|
||||
'step_type': type,
|
||||
'directory_tree': directory_tree,
|
||||
'step_index': step_index
|
||||
}, EXECUTE_COMMANDS);
|
||||
}, EXECUTE_COMMANDS)
|
||||
if type == 'COMMAND':
|
||||
for cmd in step_details:
|
||||
run_command_until_success(cmd['command'], cmd['timeout'], convo)
|
||||
|
||||
@@ -24,16 +24,17 @@ class ProductOwner(Agent):
|
||||
step = get_progress_steps(self.project.args['app_id'], self.project.current_step)
|
||||
if step and not execute_step(self.project.args['step'], self.project.current_step):
|
||||
step_already_finished(self.project.args, step)
|
||||
self.project.root_path = setup_workspace(self.project.args['name'])
|
||||
self.project.root_path = setup_workspace(self.project.args)
|
||||
self.project.project_description = step['summary']
|
||||
self.project.project_description_messages = step['messages']
|
||||
return
|
||||
|
||||
# PROJECT DESCRIPTION
|
||||
self.project.args['app_type'] = ask_for_app_type()
|
||||
self.project.args['name'] = clean_filename(ask_user(self.project, 'What is the project name?'))
|
||||
if 'name' not in self.project.args:
|
||||
self.project.args['name'] = clean_filename(ask_user(self.project, 'What is the project name?'))
|
||||
|
||||
self.project.root_path = setup_workspace(self.project.args['name'])
|
||||
self.project.root_path = setup_workspace(self.project.args)
|
||||
|
||||
self.project.app = save_app(self.project.args)
|
||||
|
||||
@@ -45,7 +46,9 @@ class ProductOwner(Agent):
|
||||
|
||||
print(colored('Project Summary:\n', 'green', attrs=['bold']))
|
||||
high_level_summary = convo_project_description.send_message('utils/summary.prompt',
|
||||
{'conversation': '\n'.join([f"{msg['role']}: {msg['content']}" for msg in high_level_messages])})
|
||||
{'conversation': '\n'.join(
|
||||
[f"{msg['role']}: {msg['content']}" for msg in
|
||||
high_level_messages])})
|
||||
|
||||
save_progress(self.project.args['app_id'], self.project.current_step, {
|
||||
"prompt": main_prompt,
|
||||
@@ -59,7 +62,6 @@ class ProductOwner(Agent):
|
||||
return
|
||||
# PROJECT DESCRIPTION END
|
||||
|
||||
|
||||
def get_user_stories(self):
|
||||
self.project.current_step = 'user_stories'
|
||||
self.convo_user_stories = AgentConvo(self)
|
||||
@@ -111,7 +113,7 @@ class ProductOwner(Agent):
|
||||
logger.info(msg)
|
||||
|
||||
self.project.user_tasks = self.convo_user_stories.continuous_conversation('user_stories/user_tasks.prompt',
|
||||
{ 'END_RESPONSE': END_RESPONSE })
|
||||
{'END_RESPONSE': END_RESPONSE})
|
||||
|
||||
logger.info(f"Final user tasks: {self.project.user_tasks}")
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import os
|
||||
import re
|
||||
import hashlib
|
||||
import getpass
|
||||
import sys
|
||||
import uuid
|
||||
|
||||
from termcolor import colored
|
||||
|
||||
from database.database import get_app
|
||||
from database.database import get_app, get_app_by_user_workspace
|
||||
|
||||
|
||||
def get_arguments():
|
||||
@@ -25,21 +26,40 @@ def get_arguments():
|
||||
else:
|
||||
arguments[arg] = True
|
||||
|
||||
if 'user_id' not in arguments:
|
||||
arguments['user_id'] = username_to_uuid(getpass.getuser())
|
||||
|
||||
app = None
|
||||
if 'workspace' in arguments:
|
||||
app = get_app_by_user_workspace(arguments['user_id'], arguments['workspace'])
|
||||
if app is not None:
|
||||
arguments['app_id'] = app.id
|
||||
else:
|
||||
arguments['workspace'] = None
|
||||
|
||||
if 'app_id' in arguments:
|
||||
try:
|
||||
app = get_app(arguments['app_id'])
|
||||
arguments['user_id'] = str(app.user.id)
|
||||
if app is None:
|
||||
app = get_app(arguments['app_id'])
|
||||
|
||||
# arguments['user_id'] = str(app.user.id)
|
||||
arguments['app_type'] = app.app_type
|
||||
arguments['name'] = app.name
|
||||
# Add any other fields from the App model you wish to include
|
||||
|
||||
print(colored('\n------------------ LOADING PROJECT ----------------------', 'green', attrs=['bold']))
|
||||
print(colored(f'{app.name} (app_id={arguments["app_id"]})', 'green', attrs=['bold']))
|
||||
print(colored('--------------------------------------------------------------\n', 'green', attrs=['bold']))
|
||||
except ValueError as e:
|
||||
print(e)
|
||||
# Handle the error as needed, possibly exiting the script
|
||||
else:
|
||||
arguments['app_id'] = str(uuid.uuid4())
|
||||
|
||||
if 'user_id' not in arguments:
|
||||
arguments['user_id'] = getpass.getuser()
|
||||
print(colored('\n------------------ STARTING NEW PROJECT ----------------------', 'green', attrs=['bold']))
|
||||
print(f"If you wish to continue with this project in future run:")
|
||||
print(colored(f'python {sys.argv[0]} app_id={arguments["app_id"]}', 'green', attrs=['bold']))
|
||||
print(colored('--------------------------------------------------------------\n', 'green', attrs=['bold']))
|
||||
|
||||
if 'email' not in arguments:
|
||||
arguments['email'] = get_email()
|
||||
@@ -50,10 +70,6 @@ def get_arguments():
|
||||
if 'step' not in arguments:
|
||||
arguments['step'] = None
|
||||
|
||||
print(colored('\n------------------ STARTING NEW PROJECT ----------------------', 'green', attrs=['bold']))
|
||||
print(f"If you wish to continue with this project in future run:")
|
||||
print(colored(f'python main.py app_id={arguments["app_id"]}', 'green', attrs=['bold']))
|
||||
print(colored('--------------------------------------------------------------\n', 'green', attrs=['bold']))
|
||||
return arguments
|
||||
|
||||
|
||||
@@ -75,3 +91,10 @@ def get_email():
|
||||
# todo change email so its not uuid4 but make sure to fix storing of development steps where
|
||||
# 1 user can have multiple apps. In that case each app should have its own development steps
|
||||
return str(uuid.uuid4())
|
||||
|
||||
|
||||
# TODO can we make BaseModel.id a CharField with default=uuid4?
|
||||
def username_to_uuid(username):
|
||||
sha1 = hashlib.sha1(username.encode()).hexdigest()
|
||||
uuid_str = "{}-{}-{}-{}-{}".format(sha1[:8], sha1[8:12], sha1[12:16], sha1[16:20], sha1[20:32])
|
||||
return str(uuid.UUID(uuid_str))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from database.database import save_user_app
|
||||
|
||||
def get_parent_folder(folder_name):
|
||||
current_path = Path(os.path.abspath(__file__)) # get the path of the current script
|
||||
@@ -11,10 +11,18 @@ def get_parent_folder(folder_name):
|
||||
return current_path.parent
|
||||
|
||||
|
||||
def setup_workspace(project_name):
|
||||
def setup_workspace(args):
|
||||
if args['workspace'] is not None:
|
||||
try:
|
||||
save_user_app(args['user_id'], args['app_id'], args['workspace'])
|
||||
except Exception as e:
|
||||
print(str(e))
|
||||
|
||||
return args['workspace']
|
||||
|
||||
root = get_parent_folder('pilot')
|
||||
create_directory(root, 'workspace')
|
||||
project_path = create_directory(os.path.join(root, 'workspace'), project_name)
|
||||
project_path = create_directory(os.path.join(root, 'workspace'), args['name'])
|
||||
create_directory(project_path, 'tests')
|
||||
return project_path
|
||||
|
||||
|
||||
26
pilot/utils/test_files.py
Normal file
26
pilot/utils/test_files.py
Normal file
@@ -0,0 +1,26 @@
|
||||
import pytest
|
||||
from .files import setup_workspace
|
||||
|
||||
|
||||
def test_setup_workspace_with_existing_workspace():
|
||||
args = {'workspace': 'some_directory', 'name': 'sample'}
|
||||
result = setup_workspace(args)
|
||||
assert result == 'some_directory'
|
||||
|
||||
|
||||
def mocked_create_directory(path, exist_ok=True):
|
||||
return
|
||||
|
||||
|
||||
def mocked_abspath(file):
|
||||
return "/root_path/pilot/helpers"
|
||||
|
||||
|
||||
def test_setup_workspace_without_existing_workspace(monkeypatch):
|
||||
args = {'workspace': None, 'name': 'project_name'}
|
||||
|
||||
monkeypatch.setattr('os.path.abspath', mocked_abspath)
|
||||
monkeypatch.setattr('os.makedirs', mocked_create_directory)
|
||||
|
||||
result = setup_workspace(args)
|
||||
assert result.replace('\\', '/') == "/root_path/workspace/project_name"
|
||||
Reference in New Issue
Block a user