Merge branch 'main' into vision-support

This commit is contained in:
gilcu3
2023-11-18 17:55:53 +01:00
8 changed files with 348 additions and 49 deletions

View File

@@ -20,10 +20,12 @@ ALLOWED_TELEGRAM_USER_IDS=USER_ID_1,USER_ID_2
# VISION_TOKEN_PRICE=0.01
# ENABLE_QUOTING=true
# ENABLE_IMAGE_GENERATION=true
# ENABLE_TTS_GENERATION=true
# ENABLE_TRANSCRIPTION=true
# ENABLE_VISION=true
# PROXY=http://localhost:8080
# OPENAI_MODEL=gpt-3.5-turbo
# OPENAI_BASE_URL=https://example.com/v1/
# ASSISTANT_PROMPT="You are a helpful assistant."
# SHOW_USAGE=false
# STREAM=true
@@ -38,9 +40,15 @@ ALLOWED_TELEGRAM_USER_IDS=USER_ID_1,USER_ID_2
# TEMPERATURE=1.0
# PRESENCE_PENALTY=0.0
# FREQUENCY_PENALTY=0.0
# IMAGE_SIZE=512x512
# IMAGE_MODEL=dall-e-3
# IMAGE_QUALITY=hd
# IMAGE_STYLE=natural
# IMAGE_SIZE=1024x1024
# IMAGE_FORMAT=document
# VISION_DETAIL="low"
# GROUP_TRIGGER_KEYWORD=""
# IGNORE_GROUP_TRANSCRIPTIONS=true
# IGNORE_GROUP_VISION=true
# TTS_MODEL="tts-1"
# TTS_VOICE="alloy"
# BOT_LANGUAGE=en

View File

@@ -30,12 +30,15 @@ A [Telegram bot](https://core.telegram.org/bots/api) that integrates with OpenAI
- [x] GPT-4 support
- If you have access to the GPT-4 API, simply change the `OPENAI_MODEL` parameter to `gpt-4`
- [x] Localized bot language
- Available languages :gb: :de: :ru: :tr: :it: :finland: :es: :indonesia: :netherlands: :cn: :taiwan: :vietnam: :iran: :brazil: :ukraine: :malaysia:
- Available languages :gb: :de: :ru: :tr: :it: :finland: :es: :indonesia: :netherlands: :cn: :taiwan: :vietnam: :iran: :brazil: :ukraine: :malaysia: :uzbekistan:
- [x] Improved inline queries support for group and private chats - by [@bugfloyd](https://github.com/bugfloyd)
- To use this feature, enable inline queries for your bot in BotFather via the `/setinline` [command](https://core.telegram.org/bots/inline)
- [x] (NEW!) Support *new models* [announced on June 13, 2023](https://openai.com/blog/function-calling-and-other-api-updates)
- [x] (NEW!) Support *functions* (plugins) to extend the bot's functionality with 3rd party services
- [x] Support *new models* [announced on June 13, 2023](https://openai.com/blog/function-calling-and-other-api-updates)
- [x] Support *functions* (plugins) to extend the bot's functionality with 3rd party services
- Weather, Spotify, Web search, text-to-speech and more. See [here](#available-plugins) for a list of available plugins
- [x] Support unofficial OpenAI-compatible APIs - by [@kristaller486](https://github.com/kristaller486)
- [x] (NEW!) Support GPT-4 Turbo and DALL·E 3 [announced on November 6, 2023](https://openai.com/blog/new-models-and-developer-products-announced-at-devday) - by [@AlexHTW](https://github.com/AlexHTW)
- [x] (NEW!) Text-to-speech support [announced on November 6, 2023](https://platform.openai.com/docs/guides/text-to-speech) - by [@gilcu3](https://github.com/gilcu3)
## Additional features - help needed!
If you'd like to help, check out the [issues](https://github.com/n3d1117/chatgpt-telegram-bot/issues) section and contribute!
@@ -78,13 +81,15 @@ Check out the [Budget Manual](https://github.com/n3d1117/chatgpt-telegram-bot/di
#### Additional optional configuration options
| Parameter | Description | Default value |
|------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------|
|------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------|
| `ENABLE_QUOTING` | Whether to enable message quoting in private chats | `true` |
| `ENABLE_IMAGE_GENERATION` | Whether to enable image generation via the `/image` command | `true` |
| `ENABLE_TRANSCRIPTION` | Whether to enable transcriptions of audio and video messages | `true` |
| `ENABLE_TTS_GENERATION` | Whether to enable text to speech generation via the `/tts` | `true` |
| `ENABLE_VISION` | Whether to enable vision capabilities in supported models | `true` |
| `PROXY` | Proxy to be used for OpenAI and Telegram bot (e.g. `http://localhost:8080`) | - |
| `OPENAI_MODEL` | The OpenAI model to use for generating responses. You can find all available models [here](https://platform.openai.com/docs/models/) | `gpt-3.5-turbo` |
| `OPENAI_BASE_URL` | Endpoint URL for unofficial OpenAI-compatible APIs (e.g., LocalAI or text-generation-webui) | Default OpenAI API URL |
| `ASSISTANT_PROMPT` | A system message that sets the tone and controls the behavior of the assistant | `You are a helpful assistant.` |
| `SHOW_USAGE` | Whether to show OpenAI token usage information after each response | `false` |
| `STREAM` | Whether to stream responses. **Note**: incompatible, if enabled, with `N_CHOICES` higher than 1 | `true` |
@@ -99,13 +104,19 @@ Check out the [Budget Manual](https://github.com/n3d1117/chatgpt-telegram-bot/di
| `TEMPERATURE` | Number between 0 and 2. Higher values will make the output more random | `1.0` |
| `PRESENCE_PENALTY` | Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far | `0.0` |
| `FREQUENCY_PENALTY` | Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far | `0.0` |
| `IMAGE_SIZE` | The DALL·E generated image size. Allowed values: `256x256`, `512x512` or `1024x1024` | `512x512` |
| `IMAGE_FORMAT` | The Telegram image receive mode. Allowed values: `document` or `photo` | `photo` |
| `IMAGE_MODEL` | The DALL·E model to be used. Available models: `dall-e-2` and `dall-e-3`, find current available models [here](https://platform.openai.com/docs/models/dall-e) | `dall-e-2` |
| `IMAGE_QUALITY` | Quality of DALL·E images, only available for `dall-e-3`-model. Possible options: `standard` or `hd`, beware of [pricing differences](https://openai.com/pricing#image-models). | `standard` |
| `IMAGE_STYLE` | Style for DALL·E image generation, only available for `dall-e-3`-model. Possible options: `vivid` or `natural`. Check availbe styles [here](https://platform.openai.com/docs/api-reference/images/create). | `vivid` |
| `IMAGE_SIZE` | The DALL·E generated image size. Must be `256x256`, `512x512`, or `1024x1024` for dall-e-2. Must be `1024x1024` for dall-e-3 models. | `512x512` |
| `VISION_DETAIL` | The detail parameter for vision models, explained [Vision Guide](https://platform.openai.com/docs/guides/vision). Allowed values: `low` or `high` | `low` |
| `GROUP_TRIGGER_KEYWORD` | If set, the bot in group chats will only respond to messages that start with this keyword | - |
| `IGNORE_GROUP_TRANSCRIPTIONS` | If set to true, the bot will not process transcriptions in group chats | `true` |
| `IGNORE_GROUP_VISION` | If set to true, the bot will not process vision queries in group chats | `true` |
| `BOT_LANGUAGE` | Language of general bot messages. Currently available: `en`, `de`, `ru`, `tr`, `it`, `fi`, `es`, `id`, `nl`, `zh-cn`, `zh-tw`, `vi`, `fa`, `pt-br`, `uk`, `ms`. [Contribute with additional translations](https://github.com/n3d1117/chatgpt-telegram-bot/discussions/219) | `en` |
| `BOT_LANGUAGE` | Language of general bot messages. Currently available: `en`, `de`, `ru`, `tr`, `it`, `fi`, `es`, `id`, `nl`, `zh-cn`, `zh-tw`, `vi`, `fa`, `pt-br`, `uk`, `ms`, `uz`. [Contribute with additional translations](https://github.com/n3d1117/chatgpt-telegram-bot/discussions/219) | `en` |
| `WHISPER_PROMPT` | To improve the accuracy of Whisper's transcription service, especially for specific names or terms, you can set up a custom message. [Speech to text - Prompting](https://platform.openai.com/docs/guides/speech-to-text/prompting) | `-` |
| `TTS_VOICE` | The Text to Speech voice to use. Allowed values: `alloy`, `echo`, `fable`, `onyx`, `nova`, or `shimmer` | `alloy` |
| `TTS_MODEL` | The Text to Speech model to use. Allowed values: `tts-1` or `tts-1-hd` | `tts-1` |
Check out the [official API reference](https://platform.openai.com/docs/api-reference/chat) for more details.

View File

@@ -41,6 +41,9 @@ def main():
'max_tokens': int(os.environ.get('MAX_TOKENS', max_tokens_default)),
'n_choices': int(os.environ.get('N_CHOICES', 1)),
'temperature': float(os.environ.get('TEMPERATURE', 1.0)),
'image_model': os.environ.get('IMAGE_MODEL', 'dall-e-2'),
'image_quality': os.environ.get('IMAGE_QUALITY', 'standard'),
'image_style': os.environ.get('IMAGE_STYLE', 'vivid'),
'image_size': os.environ.get('IMAGE_SIZE', '512x512'),
'model': model,
'enable_functions': os.environ.get('ENABLE_FUNCTIONS', str(functions_available)).lower() == 'true',
@@ -53,6 +56,8 @@ def main():
'vision_prompt': os.environ.get('VISION_PROMPT', 'What is in this image'),
'vision_detail': os.environ.get('VISION_DETAIL', 'low'),
'vision_max_tokens': int(os.environ.get('VISION_MAX_TOKENS', '300')),
'tts_model': os.environ.get('TTS_MODEL', 'tts-1'),
'tts_voice': os.environ.get('TTS_VOICE', 'alloy'),
}
if openai_config['enable_functions'] and not functions_available:
@@ -74,6 +79,7 @@ def main():
'enable_image_generation': os.environ.get('ENABLE_IMAGE_GENERATION', 'true').lower() == 'true',
'enable_transcription': os.environ.get('ENABLE_TRANSCRIPTION', 'true').lower() == 'true',
'enable_vision': os.environ.get('ENABLE_VISION', 'true').lower() == 'true',
'enable_tts_generation': os.environ.get('ENABLE_TTS_GENERATION', 'true').lower() == 'true',
'budget_period': os.environ.get('BUDGET_PERIOD', 'monthly').lower(),
'user_budgets': os.environ.get('USER_BUDGETS', os.environ.get('MONTHLY_USER_BUDGETS', '*')),
'guest_budget': float(os.environ.get('GUEST_BUDGET', os.environ.get('MONTHLY_GUEST_BUDGET', '100.0'))),
@@ -87,6 +93,9 @@ def main():
'token_price': float(os.environ.get('TOKEN_PRICE', 0.002)),
'image_prices': [float(i) for i in os.environ.get('IMAGE_PRICES', "0.016,0.018,0.02").split(",")],
'vision_token_price': float(os.environ.get('VISION_TOKEN_PRICE', '0.01')),
'image_receive_mode': os.environ.get('IMAGE_FORMAT', "photo"),
'tts_model': os.environ.get('TTS_MODEL', 'tts-1'),
'tts_prices': [float(i) for i in os.environ.get('TTS_PRICES', "0.015,0.030").split(",")],
'transcription_price': float(os.environ.get('TRANSCRIPTION_PRICE', 0.006)),
'bot_language': os.environ.get('BOT_LANGUAGE', 'en'),
}

View File

@@ -10,6 +10,7 @@ import openai
import requests
import json
import httpx
import io
from datetime import date
from calendar import monthrange
from PIL import Image
@@ -21,11 +22,12 @@ from plugin_manager import PluginManager
# Models can be found here: https://platform.openai.com/docs/models/overview
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_16K_MODELS = ("gpt-3.5-turbo-16k", "gpt-3.5-turbo-16k-0613", "gpt-3.5-turbo-1106")
GPT_4_MODELS = ("gpt-4", "gpt-4-0314", "gpt-4-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_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-4-1106-preview",)
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
def default_max_tokens(model: str) -> int:
@@ -40,11 +42,15 @@ def default_max_tokens(model: str) -> int:
elif model in GPT_4_MODELS:
return base * 2
elif model in GPT_3_16K_MODELS:
if model == "gpt-3.5-turbo-1106":
return 4096
return base * 4
elif model in GPT_4_32K_MODELS:
return base * 8
elif model in GPT_4_VISION_MODELS:
return 4096
elif model in GPT_4_128K_MODELS:
return 4096
def are_functions_available(model: str) -> bool:
@@ -55,7 +61,7 @@ def are_functions_available(model: str) -> bool:
if model in ("gpt-3.5-turbo-0301", "gpt-4-0314", "gpt-4-32k-0314"):
return False
# Stable models will be updated to support functions on June 27, 2023
if model in ("gpt-3.5-turbo", "gpt-4", "gpt-4-32k"):
if model in ("gpt-3.5-turbo", "gpt-3.5-turbo-1106", "gpt-4", "gpt-4-32k","gpt-4-1106-preview"):
return datetime.date.today() > datetime.date(2023, 6, 27)
if model == 'gpt-4-vision-preview':
return False
@@ -326,6 +332,9 @@ class OpenAIHelper:
response = await self.client.images.generate(
prompt=prompt,
n=1,
model=self.config['image_model'],
quality=self.config['image_quality'],
style=self.config['image_style'],
size=self.config['image_size']
)
@@ -340,6 +349,28 @@ class OpenAIHelper:
except Exception as e:
raise Exception(f"⚠️ _{localized_text('error', bot_language)}._ ⚠️\n{str(e)}") from e
async def generate_speech(self, text: str) -> tuple[any, int]:
"""
Generates an audio from the given text using TTS model.
:param prompt: The text to send to the model
:return: The audio in bytes and the text size
"""
bot_language = self.config['bot_language']
try:
response = await self.client.audio.speech.create(
model=self.config['tts_model'],
voice=self.config['tts_voice'],
input=text,
response_format='opus'
)
temp_file = io.BytesIO()
temp_file.write(response.read())
temp_file.seek(0)
return temp_file, len(text)
except Exception as e:
raise Exception(f"⚠️ _{localized_text('error', bot_language)}._ ⚠️\n{str(e)}") from e
async def transcribe(self, filename):
"""
Transcribes the audio file using the Whisper model.
@@ -372,7 +403,7 @@ class OpenAIHelper:
message = {'role':'user', 'content':[{'type':'text', 'text':prompt}, {'type':'image_url', \
'image_url': {'url':f'data:image/jpeg;base64,{image}', 'detail':self.config['vision_detail'] } }]}
common_args = {
'model': self.config['model'],
'model': 'gpt-4-vision-preview', # the only one that currently makes sense here
'messages': self.conversations[chat_id] + [message],
'temperature': self.config['temperature'],
'n': 1, # several choices is not implemented yet
@@ -451,7 +482,7 @@ class OpenAIHelper:
messages=messages,
temperature=0.4
)
return response.choices[0]['message']['content']
return response.choices[0].message.content
def __max_model_tokens(self):
base = 4096
@@ -465,6 +496,8 @@ class OpenAIHelper:
return base * 8
if self.config['model'] in GPT_4_VISION_MODELS:
return base * 31
if self.config['model'] in GPT_4_128K_MODELS:
return base * 31
raise NotImplementedError(
f"Max tokens for model {self.config['model']} is not implemented yet."
)
@@ -485,7 +518,7 @@ class OpenAIHelper:
if model in GPT_3_MODELS + GPT_3_16K_MODELS:
tokens_per_message = 4 # every message follows <|start|>{role/name}\n{content}<|end|>\n
tokens_per_name = -1 # if there's a name, the role is omitted
elif model in GPT_4_MODELS + GPT_4_32K_MODELS + GPT_4_VISION_MODELS:
elif model in GPT_4_MODELS + GPT_4_32K_MODELS + GPT_4_VISION_MODELS + GPT_4_128K_MODELS:
tokens_per_message = 3
tokens_per_name = 1
else:
@@ -507,9 +540,9 @@ class OpenAIHelper:
:return: the number of tokens required
"""
image = Image.open(fileobj)
model = self.config['model']
model = 'gpt-4-vision-preview' # fixed for now
if model not in GPT_4_VISION_MODELS:
raise NotImplementedError(f"""num_tokens_from_messages() is not implemented for model {model}.""")
raise NotImplementedError(f"""count_tokens_vision() is not implemented for model {model}.""")
w, h = image.size
if w > h: w, h = h, w

View File

@@ -48,6 +48,9 @@ class ChatGPTTelegramBot:
if self.config.get('enable_image_generation', False):
self.commands.append(BotCommand(command='image', description=localized_text('image_description', bot_language)))
if self.config.get('enable_tts_generation', False):
self.commands.append(BotCommand(command='tts', description=localized_text('tts_description', bot_language)))
self.group_commands = [BotCommand(
command='chat', description=localized_text('chat_description', bot_language)
)] + self.commands
@@ -97,6 +100,7 @@ class ChatGPTTelegramBot:
(transcribe_minutes_today, transcribe_seconds_today, transcribe_minutes_month,
transcribe_seconds_month) = self.usage[user_id].get_current_transcription_duration()
vision_today, vision_month = self.usage[user_id].get_current_vision_tokens()
characters_today, characters_month = self.usage[user_id].get_current_tts_usage()
current_cost = self.usage[user_id].get_current_cost()
chat_id = update.effective_chat.id
@@ -120,11 +124,16 @@ class ChatGPTTelegramBot:
if self.config.get('enable_vision', False):
text_today_vision = f"{vision_today} {localized_text('stats_vision', bot_language)}\n"
text_today_tts = ""
if self.config.get('enable_tts_generation', False):
text_today_tts = f"{characters_today} {localized_text('stats_tts', bot_language)}\n"
text_today = (
f"*{localized_text('usage_today', bot_language)}:*\n"
f"{tokens_today} {localized_text('stats_tokens', bot_language)}\n"
f"{text_today_images}" # Include the image statistics for today if applicable
f"{text_today_vision}"
f"{text_today_tts}"
f"{transcribe_minutes_today} {localized_text('stats_transcribe', bot_language)[0]} "
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"
@@ -139,12 +148,17 @@ class ChatGPTTelegramBot:
if self.config.get('enable_vision', False):
text_month_vision = f"{vision_month} {localized_text('stats_vision', bot_language)}\n"
text_month_tts = ""
if self.config.get('enable_tts_generation', False):
text_month_tts = f"{characters_month} {localized_text('stats_tts', bot_language)}\n"
# Check if image generation is enabled and, if so, generate the image statistics for the month
text_month = (
f"*{localized_text('usage_month', bot_language)}:*\n"
f"{tokens_month} {localized_text('stats_tokens', bot_language)}\n"
f"{text_month_images}" # Include the image statistics for the month if applicable
f"{text_month_vision}"
f"{text_month_tts}"
f"{transcribe_minutes_month} {localized_text('stats_transcribe', bot_language)[0]} "
f"{transcribe_seconds_month} {localized_text('stats_transcribe', bot_language)[1]}\n"
f"{localized_text('stats_total', bot_language)}{current_cost['cost_month']:.2f}"
@@ -241,10 +255,18 @@ class ChatGPTTelegramBot:
async def _generate():
try:
image_url, image_size = await self.openai.generate_image(prompt=image_query)
if self.config['image_receive_mode'] == 'photo':
await update.effective_message.reply_photo(
reply_to_message_id=get_reply_to_message_id(self.config, update),
photo=image_url
)
elif self.config['image_receive_mode'] == 'document':
await update.effective_message.reply_document(
reply_to_message_id=get_reply_to_message_id(self.config, update),
document=image_url
)
else:
raise Exception(f"env variable IMAGE_RECEIVE_MODE has invalid value {self.config['image_receive_mode']}")
# add image request to users usage tracker
user_id = update.message.from_user.id
self.usage[user_id].add_image_request(image_size, self.config['image_prices'])
@@ -263,6 +285,52 @@ class ChatGPTTelegramBot:
await wrap_with_indicator(update, context, _generate, constants.ChatAction.UPLOAD_PHOTO)
async def tts(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
"""
Generates an speech for the given input using TTS APIs
"""
if not self.config['enable_tts_generation'] \
or not await self.check_allowed_and_within_budget(update, context):
return
tts_query = message_text(update.message)
if tts_query == '':
await update.effective_message.reply_text(
message_thread_id=get_thread_id(update),
text=localized_text('tts_no_prompt', self.config['bot_language'])
)
return
logging.info(f'New speech generation request received from user {update.message.from_user.name} '
f'(id: {update.message.from_user.id})')
async def _generate():
try:
speech_file, text_length = await self.openai.generate_speech(text=tts_query)
await update.effective_message.reply_voice(
reply_to_message_id=get_reply_to_message_id(self.config, update),
voice=speech_file
)
speech_file.close()
# add image request to users usage tracker
user_id = update.message.from_user.id
self.usage[user_id].add_tts_request(text_length, self.config['tts_model'], self.config['tts_prices'])
# add guest chat request to guest usage tracker
if str(user_id) not in self.config['allowed_user_ids'].split(',') and 'guests' in self.usage:
self.usage["guests"].add_tts_request(text_length, self.config['tts_model'], self.config['tts_prices'])
except Exception as e:
logging.exception(e)
await update.effective_message.reply_text(
message_thread_id=get_thread_id(update),
reply_to_message_id=get_reply_to_message_id(self.config, update),
text=f"{localized_text('tts_fail', self.config['bot_language'])}: {str(e)}",
parse_mode=constants.ParseMode.MARKDOWN
)
await wrap_with_indicator(update, context, _generate, constants.ChatAction.UPLOAD_VOICE)
async def transcribe(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
"""
Transcribe audio messages.
@@ -909,6 +977,7 @@ class ChatGPTTelegramBot:
application.add_handler(CommandHandler('reset', self.reset))
application.add_handler(CommandHandler('help', self.help))
application.add_handler(CommandHandler('image', self.image))
application.add_handler(CommandHandler('tts', self.tts))
application.add_handler(CommandHandler('start', self.help))
application.add_handler(CommandHandler('stats', self.stats))
application.add_handler(CommandHandler('resend', self.resend))

View File

@@ -58,6 +58,8 @@ class UsageTracker:
self.usage = json.load(file)
if 'vision_tokens' not in self.usage['usage_history']:
self.usage['usage_history']['vision_tokens'] = {}
if 'tts_characters' not in self.usage['usage_history']:
self.usage['usage_history']['tts_characters'] = {}
else:
# ensure directory exists
pathlib.Path(logs_dir).mkdir(exist_ok=True)
@@ -65,7 +67,7 @@ class UsageTracker:
self.usage = {
"user_name": user_name,
"current_cost": {"day": 0.0, "month": 0.0, "all_time": 0.0, "last_update": str(date.today())},
"usage_history": {"chat_tokens": {}, "transcription_seconds": {}, "number_images": {}, "vision_tokens":{}}
"usage_history": {"chat_tokens": {}, "transcription_seconds": {}, "number_images": {}, "tts_characters": {}, "vision_tokens":{}}
}
# token usage functions:
@@ -194,6 +196,57 @@ class UsageTracker:
tokens_month += tokens
return tokens_day, tokens_month
# tts usage functions:
def add_tts_request(self, text_length, tts_model, tts_prices):
tts_models = ['tts-1', 'tts-1-hd']
price = tts_prices[tts_models.index(tts_model)]
today = date.today()
tts_price = round(text_length * price / 1000, 2)
self.add_current_costs(tts_price)
if 'tts_characters' not in self.usage['usage_history']:
self.usage['usage_history']['tts_characters'] = {}
if tts_model not in self.usage['usage_history']['tts_characters']:
self.usage['usage_history']['tts_characters'][tts_model] = {}
# update usage_history
if str(today) in self.usage["usage_history"]["tts_characters"][tts_model]:
# add requested text length to existing date
self.usage["usage_history"]["tts_characters"][tts_model][str(today)] += text_length
else:
# create new entry for current date
self.usage["usage_history"]["tts_characters"][tts_model][str(today)] = text_length
# write updated token usage to user file
with open(self.user_file, "w") as outfile:
json.dump(self.usage, outfile)
def get_current_tts_usage(self):
"""Get length of speech generated for today and this month.
:return: total amount of characters converted to speech per day and per month
"""
tts_models = ['tts-1', 'tts-1-hd']
today = date.today()
characters_day = 0
for tts_model in tts_models:
if tts_model in self.usage["usage_history"]["tts_characters"] and \
str(today) in self.usage["usage_history"]["tts_characters"][tts_model]:
characters_day += self.usage["usage_history"]["tts_characters"][tts_model][str(today)]
month = str(today)[:7] # year-month as string
characters_month = 0
for tts_model in tts_models:
if tts_model in self.usage["usage_history"]["tts_characters"]:
for today, characters in self.usage["usage_history"]["tts_characters"][tts_model].items():
if today.startswith(month):
characters_month += characters
return int(characters_day), int(characters_month)
# transcription usage functions:
def add_transcription_seconds(self, seconds, minute_price=0.006):
@@ -279,14 +332,15 @@ class UsageTracker:
cost_all_time = self.usage["current_cost"].get("all_time", self.initialize_all_time_cost())
return {"cost_today": cost_day, "cost_month": cost_month, "cost_all_time": cost_all_time}
def initialize_all_time_cost(self, tokens_price=0.002, image_prices="0.016,0.018,0.02", minute_price=0.006, vision_token_price=0.01):
def initialize_all_time_cost(self, tokens_price=0.002, image_prices="0.016,0.018,0.02", minute_price=0.006, vision_token_price=0.01, tts_prices='0.015,0.030'):
"""Get total USD amount of all requests in history
:param tokens_price: price per 1000 tokens, defaults to 0.002
:param image_prices: prices for images of sizes ["256x256", "512x512", "1024x1024"],
defaults to [0.016, 0.018, 0.02]
:param minute_price: price per minute transcription, defaults to 0.006
:param vision_token_price: price per 1k vision token interpretation, defaults to 0.01
:param vision_token_price: price per 1K vision token interpretation, defaults to 0.01
:param tts_prices: price per 1K characters tts per model ['tts-1', 'tts-1-hd'], defaults to [0.015, 0.030]
:return: total cost of all requests
"""
total_tokens = sum(self.usage['usage_history']['chat_tokens'].values())
@@ -302,5 +356,9 @@ class UsageTracker:
total_vision_tokens = sum(self.usage['usage_history']['vision_tokens'].values())
vision_cost = round(total_vision_tokens * vision_token_price / 1000, 2)
all_time_cost = token_cost + transcription_cost + image_cost + vision_cost
total_characters = [sum(tts_model.values()) for tts_model in self.usage['usage_history']['tts_characters'].values()]
tts_prices_list = [float(x) for x in tts_prices.split(',')]
tts_cost = round(sum([count * price / 1000 for count, price in zip(total_characters, tts_prices_list)]), 2)
all_time_cost = token_cost + transcription_cost + image_cost + vision_cost + tts_cost
return all_time_cost

View File

@@ -1,7 +1,7 @@
python-dotenv~=1.0.0
pydub~=0.25.1
tiktoken==0.5.1
openai==1.1.1
openai==1.3.3
python-telegram-bot==20.3
requests~=2.31.0
tenacity==8.2.2

View File

@@ -3,6 +3,7 @@
"help_description":"Show help message",
"reset_description":"Reset the conversation. Optionally pass high-level instructions (e.g. /reset You are a helpful assistant)",
"image_description":"Generate image from prompt (e.g. /image cat)",
"tts_description":"Generate speech from text (e.g. /tts my house)",
"stats_description":"Get your current usage statistics",
"resend_description":"Resend the latest message",
"chat_description":"Chat with the bot!",
@@ -15,6 +16,7 @@
"stats_tokens":"tokens",
"stats_images":"images generated",
"stats_vision":"image tokens interpreted",
"stats_tts":"characters converted to speech",
"stats_transcribe":["minutes and", "seconds transcribed"],
"stats_total":"💰 For a total amount of $",
"stats_budget":"Your remaining budget",
@@ -27,6 +29,8 @@
"image_no_prompt":"Please provide a prompt! (e.g. /image cat)",
"image_fail":"Failed to generate image",
"vision_fail":"Failed to interpret image",
"tts_no_prompt":"Please provide text! (e.g. /tts my house)",
"tts_fail":"Failed to generate speech",
"media_download_fail":["Failed to download audio file", "Make sure the file is not too large. (max 20MB)"],
"media_type_fail":"Unsupported file type",
"transcript":"Transcript",
@@ -48,6 +52,7 @@
"help_description":"Muestra el mensaje de ayuda",
"reset_description":"Reinicia la conversación. Opcionalmente, pasa instrucciones de alto nivel (por ejemplo, /reset Eres un asistente útil)",
"image_description":"Genera una imagen a partir de una sugerencia (por ejemplo, /image gato)",
"tts_description":"Genera voz a partir de texto (por ejemplo, /tts mi casa)",
"stats_description":"Obtén tus estadísticas de uso actuales",
"resend_description":"Reenvía el último mensaje",
"chat_description":"¡Chatea con el bot!",
@@ -59,6 +64,7 @@
"usage_month":"Uso este mes",
"stats_tokens":"tokens de chat usados",
"stats_images":"imágenes generadas",
"stats_tts":"caracteres convertidos a voz",
"stats_transcribe":["minutos y", "segundos transcritos"],
"stats_total":"💰 Por un monto total de $",
"stats_budget":"Tu presupuesto restante",
@@ -70,6 +76,8 @@
"reset_done":"¡Listo!",
"image_no_prompt":"¡Por favor proporciona una sugerencia! (por ejemplo, /image gato)",
"image_fail":"No se pudo generar la imagen",
"tts_no_prompt":"¡Por favor proporciona texto! (por ejemplo, /tts mi casa)",
"tts_fail":"No se pudo generar la voz",
"media_download_fail":["No se pudo descargar el archivo de audio", "Asegúrate de que el archivo no sea demasiado grande. (máx. 20MB)"],
"media_type_fail":"Tipo de archivo no compatible",
"transcript":"Transcripción",
@@ -91,6 +99,7 @@
"help_description": "Mostra a mensagem de ajuda",
"reset_description": "Redefine a conversa. Opcionalmente, passe instruções de alto nível (por exemplo, /reset Você é um assistente útil)",
"image_description": "Gera uma imagem a partir do prompt (por exemplo, /image gato)",
"tts_description": "Gera fala a partir do texto (por exemplo, /tts minha casa)",
"stats_description": "Obtenha suas estatísticas de uso atuais",
"resend_description": "Reenvia a última mensagem",
"chat_description": "Converse com o bot!",
@@ -102,6 +111,7 @@
"usage_month": "Uso este mês",
"stats_tokens": "tokens de chat usados",
"stats_images": "imagens geradas",
"stats_tts": "caracteres convertidos em fala",
"stats_transcribe": ["minutos e", "segundos transcritos"],
"stats_total": "💰 Para um valor total de $",
"stats_budget": "Seu orçamento restante",
@@ -113,6 +123,8 @@
"reset_done": "Feito!",
"image_no_prompt": "Por favor, forneça um prompt! (por exemplo, /image gato)",
"image_fail": "Falha ao gerar imagem",
"tts_no_prompt": "Por favor, forneça texto! (por exemplo, /tts minha casa)",
"tts_fail": "Falha ao gerar fala",
"media_download_fail": ["Falha ao baixar arquivo de áudio", "Certifique-se de que o arquivo não seja muito grande. (máx. 20 MB)"],
"media_type_fail": "Tipo de arquivo não suportado",
"transcript": "Transcrição",
@@ -134,6 +146,7 @@
"help_description":"Zeige die Hilfenachricht",
"reset_description":"Setze die Konversation zurück. Optionale Eingabe einer grundlegenden Anweisung (z.B. /reset Du bist ein hilfreicher Assistent)",
"image_description":"Erzeuge ein Bild aus einer Aufforderung (z.B. /image Katze)",
"tts_description":"Erzeuge Sprache aus Text (z.B. /tts mein Haus)",
"stats_description":"Zeige aktuelle Benutzungstatistiken",
"resend_description":"Wiederhole das Senden der letzten Nachricht",
"chat_description":"Schreibe mit dem Bot!",
@@ -145,6 +158,7 @@
"usage_month":"Nutzung diesen Monat",
"stats_tokens":"Chat Tokens verwendet",
"stats_images":"Bilder generiert",
"stats_tts":"Zeichen in Sprache umgewandelt",
"stats_transcribe":["Minuten und", "Sekunden abgeschrieben"],
"stats_total":"💰 Für einem Gesamtbetrag von $",
"stats_budget":"Dein verbliebenes Budget",
@@ -156,6 +170,8 @@
"reset_done":"Fertig!",
"image_no_prompt":"Bitte füge eine Aufforderung hinzu (z.B. /image Katze)",
"image_fail":"Fehler beim Generieren eines Bildes",
"tts_no_prompt":"Bitte füge Text hinzu! (z.B. /tts mein Haus)",
"tts_fail":"Fehler beim Generieren von Sprache",
"media_download_fail":["Fehler beim Herunterladen der Audiodatei", "Die Datei könnte zu groß sein. (max 20MB)"],
"media_type_fail":"Dateityp nicht unterstützt",
"transcript":"Abschrift",
@@ -177,6 +193,7 @@
"help_description":"Näytä ohjeet",
"reset_description":"Nollaa keskustelu. Voit myös antaa korkean tason ohjeita (esim. /reset Olet avulias avustaja)",
"image_description":"Luo kuva tekstistä (esim. /image kissa)",
"tts_description":"Muuta teksti puheeksi (esim. /tts taloni)",
"stats_description":"Hae tämän hetken käyttötilastot",
"resend_description":"Lähetä viimeisin viesti uudestaan",
"chat_description":"Keskustele botin kanssa!",
@@ -188,6 +205,7 @@
"usage_month":"Käyttö tässä kuussa",
"stats_tokens":"viestipolettia käytetty",
"stats_images":"kuvaa luotu",
"stats_tts":"merkkiä muutettu puheeksi",
"stats_transcribe":["minuuttia ja", "sekuntia litteroitu"],
"stats_total":"💰 Yhteensä $",
"stats_budget":"Jäljellä oleva budjettisi",
@@ -199,6 +217,8 @@
"reset_done":"Valmis!",
"image_no_prompt":"Ole hyvä ja anna ohjeet! (esim. /image kissa)",
"image_fail":"Kuvan luonti epäonnistui",
"tts_no_prompt":"Ole hyvä ja anna teksti! (esim. /tts taloni)",
"tts_fail":"Puheen luonti epäonnistui",
"media_download_fail":["Äänitiedoston lataus epäonnistui", "Varmista että se ei ole liian iso. (enintään 20MB)"],
"media_type_fail":"Tiedostomuoto ei tuettu",
"transcript":"Litteroitu teksti",
@@ -220,6 +240,7 @@
"help_description":"Показать справочное сообщение",
"reset_description":"Перезагрузить разговор. По желанию передай общие инструкции (например, /reset ты полезный помощник)",
"image_description":"Создать изображение по запросу (например, /image кошка)",
"tts_description":"Создать речь из текста (например, /tts мой дом)",
"stats_description":"Получить статистику использования",
"resend_description":"Повторная отправка последнего сообщения",
"chat_description":"Общайся с ботом!",
@@ -231,6 +252,7 @@
"usage_month":"Использование в этом месяце",
"stats_tokens":"токенов чата использовано",
"stats_images":"изображений создано",
"stats_tts":"символов преобразовано в речь",
"stats_transcribe":["минут(ы) и", "секунд(ы) расшифровки"],
"stats_total":"💰 На общую сумму $",
"stats_budget":"Остаточный бюджет",
@@ -242,6 +264,8 @@
"reset_done":"Готово!",
"image_no_prompt":"Пожалуйста, подайте запрос! (например, /image кошка)",
"image_fail":"Не удалось создать изображение",
"tts_no_prompt":"Пожалуйста, подайте текст! (например, /tts мой дом)",
"tts_fail":"Не удалось создать речь",
"media_download_fail":["Не удалось загрузить аудиофайл", "Проверьте, чтобы файл не был слишком большим. (не более 20 МБ)"],
"media_type_fail":"Неподдержанный тип файла",
"transcript":"Расшифровка",
@@ -263,6 +287,7 @@
"help_description":"Yardım mesajını göster",
"reset_description":"Konuşmayı sıfırla. İsteğe bağlı olarak botun nasıl davranacağını belirleyin (Örneğin: /reset Sen yardımcı bir asistansın)",
"image_description":"Verilen komuta göre görüntü üret (Örneğin /image kedi)",
"tts_description":"Verilen metni seslendir (Örneğin /tts evim)",
"stats_description":"Mevcut kullanım istatistiklerinizi alın",
"resend_description":"En son mesajı yeniden gönder",
"chat_description":"Bot ile sohbet edin!",
@@ -274,6 +299,7 @@
"usage_month":"Bu ayki kullanım",
"stats_tokens":"sohbet token'i kullanıldı",
"stats_images":"görüntüler oluşturuldu",
"stats_tts":"seslendirilen karakterler",
"stats_transcribe":["dakika", "saniye sesten yazıya çeviri yapıldı"],
"stats_total":"💰 Bu kullanımların toplam maliyeti $",
"stats_budget":"Kalan bütçeniz",
@@ -285,6 +311,8 @@
"reset_done":"Tamamlandı!",
"image_no_prompt":"Lütfen komut giriniz (Örneğin /image kedi)",
"image_fail":"Görüntü oluşturulamadı",
"tts_no_prompt":"Lütfen metin giriniz (Örneğin /tts evim)",
"tts_fail":"Seslendirme oluşturulamadı",
"media_download_fail":["Ses dosyası indirilemedi", "Dosyanın çok büyük olmadığından emin olun. (maksimum 20MB)"],
"media_type_fail":"Desteklenmeyen dosya türü",
"transcript":"Yazıya çevirilmiş hali",
@@ -306,6 +334,7 @@
"help_description":"Mostra il messaggio di aiuto",
"reset_description":"Resetta la conversazione. Puoi anche specificare ulteriori istruzioni (ad esempio, /reset Sei un assistente utile).",
"image_description":"Genera immagine da un testo (ad es. /image gatto)",
"tts_description":"Genera audio da un testo (ad es. /tts la mia casa)",
"stats_description":"Mostra le statistiche di utilizzo",
"resend_description":"Reinvia l'ultimo messaggio",
"chat_description":"Chatta con il bot!",
@@ -317,6 +346,7 @@
"usage_month":"Utilizzo questo mese",
"stats_tokens":"token utilizzati",
"stats_images":"immagini generate",
"stats_tts":"caratteri convertiti in audio",
"stats_transcribe":["minuti", "secondi trascritti"],
"stats_total":"💰 Per un totale di $",
"stats_budget":"Budget rimanente",
@@ -328,6 +358,8 @@
"reset_done":"Fatto!",
"image_no_prompt":"Inserisci un testo (ad es. /image gatto)",
"image_fail":"Impossibile generare l'immagine",
"tts_no_prompt":"Inserisci un testo (ad es. /tts la mia casa)",
"tts_fail":"Impossibile generare l'audio",
"media_download_fail":["Impossibile processare il file audio", "Assicurati che il file non sia troppo pesante (massimo 20MB)"],
"media_type_fail":"Tipo di file non supportato",
"transcript":"Trascrizione",
@@ -349,6 +381,7 @@
"help_description": "Menampilkan pesan bantuan",
"reset_description": "Merestart percakapan. Opsional memasukkan instruksi tingkat tinggi (misalnya /reset Anda adalah asisten yang membantu)",
"image_description": "Menghasilkan gambar dari input prompt (misalnya /image kucing)",
"tts_description": "Menghasilkan suara dari teks (misalnya /tts rumah saya)",
"stats_description": "Mendapatkan statistik penggunaan saat ini",
"resend_description": "Mengirim kembali pesan terakhir",
"chat_description": "Berkonversasi dengan bot!",
@@ -360,6 +393,7 @@
"usage_month": "Penggunaan bulan ini",
"stats_tokens": "token obrolan yang digunakan",
"stats_images": "gambar yang dihasilkan",
"stats_tts": "karakter dikonversi ke suara",
"stats_transcribe": ["menit dan", "detik ditranskripsi"],
"stats_total": "💰 Untuk total sebesar $",
"stats_budget": "Sisa anggaran Anda",
@@ -371,6 +405,8 @@
"reset_done": "Selesai!",
"image_no_prompt": "Harap berikan prompt! (misalnya /image kucing)",
"image_fail": "Gagal menghasilkan gambar",
"tts_no_prompt": "Harap berikan teks! (misalnya /tts rumah saya)",
"tts_fail": "Gagal menghasilkan suara",
"media_download_fail": ["Gagal mengunduh file audio", "Pastikan file tidak terlalu besar. (maksimal 20MB)"],
"media_type_fail": "Tipe file tidak didukung",
"transcript": "Transkrip",
@@ -392,6 +428,7 @@
"help_description":"Toon uitleg",
"reset_description":"Herstart het gesprek. Voeg eventueel instructies toe (bijv. /reset Je bent een behulpzame assistent)",
"image_description":"Genereer een afbeelding van een prompt (bijv. /image kat)",
"tts_description":"Genereer spraak van tekst (bijv. /tts mijn huis)",
"stats_description":"Bekijk je huidige gebruiksstatistieken",
"resend_description":"Verstuur het laatste bericht opnieuw",
"chat_description":"Chat met de bot!",
@@ -403,6 +440,7 @@
"usage_month":"Gebruik deze maand",
"stats_tokens":"chat tokens gebruikt",
"stats_images":"afbeeldingen gegenereerd",
"stats_tts":"karakters omgezet naar spraak",
"stats_transcribe":["minuten en", "seconden audio naar tekst omgezet"],
"stats_total":"💰 Voor een totaal van $",
"stats_budget":"Je resterende budget",
@@ -414,6 +452,8 @@
"reset_done":"Klaar!",
"image_no_prompt":"Geef a.u.b. een prompt! (bijv. /image kat)",
"image_fail":"Afbeelding genereren mislukt",
"tts_no_prompt":"Geef a.u.b. tekst! (bijv. /tts mijn huis)",
"tts_fail":"Spraak genereren mislukt",
"media_download_fail":["Audio bestand downloaden mislukt", "Check of het niet te groot is. (max 20MB)"],
"media_type_fail":"Niet ondersteund bestandsformaat",
"transcript":"Uitgeschreven tekst",
@@ -435,6 +475,7 @@
"help_description":"显示帮助信息",
"reset_description":"重置对话。可以选择传递高级指令(例如/reset 你是一个有用的助手)",
"image_description":"根据提示生成图像(例如/image 猫)",
"tts_description":"将文本转换为语音(例如/tts 我的房子)",
"stats_description":"获取您当前的使用统计",
"resend_description":"重新发送最近的消息",
"chat_description":"与机器人聊天!",
@@ -446,6 +487,7 @@
"usage_month":"本月使用情况",
"stats_tokens":"使用的token",
"stats_images":"生成图像的数量",
"stats_tts":"转换为语音的字符",
"stats_transcribe":["分钟", "秒转录时长"],
"stats_total":"💰 总计金额 $",
"stats_budget":"您的剩余预算",
@@ -457,6 +499,8 @@
"reset_done":"完成!",
"image_no_prompt":"请提供提示!(例如/image 猫)",
"image_fail":"生成图像失败",
"tts_no_prompt":"请提供文本!(例如/tts 我的房子)",
"tts_fail":"生成语音失败",
"media_download_fail":["下载音频文件失败", "请确保文件不要太大最大20MB"],
"media_type_fail":"不支持的文件类型",
"transcript":"转录",
@@ -478,6 +522,7 @@
"help_description":"顯示幫助訊息",
"reset_description":"重設對話。可以選擇傳遞進階指令(例如 /reset 你是一個樂於助人的助手)",
"image_description":"根據提示生成圖片(例如 /image 貓)",
"tts_description":"將文字轉換為語音(例如 /tts 我的房子)",
"stats_description":"取得當前使用統計",
"resend_description":"重新傳送最後一則訊息",
"chat_description":"與機器人聊天!",
@@ -489,6 +534,7 @@
"usage_month":"本月用量",
"stats_tokens":"Token 已使用",
"stats_images":"圖片已生成",
"stats_tts":"轉換為語音的字元",
"stats_transcribe":["分", "秒已轉錄"],
"stats_total":"💰 總計金額 $",
"stats_budget":"剩餘預算",
@@ -500,6 +546,8 @@
"reset_done":"重設完成!",
"image_no_prompt":"請輸入提示!(例如 /image 貓)",
"image_fail":"圖片生成失敗",
"tts_no_prompt":"請輸入文字!(例如 /tts 我的房子)",
"tts_fail":"語音生成失敗",
"media_download_fail":["下載音訊檔案失敗", "請確保檔案大小不超過 20MB"],
"media_type_fail":"不支援的檔案類型",
"transcript":"轉錄",
@@ -521,6 +569,7 @@
"help_description":"Hiển thị trợ giúp",
"reset_description":"Đặt lại cuộc trò chuyện. Tùy ý chuyển hướng dẫn cấp cao (ví dụ: /reset Bạn là một trợ lý hữu ích)",
"image_description":"Tạo hình ảnh từ câu lệnh (ví dụ: /image cat)",
"tts_description":"Tạo giọng nói từ văn bản (ví dụ: /tts nhà của tôi)",
"stats_description":"Nhận số liệu thống kê sử dụng hiện tại của bạn",
"resend_description":"Gửi lại tin nhắn mới nhất",
"chat_description":"Trò chuyện với bot!",
@@ -532,6 +581,7 @@
"usage_month":"Sử dụng trong tháng này",
"stats_tokens":"mã thông báo trò chuyện được sử dụng",
"stats_images":"hình ảnh tạo ra",
"stats_tts":"ký tự được chuyển đổi thành giọng nói",
"stats_transcribe":["phút và", "giây"],
"stats_total":"💰 Với tổng số tiền $",
"stats_budget":"Ngân sách còn lại của bạn",
@@ -543,6 +593,8 @@
"reset_done":"Xong!",
"image_no_prompt":"Vui lòng cung cấp lời nhắc! (ví dụ: /image con mèo",
"image_fail":"Không thể tạo hình ảnh",
"tts_no_prompt":"Vui lòng cung cấp văn bản! (ví dụ: /tts nhà của tôi)",
"tts_fail":"Không thể tạo giọng nói",
"media_download_fail":["Không thể tải xuống tệp âm thanh", "Đảm bảo tệp không quá lớn. (tối đa 20 MB)"],
"media_type_fail":"Loại tập tin không được hỗ trợ",
"transcript":"Dịch",
@@ -564,6 +616,7 @@
"help_description":"نمایش پیغام راهنما",
"reset_description":"مکالمه را تنظیم مجدد کنید. به صورت اختیاری می‌توانید دستورالعمل های سطح بالا را ارسال کنید (به عنوان مثال /reset تو یک دستیار مفید هستی)",
"image_description":"ایجاد تصویر بر اساس فرمان (به عنوان مثال /image گربه)",
"tts_description":"تبدیل متن به صدا (به عنوان مثال /tts خانه من)",
"stats_description":"آمار استفاده فعلی خود را دریافت کنید",
"resend_description":"آخرین پیام را دوباره ارسال کنید",
"chat_description":"چت با ربات!",
@@ -575,6 +628,7 @@
"usage_month":"استفاده این ماه",
"stats_tokens":"توکن چت استفاده شده است",
"stats_images":"تصویر تولید شده است",
"stats_tts":"کاراکترهای تبدیل شده به صدا",
"stats_transcribe":["دقیقه و", "ثانیه رونویسی شده است"],
"stats_total":"💰 مقدار کل مصرف: $",
"stats_budget":"بودجه باقی‌مانده شما",
@@ -586,6 +640,8 @@
"reset_done":"انجام شد!",
"image_no_prompt":"لطفا یک فرمان ارائه دهید! (به عنوان مثال /image گربه)",
"image_fail":"در تولید تصویر خطایی رخ داد",
"tts_no_prompt":"لطفا متنی را وارد کنید! (به عنوان مثال /tts خانه من)",
"tts_fail":"در تولید صدا خطایی رخ داد",
"media_download_fail":["فایل صوتی دانلود نشد", "دقت کنید که فایل خیلی بزرگ نباشد. (حداکثر 20 مگابایت)"],
"media_type_fail":"نوع فایل پشتیبانی نمی‌شود",
"transcript":"رونوشت",
@@ -607,6 +663,7 @@
"help_description":"Показати повідомлення допомоги",
"reset_description":"Скинути розмову. Опціонально передайте високорівневі інструкції (наприклад, /reset Ви корисний помічник)",
"image_description":"Створити зображення за вашим запитом (наприклад, /image кіт)",
"tts_description":"Створити голос з тексту (наприклад, /tts мій будинок)",
"stats_description":"Отримати вашу поточну статистику використання",
"resend_description":"Повторно відправити останнє повідомлення",
"chat_description":"Розмовляйте з ботом!",
@@ -618,6 +675,7 @@
"usage_month":"Використання цього місяця",
"stats_tokens":"використано токенів чату",
"stats_images":"згенеровано зображень",
"stats_tts":"символів перетворено на голос",
"stats_transcribe":["хвилин і", "секунд транскрибовано"],
"stats_total":"💰 Загальна сума $",
"stats_budget":"Ваш залишок бюджету",
@@ -629,6 +687,8 @@
"reset_done":"Готово!",
"image_no_prompt":"Будь ласка, надайте свій запит! (наприклад, /image кіт)",
"image_fail":"Не вдалося створити зображення",
"tts_no_prompt":"Будь ласка, надайте текст! (наприклад, /tts мій будинок)",
"tts_fail":"Не вдалося створити голос",
"media_download_fail":["Не вдалося завантажити аудіофайл", "Переконайтеся, що файл не занадто великий. (максимум 20 МБ)"],
"media_type_fail":"Непідтримуваний тип файлу",
"transcript":"Транскрипт",
@@ -650,6 +710,7 @@
"help_description":"Lihat Mesej Bantuan",
"reset_description":"Tetapkan semula perbualan. Secara pilihan, hantar arahan peringkat tinggi (cth. /reset Anda adalah pembantu yang membantu)",
"image_description":"Jana imej daripada gesaan (cth. /image cat)",
"tts_description":"Tukar teks kepada suara (cth. /tts rumah saya)",
"stats_description":"Dapatkan statistik penggunaan semasa anda",
"resend_description":"Hantar semula mesej terkini",
"chat_description":"Sembang dengan bot!",
@@ -661,6 +722,7 @@
"usage_month":"Penggunaan bulan ini",
"stats_tokens":"Token",
"stats_images":"Penghasilan",
"stats_tts":"Aksara yang ditukar kepada suara",
"stats_transcribe":["Minit dan", "Penterjemah yang kedua"],
"stats_total":"Jumlah semua 💰 dalam $",
"stats_budget":"Baki yang tersisa",
@@ -672,6 +734,8 @@
"reset_done":"Selesai!",
"image_no_prompt":"Sila berikan gesaan! (cth. /image cat)",
"image_fail":"Gagal menjana imej",
"tts_no_prompt":"Sila berikan teks! (cth. /tts rumah saya)",
"tts_fail":"Gagal menjana suara",
"media_download_fail":["Gagal memuat turun fail audio", "Pastikan fail tidak terlalu besar. (maks 20MB)"],
"media_type_fail":"Jenis fail tidak disokong",
"transcript":"Transkrip",
@@ -688,5 +752,52 @@
"ask_chatgpt":"Tanya ChatGPT",
"loading":"Memuatkan...",
"function_unavailable_in_inline_mode": "Fungsi ini tidak tersedia dalam mod sebaris"
},
"uz": {
"help_description": "Yordam xabarini ko'rsatish",
"reset_description": "Suhbatni qayta boshlang. Agar xohlasangiz, umumiy ko'rsatmalar bering (masalan, /reset siz foydali yordamchisiz)",
"image_description": "Tasvirni so'rov bo'yicha yaratish (masalan, /image mushuk)",
"tts_description": "Matnni ovozga aylantirish (masalan, /tts uyim)",
"stats_description": "Hozirgi foydalanilgan statistikani olish",
"resend_description": "Oxirgi xabarni qayta yuborish",
"chat_description": "Bot bilan suxbat!",
"disallowed": "Kechirasiz, sizga bu botdan foydalanish taqiqlangan. Siz manba kodini tekshirishingiz mumkin https://github.com/n3d1117/chatgpt-telegram-bot",
"budget_limit": "Kechirasiz, siz foydalanish chegarasiga yetdingiz.",
"help_text": ["Men ChatGPT botman, men bilan gaplashing!", "Menga ovozli xabar yoki fayl yuboring, men uni siz uchun transkripsiya qilaman", "Ochiq manba: https://github.com/n3d1117/chatgpt-telegram-bot"],
"stats_conversation": ["Hozirgi suhbat", "tarixdagi chat xabarlari", "tarixdagi suhbat tokenlari"],
"usage_today": "Bugungi foydalanish",
"usage_month": "Bu oydagi foydalanish",
"stats_tokens": "tokenlar",
"stats_images": "yaratilgan tasvirlar",
"stats_tts": "ovozga aylangan belgilar",
"stats_transcribe": ["minutlar va", "soniyalar transkripsiya qilingan"],
"stats_total": "💰 Jami miqdor $",
"stats_budget": "Qolgan budjetingiz",
"monthly": " bu oy uchun",
"daily": " bugun uchun",
"all-time": "",
"stats_openai": "Shu oyda OpenAI hisobingizdan to'lov amalga oshirildi $",
"resend_failed": "Sizda qayta yuborish uchun hech narsa yo'q",
"reset_done": "Bajarildi!",
"image_no_prompt": "Iltimos, so'rov yozing! (masalan, /image mushuk)",
"image_fail": "Tasvir yaratish amalga oshmadi",
"tts_no_prompt": "Iltimos, matn kiriting! (masalan, /tts uyim)",
"tts_fail": "Ovoz yaratish amalga oshmadi",
"media_download_fail": ["Audio faylni yuklab olish amalga oshmadi", "Fayl hajmi katta emasligiga ishonch hosil qiling. (max 20MB)"],
"media_type_fail": "Qo'llab-quvvatlanmaydigan fayl turi",
"transcript": "Transkript",
"answer": "Javob",
"transcribe_fail": "Matnni transkripsiya qilib bo'lmadi",
"chat_fail": "Javob olish amalga oshmadi",
"prompt": "so'rov",
"completion": "yakunlash",
"openai_rate_limit": "OpenAI ta'rif chegarasidan oshib ketdi",
"openai_invalid": "OpenAI So'rov noto'g'ri",
"error": "Xatolik yuz berdi",
"try_again": "Birozdan keyin qayta urinib ko'ring",
"answer_with_chatgpt": "ChatGPT bilan javob berish",
"ask_chatgpt": "ChatGPTdan so'rash",
"loading": "Yuklanmoqda...",
"function_unavailable_in_inline_mode": "Bu funksiya inline rejimida mavjud emas"
}
}