diff --git a/README-en.md b/README-en.md index 3934aa1..9d4abb9 100644 --- a/README-en.md +++ b/README-en.md @@ -5,103 +5,156 @@ [![Documentation Status](https://img.shields.io/badge/docs-github_pages-blue.svg)](https://cubenlp.github.io/askchat/) [![Coverage](https://codecov.io/gh/cubenlp/askchat/branch/main/graph/badge.svg)](https://codecov.io/gh/cubenlp/askchat) -[English](README-en.md) | [Simplified Chinese](README.md) +[English](README-en.md) | [简体中文](README.md) Invoke ChatGPT from the command line. -## Installation +## Installation and Configuration ```bash pip install askchat --upgrade ``` -## How to Use - -Run simply with the default environment variables: +Configure environment variables: ```bash -ask hello +export OPENAI_API_KEY="your-api-key" +export OPENAI_API_BASE_URL="https://api.openai.com" +export OPENAI_API_BASE="https://api.openai.com/v1" +export OPENAI_MODEL="gpt-3.5-turbo" ``` -Specify other options via `askchat`: +Note: The `OPENAI_API_BASE` variable takes precedence over `OPENAI_API_BASE_URL`. Use one of them as needed. + +## Usage + +To run with the default environment variables: ```bash -# Ask using a specific model -askchat hello -m "baichuan2" --base-url "localhost:8000" +ask hello ``` -Generate a default configuration file via environment variables, edit the configuration in `~/.askchat/.env`: +## AskChat + +Use `askchat` for more flexibility with parameters and to manage conversations, with related files saved under `~/.askchat/`. Supported options include: ```bash -askchat --generate-config +❯ askchat --help +Usage: askchat [OPTIONS] [MESSAGE]... + + Interact with ChatGPT in terminal via chattool + +Options: + -m, --model TEXT Model name + -b, --base-url TEXT Base URL of the API (without suffix `/v1`) + --api-base TEXT Base URL of the API (with suffix `/v1`) + -a, --api-key TEXT OpenAI API key + -u, --use-env TEXT Use environment variables from the ENV_PATH + -c Continue the last conversation + -r, --regenerate Regenerate the last conversation + -l, --load TEXT Load the conversation from a file + -p, --print Print the last conversation or a specific conversation + -s, --save TEXT Save the conversation to a file + -d, --delete TEXT Delete the conversation from a file + --list List all the conversation files + --generate-config Generate a configuration file by environment table + --debug Print debug log + --valid-models Print valid models that contain "gpt" in their names + --all-valid-models Print all valid models + -v, --version Print the version + --help Show this message and exit. ``` -## Chat Options +### Default Parameters -```bash -# Show the current version -askchat -v +Default parameters for the `askchat` command-line tool, used for direct interaction with ChatGPT or configuring API connection information. -# Print debug logs -askchat --debug +| Parameter | Example | Description | +|--------------------|---------------------------|------------------------------------| +| `` | `askchat hello` | The simplest form of dialogue | +| `-m / --model` | `-m gpt-3.5-turbo` | Specify the model name | +| `-b / --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 (including `/v1`) | +| `-a / --api-key` | `-a sk-xxxxxxx` | Provide the OpenAI API key | +| `-u / --use-env` | `-u prod` | Load environment variables from the specified config file, see `chatenv` | -# Get valid models that include "gpt" -askchat --valid-models +Note: For some model APIs, like ChatGPT, `/v4` is used as the base path of the API. In such cases, use the `--api-base` parameter. -# Get all valid models -askchat --all-valid-models -``` +### Conversation Management +Conversation management parameters allow users to save, load, delete, and list conversation histories, as well as continue a previous conversation. -## Managing Conversation History +| Parameter | Example | Description | +|------------------------|---------------------------------|------------------------------------------------| +| `-c` | `askchat -c` | Continue the last conversation | +| `-r / --regenerate` | `askchat -r` | Regenerate the last response of the conversation | +| `-l / --load` | `askchat -l conversation1` | Load conversation history from a file and continue | +| `-p / --print` | `askchat -p [name]` | Print -Manage conversations using `askchat`: + the last or a specified conversation history | +| `-s / --save` | `askchat -s conversation1` | Save the current conversation history to a file | +| `-d / --delete` | `askchat -d conversation1` | Delete a specified conversation history file | +| `--list` | `askchat --list` | List all saved conversation history files | -```bash -askchat hello -# Continue the last conversation: -c -askchat -c please tell me a joke -# Regenerate the last conversation: -r -askchat -r -# Modify and regenerate the last conversation: -r -askchat -r give me some jokes please -# Save the conversation: -s/--save -askchat -s joke -# Load a conversation: -l/--load -askchat -l joke -# Delete a conversation: -d/--delete -askchat -d joke -# List all saved conversations: --list -askchat --list -# Print the last conversation: -p/--print -askchat -p -# Print a specific conversation: -p/--print -askchat -p joke -``` +All conversations are saved in `~/.askchat/`, with the most recent conversation saved in `~/.askchat/_last_chat.json`. -## Managing Environment Configuration +### Other Options -Manage different environment configurations with `chatenv`: +These options provide auxiliary functions, such as generating configuration files, printing debug logs, listing models, and showing version information. -```bash -# Create a new environment -chatenv create [--api-key ""] [--base-url ""] [--api-base ""] [--model ""] +| Parameter | Example | Description | +|--------------------------|-------------------------------|--------------------------------------------| +| `--generate-config` | `askchat --generate-config` | Generate a config file, saved in `~/.askchat/.env` | +| `--debug` | `askchat --debug` | Print debug logs | +| `--valid-models` | `askchat --valid-models` | Print valid models containing "gpt" in their names | +| `--all-valid-models` | `askchat --all-valid-models` | Print all valid models | +| `-v / --version` | `askchat -v` | Print the version of `askchat` | + +Note: `--all-valid-models` prints all available models, including Embedding, dalle-3, tts, etc. Use `--valid-models` to filter these out. + +## ChatEnv + +`chatenv` is a command-line tool designed for managing different environment configurations for `askchat`, supporting operations such as create, activate, delete, etc. It facilitates switching between different environments, managing API keys, model names, and API base URLs. + +1. Create a new environment configuration using the `create` command. + + ```bash + chatenv create [-a API_KEY] [-b BASE_URL] [--api-base API_BASE] [-m MODEL] + ``` + +2. Activate an environment, setting it as the current configuration. + + ```bash + chatenv use + ``` + +3. Delete a specified environment configuration file. + + ```bash + chatenv delete + chatenv delete --default + ``` + +4. List all available environments. + + ```bash + chatenv list + ``` -# Activate a specified environment -chatenv use +5. Display the configuration information of a specified environment, or the default environment if no name is provided. -# Update environment configuration -chatenv config [] [--api-key ""] [--base-url ""] [--api-base ""] [--model ""] + ```bash + chatenv show [name] + ``` -# List all environments -chatenv list +6. Save the currently active environment configuration to a file with a specified name. -# Show variables of a specified or default environment -chatenv show [] + ```bash + chatenv save + ``` -# Save the current environment as a new environment file -chatenv save +7. Update one or more settings of a specified or default environment configuration. -# Delete a specified or the default environment configuration -chatenv delete [] [--default] -``` \ No newline at end of file + ```bash + chatenv config [name] [-a API_KEY] [-b BASE_URL] [--api-base API_BASE] [-m MODEL] + ``` \ No newline at end of file diff --git a/README.md b/README.md index b454970..c9cbfbe 100644 --- a/README.md +++ b/README.md @@ -9,100 +9,150 @@ 在命令行中调用 ChatGPT。 -## 安装 +## 安装及配置 ```bash pip install askchat --upgrade ``` +配置环境变量: + +```bash +export OPENAI_API_KEY="your-api-key" +export OPENAI_API_BASE_URL="https://api.openai.com" +export OPENAI_API_BASE="https://api.openai.com/v1" +export OPENAI_MODEL="gpt-3.5-turbo" +``` + +注:`OPENAI_API_BASE` 变量优先于 `OPENAI_API_BASE_URL` 变量,二者选一即可。 + ## 使用方法 -使用默认的环境变量进行简单运行: +使用默认的环境变量简单地运行: ```bash ask hello ``` -通过 `askchat` 指定其他选项: +## AskChat + +通过 `askchat` 更灵活地使用参数和管理对话,工作目录为 `~/.askchat/`,支持选项如下: ```bash -# 使用特定模型提问 -askchat hello -m "baichuan2" --base-url "localhost:8000" +❯ askchat --help +Usage: askchat [OPTIONS] [MESSAGE]... + + Interact with ChatGPT in terminal via chattool + +Options: + -m, --model TEXT Model name + -b, --base-url TEXT Base URL of the API (without suffix `/v1`) + --api-base TEXT Base URL of the API (with suffix `/v1`) + -a, --api-key TEXT OpenAI API key + -u, --use-env TEXT Use environment variables from the ENV_PATH + -c Continue the last conversation + -r, --regenerate Regenerate the last conversation + -l, --load TEXT Load the conversation from a file + -p, --print Print the last conversation or a specific conversation + -s, --save TEXT Save the conversation to a file + -d, --delete TEXT Delete the conversation from a file + --list List all the conversation files + --generate-config Generate a configuration file by environment table + --debug Print debug log + --valid-models Print valid models that contain "gpt" in their names + --all-valid-models Print all valid models + -v, --version Print the version + --help Show this message and exit. ``` -通过环境变量生成默认的配置文件,在 `~/.askchat/.env` 中编辑配置: +### 默认参数 -```bash -askchat --generate-config -``` +`askchat` 命令行工具的默认参数,这些参数用于直接与 ChatGPT 交互或者配置 API 的连接信息。 -## 聊天选项 +| 参数 | 示例 | 解释 | +|-----------------|-----------------|-----------------------------------| +| `` | `askchat hello` | 最简单的对话 | +| `-m / --model` | `-m gpt-3.5-turbo` | 指定使用的模型名称 | +| `-b / --base-url` | `-b https://api.example.com` | 设置 Base URL (不包含 `/v1`) | +| `--api-base` | `--api-base https://api.example.com/v1` | 设置 Base URL (包含 `/v1`) | +| `-a / --api-key` | `-a sk-xxxxxxx` | 提供 OpenAI API 密钥 | +| `-u / --use-env` | `-u prod` | 使用指定配置文件加载环境变量,详见 `chatenv` | -```bash -# 显示当前版本 -askchat -v +注:一些模型 API,比如智谱,使用 `/v4` 作为 API 的基础路径,这时可以使用 `--api-base` 参数。 -# 打印调试日志 -askchat --debug +### 对话管理 -# 获取包含 "gpt" 的有效模型 -askchat --valid-models +对话管理参数允许用户保存、加载、删除和列出对话历史记录,以及继续之前的对话。 -# 获取所有有效模型 -askchat --all-valid-models -``` +| 参数 | 示例 | 解释 | +|---------------------|------------------|--------------------------------------------| +| `-c` | `askchat -c` | 继续上一次的对话 | +| `-r / --regenerate` | `askchat -r` | 重新生成上一次对话的最后回复 | +| `-l / --load` | `askchat -l conversation1` | 从文件加载对话历史,继续对话 | +| `-p / --print` | `askchat -p [name]` | 打印上次或指定的对话历史 | +| `-s / --save` | `askchat -s conversation1` | 将当前对话历史保存到文件 | +| `-d / --delete` | `askchat -d conversation1` | 删除指定的对话历史文件 | +| `--list` | `askchat --list` | 列出所有保存的对话历史文件 | +所有对话保存在 `~/.askchat/`,使用 `askchat` 的最近一次对话保存在 `~/.askchat/_last_chat.json` 文件。 -## 管理对话记录 +### 其他选项 -使用 `askchat` 管理对话: +这些选项提供了一些辅助功能,如生成配置文件、调试日志、打印模型列表和显示版本信息。 -```bash -askchat hello -# 继续上一次对话:-c -askchat -c 请给我讲个笑话 -# 重新生成最后一次对话:-r -askchat -r -# 修改并重新生成最后一次对话:-r -askchat -r give me some jokes please -# 保存对话:-s/--save -askchat -s joke -# 加载对话:-l/--load -askchat -l joke -# 删除对话:-d/--delete -askchat -d joke -# 列出所有保存的对话:--list -askchat --list -# 打印最后一次对话:-p/--print -askchat -p -# 打印指定的对话:-p/--print -askchat -p joke -``` +| 参数 | 示例 | 解释 | +|---------------------------|----------------------|--------------------------------------------| +| `--generate-config` | `askchat --generate-config` | 生成配置文件,保存在 `~/.askchat/.env` 中 | +| `--debug` | `askchat --debug` | 打印调试日志 | +| `--valid-models` | `askchat --valid-models` | 打印包含 "gpt" 名称的有效模型列表 | +| `--all-valid-models` | `askchat --all-valid-models` | 打印所有有效的模型列表 | +| `-v / --version` | `askchat -v` | 打印 `askchat` 的版本信息 | -## 管理环境配置 +注:`--all-valid-models` 会打印所有可用模型,包括 Embedding, dalle-3, tts 等,使用 `--valid-models` 可以过滤掉这些。 -通过 `chatenv` 管理不同的环境配置: +## ChatEnv -```bash -# 创建新环境 -chatenv create [--api-key ""] [--base-url ""] [--api-base ""] [--model ""] +`chatenv` 用于管理不同的环境配置,支持创建、激活、删除等操作,便于在不同的环境之间切换,管理 API 密钥、模型名称和 API 的基础 URL 等配置信息。 -# 激活指定环境 -chatenv use +1. 创建一个新的环境配置,使用 `create` 命令。 -# 更新环境配置 -chatenv config [] [--api-key ""] [--base-url ""] [--api-base ""] [--model ""] + ```bash + chatenv create [-a API_KEY] [-b BASE_URL] [--api-base API_BASE] [-m MODEL] + ``` -# 列出所有环境 -chatenv list +2. 激活某个环境,将其设置为当前使用的配置。 -# 显示指定环境或默认环境的变量 -chatenv show [] + ```bash + chatenv use + ``` -# 保存当前环境为一个新的环境文件 -chatenv save +3. 删除指定的环境配置文件。 -# 删除指定的环境或默认环境配置 -chatenv delete [] [--default] -``` + ```bash + chatenv delete + chatenv delete --default + ``` + +4. 列出当前所有可用环境。 + + ```bash + chatenv list + ``` + +5. 显示指定环境的配置信息,如果没有指定环境名称,则显示默认环境的配置。 + + ```bash + chatenv show [name] + ``` + +6. 将当前激活的环境配置保存为指定名称的配置文件。 + + ```bash + chatenv save + ``` + +7. 更新指定或默认环境配置的一项或多项设置。 + ```bash + chatenv config [name] [-a API_KEY] [-b BASE_URL] [--api-base API_BASE] [-m MODEL] + ``` \ No newline at end of file diff --git a/askchat/askchat.py b/askchat/askchat.py index 6e472e9..e0617ba 100644 --- a/askchat/askchat.py +++ b/askchat/askchat.py @@ -15,6 +15,7 @@ CONFIG_PATH = Path.home() / ".askchat" CONFIG_FILE = CONFIG_PATH / ".env" LAST_CHAT_FILE = CONFIG_PATH / "_last_chat.json" +ENV_PATH = Path.home() / '.askchat' / 'envs' def setup(): """Application setup: Ensure that necessary folders and files exist.""" @@ -22,26 +23,78 @@ def setup(): if not os.path.exists(CONFIG_FILE): with open(CONFIG_FILE, 'w') as cf: cf.write("# Initial configuration\n") + load_dotenv(CONFIG_FILE, override=True) # if not os.path.exists(LAST_CHAT_FILE): # with open(LAST_CHAT_FILE, 'w') as lcf: # lcf.write('{"index": 0, "chat_log": []}') -def _generate_config(): +# callback functions +def generate_config_callback(ctx, param, value): """Generate a configuration file by environment table.""" + 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") - - # move the old config file to a temporary file - if os.path.exists(CONFIG_FILE): - # move the old config file to a temporary file - os.makedirs("/tmp", exist_ok=True) - tmp_file = os.path.join("/tmp", str(uuid.uuid4())[:8] + ".askchat.env") - shutil.move(CONFIG_FILE, tmp_file) - print(f"Moved old config file to {tmp_file}") - # save the config file + # save the config file write_config(CONFIG_FILE, api_key, model, base_url, api_base) print("Created config file at", CONFIG_FILE) - return + ctx.exit() + +def debug_log_callback(ctx, param, value): + if not value: + return + debug_log() + ctx.exit() + +def valid_models_callback(ctx, param, value): + if not value: + return + 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 + click.echo('All valid models:') + click.echo(pprint(Chat().get_valid_models(gpt_only=False))) + ctx.exit() + +def version_callback(ctx, param, value): + if not value: + return + click.echo(f"askchat version: {VERSION}") + ctx.exit() + +# callback functions for handling chat history +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") + except FileNotFoundError: + click.echo("No last conversation to save.") + ctx.exit() + +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") + except FileNotFoundError: + click.echo(f"The specified conversation {CONFIG_PATH}/{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"): + if not file.name.startswith("_"): + click.echo(f" - {file.stem}") + ctx.exit() @click.group() def cli(): @@ -54,31 +107,34 @@ def cli(): @click.option('-b', '--base-url', default=None, help='Base URL of the API (without suffix `/v1`)') @click.option('--api-base', default=None, help='Base URL of the API (with suffix `/v1`)') @click.option('-a', '--api-key', default=None, help='OpenAI API key') +@click.option('-u', '--use-env', default=None, help='Use environment variables from the ENV_PATH') # 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('-s', '--save', default=None, help='Save the conversation to a file') @click.option('-l', '--load', default=None, help='Load the 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('-d', '--delete', default=None, help='Delete the conversation from a file') -@click.option('--list', is_flag=True, help='List all the conversation files') +@click.option('-s', '--save', callback=save_chat_callback, expose_value=False, help='Save the conversation to a file') +@click.option('-d', '--delete', callback=delete_chat_callback, expose_value=False, help='Delete the conversation from a file') +@click.option('--list', is_flag=True, callback=list_chats_callback, expose_value=False, help='List all the conversation files') # Other options -@click.option('--generate-config', is_flag=True, help='Generate a configuration file by environment table') -@click.option('--debug', is_flag=True, help='Print debug log') -@click.option('--valid-models', is_flag=True, help='Print valid models that contain "gpt" in their names') -@click.option('--all-valid-models', is_flag=True, help='Print all valid models') -@click.option('-v', '--version', is_flag=True, help='Print the version') -def main( message, model, base_url, api_base, api_key - , c, regenerate, save, load, print, delete, list - , generate_config, debug, valid_models, all_valid_models, version): +@click.option('--generate-config', is_flag=True, callback=generate_config_callback, expose_value=False, help='Generate a configuration file by environment table') +@click.option('--debug', is_flag=True, callback=debug_log_callback, expose_value=False, help='Print debug log') +@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') +def main( message, model, base_url, api_base, api_key, use_env + , c, regenerate, load, print): """Interact with ChatGPT in terminal via chattool""" - message_text = ' '.join(message).strip() - + # read environment variables from the ENV_PATH + if use_env: + env_file = ENV_PATH / f"{use_env}.env" + if env_file.exists(): + load_dotenv(env_file, override=True) + else: + click.echo(f"Environment file {env_file} does not exist.") + return # set values for the environment variables - ## 1. read from config file `~/.askchat/.env` - if os.path.exists(CONFIG_FILE): - load_dotenv(CONFIG_FILE, override=True) - ## 2. read from command line if api_key: os.environ['OPENAI_API_KEY'] = api_key if base_url: @@ -87,52 +143,9 @@ def main( message, model, base_url, api_base, api_key os.environ['OPENAI_API_BASE'] = api_base if model: os.environ['OPENAI_API_MODEL'] = model - # generate config file - if generate_config: - return _generate_config() - # update environment variables for chattool - chattool.load_envs() - # show debug log - if debug: - return debug_log() - # show valid models - if valid_models: - click.echo('Valid models that contain "gpt" in their names:') - click.echo(pprint(Chat().get_valid_models())) - return - if all_valid_models: - click.echo('All valid models:') - click.echo(pprint(Chat().get_valid_models(gpt_only=False))) - return - # Handle chat history operations - if load: - 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.") - return - if save: - try: - shutil.copyfile(LAST_CHAT_FILE, CONFIG_PATH / f"{save}.json") - click.echo(f"Saved conversation to {CONFIG_PATH}/{save}.json") - except FileNotFoundError: - click.echo("No last conversation to save.") - return - if delete: - try: - os.remove(CONFIG_PATH / f"{delete}.json") - click.echo(f"Deleted conversation at {CONFIG_PATH}/{delete}.json") - except FileNotFoundError: - click.echo(f"The specified conversation {CONFIG_PATH}/{delete}.json does not exist.") - return - if list: - click.echo("All conversation files:") - for file in CONFIG_PATH.glob("*.json"): - if not file.name.startswith("_"): - click.echo(f" - {file.stem}") - return + chattool.load_envs() # update the environment variables in chattool + # print chat messages + message_text = ' '.join(message).strip() if print: fname = message_text if message_text else '_last_chat' fname = f"{CONFIG_PATH}/{fname}.json" @@ -141,29 +154,45 @@ def main( message, model, base_url, api_base, api_key except FileNotFoundError: click.echo(f"The specified conversation {fname} does not exist.") return - # Handle version option - if version: - click.echo(f"askchat version: {VERSION}") - return - # Main chat + # handling chat history | Four cases: regenerate, load, continue, default chat = Chat() - if c or regenerate: # Load last chat if -c or -r is used + if regenerate: try: chat = Chat.load(LAST_CHAT_FILE) except FileNotFoundError: click.echo("No last conversation found. Starting a new conversation.") return - if regenerate: if len(chat) < 2: 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!") + return + try: + chat = Chat.load(LAST_CHAT_FILE) + except FileNotFoundError: + click.echo("No last conversation found. Starting a new conversation.") + return + chat.user(message_text) else: if not message_text: click.echo("Please specify message!") return chat.user(message_text) - # Simulate chat response + # Add chat response chat.assistant(asyncio.run(show_resp(chat))) chat.save(LAST_CHAT_FILE, mode='w')