Skip to content

Commit

Permalink
Added CLI options to import and export config. Automatic add/removal …
Browse files Browse the repository at this point in the history
…of fields from cached config upon models.json update
  • Loading branch information
AlexanderLourenco committed Apr 5, 2023
1 parent e5880c6 commit 88f8dbf
Show file tree
Hide file tree
Showing 2 changed files with 162 additions and 48 deletions.
76 changes: 64 additions & 12 deletions server/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,6 @@ def __initialization_check__(self):

for model in models:
if model.status == 'pending':
print(model)
self.model_queue.put(model)

# TODO: In the future it might make sense to have local provider specific instances
Expand All @@ -207,7 +206,7 @@ def __initialization_check__(self):
capabilities=hugging_face_local.default_capabilities,
provider="huggingface-local",
status="ready",
enabled=True,
enabled=False,
parameters=hugging_face_local.default_parameters
)
hugging_face_local.add_model(model)
Expand All @@ -227,12 +226,9 @@ def __download_loop__(self):
output_buffer = io.StringIO()
model = self.model_queue.get(block=False)

print(f"Should download {model.name} from {model.provider}")

monitor_thread = MonitorThread(model, output_buffer)

monitor_thread.start()
print("About to start downloading")

sys.stderr = output_buffer
sys.stdout = output_buffer
_ = AutoTokenizer.from_pretrained(model.name)
Expand Down Expand Up @@ -312,21 +308,77 @@ def cli():
pass

@click.command()
@click.option('--host', '-h', default='localhost', help='The host to bind to [default: localhost]')
@click.option('--port', '-p', default=5432, help='The port to bind to [default: 5432]')
@click.option('--debug/--no-debug', default=False, help='Set flask to debug mode')
@click.option('--env', '-e', default=".env", help='Environment file to read and store API keys')
@click.option('--models', '-m', default=None, help='Config file containing model information')
@click.help_option('-h', '--help')
@click.option('--host', '-h', default='localhost', help='The host to bind to. Default: localhost.')
@click.option('--port', '-p', default=5432, help='The port to bind to. Default: 5432.')
@click.option('--debug/--no-debug', default=False, help='Enable or disable Flask debug mode. Default: False.')
@click.option('--env', '-e', default=".env", help='Path to the environment file for storing and reading API keys. Default: .env.')
@click.option('--models', '-m', default=None, help='Path to the configuration file for loading models. Default: None.')
def run(host, port, debug, env, models):
"""
Run the OpenPlayground server.
This command starts the OpenPlayground server with the specified options.
Arguments:
--host, -h: The host to bind to. Default: localhost.
--port, -p: The port to bind to. Default: 5432.
--debug/--no-debug: Enable or disable Flask debug mode. Default: False.
--env, -e: Path to the environment file for storing and reading API keys. Default: .env.
--models, -m: Path to the configuration file for loading models. Default: None.
Example usage:
$ openplayground run --host=0.0.0.0 --port=8080 --debug --env=keys.env --models=models.json
"""
storage = Storage(models, env)
app.config['GLOBAL_STATE'] = GlobalStateManager(storage)

app.run(host=host, port=port, debug=debug)

@click.command()
@click.help_option('-h', '--help')
@click.option('--input', '-i', default=None, help='Path to the configuration file for importing models')
def import_config(input):
"""
Import configuration settings.
This command imports configuration settings for one or more models from a file.
Arguments:
--input, -i: Path to the configuration file for importing models. Default: None.
Example usage:
$ openplayground import-config --input=/path/to/config.json
"""
Storage.import_config(input)

@click.command()
@click.help_option('-h', '--help')
@click.option('--output', '-o', default=None, help='Output file path for the exported configuration settings')
@click.pass_context
def export_config(ctx, output):
"""
Export configuration settings.
This command exports the current configuration settings to a file.
Arguments:
--output, -o: Output file path for the exported configuration settings. Default: None.
Example usage:
$ openplayground export-config --output=/path/to/config.json
"""
Storage.export_config(output)

cli.add_command(export_config)
cli.add_command(import_config)
cli.add_command(run)

if __name__ == '__main__':
app.static_folder='../app/dist'
run()
else:
app.static_folder='./static'
app.static_folder='./static'
134 changes: 98 additions & 36 deletions server/lib/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,61 +21,40 @@
APP_DIR = os.path.join(config_dir, 'openplayground')
os.makedirs(APP_DIR, exist_ok=True)

#TODO in dev it's easier if we keep replacing the file
# Need to add a dev check
if not os.path.exists(os.path.join(APP_DIR, 'models.json')):
#check if pkg_resources is available

if not pkg_resources.is_resource('server', 'models.json'):
models_json = open('./models.json').read()
else:
models_json = pkg_resources.read_text('server', 'models.json')

with open(os.path.join(APP_DIR, 'models.json'), 'w') as f:
f.write(models_json)

class Storage:
def __init__(self, models_json_path: str = None, env_file_path: str = None):
self.event_emitter = EventEmitter()
self.providers = []
self.models = []
self.models_json_path = models_json_path
self.models_json, self.models_json_path = self.__initialize_config__(models_json_path)
self.env_file_path = env_file_path

if models_json_path is None:
self.models_json_path = os.path.join(APP_DIR, 'models.json')
else:
self.models_json_path = models_json_path

if env_file_path is None:
self.env_file_path = os.path.join(os.getcwd(), 'env')
elif os.path.exists(env_file_path):
load_dotenv(env_file_path)

with open(self.models_json_path, 'r') as f:
self.models_json = json.load(f)

for provider_name, provider in self.models_json.items():
models = [
Model(
model_name,
model['capabilities'],
model['enabled'],
provider_name,
model['status'],
model['parameters'],
name=model_name,
provider=provider_name,
capabilities=model.get("capabilities", []),
enabled=model.get("enabled", False),
status=model.get("status", "ready"),
parameters=model.get("parameters", {})
)
for model_name, model in provider['models'].items()
]
self.providers.append(
Provider(
provider_name,
models,
provider.get('remoteInference', None),
provider.get('defaultCapabilities', []),
provider.get('defaultParameters', None),
os.environ.get(f'{provider_name.upper()}_API_KEY'),
provider['requiresAPIKey'],
name=provider_name,
models=models,
remote_inference=provider.get('remoteInference', None),
default_capabilities=provider.get('defaultCapabilities', []),
default_parameters=provider.get('defaultParameters', None),
api_key=os.environ.get(f'{provider_name.upper()}_API_KEY'),
requires_api_key=provider.get("requiresAPIKey", False),
search_url=provider.get('searchURL', None),
)
)
Expand All @@ -91,6 +70,67 @@ def __init__(self, models_json_path: str = None, env_file_path: str = None):
]:
EventEmitter().on(event, self.__update___)

def __initialize_config__(self, models_json_path: str = None):
if models_json_path is None:
models_json_path = os.path.join(APP_DIR, 'models.json')

original_models_json = None
if not pkg_resources.is_resource('server', 'models.json'):
original_models_json = open('./models.json').read()
else:
original_models_json = pkg_resources.read_text('server', 'models.json')

if not os.path.exists(os.path.join(APP_DIR, 'models.json')):
with open(os.path.join(APP_DIR, 'models.json'), 'w') as f:
f.write(original_models_json)
else:
original_models_json = json.loads(original_models_json)

with open(os.path.join(APP_DIR, 'models.json'), 'r') as f:
cached_models_json = json.load(f)

cached_providers = cached_models_json.keys()
original_providers = original_models_json.keys()

provider_in_original_not_cache = [provider for provider in original_providers if provider not in cached_providers]

for provider in provider_in_original_not_cache:
cached_models_json[provider] = original_models_json[provider]

cached_providers = cached_models_json.keys()

for cached_provider in cached_providers:
cached_provider_keys = cached_models_json[cached_provider].keys()
original_provider_keys = original_models_json[cached_provider].keys()

#keys in cache but not in original
cache_keys_missing = [key for key in cached_provider_keys if key not in original_provider_keys]
#keys in original but not in cache
missing_original_keys = [key for key in original_provider_keys if key not in cached_provider_keys]

for missing_cached_key in cache_keys_missing:
del cached_models_json[cached_provider][missing_cached_key]

for missing_original_key in missing_original_keys:
cached_models_json[cached_provider][missing_original_key] = original_models_json[cached_provider][missing_original_key]

cached_provider_models = cached_models_json[cached_provider]['models'].keys()
original_provider_models = original_models_json[cached_provider]['models'].keys()

for cached_model in cached_provider_models:
if cached_model not in original_provider_models:
continue

cached_model_keys = cached_models_json[cached_provider]['models'][cached_model].keys()
original_model_keys = original_models_json[cached_provider]['models'][cached_model].keys()

for original_model_key in original_model_keys:
if original_model_key not in cached_model_keys:
cached_models_json[cached_provider]['models'][cached_model][original_model_key] = original_models_json[cached_provider]['models'][cached_model][original_model_key]

with open(models_json_path, 'r') as f:
return json.load(f), models_json_path

def get_models(self) -> List[Model]:
return self.models

Expand Down Expand Up @@ -193,4 +233,26 @@ def __save__(self):
with open(self.models_json_path, 'w') as f:
json.dump(new_json, f, indent=4)

self.event_emitter.emit(EVENTS.SAVED_TO_DISK)
self.event_emitter.emit(EVENTS.SAVED_TO_DISK)

def import_config(config_path: str):
'''
Imports the models.json file from the specified path
'''
if not os.path.exists(config_path):
raise FileNotFoundError(f'{config_path} not found')

with open(config_path, 'r') as f:
with open(os.path.join(APP_DIR, 'models.json'), 'w') as f2:
f2.write(f.read())

def export_config(output_path: str):
'''
Exports the models.json file to the specified path
'''
if not os.path.exists(os.path.join(APP_DIR, 'models.json')):
raise FileNotFoundError('models.json not found')

with open(os.path.join(APP_DIR, 'models.json'), 'r') as f:
with open(output_path, 'w') as f2:
f2.write(f.read())

0 comments on commit 88f8dbf

Please sign in to comment.