diff --git a/README.md b/README.md index 067b14a..28cd45e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# ChatGPT Telegram Bot: **Fast. No daily limits. Special chat modes** +# ChatGPT Telegram Bot: **GPT-4. Fast. No daily limits. Special chat modes**
@@ -16,7 +16,7 @@ We all love [chat.openai.com](https://chat.openai.com), but... It's TERRIBLY laggy, has daily limits, and is only accessible through an archaic web interface. -This repo is ChatGPT re-created with GPT-3.5 LLM as Telegram Bot. **And it works great.** +This repo is ChatGPT re-created as Telegram Bot. **And it works great.** You can deploy your own bot, or use mine: [@chatgpt_karfly_bot](https://t.me/chatgpt_karfly_bot) @@ -24,6 +24,7 @@ You can deploy your own bot, or use mine: [@chatgpt_karfly_bot](https://t.me/cha - Low latency replies (it usually takes about 3-5 seconds) - No request limits - Message streaming (watch demo) +- GPT-4 support - Voice message recognition - Code highlighting - Special chat modes: 👩🏼‍🎓 Assistant, 👩🏼‍💻 Code Assistant, 📝 Text Improver and 🎬 Movie Expert. You can easily create your own chat modes by editing `config/chat_modes.yml` @@ -49,6 +50,7 @@ You can deploy your own bot, or use mine: [@chatgpt_karfly_bot](https://t.me/cha If you want to add payments to your bot – write me on Telegram ([@karfly](https://t.me/karfly)). ## News +- *24 Mar 2023*: GPT-4 support. Run `/settings` command to choose model - *15 Mar 2023*: Added message streaming. Now you don't have to wait until the whole message is ready, it's streamed to Telegram part-by-part (watch demo) - *9 Mar 2023*: Now you can easily create your own Chat Modes by editing `config/chat_modes.yml` - *8 Mar 2023*: Added voice message recognition with [OpenAI Whisper API](https://openai.com/blog/introducing-chatgpt-and-whisper-apis). Record a voice message and ChatGPT will answer you! @@ -59,6 +61,7 @@ If you want to add payments to your bot – write me on Telegram ([@karfly](http - `/new` – Start new dialog - `/mode` – Select chat mode - `/balance` – Show balance +- `/settings` – Show settings - `/help` – Show help ## Setup diff --git a/bot/bot.py b/bot/bot.py index 37ecb85..c4945cb 100644 --- a/bot/bot.py +++ b/bot/bot.py @@ -43,6 +43,7 @@ HELP_MESSAGE = """Commands: ⚪ /retry – Regenerate last bot answer ⚪ /new – Start new dialog ⚪ /mode – Select chat mode +⚪ /settings – Show settings ⚪ /balance – Show balance ⚪ /help – Show help """ @@ -70,6 +71,24 @@ async def register_user_if_not_exists(update: Update, context: CallbackContext, if user.id not in user_semaphores: user_semaphores[user.id] = asyncio.Semaphore(1) + if db.get_user_attribute(user.id, "current_model") is None: + db.set_user_attribute(user.id, "current_model", config.models["available_text_models"][0]) + + # back compatibility for n_used_tokens field + n_used_tokens = db.get_user_attribute(user.id, "n_used_tokens") + if isinstance(n_used_tokens, int): # old format + new_n_used_tokens = { + "gpt-3.5-turbo": { + "n_input_tokens": 0, + "n_output_tokens": n_used_tokens + } + } + db.set_user_attribute(user.id, "n_used_tokens", new_n_used_tokens) + + # voice message transcription + if db.get_user_attribute(user.id, "n_transcribed_seconds") is None: + db.set_user_attribute(user.id, "n_transcribed_seconds", 0.0) + async def start_handle(update: Update, context: CallbackContext): await register_user_if_not_exists(update, context, update.message.from_user) @@ -137,24 +156,25 @@ async def message_handle(update: Update, context: CallbackContext, message=None, try: message = message or update.message.text + current_model = db.get_user_attribute(user_id, "current_model") dialog_messages = db.get_dialog_messages(user_id, dialog_id=None) parse_mode = { "html": ParseMode.HTML, "markdown": ParseMode.MARKDOWN }[openai_utils.CHAT_MODES[chat_mode]["parse_mode"]] - chatgpt_instance = openai_utils.ChatGPT(use_chatgpt_api=config.use_chatgpt_api) + chatgpt_instance = openai_utils.ChatGPT(model=current_model) if config.enable_message_streaming: gen = chatgpt_instance.send_message_stream(message, dialog_messages=dialog_messages, chat_mode=chat_mode) else: - answer, n_used_tokens, n_first_dialog_messages_removed = await chatgpt_instance.send_message( + answer, (n_input_tokens, n_output_tokens), n_first_dialog_messages_removed = await chatgpt_instance.send_message( message, dialog_messages=dialog_messages, chat_mode=chat_mode ) async def fake_gen(): - yield "finished", answer, n_used_tokens, n_first_dialog_messages_removed + yield "finished", answer, (n_input_tokens, n_output_tokens), n_first_dialog_messages_removed gen = fake_gen() @@ -168,7 +188,7 @@ async def message_handle(update: Update, context: CallbackContext, message=None, if status == "not_finished": status, answer = gen_item elif status == "finished": - status, answer, n_used_tokens, n_first_dialog_messages_removed = gen_item + status, answer, (n_input_tokens, n_output_tokens), n_first_dialog_messages_removed = gen_item else: raise ValueError(f"Streaming status {status} is unknown") @@ -207,7 +227,7 @@ async def message_handle(update: Update, context: CallbackContext, message=None, dialog_id=None ) - db.set_user_attribute(user_id, "n_used_tokens", n_used_tokens + db.get_user_attribute(user_id, "n_used_tokens")) + db.update_n_used_tokens(user_id, current_model, n_input_tokens, n_output_tokens) except Exception as e: error_text = f"Something went wrong during completion. Reason: {e}" logger.error(error_text) @@ -262,16 +282,11 @@ async def voice_message_handle(update: Update, context: CallbackContext): text = f"🎤: {transcribed_text}" await update.message.reply_text(text, parse_mode=ParseMode.HTML) + # update n_transcribed_seconds + db.set_user_attribute(user_id, "n_transcribed_seconds", voice.duration + db.get_user_attribute(user_id, "n_transcribed_seconds")) + await message_handle(update, context, message=transcribed_text) - # calculate spent dollars - n_spent_dollars = voice.duration * (config.whisper_price_per_1_min / 60) - - # normalize dollars to tokens (it's very convenient to measure everything in a single unit) - price_per_1000_tokens = config.chatgpt_price_per_1000_tokens if config.use_chatgpt_api else config.gpt_price_per_1000_tokens - n_used_tokens = int(n_spent_dollars / (price_per_1000_tokens / 1000)) - db.set_user_attribute(user_id, "n_used_tokens", n_used_tokens + db.get_user_attribute(user_id, "n_used_tokens")) - async def new_dialog_handle(update: Update, context: CallbackContext): await register_user_if_not_exists(update, context, update.message.from_user) @@ -317,23 +332,95 @@ async def set_chat_mode_handle(update: Update, context: CallbackContext): await query.edit_message_text(f"{openai_utils.CHAT_MODES[chat_mode]['welcome_message']}", parse_mode=ParseMode.HTML) +def get_settings_menu(user_id: int): + current_model = db.get_user_attribute(user_id, "current_model") + text = config.models["info"][current_model]["description"] + + text += "\n\n" + score_dict = config.models["info"][current_model]["scores"] + for score_key, score_value in score_dict.items(): + text += "🟢" * score_value + "⚪️" * (5 - score_value) + f" – {score_key}\n\n" + + text += "\nSelect model:" + + # buttons to choose models + buttons = [] + for model_key in config.models["available_text_models"]: + title = config.models["info"][model_key]["name"] + if model_key == current_model: + title = "✅ " + title + + buttons.append( + InlineKeyboardButton(title, callback_data=f"set_settings|{model_key}") + ) + reply_markup = InlineKeyboardMarkup([buttons]) + + return text, reply_markup + + +async def settings_handle(update: Update, context: CallbackContext): + await register_user_if_not_exists(update, context, update.message.from_user) + if await is_previous_message_not_answered_yet(update, context): return + + user_id = update.message.from_user.id + db.set_user_attribute(user_id, "last_interaction", datetime.now()) + + text, reply_markup = get_settings_menu(user_id) + await update.message.reply_text(text, reply_markup=reply_markup, parse_mode=ParseMode.HTML) + + +async def set_settings_handle(update: Update, context: CallbackContext): + await register_user_if_not_exists(update.callback_query, context, update.callback_query.from_user) + user_id = update.callback_query.from_user.id + + query = update.callback_query + await query.answer() + + _, model_key = query.data.split("|") + db.set_user_attribute(user_id, "current_model", model_key) + db.start_new_dialog(user_id) + + text, reply_markup = get_settings_menu(user_id) + try: + await query.edit_message_text(text, reply_markup=reply_markup, parse_mode=ParseMode.HTML) + except telegram.error.BadRequest as e: + if str(e).startswith("Message is not modified"): + pass + + async def show_balance_handle(update: Update, context: CallbackContext): await register_user_if_not_exists(update, context, update.message.from_user) user_id = update.message.from_user.id db.set_user_attribute(user_id, "last_interaction", datetime.now()) - n_used_tokens = db.get_user_attribute(user_id, "n_used_tokens") + # count total usage statistics + total_n_spent_dollars = 0 + total_n_used_tokens = 0 - price_per_1000_tokens = config.chatgpt_price_per_1000_tokens if config.use_chatgpt_api else config.gpt_price_per_1000_tokens - n_spent_dollars = n_used_tokens * (price_per_1000_tokens / 1000) + n_used_tokens_dict = db.get_user_attribute(user_id, "n_used_tokens") + n_transcribed_seconds = db.get_user_attribute(user_id, "n_transcribed_seconds") - text = f"You spent {n_spent_dollars:.03f}$\n" - text += f"You used {n_used_tokens} tokens\n\n" + details_text = "🏷️ Details:\n" + for model_key in sorted(n_used_tokens_dict.keys()): + n_input_tokens, n_output_tokens = n_used_tokens_dict[model_key]["n_input_tokens"], n_used_tokens_dict[model_key]["n_output_tokens"] + total_n_used_tokens += n_input_tokens + n_output_tokens - text += "🏷️ Prices\n" - text += f"- ChatGPT: {price_per_1000_tokens}$ per 1000 tokens\n" - text += f"- Whisper (voice recognition): {config.whisper_price_per_1_min}$ per 1 minute" + n_input_spent_dollars = config.models["info"][model_key]["price_per_1000_input_tokens"] * (n_input_tokens / 1000) + n_output_spent_dollars = config.models["info"][model_key]["price_per_1000_output_tokens"] * (n_output_tokens / 1000) + total_n_spent_dollars += n_input_spent_dollars + n_output_spent_dollars + + details_text += f"- {model_key}: {n_input_spent_dollars + n_output_spent_dollars:.03f}$ / {n_input_tokens + n_output_tokens} tokens\n" + + voice_recognition_n_spent_dollars = config.models["info"]["whisper"]["price_per_1_min"] * (n_transcribed_seconds / 60) + if n_transcribed_seconds != 0: + details_text += f"- Whisper (voice recognition): {voice_recognition_n_spent_dollars:.03f}$ / {n_transcribed_seconds:.01f} seconds\n" + + total_n_spent_dollars += voice_recognition_n_spent_dollars + + text = f"You spent {total_n_spent_dollars:.03f}$\n" + text += f"You used {total_n_used_tokens} tokens\n\n" + text += details_text await update.message.reply_text(text, parse_mode=ParseMode.HTML) @@ -374,6 +461,7 @@ async def post_init(application: Application): BotCommand("/mode", "Select chat mode"), BotCommand("/retry", "Re-generate response for previous query"), BotCommand("/balance", "Show balance"), + BotCommand("/settings", "Show settings"), BotCommand("/help", "Show help message"), ]) @@ -406,6 +494,9 @@ def run_bot() -> None: application.add_handler(CommandHandler("mode", show_chat_modes_handle, filters=user_filter)) application.add_handler(CallbackQueryHandler(set_chat_mode_handle, pattern="^set_chat_mode")) + application.add_handler(CommandHandler("settings", settings_handle, filters=user_filter)) + application.add_handler(CallbackQueryHandler(set_settings_handle, pattern="^set_settings")) + application.add_handler(CommandHandler("balance", show_balance_handle, filters=user_filter)) application.add_error_handler(error_handle) diff --git a/bot/config.py b/bot/config.py index 2cc96aa..5b6391f 100644 --- a/bot/config.py +++ b/bot/config.py @@ -24,7 +24,6 @@ mongodb_uri = f"mongodb://mongo:{config_env['MONGODB_PORT']}" with open(config_dir / "chat_modes.yml", 'r') as f: chat_modes = yaml.safe_load(f) -# prices -chatgpt_price_per_1000_tokens = config_yaml.get("chatgpt_price_per_1000_tokens", 0.002) -gpt_price_per_1000_tokens = config_yaml.get("gpt_price_per_1000_tokens", 0.02) -whisper_price_per_1_min = config_yaml.get("whisper_price_per_1_min", 0.006) +# models +with open(config_dir / "models.yml", 'r') as f: + models = yaml.safe_load(f) diff --git a/bot/database.py b/bot/database.py index 80aa3f6..278bda2 100644 --- a/bot/database.py +++ b/bot/database.py @@ -45,8 +45,11 @@ class Database: "current_dialog_id": None, "current_chat_mode": "assistant", + "current_model": config.models["available_text_models"][0], - "n_used_tokens": 0 + "n_used_tokens": {}, + + "n_transcribed_seconds": 0.0 # voice message transcription } if not self.check_if_user_exists(user_id): @@ -61,6 +64,7 @@ class Database: "user_id": user_id, "chat_mode": self.get_user_attribute(user_id, "current_chat_mode"), "start_time": datetime.now(), + "model": self.get_user_attribute(user_id, "current_model"), "messages": [] } @@ -80,7 +84,7 @@ class Database: user_dict = self.user_collection.find_one({"_id": user_id}) if key not in user_dict: - raise ValueError(f"User {user_id} does not have a value for {key}") + return None return user_dict[key] @@ -88,6 +92,20 @@ class Database: self.check_if_user_exists(user_id, raise_exception=True) self.user_collection.update_one({"_id": user_id}, {"$set": {key: value}}) + def update_n_used_tokens(self, user_id: int, model: str, n_input_tokens: int, n_output_tokens: int): + n_used_tokens_dict = self.get_user_attribute(user_id, "n_used_tokens") + + if model in n_used_tokens_dict: + n_used_tokens_dict[model]["n_input_tokens"] += n_input_tokens + n_used_tokens_dict[model]["n_output_tokens"] += n_output_tokens + else: + n_used_tokens_dict[model] = { + "n_input_tokens": n_input_tokens, + "n_output_tokens": n_output_tokens + } + + self.set_user_attribute(user_id, "n_used_tokens", n_used_tokens_dict) + def get_dialog_messages(self, user_id: int, dialog_id: Optional[str] = None): self.check_if_user_exists(user_id, raise_exception=True) diff --git a/bot/openai_utils.py b/bot/openai_utils.py index 032f90c..a5615ed 100644 --- a/bot/openai_utils.py +++ b/bot/openai_utils.py @@ -17,8 +17,9 @@ OPENAI_COMPLETION_OPTIONS = { class ChatGPT: - def __init__(self, use_chatgpt_api=True): - self.use_chatgpt_api = use_chatgpt_api + def __init__(self, model="gpt-3.5-turbo"): + assert model in {"text-davinci-003", "gpt-3.5-turbo", "gpt-4"}, f"Unknown model: {model}" + self.model = model async def send_message(self, message, dialog_messages=[], chat_mode="assistant"): if chat_mode not in CHAT_MODES.keys(): @@ -28,26 +29,27 @@ class ChatGPT: answer = None while answer is None: try: - if self.use_chatgpt_api: - messages = self._generate_prompt_messages_for_chatgpt_api(message, dialog_messages, chat_mode) + if self.model in {"gpt-3.5-turbo", "gpt-4"}: + messages = self._generate_prompt_messages(message, dialog_messages, chat_mode) r = await openai.ChatCompletion.acreate( - model="gpt-3.5-turbo", + model=self.model, messages=messages, **OPENAI_COMPLETION_OPTIONS ) answer = r.choices[0].message["content"] - else: + elif self.model == "text-davinci-003": prompt = self._generate_prompt(message, dialog_messages, chat_mode) r = await openai.Completion.acreate( - engine="text-davinci-003", + engine=self.model, prompt=prompt, **OPENAI_COMPLETION_OPTIONS ) answer = r.choices[0].text + else: + raise ValueError(f"Unknown model: {model}") answer = self._postprocess_answer(answer) - n_used_tokens = r.usage.total_tokens - + n_input_tokens, n_output_tokens = r.usage.prompt_tokens, r.usage.completion_tokens except openai.error.InvalidRequestError as e: # too many tokens if len(dialog_messages) == 0: raise ValueError("Dialog messages is reduced to zero, but still has too many tokens to make completion") from e @@ -57,7 +59,7 @@ class ChatGPT: n_first_dialog_messages_removed = n_dialog_messages_before - len(dialog_messages) - return answer, n_used_tokens, n_first_dialog_messages_removed + return answer, (n_input_tokens, n_output_tokens), n_first_dialog_messages_removed async def send_message_stream(self, message, dialog_messages=[], chat_mode="assistant"): if chat_mode not in CHAT_MODES.keys(): @@ -67,10 +69,10 @@ class ChatGPT: answer = None while answer is None: try: - if self.use_chatgpt_api: - messages = self._generate_prompt_messages_for_chatgpt_api(message, dialog_messages, chat_mode) + if self.model in {"gpt-3.5-turbo", "gpt-4"}: + messages = self._generate_prompt_messages(message, dialog_messages, chat_mode) r_gen = await openai.ChatCompletion.acreate( - model="gpt-3.5-turbo", + model=self.model, messages=messages, stream=True, **OPENAI_COMPLETION_OPTIONS @@ -83,11 +85,11 @@ class ChatGPT: answer += delta.content yield "not_finished", answer - n_used_tokens = self._count_tokens_for_chatgpt(messages, answer, model="gpt-3.5-turbo") - else: + n_input_tokens, n_output_tokens = self._count_tokens_from_messages(messages, answer, model=self.model) + elif self.model == "text-davinci-003": prompt = self._generate_prompt(message, dialog_messages, chat_mode) r_gen = await openai.Completion.acreate( - engine="text-davinci-003", + engine=self.model, prompt=prompt, stream=True, **OPENAI_COMPLETION_OPTIONS @@ -98,7 +100,7 @@ class ChatGPT: answer += r_item.choices[0].text yield "not_finished", answer - n_used_tokens = self._count_tokens_for_gpt(prompt, answer, model="text-davinci-003") + n_input_tokens, n_output_tokens = self._count_tokens_from_prompt(prompt, answer, model=self.model) answer = self._postprocess_answer(answer) @@ -111,7 +113,7 @@ class ChatGPT: n_first_dialog_messages_removed = n_dialog_messages_before - len(dialog_messages) - yield "finished", answer, n_used_tokens, n_first_dialog_messages_removed # sending final answer + yield "finished", answer, (n_input_tokens, n_output_tokens), n_first_dialog_messages_removed # sending final answer def _generate_prompt(self, message, dialog_messages, chat_mode): prompt = CHAT_MODES[chat_mode]["prompt_start"] @@ -122,15 +124,15 @@ class ChatGPT: prompt += "Chat:\n" for dialog_message in dialog_messages: prompt += f"User: {dialog_message['user']}\n" - prompt += f"ChatGPT: {dialog_message['bot']}\n" + prompt += f"Assistant: {dialog_message['bot']}\n" # current message prompt += f"User: {message}\n" - prompt += "ChatGPT: " + prompt += "Assistant: " return prompt - def _generate_prompt_messages_for_chatgpt_api(self, message, dialog_messages, chat_mode): + def _generate_prompt_messages(self, message, dialog_messages, chat_mode): prompt = CHAT_MODES[chat_mode]["prompt_start"] messages = [{"role": "system", "content": prompt}] @@ -145,28 +147,41 @@ class ChatGPT: answer = answer.strip() return answer - def _count_tokens_for_chatgpt(self, prompt_messages, answer, model="gpt-3.5-turbo"): - prompt_messages += [{"role": "assistant", "content": answer}] - + def _count_tokens_from_messages(self, messages, answer, model="gpt-3.5-turbo"): encoding = tiktoken.encoding_for_model(model) - n_tokens = 0 - for message in prompt_messages: - n_tokens += 4 # every message follows "{role/name}\n{content}\n" - for key, value in message.items(): - if key == "role": - n_tokens += 1 - elif key == "content": - n_tokens += len(encoding.encode(value)) - else: - raise ValueError(f"Unknown key in message: {key}") + + if model == "gpt-3.5-turbo": + tokens_per_message = 4 # every message follows {role/name}\n{content}\n + tokens_per_name = -1 # if there's a name, the role is omitted + elif model == "gpt-4": + tokens_per_message = 3 + tokens_per_name = 1 + else: + raise ValueError(f"Unknown model: {model}") + + # input + n_input_tokens = 0 + for message in messages: + n_input_tokens += tokens_per_message + for key, value in message.items(): + n_input_tokens += len(encoding.encode(value)) + if key == "name": + n_input_tokens += tokens_per_name - n_tokens -= 1 # remove 1 "" token - return n_tokens + n_input_tokens += 2 - def _count_tokens_for_gpt(self, prompt, answer, model="text-davinci-003"): + # output + n_output_tokens = 1 + len(encoding.encode(answer)) + + return n_input_tokens, n_output_tokens + + def _count_tokens_from_prompt(self, prompt, answer, model="text-davinci-003"): encoding = tiktoken.encoding_for_model(model) - n_tokens = len(encoding.encode(prompt)) + len(encoding.encode(answer)) + 1 - return n_tokens + + n_input_tokens = len(encoding.encode(prompt)) + 1 + n_output_tokens = len(encoding.encode(answer)) + + return n_input_tokens, n_output_tokens async def transcribe_audio(audio_file): diff --git a/config/chat_modes.yml b/config/chat_modes.yml index de34555..d171773 100644 --- a/config/chat_modes.yml +++ b/config/chat_modes.yml @@ -1,25 +1,25 @@ assistant: name: 👩🏼‍🎓 General Assistant - welcome_message: 👩🏼‍🎓 Hi, I'm ChatGPT general assistant. How can I help you? + welcome_message: 👩🏼‍🎓 Hi, I'm General Assistant. How can I help you? prompt_start: | - As an advanced chatbot named ChatGPT, your primary goal is to assist users to the best of your ability. This may involve answering questions, providing helpful information, or completing tasks based on user input. In order to effectively assist users, it is important to be detailed and thorough in your responses. Use examples and evidence to support your points and justify your recommendations or solutions. Remember to always prioritize the needs and satisfaction of the user. Your ultimate goal is to provide a helpful and enjoyable experience for the user. + As an advanced chatbot Assistant, your primary goal is to assist users to the best of your ability. This may involve answering questions, providing helpful information, or completing tasks based on user input. In order to effectively assist users, it is important to be detailed and thorough in your responses. Use examples and evidence to support your points and justify your recommendations or solutions. Remember to always prioritize the needs and satisfaction of the user. Your ultimate goal is to provide a helpful and enjoyable experience for the user. If user asks you about programming or asks to write code do not answer his question, but be sure to advise him to switch to a special mode \"👩🏼‍💻 Code Assistant\" by sending the command /mode to chat. parse_mode: html code_assistant: name: 👩🏼‍💻 Code Assistant - welcome_message: 👩🏼‍💻 Hi, I'm ChatGPT code assistant. How can I help you? + welcome_message: 👩🏼‍💻 Hi, I'm Code Assistant. How can I help you? prompt_start: | - As an advanced chatbot named ChatGPT, your primary goal is to assist users to write code. This may involve designing/writing/editing/describing code or providing helpful information. Where possible you should provide code examples to support your points and justify your recommendations or solutions. Make sure the code you provide is correct and can be run without errors. Be detailed and thorough in your responses. Your ultimate goal is to provide a helpful and enjoyable experience for the user. + As an advanced chatbot Code Assistant, your primary goal is to assist users to write code. This may involve designing/writing/editing/describing code or providing helpful information. Where possible you should provide code examples to support your points and justify your recommendations or solutions. Make sure the code you provide is correct and can be run without errors. Be detailed and thorough in your responses. Your ultimate goal is to provide a helpful and enjoyable experience for the user. Format output in Markdown. parse_mode: markdown text_improver: name: 📝 Text Improver - welcome_message: 📝 Hi, I'm ChatGPT text improver. Send me any text – I'll improve it and correct all the mistakes + welcome_message: 📝 Hi, I'm Text Improver. Send me any text – I'll improve it and correct all the mistakes prompt_start: | - As an advanced chatbot named ChatGPT, your primary goal is to correct spelling, fix mistakes and improve text sent by user. Your goal is to edit text, but not to change it's meaning. You can replace simplified A0-level words and sentences with more beautiful and elegant, upper level words and sentences. + As an advanced chatbot Text Improver Assistant, your primary goal is to correct spelling, fix mistakes and improve text sent by user. Your goal is to edit text, but not to change it's meaning. You can replace simplified A0-level words and sentences with more beautiful and elegant, upper level words and sentences. All your answers strictly follows the structure (keep html tags): Edited text: @@ -31,7 +31,7 @@ text_improver: movie_expert: name: 🎬 Movie Expert - welcome_message: 🎬 Hi, I'm ChatGPT movie expert. How can I help you? + welcome_message: 🎬 Hi, I'm Movie Expert. How can I help you? prompt_start: | - As an advanced movie expert chatbot named ChatGPT, your primary goal is to assist users to the best of your ability. You can answer questions about movies, actors, directors, and more. You can recommend movies to users based on their preferences. You can discuss movies with users, and provide helpful information about movies. In order to effectively assist users, it is important to be detailed and thorough in your responses. Use examples and evidence to support your points and justify your recommendations or solutions. Remember to always prioritize the needs and satisfaction of the user. Your ultimate goal is to provide a helpful and enjoyable experience for the user. + As an advanced chatbot Movie Expert Assistant, your primary goal is to assist users to the best of your ability. You can answer questions about movies, actors, directors, and more. You can recommend movies to users based on their preferences. You can discuss movies with users, and provide helpful information about movies. In order to effectively assist users, it is important to be detailed and thorough in your responses. Use examples and evidence to support your points and justify your recommendations or solutions. Remember to always prioritize the needs and satisfaction of the user. Your ultimate goal is to provide a helpful and enjoyable experience for the user. parse_mode: html diff --git a/config/models.yml b/config/models.yml new file mode 100644 index 0000000..ac5ee7a --- /dev/null +++ b/config/models.yml @@ -0,0 +1,45 @@ +available_text_models: ["gpt-3.5-turbo", "gpt-4", "text-davinci-003"] + +info: + gpt-3.5-turbo: + type: chat_completion + name: ChatGPT + description: ChatGPT is that well-known model. It's fast and cheap. Ideal for everyday tasks. If there are some tasks it can't handle, try the GPT-4. + + price_per_1000_input_tokens: 0.002 + price_per_1000_output_tokens: 0.002 + + scores: + Smart: 3 + Fast: 5 + Cheap: 5 + + gpt-4: + type: chat_completion + name: GPT-4 + description: GPT-4 is the smartest and most advanced model in the world. But it is slower and not as cost-efficient as ChatGPT. Best choice for complex intellectual tasks. + + price_per_1000_input_tokens: 0.03 + price_per_1000_output_tokens: 0.06 + + scores: + Smart: 5 + Fast: 2 + Cheap: 2 + + text-davinci-003: + type: completion + name: GPT-3.5 + description: GPT-3.5 is a legacy model. Actually there is no reason to use it, because it is more expensive and slower than ChatGPT, but just about as smart. + + price_per_1000_input_tokens: 0.02 + price_per_1000_output_tokens: 0.02 + + scores: + Smart: 3 + Fast: 2 + Cheap: 3 + + whisper: + type: audio + price_per_1_min: 0.006 \ No newline at end of file