From e4cc65fb530b93d2300acf633a5e815fb0d0d120 Mon Sep 17 00:00:00 2001 From: rex <1073853456@qq.com> Date: Sun, 24 Mar 2024 15:38:10 +0800 Subject: [PATCH 1/3] add line break for print --- askchat/__init__.py | 2 ++ requirements_dev.txt | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/askchat/__init__.py b/askchat/__init__.py index 1b394e0..fe2fa07 100644 --- a/askchat/__init__.py +++ b/askchat/__init__.py @@ -38,6 +38,8 @@ async def show_resp(chat): 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 write_config(config_file, api_key, model, base_url, api_base): diff --git a/requirements_dev.txt b/requirements_dev.txt index 5d10382..22e5671 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -7,6 +7,4 @@ tox==3.14.0 coverage==4.5.4 Sphinx==1.8.5 twine==1.14.0 - pytest==6.2.4 - From 883348c0b24520c7e4d12c344e52f7346666bd5b Mon Sep 17 00:00:00 2001 From: rex <1073853456@qq.com> Date: Sun, 24 Mar 2024 16:36:56 +0800 Subject: [PATCH 2/3] edit load option & env rules --- askchat/__init__.py | 6 +++--- askchat/cli.py | 43 +++++++++++++++++++------------------------ 2 files changed, 22 insertions(+), 27 deletions(-) diff --git a/askchat/__init__.py b/askchat/__init__.py index fe2fa07..a60dee9 100644 --- a/askchat/__init__.py +++ b/askchat/__init__.py @@ -2,7 +2,7 @@ __author__ = """Rex Wang""" __email__ = '1073853456@qq.com' -__version__ = '1.1.1' +__version__ = '1.1.2' import asyncio from pathlib import Path @@ -32,9 +32,9 @@ def shell_complete(self, ctx, param, incomplete): ] # common functions -async def show_resp(chat): +async def show_resp(chat, **options): msg = '' - async for char in chat.async_stream_responses(textonly=True): + async for char in chat.async_stream_responses(textonly=True, **options): print(char, end='', flush=True) msg += char await asyncio.sleep(0.01) diff --git a/askchat/cli.py b/askchat/cli.py index 0addb1f..226f54c 100644 --- a/askchat/cli.py +++ b/askchat/cli.py @@ -33,14 +33,10 @@ def setup(): load_dotenv(CONFIG_FILE, override=True) chattool.load_envs() -# load environment variables from the configuration file -setup() - # callback functions for general options def generate_config_callback(ctx, param, value): """Generate a configuration file by environment table.""" - if not value: - return + if not value: return api_key, model = os.getenv("OPENAI_API_KEY"), os.getenv("OPENAI_API_MODEL") base_url, api_base = os.getenv("OPENAI_API_BASE_URL"), os.getenv("OPENAI_API_BASE") # save the config file @@ -51,21 +47,21 @@ def generate_config_callback(ctx, param, value): ctx.exit() def debug_log_callback(ctx, param, value): - if not value: - return + if not value: return + setup() debug_log() ctx.exit() def valid_models_callback(ctx, param, value): - if not value: - return + if not value: return + setup() click.echo('Valid models that contain "gpt" in their names:') click.echo(pprint(Chat().get_valid_models())) ctx.exit() def all_valid_models_callback(ctx, param, value): - if not value: - return + if not value: return + setup() click.echo('All valid models:') click.echo(pprint(Chat().get_valid_models(gpt_only=False))) ctx.exit() @@ -106,6 +102,15 @@ def list_chats_callback(ctx, param, value): click.echo(f" - {file.stem}") ctx.exit() +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") + except FileNotFoundError: + click.echo(f"The specified conversation {value} 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: @@ -135,7 +140,7 @@ def cli(): # Chat with history @click.option('-c', is_flag=True, help='Continue the last conversation') @click.option('-r', '--regenerate', is_flag=True, help='Regenerate the last conversation') -@click.option('-l', '--load', default=None, help='Load the conversation from a file') +@click.option('-l', '--load', default=None, type=ChatFileCompletionType(), callback=load_chat_callback, expose_value=False, help='Load a conversation from a file') # Handling chat history @click.option('-p', '--print', is_flag=True, help='Print the last conversation or a specific conversation') @click.option('-s', '--save', callback=save_chat_callback, expose_value=False, help='Save the conversation to a file') @@ -148,8 +153,9 @@ def cli(): @click.option('--all-valid-models', is_flag=True, callback=all_valid_models_callback, expose_value=False, help='Print all valid models') @click.option('-v', '--version', is_flag=True, callback=version_callback, expose_value=False, help='Print the version') def main( message, model, base_url, api_base, api_key, use_env - , c, regenerate, load, print): + , c, regenerate, print): """Interact with ChatGPT in terminal via chattool""" + setup() message_text = ' '.join(message).strip() if use_env and not message_text: return # set values for the environment variables @@ -183,17 +189,6 @@ def main( message, model, base_url, api_base, api_key, use_env click.echo("You should have at least two messages in the conversation") return chat.pop() - elif load: # load and continue the conversation - try: - shutil.copyfile(CONFIG_PATH / f"{load}.json", LAST_CHAT_FILE) - click.echo(f"Loaded conversation from {CONFIG_PATH}/{load}.json") - except FileNotFoundError: - click.echo(f"The specified conversation {load} does not exist." +\ - "Please check the chat list with `--list` option.") - if not message_text: # if no message is provided, just quit - return - chat = Chat.load(LAST_CHAT_FILE) - chat.user(message_text) elif c: # continue the last conversation if not message_text: click.echo("Please specify message!") From dc072470d546ebe2179fe5cb3b284d6ff6a67da1 Mon Sep 17 00:00:00 2001 From: rex <1073853456@qq.com> Date: Sun, 24 Mar 2024 16:51:18 +0800 Subject: [PATCH 3/3] add response options --- README-en.md | 3 ++- README.md | 3 ++- askchat/cli.py | 5 +++-- setup.py | 4 ++-- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/README-en.md b/README-en.md index 75e6067..357bb5f 100644 --- a/README-en.md +++ b/README-en.md @@ -87,7 +87,7 @@ Manage conversation history, including saving, loading, deleting, and listing co |-----------------|------------------------|-----------------------------------------------| | `-c` | `askchat -c ` | Continue the last conversation | | `--regenerate` | `askchat -r` | Regenerate the last response of the conversation | -| `--load` | `askchat -l [message]` | Load conversation history from a file and continue | +| `--load` | `askchat -l ` | Load conversation history from a file | | `--print` | `askchat -p []` | Print the last or a specified conversation history | | `--save` | `askchat -s ` | Save the current conversation history to a file | | `--delete` | `askchat -d ` | Delete a specified conversation history file | @@ -108,6 +108,7 @@ Default parameters for `askchat`, used for direct interaction with ChatGPT or co | `--base-url` | `-b https://api.example.com` | Set the Base URL (excluding `/v1`) | | `--api-base` | `--api-base https://api.example.com/v1` | Set the Base URL | | `--api-key` | `-a sk-xxxxxxx` | Provide the OpenAI API key | +| `--option` | `-o top_p 1 temperature 0.5` | Set request parameters | | `--use-env` | `-u prod` | Load environment variables from the specified config file, see [AskEnv](#askenv) | Note: Some model APIs, like ChatGPT, use `/v4` as the base path of the API, so the `--api-base` parameter would be needed. diff --git a/README.md b/README.md index b730f23..ab67540 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,7 @@ Options: |---------------------|------------------|--------------------------------------------| | `-c` | `askchat -c ` | 继续上一次的对话 | | `--regenerate` | `askchat -r` | 重新生成上一次对话的最后回复 | -| `--load` | `askchat -l [message]` | 从文件加载对话历史,继续对话 | +| `--load` | `askchat -l ` | 加载历史对话 | | `--print` | `askchat -p []` | 打印上次或指定的对话历史 | | `--save` | `askchat -s ` | 将当前对话历史保存到文件 | | `--delete` | `askchat -d ` | 删除指定的对话历史文件 | @@ -106,6 +106,7 @@ Options: | `--base-url` | `-b https://api.example.com` | 设置 Base URL (不包含 `/v1`) | | `--api-base` | `--api-base https://api.example.com/v1` | 设置 Base URL | | `--api-key` | `-a sk-xxxxxxx` | 提供 OpenAI API 密钥 | +| `--option` | `-o top_p 1 temperature 0.5` | 设置请求参数 | | `--use-env` | `-u prod` | 使用指定配置文件加载环境变量,详见 [AskEnv](#askenv) | 注:一些模型 API,比如智谱,使用 `/v4` 作为 API 的基础路径,这时得用 `--api-base` 参数。 diff --git a/askchat/cli.py b/askchat/cli.py index 226f54c..c55a62b 100644 --- a/askchat/cli.py +++ b/askchat/cli.py @@ -152,8 +152,9 @@ def cli(): @click.option('--valid-models', is_flag=True, callback=valid_models_callback, expose_value=False, help='Print valid models that contain "gpt" in their names') @click.option('--all-valid-models', is_flag=True, callback=all_valid_models_callback, expose_value=False, help='Print all valid models') @click.option('-v', '--version', is_flag=True, callback=version_callback, expose_value=False, help='Print the version') +@click.option('-o', '--option', multiple=True, type=(str, str), help='Additional options for show_resp in the form of key=value') def main( message, model, base_url, api_base, api_key, use_env - , c, regenerate, print): + , c, regenerate, print, option): """Interact with ChatGPT in terminal via chattool""" setup() message_text = ' '.join(message).strip() @@ -205,7 +206,7 @@ def main( message, model, base_url, api_base, api_key, use_env return chat.user(message_text) # Add chat response - chat.assistant(asyncio.run(show_resp(chat))) + chat.assistant(asyncio.run(show_resp(chat, **dict(option)))) chat.save(LAST_CHAT_FILE, mode='w') if __name__ == '__main__': diff --git a/setup.py b/setup.py index 3869cf4..8f67ed6 100644 --- a/setup.py +++ b/setup.py @@ -4,12 +4,12 @@ from setuptools import setup, find_packages -VERSION = '1.1.1' +VERSION = '1.1.2' with open('README.md') as readme_file: readme = readme_file.read() -requirements = ['chattool>=3.1.2', "python-dotenv>=0.17.0", 'Click>=8.0'] +requirements = ['chattool>=3.1.3', "python-dotenv>=0.17.0", 'Click>=8.0'] test_requirements = ['pytest>=3']