From 3dfec986204b0c4a51786250f385f94f5a81ad64 Mon Sep 17 00:00:00 2001 From: rex <1073853456@qq.com> Date: Thu, 16 Oct 2025 03:42:06 +0800 Subject: [PATCH 1/7] reorganize files --- pyproject.toml | 81 ++++++++++++++++++++++++++++ requirements_dev.txt | 10 ---- setup.cfg | 14 ----- setup.py | 44 --------------- {askchat => src/askchat}/__init__.py | 4 +- {askchat => src/askchat}/ask.py | 0 {askchat => src/askchat}/askenv.py | 0 {askchat => src/askchat}/cli.py | 0 src/askchat/const.py | 0 9 files changed, 82 insertions(+), 71 deletions(-) create mode 100644 pyproject.toml delete mode 100644 requirements_dev.txt delete mode 100644 setup.cfg delete mode 100644 setup.py rename {askchat => src/askchat}/__init__.py (97%) rename {askchat => src/askchat}/ask.py (100%) rename {askchat => src/askchat}/askenv.py (100%) rename {askchat => src/askchat}/cli.py (100%) create mode 100644 src/askchat/const.py diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..c32348c --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,81 @@ +[build-system] +requires = ["setuptools>=45", "wheel", "setuptools_scm[toml]>=6.2"] +build-backend = "setuptools.build_meta" + +[project] +name = "askchat" +dynamic = ["version"] +description = "Interact with ChatGPT in terminal via chattool" +readme = "README.md" +license = {text = "MIT"} +authors = [ + {name = "Rex Wang", email = "1073853456@qq.com"} +] +keywords = ["askchat"] +classifiers = [ + "Development Status :: 2 - Pre-Alpha", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Natural Language :: English", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", +] +requires-python = ">=3.6" +dependencies = [ + "chattool>=3.2.0", + "python-dotenv>=0.17.0", + "Click>=8.0" +] + +[project.urls] +Homepage = "https://github.com/cubenlp/askchat" +Repository = "https://github.com/cubenlp/askchat" + +[project.scripts] +ask = "askchat.ask:main" +askchat = "askchat.cli:main" +askenv = "askchat.askenv:cli" + +[project.optional-dependencies] +dev = [ + "pip==19.2.3", + "bump2version==0.5.11", + "wheel==0.33.6", + "watchdog==0.9.0", + "flake8==3.7.8", + "tox==3.14.0", + "coverage==4.5.4", + "Sphinx==1.8.5", + "twine==1.14.0", + "pytest==6.2.4" +] +test = [ + "pytest>=3" +] + +[tool.setuptools] +include-package-data = true +zip-safe = false + +[tool.setuptools.packages.find] +where = ["src"] +include = ["askchat*"] + +[tool.setuptools.dynamic] +version = {attr = "askchat.__version__"} + +[tool.setuptools.package-dir] +"" = "src" + +[tool.pytest.ini_options] +addopts = "--ignore=setup.py" +testpaths = ["tests"] + +[tool.flake8] +exclude = ["docs"] + +[tool.bdist_wheel] +universal = true \ No newline at end of file diff --git a/requirements_dev.txt b/requirements_dev.txt deleted file mode 100644 index 22e5671..0000000 --- a/requirements_dev.txt +++ /dev/null @@ -1,10 +0,0 @@ -pip==19.2.3 -bump2version==0.5.11 -wheel==0.33.6 -watchdog==0.9.0 -flake8==3.7.8 -tox==3.14.0 -coverage==4.5.4 -Sphinx==1.8.5 -twine==1.14.0 -pytest==6.2.4 diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 8566fdb..0000000 --- a/setup.cfg +++ /dev/null @@ -1,14 +0,0 @@ -[bdist_wheel] -universal = 1 - -[flake8] -exclude = docs -[tool:pytest] -addopts = --ignore=setup.py - -[options.entry_points] -console_scripts = - ask = askchat.ask:main - askchat = askchat.cli:main - askenv = askchat.askenv:cli - diff --git a/setup.py b/setup.py deleted file mode 100644 index 198cfc6..0000000 --- a/setup.py +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env python - -"""The setup script.""" - -from setuptools import setup, find_packages - -VERSION = '1.2.3' - -with open('README.md') as readme_file: - readme = readme_file.read() - -requirements = ['chattool>=3.2.0', "python-dotenv>=0.17.0", 'Click>=8.0'] - -test_requirements = ['pytest>=3'] - -setup( - author="Rex Wang", - author_email='1073853456@qq.com', - python_requires='>=3.6', - classifiers=[ - 'Development Status :: 2 - Pre-Alpha', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: MIT License', - 'Natural Language :: English', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3.9', - ], - description="Interact with ChatGPT in terminal via chattool", - install_requires=requirements, - license="MIT license", - # long_description=readme + '\n\n' + history , - include_package_data=True, - keywords='askchat', - name='askchat', - packages=find_packages(include=['askchat', 'askchat.*']), - test_suite='tests', - tests_require=test_requirements, - url='https://github.com/cubenlp/askchat', - version=VERSION, - zip_safe=False, -) diff --git a/askchat/__init__.py b/src/askchat/__init__.py similarity index 97% rename from askchat/__init__.py rename to src/askchat/__init__.py index 6f74a11..b5728c3 100644 --- a/askchat/__init__.py +++ b/src/askchat/__init__.py @@ -2,12 +2,10 @@ __author__ = """Rex Wang""" __email__ = '1073853456@qq.com' -__version__ = '1.2.3' +__version__ = '2.0.0' -import asyncio from pathlib import Path import click -from dotenv import set_key import os # Main environment file diff --git a/askchat/ask.py b/src/askchat/ask.py similarity index 100% rename from askchat/ask.py rename to src/askchat/ask.py diff --git a/askchat/askenv.py b/src/askchat/askenv.py similarity index 100% rename from askchat/askenv.py rename to src/askchat/askenv.py diff --git a/askchat/cli.py b/src/askchat/cli.py similarity index 100% rename from askchat/cli.py rename to src/askchat/cli.py diff --git a/src/askchat/const.py b/src/askchat/const.py new file mode 100644 index 0000000..e69de29 From 72c66098024320914cb043a3ccbb105c3756ab65 Mon Sep 17 00:00:00 2001 From: rex <1073853456@qq.com> Date: Thu, 16 Oct 2025 14:51:29 +0800 Subject: [PATCH 2/7] update codes --- pyproject.toml | 3 +- src/askchat/__init__.py | 100 +++++----------------------------------- src/askchat/askenv.py | 29 ++++++------ src/askchat/cli.py | 68 +++++++++++++-------------- src/askchat/const.py | 0 src/askchat/elements.py | 20 ++++++++ src/askchat/utils.py | 41 ++++++++++++++++ tests/test_askenv.py | 4 +- 8 files changed, 122 insertions(+), 143 deletions(-) delete mode 100644 src/askchat/const.py create mode 100644 src/askchat/elements.py create mode 100644 src/askchat/utils.py diff --git a/pyproject.toml b/pyproject.toml index c32348c..42e6163 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,7 +27,8 @@ requires-python = ">=3.6" dependencies = [ "chattool>=3.2.0", "python-dotenv>=0.17.0", - "Click>=8.0" + "Click>=8.0", + "platformdirs>=2.0.0" ] [project.urls] diff --git a/src/askchat/__init__.py b/src/askchat/__init__.py index b5728c3..77f7d4a 100644 --- a/src/askchat/__init__.py +++ b/src/askchat/__init__.py @@ -4,92 +4,14 @@ __email__ = '1073853456@qq.com' __version__ = '2.0.0' -from pathlib import Path -import click -import os - -# Main environment file -CONFIG_PATH = Path.home() / ".askchat" -CONFIG_FILE = CONFIG_PATH / ".env" -MAIN_ENV_PATH = Path.home() / '.askchat' / '.env' -ENV_PATH = Path.home() / '.askchat' / 'envs' - -raw_env_text = f"""# Description: Env file for askchat. -# Current version: {__version__} - -# The base url of the API (with suffix /v1) -# This will override OPENAI_API_BASE_URL if both are set. -OPENAI_API_BASE='' - -# The base url of the API (without suffix /v1) -OPENAI_API_BASE_URL='' - -# Your API key -OPENAI_API_KEY='' - -# The default model name -# You can use `askchat --all-valid-models` to see supported models -OPENAI_API_MODEL='' -""" - -# Autocompletion -# environment name completion -class EnvNameCompletionType(click.ParamType): - name = "envname" - def shell_complete(self, ctx, param, incomplete): - return [ - click.shell_completion.CompletionItem(path.stem) for path in ENV_PATH.glob(f"{incomplete}*.env") - ] -# chat file completion -class ChatFileCompletionType(click.ParamType): - name = "chatfile" - def shell_complete(self, ctx, param, incomplete): - return [ - click.shell_completion.CompletionItem(path.stem) for path in CONFIG_PATH.glob(f"{incomplete}*.json") - if not path.name.startswith("_") - ] - -# common functions -async def show_resp(chat, **options): - msg = '' - async for char in chat.async_stream_responses(textonly=True, **options): - print(char, end='', flush=True) - msg += char - # await asyncio.sleep(0.01) - if not msg.endswith('\n'): - print() # add a newline if the message doesn't end with one - return msg - -def set_keys(config_file, keys): - """Set multiple keys in the config file.""" - for key, value in keys.items(): - if value: - set_key(config_file, key, value) - -def create_empty_config(config_file:str): - """Empty config file.""" - if not CONFIG_PATH.exists(): - CONFIG_PATH.mkdir(parents=True) - with open(config_file, "w") as f: - f.write(raw_env_text) - -def initialize_config(config_file:str): - """Initialize the config file with the current environment variables.""" - create_empty_config(config_file) - set_keys(config_file, { - "OPENAI_API_KEY": os.getenv("OPENAI_API_KEY"), - "OPENAI_API_MODEL": os.getenv("OPENAI_API_MODEL"), - "OPENAI_API_BASE_URL": os.getenv("OPENAI_API_BASE_URL"), - "OPENAI_API_BASE": os.getenv("OPENAI_API_BASE"), - }) - -def write_config(config_file, api_key, model, base_url, api_base, overwrite=False): - """Write the environment variables to a config file.""" - if overwrite or not config_file.exists(): - create_empty_config(config_file) - set_keys(config_file, { - "OPENAI_API_KEY": api_key, - "OPENAI_API_MODEL": model, - "OPENAI_API_BASE_URL": base_url, - "OPENAI_API_BASE": api_base, - }) \ No newline at end of file +from .elements import ChatFileCompletionType, EnvNameCompletionType +from .utils import show_resp, set_keys, initialize_config, write_config + +__all__ = [ + "ChatFileCompletionType", + "EnvNameCompletionType", + "show_resp", + "set_keys", + "initialize_config", + "write_config", +] \ No newline at end of file diff --git a/src/askchat/askenv.py b/src/askchat/askenv.py index fe0b63f..70d07b2 100644 --- a/src/askchat/askenv.py +++ b/src/askchat/askenv.py @@ -1,5 +1,6 @@ import click -from askchat import write_config, ENV_PATH, MAIN_ENV_PATH, EnvNameCompletionType +from askchat import write_config, EnvNameCompletionType +from chattool.const import CHATTOOL_ENV_DIR, CHATTOOL_ENV_FILE from dotenv import set_key help_message = """Manage askchat environments. @@ -13,13 +14,13 @@ @click.group(help=help_message) def cli(): """askenv CLI for managing askchat environments.""" - if not ENV_PATH.exists(): - ENV_PATH.mkdir(parents=True) + if not CHATTOOL_ENV_DIR.exists(): + CHATTOOL_ENV_DIR.mkdir(parents=True) @cli.command() def list(): """List all environment configurations.""" - configs = [env for env in ENV_PATH.glob('*.env')] + configs = [env for env in CHATTOOL_ENV_DIR.glob('*.env')] if configs: click.echo("Available environments:") for config in configs: @@ -36,7 +37,7 @@ def list(): @click.option('--interactive', '-i', is_flag=True, default=False, help='Enable interactive mode for inputting options') def new(name, api_key, base_url, api_base, model, interactive): """Create a new environment configuration.""" - config_path = ENV_PATH / f'{name}.env' + config_path = CHATTOOL_ENV_DIR / f'{name}.env' if config_path.exists(): click.echo(f"Warning: Overwriting existing environment '{name}'.") click.confirm("Do you want to continue?", abort=True) @@ -54,7 +55,7 @@ def new(name, api_key, base_url, api_base, model, interactive): def delete(name, default): """Delete an environment configuration.""" if default: - default_config_path = MAIN_ENV_PATH + default_config_path = CHATTOOL_ENV_DIR / 'default.env' if default_config_path.exists(): default_config_path.unlink() click.echo("Default environment configuration deleted.") @@ -64,7 +65,7 @@ def delete(name, default): if not name: click.echo("Please specify an environment name or use --default to delete the default configuration.") return - config_path = ENV_PATH / f'{name}.env' + config_path = CHATTOOL_ENV_DIR / f'{name}.env' if config_path.exists(): config_path.unlink() click.echo(f"Environment '{name}' deleted.") @@ -75,7 +76,7 @@ def delete(name, default): @click.argument('name', required=False, type=EnvNameCompletionType()) def show(name): """Print environment variables. Show default if no name is provided.""" - config_path = ENV_PATH / f'{name}.env' if name else MAIN_ENV_PATH + config_path = CHATTOOL_ENV_DIR / f'{name}.env' if name else CHATTOOL_ENV_FILE if config_path.exists(): with config_path.open() as f: click.echo(f.read()) @@ -89,9 +90,9 @@ def show(name): @click.argument('name') def save(name): """Save the current environment variables to a file.""" - if MAIN_ENV_PATH.exists(): - content = MAIN_ENV_PATH.read_text() - config_path = ENV_PATH / f'{name}.env' + if CHATTOOL_ENV_FILE.exists(): + content = CHATTOOL_ENV_FILE.read_text() + config_path = CHATTOOL_ENV_DIR / f'{name}.env' if config_path.exists(): click.echo(f"Warning: Overwriting existing environment '{name}'.") click.confirm("Do you want to continue?", abort=True) @@ -104,10 +105,10 @@ def save(name): @click.argument('name', type=EnvNameCompletionType()) def use(name): """Activate an environment by replacing the .env file.""" - config_path = ENV_PATH / f'{name}.env' + config_path = CHATTOOL_ENV_DIR / f'{name}.env' if config_path.exists(): content = config_path.read_text() - MAIN_ENV_PATH.write_text(content) + CHATTOOL_ENV_FILE.write_text(content) click.echo(f"Environment '{name}' activated.") else: click.echo(f"Environment '{name}' not found.") @@ -123,7 +124,7 @@ def config(name, api_key, base_url, api_base, model): if not any([api_key, base_url, api_base, model]): click.echo("No updates made. Provide at least one option to update.") return - config_path = ENV_PATH / f'{name}.env' if name else MAIN_ENV_PATH + config_path = CHATTOOL_ENV_DIR / f'{name}.env' if name else CHATTOOL_ENV_FILE if not config_path.exists(): click.echo(f"Environment '{config_path}' not found.\n" +\ "Use `askenv new` to create a new environment." ) diff --git a/src/askchat/cli.py b/src/askchat/cli.py index 6130649..606d74f 100644 --- a/src/askchat/cli.py +++ b/src/askchat/cli.py @@ -1,22 +1,19 @@ """Main module.""" - +import chattool import click, asyncio, askchat, chattool -from pathlib import Path from pprint import pprint from dotenv import load_dotenv import asyncio, os, shutil -from chattool import Chat, debug_log -from pathlib import Path -from askchat import ( - show_resp, write_config, initialize_config - , ENV_PATH, MAIN_ENV_PATH - , CONFIG_PATH, CONFIG_FILE - , EnvNameCompletionType, ChatFileCompletionType +from chattool import Chat, debug_log, ChatBase +from chattool.const import ( + CHATTOOL_CACHE_DIR, CHATTOOL_ENV_DIR, CHATTOOL_ENV_FILE ) +from .elements import EnvNameCompletionType, ChatFileCompletionType +from .utils import show_resp, write_config, initialize_config # Version and Config Path VERSION = askchat.__version__ -LAST_CHAT_FILE = CONFIG_PATH / "_last_chat.json" +LAST_CHAT_FILE = CHATTOOL_CACHE_DIR / "_last_chat.json" help_message = """Interact with ChatGPT in terminal via chattool. @@ -28,20 +25,18 @@ def setup(): """Application setup: Ensure that necessary folders and files exist.""" - os.makedirs(CONFIG_PATH, exist_ok=True) - if os.path.exists(CONFIG_FILE): - load_dotenv(CONFIG_FILE, override=True) - chattool.load_envs() + os.makedirs(CHATTOOL_ENV_DIR, exist_ok=True) + chattool.load_envs(CHATTOOL_ENV_FILE) # callback functions for general options def generate_config_callback(ctx, param, value): """Generate a configuration file by environment table.""" if not value: return # save the config file - if os.path.exists(CONFIG_FILE): - click.confirm(f"Overwrite the existing configuration file {CONFIG_FILE}?", abort=True) - initialize_config(CONFIG_FILE) - print("Created config file at", CONFIG_FILE) + if os.path.exists(CHATTOOL_ENV_FILE): + click.confirm(f"Overwrite the existing configuration file {CHATTOOL_ENV_FILE}?", abort=True) + initialize_config(CHATTOOL_ENV_FILE) + print("Created config file at", CHATTOOL_ENV_FILE) ctx.exit() def debug_log_callback(ctx, param, value): @@ -75,8 +70,8 @@ def save_chat_callback(ctx, param, value): if not value: return try: - shutil.copyfile(LAST_CHAT_FILE, CONFIG_PATH / f"{value}.json") - click.echo(f"Saved conversation to {CONFIG_PATH}/{value}.json") + shutil.copyfile(LAST_CHAT_FILE, CHATTOOL_CACHE_DIR / f"{value}.json") + click.echo(f"Saved conversation to {CHATTOOL_CACHE_DIR}/{value}.json") except FileNotFoundError: click.echo("No last conversation to save.") ctx.exit() @@ -85,17 +80,17 @@ def delete_chat_callback(ctx, param, value): if not value: return try: - os.remove(CONFIG_PATH / f"{value}.json") - click.echo(f"Deleted conversation at {CONFIG_PATH}/{value}.json") + os.remove(CHATTOOL_CACHE_DIR / f"{value}.json") + click.echo(f"Deleted conversation at {CHATTOOL_CACHE_DIR}/{value}.json") except FileNotFoundError: - click.echo(f"The specified conversation {CONFIG_PATH}/{value}.json does not exist.") + click.echo(f"The specified conversation {CHATTOOL_CACHE_DIR}/{value}.json does not exist.") ctx.exit() def list_chats_callback(ctx, param, value): if not value: return click.echo("All conversation files:") - for file in CONFIG_PATH.glob("*.json"): + for file in CHATTOOL_CACHE_DIR.glob("*.json"): if not file.name.startswith("_"): click.echo(f" - {file.stem}") ctx.exit() @@ -103,20 +98,20 @@ def list_chats_callback(ctx, param, value): def load_chat_callback(ctx, param, value): if not value: return try: - shutil.copyfile(CONFIG_PATH / f"{value}.json", LAST_CHAT_FILE) - click.echo(f"Loaded conversation from {CONFIG_PATH}/{value}.json") + shutil.copyfile(CHATTOOL_CACHE_DIR / f"{value}.json", LAST_CHAT_FILE) + click.echo(f"Loaded conversation from {CHATTOOL_CACHE_DIR}/{value}.json") except FileNotFoundError: - click.echo(f"The specified conversation {value} does not exist." +\ + click.echo(f"The specified conversation {CHATTOOL_CACHE_DIR}/{value}.json does not exist." +\ "Please check the chat list with `--list` option.") ctx.exit() # callback function for --use-env option def use_env_callback(ctx, param, value): if not value: return - env_file = ENV_PATH / f"{value}.env" + env_file = CHATTOOL_ENV_DIR / f"{value}.env" if env_file.exists(): content = env_file.read_text() - MAIN_ENV_PATH.write_text(content) + CHATTOOL_ENV_FILE.write_text(content) setup() click.echo(f"Environment '{value}' activated.") else: @@ -160,17 +155,16 @@ def main( message, model, base_url, api_base, api_key, use_env if use_env and not message_text: return # set values for the environment variables if api_key: - os.environ['OPENAI_API_KEY'] = api_key + chattool.const.OPENAI_API_KEY = api_key if base_url: - os.environ['OPENAI_API_BASE_URL'] = base_url + chattool.const.OPENAI_API_BASE_URL = base_url if api_base: - os.environ['OPENAI_API_BASE'] = api_base + chattool.const.OPENAI_API_BASE = api_base if model: - os.environ['OPENAI_API_MODEL'] = model - chattool.load_envs() # update the environment variables in chattool + chattool.const.OPENAI_API_MODEL = model # print chat messages if p: - fname = f"{CONFIG_PATH}/{message_text}.json" if message_text else LAST_CHAT_FILE + fname = f"{CHATTOOL_CACHE_DIR}/{message_text}.json" if message_text else LAST_CHAT_FILE try: Chat().load(fname).print_log() except FileNotFoundError: @@ -180,7 +174,7 @@ def main( message, model, base_url, api_base, api_key, use_env chat = Chat() if regenerate: try: - chat = Chat.load(LAST_CHAT_FILE) + chat = Chat().load(LAST_CHAT_FILE) except FileNotFoundError: click.echo("No last conversation found. Starting a new conversation.") return @@ -196,7 +190,7 @@ def main( message, model, base_url, api_base, api_key, use_env click.echo("Please specify message!") return try: - chat = Chat.load(LAST_CHAT_FILE) + chat = Chat().load(LAST_CHAT_FILE) except FileNotFoundError: click.echo("No last conversation found. Starting a new conversation.") return diff --git a/src/askchat/const.py b/src/askchat/const.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/askchat/elements.py b/src/askchat/elements.py new file mode 100644 index 0000000..6ca7bd8 --- /dev/null +++ b/src/askchat/elements.py @@ -0,0 +1,20 @@ +import click +import click.shell_completion +from chattool.const import CHATTOOL_CONFIG_DIR, CHATTOOL_ENV_DIR + +# Autocompletion +# environment name completion +class EnvNameCompletionType(click.ParamType): + name = "envname" + def shell_complete(self, ctx, param, incomplete): + return [ + click.shell_completion.CompletionItem(path.stem) for path in CHATTOOL_ENV_DIR.glob(f"{incomplete}*.env") + ] +# chat file completion +class ChatFileCompletionType(click.ParamType): + name = "chatfile" + def shell_complete(self, ctx, param, incomplete): + return [ + click.shell_completion.CompletionItem(path.stem) for path in CHATTOOL_CONFIG_DIR.glob(f"{incomplete}*.json") + if not path.name.startswith("_") + ] \ No newline at end of file diff --git a/src/askchat/utils.py b/src/askchat/utils.py new file mode 100644 index 0000000..c58d9e9 --- /dev/null +++ b/src/askchat/utils.py @@ -0,0 +1,41 @@ +import os +from dotenv import set_key +from chattool import create_env_file, ChatOpenAI + +# common functions +async def show_resp(chat:ChatOpenAI, **options): + msg = '' + async for resp in chat.get_response_stream_async(**options): + print(resp.delta_content, end='', flush=True) + msg += resp.delta_content + # await asyncio.sleep(0.01) + if not msg.endswith('\n'): + print() # add a newline if the message doesn't end with one + return msg + +def set_keys(config_file, keys): + """Set multiple keys in the config file.""" + for key, value in keys.items(): + if value: + set_key(config_file, key, value) + +def initialize_config(config_file:str): + """Initialize the config file with the current environment variables.""" + create_env_file(config_file) + set_keys(config_file, { + "OPENAI_API_KEY": os.getenv("OPENAI_API_KEY"), + "OPENAI_API_MODEL": os.getenv("OPENAI_API_MODEL"), + "OPENAI_API_BASE_URL": os.getenv("OPENAI_API_BASE_URL"), + "OPENAI_API_BASE": os.getenv("OPENAI_API_BASE"), + }) + +def write_config(config_file, api_key, model, base_url, api_base, overwrite=False): + """Write the environment variables to a config file.""" + if overwrite or not config_file.exists(): + create_env_file(config_file) + set_keys(config_file, { + "OPENAI_API_KEY": api_key, + "OPENAI_API_MODEL": model, + "OPENAI_API_BASE_URL": base_url, + "OPENAI_API_BASE": api_base, + }) \ No newline at end of file diff --git a/tests/test_askenv.py b/tests/test_askenv.py index 30b1d95..0a9cdfd 100644 --- a/tests/test_askenv.py +++ b/tests/test_askenv.py @@ -3,7 +3,7 @@ from askchat.askenv import cli from pathlib import Path -ENV_PATH = Path.home() / '.askchat' / 'envs' +CHATTOOL_ENV_DIR = Path.home() / '.askchat' / 'envs' @pytest.fixture def runner(): @@ -14,7 +14,7 @@ def runner(): def setup_env(): """Fixture to set up and tear down an environment configuration.""" env_name = "pytest_env" - config_path = ENV_PATH / f"{env_name}.env" + config_path = CHATTOOL_ENV_DIR / f"{env_name}.env" # Setup code before yield yield env_name, config_path # Teardown code after yield From 1fdff4167af8a80451d011c1bec2b7561f9aa6d0 Mon Sep 17 00:00:00 2001 From: rex <1073853456@qq.com> Date: Thu, 16 Oct 2025 15:18:09 +0800 Subject: [PATCH 3/7] update cli --- src/askchat/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/askchat/cli.py b/src/askchat/cli.py index 606d74f..6a67afe 100644 --- a/src/askchat/cli.py +++ b/src/askchat/cli.py @@ -4,7 +4,7 @@ from pprint import pprint from dotenv import load_dotenv import asyncio, os, shutil -from chattool import Chat, debug_log, ChatBase +from chattool import Chat, debug_log from chattool.const import ( CHATTOOL_CACHE_DIR, CHATTOOL_ENV_DIR, CHATTOOL_ENV_FILE ) From 3bfae37e6976a99773d6a3f330b8a87497d1ad49 Mon Sep 17 00:00:00 2001 From: rex <1073853456@qq.com> Date: Thu, 16 Oct 2025 15:21:12 +0800 Subject: [PATCH 4/7] update workflow --- .github/workflows/test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8f6f824..d1cb9d7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -30,13 +30,13 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - python -m pip install .[test] - python -m pip install -r requirements_dev.txt + python -m pip install .[dev] - name: Test with pytest and coverage env: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} OPENAI_API_BASE_URL: ${{ secrets.OPENAI_API_BASE_URL }} run: | + askchat hello pip install coverage coverage run -m pytest tests/ - name: Upload coverage to Codecov From 0a3cd8a6d88d646fe5afb2df6d9e7f96af39e32f Mon Sep 17 00:00:00 2001 From: rex <1073853456@qq.com> Date: Thu, 16 Oct 2025 15:31:53 +0800 Subject: [PATCH 5/7] update workflow --- .github/workflows/publish.yml | 2 +- pyproject.toml | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index e0ad872..ba51274 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -26,6 +26,6 @@ jobs: TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} run: | - python setup.py sdist bdist_wheel + python -m build twine check dist/* twine upload dist/* --skip-existing diff --git a/pyproject.toml b/pyproject.toml index 42e6163..8e122b5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,7 +25,7 @@ classifiers = [ ] requires-python = ">=3.6" dependencies = [ - "chattool>=3.2.0", + "chattool>=4.0.0", "python-dotenv>=0.17.0", "Click>=8.0", "platformdirs>=2.0.0" @@ -42,19 +42,19 @@ askenv = "askchat.askenv:cli" [project.optional-dependencies] dev = [ - "pip==19.2.3", - "bump2version==0.5.11", - "wheel==0.33.6", - "watchdog==0.9.0", - "flake8==3.7.8", - "tox==3.14.0", - "coverage==4.5.4", - "Sphinx==1.8.5", - "twine==1.14.0", - "pytest==6.2.4" + "pip>=25.0", + "bump2version>=1.0.0", + "wheel>=0.37", + "watchdog>=6.0.0", + "flake8>=7.3.0", + "tox>=4.0.0", + "coverage>=4.5.4", + "Sphinx>=8.2.0", + "twine>=6.2.0", + "pytest>=8.4.2" ] test = [ - "pytest>=3" + "pytest>=8.4.2" ] [tool.setuptools] From 99612ed303fd7559db81c011848f04a04f04e17b Mon Sep 17 00:00:00 2001 From: rex <1073853456@qq.com> Date: Thu, 16 Oct 2025 15:35:11 +0800 Subject: [PATCH 6/7] update deps --- pyproject.toml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 8e122b5..7d421e9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,12 +49,9 @@ dev = [ "flake8>=7.3.0", "tox>=4.0.0", "coverage>=4.5.4", - "Sphinx>=8.2.0", - "twine>=6.2.0", - "pytest>=8.4.2" -] -test = [ - "pytest>=8.4.2" + "Sphinx", + "twine", + "pytest" ] [tool.setuptools] From 90d90352bffecc2f0357a56b1cecfd82d09c336b Mon Sep 17 00:00:00 2001 From: rex <1073853456@qq.com> Date: Thu, 16 Oct 2025 15:46:47 +0800 Subject: [PATCH 7/7] update deps --- pyproject.toml | 12 ++++++------ tests/test_askenv.py | 4 +--- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 7d421e9..737afa9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,12 +43,12 @@ askenv = "askchat.askenv:cli" [project.optional-dependencies] dev = [ "pip>=25.0", - "bump2version>=1.0.0", - "wheel>=0.37", - "watchdog>=6.0.0", - "flake8>=7.3.0", - "tox>=4.0.0", - "coverage>=4.5.4", + "bump2version", + "wheel", + "watchdog", + "flake8", + "tox", + "coverage", "Sphinx", "twine", "pytest" diff --git a/tests/test_askenv.py b/tests/test_askenv.py index 0a9cdfd..26e9879 100644 --- a/tests/test_askenv.py +++ b/tests/test_askenv.py @@ -1,10 +1,8 @@ import pytest from click.testing import CliRunner -from askchat.askenv import cli +from askchat.askenv import cli, CHATTOOL_ENV_DIR, CHATTOOL_ENV_FILE from pathlib import Path -CHATTOOL_ENV_DIR = Path.home() / '.askchat' / 'envs' - @pytest.fixture def runner(): """Fixture providing a CliRunner for invoking command-line interfaces."""