Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【WEBUI】Saving runtime configuration in root directory automatically #28

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions src/agentscope/_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from typing import Optional, Union, Sequence
from agentscope import agents
from .agents import AgentBase
from ._runtime import Runtime
from ._runtime import _runtime
from .file_manager import file_manager
from .utils.logging_utils import LOG_LEVEL, setup_logger
from .utils.monitor import MonitorFactory
Expand Down Expand Up @@ -73,7 +73,7 @@ def init(
_INIT_SETTINGS["model_configs"] = model_configs
_INIT_SETTINGS["project"] = project
_INIT_SETTINGS["name"] = name
_INIT_SETTINGS["runtime_id"] = Runtime.runtime_id
_INIT_SETTINGS["runtime_id"] = _runtime.runtime_id
_INIT_SETTINGS["save_dir"] = save_dir
_INIT_SETTINGS["save_api_invoke"] = save_api_invoke
_INIT_SETTINGS["save_log"] = save_log
Expand Down Expand Up @@ -119,7 +119,7 @@ def init_process(
save_log: bool = False,
logger_level: LOG_LEVEL = _DEFAULT_LOG_LEVEL,
) -> None:
"""A entry to initialize the package in a process.
"""An entry to initialize the package in a process.

Args:
project (`Optional[str]`, defaults to `None`):
Expand Down Expand Up @@ -147,12 +147,12 @@ def init_process(
read_model_configs(model_configs)

# Init the runtime
Runtime.project = project
Runtime.name = name
_runtime.project = project
_runtime.name = name
if runtime_id is not None:
Runtime.runtime_id = runtime_id
_runtime.runtime_id = runtime_id

# Init file manager
# Init file manager and save configs by default
file_manager.init(save_dir, save_api_invoke)

# Init monitor
Expand Down
54 changes: 48 additions & 6 deletions src/agentscope/_runtime.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,64 @@
# -*- coding: utf-8 -*-
"""Manage the id for each runtime"""
from datetime import datetime
from typing import Any

from agentscope.utils.tools import _get_timestamp
from agentscope.utils.tools import _generate_random_code

_RUNTIME_ID_FORMAT = "run_%Y%m%d-%H%M%S_{}"
_RUNTIME_TIMESTAMP_FORMAT = "%Y-%m-%d %H:%M:%S"


class Runtime:
"""Used to record the runtime information."""
class _Runtime:
"""A singleton class used to record the runtime information, which will
be initialized when the package is imported."""

project: str = None
"""The project name, which is used to identify the project."""

name: str = None
"""The name for runtime, which is used to identify this runtime."""

runtime_id: str = _get_timestamp(_RUNTIME_ID_FORMAT).format(
_generate_random_code(),
)
runtime_id: str = None
"""The id for runtime, which is used to identify the this runtime and
name the saving directory."""
name the saving directory."""

_timestamp: datetime = datetime.now()
"""The timestamp of when the runtime is initialized."""

_instance = None

def __new__(cls, *args: Any, **kwargs: Any) -> Any:
"""Create a singleton instance."""
if not cls._instance:
cls._instance = super(_Runtime, cls).__new__(
cls,
*args,
**kwargs,
)
return cls._instance

def __init__(self) -> None:
"""Generate random project name, runtime name and default
runtime_id when the package is initialized. After that, user can set
them by calling `agentscope.init(project="xxx", name="xxx",
runtime_id="xxx")`."""

self.project = _generate_random_code()
self.name = _generate_random_code(uppercase=False)

# Obtain time from timestamp in string format, and then turn it into
# runtime ID format
self.runtime_id = _get_timestamp(
_RUNTIME_ID_FORMAT,
self._timestamp,
).format(self.name)

@property
def timestamp(self) -> str:
"""Get the current timestamp in specific format."""
return self._timestamp.strftime(_RUNTIME_TIMESTAMP_FORMAT)


_runtime = _Runtime()
3 changes: 3 additions & 0 deletions src/agentscope/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@
_DEFAULT_SUBDIR_CODE = "code"
_DEFAULT_SUBDIR_FILE = "file"
_DEFAULT_SUBDIR_INVOKE = "invoke"
_DEFAULT_CFG_NAME = ".config"
_DEFAULT_IMAGE_NAME = "image_{}_{}.png"
_DEFAULT_SQLITE_DB_PATH = "agentscope.db"


# for model wrapper
_DEFAULT_MAX_RETRIES = 3
_DEFAULT_MESSAGES_KEY = "inputs"
Expand Down
34 changes: 29 additions & 5 deletions src/agentscope/file_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import numpy as np

from agentscope._runtime import Runtime
from agentscope._runtime import _runtime
from agentscope.utils.tools import _download_file, _get_timestamp
from agentscope.utils.tools import _generate_random_code
from agentscope.constants import (
Expand All @@ -16,6 +16,7 @@
_DEFAULT_SUBDIR_INVOKE,
_DEFAULT_SQLITE_DB_PATH,
_DEFAULT_IMAGE_NAME,
_DEFAULT_CFG_NAME,
)


Expand Down Expand Up @@ -44,19 +45,24 @@ def __new__(cls, *args: Any, **kwargs: Any) -> Any:
def _get_and_create_subdir(self, subdir: str) -> str:
"""Get the path of the subdir and create the subdir if it does not
exist."""
path = os.path.join(self.dir, Runtime.runtime_id, subdir)
path = os.path.join(self.dir, _runtime.runtime_id, subdir)
if not os.path.exists(path):
os.makedirs(path)
return path

def _get_file_path(self, file_name: str) -> str:
"""Get the path of the file."""
return os.path.join(self.dir, Runtime.runtime_id, file_name)
return os.path.join(self.dir, _runtime.runtime_id, file_name)

@property
def dir_root(self) -> str:
"""The root directory to save code, information and logs."""
return os.path.join(self.dir, _runtime.runtime_id)

@property
def dir_log(self) -> str:
"""The directory for saving logs."""
return os.path.join(self.dir, Runtime.runtime_id)
return os.path.join(self.dir, _runtime.runtime_id)

@property
def dir_file(self) -> str:
Expand All @@ -82,12 +88,30 @@ def path_db(self) -> str:
def init(self, save_dir: str, save_api_invoke: bool = False) -> None:
"""Set the directory for saving files."""
self.dir = save_dir
runtime_dir = os.path.join(save_dir, Runtime.runtime_id)
runtime_dir = os.path.join(save_dir, _runtime.runtime_id)
if not os.path.exists(runtime_dir):
os.makedirs(runtime_dir)

self.save_api_invoke = save_api_invoke

# Save the project and name to the runtime directory
self._save_config()

def _save_config(self) -> None:
"""Save the configuration of the runtime in its root directory."""
cfg = {
"project": _runtime.project,
"name": _runtime.name,
"id": _runtime.runtime_id,
"timestamp": _runtime.timestamp,
}
with open(
os.path.join(self.dir_root, _DEFAULT_CFG_NAME),
"w",
encoding="utf-8",
) as file:
json.dump(cfg, file, indent=4)

def save_api_invocation(
self,
prefix: str,
Expand Down
25 changes: 21 additions & 4 deletions src/agentscope/utils/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,15 @@ def extract_json_str(json_str: str) -> str:
return json_str[start_index:]


def _get_timestamp(format_: str = "%Y-%m-%d %H:%M:%S") -> str:
def _get_timestamp(
format_: str = "%Y-%m-%d %H:%M:%S",
time: datetime.datetime = None,
) -> str:
"""Get current timestamp."""
return datetime.datetime.now().strftime(format_)
if time is None:
return datetime.datetime.now().strftime(format_)
else:
return time.strftime(format_)


def to_openai_dict(item: dict) -> dict:
Expand Down Expand Up @@ -140,7 +146,18 @@ def _download_file(url: str, path_file: str, max_retries: int = 3) -> bool:
return False


def _generate_random_code(length: int = 6) -> str:
def _generate_random_code(
length: int = 6,
uppercase: bool = True,
lowercase: bool = True,
digits: bool = True,
) -> str:
"""Get random code."""
characters = string.ascii_letters + string.digits
characters = ""
if uppercase:
characters += string.ascii_uppercase
if lowercase:
characters += string.ascii_lowercase
if digits:
characters += string.digits
return "".join(secrets.choice(characters) for i in range(length))