mirror of
https://github.com/aljazceru/chatgpt-telegram-bot.git
synced 2025-12-18 13:14:59 +01:00
Merge branch 'main' into gpt-4o
This commit is contained in:
@@ -64,7 +64,7 @@ def main():
|
|||||||
|
|
||||||
if openai_config['enable_functions'] and not functions_available:
|
if openai_config['enable_functions'] and not functions_available:
|
||||||
logging.error(f'ENABLE_FUNCTIONS is set to true, but the model {model} does not support it. '
|
logging.error(f'ENABLE_FUNCTIONS is set to true, but the model {model} does not support it. '
|
||||||
f'Please set ENABLE_FUNCTIONS to false or use a model that supports it.')
|
'Please set ENABLE_FUNCTIONS to false or use a model that supports it.')
|
||||||
exit(1)
|
exit(1)
|
||||||
if os.environ.get('MONTHLY_USER_BUDGETS') is not None:
|
if os.environ.get('MONTHLY_USER_BUDGETS') is not None:
|
||||||
logging.warning('The environment variable MONTHLY_USER_BUDGETS is deprecated. '
|
logging.warning('The environment variable MONTHLY_USER_BUDGETS is deprecated. '
|
||||||
|
|||||||
@@ -24,14 +24,13 @@ from plugin_manager import PluginManager
|
|||||||
# Models gpt-3.5-turbo-0613 and gpt-3.5-turbo-16k-0613 will be deprecated on June 13, 2024
|
# Models gpt-3.5-turbo-0613 and gpt-3.5-turbo-16k-0613 will be deprecated on June 13, 2024
|
||||||
GPT_3_MODELS = ("gpt-3.5-turbo", "gpt-3.5-turbo-0301", "gpt-3.5-turbo-0613")
|
GPT_3_MODELS = ("gpt-3.5-turbo", "gpt-3.5-turbo-0301", "gpt-3.5-turbo-0613")
|
||||||
GPT_3_16K_MODELS = ("gpt-3.5-turbo-16k", "gpt-3.5-turbo-16k-0613", "gpt-3.5-turbo-1106", "gpt-3.5-turbo-0125")
|
GPT_3_16K_MODELS = ("gpt-3.5-turbo-16k", "gpt-3.5-turbo-16k-0613", "gpt-3.5-turbo-1106", "gpt-3.5-turbo-0125")
|
||||||
GPT_4_MODELS = ("gpt-4", "gpt-4-0314", "gpt-4-0613")
|
GPT_4_MODELS = ("gpt-4", "gpt-4-0314", "gpt-4-0613", "gpt-4-turbo-preview")
|
||||||
GPT_4_32K_MODELS = ("gpt-4-32k", "gpt-4-32k-0314", "gpt-4-32k-0613")
|
GPT_4_32K_MODELS = ("gpt-4-32k", "gpt-4-32k-0314", "gpt-4-32k-0613")
|
||||||
GPT_4_VISION_MODELS = ("gpt-4-vision-preview",)
|
GPT_4_VISION_MODELS = ("gpt-4-vision-preview",)
|
||||||
GPT_4_128K_MODELS = ("gpt-4-1106-preview","gpt-4-0125-preview","gpt-4-turbo-preview")
|
GPT_4_128K_MODELS = ("gpt-4-1106-preview","gpt-4-0125-preview","gpt-4-turbo-preview", "gpt-4-turbo", "gpt-4-turbo-2024-04-09")
|
||||||
GPT_4O_MODELS = ("gpt-4o",)
|
GPT_4O_MODELS = ("gpt-4o",)
|
||||||
GPT_ALL_MODELS = GPT_3_MODELS + GPT_3_16K_MODELS + GPT_4_MODELS + GPT_4_32K_MODELS + GPT_4_VISION_MODELS + GPT_4_128K_MODELS + GPT_4O_MODELS
|
GPT_ALL_MODELS = GPT_3_MODELS + GPT_3_16K_MODELS + GPT_4_MODELS + GPT_4_32K_MODELS + GPT_4_VISION_MODELS + GPT_4_128K_MODELS + GPT_4O_MODELS
|
||||||
|
|
||||||
|
|
||||||
def default_max_tokens(model: str) -> int:
|
def default_max_tokens(model: str) -> int:
|
||||||
"""
|
"""
|
||||||
Gets the default number of max tokens for the given model.
|
Gets the default number of max tokens for the given model.
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ from plugins.deepl import DeeplTranslatePlugin
|
|||||||
from plugins.worldtimeapi import WorldTimeApiPlugin
|
from plugins.worldtimeapi import WorldTimeApiPlugin
|
||||||
from plugins.whois_ import WhoisPlugin
|
from plugins.whois_ import WhoisPlugin
|
||||||
from plugins.webshot import WebshotPlugin
|
from plugins.webshot import WebshotPlugin
|
||||||
|
from plugins.iplocation import IpLocationPlugin
|
||||||
|
|
||||||
|
|
||||||
class PluginManager:
|
class PluginManager:
|
||||||
@@ -40,6 +41,7 @@ class PluginManager:
|
|||||||
'auto_tts': AutoTextToSpeech,
|
'auto_tts': AutoTextToSpeech,
|
||||||
'whois': WhoisPlugin,
|
'whois': WhoisPlugin,
|
||||||
'webshot': WebshotPlugin,
|
'webshot': WebshotPlugin,
|
||||||
|
'iplocation': IpLocationPlugin,
|
||||||
}
|
}
|
||||||
self.plugins = [plugin_mapping[plugin]() for plugin in enabled_plugins if plugin in plugin_mapping]
|
self.plugins = [plugin_mapping[plugin]() for plugin in enabled_plugins if plugin in plugin_mapping]
|
||||||
|
|
||||||
@@ -69,4 +71,4 @@ class PluginManager:
|
|||||||
|
|
||||||
def __get_plugin_by_function_name(self, function_name):
|
def __get_plugin_by_function_name(self, function_name):
|
||||||
return next((plugin for plugin in self.plugins
|
return next((plugin for plugin in self.plugins
|
||||||
if function_name in map(lambda spec: spec.get('name'), plugin.get_spec())), None)
|
if function_name in map(lambda spec: spec.get('name'), plugin.get_spec())), None)
|
||||||
|
|||||||
44
bot/plugins/iplocation.py
Normal file
44
bot/plugins/iplocation.py
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import requests
|
||||||
|
from typing import Dict
|
||||||
|
|
||||||
|
from .plugin import Plugin
|
||||||
|
|
||||||
|
class IpLocationPlugin(Plugin):
|
||||||
|
"""
|
||||||
|
A plugin to get geolocation and other information for a given IP address
|
||||||
|
"""
|
||||||
|
|
||||||
|
def get_source_name(self) -> str:
|
||||||
|
return "IP.FM"
|
||||||
|
|
||||||
|
def get_spec(self) -> [Dict]:
|
||||||
|
return [{
|
||||||
|
"name": "iplocaion",
|
||||||
|
"description": "Get information for an IP address using the IP.FM API.",
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"ip": {"type": "string", "description": "IP Address"}
|
||||||
|
},
|
||||||
|
"required": ["ip"],
|
||||||
|
},
|
||||||
|
}]
|
||||||
|
|
||||||
|
async def execute(self, function_name, helper, **kwargs) -> Dict:
|
||||||
|
ip = kwargs.get('ip')
|
||||||
|
BASE_URL = "https://api.ip.fm/?ip={}"
|
||||||
|
url = BASE_URL.format(ip)
|
||||||
|
try:
|
||||||
|
response = requests.get(url)
|
||||||
|
response_data = response.json()
|
||||||
|
country = response_data.get('data', {}).get('country', "None")
|
||||||
|
subdivisions = response_data.get('data', {}).get('subdivisions', "None")
|
||||||
|
city = response_data.get('data', {}).get('city', "None")
|
||||||
|
location = ', '.join(filter(None, [country, subdivisions, city])) or "None"
|
||||||
|
|
||||||
|
asn = response_data.get('data', {}).get('asn', "None")
|
||||||
|
as_name = response_data.get('data', {}).get('as_name', "None")
|
||||||
|
as_domain = response_data.get('data', {}).get('as_domain', "None")
|
||||||
|
return {"Location": location, "ASN": asn, "AS Name": as_name, "AS Domain": as_domain}
|
||||||
|
except Exception as e:
|
||||||
|
return {"Error": str(e)}
|
||||||
@@ -58,7 +58,7 @@ class WeatherPlugin(Plugin):
|
|||||||
]
|
]
|
||||||
|
|
||||||
async def execute(self, function_name, helper, **kwargs) -> Dict:
|
async def execute(self, function_name, helper, **kwargs) -> Dict:
|
||||||
url = f'https://api.open-meteo.com/v1/forecast' \
|
url = 'https://api.open-meteo.com/v1/forecast' \
|
||||||
f'?latitude={kwargs["latitude"]}' \
|
f'?latitude={kwargs["latitude"]}' \
|
||||||
f'&longitude={kwargs["longitude"]}' \
|
f'&longitude={kwargs["longitude"]}' \
|
||||||
f'&temperature_unit={kwargs["unit"]}'
|
f'&temperature_unit={kwargs["unit"]}'
|
||||||
|
|||||||
@@ -21,13 +21,13 @@ class WorldTimeApiPlugin(Plugin):
|
|||||||
def get_spec(self) -> [Dict]:
|
def get_spec(self) -> [Dict]:
|
||||||
return [{
|
return [{
|
||||||
"name": "worldtimeapi",
|
"name": "worldtimeapi",
|
||||||
"description": f"Get the current time from a given timezone",
|
"description": "Get the current time from a given timezone",
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"timezone": {
|
"timezone": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": f"The timezone identifier (e.g: `Europe/Rome`). Infer this from the location."
|
"description": "The timezone identifier (e.g: `Europe/Rome`). Infer this from the location."
|
||||||
f"Use {self.default_timezone} if not specified."
|
f"Use {self.default_timezone} if not specified."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -84,12 +84,12 @@ class ChatGPTTelegramBot:
|
|||||||
"""
|
"""
|
||||||
if not await is_allowed(self.config, update, context):
|
if not await is_allowed(self.config, update, context):
|
||||||
logging.warning(f'User {update.message.from_user.name} (id: {update.message.from_user.id}) '
|
logging.warning(f'User {update.message.from_user.name} (id: {update.message.from_user.id}) '
|
||||||
f'is not allowed to request their usage statistics')
|
'is not allowed to request their usage statistics')
|
||||||
await self.send_disallowed_message(update, context)
|
await self.send_disallowed_message(update, context)
|
||||||
return
|
return
|
||||||
|
|
||||||
logging.info(f'User {update.message.from_user.name} (id: {update.message.from_user.id}) '
|
logging.info(f'User {update.message.from_user.name} (id: {update.message.from_user.id}) '
|
||||||
f'requested their usage statistics')
|
'requested their usage statistics')
|
||||||
|
|
||||||
user_id = update.message.from_user.id
|
user_id = update.message.from_user.id
|
||||||
if user_id not in self.usage:
|
if user_id not in self.usage:
|
||||||
@@ -112,7 +112,7 @@ class ChatGPTTelegramBot:
|
|||||||
f"*{localized_text('stats_conversation', bot_language)[0]}*:\n"
|
f"*{localized_text('stats_conversation', bot_language)[0]}*:\n"
|
||||||
f"{chat_messages} {localized_text('stats_conversation', bot_language)[1]}\n"
|
f"{chat_messages} {localized_text('stats_conversation', bot_language)[1]}\n"
|
||||||
f"{chat_token_length} {localized_text('stats_conversation', bot_language)[2]}\n"
|
f"{chat_token_length} {localized_text('stats_conversation', bot_language)[2]}\n"
|
||||||
f"----------------------------\n"
|
"----------------------------\n"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Check if image generation is enabled and, if so, generate the image statistics for today
|
# Check if image generation is enabled and, if so, generate the image statistics for today
|
||||||
@@ -137,7 +137,7 @@ class ChatGPTTelegramBot:
|
|||||||
f"{transcribe_minutes_today} {localized_text('stats_transcribe', bot_language)[0]} "
|
f"{transcribe_minutes_today} {localized_text('stats_transcribe', bot_language)[0]} "
|
||||||
f"{transcribe_seconds_today} {localized_text('stats_transcribe', bot_language)[1]}\n"
|
f"{transcribe_seconds_today} {localized_text('stats_transcribe', bot_language)[1]}\n"
|
||||||
f"{localized_text('stats_total', bot_language)}{current_cost['cost_today']:.2f}\n"
|
f"{localized_text('stats_total', bot_language)}{current_cost['cost_today']:.2f}\n"
|
||||||
f"----------------------------\n"
|
"----------------------------\n"
|
||||||
)
|
)
|
||||||
|
|
||||||
text_month_images = ""
|
text_month_images = ""
|
||||||
@@ -190,14 +190,14 @@ class ChatGPTTelegramBot:
|
|||||||
"""
|
"""
|
||||||
if not await is_allowed(self.config, update, context):
|
if not await is_allowed(self.config, update, context):
|
||||||
logging.warning(f'User {update.message.from_user.name} (id: {update.message.from_user.id})'
|
logging.warning(f'User {update.message.from_user.name} (id: {update.message.from_user.id})'
|
||||||
f' is not allowed to resend the message')
|
' is not allowed to resend the message')
|
||||||
await self.send_disallowed_message(update, context)
|
await self.send_disallowed_message(update, context)
|
||||||
return
|
return
|
||||||
|
|
||||||
chat_id = update.effective_chat.id
|
chat_id = update.effective_chat.id
|
||||||
if chat_id not in self.last_message:
|
if chat_id not in self.last_message:
|
||||||
logging.warning(f'User {update.message.from_user.name} (id: {update.message.from_user.id})'
|
logging.warning(f'User {update.message.from_user.name} (id: {update.message.from_user.id})'
|
||||||
f' does not have anything to resend')
|
' does not have anything to resend')
|
||||||
await update.effective_message.reply_text(
|
await update.effective_message.reply_text(
|
||||||
message_thread_id=get_thread_id(update),
|
message_thread_id=get_thread_id(update),
|
||||||
text=localized_text('resend_failed', self.config['bot_language'])
|
text=localized_text('resend_failed', self.config['bot_language'])
|
||||||
@@ -218,7 +218,7 @@ class ChatGPTTelegramBot:
|
|||||||
"""
|
"""
|
||||||
if not await is_allowed(self.config, update, context):
|
if not await is_allowed(self.config, update, context):
|
||||||
logging.warning(f'User {update.message.from_user.name} (id: {update.message.from_user.id}) '
|
logging.warning(f'User {update.message.from_user.name} (id: {update.message.from_user.id}) '
|
||||||
f'is not allowed to reset the conversation')
|
'is not allowed to reset the conversation')
|
||||||
await self.send_disallowed_message(update, context)
|
await self.send_disallowed_message(update, context)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -339,7 +339,7 @@ class ChatGPTTelegramBot:
|
|||||||
return
|
return
|
||||||
|
|
||||||
if is_group_chat(update) and self.config['ignore_group_transcriptions']:
|
if is_group_chat(update) and self.config['ignore_group_transcriptions']:
|
||||||
logging.info(f'Transcription coming from group chat, ignoring...')
|
logging.info('Transcription coming from group chat, ignoring...')
|
||||||
return
|
return
|
||||||
|
|
||||||
chat_id = update.effective_chat.id
|
chat_id = update.effective_chat.id
|
||||||
@@ -463,13 +463,13 @@ class ChatGPTTelegramBot:
|
|||||||
|
|
||||||
if is_group_chat(update):
|
if is_group_chat(update):
|
||||||
if self.config['ignore_group_vision']:
|
if self.config['ignore_group_vision']:
|
||||||
logging.info(f'Vision coming from group chat, ignoring...')
|
logging.info('Vision coming from group chat, ignoring...')
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
trigger_keyword = self.config['group_trigger_keyword']
|
trigger_keyword = self.config['group_trigger_keyword']
|
||||||
if (prompt is None and trigger_keyword != '') or \
|
if (prompt is None and trigger_keyword != '') or \
|
||||||
(prompt is not None and not prompt.lower().startswith(trigger_keyword.lower())):
|
(prompt is not None and not prompt.lower().startswith(trigger_keyword.lower())):
|
||||||
logging.info(f'Vision coming from group chat with wrong keyword, ignoring...')
|
logging.info('Vision coming from group chat with wrong keyword, ignoring...')
|
||||||
return
|
return
|
||||||
|
|
||||||
image = update.message.effective_attachment[-1]
|
image = update.message.effective_attachment[-1]
|
||||||
|
|||||||
@@ -293,6 +293,55 @@
|
|||||||
"loading":"Lataa...",
|
"loading":"Lataa...",
|
||||||
"function_unavailable_in_inline_mode": "Tämä toiminto ei ole käytettävissä sisäisessä tilassa"
|
"function_unavailable_in_inline_mode": "Tämä toiminto ei ole käytettävissä sisäisessä tilassa"
|
||||||
},
|
},
|
||||||
|
"he": {
|
||||||
|
"help_description": "הצג הודעת עזרה",
|
||||||
|
"reset_description": "אתחל את השיחה. ניתן להעביר הוראות ברמה גבוהה (למשל, /reset אתה עוזר מועיל)",
|
||||||
|
"image_description": "צור תמונה מהפרומפט (למשל, /image חתול)",
|
||||||
|
"tts_description": "צור דיבור מטקסט (למשל, /tts הבית שלי)",
|
||||||
|
"stats_description": "קבל את סטטיסטיקות השימוש הנוכחיות שלך",
|
||||||
|
"resend_description": "שלח מחדש את ההודעה האחרונה",
|
||||||
|
"chat_description": "שוחח עם הבוט!",
|
||||||
|
"disallowed": "מצטערים, אינך מורשה להשתמש בבוט זה. תוכל לבדוק את הקוד המקור ב https://github.com/n3d1117/chatgpt-telegram-bot",
|
||||||
|
"budget_limit": "מצטערים, הגעת למגבלת השימוש שלך.",
|
||||||
|
"help_text": ["אני בוט של ChatGPT, דבר איתי!", "שלח לי הודעה קולית או קובץ ואני אתרגם אותו בשבילך", "קוד פתוח ב https://github.com/n3d1117/chatgpt-telegram-bot"],
|
||||||
|
"stats_conversation": ["שיחה נוכחית", "הודעות צ'אט בהיסטוריה", "אסימוני צ'אט בהיסטוריה"],
|
||||||
|
"usage_today": "שימוש היום",
|
||||||
|
"usage_month": "שימוש החודש",
|
||||||
|
"stats_tokens": "אסימונים",
|
||||||
|
"stats_images": "תמונות שנוצרו",
|
||||||
|
"stats_vision": "אסימוני תמונה שפורשו",
|
||||||
|
"stats_tts": "תווים שהומרו לדיבור",
|
||||||
|
"stats_transcribe": ["דקות ו", "שניות שהוקלטו"],
|
||||||
|
"stats_total": "💰 לסך כל של $",
|
||||||
|
"stats_budget": "התקציב הנותר שלך",
|
||||||
|
"monthly": " לחודש זה",
|
||||||
|
"daily": " להיום",
|
||||||
|
"all-time": "",
|
||||||
|
"stats_openai": "החשבון שלך ב-OpenAI חויב החודש ב-$",
|
||||||
|
"resend_failed": "אין לך מה לשלוח מחדש",
|
||||||
|
"reset_done": "בוצע!",
|
||||||
|
"image_no_prompt": "נא לספק פרומפט! (למשל, /image חתול)",
|
||||||
|
"image_fail": "נכשל ביצירת התמונה",
|
||||||
|
"vision_fail": "נכשל בפרשנות התמונה",
|
||||||
|
"tts_no_prompt": "נא לספק טקסט! (למשל, /tts הבית שלי)",
|
||||||
|
"tts_fail": "נכשל ביצירת הדיבור",
|
||||||
|
"media_download_fail": ["נכשל בהורדת קובץ השמע", "ודא שהקובץ אינו גדול מדי. (מקסימום 20MB)"],
|
||||||
|
"media_type_fail": "סוג קובץ לא נתמך",
|
||||||
|
"transcript": "תמליל",
|
||||||
|
"answer": "תשובה",
|
||||||
|
"transcribe_fail": "נכשל בתרגום הטקסט",
|
||||||
|
"chat_fail": "נכשל בקבלת תגובה",
|
||||||
|
"prompt": "פרומפט",
|
||||||
|
"completion": "השלמה",
|
||||||
|
"openai_rate_limit": "חריגה מהגבלת השימוש של OpenAI",
|
||||||
|
"openai_invalid": "בקשה לא חוקית של OpenAI",
|
||||||
|
"error": "אירעה שגיאה",
|
||||||
|
"try_again": "נא לנסות שוב מאוחר יותר",
|
||||||
|
"answer_with_chatgpt": "ענה באמצעות ChatGPT",
|
||||||
|
"ask_chatgpt": "שאל את ChatGPT",
|
||||||
|
"loading": "טוען...",
|
||||||
|
"function_unavailable_in_inline_mode": "הפונקציה לא זמינה במצב inline"
|
||||||
|
}
|
||||||
"id": {
|
"id": {
|
||||||
"help_description": "Menampilkan pesan bantuan",
|
"help_description": "Menampilkan pesan bantuan",
|
||||||
"reset_description": "Merestart percakapan. Opsional memasukkan instruksi tingkat tinggi (misalnya /reset Anda adalah asisten yang membantu)",
|
"reset_description": "Merestart percakapan. Opsional memasukkan instruksi tingkat tinggi (misalnya /reset Anda adalah asisten yang membantu)",
|
||||||
|
|||||||
Reference in New Issue
Block a user