Skip to content

Commit

Permalink
Merge pull request #149 from sambhavnoobcoder/Select-Menu-List-Command
Browse files Browse the repository at this point in the history
Implement SelectCommand with interactive menu for assets, apps, and models #133
  • Loading branch information
Bishoy-at-pieces authored Jul 24, 2024
2 parents f794c65 + acdff54 commit ae7eeae
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 37 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
# Changelog
## July 24th, 2024

- Add select menu for the list command

## April 8th, 2024

- Add the conversation command with the --rename ,--new , --delete flags
Expand Down
3 changes: 2 additions & 1 deletion src/pieces/assets/assets_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from pieces.utils import get_file_extension,sanitize_filename,export_code_to_file
from .assets_api import AssetsCommandsApi
from pieces.gui import show_error,print_model_details,space_below,double_line
from pieces.gui import show_error,print_model_details,space_below,double_line,deprecated
from pieces.settings import Settings


Expand Down Expand Up @@ -39,6 +39,7 @@ class AssetsCommands:

@classmethod
@check_assets_existence
@deprecated("open","list assets")
def open_asset(cls,**kwargs):
item_index = kwargs.get('ITEM_INDEX',1)
if not item_index:
Expand Down
2 changes: 1 addition & 1 deletion src/pieces/commands/change_model.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from pieces.gui import *
from pieces.settings import Settings


@deprecated("change_model","list models")
def change_model(**kwargs): # Change the model used in the ask command
model_index = kwargs.get('MODEL_INDEX')
try:
Expand Down
133 changes: 99 additions & 34 deletions src/pieces/commands/list_command.py
Original file line number Diff line number Diff line change
@@ -1,61 +1,126 @@
from pieces.settings import Settings
from collections.abc import Iterable
from pieces.assets import check_assets_existence,AssetsCommandsApi

from pieces.assets import check_assets_existence, AssetsCommandsApi
from pieces_os_client.api.applications_api import ApplicationsApi
from prompt_toolkit import Application
from prompt_toolkit.key_binding import KeyBindings
from prompt_toolkit.layout import Layout
from prompt_toolkit.layout.containers import HSplit, Window
from prompt_toolkit.layout.controls import FormattedTextControl
from prompt_toolkit.styles import Style
from typing import List, Tuple, Callable
from pieces.assets.assets_command import AssetsCommands
import time
from .change_model import change_model

class PiecesSelectMenu:
def __init__(self, menu_options:List[Tuple],on_enter_callback:Callable):
self.menu_options = menu_options
self.on_enter_callback = on_enter_callback
self.current_selection = 0

def get_menu_text(self):
result = []
for i, option in enumerate(self.menu_options):
if i == self.current_selection:
result.append(('class:selected', f'> {option[0]}\n'))
else:
result.append(('class:unselected', f' {option[0]}\n'))
return result

def run(self):
bindings = KeyBindings()

@bindings.add('up')
def move_up(event):
if self.current_selection > 0:
self.current_selection -= 1
event.app.layout.focus(self.menu_window)

@bindings.add('down')
def move_down(event):
if self.current_selection < len(self.menu_options) - 1:
self.current_selection += 1
event.app.layout.focus(self.menu_window)

@bindings.add('enter')
def select_option(event):
args = self.menu_options[self.current_selection][1]
event.app.exit(result=args)

menu_control = FormattedTextControl(text=self.get_menu_text)
self.menu_window = Window(content=menu_control, always_hide_cursor=True)

layout = Layout(HSplit([self.menu_window]))

style = Style.from_dict({
'selected': 'reverse',
'unselected': ''
})

app = Application(layout=layout, key_bindings=bindings, style=style, full_screen=True)
args = app.run()

if isinstance(args, list):
self.on_enter_callback(*args)
elif isinstance(args, str):
self.on_enter_callback(args)
elif isinstance(args, dict):
self.on_enter_callback(**args)

class ListCommand:
@classmethod
def list_command(cls,**kwargs):
type = kwargs.get("type","assets")
max_assets = kwargs.get("max_assets",10)
def list_command(cls, **kwargs):
type = kwargs.get("type", "assets")
max_assets = kwargs.get("max_assets", 10)
if max_assets < 1:
print("Max assets must be greater than 0")
max_assets = 10

if type == "assets":
cls.list_assets(max_assets)
elif type == "apps":
cls.list_apps()
cls.list_apps()
elif type == "models":
cls.list_models()
@staticmethod
def list_models():
for idx,model_name in enumerate(Settings.models,start=1):
print(f"{idx}: {model_name}")
print(f"Currently using: {Settings.model_name} with uuid {Settings.model_id}")

@staticmethod
def list_apps():
# Get the list of applications

@classmethod
@check_assets_existence
def list_assets(cls, max_assets: int = 10):
assets_snapshot = AssetsCommandsApi().assets_snapshot
assets = []
for i, uuid in enumerate(list(assets_snapshot.keys())[:max_assets], start=1):
asset = AssetsCommandsApi.get_asset_snapshot(uuid)
assets.append((f"{i}: {asset.name}", {"ITEM_INDEX":i,"show_warning":False}))

select_menu = PiecesSelectMenu(assets, AssetsCommands.open_asset)
select_menu.run()

@classmethod
def list_models(cls):
if not hasattr(Settings, 'models'):
Settings.load_models()

applications_api = ApplicationsApi(Settings.api_client)
if not Settings.models:
print("No models available.")
return

models = [(f"{idx}: {model_name}", {"MODEL_INDEX":idx,"show_warning":False}) for idx, model_name in enumerate(Settings.models.keys(), start=1)]
# models.append((f"Currently using: {Settings.model_name} with uuid {Settings.model_id}")) # TODO
# TODO: add a normal print message
select_menu = PiecesSelectMenu(models, change_model)
select_menu.run()

@classmethod
def list_apps(cls):
applications_api = ApplicationsApi(Settings.api_client)
application_list = applications_api.applications_snapshot()
# Check if the application_list object has an iterable attribute and if it is an instance of Iterable

if hasattr(application_list, 'iterable') and isinstance(application_list.iterable, Iterable):
# Iterate over the applications in the list
for i, app in enumerate(application_list.iterable, start=1):
# Get the name of the application, default to 'Unknown' if not available
app_name = getattr(app, 'name', 'Unknown').value if hasattr(app, 'name') and hasattr(app.name, 'value') else 'Unknown'
# Get the version of the application, default to 'Unknown' if not available
app_version = getattr(app, 'version', 'Unknown')
# Get the platform of the application, default to 'Unknown' if not available
app_platform = getattr(app, 'platform', 'Unknown').value if hasattr(app, 'platform') and hasattr(app.platform, 'value') else 'Unknown'

# Print the application details
print(f"{i}: {app_name}, {app_version}, {app_platform}")
else:
# Print an error message if the 'Applications' object does not contain an iterable list of applications
print("Error: The 'Applications' object does not contain an iterable list of applications.")

@staticmethod
@check_assets_existence
def list_assets(max_assets:int=10):
assets_snapshot = AssetsCommandsApi().assets_snapshot
for i, uuid in enumerate(list(assets_snapshot.keys())[:max_assets], start=1):
asset = assets_snapshot[uuid]
if not asset:
asset = AssetsCommandsApi.get_asset_snapshot(uuid)
print(f"{i}: {asset.name}")
15 changes: 14 additions & 1 deletion src/pieces/gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,4 +160,17 @@ def show_error(error_message,error):
print(f"\033[31m{error_message}\033[0m")
print(f"\033[31m{error}\033[0m")
print()


def deprecated(command,instead):
"""
Decorator
command(str): which is the command that is deprated
instead(str): which command should we use instead
"""
def decorator(func):
def wrapper(*args, **kwargs):
if kwargs.get("show_warning",True):
print(f"\033[93m WARNING: `{command}` is deprecated and will be removed in later versions\nPlease use `{instead}` instead \033[0m")
func(*args,**kwargs)
return wrapper
return decorator

0 comments on commit ae7eeae

Please sign in to comment.