From 16735551c01aaec444a1e47318dd57765ee73e84 Mon Sep 17 00:00:00 2001 From: F4ria Date: Wed, 10 Apr 2024 19:03:55 +0800 Subject: [PATCH 1/8] feat: support chatgpt --- handlers/chatgpt.py | 246 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 246 insertions(+) create mode 100644 handlers/chatgpt.py diff --git a/handlers/chatgpt.py b/handlers/chatgpt.py new file mode 100644 index 0000000..927fb7a --- /dev/null +++ b/handlers/chatgpt.py @@ -0,0 +1,246 @@ +import base64 +from os import environ +from pathlib import Path +import time + +from openai import OpenAI +from telebot import TeleBot +from telebot.types import Message + +from . import * + +from telegramify_markdown import convert +from telegramify_markdown.customize import markdown_symbol + +markdown_symbol.head_level_1 = "📌" # If you want, Customizing the head level 1 symbol +markdown_symbol.link = "🔗" # If you want, Customizing the link symbol + +CHATGPT_API_KEY = environ.get("OPENAI_API_KEY") +CHATGPT_BASE_URL = environ.get("OPENAI_API_BASE") or "https://api.openai.com/v1" +CHATGPT_MODEL = "gpt-3.5-turbo" +CHATGPT_PRO_MODEL = "gpt-4-turbo" + + +client = OpenAI(api_key=CHATGPT_API_KEY, base_url=CHATGPT_BASE_URL, timeout=20) + + +# Global history cache +chatgpt_player_dict = {} +chatgpt_pro_player_dict = {} + + +def chatgpt_handler(message: Message, bot: TeleBot) -> None: + """chatgpt : /chatgpt """ + m = message.text.strip() + + player_message = [] + # restart will lose all TODO + if str(message.from_user.id) not in chatgpt_player_dict: + chatgpt_player_dict[str(message.from_user.id)] = ( + player_message # for the imuutable list + ) + else: + player_message = chatgpt_player_dict[str(message.from_user.id)] + if m.strip() == "clear": + bot.reply_to( + message, + "just clear your chatgpt messages history", + ) + player_message.clear() + return + + # show something, make it more responsible + reply_id = bot_reply_first(message, "ChatGPT", bot) + + player_message.append({"role": "user", "content": m}) + # keep the last 5, every has two ask and answer. + if len(player_message) > 10: + player_message = player_message[2:] + + chatgpt_reply_text = "" + try: + r = client.chat.completions.create( + messages=player_message, max_tokens=1024, model=CHATGPT_MODEL + ) + content = r.choices[0].message.content.encode("utf8").decode() + if not content: + chatgpt_reply_text = "chatgpt did not answer." + player_message.pop() + else: + chatgpt_reply_text = content + player_message.append( + { + "role": "assistant", + "content": chatgpt_reply_text, + } + ) + + except Exception as e: + print(e) + bot.reply_to( + message, + "ChatGPT answer:\n" + "chatgpt answer timeout", + parse_mode="MarkdownV2", + ) + # pop my user + player_message.pop() + return + + # reply back as Markdown and fallback to plain text if failed. + bot_reply_markdown(reply_id, "ChatGPT", chatgpt_reply_text, bot) + + +def chatgpt_pro_handler(message: Message, bot: TeleBot) -> None: + """chatgpt_pro : /chatgpt_pro """ + m = message.text.strip() + + player_message = [] + # restart will lose all TODO + if str(message.from_user.id) not in chatgpt_player_dict: + chatgpt_player_dict[str(message.from_user.id)] = ( + player_message # for the imuutable list + ) + else: + player_message = chatgpt_player_dict[str(message.from_user.id)] + if m.strip() == "clear": + bot.reply_to( + message, + "just clear your chatgpt messages history", + ) + player_message.clear() + return + + reply_id = bot_reply_first(message, "ChatGPT", bot) + + player_message.append({"role": "user", "content": m}) + # keep the last 5, every has two ask and answer. + if len(player_message) > 10: + player_message = player_message[2:] + + try: + r = client.chat.completions.create( + messages=player_message, + max_tokens=2048, + model=CHATGPT_PRO_MODEL, + stream=True, + ) + s = "" + start = time.time() + for chunk in r: + if chunk.choices[0].delta.content is None: + break + s += chunk.choices[0].delta.content + + if time.time() - start > 1.7: + start = time.time() + try: + bot.edit_message_text( + message_id=reply_id.message_id, + chat_id=reply_id.chat.id, + text=convert(s), + parse_mode="MarkdownV2", + ) + except Exception as e: + print(str(e)) + try: + # maybe not complete + # maybe the same message + bot.edit_message_text( + message_id=reply_id.message_id, + chat_id=reply_id.chat.id, + text=convert(s), + parse_mode="MarkdownV2", + ) + except Exception as e: + player_message.clear() + print(str(e)) + return + + player_message.append( + { + "role": "assistant", + "content": convert(s), + } + ) + + except Exception as e: + bot.reply_to( + message, + "chatgpt answer:\n" + "chatgpt answer timeout", + parse_mode="MarkdownV2", + ) + # pop my user + player_message.clear() + return + + +def _image_to_data_uri(file_path): + with open(file_path, "rb") as image_file: + encoded_image = base64.b64encode(image_file.read()).decode("utf-8") + return f"data:image/png;base64,{encoded_image}" + + +def chatgpt_photo_handler(message: Message, bot: TeleBot) -> None: + s = message.caption + reply_message = bot.reply_to( + message, + "Generating chatgpt vision answer please wait.", + ) + prompt = s.strip() + # get the high quaility picture. + max_size_photo = max(message.photo, key=lambda p: p.file_size) + file_path = bot.get_file(max_size_photo.file_id).file_path + downloaded_file = bot.download_file(file_path) + with open("chatgpt_temp.jpg", "wb") as temp_file: + temp_file.write(downloaded_file) + + try: + r = client.chat.completions.create( + max_tokens=1024, + messages=[ + { + "role": "user", + "content": [ + {"type": "text", "text": prompt}, + { + "type": "image_url", + "image_url": { + "url": _image_to_data_uri("chatgpt_temp.jpg") + }, + }, + ], + } + ], + model=CHATGPT_PRO_MODEL, + ) + bot.reply_to( + message, + "ChatGPT vision answer:\n" + + r.choices[0].message.content.encode("utf8").decode(), + ) + except Exception as e: + print(e) + bot.reply_to( + message, + "ChatGPT vision answer:\n" + "chatgpt vision answer wrong", + parse_mode="MarkdownV2", + ) + finally: + bot.delete_message(reply_message.chat.id, reply_message.message_id) + + +def register(bot: TeleBot) -> None: + bot.register_message_handler(chatgpt_handler, commands=["chatgpt"], pass_bot=True) + bot.register_message_handler(chatgpt_handler, regexp="^chatgpt:", pass_bot=True) + bot.register_message_handler( + chatgpt_pro_handler, commands=["chatgpt_pro"], pass_bot=True + ) + bot.register_message_handler( + chatgpt_pro_handler, regexp="^chatgpt_pro:", pass_bot=True + ) + bot.register_message_handler( + chatgpt_photo_handler, + content_types=["photo"], + func=lambda m: m.caption and m.caption.startswith(("chatgpt:", "/chatgpt")), + pass_bot=True, + ) From 394dc8df99d7b388999c9c62bc0cf9f1cf1bd070 Mon Sep 17 00:00:00 2001 From: F4ria Date: Thu, 11 Apr 2024 11:18:07 +0800 Subject: [PATCH 2/8] feat: chatgpt photo stream --- handlers/chatgpt.py | 61 +++++++++++++++++++++++++++++---------------- 1 file changed, 40 insertions(+), 21 deletions(-) diff --git a/handlers/chatgpt.py b/handlers/chatgpt.py index 927fb7a..443ff80 100644 --- a/handlers/chatgpt.py +++ b/handlers/chatgpt.py @@ -174,26 +174,19 @@ def chatgpt_pro_handler(message: Message, bot: TeleBot) -> None: return -def _image_to_data_uri(file_path): - with open(file_path, "rb") as image_file: - encoded_image = base64.b64encode(image_file.read()).decode("utf-8") - return f"data:image/png;base64,{encoded_image}" - - def chatgpt_photo_handler(message: Message, bot: TeleBot) -> None: s = message.caption - reply_message = bot.reply_to( - message, - "Generating chatgpt vision answer please wait.", - ) prompt = s.strip() + reply_id = bot_reply_first(message, "ChatGPT Vision", bot) # get the high quaility picture. max_size_photo = max(message.photo, key=lambda p: p.file_size) file_path = bot.get_file(max_size_photo.file_id).file_path downloaded_file = bot.download_file(file_path) with open("chatgpt_temp.jpg", "wb") as temp_file: temp_file.write(downloaded_file) - + with open("chatgpt_temp.jpg", "rb") as image_file: + image_data = image_file.read() + base64_image_data = base64.b64encode(image_data).decode("utf-8") try: r = client.chat.completions.create( max_tokens=1024, @@ -205,28 +198,54 @@ def chatgpt_photo_handler(message: Message, bot: TeleBot) -> None: { "type": "image_url", "image_url": { - "url": _image_to_data_uri("chatgpt_temp.jpg") + "url": f"data:image/jpeg;base64,{base64_image_data}" }, }, ], } ], model=CHATGPT_PRO_MODEL, + stream=True, ) - bot.reply_to( - message, - "ChatGPT vision answer:\n" - + r.choices[0].message.content.encode("utf8").decode(), - ) + s = "ChatGPT Vision answer:\n" + start = time.time() + for chunk in r: + if chunk.choices[0].delta.content is None: + break + s += chunk.choices[0].delta.content + + if time.time() - start > 1.7: + start = time.time() + try: + bot.edit_message_text( + message_id=reply_id.message_id, + chat_id=reply_id.chat.id, + text=convert(s), + parse_mode="MarkdownV2", + ) + except Exception as e: + print(str(e)) + try: + # maybe not complete + # maybe the same message + bot.edit_message_text( + message_id=reply_id.message_id, + chat_id=reply_id.chat.id, + text=convert(s), + parse_mode="MarkdownV2", + ) + except Exception as e: + print(str(e)) + return + except Exception as e: - print(e) + print(str(e)) bot.reply_to( message, - "ChatGPT vision answer:\n" + "chatgpt vision answer wrong", + "ChatGPT Vision answer:\n" + "ChatGPT Vision answer timeout", parse_mode="MarkdownV2", ) - finally: - bot.delete_message(reply_message.chat.id, reply_message.message_id) + return def register(bot: TeleBot) -> None: From 2248d649fcc95f033d84837f7537d95e7a30142c Mon Sep 17 00:00:00 2001 From: F4ria Date: Fri, 12 Apr 2024 10:34:17 +0800 Subject: [PATCH 3/8] simplify chatgpt handler functions --- handlers/chatgpt.py | 85 +++++++++++---------------------------------- 1 file changed, 20 insertions(+), 65 deletions(-) diff --git a/handlers/chatgpt.py b/handlers/chatgpt.py index 443ff80..215f716 100644 --- a/handlers/chatgpt.py +++ b/handlers/chatgpt.py @@ -49,8 +49,9 @@ def chatgpt_handler(message: Message, bot: TeleBot) -> None: player_message.clear() return + who = "ChatGPT" # show something, make it more responsible - reply_id = bot_reply_first(message, "ChatGPT", bot) + reply_id = bot_reply_first(message, who, bot) player_message.append({"role": "user", "content": m}) # keep the last 5, every has two ask and answer. @@ -64,7 +65,7 @@ def chatgpt_handler(message: Message, bot: TeleBot) -> None: ) content = r.choices[0].message.content.encode("utf8").decode() if not content: - chatgpt_reply_text = "chatgpt did not answer." + chatgpt_reply_text = f"{who} did not answer." player_message.pop() else: chatgpt_reply_text = content @@ -77,17 +78,13 @@ def chatgpt_handler(message: Message, bot: TeleBot) -> None: except Exception as e: print(e) - bot.reply_to( - message, - "ChatGPT answer:\n" + "chatgpt answer timeout", - parse_mode="MarkdownV2", - ) + bot_reply_markdown(reply_id, who, "answer wrong", bot) # pop my user player_message.pop() return # reply back as Markdown and fallback to plain text if failed. - bot_reply_markdown(reply_id, "ChatGPT", chatgpt_reply_text, bot) + bot_reply_markdown(reply_id, who, chatgpt_reply_text, bot) def chatgpt_pro_handler(message: Message, bot: TeleBot) -> None: @@ -110,7 +107,8 @@ def chatgpt_pro_handler(message: Message, bot: TeleBot) -> None: player_message.clear() return - reply_id = bot_reply_first(message, "ChatGPT", bot) + who = "ChatGPT Pro" + reply_id = bot_reply_first(message, who, bot) player_message.append({"role": "user", "content": m}) # keep the last 5, every has two ask and answer. @@ -130,30 +128,14 @@ def chatgpt_pro_handler(message: Message, bot: TeleBot) -> None: if chunk.choices[0].delta.content is None: break s += chunk.choices[0].delta.content - if time.time() - start > 1.7: start = time.time() - try: - bot.edit_message_text( - message_id=reply_id.message_id, - chat_id=reply_id.chat.id, - text=convert(s), - parse_mode="MarkdownV2", - ) - except Exception as e: - print(str(e)) - try: + bot_reply_markdown(reply_id, who, s, bot, split_text=False) + + if not bot_reply_markdown(reply_id, who, s, bot): # maybe not complete # maybe the same message - bot.edit_message_text( - message_id=reply_id.message_id, - chat_id=reply_id.chat.id, - text=convert(s), - parse_mode="MarkdownV2", - ) - except Exception as e: player_message.clear() - print(str(e)) return player_message.append( @@ -164,12 +146,8 @@ def chatgpt_pro_handler(message: Message, bot: TeleBot) -> None: ) except Exception as e: - bot.reply_to( - message, - "chatgpt answer:\n" + "chatgpt answer timeout", - parse_mode="MarkdownV2", - ) - # pop my user + print(e) + bot_reply_markdown(reply_id, who, "answer wrong", bot) player_message.clear() return @@ -177,7 +155,9 @@ def chatgpt_pro_handler(message: Message, bot: TeleBot) -> None: def chatgpt_photo_handler(message: Message, bot: TeleBot) -> None: s = message.caption prompt = s.strip() - reply_id = bot_reply_first(message, "ChatGPT Vision", bot) + who = "ChatGPT Vision" + # show something, make it more responsible + reply_id = bot_reply_first(message, who, bot) # get the high quaility picture. max_size_photo = max(message.photo, key=lambda p: p.file_size) file_path = bot.get_file(max_size_photo.file_id).file_path @@ -207,45 +187,20 @@ def chatgpt_photo_handler(message: Message, bot: TeleBot) -> None: model=CHATGPT_PRO_MODEL, stream=True, ) - s = "ChatGPT Vision answer:\n" + s = "" start = time.time() for chunk in r: if chunk.choices[0].delta.content is None: break s += chunk.choices[0].delta.content - if time.time() - start > 1.7: start = time.time() - try: - bot.edit_message_text( - message_id=reply_id.message_id, - chat_id=reply_id.chat.id, - text=convert(s), - parse_mode="MarkdownV2", - ) - except Exception as e: - print(str(e)) - try: - # maybe not complete - # maybe the same message - bot.edit_message_text( - message_id=reply_id.message_id, - chat_id=reply_id.chat.id, - text=convert(s), - parse_mode="MarkdownV2", - ) - except Exception as e: - print(str(e)) - return + bot_reply_markdown(reply_id, who, s, bot, split_text=False) + bot_reply_markdown(reply_id, who, s, bot) except Exception as e: - print(str(e)) - bot.reply_to( - message, - "ChatGPT Vision answer:\n" + "ChatGPT Vision answer timeout", - parse_mode="MarkdownV2", - ) - return + print(e) + bot_reply_markdown(reply_id, who, "answer wrong", bot) def register(bot: TeleBot) -> None: From a0e65d8bd9b9b61d1e6b608fc19d7706a4f46c23 Mon Sep 17 00:00:00 2001 From: F4ria Date: Mon, 15 Apr 2024 18:55:30 +0800 Subject: [PATCH 4/8] start a new chat if the message starts with 'new ' --- handlers/chatgpt.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/handlers/chatgpt.py b/handlers/chatgpt.py index 215f716..f42d999 100644 --- a/handlers/chatgpt.py +++ b/handlers/chatgpt.py @@ -48,6 +48,9 @@ def chatgpt_handler(message: Message, bot: TeleBot) -> None: ) player_message.clear() return + if m[:4].lower() == "new ": + m = m[4:].strip() + player_message.clear() who = "ChatGPT" # show something, make it more responsible @@ -106,6 +109,9 @@ def chatgpt_pro_handler(message: Message, bot: TeleBot) -> None: ) player_message.clear() return + if m[:4].lower() == "new ": + m = m[4:].strip() + player_message.clear() who = "ChatGPT Pro" reply_id = bot_reply_first(message, who, bot) @@ -128,7 +134,7 @@ def chatgpt_pro_handler(message: Message, bot: TeleBot) -> None: if chunk.choices[0].delta.content is None: break s += chunk.choices[0].delta.content - if time.time() - start > 1.7: + if time.time() - start > 2.0: start = time.time() bot_reply_markdown(reply_id, who, s, bot, split_text=False) @@ -193,7 +199,7 @@ def chatgpt_photo_handler(message: Message, bot: TeleBot) -> None: if chunk.choices[0].delta.content is None: break s += chunk.choices[0].delta.content - if time.time() - start > 1.7: + if time.time() - start > 2.0: start = time.time() bot_reply_markdown(reply_id, who, s, bot, split_text=False) From 19bb441533230ea0a33f3c51d91ebb6000a926ec Mon Sep 17 00:00:00 2001 From: F4ria Date: Tue, 16 Apr 2024 14:15:12 +0800 Subject: [PATCH 5/8] url reader for chatgpt --- handlers/chatgpt.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/handlers/chatgpt.py b/handlers/chatgpt.py index f42d999..0b787f6 100644 --- a/handlers/chatgpt.py +++ b/handlers/chatgpt.py @@ -51,6 +51,7 @@ def chatgpt_handler(message: Message, bot: TeleBot) -> None: if m[:4].lower() == "new ": m = m[4:].strip() player_message.clear() + m = enrich_text_with_urls(m) who = "ChatGPT" # show something, make it more responsible @@ -112,6 +113,7 @@ def chatgpt_pro_handler(message: Message, bot: TeleBot) -> None: if m[:4].lower() == "new ": m = m[4:].strip() player_message.clear() + m = enrich_text_with_urls(m) who = "ChatGPT Pro" reply_id = bot_reply_first(message, who, bot) From 2abcc90a3234988950eb037433ab955c2e7d5cf6 Mon Sep 17 00:00:00 2001 From: F4ria Date: Wed, 17 Apr 2024 14:03:26 +0800 Subject: [PATCH 6/8] reduce code duplication and reuse image_to_data_uri --- handlers/__init__.py | 14 +++++++++++++- handlers/chatgpt.py | 10 ++-------- handlers/yi.py | 10 +--------- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/handlers/__init__.py b/handlers/__init__.py index 2356bfd..c875518 100644 --- a/handlers/__init__.py +++ b/handlers/__init__.py @@ -1,5 +1,6 @@ from __future__ import annotations +import base64 import importlib import re import traceback @@ -186,5 +187,16 @@ def enrich_text_with_urls(text: str) -> str: return text +def image_to_data_uri(file_path): + with open(file_path, "rb") as image_file: + encoded_image = base64.b64encode(image_file.read()).decode("utf-8") + return f"data:image/png;base64,{encoded_image}" + + # `import *` will give you these -__all__ = ["bot_reply_first", "bot_reply_markdown", "enrich_text_with_urls"] +__all__ = [ + "bot_reply_first", + "bot_reply_markdown", + "enrich_text_with_urls", + "image_to_data_uri", +] diff --git a/handlers/chatgpt.py b/handlers/chatgpt.py index 0b787f6..0cd8ae9 100644 --- a/handlers/chatgpt.py +++ b/handlers/chatgpt.py @@ -1,6 +1,4 @@ -import base64 from os import environ -from pathlib import Path import time from openai import OpenAI @@ -172,9 +170,7 @@ def chatgpt_photo_handler(message: Message, bot: TeleBot) -> None: downloaded_file = bot.download_file(file_path) with open("chatgpt_temp.jpg", "wb") as temp_file: temp_file.write(downloaded_file) - with open("chatgpt_temp.jpg", "rb") as image_file: - image_data = image_file.read() - base64_image_data = base64.b64encode(image_data).decode("utf-8") + try: r = client.chat.completions.create( max_tokens=1024, @@ -185,9 +181,7 @@ def chatgpt_photo_handler(message: Message, bot: TeleBot) -> None: {"type": "text", "text": prompt}, { "type": "image_url", - "image_url": { - "url": f"data:image/jpeg;base64,{base64_image_data}" - }, + "image_url": {"url": image_to_data_uri("chatgpt_temp.jpg")}, }, ], } diff --git a/handlers/yi.py b/handlers/yi.py index 684c0f2..bd3dbef 100644 --- a/handlers/yi.py +++ b/handlers/yi.py @@ -1,6 +1,4 @@ -import base64 from os import environ -from pathlib import Path from openai import OpenAI import requests @@ -88,12 +86,6 @@ def yi_handler(message: Message, bot: TeleBot) -> None: bot_reply_markdown(reply_id, who, yi_reply_text, bot) -def _image_to_data_uri(file_path): - with open(file_path, "rb") as image_file: - encoded_image = base64.b64encode(image_file.read()).decode("utf-8") - return f"data:image/png;base64,{encoded_image}" - - def yi_photo_handler(message: Message, bot: TeleBot) -> None: s = message.caption prompt = s.strip() @@ -121,7 +113,7 @@ def yi_photo_handler(message: Message, bot: TeleBot) -> None: {"type": "text", "text": prompt}, { "type": "image_url", - "image_url": {"url": _image_to_data_uri("yi_temp.jpg")}, + "image_url": {"url": image_to_data_uri("yi_temp.jpg")}, }, ], } From a48187e98c7f525b487e3f12e8c6200d620c1550 Mon Sep 17 00:00:00 2001 From: F4ria Date: Wed, 17 Apr 2024 14:10:22 +0800 Subject: [PATCH 7/8] increase max_tokens from 1024 to 2048 in chatgpt_photo_handler --- handlers/chatgpt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/handlers/chatgpt.py b/handlers/chatgpt.py index 0cd8ae9..5ed9e93 100644 --- a/handlers/chatgpt.py +++ b/handlers/chatgpt.py @@ -173,7 +173,7 @@ def chatgpt_photo_handler(message: Message, bot: TeleBot) -> None: try: r = client.chat.completions.create( - max_tokens=1024, + max_tokens=2048, messages=[ { "role": "user", From 0bfce8b3c0e9daf83c8ed304359b17a55a2ec650 Mon Sep 17 00:00:00 2001 From: F4ria Date: Wed, 17 Apr 2024 14:21:51 +0800 Subject: [PATCH 8/8] README: update the ChatGPT instructions --- README.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d352700..84c8a50 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,15 @@ Note, if you are using third party service, you need to `export ANTHROPIC_BASE_U ![image](https://github.com/yihong0618/tg_bot_collections/assets/15976103/11d96dde-447b-4b7e-886d-c3564e27b0d6) +## Bot -> ChatGPT + +1. visit https://platform.openai.com/account/api-keys get the key +2. export OPENAI_API_KEY=${the_key} +3. use `chatgpt: ${message}` to ask + +Note, if you are using third party service, you need to `export OPENAI_API_BASE=${the_url}` to change the url. + + ## HOW TO Install and Run ### Manually install @@ -58,7 +67,8 @@ Note, if you are using third party service, you need to `export ANTHROPIC_BASE_U `docker run -d --name tg_bot_collections -e ANTHROPIC_API_KEY='${ANTHROPIC_API_KEY}' -e TELEGRAM_BOT_TOKEN='${TELEGRAM_BOT_TOKEN}' --network host tg_bot_collections` #### Run lingyiwanwu `docker run -d --name tg_bot_collections -e YI_API_KEY='${YI_API_KEY}' -e YI_BASE_URL='${YI_BASE_URL}' -e TELEGRAM_BOT_TOKEN='${TELEGRAM_BOT_TOKEN}' --network host tg_bot_collections` - +#### Run ChatGPT +`docker run -d --name tg_bot_collections -e OPENAI_API_KEY='${CHATGPT_API_KEY}' -e TELEGRAM_BOT_TOKEN='${TELEGRAM_BOT_TOKEN}' --network host tg_bot_collections` ### Run as shell @@ -86,6 +96,7 @@ Note, this may break your system config -> check this https://github.com/yihong0 - Gemini use -> https://github.com/google/generative-ai-python - Telegram markdownV2 change code copy from https://github.com/yym68686/md2tgmd/blob/main/src/md2tgmd.py thanks a lot. - Telegram markdownV2 change to telegramify-markdown +- ChatGPT use -> https://github.com/openai/openai-python ## Appreciation