From ad3bafcd35bfc46ca7cfe5942aff8215ce3fcb49 Mon Sep 17 00:00:00 2001 From: MangoFanFanw Date: Sat, 6 Jun 2026 10:04:26 +0800 Subject: [PATCH] =?UTF-8?q?feat(cli):=20=E5=AE=9E=E7=8E=B0=20nyahome=20con?= =?UTF-8?q?fig=20=E5=91=BD=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 允许通过 nyahome 终端命令修改设置 同时再次调整数据库有关的内部常量的位置 --- src/nyahome/cli/cli_check.py | 2 +- src/nyahome/cli/cli_config.py | 70 ++++++++++++++++++++++++++++++++++ src/nyahome/config/__init__.py | 2 + src/nyahome/config/manager.py | 46 ++++++++++++++++++++++ src/nyahome/data.py | 6 +++ src/nyahome/database/engine.py | 7 +--- src/nyahome/manage.py | 21 ++++++++-- 7 files changed, 143 insertions(+), 11 deletions(-) create mode 100644 src/nyahome/cli/cli_config.py create mode 100644 src/nyahome/data.py diff --git a/src/nyahome/cli/cli_check.py b/src/nyahome/cli/cli_check.py index 1373c3d..d6dd85d 100644 --- a/src/nyahome/cli/cli_check.py +++ b/src/nyahome/cli/cli_check.py @@ -5,7 +5,7 @@ from pathlib import Path from typing import Mapping from nyahome.cli.cli import console -from nyahome.database.engine import db_driver_available, db_type_allowlist +from nyahome.data import db_type_allowlist, db_driver_available class CliWarning: diff --git a/src/nyahome/cli/cli_config.py b/src/nyahome/cli/cli_config.py new file mode 100644 index 0000000..bc2e827 --- /dev/null +++ b/src/nyahome/cli/cli_config.py @@ -0,0 +1,70 @@ +from typing import Annotated + +import typer +from rich.table import Table + +from nyahome.config import Config, config_manager + +from .cli import console + +config_app = typer.Typer() + + +@config_app.command(name="list") +def list_all_configs() -> None: + """ + 列出所有 NyaHome 定义的设置项。直接输出,可能包含敏感信息。 + + 同时包含默认值和当前值。在 NyaHome 首次运行时,所有设置项都会以默认值存储。 + """ + config_manager.sync_load_config() + ci = Config() + + table = Table(title="NyaHome 设置") + table.add_column("设置键名", style="cyan", no_wrap=True) + table.add_column("值类型", style="bright_black", no_wrap=True) + table.add_column("当前值", style="white") + table.add_column("默认值", style="bright_black") + + for key, value in config_manager.get_config().items(): + default_value = getattr(ci, key) + table.add_row(key, type(default_value).__name__, str(value), str(default_value)) + + console.print(table) + + +@config_app.command(name="set") +def set_config_item( + key: Annotated[str, typer.Argument(help="设置键名")], + value: Annotated[list[str], typer.Argument(help="设置键新值,类型会自动转换,多个输入将被视作列表")], +) -> None: + """ + 修改一项设置。 + + 目前,NyaHome 的设置键所支持的值类型包括:str int bool list + """ + config_manager.sync_load_config() + if len(value) == 1: + value = value[0] + try: + config_manager.set(key, value) + except AttributeError: + console.print(f"[yellow]设置失败,设置键 [cyan]{key}[/cyan] 不存在。[/yellow]") + config_manager.sync_save_config() + console.print(f"已经将设置项 [cyan]{key}[/cyan] 的值设置为 [cyan]{value}[/cyan]") + + +@config_app.command(name="reset") +def reset_config_item( + key: Annotated[str, typer.Argument(help="设置键名")], +) -> None: + """ + 重置一项设置至默认值。 + """ + config_manager.sync_load_config() + try: + config_manager.reset(key) + except AttributeError: + console.print(f"[yellow]设置失败,设置键 [cyan]{key}[/cyan] 不存在。[/yellow]") + config_manager.sync_save_config() + console.print(f"已经将设置项 [cyan]{key}[/cyan] 的值重置为默认值。") diff --git a/src/nyahome/config/__init__.py b/src/nyahome/config/__init__.py index f7dd69e..79bf087 100644 --- a/src/nyahome/config/__init__.py +++ b/src/nyahome/config/__init__.py @@ -1,5 +1,7 @@ +from .config import Config from .manager import config_manager __all__ = [ + Config, config_manager, ] diff --git a/src/nyahome/config/manager.py b/src/nyahome/config/manager.py index a354c45..7483f62 100644 --- a/src/nyahome/config/manager.py +++ b/src/nyahome/config/manager.py @@ -15,6 +15,11 @@ T = TypeVar("T") class ConfigManager: + """ + ConfigManager 携带一个初始化的 Config 实例。在 Config 初始化时,所有的默认设置键的值就都已经加载。 + 因此,如果不 load_config,ConfigManager 也将持有一套默认设置。 + """ + def __init__(self) -> None: CONFIG_PATH.parent.mkdir(exist_ok=True) self._config = Config() @@ -76,6 +81,47 @@ class ConfigManager: """ return getattr(self._config, key, default) # type: ignore[return-value] + def set(self, key: str, value: T) -> None: + """ + 设置配置项。 + + Args: + key: 配置键名 + value: 配置键的新值,可以是(且仅支持)字符串、整型以及列表。 + """ + try: + old_value = self.get(key) + except AttributeError as e: + raise e + + match old_value: + case str(): + new_value = str(value) + case int(): + new_value = int(value) + case bool(): + new_value = bool(value) + case list(): + new_value = [x for x in value] + case _: + raise TypeError(f"不支持 {type(old_value).__name__} 类型的设置项。({key})") + setattr(self._config, key, new_value) + + def reset(self, key: str) -> None: + """ + 将配置项恢复至默认值。 + + Args: + key: 配置键名 + + """ + ci = Config() + try: + default_value = getattr(ci, key) + except AttributeError as e: + raise e + setattr(self._config, key, default_value) + def get_config(self) -> dict[str, Any]: config = {} for attr in dir(self._config): diff --git a/src/nyahome/data.py b/src/nyahome/data.py new file mode 100644 index 0000000..f7b0b8c --- /dev/null +++ b/src/nyahome/data.py @@ -0,0 +1,6 @@ +db_driver_available = { + "sqlite": ["sqlite3"], + "mysql": ["pymysql"], + "postgresql": ["psycopg"], +} +db_type_allowlist = ["sqlite", "mysql", "postgresql"] \ No newline at end of file diff --git a/src/nyahome/database/engine.py b/src/nyahome/database/engine.py index c48ae8e..2492a53 100644 --- a/src/nyahome/database/engine.py +++ b/src/nyahome/database/engine.py @@ -3,12 +3,7 @@ import os from sqlalchemy import Engine from sqlmodel import create_engine -db_driver_available = { - "sqlite": ["sqlite3"], - "mysql": ["pymysql"], - "postgresql": ["psycopg"], -} -db_type_allowlist = ["sqlite", "mysql", "postgresql"] +from nyahome.data import db_driver_available, db_type_allowlist def build_engine() -> Engine: diff --git a/src/nyahome/manage.py b/src/nyahome/manage.py index a847bac..f3725a2 100644 --- a/src/nyahome/manage.py +++ b/src/nyahome/manage.py @@ -12,6 +12,7 @@ from rich.table import Table from nyahome import __version__ from nyahome.cli.cli import console from nyahome.cli.cli_aii import aii_app +from nyahome.cli.cli_config import config_app from nyahome.cli.cli_env import ENV_PATH, env_app app = typer.Typer( @@ -38,7 +39,7 @@ def main( is_eager=True, ), ) -> None: - console.print("[bright_black]NyaHome 仍然处于极早期的阶段。如果遇到任何问题,请告诉芒果帆帆喵![/bright_black]") + console.print("(!) [bright_black]NyaHome 仍然处于极早期的阶段。如果遇到任何问题,请告诉芒果帆帆喵![/bright_black]") @app.command() @@ -91,7 +92,8 @@ def init() -> None: from nyahome.cli.cli import DATA_DIR, ENV_PATH, LOGGING_YAML from nyahome.cli.cli_check import LOGGING_YAML_CONTENT - from nyahome.database.engine import db_driver_available, db_type_allowlist + from nyahome.config import config_manager + from nyahome.data import db_driver_available, db_type_allowlist console.print("\n准备初始化 NyaHome。") @@ -153,6 +155,16 @@ def init() -> None: set_key(ENV_PATH, "NYAHOME_UVICORN_RELOAD", "true" if un_reload else "false") console.print("已设置 uvicorn 启动配置。") + # 4.NyaHome 设置初始化 + console.print("\n4. NyaHome 设置初始化") + try: + config_manager.sync_load_config() + except FileNotFoundError: + console.print("配置文件 [cyan].nyahome/config.json[/cyan] 不存在,创建默认配置。") + config_manager.sync_save_config() + else: + console.print("配置文件已存在,跳过。") + @app.command() def check() -> None: @@ -203,8 +215,9 @@ def check() -> None: console.print(f"\n[yellow]完成自检,共有 {cw.counter} 个警告。[/yellow]") -app.add_typer(env_app, name="env", no_args_is_help=True, help="设置 NyaHome 应用的环境变量。") -app.add_typer(aii_app, name="aii", no_args_is_help=True, help="添加、设置、修改 AI 提供商和模型。") +app.add_typer(config_app, name="config", no_args_is_help=True, help="设置 NyaHome 的设置。(需要初始化)") +app.add_typer(env_app, name="env", no_args_is_help=True, help="设置 NyaHome 应用的环境变量。(需要初始化)") +app.add_typer(aii_app, name="aii", no_args_is_help=True, help="添加、设置、修改 AI 提供商和模型。(需要初始化)") if __name__ == "__main__":