From fee0f86fe83e9ce024b9e92fe87edd3aa1ee0083 Mon Sep 17 00:00:00 2001 From: okxlin Date: Wed, 10 Jan 2024 15:24:07 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E6=B7=BB=E5=8A=A0=E5=B7=9D=E8=99=8EChat?= =?UTF-8?q?=E5=88=B0=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/chuanhuchat/README.md | 183 ++++++++++++++++++ apps/chuanhuchat/data.yml | 20 ++ apps/chuanhuchat/latest/.env.sample | 2 + apps/chuanhuchat/latest/data.yml | 10 + apps/chuanhuchat/latest/data/config.json | 64 ++++++ .../latest/data/config_example.json | 87 +++++++++ apps/chuanhuchat/latest/docker-compose.yml | 19 ++ apps/chuanhuchat/logo.png | Bin 0 -> 8672 bytes 8 files changed, 385 insertions(+) create mode 100644 apps/chuanhuchat/README.md create mode 100644 apps/chuanhuchat/data.yml create mode 100644 apps/chuanhuchat/latest/.env.sample create mode 100644 apps/chuanhuchat/latest/data.yml create mode 100644 apps/chuanhuchat/latest/data/config.json create mode 100644 apps/chuanhuchat/latest/data/config_example.json create mode 100644 apps/chuanhuchat/latest/docker-compose.yml create mode 100644 apps/chuanhuchat/logo.png diff --git a/apps/chuanhuchat/README.md b/apps/chuanhuchat/README.md new file mode 100644 index 00000000..8b557bfc --- /dev/null +++ b/apps/chuanhuchat/README.md @@ -0,0 +1,183 @@ +# 使用说明 + +## 功能相关由`config.json`决定,配置问题注意查看官方文档与教程 + +- https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki + +# 原始相关 +*** +
+ + 简体中文 | English | 日本語 | Russian | 한국어 +
+ +

川虎 Chat 🐯 Chuanhu Chat

+
+ + Logo + + +

+

为ChatGPT等多种LLM提供了一个轻快好用的Web图形界面和众多附加功能

+

+ + Tests Passing + + + GitHub Contributors + + + GitHub pull requests + +

+ 支持 GPT-4 · 基于文件问答 · LLM本地部署 · 联网搜索 · Agent 助理 · 支持 Fine-tune +

+ 视频教程 + · + 2.0介绍视频 + || + 在线体验 + · + 一键部署 +

+

+
+ +[![Video Title](https://github.com/GaiZhenbiao/ChuanhuChatGPT/assets/51039745/0eee1598-c2fd-41c6-bda9-7b059a3ce6e7.jpg)](https://github.com/GaiZhenbiao/ChuanhuChatGPT/assets/51039745/0eee1598-c2fd-41c6-bda9-7b059a3ce6e7?autoplay=1) + +## 目录 + +| [支持模型](#支持模型) | [使用技巧](#使用技巧) | [安装方式](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程) | [常见问题](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/常见问题) | [给作者买可乐🥤](#捐款) | [加入Telegram群组](https://t.me/tkdifferent) | +| --- | --- | --- | --- | --- | --- | + +## 支持模型 + +| API 调用模型 | 备注 | 本地部署模型 | 备注 | +| :---: | --- | :---: | --- | +| [ChatGPT(GPT-4)](https://chat.openai.com) | 支持微调 gpt-3.5 | [ChatGLM](https://github.com/THUDM/ChatGLM-6B) ([ChatGLM2](https://github.com/THUDM/ChatGLM2-6B)) | +| [Azure OpenAI](https://azure.microsoft.com/en-us/products/ai-services/openai-service) | | [LLaMA](https://github.com/facebookresearch/llama) | 支持 Lora 模型  +| [Google PaLM](https://developers.generativeai.google/products/palm) | 不支持流式传输 | [StableLM](https://github.com/Stability-AI/StableLM) +| [讯飞星火认知大模型](https://xinghuo.xfyun.cn) | | [MOSS](https://github.com/OpenLMLab/MOSS) +| [Inspur Yuan 1.0](https://air.inspur.com/home) | | [通义千问](https://github.com/QwenLM/Qwen/tree/main) +| [MiniMax](https://api.minimax.chat/) | +| [XMChat](https://github.com/MILVLG/xmchat) | 不支持流式传输 +| [Midjourney](https://www.midjourney.com/) | 不支持流式传输 +| [Claude](https://www.anthropic.com/) | +| DALL·E 3 | + +## 使用技巧 + +### 💪 强力功能 +- **川虎助理**:类似 AutoGPT,全自动解决你的问题; +- **在线搜索**:ChatGPT 的数据太旧?给 LLM 插上网络的翅膀; +- **知识库**:让 ChatGPT 帮你量子速读!根据文件回答问题。 +- **本地部署LLM**:一键部署,获取属于你自己的大语言模型。 + +### 🤖 System Prompt +- 通过 System Prompt 设定前提条件,可以很有效地进行角色扮演; +- 川虎Chat 预设了Prompt模板,点击`加载Prompt模板`,先选择 Prompt 模板集合,然后在下方选择想要的 Prompt。 + +### 💬 基础对话 +- 如果回答不满意,可以使用 `重新生成` 按钮再试一次,或者直接 `删除这轮对话`; +- 输入框支持换行,按 Shift + Enter即可; +- 在输入框按 方向键,可以在发送记录中快速切换; +- 每次新建一个对话太麻烦,试试 `单论对话` 功能; +- 回答气泡旁边的小按钮,不仅能 `一键复制`,还能 `查看Markdown原文`; +- 指定回答语言,让 ChatGPT 固定以某种语言回答。 + +### 📜 对话历史 +- 对话历史记录会被自动保存,不用担心问完之后找不到了; +- 多用户历史记录隔离,除了你都看不到; +- 重命名历史记录,方便日后查找; +- New! 魔法般自动命名历史记录,让 LLM 理解对话内容,帮你自动为历史记录命名! +- New! 搜索历史记录,支持正则表达式! + +### 🖼️ 小而美的体验 +- 自研 Small-and-Beautiful 主题,带给你小而美的体验; +- 自动亮暗色切换,给你从早到晚的舒适体验; +- 完美渲染 LaTeX / 表格 / 代码块,支持代码高亮; +- New! 非线性动画、毛玻璃效果,精致得不像 Gradio! +- New! 适配 Windows / macOS / Linux / iOS / Android,从图标到全面屏适配,给你最合适的体验! +- New! 支持以 PWA应用程序 安装,体验更加原生! + +### 👨‍💻 极客功能 +- New! 支持 Fine-tune(微调)gpt-3.5! +- 大量 LLM 参数可调; +- 支持更换 api-host; +- 支持自定义代理; +- 支持多 api-key 负载均衡。 + +### ⚒️ 部署相关 +- 部署到服务器:在 `config.json` 中设置 `"server_name": "0.0.0.0", "server_port": <你的端口号>,`。 +- 获取公共链接:在 `config.json` 中设置 `"share": true,`。注意程序必须在运行,才能通过公共链接访问。 +- 在Hugging Face上使用:建议在右上角 **复制Space** 再使用,这样App反应可能会快一点。 + +## 快速上手 + +在终端执行以下命令: + +```shell +git clone https://github.com/GaiZhenbiao/ChuanhuChatGPT.git +cd ChuanhuChatGPT +pip install -r requirements.txt +``` + +然后,在项目文件夹中复制一份 `config_example.json`,并将其重命名为 `config.json`,在其中填入 `API-Key` 等设置。 + +```shell +python ChuanhuChatbot.py +``` + +一个浏览器窗口将会自动打开,此时您将可以使用 **川虎Chat** 与ChatGPT或其他模型进行对话。 + +> **Note** +> +> 具体详尽的安装教程和使用教程请查看[本项目的wiki页面](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程)。 + +## 疑难杂症解决 + +在遇到各种问题查阅相关信息前,您可以先尝试 **手动拉取本项目的最新更改1** 并 **更新依赖库2**,然后重试。步骤为: + +1. 点击网页上的 `Download ZIP` 按钮,下载最新代码并解压覆盖,或 + ```shell + git pull https://github.com/GaiZhenbiao/ChuanhuChatGPT.git main -f + ``` +2. 尝试再次安装依赖(可能本项目引入了新的依赖) + ``` + pip install -r requirements.txt + ``` + +很多时候,这样就可以解决问题。 + +如果问题仍然存在,请查阅该页面:[常见问题](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/常见问题) + +该页面列出了**几乎所有**您可能遇到的各种问题,包括如何配置代理,以及遇到问题后您该采取的措施,**请务必认真阅读**。 + +## 了解更多 + +若需了解更多信息,请查看我们的 [wiki](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki): + +- [想要做出贡献?](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/贡献指南) +- [项目更新情况?](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/更新日志) +- [二次开发许可?](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用许可) +- [如何引用项目?](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用许可#如何引用该项目) + +## Starchart + +[![Star History Chart](https://api.star-history.com/svg?repos=GaiZhenbiao/ChuanhuChatGPT&type=Date)](https://star-history.com/#GaiZhenbiao/ChuanhuChatGPT&Date) + +## Contributors + + + + + +## 捐款 + +🐯如果觉得这个软件对你有所帮助,欢迎请作者喝可乐、喝咖啡~ + +联系作者:请去[我的bilibili账号](https://space.bilibili.com/29125536)私信我。 + +Buy Me A Coffee + +image diff --git a/apps/chuanhuchat/data.yml b/apps/chuanhuchat/data.yml new file mode 100644 index 00000000..ddd3782a --- /dev/null +++ b/apps/chuanhuchat/data.yml @@ -0,0 +1,20 @@ +name: 川虎 Chat (Chuanhu Chat) +tags: + - 工具 +title: 为多种 LLM 提供了一个轻快好用的 Web 图形界面和众多附加功能 +type: 工具 +description: 为多种 LLM 提供了一个轻快好用的 Web 图形界面和众多附加功能 +additionalProperties: + key: chuanhuchat + name: 川虎 Chat (Chuanhu Chat) + tags: + - Tool + shortDescZh: 为多种 LLM 提供了一个轻快好用的 Web 图形界面和众多附加功能 + shortDescEn: Lightweight and User-friendly Web-UI for LLMs + type: tool + crossVersionUpdate: true + limit: 0 + recommend: 0 + website: https://github.com/GaiZhenbiao/ChuanhuChatGPT + github: https://github.com/GaiZhenbiao/ChuanhuChatGPT + document: https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki diff --git a/apps/chuanhuchat/latest/.env.sample b/apps/chuanhuchat/latest/.env.sample new file mode 100644 index 00000000..44077e2a --- /dev/null +++ b/apps/chuanhuchat/latest/.env.sample @@ -0,0 +1,2 @@ +CONTAINER_NAME="chuanhuchat" +PANEL_APP_PORT_HTTP="40193" diff --git a/apps/chuanhuchat/latest/data.yml b/apps/chuanhuchat/latest/data.yml new file mode 100644 index 00000000..27359aaf --- /dev/null +++ b/apps/chuanhuchat/latest/data.yml @@ -0,0 +1,10 @@ +additionalProperties: + formFields: + - default: 40193 + edit: true + envKey: PANEL_APP_PORT_HTTP + labelEn: Port + labelZh: 端口 + required: true + rule: paramPort + type: number diff --git a/apps/chuanhuchat/latest/data/config.json b/apps/chuanhuchat/latest/data/config.json new file mode 100644 index 00000000..1119150e --- /dev/null +++ b/apps/chuanhuchat/latest/data/config.json @@ -0,0 +1,64 @@ +{ + "openai_api_key": "", + "google_palm_api_key": "", + "xmchat_api_key": "", + "minimax_api_key": "", + "minimax_group_id": "", + "midjourney_proxy_api_base": "", + "midjourney_proxy_api_secret": "", + "midjourney_discord_proxy_url": "", + "midjourney_temp_folder": "./tmp", + "spark_appid": "", + "spark_api_key": "", + "spark_api_secret": "", + "claude_api_secret":"", + "ernie_api_key": "", + "ernie_secret_key": "", + + + + "openai_api_type": "openai", + "azure_openai_api_key": "", + "azure_openai_api_base_url": "", + "azure_openai_api_version": "2023-05-15", + "azure_deployment_name": "", + "azure_embedding_deployment_name": "", + "azure_embedding_model_name": "text-embedding-ada-002", + + + "language": "zh_CN", + "users": [], + "local_embedding": false, + "hide_history_when_not_logged_in": false, + "check_update": true, + "default_model": "GPT3.5 Turbo", + "chat_name_method_index": 2, + "bot_avatar": "default", + "user_avatar": "default", + + + "show_api_billing": false, + "sensitive_id": "", + "usage_limit": 120, + "legacy_api_usage": false, + + + "default_chuanhu_assistant_model": "gpt-4", + "GOOGLE_CSE_ID": "", + "GOOGLE_API_KEY": "", + "WOLFRAM_ALPHA_APPID": "", + "SERPAPI_API_KEY": "", + + + "latex_option": "default", + "advance_docs": { + "pdf": { + "two_column": false, + "formula_ocr": true + } + }, + + + "multi_api_key": false, + "hide_my_key": false +} diff --git a/apps/chuanhuchat/latest/data/config_example.json b/apps/chuanhuchat/latest/data/config_example.json new file mode 100644 index 00000000..9c4180d1 --- /dev/null +++ b/apps/chuanhuchat/latest/data/config_example.json @@ -0,0 +1,87 @@ +{ + // 各配置具体说明,见 [https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#配置-configjson] + + //== API 配置 == + "openai_api_key": "", // 你的 OpenAI API Key,一般必填,若空缺则需在图形界面中填入API Key + "google_palm_api_key": "", // 你的 Google PaLM API Key,用于 Google PaLM 对话模型 + "xmchat_api_key": "", // 你的 xmchat API Key,用于 XMChat 对话模型 + "minimax_api_key": "", // 你的 MiniMax API Key,用于 MiniMax 对话模型 + "minimax_group_id": "", // 你的 MiniMax Group ID,用于 MiniMax 对话模型 + "midjourney_proxy_api_base": "https://xxx/mj", // 你的 https://github.com/novicezk/midjourney-proxy 代理地址 + "midjourney_proxy_api_secret": "", // 你的 MidJourney Proxy API Secret,用于鉴权访问 api,可选 + "midjourney_discord_proxy_url": "", // 你的 MidJourney Discord Proxy URL,用于对生成对图进行反代,可选 + "midjourney_temp_folder": "./tmp", // 你的 MidJourney 临时文件夹,用于存放生成的图片,填空则关闭自动下载切图(直接显示MJ的四宫格图) + "spark_appid": "", // 你的 讯飞星火大模型 API AppID,用于讯飞星火大模型对话模型 + "spark_api_key": "", // 你的 讯飞星火大模型 API Key,用于讯飞星火大模型对话模型 + "spark_api_secret": "", // 你的 讯飞星火大模型 API Secret,用于讯飞星火大模型对话模型 + "claude_api_secret":"",// 你的 Claude API Secret,用于 Claude 对话模型 + "ernie_api_key": "",// 你的文心一言在百度云中的API Key,用于文心一言对话模型 + "ernie_secret_key": "",// 你的文心一言在百度云中的Secret Key,用于文心一言对话模型 + + + //== Azure == + "openai_api_type": "openai", // 可选项:azure, openai + "azure_openai_api_key": "", // 你的 Azure OpenAI API Key,用于 Azure OpenAI 对话模型 + "azure_openai_api_base_url": "", // 你的 Azure Base URL + "azure_openai_api_version": "2023-05-15", // 你的 Azure OpenAI API 版本 + "azure_deployment_name": "", // 你的 Azure OpenAI Chat 模型 Deployment 名称 + "azure_embedding_deployment_name": "", // 你的 Azure OpenAI Embedding 模型 Deployment 名称 + "azure_embedding_model_name": "text-embedding-ada-002", // 你的 Azure OpenAI Embedding 模型名称 + + //== 基础配置 == + "language": "auto", // 界面语言,可选"auto", "zh_CN", "en_US", "ja_JP", "ko_KR", "sv_SE", "ru_RU", "vi_VN" + "users": [], // 用户列表,[[用户名1, 密码1], [用户名2, 密码2], ...] + "local_embedding": false, //是否在本地编制索引 + "hide_history_when_not_logged_in": false, //未登录情况下是否不展示对话历史 + "check_update": true, //是否启用检查更新 + "default_model": "GPT3.5 Turbo", // 默认模型 + "chat_name_method_index": 2, // 选择对话名称的方法。0: 使用日期时间命名;1: 使用第一条提问命名,2: 使用模型自动总结 + "bot_avatar": "default", // 机器人头像,可填写本地或网络图片链接,或者"none"(不显示头像) + "user_avatar": "default", // 用户头像,可填写本地或网络图片链接,或者"none"(不显示头像) + + //== API 用量 == + "show_api_billing": false, //是否显示OpenAI API用量(启用需要填写sensitive_id) + "sensitive_id": "", // 你 OpenAI 账户的 Sensitive ID,用于查询 API 用量 + "usage_limit": 120, // 该 OpenAI API Key 的当月限额,单位:美元,用于计算百分比和显示上限 + "legacy_api_usage": false, // 是否使用旧版 API 用量查询接口(OpenAI现已关闭该接口,但是如果你在使用第三方 API,第三方可能仍然支持此接口) + + //== 川虎助理设置 == + "default_chuanhu_assistant_model": "gpt-4", //川虎助理使用的模型,可选gpt-3.5-turbo或者gpt-4等 + "GOOGLE_CSE_ID": "", //谷歌搜索引擎ID,用于川虎助理Pro模式,获取方式请看 https://stackoverflow.com/questions/37083058/programmatically-searching-google-in-python-using-custom-search + "GOOGLE_API_KEY": "", //谷歌API Key,用于川虎助理Pro模式 + "WOLFRAM_ALPHA_APPID": "", //Wolfram Alpha API Key,用于川虎助理Pro模式,获取方式请看 https://products.wolframalpha.com/api/ + "SERPAPI_API_KEY": "", //SerpAPI API Key,用于川虎助理Pro模式,获取方式请看 https://serpapi.com/ + + //== 文档处理与显示 == + "latex_option": "default", // LaTeX 公式渲染策略,可选"default", "strict", "all"或者"disabled" + "advance_docs": { + "pdf": { + "two_column": false, // 是否认为PDF是双栏的 + "formula_ocr": true // 是否使用OCR识别PDF中的公式 + } + }, + + //== 高级配置 == + // 是否多个API Key轮换使用 + "multi_api_key": false, + "hide_my_key": false, // 如果你想在UI中隐藏 API 密钥输入框,将此值设置为 true + // "available_models": ["GPT3.5 Turbo", "GPT4 Turbo", "GPT4 Vision"], // 可用的模型列表,将覆盖默认的可用模型列表 + // "extra_models": ["模型名称3", "模型名称4", ...], // 额外的模型,将添加到可用的模型列表之后 + // "api_key_list": [ + // "sk-xxxxxxxxxxxxxxxxxxxxxxxx1", + // "sk-xxxxxxxxxxxxxxxxxxxxxxxx2", + // "sk-xxxxxxxxxxxxxxxxxxxxxxxx3" + // ], + // 自定义OpenAI API Base + // "openai_api_base": "https://api.openai.com", + // 自定义使用代理(请替换代理URL) + // "https_proxy": "http://127.0.0.1:1079", + // "http_proxy": "http://127.0.0.1:1079", + // 自定义端口、自定义ip(请替换对应内容) + // "server_name": "0.0.0.0", + // "server_port": 7860, + // 如果要share到gradio,设置为true + // "share": false, + //如果不想自动打开浏览器,设置为false + //"autobrowser": false +} diff --git a/apps/chuanhuchat/latest/docker-compose.yml b/apps/chuanhuchat/latest/docker-compose.yml new file mode 100644 index 00000000..a5bdab20 --- /dev/null +++ b/apps/chuanhuchat/latest/docker-compose.yml @@ -0,0 +1,19 @@ +version: '3' +services: + chuanhuchat: + container_name: ${CONTAINER_NAME} + restart: always + networks: + - 1panel-network + ports: + - "${PANEL_APP_PORT_HTTP}:7860" + volumes: + - ./data/history:/app/history + - ./data/config.json:/app/config.json + image: tuchuanhuhuhu/chuanhuchatgpt:latest + labels: + createdBy: "Apps" + +networks: + 1panel-network: + external: true diff --git a/apps/chuanhuchat/logo.png b/apps/chuanhuchat/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..4cb36f4664d947f3a139ceead45ffff62c05e753 GIT binary patch literal 8672 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