__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=[]
)