__version__ = (1, 1, 0) # ©️ Fixyres, 2026-2030 # 🌐 https://github.com/Fixyres/FModules # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # 🔑 http://www.apache.org/licenses/LICENSE-2.0 # meta banner: https://raw.githubusercontent.com/Fixyres/FModules/refs/heads/main/assets/akinator/banner.png # meta developer: @NFModules # meta fhsdesc: game, funny, guess, question game # requires: curl_cffi import html import re import inspect from curl_cffi import requests from .. import loader, utils from telethon.tl.functions.messages import TranslateTextRequest from telethon.tl.types import TextWithEntities class AsyncAki: def __init__(self, lang="en", cm=False): self.user_lang = lang aki_langs =[ "en", "ar", "cn", "de", "es", "fr", "il", "it", "jp", "kr", "nl", "pl", "pt", "ru", "tr", "id" ] if lang in aki_langs: self.aki_lang = lang elif lang in ["uk", "uz", "kk", "be"]: self.aki_lang = "ru" else: self.aki_lang = "en" self.cm = str(cm).lower() self.uri = f"https://{self.aki_lang}.akinator.com" self.session = requests.AsyncSession(impersonate="chrome120") self.session.headers.update({ "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8", "Accept-Language": "ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7", "Sec-Fetch-Dest": "document", "Sec-Fetch-Mode": "navigate", "Sec-Fetch-Site": "none", "Sec-Fetch-User": "?1", "Upgrade-Insecure-Requests": "1" }) self.win = False self.prog = "0.0" self.step = "0" self.slp = "" self.name = None self.desc = "" self.photo = "https://raw.githubusercontent.com/Fixyres/FModules/refs/heads/main/assets/akinator/banner.png" self.q = "" async def _req(self, ep, data=None): method = "POST" if data else "GET" url = f"{self.uri}/{ep}" headers = {} if data: headers["x-requested-with"] = "XMLHttpRequest" headers["Content-Type"] = "application/x-www-form-urlencoded" r = await self.session.request(method, url, data=data, headers=headers) if r.status_code != 200: raise Exception(f"AE{r.status_code}") try: return r.json() except Exception: return r.text async def start(self): t = await self._req("game", {"sid": 1, "cm": self.cm}) if "technical problem" in (t if isinstance(t, str) else "").lower(): raise Exception("ATP") ses_m = re.search(r"session['\"]\)\.val\(['\"](.+?)['\"]", t if isinstance(t, str) else str(t)) sig_m = re.search(r"signature['\"]\)\.val\(['\"](.+?)['\"]", t if isinstance(t, str) else str(t)) q_m = re.search(r'class="question-text".*?>(.+?)

', t if isinstance(t, str) else str(t), re.S) if not ses_m or not sig_m or not q_m: raise Exception("AECF") self.ses = ses_m.group(1) self.sig = sig_m.group(1) self.q = html.unescape(q_m.group(1)).strip() async def answer(self, a): data = { "step": self.step, "progression": self.prog, "sid": 1, "cm": self.cm, "answer": a, "step_last_proposition": self.slp, "session": self.ses, "signature": self.sig } res = await self._req("answer", data) self._upd(res) async def exclude(self): data = { "step": self.step, "progression": self.prog, "sid": 1, "cm": self.cm, "session": self.ses, "signature": self.sig, "forward_answer": "1" } try: res = await self._req("exclude", data) if isinstance(res, dict) and res.get("question"): self.win = False self.name = None self._upd(res) else: self.win = False self.name = None self.q = None except Exception: self.win, self.name, self.q = False, None, None def _upd(self, d): if not isinstance(d, dict): return if d.get("id_proposition"): self.win = True self.name = html.unescape(d.get("name_proposition", "")) self.desc = html.unescape(d.get("description_proposition", "")) self.photo = d.get("photo", "https://raw.githubusercontent.com/Fixyres/FModules/refs/heads/main/assets/akinator/banner.png") self.step = str(d.get("step", self.step)) self.slp = self.step if "progression" in d and d["progression"] is not None: self.prog = str(d["progression"]) elif d.get("question"): self.win = False self.q = html.unescape(d.get("question", "")) self.prog = str(d.get("progression", "0")) self.step = str(d.get("step", "0")) self.slp = str(d.get("step_last_proposition", self.slp)) else: self.win = False self.name = None self.q = None async def close(self): try: if inspect.iscoroutinefunction(self.session.close): await self.session.close() else: res = self.session.close() if inspect.isawaitable(res): await res except Exception: pass @loader.tds class Akinator(loader.Module): '''Akinator will guess any character you have in mind, you just need to answer a couple of questions.''' strings = { "name": "Akinator", "lang": "en", "child_mode": "Child mode. If enabled, it will be easier to guess 18+ heroes.", "start": "Start", "text": "Guess any character you have in mind, and click on the Start button.", "yes": "Yes", "no": "No", "idk": "I don't know", "probably": "Probably", "probably_not": "Probably not", "this_is": "This is {name}\n{description}", "this_is_no_desc": "This is {name}", "not_right": "Not right", "failed": "Failed to guess the character." } strings_ru = { "lang": "ru", "_cls_doc": "Акинатор угадает любого вами загаданного персонажа.", "child_mode": "Детский режим. Сложнее отгадать 18+ героев.", "start": "Начать", "text": "Задумайте персонажа, и нажмите начать.", "yes": "Да", "no": "Нет", "idk": "Не знаю", "probably": "Возможно", "probably_not": "Скорее нет", "this_is": "Это {name}\n{description}", "this_is_no_desc": "Это {name}", "not_right": "Это не он", "failed": "Не удалось угадать персонажа." } strings_ua = { "lang": "uk", "_cls_doc": "Акінатор вгадає будь-якого персонажа.", "child_mode": "Дитячий режим. Складніше відгадати 18+ героїв.", "start": "Почати", "text": "Загадайте персонажа, і натисніть почати.", "yes": "Так", "no": "Ні", "idk": "Не знаю", "probably": "Можливо", "probably_not": "Швидше ні", "this_is": "Це {name}\n{description}", "this_is_no_desc": "Це {name}", "not_right": "Це не він", "failed": "Не вдалося вгадати персонажа." } strings_de = { "lang": "de", "_cls_doc": "Akinator errät jeden Charakter, den du dir vorstellst.", "child_mode": "Kindermodus. Wenn aktiviert, wird es schwieriger sein, 18+ Helden zu erraten.", "start": "Start", "text": "Denk dir einen Charakter aus und klicke auf Start.", "yes": "Ja", "no": "Nein", "idk": "Ich weiß nicht", "probably": "Wahrscheinlich", "probably_not": "Wahrscheinlich nicht", "this_is": "Das ist {name}\n{description}", "this_is_no_desc": "Das ist {name}", "not_right": "Das ist er nicht", "failed": "Charakter konnte nicht erraten werden." } strings_fr = { "lang": "fr", "_cls_doc": "Akinator devinera n'importe quel personnage.", "child_mode": "Mode enfant. Héros 18+ plus difficiles à deviner.", "start": "Commencer", "text": "Pensez à un personnage et cliquez sur Commencer.", "yes": "Oui", "no": "Non", "idk": "Je ne sais pas", "probably": "Probablement", "probably_not": "Probablement pas", "this_is": "C'est {name}\n{description}", "this_is_no_desc": "C'est {name}", "not_right": "Ce n'est pas lui", "failed": "Impossible de deviner." } strings_jp = { "lang": "ja", "_cls_doc": "アキネーターはあなたが考えているキャラクターを当てます。", "child_mode": "子供モード。有効にすると、18歳以上のキャラクターを推測するのが難しくなります。", "start": "開始", "text": "キャラクターを思い浮かべて開始。", "yes": "はい", "no": "いいえ", "idk": "わかりません", "probably": "おそらく", "probably_not": "おそらく違う", "this_is": "これは {name}\n{description}", "this_is_no_desc": "これは {name}", "not_right": "違います", "failed": "推測できませんでした。" } strings_uz = { "lang": "uz", "_cls_doc": "Akinator siz o'ylagan har qanday qahramonni topadi.", "child_mode": "Bolalar rejimi. Yoqilgan bo'lsa, 18+ qahramonlarni topish qiyinroq bo'ladi.", "start": "Boshlash", "text": "Qahramonni o'ylang va Boshlash tugmasini bosing.", "yes": "Ha", "no": "Yo'q", "idk": "Bilmayman", "probably": "Ehtimol", "probably_not": "Ehtimol yo'q", "this_is": "Bu {name}\n{description}", "this_is_no_desc": "Bu {name}", "not_right": "Bu u emas", "failed": "Qahramonni topib bo'lmadi." } strings_kz = { "lang": "kk", "_cls_doc": "Акинатор сіз ойлаған кез келген кейіпкерді табады.", "child_mode": "Балалар режимі. Қосылған болса, 18+ кейіпкерлерді табу қиынырақ болады.", "start": "Бастау", "text": "Кейіпкерді ойлаңыз және Бастау түймесін басыңыз.", "yes": "Иә", "no": "Жоқ", "idk": "Білмеймін", "probably": "Мүмкін", "probably_not": "Мүмкін емес", "this_is": "Бұл {name}\n{description}", "this_is_no_desc": "Бұл {name}", "not_right": "Бұл ол емес", "failed": "Кейіпкерді таба алмадық." } def __init__(self): self.config = loader.ModuleConfig( loader.ConfigValue( "child_mode", False, lambda: self.strings["child_mode"], validator=loader.validators.Boolean() ) ) self.games = {} async def _tr(self, client, text, to_lang): if not text: return text try: request = TranslateTextRequest( to_lang=to_lang, text=[TextWithEntities(text=text, entities=[])] ) result = await client(request) return result.result[0].text except Exception: return text @loader.command( ru_doc="- начать игру.", ua_doc="- почати гру.", de_doc="- Spiel starten.", fr_doc="- commencer le jeu.", jp_doc="- ゲームを開始します。", uz_doc="- o'yinni boshlash.", kz_doc="- ойынды бастау.", ) async def akinator(self, message): '''- start the game.''' try: aki = AsyncAki(self.strings["lang"], self.config["child_mode"]) await aki.start() self.games.setdefault(message.chat_id, {})[message.id] = aki await self.inline.form( text=self.strings["text"], message=message, photo="https://raw.githubusercontent.com/Fixyres/FModules/refs/heads/main/assets/akinator/banner.png", reply_markup={ "text": self.strings["start"], "callback": self._cb, "args": (message,) } ) except Exception as e: await utils.answer(message, f"{e}") async def _cb(self, call, message): aki = self.games.get(message.chat_id, {}).get(message.id) if aki: await self._sq(call, aki, message) async def _sq(self, call, aki, message): if aki.aki_lang != aki.user_lang: question = await self._tr(message.client, aki.q, aki.user_lang) else: question = aki.q markup = [[ {"text": self.strings["yes"], "callback": self._ans, "args": (0, message)}, {"text": self.strings["no"], "callback": self._ans, "args": (1, message)}, {"text": self.strings["idk"], "callback": self._ans, "args": (2, message)} ],[ {"text": self.strings["probably"], "callback": self._ans, "args": (3, message)}, {"text": self.strings["probably_not"], "callback": self._ans, "args": (4, message)} ] ] await call.edit( f"{question}", photo="https://raw.githubusercontent.com/Fixyres/FModules/refs/heads/main/assets/akinator/banner.png", reply_markup=markup ) async def _show_guess(self, call, aki, message): if aki.aki_lang != aki.user_lang: name = await self._tr(message.client, aki.name, aki.user_lang) desc = await self._tr(message.client, aki.desc, aki.user_lang) if aki.desc else aki.desc else: name = aki.name desc = aki.desc if desc: text = self.strings["this_is"].format(name=name, description=desc) else: text = self.strings["this_is_no_desc"].format(name=name) markup = [[ {"text": self.strings["yes"], "callback": self._fin, "args": (True, message, text, aki.photo)}, {"text": self.strings["not_right"], "callback": self._rej, "args": (message,)} ] ] await call.edit( text, photo=aki.photo, reply_markup=markup ) async def _ans(self, call, answer_id, message): aki = self.games.get(message.chat_id, {}).get(message.id) if not aki: return await aki.answer(answer_id) if aki.win: await self._show_guess(call, aki, message) elif getattr(aki, 'q', None): await self._sq(call, aki, message) else: await self._fin(call, False, message, "", "") async def _rej(self, call, message): aki = self.games.get(message.chat_id, {}).get(message.id) if not aki: return try: await aki.exclude() except Exception: pass if aki.win: await self._show_guess(call, aki, message) elif getattr(aki, 'q', None): await self._sq(call, aki, message) else: await self._fin(call, False, message, "", "") async def _fin(self, call, won, message, text, photo): aki = self.games.get(message.chat_id, {}).pop(message.id, None) if aki: await aki.close() if won: await call.edit(text, photo=photo, reply_markup=[]) else: await call.edit( self.strings["failed"], photo="https://raw.githubusercontent.com/Fixyres/FModules/refs/heads/main/assets/akinator/idk.png", reply_markup=[] )