Skip to content

Commit

Permalink
💻 Code: Refactor code, use ModelMerge as the model Q&A backend.
Browse files Browse the repository at this point in the history
  • Loading branch information
yym68686 committed May 10, 2024
1 parent 223cc38 commit 5143628
Show file tree
Hide file tree
Showing 12 changed files with 39 additions and 3,091 deletions.
22 changes: 1 addition & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,26 +46,6 @@ The ChatGPT Telegram Bot is a powerful Telegram bot that utilizes the latest GPT
| GOOGLE_AI_API_KEY | Google AI offical API key. | No |
| GROQ_API_KEY | Groq AI offical API key. | No |

## 🔌 Plugins

Our plugin system has been successfully developed and is now fully operational. We welcome everyone to contribute their code to enrich our plugin library. All plugins can be activated or deactivated using the `/info` command. The following plugins are currently supported:

- **Web Search**: By default, DuckDuckGo search is provided. Google search is automatically activated when the `GOOGLE_CSE_ID` and `GOOGLE_API_KEY` environment variables are set.
- **Time Retrieval**: Retrieves the current time, date, and day of the week in the GMT+8 time zone.
- **URL Summary**: Automatically extracts URLs from queries and responds based on the content of the URLs.
- **Version Information**: Displays the current version of the bot, commit hash, update time, and developer name.

To develop plugins, please follow the steps outlined below:

- Initially, you need to add the environment variable for the plugin in the `config.PLUGINS` dictionary located in the `config.py` file. The value can be customized to be either enabled or disabled by default. It is advisable to use uppercase letters for the entire environment variable.
- Subsequently, append the function's name and description in the `utils/function_call.py` file.
- Then, enhance the `ask_stream` function in the `utils/chatgpt2api.py` file with the function's processing logic. You can refer to the existing examples within the `ask_stream` method for guidance on how to write it.
- Following that, write the function, as mentioned in the `utils/function_call.py` file, in the `utils/plugins.py` file.
- Next, in the `bot.py` file, augment the `update_first_buttons_message` function with buttons, enabling users to freely toggle plugins using the `info` command.
- Lastly, don't forget to add the plugin's description in the plugins section of the README.

Please note that the above steps are a general guide and may need to be adjusted based on the specific requirements of your plugin.

## Zeabur Remote Deployment (Recommended)

One-click deployment:
Expand Down Expand Up @@ -272,7 +252,7 @@ In a group chat scenario, if the environment variable `NICK` is not set, the bot

- How many messages will the history keep?

Apart from the latest `gpt-4-turbo-preview` model, the official context supports 128k tokens, but this project limits it to 16k tokens. All other models use the official context length settings, for example, the `gpt-3.5-turbo-16k` context is 16k, the `gpt-4-32k` context is 32k, and the `Claude2` context is 200k. This limitation is implemented to save user costs, as most scenarios do not require a high context. If you have specific needs, you can modify the context limits for each model in the `utils/chatgpt2api.py` file.
Apart from the latest `gpt-4-turbo-preview` model, the official context supports 128k tokens, but this project limits it to 16k tokens. All other models use the official context length settings, for example, the `gpt-3.5-turbo-16k` context is 16k, the `gpt-4-32k` context is 32k, and the `Claude2` context is 200k. This limitation is implemented to save user costs, as most scenarios do not require a high context.

## References

Expand Down
40 changes: 21 additions & 19 deletions bot.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
import re
import os
import sys
sys.dont_write_bytecode = True
import config
import logging
import traceback
import utils.decorators as decorators
from md2tgmd import escape
from utils.chatgpt2api import Chatbot as GPT
from utils.chatgpt2api import claudebot, groqbot, claude3bot, gemini_bot
from utils.prompt import translator_en2zh_prompt, translator_prompt, claude3_doc_assistant_prompt

from ModelMerge.models import chatgpt, claude, groq, claude3, gemini
from ModelMerge.models.config import PLUGINS
from ModelMerge.utils.prompt import translator_en2zh_prompt, translator_prompt, claude3_doc_assistant_prompt
from ModelMerge.utils.scripts import Document_extract, get_encode_image, claude_replace

import config
from config import WEB_HOOK, PORT, BOT_TOKEN, update_first_buttons_message, buttons

from telegram.constants import ChatAction
from utils.plugins import Document_extract, get_encode_image, claude_replace
from telegram import BotCommand, InlineKeyboardMarkup, InlineQueryResultArticle, InputTextMessageContent
from telegram.ext import CommandHandler, MessageHandler, ApplicationBuilder, filters, CallbackQueryHandler, Application, AIORateLimiter, InlineQueryHandler
from config import WEB_HOOK, PORT, BOT_TOKEN, update_first_buttons_message, buttons


logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s")
Expand Down Expand Up @@ -269,7 +271,7 @@ async def image(update, context):
start_messageid = message.message_id

try:
for data in robot.dall_e_3(text):
for data in robot.generate(text):
result = data
await context.bot.delete_message(chat_id=chatid, message_id=start_messageid)
await context.bot.send_photo(chat_id=chatid, photo=result, reply_to_message_id=messageid)
Expand Down Expand Up @@ -329,16 +331,16 @@ async def button_press(update, context):
config.GPT_ENGINE = data
# print("config.GPT_ENGINE", config.GPT_ENGINE)
if (config.API and "gpt-" in data) or (config.API and not config.ClaudeAPI) or (config.API and config.CUSTOM_MODELS and data in config.CUSTOM_MODELS):
config.ChatGPTbot = GPT(api_key=f"{config.API}", engine=config.GPT_ENGINE, system_prompt=config.systemprompt, temperature=config.temperature)
config.ChatGPTbot = chatgpt(api_key=f"{config.API}", engine=config.GPT_ENGINE, system_prompt=config.systemprompt, temperature=config.temperature)
config.ChatGPTbot.reset(convo_id=str(update.effective_chat.id), system_prompt=config.systemprompt)
if config.ClaudeAPI and "claude-2.1" in data:
config.claudeBot = claudebot(api_key=f"{config.ClaudeAPI}", engine=config.GPT_ENGINE, system_prompt=config.claude_systemprompt, temperature=config.temperature)
config.claudeBot = claude(api_key=f"{config.ClaudeAPI}", engine=config.GPT_ENGINE, system_prompt=config.claude_systemprompt, temperature=config.temperature)
if config.ClaudeAPI and "claude-3" in data:
config.claude3Bot = claude3bot(api_key=f"{config.ClaudeAPI}", engine=config.GPT_ENGINE, system_prompt=config.claude_systemprompt, temperature=config.temperature)
config.claude3Bot = claude3(api_key=f"{config.ClaudeAPI}", engine=config.GPT_ENGINE, system_prompt=config.claude_systemprompt, temperature=config.temperature)
if config.GROQ_API_KEY and ("mixtral" in data or "llama" in data):
config.groqBot = groqbot(api_key=f"{config.GROQ_API_KEY}", engine=config.GPT_ENGINE, system_prompt=config.systemprompt, temperature=config.temperature)
config.groqBot = groq(api_key=f"{config.GROQ_API_KEY}", engine=config.GPT_ENGINE, system_prompt=config.systemprompt, temperature=config.temperature)
if config.GOOGLE_AI_API_KEY and "gemini" in data:
config.gemini_Bot = gemini_bot(api_key=f"{config.GOOGLE_AI_API_KEY}", engine=config.GPT_ENGINE, system_prompt=config.systemprompt, temperature=config.temperature)
config.gemini_Bot = gemini(api_key=f"{config.GOOGLE_AI_API_KEY}", engine=config.GPT_ENGINE, system_prompt=config.systemprompt, temperature=config.temperature)
try:
info_message = update_info_message(update)
if info_message + banner != callback_query.message.text:
Expand Down Expand Up @@ -373,15 +375,15 @@ async def button_press(update, context):
config.claude_systemprompt = config.claude_systemprompt.replace("English", "Simplified Chinese")
# config.systemprompt = f"You are ChatGPT, a large language model trained by OpenAI. Respond conversationally in {config.LANGUAGE}. Knowledge cutoff: 2021-09. Current date: [ {config.Current_Date} ]"
if config.API:
config.ChatGPTbot = GPT(api_key=f"{config.API}", engine=config.GPT_ENGINE, system_prompt=config.systemprompt, temperature=config.temperature)
config.ChatGPTbot = chatgpt(api_key=f"{config.API}", engine=config.GPT_ENGINE, system_prompt=config.systemprompt, temperature=config.temperature)
config.ChatGPTbot.reset(convo_id=str(update.effective_chat.id), system_prompt=config.systemprompt)
if config.ClaudeAPI:
config.claudeBot = claudebot(api_key=f"{config.ClaudeAPI}", engine=config.GPT_ENGINE, system_prompt=config.claude_systemprompt, temperature=config.temperature)
config.claude3Bot = claude3bot(api_key=f"{config.ClaudeAPI}", engine=config.GPT_ENGINE, system_prompt=config.claude_systemprompt, temperature=config.temperature)
config.claudeBot = claude(api_key=f"{config.ClaudeAPI}", engine=config.GPT_ENGINE, system_prompt=config.claude_systemprompt, temperature=config.temperature)
config.claude3Bot = claude3(api_key=f"{config.ClaudeAPI}", engine=config.GPT_ENGINE, system_prompt=config.claude_systemprompt, temperature=config.temperature)
if config.GROQ_API_KEY:
config.groqBot = groqbot(api_key=f"{config.GROQ_API_KEY}", engine=config.GPT_ENGINE, system_prompt=config.systemprompt, temperature=config.temperature)
config.groqBot = groq(api_key=f"{config.GROQ_API_KEY}", engine=config.GPT_ENGINE, system_prompt=config.systemprompt, temperature=config.temperature)
if config.GOOGLE_AI_API_KEY:
config.gemini_Bot = gemini_bot(api_key=f"{config.GOOGLE_AI_API_KEY}", engine=config.GPT_ENGINE, system_prompt=config.systemprompt, temperature=config.temperature)
config.gemini_Bot = gemini(api_key=f"{config.GOOGLE_AI_API_KEY}", engine=config.GPT_ENGINE, system_prompt=config.systemprompt, temperature=config.temperature)

info_message = update_info_message(update)
message = await callback_query.edit_message_text(
Expand All @@ -391,7 +393,7 @@ async def button_press(update, context):
)
else:
try:
config.PLUGINS[data] = not config.PLUGINS[data]
PLUGINS[data] = not PLUGINS[data]
except:
setattr(config, data, not getattr(config, data))
info_message = update_info_message(update)
Expand Down
49 changes: 13 additions & 36 deletions config.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import os
from dotenv import load_dotenv
load_dotenv()
import utils.prompt as prompt

from telegram import InlineKeyboardButton

WEB_HOOK = os.environ.get('WEB_HOOK', None)
Expand All @@ -28,32 +28,32 @@
CUSTOM_MODELS_LIST = None


from ModelMerge.utils import prompt
from datetime import datetime
current_date = datetime.now()
Current_Date = current_date.strftime("%Y-%m-%d")
systemprompt = os.environ.get('SYSTEMPROMPT', prompt.system_prompt.format(LANGUAGE, Current_Date))
claude_systemprompt = os.environ.get('SYSTEMPROMPT', prompt.claude_system_prompt)

from utils.chatgpt2api import Chatbot as GPT
from utils.chatgpt2api import Imagebot, claudebot, groqbot, claude3bot, gemini_bot
from ModelMerge.models import chatgpt, claude, groq, claude3, gemini, dalle3
if API:
ChatGPTbot = GPT(api_key=f"{API}", engine=GPT_ENGINE, system_prompt=systemprompt, temperature=temperature)
ChatGPTbot = chatgpt(api_key=f"{API}", engine=GPT_ENGINE, system_prompt=systemprompt, temperature=temperature)

translate_bot = GPT(api_key=f"{API}", engine=GPT_ENGINE, system_prompt=systemprompt, temperature=temperature)
copilot_bot = GPT(api_key=f"{API}", engine=GPT_ENGINE, system_prompt=prompt.search_system_prompt.format(LANGUAGE), temperature=temperature)
dallbot = Imagebot(api_key=f"{API}")
translate_bot = chatgpt(api_key=f"{API}", engine=GPT_ENGINE, system_prompt=systemprompt, temperature=temperature)
copilot_bot = chatgpt(api_key=f"{API}", engine=GPT_ENGINE, system_prompt=prompt.search_system_prompt.format(LANGUAGE), temperature=temperature)
dallbot = dalle3(api_key=f"{API}")
else:
ChatGPTbot = None

ClaudeAPI = os.environ.get('claude_api_key', None)
if ClaudeAPI:
claudeBot = claudebot(api_key=f"{ClaudeAPI}", system_prompt=claude_systemprompt)
claude3Bot = claude3bot(api_key=f"{ClaudeAPI}", system_prompt=claude_systemprompt)
claudeBot = claude(api_key=f"{ClaudeAPI}", system_prompt=claude_systemprompt)
claude3Bot = claude3(api_key=f"{ClaudeAPI}", system_prompt=claude_systemprompt)

if GROQ_API_KEY:
groqBot = groqbot(api_key=f"{GROQ_API_KEY}")
groqBot = groq(api_key=f"{GROQ_API_KEY}")
if GOOGLE_AI_API_KEY:
gemini_Bot = gemini_bot(api_key=f"{GOOGLE_AI_API_KEY}")
gemini_Bot = gemini(api_key=f"{GOOGLE_AI_API_KEY}")

whitelist = os.environ.get('whitelist', None)
if whitelist:
Expand All @@ -65,14 +65,6 @@
if GROUP_LIST:
GROUP_LIST = [int(id) for id in GROUP_LIST.split(",")]

PLUGINS = {
"SEARCH_USE_GPT": (os.environ.get('SEARCH_USE_GPT', "True") == "False") == False,
# "USE_G4F": (os.environ.get('USE_G4F', "False") == "False") == False,
"DATE": True,
"URL": True,
"VERSION": True,
}

class userConfig:
def __init__(self, user_id: int):
self.user_id = user_id
Expand All @@ -83,21 +75,7 @@ def __init__(self, user_id: int):
self.search_system_prompt = prompt.search_system_prompt.format(self.language)
self.search_model = "gpt-3.5-turbo-1106"

class openaiAPI:
def __init__(
self,
api_url: str = (os.environ.get("API_URL") or "https://api.openai.com/v1/chat/completions"),
):
from urllib.parse import urlparse, urlunparse
self.source_api_url: str = api_url
parsed_url = urlparse(self.source_api_url)
self.base_url: str = urlunparse(parsed_url[:2] + ("",) * 4)
self.v1_url: str = urlunparse(parsed_url[:2] + ("/v1",) + ("",) * 3)
self.chat_url: str = urlunparse(parsed_url[:2] + ("/v1/chat/completions",) + ("",) * 3)
self.image_url: str = urlunparse(parsed_url[:2] + ("/v1/images/generations",) + ("",) * 3)

bot_api_url = openaiAPI()

from ModelMerge.models.config import PLUGINS
def get_plugins_status(item):
return "✅" if PLUGINS[item] else "☑️"

Expand Down Expand Up @@ -181,13 +159,12 @@ def update_first_buttons_message():
InlineKeyboardButton(f"历史记录 {history}", callback_data="PASS_HISTORY"),
],
[
InlineKeyboardButton(f"搜索 {get_plugins_status('SEARCH_USE_GPT')}", callback_data='SEARCH_USE_GPT'),
InlineKeyboardButton(f"搜索 {get_plugins_status('SEARCH')}", callback_data='SEARCH'),
InlineKeyboardButton(f"当前时间 {get_plugins_status('DATE')}", callback_data='DATE'),
],
[
InlineKeyboardButton(f"URL 总结 {get_plugins_status('URL')}", callback_data='URL'),
InlineKeyboardButton(f"版本信息 {get_plugins_status('VERSION')}", callback_data='VERSION'),
# InlineKeyboardButton(f"gpt4free {get_plugins_status('USE_G4F')}", callback_data='USE_G4F'),
],
]
return first_buttons
25 changes: 4 additions & 21 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,25 +1,8 @@
--index-url https://pypi.python.org/simple/
requests
tiktoken==0.6.0
md2tgmd==0.1.9
# jieba
pytz
python-dotenv
beautifulsoup4
lxml
python-telegram-bot[webhooks,rate-limiter]==21.0.1
# python-telegram-bot[webhooks,rate-limiter]==20.6

# langchain
# chromadb
# unstructured[md,pdf]
md2tgmd==0.1.9
fake_useragent
openai==0.28.1
google-api-python-client
duckduckgo-search==5.3.0
langchain==0.0.271
ModelMerge==0.2.9
oauth2client==3.0.0
pdfminer.six
# g4f==0.1.9.6

# plugin
pytz
python-telegram-bot[webhooks,rate-limiter]==21.0.1
Loading

0 comments on commit 5143628

Please sign in to comment.