{"id":484354,"date":"2026-06-20T03:22:15","date_gmt":"2026-06-20T03:22:15","guid":{"rendered":"https:\/\/savepearlharbor.com\/?p=484354"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=484354","title":{"rendered":"\u041f\u0438\u0448\u0435\u043c \u0447\u0430\u0442 \u0441 \u0418\u0418 \u0434\u0435\u0432\u0443\u0448\u043a\u043e\u0439 \u043d\u0430 Python: LLM-\u0440\u043e\u0443\u0442\u0438\u043d\u0433, \u0434\u043e\u043b\u0433\u043e\u0441\u0440\u043e\u0447\u043d\u0430\u044f \u043f\u0430\u043c\u044f\u0442\u044c \u0438 \u0433\u043e\u043b\u043e\u0441 \u0437\u0430 \u0432\u044b\u0445\u043e\u0434\u043d\u044b\u0435"},"content":{"rendered":"<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p><strong>19 \u0438\u044e\u043d\u044f 2026 \u042f\u043d\u0434\u0435\u043a\u0441 <\/strong><a href=\"https:\/\/yandex.ru\/company\/news\/19-06-2026-02\" rel=\"noopener noreferrer nofollow\"><strong>\u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043b \u0418\u0418-\u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0435\u0439 \u0432 \u0410\u043b\u0438\u0441\u0435<\/strong><\/a> \u2014 \u0431\u043e\u043b\u044c\u0448\u0435 30 \u0441\u043e\u0431\u0435\u0441\u0435\u0434\u043d\u0438\u043a\u043e\u0432 \u0441 \u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u043e\u043c, \u043e\u0442 \u0431\u043b\u043e\u0433\u0435\u0440\u043e\u0432 \u0434\u043e \u0430\u043d\u0438\u043c\u0435-\u0433\u0435\u0440\u043e\u0438\u043d\u044c; \u043e\u043d\u0438 \u0437\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u044e\u0442 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442, \u0430 \u0433\u043e\u043b\u043e\u0441\u0430 \u0438 \u043e\u0431\u0441\u0443\u0436\u0434\u0435\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0441\u0442\u0435\u0439 \u043e\u0431\u0435\u0449\u0430\u044e\u0442 \u043f\u043e\u0437\u0436\u0435. \u0416\u0430\u043d\u0440 \u043d\u0435 \u043d\u043e\u0432\u044b\u0439: \u00ab\u0447\u0430\u0442 \u0441 \u0418\u0418-\u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0435\u043c\u00bb \u0443\u0436\u0435 \u043f\u0430\u0440\u0443 \u043b\u0435\u0442 \u0442\u044f\u043d\u0443\u0442 Character.AI, Replika \u0438 \u0434\u0435\u0441\u044f\u0442\u043a\u0438 Telegram-\u0431\u043e\u0442\u043e\u0432. \u0423\u0434\u0438\u0432\u043b\u044f\u0435\u0442 \u0434\u0440\u0443\u0433\u043e\u0435 \u2014 \u043d\u0430\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u0430\u043b\u043e \u043d\u0443\u0436\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u0442\u0430\u043a\u043e\u0435 \u0441\u0430\u043c\u043e\u043c\u0443. \u041f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c \u0432\u0441\u0435\u0433\u043e \u0442\u0440\u0438 \u043a\u0443\u0431\u0438\u043a\u0430: \u044f\u0437\u044b\u043a\u043e\u0432\u0430\u044f \u043c\u043e\u0434\u0435\u043b\u044c, \u043f\u0430\u043c\u044f\u0442\u044c \u0438 \u0441\u0438\u043d\u0442\u0435\u0437 \u0440\u0435\u0447\u0438.<\/p>\n<p>\u0421\u0434\u0435\u043b\u0430\u0442\u044c <strong>\u0447\u0430\u0442 \u0441 \u0418\u0418 \u0434\u0435\u0432\u0443\u0448\u043a\u043e\u0439<\/strong> (\u0438\u043b\u0438 \u043b\u044e\u0431\u044b\u043c \u0434\u0440\u0443\u0433\u0438\u043c \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0435\u043c) \u043f\u043e\u0432\u0435\u0440\u0445 \u0433\u043e\u0442\u043e\u0432\u043e\u0439 \u043c\u043e\u0434\u0435\u043b\u0438 \u2014 \u044d\u0442\u043e \u0433\u0440\u0443\u0431\u043e \u0433\u043e\u0432\u043e\u0440\u044f \u0432\u0435\u0447\u0435\u0440 \u0440\u0430\u0431\u043e\u0442\u044b. \u0410 \u0432\u043e\u0442 \u0437\u0430\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0435\u0433\u043e \u043d\u0435 \u0437\u0430\u0431\u044b\u0432\u0430\u0442\u044c \u0432\u0447\u0435\u0440\u0430\u0448\u043d\u0438\u0439 \u0440\u0430\u0437\u0433\u043e\u0432\u043e\u0440, \u043d\u0435 \u043e\u0442\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043d\u0430 \u0440\u043e\u0432\u043d\u043e\u043c \u043c\u0435\u0441\u0442\u0435, \u0433\u043e\u0432\u043e\u0440\u0438\u0442\u044c \u0433\u043e\u043b\u043e\u0441\u043e\u043c \u0438 \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u043d\u0435 \u0440\u0430\u0437\u043e\u0440\u0438\u0442\u044c \u0432\u0430\u0441 \u043d\u0430 \u0441\u0447\u0435\u0442\u0430\u0445 \u0437\u0430 API \u2014 \u043d\u0430 \u044d\u0442\u043e \u0443\u0445\u043e\u0434\u0438\u0442 \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u0431\u043e\u043b\u044c\u0448\u0435 \u0432\u0440\u0435\u043c\u0435\u043d\u0438. \u042f \u043f\u043e\u043b\u0433\u043e\u0434\u0430 \u0432\u043e\u0436\u0443\u0441\u044c \u0441 \u0442\u0430\u043a\u0438\u043c \u0431\u043e\u0442\u043e\u043c \u0432 \u043f\u0440\u043e\u0434\u0435; \u043d\u0438\u0436\u0435 \u2014 \u0440\u0430\u0431\u043e\u0447\u0438\u0439 \u043a\u0430\u0440\u043a\u0430\u0441 \u043d\u0430 Python \u0438 \u0447\u0435\u0442\u044b\u0440\u0435 \u043c\u0435\u0441\u0442\u0430, \u0433\u0434\u0435 \u043c\u044b \u0441\u043f\u043e\u0442\u044b\u043a\u0430\u043b\u0438\u0441\u044c.<\/p>\n<h3>\u041a\u0430\u0440\u043a\u0430\u0441: \u043e\u0434\u0438\u043d \u0437\u0430\u043f\u0440\u043e\u0441 \u043a \u043c\u043e\u0434\u0435\u043b\u0438<\/h3>\n<p>\u041b\u044e\u0431\u043e\u0439 \u0447\u0430\u0442 \u0441 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0435\u043c \u2014 \u044d\u0442\u043e \u043e\u0434\u0438\u043d \u0438 \u0442\u043e\u0442 \u0436\u0435 \u0446\u0438\u043a\u043b: \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0439 \u043f\u0440\u043e\u043c\u043f\u0442, \u0438\u0441\u0442\u043e\u0440\u0438\u044f \u0434\u0438\u0430\u043b\u043e\u0433\u0430, \u043d\u043e\u0432\u0430\u044f \u0440\u0435\u043f\u043b\u0438\u043a\u0430 \u2014 \u0438 \u043e\u0442\u0432\u0435\u0442 \u043c\u043e\u0434\u0435\u043b\u0438. \u0421\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0439 \u043f\u0440\u043e\u043c\u043f\u0442 \u0443\u0434\u043e\u0431\u043d\u043e \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u0441\u043b\u043e\u044f\u043c\u0438: \u043a\u0442\u043e \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436, \u0441 \u043a\u0435\u043c \u0433\u043e\u0432\u043e\u0440\u0438\u0442, \u0432 \u043a\u0430\u043a\u043e\u043c \u0444\u043e\u0440\u043c\u0430\u0442\u0435 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442. \u0425\u043e\u0434\u0438\u0442\u044c \u043a \u043c\u043e\u0434\u0435\u043b\u044f\u043c \u044f \u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0438\u0442\u0430\u044e \u0447\u0435\u0440\u0435\u0437 OpenAI-\u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u044b\u0439 \u043a\u043b\u0438\u0435\u043d\u0442 \u2014 \u0442\u043e\u0442 \u0436\u0435 OpenRouter \u0434\u0430\u0451\u0442 \u0435\u0434\u0438\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043a \u0434\u0435\u0441\u044f\u0442\u043a\u0430\u043c \u043c\u043e\u0434\u0435\u043b\u0435\u0439, \u0438 \u043c\u0435\u043d\u044f\u0442\u044c \u0438\u0445 \u043c\u043e\u0436\u043d\u043e \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u043e\u0439.<\/p>\n<p><strong>\u041a\u043b\u044e\u0447 \u0434\u043b\u044f OpenRouter.<\/strong> \u0417\u0430\u0432\u0435\u0434\u0438\u0442\u0435 \u043d\u0430 <a href=\"https:\/\/openrouter.ai\/keys\" rel=\"noopener noreferrer nofollow\">openrouter.ai\/keys<\/a> (\u0432\u0445\u043e\u0434 \u0447\u0435\u0440\u0435\u0437 Google\/GitHub \u2192 <em>Create Key<\/em>), \u043f\u043e\u043b\u043e\u0436\u0438\u0442\u0435 \u043f\u0430\u0440\u0443 \u0434\u043e\u043b\u043b\u0430\u0440\u043e\u0432 \u043d\u0430 \u0431\u0430\u043b\u0430\u043d\u0441 \u0438\u043b\u0438 \u0432\u043e\u0437\u044c\u043c\u0438\u0442\u0435 \u043c\u043e\u0434\u0435\u043b\u044c \u0441 \u043f\u043e\u043c\u0435\u0442\u043a\u043e\u0439 <em>free<\/em>. \u041a\u043b\u044e\u0447 \u0434\u0435\u0440\u0436\u0438\u043c \u043d\u0435 \u0432 \u043a\u043e\u0434\u0435, \u0430 \u0432 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f <code>OPENROUTER_API_KEY<\/code>.<\/p>\n<pre><code class=\"python\">from openai import AsyncOpenAIclient = AsyncOpenAI(base_url=\"https:\/\/openrouter.ai\/api\/v1\", api_key=API_KEY)def build_system_prompt(char, user):    # \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0439 \u043f\u0440\u043e\u043c\u043f\u0442 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u043c \u0441\u043b\u043e\u044f\u043c\u0438: \u043f\u0435\u0440\u0441\u043e\u043d\u0430 -&gt; \u043a\u0442\u043e \u0441\u043e\u0431\u0435\u0441\u0435\u0434\u043d\u0438\u043a -&gt; \u0444\u043e\u0440\u043c\u0430\u0442 \u043e\u0442\u0432\u0435\u0442\u0430    return \"\\n\".join([        f\"\u0422\u044b \u2014 {char['name']}, {char['persona']}.\",        f\"\u0421\u043e\u0431\u0435\u0441\u0435\u0434\u043d\u0438\u043a: {user['name']}.\",        \"\u041e\u0442\u0432\u0435\u0447\u0430\u0439 2\u20134 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u043c\u0438. \u0414\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u2014 \u0432 *\u0437\u0432\u0451\u0437\u0434\u043e\u0447\u043a\u0430\u0445*, \u043c\u044b\u0441\u043b\u0438 \u2014 \u0432 ~\u0442\u0438\u043b\u044c\u0434\u0430\u0445~.\",    ])async def reply(char, user, history, user_msg, model):    messages = [{\"role\": \"system\", \"content\": build_system_prompt(char, user)}]    messages += history                       # \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u0440\u0435\u043f\u043b\u0438\u043a\u0438 \u0434\u0438\u0430\u043b\u043e\u0433\u0430    messages.append({\"role\": \"user\", \"content\": user_msg})    resp = await client.chat.completions.create(model=model, messages=messages)    return resp.choices[0].message.content<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:87px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u042d\u0442\u043e \u0443\u0436\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0439 \u0447\u0430\u0442. \u0412\u0441\u0451 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0435 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u0434\u0430\u043b\u044c\u0448\u0435.<\/p>\n<h3>\u041a\u0430\u043a\u0443\u044e \u043c\u043e\u0434\u0435\u043b\u044c \u0432\u044b\u0431\u0440\u0430\u0442\u044c?<\/h3>\n<p>\u041f\u043e\u0434 \u043a\u0430\u0436\u0434\u0443\u044e \u0440\u0435\u043f\u043b\u0438\u043a\u0443 \u043c\u043e\u0434\u0435\u043b\u044c \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u043f\u043e \u0434\u0432\u0443\u043c \u043f\u0440\u0438\u0437\u043d\u0430\u043a\u0430\u043c \u2014 \u0442\u0430\u0440\u0438\u0444 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438 \u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440 \u0441\u0446\u0435\u043d\u044b. \u0411\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u043c \u2014 \u0434\u0435\u0448\u0451\u0432\u0443\u044e, \u043f\u043b\u0430\u0442\u043d\u044b\u043c \u2014 \u043f\u043e\u0443\u043c\u043d\u0435\u0435, \u0434\u043b\u044f \u043e\u0442\u043a\u0440\u043e\u0432\u0435\u043d\u043d\u044b\u0445 \u0441\u0446\u0435\u043d \u2014 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e, \u0431\u0435\u0437 \u0436\u0451\u0441\u0442\u043a\u043e\u0439 \u0446\u0435\u043d\u0437\u0443\u0440\u044b. \u042f \u0434\u0435\u0440\u0436\u0443 \u044d\u0442\u043e \u043e\u0431\u044b\u0447\u043d\u044b\u043c \u0441\u043b\u043e\u0432\u0430\u0440\u0451\u043c, \u0431\u0435\u0437 \u0434\u0435\u0440\u0435\u0432\u0430 \u0438\u0437 <code>if<\/code>:<\/p>\n<pre><code class=\"python\">MODEL_BY_ROUTE = {    (\"free\", \"\u043e\u0431\u044b\u0447\u043d\u044b\u0439\"): \"\u0434\u0435\u0448\u0451\u0432\u0430\u044f-\u0431\u0430\u0437\u043e\u0432\u0430\u044f-\u043c\u043e\u0434\u0435\u043b\u044c\",    (\"free\", \"\u0433\u043e\u0440\u044f\u0447\u0438\u0439\"): \"\u043c\u043e\u0434\u0435\u043b\u044c-\u0431\u0435\u0437-\u0436\u0451\u0441\u0442\u043a\u043e\u0439-\u0446\u0435\u043d\u0437\u0443\u0440\u044b\",    (\"paid\", \"\u043e\u0431\u044b\u0447\u043d\u044b\u0439\"): \"\u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f-\u043c\u043e\u0434\u0435\u043b\u044c\",    (\"paid\", \"\u0433\u043e\u0440\u044f\u0447\u0438\u0439\"): \"\u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f-\u043c\u043e\u0434\u0435\u043b\u044c\",}def select_model(tier: str, mode: str = \"\u043e\u0431\u044b\u0447\u043d\u044b\u0439\") -&gt; str:    return MODEL_BY_ROUTE.get((tier, mode), MODEL_BY_ROUTE[(\"free\", \"\u043e\u0431\u044b\u0447\u043d\u044b\u0439\")])# \u0438 \u043f\u043e\u0442\u043e\u043b\u043e\u043a \u0434\u043b\u0438\u043d\u044b \u043e\u0442\u0432\u0435\u0442\u0430 \u0434\u0435\u0440\u0436\u0438\u043c \u043f\u043e \u0442\u0430\u0440\u0438\u0444\u0443 \u2014 \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u043f\u043b\u0430\u0442\u0438\u0442\u044c \u0437\u0430 \u043b\u0438\u0448\u043d\u0438\u0435 \u0442\u043e\u043a\u0435\u043d\u044bMAX_TOKENS = {\"free\": 1500, \"paid\": 3500}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0423\u043c\u043d\u044b\u0435 \u043c\u043e\u0434\u0435\u043b\u0438 \u0441\u0442\u043e\u044f\u0442 \u0432 \u0440\u0430\u0437\u044b \u0434\u043e\u0440\u043e\u0436\u0435 \u0434\u0435\u0448\u0451\u0432\u044b\u0445, \u0430 \u043b\u0438\u043c\u0438\u0442 \u043d\u0430 \u0434\u043b\u0438\u043d\u0443 \u043e\u0442\u0432\u0435\u0442\u0430 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u0431\u044c\u0435\u0442 \u043f\u043e \u043a\u043e\u0448\u0435\u043b\u044c\u043a\u0443. \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u043e\u0432\u044b\u0439 \u0442\u0430\u0440\u0438\u0444 \u0438\u043b\u0438 \u0440\u0435\u0436\u0438\u043c \u2014 \u043e\u0434\u043d\u0430 \u0441\u0442\u0440\u043e\u043a\u0430 \u0432 \u0441\u043b\u043e\u0432\u0430\u0440\u0435, \u0430 \u043d\u0435 \u043d\u043e\u0432\u0430\u044f \u0432\u0435\u0442\u043a\u0430 \u0432 \u043a\u043e\u0434\u0435.<\/p>\n<h4>\u041f\u043e\u0434\u0432\u043e\u0434\u043d\u044b\u0439 \u043a\u0430\u043c\u0435\u043d\u044c 1: \u043c\u043e\u0434\u0435\u043b\u044c \u043e\u0442\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043e\u0442\u0432\u0435\u0447\u0430\u0442\u044c<\/h4>\n<p>\u0420\u0430\u043d\u043e \u0438\u043b\u0438 \u043f\u043e\u0437\u0434\u043d\u043e \u0444\u0438\u043b\u044c\u0442\u0440 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 \u0441\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043d\u0430 \u0431\u0435\u0437\u043e\u0431\u0438\u0434\u043d\u043e\u0439 \u0444\u0440\u0430\u0437\u0435, \u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0443\u043f\u0440\u0451\u0442\u0441\u044f \u0432 \u0441\u0442\u0435\u043d\u0443 \u00ab\u0418\u0437\u0432\u0438\u043d\u0438\u0442\u0435, \u044f \u043d\u0435 \u043c\u043e\u0433\u0443\u2026\u00bb. \u041d\u0430 \u043d\u0430\u0448\u0435\u043c \u0442\u0440\u0430\u0444\u0438\u043a\u0435 \u0442\u0430\u043a\u0438\u0435 \u043b\u043e\u0436\u043d\u044b\u0435 \u043e\u0442\u043a\u0430\u0437\u044b \u2014 \u044d\u0442\u043e 2\u20138% \u043e\u0442\u0432\u0435\u0442\u043e\u0432 (\u0443 \u0432\u0430\u0441 \u0446\u0438\u0444\u0440\u0430 \u0431\u0443\u0434\u0435\u0442 \u0441\u0432\u043e\u044f). \u0421\u043e\u0432\u0441\u0435\u043c \u0438\u0445 \u043d\u0435 \u0443\u0431\u0440\u0430\u0442\u044c, \u043d\u043e \u0431\u043e\u043b\u044c\u0448\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u043c\u043e\u0436\u043d\u043e \u0432\u0435\u0440\u043d\u0443\u0442\u044c, \u043f\u0440\u0438\u0447\u0451\u043c \u0434\u0451\u0448\u0435\u0432\u043e. \u041b\u043e\u0433\u0438\u043a\u0430 \u2014 \u043e\u0442 \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u043e\u0433\u043e \u043a \u0434\u043e\u0440\u043e\u0433\u043e\u043c\u0443: \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u0441\u043f\u0430\u0441\u0442\u0438 \u0442\u043e, \u0447\u0442\u043e \u043c\u043e\u0434\u0435\u043b\u044c \u0443\u0436\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u043b\u0430 \u0434\u043e \u043e\u0442\u043a\u0430\u0437\u0430, \u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u0435\u0441\u043b\u0438 \u043d\u0435 \u0432\u044b\u0448\u043b\u043e \u2014 \u0437\u043e\u0432\u0451\u043c \u0437\u0430\u043f\u0430\u0441\u043d\u0443\u044e \u043c\u043e\u0434\u0435\u043b\u044c.<\/p>\n<pre><code class=\"python\">REFUSAL_MARKERS = (\"\u044f \u043d\u0435 \u043c\u043e\u0433\u0443\", \"i can't\", \"as an ai\", \"\u7533\u3057\u8a33\")def salvage(text: str) -&gt; str | None:    # \u0447\u0430\u0441\u0442\u043e \u043f\u0435\u0440\u0435\u0434 \u0444\u0440\u0430\u0437\u043e\u0439-\u043e\u0442\u043a\u0430\u0437\u043e\u043c \u0443\u0436\u0435 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0439 \u0442\u0435\u043a\u0441\u0442 \u2014 \u043e\u0442\u0440\u0435\u0437\u0430\u0435\u043c \u0445\u0432\u043e\u0441\u0442    low = text.lower()    for m in REFUSAL_MARKERS:        i = low.rfind(m)        if i &gt; 150:            text = text[:i].rstrip()            break    return text if len(text) &gt;= 150 else Noneasync def reply_with_rescue(tier, messages):    raw = await call_model(PRIMARY_MODEL, messages)    if not is_refusal(raw):        return raw    if good := salvage(raw):                  # 0 \u043b\u0438\u0448\u043d\u0438\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432        return good    if tier == \"paid\":                        # \u0437\u0430\u043f\u0430\u0441\u043d\u0443\u044e \u043c\u043e\u0434\u0435\u043b\u044c \u2014 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043b\u0430\u0442\u043d\u044b\u043c        return await call_model(BACKUP_MODEL, messages)    return in_character_refusal()             # \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u043c \u2014 \u043c\u044f\u0433\u043a\u0438\u0439 \u043e\u0442\u043a\u0430\u0437 \u0432 \u0440\u043e\u043b\u0438<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u043e\u043d\u043a\u043e\u0441\u0442\u044c, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u044b \u043f\u043e\u043d\u044f\u043b\u0438 \u043d\u0435 \u0441\u0440\u0430\u0437\u0443: \u0437\u0430\u043f\u0430\u0441\u043d\u0443\u044e \u043c\u043e\u0434\u0435\u043b\u044c \u0438\u043c\u0435\u0435\u0442 \u0441\u043c\u044b\u0441\u043b \u0437\u0432\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043b\u0430\u0442\u043d\u044b\u043c. \u0418\u043d\u0430\u0447\u0435 \u043a\u0430\u0436\u0434\u044b\u0439 \u043e\u0442\u043a\u0430\u0437 \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0432 \u043b\u0438\u0448\u043d\u0438\u0439 \u0437\u0430\u043f\u0440\u043e\u0441, \u0430 \u043d\u0430 \u043e\u0431\u044a\u0451\u043c\u0435 \u044d\u0442\u043e \u0437\u0430\u043c\u0435\u0442\u043d\u0430\u044f \u0441\u0442\u0430\u0442\u044c\u044f \u0440\u0430\u0441\u0445\u043e\u0434\u043e\u0432. \u0411\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u043c \u043e\u0442\u0434\u0430\u0451\u043c \u043c\u044f\u0433\u043a\u0438\u0439 \u043e\u0442\u043a\u0430\u0437 \u00ab\u0432 \u0440\u043e\u043b\u0438\u00bb \u2014 \u043e\u043d \u0432\u0441\u0451 \u0440\u0430\u0432\u043d\u043e \u043f\u0440\u0438\u044f\u0442\u043d\u0435\u0435 \u0441\u044b\u0440\u043e\u0439 \u0441\u0442\u0435\u043d\u044b. \u0426\u0435\u043f\u043e\u0447\u043a\u0443 \u043c\u043e\u0436\u043d\u043e \u0443\u0441\u043b\u043e\u0436\u043d\u0438\u0442\u044c: \u043f\u0435\u0440\u0432\u044b\u043c \u0448\u0430\u0433\u043e\u043c, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u0440\u0438\u0441\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 \u0443 \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u0430, \u0435\u0441\u043b\u0438 \u043e\u043d \u044d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442.<\/p>\n<h3>\u041a\u0430\u043a \u0434\u0430\u0442\u044c \u0447\u0430\u0442-\u0431\u043e\u0442\u0443 \u0434\u043e\u043b\u0433\u043e\u0441\u0440\u043e\u0447\u043d\u0443\u044e \u043f\u0430\u043c\u044f\u0442\u044c?<\/h3>\n<p>\u041f\u0430\u043c\u044f\u0442\u044c \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u0438\u0437 \u0442\u0440\u0451\u0445 \u0441\u043b\u043e\u0451\u0432, \u0438 \u043a\u0430\u0436\u0434\u044b\u0439 \u0437\u0430\u043a\u0440\u044b\u0432\u0430\u0435\u0442 \u0441\u0432\u043e\u044e \u0437\u0430\u0434\u0430\u0447\u0443. \u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u0440\u0435\u043f\u043b\u0438\u043a\u0438 \u0434\u0435\u0440\u0436\u0438\u043c \u0432 Redis \u2014 \u044d\u0442\u043e \u0431\u044b\u0441\u0442\u0440\u043e. \u0427\u0442\u043e\u0431\u044b \u00ab\u0432\u0441\u043f\u043e\u043c\u043d\u0438\u0442\u044c, \u0447\u0442\u043e \u0431\u044b\u043b\u043e \u0441\u0442\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u043d\u0430\u0437\u0430\u0434\u00bb, \u043d\u0443\u0436\u0435\u043d \u043f\u043e\u0438\u0441\u043a \u043f\u043e \u0441\u043c\u044b\u0441\u043b\u0443, \u0430 \u043d\u0435 \u043f\u043e \u0441\u043b\u043e\u0432\u0430\u043c \u2014 \u0435\u0433\u043e \u0434\u0430\u0451\u0442 \u0432\u0435\u043a\u0442\u043e\u0440\u043d\u0430\u044f \u0431\u0430\u0437\u0430 \u0432\u0440\u043e\u0434\u0435 ChromaDB. \u0410 \u0447\u0442\u043e\u0431\u044b \u0434\u043b\u0438\u043d\u043d\u0430\u044f \u0438\u0441\u0442\u043e\u0440\u0438\u044f \u043d\u0435 \u0440\u0430\u0437\u0434\u0443\u0432\u0430\u043b\u0430 \u043f\u0440\u043e\u043c\u043f\u0442 \u0434\u043e \u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u043e\u0441\u0442\u0438, \u0435\u0451 \u043f\u0435\u0440\u0438\u043e\u0434\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u0436\u0438\u043c\u0430\u044e\u0442 \u0432 \u043d\u0430\u043a\u043e\u043f\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0441\u0430\u043c\u043c\u0430\u0440\u0438. \u041f\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u043d\u0438 \u043e\u0434\u0438\u043d \u0441\u043b\u043e\u0439 \u043d\u0435 \u0432\u044b\u0432\u043e\u0437\u0438\u0442.<\/p>\n<pre><code class=\"python\"># \u0441\u043b\u043e\u0439 1 \u2014 \u0433\u043e\u0440\u044f\u0447\u0438\u0439: \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 N \u0440\u0435\u043f\u043b\u0438\u043a \u0432 Redis (\u0436\u0438\u0432\u0451\u0442 \u043c\u0438\u043b\u043b\u0438\u0441\u0435\u043a\u0443\u043d\u0434\u044b)async def remember_turn(r, key, text):    await r.rpush(key, text)    await r.ltrim(key, -20, -1)               # \u0434\u0435\u0440\u0436\u0438\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u0445\u0432\u043e\u0441\u0442# \u0441\u043b\u043e\u0439 2 \u2014 \u0441\u043c\u044b\u0441\u043b\u043e\u0432\u043e\u0439: \u0438\u0449\u0435\u043c \u0440\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d\u043e\u0435 \u043f\u0440\u043e\u0448\u043b\u043e\u0435 \u043f\u043e \u0441\u043c\u044b\u0441\u043b\u0443, \u0430 \u043d\u0435 \u043f\u043e \u0441\u043b\u043e\u0432\u0430\u043cdef recall(collection, query, k=3):    res = collection.query(query_texts=[query], n_results=k)    docs, dists = res[\"documents\"][0], res[\"distances\"][0]    return [d for d, dist in zip(docs, dists) if dist &lt;= 0.55]   # \u043f\u043e\u0440\u043e\u0433 \u0431\u043b\u0438\u0437\u043e\u0441\u0442\u0438# \u0441\u043b\u043e\u0439 3 \u2014 \u043d\u0430\u043a\u043e\u043f\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0441\u0430\u043c\u043c\u0430\u0440\u0438: \u0441\u0436\u0438\u043c\u0430\u0435\u043c \u0441\u0442\u0430\u0440\u043e\u0435 + \u0434\u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u043d\u043e\u0432\u043e\u0435async def update_summary(prev_summary, recent_msgs):    prompt = f\"\u0414\u043e\u043f\u043e\u043b\u043d\u0438 summary \u043d\u043e\u0432\u044b\u043c\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u044f\u043c\u0438.\\n\u0411\u044b\u043b\u043e: {prev_summary}\\n\u0414\u0438\u0430\u043b\u043e\u0433: {recent_msgs}\"    summary = await llm_summarize(prompt)    return summary[:900]                       # \u0434\u0435\u0440\u0436\u0438\u043c \u0432 \u0440\u0430\u043c\u043a\u0430\u0445, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0440\u0430\u0437\u0434\u0443\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u043c\u043f\u0442<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u043e\u0440\u043e\u0433 \u0431\u043b\u0438\u0437\u043e\u0441\u0442\u0438 <code>0.55<\/code> \u0438 \u043f\u043e\u0442\u043e\u043b\u043e\u043a \u0441\u0430\u043c\u043c\u0430\u0440\u0438 \u0432 <code>900<\/code> \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432 \u2014 \u044d\u0442\u043e \u043d\u0430\u0448\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, \u043f\u043e\u0434 \u0441\u0432\u043e\u0439 \u044d\u043c\u0431\u0435\u0434\u0434\u0435\u0440 \u043f\u043e\u0434\u0431\u0438\u0440\u0430\u0439\u0442\u0435 \u0441\u0432\u043e\u0438. \u0418 \u043f\u0440\u043e \u0438\u0437\u043e\u043b\u044f\u0446\u0438\u044e: \u0438\u043c\u044f \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438 \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 id \u0441\u0435\u0441\u0441\u0438\u0438 (<code>mem_{user}_{char}_{session}<\/code>), \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0444\u0430\u043a\u0442\u044b \u0438\u0437 \u043e\u0434\u043d\u043e\u0439 \u0441\u0446\u0435\u043d\u044b \u043d\u0435 \u043f\u0440\u043e\u0442\u0435\u043a\u0430\u044e\u0442 \u0432 \u0434\u0440\u0443\u0433\u0443\u044e \u2014 \u0432 \u043e\u0434\u043d\u043e\u0439 \u0441\u0446\u0435\u043d\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0441\u0442\u0443\u0434\u0435\u043d\u0442\u043a\u0430, \u0432 \u0434\u0440\u0443\u0433\u043e\u0439 \u043f\u0438\u043b\u043e\u0442, \u0441\u043c\u0435\u0448\u0438\u0432\u0430\u0442\u044c \u0438\u0445 \u043d\u0435\u043b\u044c\u0437\u044f.<\/p>\n<h4>\u041f\u043e\u0434\u0432\u043e\u0434\u043d\u044b\u0439 \u043a\u0430\u043c\u0435\u043d\u044c 2: ChromaDB \u0438 \u043f\u0430\u043c\u044f\u0442\u044c \u0441\u0435\u0440\u0432\u0435\u0440\u0430<\/h4>\n<p>\u041a\u043e\u0433\u0434\u0430 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0439 \u043c\u043d\u043e\u0433\u043e \u2014 \u0430 \u0443 \u043d\u0430\u0441 \u0438\u0445 \u0437\u0430 \u0447\u0435\u0442\u044b\u0440\u0435 \u0442\u044b\u0441\u044f\u0447\u0438, \u043f\u043e \u043e\u0434\u043d\u043e\u0439 \u043d\u0430 \u0441\u0446\u0435\u043d\u0443, \u2014 ChromaDB \u0441\u043f\u043e\u0441\u043e\u0431\u0435\u043d \u043d\u0435\u0437\u0430\u043c\u0435\u0442\u043d\u043e \u0441\u044a\u0435\u0441\u0442\u044c \u0432\u0441\u044e \u043f\u0430\u043c\u044f\u0442\u044c \u0445\u043e\u0441\u0442\u0430. \u041d\u0430 \u0432\u0435\u0442\u043a\u0435 <strong>0.5.x<\/strong> \u043a\u044d\u0448 \u0441\u0435\u0433\u043c\u0435\u043d\u0442\u043e\u0432 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u043d\u0435\u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d: \u043f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0438 \u043a \u0441\u0432\u0435\u0436\u0435\u0439 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438 RSS \u043f\u043e\u0434\u0440\u0430\u0441\u0442\u0430\u0435\u0442 \u0438 \u043e\u0431\u0440\u0430\u0442\u043d\u043e \u043d\u0435 \u043e\u0442\u0434\u0430\u0451\u0442\u0441\u044f. \u0423 \u043d\u0430\u0441 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0432\u044b\u0435\u0434\u0430\u043b \u0441\u0432\u043e\u0439 \u0431\u044e\u0434\u0436\u0435\u0442 \u0437\u0430 \u043f\u0430\u0440\u0443-\u0442\u0440\u043e\u0439\u043a\u0443 \u0434\u043d\u0435\u0439 \u0438 \u0443\u0445\u043e\u0434\u0438\u043b \u0432 OOM \u043f\u043e \u043d\u043e\u0447\u0430\u043c. \u0415\u0441\u043b\u0438 \u0432\u044b \u0437\u0430\u0441\u0442\u0440\u044f\u043b\u0438 \u043d\u0430 0.5.x, \u043b\u0435\u0447\u0438\u0442\u0441\u044f \u0434\u0432\u0443\u043c\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u043c\u0438 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u2014 \u0438 \u043f\u043e\u043c\u043d\u0438\u0442\u0435, \u0447\u0442\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u043e\u043d\u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430, <code>restart<\/code> \u0438\u0445 \u043d\u0435 \u043f\u043e\u0434\u0445\u0432\u0430\u0442\u0438\u0442:<\/p>\n<pre><code class=\"yaml\"># docker-compose.yml \u2014 \u043e\u0431\u0445\u043e\u0434\u043d\u043e\u0439 \u043f\u0443\u0442\u044c, \u0435\u0441\u043b\u0438 \u0441\u0438\u0434\u0438\u0442\u0435 \u043d\u0430 0.5.xchromadb:  image: chromadb\/chroma:0.5.18  environment:    CHROMA_SEGMENT_CACHE_POLICY: \"LRU\"    CHROMA_MEMORY_LIMIT_BYTES: \"10737418240\"   # 10 \u0413\u0438\u0411<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041c\u043e\u0439 \u0441\u043e\u0432\u0435\u0442 &#8212; \u043d\u0435 \u043f\u044b\u0442\u0430\u0442\u044c\u0441\u044f \u043f\u0440\u0430\u0432\u0438\u0442\u044c 0.5.x, \u0430 \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c\u0441\u044f \u043d\u0430 \u0432\u0435\u0442\u043a\u0443 <strong>1.x<\/strong>: \u0435\u0451 \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u0430\u043b\u0438 \u043d\u0430 Rust, \u0438 \u044d\u0442\u043e \u0441\u043e\u0432\u0441\u0435\u043c \u0434\u0440\u0443\u0433\u043e\u0439 \u0440\u0430\u0437\u0433\u043e\u0432\u043e\u0440. \u041f\u043e\u0441\u043b\u0435 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 RSS \u0443 \u043d\u0430\u0441 \u0443\u043f\u0430\u043b \u0441 ~14 \u0413\u0411 \u0434\u043e ~300 \u041c\u0438\u0411, \u0441\u0432\u043e\u043f \u043d\u0430 \u0445\u043e\u0441\u0442\u0435 \u2014 \u0441\u043e 100% \u0434\u043e 2%, \u0430 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u043f\u043e\u0438\u0441\u043a\u0430 \u0438 \u0434\u0438\u0441\u0442\u0430\u043d\u0446\u0438\u0438 \u043e\u0441\u0442\u0430\u043b\u0438\u0441\u044c \u043f\u0440\u0435\u0436\u043d\u0438\u043c\u0438 (\u0442\u0435 \u0436\u0435 4,5 \u0442\u044b\u0441\u044f\u0447\u0438 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0439 \u043d\u0430 \u043c\u0435\u0441\u0442\u0435). \u0422\u043e\u043b\u044c\u043a\u043e \u0443 \u0430\u043f\u0433\u0440\u0435\u0439\u0434\u0430 \u0435\u0441\u0442\u044c \u0442\u0440\u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u043d\u0430\u043f\u043e\u0440\u043e\u043b\u0438\u0441\u044c:<\/p>\n<ul>\n<li>\n<p><strong>\u041c\u0438\u0433\u0440\u0430\u0446\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u043e\u0434\u043d\u043e\u0441\u0442\u043e\u0440\u043e\u043d\u043d\u044f\u044f.<\/strong> \u041d\u0430 \u043f\u0435\u0440\u0432\u043e\u043c \u0441\u0442\u0430\u0440\u0442\u0435 1.x \u043d\u0435\u043e\u0431\u0440\u0430\u0442\u0438\u043c\u043e \u043f\u0440\u0430\u0432\u0438\u0442 \u0441\u0445\u0435\u043c\u0443 sqlite \u2014 \u043e\u0442\u043a\u0430\u0442\u0438\u0442\u044c\u0441\u044f \u043d\u0430 0.5.x \u043f\u043e\u0432\u0435\u0440\u0445 \u0442\u0440\u043e\u043d\u0443\u0442\u043e\u0433\u043e \u0442\u043e\u043c\u0430 \u0443\u0436\u0435 \u043d\u0435 \u0432\u044b\u0439\u0434\u0435\u0442. \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0431\u044d\u043a\u0430\u043f (\u0443 \u043d\u0430\u0441 \u2014 tar \u0432 S3), \u043f\u043e\u0442\u043e\u043c \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435.<\/p>\n<\/li>\n<li>\n<p><strong>\u041a\u043b\u0438\u0435\u043d\u0442 \u0438 \u0441\u0435\u0440\u0432\u0435\u0440 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043e\u0434\u043d\u0438\u043c \u0434\u0435\u043f\u043b\u043e\u0435\u043c.<\/strong> \u0421\u0442\u0430\u0440\u044b\u0439 \u043a\u043b\u0438\u0435\u043d\u0442 \u043f\u0440\u043e\u0442\u0438\u0432 \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043f\u0430\u0434\u0430\u0435\u0442 \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u043c \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0438 \u043a \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438. \u0423 \u043d\u0430\u0441 \u0432\u0435\u0440\u0441\u0438\u0438 \u043e\u0434\u043d\u0430\u0436\u0434\u044b \u0440\u0430\u0437\u044a\u0435\u0445\u0430\u043b\u0438\u0441\u044c \u0432 \u043f\u0440\u043e\u0434\u0435 \u2014 \u044d\u0442\u043e \u0441\u0442\u043e\u0438\u043b\u043e \u0434\u0432\u0435\u043d\u0430\u0434\u0446\u0430\u0442\u0438 \u0447\u0430\u0441\u043e\u0432 \u0442\u0438\u0445\u043e\u0439 \u043f\u043e\u0442\u0435\u0440\u0438 \u043f\u0430\u043c\u044f\u0442\u0438, \u043f\u043e\u043a\u0430 \u0447\u0430\u0441\u0442\u044c \u0432\u043e\u0440\u043a\u0435\u0440\u043e\u0432 \u043f\u0438\u0441\u0430\u043b\u0430 \u0432 \u043f\u0443\u0441\u0442\u043e\u0442\u0443.<\/p>\n<\/li>\n<li>\n<p><strong>\u041b\u0438\u043c\u0438\u0442 \u0444\u0430\u0439\u043b\u043e\u0432\u044b\u0445 \u0434\u0435\u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0440\u043e\u0432.<\/strong> Rust-\u0432\u0435\u0440\u0441\u0438\u044f \u0434\u0435\u0440\u0436\u0438\u0442 \u043f\u043e sqlite-\u0444\u0430\u0439\u043b\u0443 \u043d\u0430 \u0441\u0435\u0433\u043c\u0435\u043d\u0442; \u043d\u0430 \u0442\u044b\u0441\u044f\u0447\u0430\u0445 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0439 \u043e\u043d\u0430 \u043f\u0440\u043e\u0431\u0438\u0432\u0430\u0435\u0442 \u0434\u0435\u0444\u043e\u043b\u0442\u043d\u044b\u0439 <code>nofile=1024<\/code>, \u0441\u0435\u0440\u0432\u0435\u0440 \u0432\u0441\u0442\u0430\u0451\u0442 \u043d\u0430\u043c\u0435\u0440\u0442\u0432\u043e \u2014 \u0430 \u043a\u043b\u0438\u0435\u043d\u0442 1.x \u0432\u0434\u043e\u0431\u0430\u0432\u043e\u043a \u0437\u0430\u0448\u0438\u0432\u0430\u0435\u0442 \u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0439 \u0442\u0430\u0439\u043c\u0430\u0443\u0442, \u0438 \u0442\u043e\u0433\u0434\u0430 \u0432\u0438\u0441\u043d\u0435\u0442 \u0443\u0436\u0435 \u0432\u0435\u0441\u044c \u0431\u043e\u0442, \u0443 \u0432\u0441\u0435\u0445 \u0441\u0440\u0430\u0437\u0443. \u041b\u0435\u0447\u0438\u0442\u0441\u044f \u043f\u043e\u0434\u043d\u044f\u0442\u0438\u0435\u043c \u043b\u0438\u043c\u0438\u0442\u0430 (\u0442\u043e\u0436\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0435\u0440\u0435\u0437 \u043f\u0435\u0440\u0435\u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435):<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"yaml\">chromadb:  image: chromadb\/chroma:1.5.9  ulimits:    nofile: 262144<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h3>\u041a\u0430\u043a \u043e\u0437\u0432\u0443\u0447\u0438\u0442\u044c \u043e\u0442\u0432\u0435\u0442?<\/h3>\n<p>\u0413\u043e\u043b\u043e\u0441 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0437\u0430 \u0432\u0435\u0447\u0435\u0440: \u0442\u0435\u043a\u0441\u0442 \u0443\u0445\u043e\u0434\u0438\u0442 \u0432 TTS-\u0441\u0435\u0440\u0432\u0438\u0441, \u043e\u0431\u0440\u0430\u0442\u043d\u043e \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 mp3. \u042f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e Inworld TTS, \u043d\u0430 \u043e\u0448\u0438\u0431\u043a\u0435 \u043e\u0442\u043a\u0430\u0442\u044b\u0432\u0430\u044e\u0441\u044c \u043d\u0430 \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u0439 gTTS \u2014 \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0445\u043e\u0442\u044f \u0431\u044b \u0447\u0442\u043e-\u0442\u043e \u0443\u0441\u043b\u044b\u0448\u0430\u043b.<\/p>\n<p><strong>\u041a\u043b\u044e\u0447 \u0434\u043b\u044f Inworld.<\/strong> \u0421\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u0438 <a href=\"https:\/\/platform.inworld.ai\/\" rel=\"noopener noreferrer nofollow\">platform.inworld.ai<\/a> (\u0440\u0430\u0437\u0434\u0435\u043b API Keys) \u2014 \u044d\u0442\u043e \u0441\u0442\u0440\u043e\u043a\u0430 \u0432 Base64, \u043e\u043d\u0430 \u0438\u0434\u0451\u0442 \u0432 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0435 <code>Authorization: Basic<\/code>. \u041a\u043b\u0430\u0434\u0451\u043c \u0432 <code>INWORLD_API_KEY<\/code>, \u0430 <code>voiceId<\/code> \u0431\u0435\u0440\u0451\u043c \u0442\u0430\u043c \u0436\u0435 \u0438\u0437 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0430 \u0433\u043e\u043b\u043e\u0441\u043e\u0432.<\/p>\n<pre><code class=\"python\">import base64, httpxasync def text_to_speech(text, voice_id, lang=\"ru\"):    text = enrich_for_tts(text, lang)          # \u0433\u043e\u0442\u043e\u0432\u0438\u043c \u0442\u0435\u043a\u0441\u0442 (\u0441\u043c. \u043d\u0438\u0436\u0435)    body = {        \"text\": text, \"voiceId\": voice_id, \"modelId\": TTS_MODEL,        \"audioConfig\": {\"encoding\": \"MP3\", \"sampleRateHertz\": 24000},    }    async with httpx.AsyncClient(timeout=30) as c:        r = await c.post(TTS_URL, json=body,                         headers={\"Authorization\": f\"Basic {TTS_KEY}\"})    if r.status_code == 200:        return base64.b64decode(r.json()[\"audioContent\"])    return None                                # \u0434\u0430\u043b\u044c\u0448\u0435 \u2014 \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u0439 \u0437\u0430\u043f\u0430\u0441\u043d\u043e\u0439 gTTS<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h4>\u041f\u043e\u0434\u0432\u043e\u0434\u043d\u044b\u0439 \u043a\u0430\u043c\u0435\u043d\u044c 3: \u0442\u0435\u0433\u0438 \u044d\u043c\u043e\u0446\u0438\u0439 [laugh]\/[sigh] \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442<\/h4>\n<p>\u041f\u043e\u0447\u0442\u0438 \u043a\u0430\u0436\u0434\u044b\u0439 \u0433\u0430\u0439\u0434 \u043f\u043e TTS \u0441\u043e\u0432\u0435\u0442\u0443\u0435\u0442 \u0440\u0430\u0441\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u0442\u0435\u0433\u0438 \u0432\u0440\u043e\u0434\u0435 <code>[laugh]<\/code>, <code>[sigh]<\/code>, <code>[breathe]<\/code>. \u041c\u044b \u0442\u0430\u043a \u0438 \u0441\u0434\u0435\u043b\u0430\u043b\u0438 \u2014 \u0438 \u043a\u0430\u043a\u043e\u0435-\u0442\u043e \u0432\u0440\u0435\u043c\u044f \u043d\u0435\u0434\u043e\u0443\u043c\u0435\u0432\u0430\u043b\u0438, \u043f\u043e\u0447\u0435\u043c\u0443 \u0433\u043e\u043b\u043e\u0441 \u0437\u0432\u0443\u0447\u0438\u0442 \u0440\u043e\u0432\u043d\u043e \u0442\u0430\u043a \u0436\u0435, \u043a\u0430\u043a \u0431\u0435\u0437 \u043d\u0438\u0445. \u041a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e \u0443 <strong>Inworld TTS-1.5 Max<\/strong> \u044d\u0442\u0438\u0445 \u0442\u0435\u0433\u043e\u0432 \u043f\u043e\u043f\u0440\u043e\u0441\u0442\u0443 \u043d\u0435\u0442: \u0442\u0435\u0433 \u043b\u0438\u0431\u043e \u043f\u0440\u043e\u0433\u043b\u0430\u0442\u044b\u0432\u0430\u0435\u0442\u0441\u044f, \u043b\u0438\u0431\u043e \u2014 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u043d\u0430 \u0440\u0443\u0441\u0441\u043a\u043e\u043c \u2014 \u0437\u0430\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432\u0441\u043b\u0443\u0445 \u043a\u0430\u043a \u0442\u0435\u043a\u0441\u0442. \u0423 \u0434\u0440\u0443\u0433\u0438\u0445 \u0434\u0432\u0438\u0436\u043a\u043e\u0432, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 ElevenLabs, \u0430\u0443\u0434\u0438\u043e-\u0442\u0435\u0433\u0438 \u0431\u044b\u0432\u0430\u044e\u0442, \u0442\u0430\u043a \u0447\u0442\u043e \u0441\u0432\u0435\u0440\u044f\u0439\u0442\u0435\u0441\u044c \u0441\u043e \u0441\u0432\u043e\u0438\u043c.<\/p>\n<p>\u042d\u043c\u043e\u0446\u0438\u044e \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u0442\u0435\u043c, \u0447\u0442\u043e \u0434\u0432\u0438\u0436\u043e\u043a \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u0435\u0442:<\/p>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<th>\n<p align=\"left\">\u041f\u0440\u0438\u0451\u043c<\/p>\n<\/th>\n<th>\n<p align=\"left\">\u0427\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442<\/p>\n<\/th>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><code>[laugh]<\/code> <code>[sigh]<\/code> <code>[breathe]<\/code><\/p>\n<\/td>\n<td>\n<p align=\"left\">\u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u2014 \u0442\u0438\u0448\u0438\u043d\u0430 \u0438\u043b\u0438 \u0442\u0435\u043a\u0441\u0442 \u0432\u0441\u043b\u0443\u0445<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><code>*\u0441\u043b\u043e\u0432\u043e*<\/code><\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0443\u0434\u0430\u0440\u0435\u043d\u0438\u0435 \u043d\u0430 \u0441\u043b\u043e\u0432\u0435<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><code>...<\/code> (\u043c\u043d\u043e\u0433\u043e\u0442\u043e\u0447\u0438\u0435)<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u043f\u0430\u0443\u0437\u0430 \u0441 \u043f\u0430\u0434\u0435\u043d\u0438\u0435\u043c \u0438\u043d\u0442\u043e\u043d\u0430\u0446\u0438\u0438<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">SSML <code>&lt;break time=\"0.4s\"\/&gt;<\/code><\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0442\u043e\u0447\u043d\u0430\u044f \u043f\u0430\u0443\u0437\u0430<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">\u0437\u0432\u0443\u043a\u043e\u043f\u043e\u0434\u0440\u0430\u0436\u0430\u043d\u0438\u0435 (<code>ahh<\/code>, <code>mmm<\/code>, <code>ha-ha<\/code>)<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0439 \u0437\u0432\u0443\u043a \u2014 \u0435\u0441\u0442\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u0435\u0435 \u0441\u0438\u043d\u0442\u0435\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e <code>[laugh]<\/code><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><code>temperature<\/code> \/ \u0442\u0435\u043c\u043f \u0440\u0435\u0447\u0438<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u043e\u0431\u0449\u0430\u044f \u0436\u0438\u0432\u043e\u0441\u0442\u044c \u0438 \u044d\u043c\u043e\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>\u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0435\u0440\u0435\u0434 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u043e\u0439 \u0442\u0435\u043a\u0441\u0442 \u043f\u0440\u043e\u0433\u043e\u043d\u044f\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u043f\u0440\u0435\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440: \u0432\u044b\u043a\u0438\u0434\u044b\u0432\u0430\u0435\u043c \u043d\u0435\u0440\u0430\u0431\u043e\u0447\u0438\u0435 \u0442\u0435\u0433\u0438, \u043c\u043d\u043e\u0433\u043e\u0442\u043e\u0447\u0438\u044f \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0432 SSML-\u043f\u0430\u0443\u0437\u044b.<\/p>\n<pre><code class=\"python\">import reFAKE_TAGS = re.compile(r\"\\[(?:laugh|sigh|breathe|moan)\\]\")def enrich_for_tts(text, lang=\"ru\"):    text = FAKE_TAGS.sub(\"\", text)             # \u044d\u0442\u0438 \u0442\u0435\u0433\u0438 \u043e\u0437\u0432\u0443\u0447\u043a\u0430 \u0438\u0433\u043d\u043e\u0440\u0438\u0442\/\u0447\u0438\u0442\u0430\u0435\u0442 \u0432\u0441\u043b\u0443\u0445    text = text.replace(\"...\", '&lt;break time=\"0.3s\"\/&gt;')   # \u043f\u0430\u0443\u0437\u0443 \u0437\u0430\u0434\u0430\u0451\u043c \u0447\u0435\u0440\u0435\u0437 SSML    if \"&lt;break\" in text:        text = f\"&lt;speak&gt;{text}&lt;\/speak&gt;\"    return text<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u044d\u0442\u043e \u043b\u0443\u0447\u0448\u0435 \u043d\u0430 \u0441\u043b\u0443\u0445: \u0442\u0435\u0433, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b\u0434\u0430\u0451\u0442 \u0442\u0438\u0448\u0438\u043d\u0443, \u0432 \u043b\u043e\u0433\u0430\u0445 \u043d\u0435 \u043e\u0442\u043b\u0438\u0447\u0438\u0442\u044c \u043e\u0442 \u0440\u0430\u0431\u043e\u0447\u0435\u0433\u043e \u2014 \u043d\u0443\u0436\u043d\u043e \u0440\u0435\u0430\u043b\u044c\u043d\u043e \u0441\u043b\u0443\u0448\u0430\u0442\u044c \u0430\u0443\u0434\u0438\u043e.<\/p>\n<h3>\u041f\u043e\u0447\u0435\u043c\u0443 \u0441\u0447\u0451\u0442 \u0437\u0430 LLM \u0442\u0430\u043a\u043e\u0439 \u0431\u043e\u043b\u044c\u0448\u043e\u0439?<\/h3>\n<p>\u041f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0434\u043b\u0438\u043d\u043d\u044b\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0439 \u043f\u0440\u043e\u043c\u043f\u0442 \u2014 \u0443 \u043d\u0430\u0441 \u044d\u0442\u043e \u043f\u0435\u0440\u0441\u043e\u043d\u0430, \u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u0438 \u043f\u0430\u043c\u044f\u0442\u044c, \u0441\u0443\u043c\u043c\u0430\u0440\u043d\u043e \u043e\u043a\u043e\u043b\u043e 5K \u0442\u043e\u043a\u0435\u043d\u043e\u0432 \u2014 \u043e\u043f\u043b\u0430\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u043c \u0445\u043e\u0434\u0443 \u0434\u0438\u0430\u043b\u043e\u0433\u0430 \u0437\u0430\u043d\u043e\u0432\u043e. \u041a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u043c\u043f\u0442\u0430 \u0441\u043d\u0438\u043c\u0430\u0435\u0442 \u0441 \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u043e\u0446\u0435\u043d\u0442\u043e\u0432 \u0441\u043e\u0440\u043e\u043a \u0438 \u043f\u043e \u0434\u0435\u043d\u044c\u0433\u0430\u043c, \u0438 \u043f\u043e \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0435. \u041d\u043e \u0434\u0435\u0448\u0451\u0432\u044b\u043c \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0442\u0435\u043b\u0435\u043c \u043e\u043d\u043e \u043d\u0435 \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f, \u0438 \u0442\u0443\u0442 \u0435\u0441\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043d\u044e\u0430\u043d\u0441\u043e\u0432.<\/p>\n<p>\u041f\u0435\u0440\u0432\u044b\u0439: \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u0430\u043c \u043d\u0443\u0436\u0435\u043d \u044f\u0432\u043d\u044b\u0439 \u043c\u0430\u0440\u043a\u0435\u0440 \u043a\u044d\u0448\u0430. \u0411\u0435\u0437 \u043d\u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u043d\u0435\u0434\u0435\u043b\u044e \u0433\u043e\u043d\u044f\u0442\u044c \u043c\u043e\u0434\u0435\u043b\u044c \u0438 \u0432\u0438\u0434\u0435\u0442\u044c \u043d\u043e\u043b\u044c \u043f\u043e\u043f\u0430\u0434\u0430\u043d\u0438\u0439, \u0440\u0435\u0448\u0438\u0432, \u0447\u0442\u043e \u00ab\u043e\u043d\u0430 \u043d\u0435 \u0443\u043c\u0435\u0435\u0442 \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u00bb. \u0423 \u043d\u0430\u0441 \u043e\u0434\u0438\u043d \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440 \u0441 \u044d\u0442\u0438\u043c \u043c\u0430\u0440\u043a\u0435\u0440\u043e\u043c \u043f\u0440\u044b\u0433\u043d\u0443\u043b \u0441 0% \u0434\u043e ~90% \u043f\u043e\u043f\u0430\u0434\u0430\u043d\u0438\u0439; \u0434\u0440\u0443\u0433\u043e\u0439 \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043b \u0438 \u0442\u0430\u043a, \u0431\u0435\u0437 \u0432\u0441\u044f\u043a\u043e\u0433\u043e \u043c\u0430\u0440\u043a\u0435\u0440\u0430, \u043e\u043a\u043e\u043b\u043e 96%.<\/p>\n<pre><code class=\"python\">messages = [    {        \"role\": \"system\",        \"content\": [{            \"type\": \"text\",            \"text\": SYSTEM_PROMPT,                 # \u0434\u043b\u0438\u043d\u043d\u044b\u0439 \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u044b\u0439 \u043f\u0440\u0435\u0444\u0438\u043a\u0441            \"cache_control\": {\"type\": \"ephemeral\"} # \u0431\u0435\u0437 \u043d\u0435\u0433\u043e \u0443 \u0447\u0430\u0441\u0442\u0438 \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u043e\u0432 0% \u043f\u043e\u043f\u0430\u0434\u0430\u043d\u0438\u0439        }],    },    {\"role\": \"user\", \"content\": user_msg},         # \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u044d\u0442\u043e]<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0412\u0442\u043e\u0440\u043e\u0439 \u043d\u044e\u0430\u043d\u0441. \u0415\u0441\u043b\u0438 \u0432\u044b \u0445\u043e\u0434\u0438\u0442\u0435 \u0447\u0435\u0440\u0435\u0437 \u0430\u0433\u0440\u0435\u0433\u0430\u0442\u043e\u0440 \u0432\u0440\u043e\u0434\u0435 OpenRouter, \u043e\u043d \u0431\u0430\u043b\u0430\u043d\u0441\u0438\u0440\u0443\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043c\u0435\u0436\u0434\u0443 \u043d\u043e\u0434\u0430\u043c\u0438, \u0438 \u043d\u0435\u044f\u0432\u043d\u044b\u0439 \u043f\u0440\u0435\u0444\u0438\u043a\u0441\u043d\u044b\u0439 \u043a\u044d\u0448 \u043b\u043e\u043c\u0430\u0435\u0442\u0441\u044f \u2014 \u043b\u0435\u0447\u0438\u0442\u0441\u044f \u043d\u0435 \u043c\u0430\u0440\u043a\u0435\u0440\u043e\u043c, \u0430 \u0437\u0430\u043a\u0440\u0435\u043f\u043b\u0435\u043d\u0438\u0435\u043c \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u0430. \u0418 \u0441\u0440\u0430\u0437\u0443 \u043f\u043e\u0434\u0432\u043e\u0445 \u043f\u043e \u044d\u043a\u043e\u043d\u043e\u043c\u0438\u043a\u0435: \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440 \u0441 \u043a\u044d\u0448\u0435\u043c \u0438\u043d\u043e\u0433\u0434\u0430 \u0434\u043e\u0440\u043e\u0436\u0435 \u043f\u043e \u0432\u0445\u043e\u0434\u043d\u044b\u043c \u0442\u043e\u043a\u0435\u043d\u0430\u043c, \u0442\u0430\u043a \u0447\u0442\u043e \u043d\u0430 \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u043e\u043c \u0442\u0440\u0430\u0444\u0438\u043a\u0435 \u0432\u044b\u0438\u0433\u0440\u044b\u0448 \u043c\u043e\u0436\u0435\u0442 \u0443\u0439\u0442\u0438 \u0432 \u043c\u0438\u043d\u0443\u0441. \u0421\u0447\u0438\u0442\u0430\u0442\u044c \u043d\u0430\u0434\u043e \u043f\u043e \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c\u0443 \u0431\u0438\u043b\u043b\u0438\u043d\u0433\u0443 \u0437\u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u0438\u043d\u0443\u0442 \u0436\u0438\u0432\u043e\u0433\u043e \u0442\u0440\u0430\u0444\u0438\u043a\u0430, \u0430 \u043d\u0435 \u043f\u043e \u0434\u0435\u0441\u044f\u0442\u0438 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u043c \u0432 \u0446\u0438\u043a\u043b\u0435.<\/p>\n<h4>\u041f\u043e\u0434\u0432\u043e\u0434\u043d\u044b\u0439 \u043a\u0430\u043c\u0435\u043d\u044c 4: \u043a\u043e\u0440\u043e\u0442\u043a\u0438\u0439 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0439 \u043f\u0440\u043e\u043c\u043f\u0442 \u0432\u0440\u0451\u0442 \u043f\u0440\u043e \u043a\u044d\u0448<\/h4>\n<p>\u041f\u0435\u0440\u0432\u044b\u0439 \u0440\u0430\u0437 \u043c\u044b \u043c\u0435\u0440\u0438\u043b\u0438 \u043a\u044d\u0448 \u043d\u0430 \u043a\u043e\u0440\u043e\u0442\u043a\u043e\u043c \u043f\u0440\u043e\u043c\u043f\u0442\u0435 \u2014 \u0432\u044b\u0448\u043b\u043e 0% \u043f\u043e\u043f\u0430\u0434\u0430\u043d\u0438\u0439 \u043f\u043e \u0432\u0441\u0435\u043c \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u0430\u043c, \u0438 \u043c\u044b \u0437\u0430\u043f\u0438\u0441\u0430\u043b\u0438 \u0438\u0445 \u0432 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u044e \u00ab\u043d\u0435 \u0443\u043c\u0435\u044e\u0442\u00bb. \u041e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c, \u0443 \u043a\u044d\u0448\u0430 \u0435\u0441\u0442\u044c \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u0430\u044f \u0434\u043b\u0438\u043d\u0430 \u043f\u0440\u0435\u0444\u0438\u043a\u0441\u0430: \u043d\u0438\u0436\u0435 \u043d\u0435\u0451 \u043e\u043d \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0435 \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f. \u041d\u0430 \u043f\u0440\u043e\u043c\u043f\u0442\u0435 \u0431\u043e\u0435\u0432\u043e\u0433\u043e \u0440\u0430\u0437\u043c\u0435\u0440\u0430 (\u22655K \u0442\u043e\u043a\u0435\u043d\u043e\u0432) \u0442\u043e\u0442 \u0436\u0435 \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440 \u0441 \u0442\u0435\u043c \u0436\u0435 \u043c\u0430\u0440\u043a\u0435\u0440\u043e\u043c \u0434\u0430\u043b \u0443\u0436\u0435 \u0434\u0435\u0441\u044f\u0442\u043a\u0438 \u043f\u0440\u043e\u0446\u0435\u043d\u0442\u043e\u0432 \u043f\u043e\u043f\u0430\u0434\u0430\u043d\u0438\u0439. \u0418 \u0432\u0442\u043e\u0440\u043e\u0435: \u0446\u0438\u043a\u043b \u0438\u0437 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0437\u0430\u0432\u044b\u0448\u0430\u0435\u0442 \u0446\u0438\u0444\u0440\u0443 \u2014 \u043d\u0430 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u0442\u0440\u0430\u0444\u0438\u043a\u0435 \u0441 \u0445\u043e\u043b\u043e\u0434\u043d\u044b\u043c\u0438 \u0441\u0442\u0430\u0440\u0442\u0430\u043c\u0438 \u0438 \u0440\u0435\u0434\u043a\u0438\u043c\u0438 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430\u043c\u0438 \u043e\u043d\u0430 \u043d\u0438\u0436\u0435. \u041c\u0435\u0440\u044c\u0442\u0435 \u043f\u043e usage-\u043f\u043e\u043b\u044f\u043c \u043e\u0442\u0432\u0435\u0442\u0430 (<code>cache_read_input_tokens<\/code>) \u0438 \u043f\u043e \u0431\u0438\u043b\u043b\u0438\u043d\u0433\u0443, \u0430 \u043d\u0435 \u043f\u043e \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0435 \u2014 \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0430 \u0448\u0443\u043c\u0438\u0442. \u0427\u0438\u0441\u043b\u0430 \u0438\u0437 2026 \u0433\u043e\u0434\u0430 \u0438 \u0437\u0430\u0432\u0438\u0441\u044f\u0442 \u043e\u0442 \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u0430; \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u044b \u0438\u043d\u043e\u0433\u0434\u0430 \u043c\u0435\u043d\u044f\u044e\u0442 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435, \u0442\u0430\u043a \u0447\u0442\u043e \u043f\u0435\u0440\u0435\u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0439\u0442\u0435 \u043f\u043e\u0434 \u0441\u0435\u0431\u044f.<\/p>\n<h3>\u0417\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0437\u0430 \u0434\u0432\u0435 \u043c\u0438\u043d\u0443\u0442\u044b, \u0431\u0435\u0437 Docker<\/h3>\n<p>\u0412\u0441\u0451 \u0432\u044b\u0448\u0435 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u0432 \u043e\u0434\u0438\u043d \u0444\u0430\u0439\u043b \u2014 \u0440\u0430\u0431\u043e\u0447\u0438\u0439 \u0447\u0430\u0442 \u0432 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0435, \u043a\u043b\u044e\u0447\u0438 \u0447\u0435\u0440\u0435\u0437 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f. \u0413\u043e\u043b\u043e\u0441 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e: \u0435\u0441\u043b\u0438 \u0437\u0430\u0434\u0430\u043d\u044b \u043a\u043b\u044e\u0447 \u0438 <code>voiceId<\/code> Inworld, \u043e\u0442\u0432\u0435\u0442 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u0432 <code>reply.mp3<\/code>.<\/p>\n<pre><code class=\"python\">#!\/usr\/bin\/env python3\"\"\"\u041c\u0438\u043d\u0438-\u0447\u0430\u0442 \u0441 \u0418\u0418-\u0434\u0435\u0432\u0443\u0448\u043a\u043e\u0439 \u0432 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0435. \u0411\u0435\u0437 Docker, \u043a\u043b\u044e\u0447\u0438 \u0447\u0435\u0440\u0435\u0437 env.    pip install openai    export OPENROUTER_API_KEY=sk-or-...          # \u043a\u043b\u044e\u0447: https:\/\/openrouter.ai\/keys    python mini_waifu.py\u0413\u043e\u043b\u043e\u0441 (\u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e) \u2014 \u0434\u043e\u043f\u0438\u0448\u0435\u0442 reply.mp3:    export INWORLD_API_KEY=...                   # \u043a\u043b\u044e\u0447: https:\/\/platform.inworld.ai\/    export INWORLD_VOICE_ID=...                  # id \u0433\u043e\u043b\u043e\u0441\u0430 \u0438\u0437 \u043a\u043e\u043d\u0441\u043e\u043b\u0438 Inworld\"\"\"import os, sys, json, base64, urllib.requestOR_KEY = os.environ.get(\"OPENROUTER_API_KEY\")if not OR_KEY:    sys.exit(\"\u041d\u0435\u0442 OPENROUTER_API_KEY. \u0421\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u043a\u043b\u044e\u0447 \u043d\u0430 https:\/\/openrouter.ai\/keys \"             \"\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u0435: export OPENROUTER_API_KEY=sk-or-...\")from openai import OpenAIclient = OpenAI(base_url=\"https:\/\/openrouter.ai\/api\/v1\", api_key=OR_KEY)MODEL = os.environ.get(\"MODEL\", \"qwen\/qwen3-235b-a22b-2507\")   # \u043b\u044e\u0431\u0430\u044f \u043c\u043e\u0434\u0435\u043b\u044c OpenRouterPERSONA = \"\u041c\u0438\u044f, 23 \u0433\u043e\u0434\u0430, \u0445\u0443\u0434\u043e\u0436\u043d\u0438\u0446\u0430 \u2014 \u0442\u0451\u043f\u043b\u0430\u044f \u0438 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0434\u0435\u0440\u0437\u043a\u0430\u044f\"SYSTEM = (f\"\u0422\u044b \u2014 {PERSONA}. \u041e\u0431\u0449\u0430\u0435\u0448\u044c\u0441\u044f \u0442\u0435\u043f\u043b\u043e \u0438 \u043f\u043e-\u0447\u0435\u043b\u043e\u0432\u0435\u0447\u0435\u0441\u043a\u0438. \"          \"\u041e\u0442\u0432\u0435\u0447\u0430\u0439 2\u20134 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u043c\u0438. \u0414\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u2014 \u0432 *\u0437\u0432\u0451\u0437\u0434\u043e\u0447\u043a\u0430\u0445*.\")NAME = PERSONA.split(\",\")[0]def synth_voice(text):    \"\"\"\u041e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u0430\u044f \u043e\u0437\u0432\u0443\u0447\u043a\u0430 \u0447\u0435\u0440\u0435\u0437 Inworld -&gt; reply.mp3 (\u0435\u0441\u043b\u0438 \u0437\u0430\u0434\u0430\u043d\u044b env).\"\"\"    key, voice = os.environ.get(\"INWORLD_API_KEY\"), os.environ.get(\"INWORLD_VOICE_ID\")    if not (key and voice):        return    body = json.dumps({        \"text\": text, \"voiceId\": voice,        \"modelId\": os.environ.get(\"INWORLD_MODEL\", \"inworld-tts-1.5-max\"),        \"audioConfig\": {\"encoding\": \"MP3\", \"sampleRateHertz\": 24000},    }).encode()    req = urllib.request.Request(        \"https:\/\/api.inworld.ai\/tts\/v1\/voice\", data=body,        headers={\"Authorization\": f\"Basic {key}\", \"Content-Type\": \"application\/json\"})    try:        resp = json.load(urllib.request.urlopen(req, timeout=30))        with open(\"reply.mp3\", \"wb\") as f:            f.write(base64.b64decode(resp[\"audioContent\"]))        print(\"  (\u0433\u043e\u043b\u043e\u0441 \u0441\u043e\u0445\u0440\u0430\u043d\u0451\u043d \u0432 reply.mp3)\")    except Exception as e:        print(f\"  (\u043e\u0437\u0432\u0443\u0447\u043a\u0430 \u043d\u0435 \u0443\u0434\u0430\u043b\u0430\u0441\u044c: {e})\")def main():    history = []    print(f\"\u0427\u0430\u0442 \u0441 {NAME}. \u041f\u0443\u0441\u0442\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430 \u2014 \u0432\u044b\u0445\u043e\u0434.\\n\")    while True:        try:            user = input(\"\u0412\u044b: \").strip()        except (EOFError, KeyboardInterrupt):            break        if not user:            break        messages = [{\"role\": \"system\", \"content\": SYSTEM}, *history,                    {\"role\": \"user\", \"content\": user}]        reply = client.chat.completions.create(            model=MODEL, messages=messages, max_tokens=400).choices[0].message.content        print(f\"{NAME}: {reply}\\n\")        history += [{\"role\": \"user\", \"content\": user},                    {\"role\": \"assistant\", \"content\": reply}]        history = history[-12:]          # \u043f\u043e\u043c\u043d\u0438\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u0445\u0432\u043e\u0441\u0442 \u0434\u0438\u0430\u043b\u043e\u0433\u0430        synth_voice(reply)if __name__ == \"__main__\":    main()<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a:<\/p>\n<pre><code class=\"bash\">pip install openaiexport OPENROUTER_API_KEY=sk-or-...   # \u0432\u0430\u0448 \u043a\u043b\u044e\u0447 \u0441 openrouter.ai\/keyspython mini_waifu.py<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u0440\u0438\u0434\u0446\u0430\u0442\u044c \u0441\u0442\u0440\u043e\u043a, \u0438 \u044d\u0442\u043e \u0443\u0436\u0435 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436 \u0441 \u043f\u0430\u043c\u044f\u0442\u044c\u044e; \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u043a\u043b\u044e\u0447 Inworld, \u0438 \u043e\u043d \u0437\u0430\u0433\u043e\u0432\u043e\u0440\u0438\u0442 \u0433\u043e\u043b\u043e\u0441\u043e\u043c. \u0414\u0430\u043b\u044c\u0448\u0435 \u043d\u0430\u0432\u0435\u0448\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0432\u0441\u0451 \u0438\u0437 \u0441\u0442\u0430\u0442\u044c\u0438: \u0440\u043e\u0443\u0442\u0438\u043d\u0433 \u043c\u043e\u0434\u0435\u043b\u0435\u0439, \u0440\u0430\u0431\u043e\u0442\u0430 \u0441 \u043e\u0442\u043a\u0430\u0437\u0430\u043c\u0438, \u0432\u0435\u043a\u0442\u043e\u0440\u043d\u0430\u044f \u043f\u0430\u043c\u044f\u0442\u044c \u0438 \u043a\u044d\u0448.<\/p>\n<h3>\u0427\u0442\u043e \u0432 \u0438\u0442\u043e\u0433\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442, \u0430 \u0447\u0442\u043e \u043d\u0435\u0442<\/h3>\n<p>\u0420\u0430\u0431\u043e\u0442\u0430\u0435\u0442:<\/p>\n<ul>\n<li>\n<p>\u0440\u043e\u0443\u0442\u0438\u043d\u0433 \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u0441\u043b\u043e\u0432\u0430\u0440\u0451\u043c <code>(\u0442\u0430\u0440\u0438\u0444, \u0440\u0435\u0436\u0438\u043c) \u2192 \u043c\u043e\u0434\u0435\u043b\u044c<\/code>;<\/p>\n<\/li>\n<li>\n<p>\u0441\u043f\u0430\u0441\u0435\u043d\u0438\u0435 \u043e\u0442\u043a\u0430\u0437\u043e\u0432: \u0441\u043f\u0435\u0440\u0432\u0430 \u0432\u044b\u0442\u0430\u0449\u0438\u0442\u044c \u043f\u043e\u043b\u0435\u0437\u043d\u043e\u0435 \u0438\u0437 \u043e\u0442\u0432\u0435\u0442\u0430, \u0437\u0430\u043f\u0430\u0441\u043d\u0443\u044e \u043c\u043e\u0434\u0435\u043b\u044c \u2014 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043b\u0430\u0442\u043d\u044b\u043c;<\/p>\n<\/li>\n<li>\n<p>\u043f\u0430\u043c\u044f\u0442\u044c \u0442\u0440\u0435\u043c\u044f \u0441\u043b\u043e\u044f\u043c\u0438: Redis, \u0432\u0435\u043a\u0442\u043e\u0440\u043d\u0430\u044f \u0431\u0430\u0437\u0430, \u043d\u0430\u043a\u043e\u043f\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0440\u0435\u0437\u044e\u043c\u0435;<\/p>\n<\/li>\n<li>\n<p>\u044d\u043c\u043e\u0446\u0438\u0438 \u0432 TTS \u0447\u0435\u0440\u0435\u0437 <code>*\u0443\u0434\u0430\u0440\u0435\u043d\u0438\u0435*<\/code>, <code>...<\/code>, <code>&lt;break&gt;<\/code> \u0438 \u0437\u0432\u0443\u043a\u043e\u043f\u043e\u0434\u0440\u0430\u0436\u0430\u043d\u0438\u0435;<\/p>\n<\/li>\n<li>\n<p>\u043a\u044d\u0448 \u043f\u0440\u043e\u043c\u043f\u0442\u0430 \u043d\u0430 \u0434\u043b\u0438\u043d\u043d\u043e\u043c \u043f\u0440\u0435\u0444\u0438\u043a\u0441\u0435 \u0441 \u044f\u0432\u043d\u044b\u043c \u043c\u0430\u0440\u043a\u0435\u0440\u043e\u043c.<\/p>\n<\/li>\n<\/ul>\n<p>\u041d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442:<\/p>\n<ul>\n<li>\n<p>\u0437\u0430\u043f\u0430\u0441\u043d\u0430\u044f \u043c\u043e\u0434\u0435\u043b\u044c \u043d\u0430 \u043a\u0430\u0436\u0434\u044b\u0439 \u043e\u0442\u043a\u0430\u0437 \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c;<\/p>\n<\/li>\n<li>\n<p>ChromaDB 0.5.x \u043d\u0430 \u0442\u044b\u0441\u044f\u0447\u0430\u0445 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0439 \u0431\u0435\u0437 \u043b\u0438\u043c\u0438\u0442\u0430 \u043a\u044d\u0448\u0430 (\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u0435\u0435 \u2014 \u0441\u0440\u0430\u0437\u0443 \u043d\u0430 1.x);<\/p>\n<\/li>\n<li>\n<p>\u0432\u0435\u0440\u0430 \u0432 \u0442\u0435\u0433\u0438 <code>[laugh]<\/code>\/<code>[sigh]<\/code> (\u0442\u043e\u043b\u044c\u043a\u043e \u043a\u0430\u0441\u0430\u0435\u0442\u0441\u044f inworld TTS 1.5 max, \u0432 \u0434\u0440\u0443\u0433\u0438\u0445 \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u0445 \u043f\u043e \u0442\u0438\u043f\u0443 ElevenLabs \u043d\u0443\u0436\u043d\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e, \u043d\u043e \u044d\u0442\u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u044b \u0447\u0430\u0441\u0442\u043e \u0438 \u0441\u0438\u043b\u044c\u043d\u043e \u0434\u043e\u0440\u043e\u0436\u0435) \u0438 \u0432 \u043a\u043e\u0440\u043e\u0442\u043a\u0438\u0435 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0435 \u043f\u0440\u043e\u043c\u043f\u0442\u044b.<\/p>\n<\/li>\n<\/ul>\n<p>\u041a\u0430\u0440\u043a\u0430\u0441 \u0438 \u043f\u0440\u0430\u0432\u0434\u0430 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u0437\u0430 \u0432\u0435\u0447\u0435\u0440-\u0434\u0440\u0443\u0433\u043e\u0439. \u0410 \u0432\u043e\u0442 \u044d\u0442\u0438 \u0447\u0435\u0442\u044b\u0440\u0435 \u043c\u0435\u0441\u0442\u0430 \u0441\u044a\u0435\u0434\u0430\u044e\u0442 \u043f\u043e\u0442\u043e\u043c \u0431\u043e\u043b\u044c\u0448\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u2014 \u0442\u0430\u043a \u0447\u0442\u043e \u043f\u0443\u0441\u0442\u044c \u043e\u043d\u0438 \u0431\u0443\u0434\u0443\u0442 \u0437\u0430\u043a\u0440\u044b\u0442\u044b \u0437\u0430\u0440\u0430\u043d\u0435\u0435.<\/p>\n<hr\/>\n<blockquote>\n<p><strong>\u0420\u0430\u0437\u0431\u043e\u0440 \u043e\u0441\u043d\u043e\u0432\u0430\u043d \u043d\u0430 \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u0435\u043d\u0435 <\/strong><a href=\"https:\/\/honeychat.bot\/\" rel=\"noopener noreferrer nofollow\"><strong>HoneyChat<\/strong><\/a> \u2014 Telegram \u0431\u043e\u0442\u0430 \u0438 \u0441\u0430\u0439\u0442\u0430 \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435 \u0441 \u0418\u0418 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430\u043c\u0438: 500\u2013700 \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0432 \u0434\u0435\u043d\u044c, 20 \u044f\u0437\u044b\u043a\u043e\u0432. \u0421\u0442\u0435\u043a: <code>aiogram<\/code> + <code>FastAPI<\/code> (uvicorn) + Celery-\u0432\u043e\u0440\u043a\u0435\u0440\u044b (\u043e\u0447\u0435\u0440\u0435\u0434\u0438 \u043f\u043e\u0434 \u0442\u0435\u043a\u0441\u0442, \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438, \u0433\u043e\u043b\u043e\u0441), \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u2014 PostgreSQL, Redis \u0438 ChromaDB. \u0412\u0441\u0435 \u0447\u0438\u0441\u043b\u0430 \u0438 \u043f\u043e\u0434\u0432\u043e\u0434\u043d\u044b\u0435 \u043a\u0430\u043c\u043d\u0438 \u0432\u044b\u0448\u0435 \u2014 \u0438\u0437 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0439 \u044d\u043a\u0441\u043f\u043b\u0443\u0430\u0442\u0430\u0446\u0438\u0438, \u0430 \u043d\u0435 \u0438\u0437 \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b\u043e\u0432.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u0434\u0435\u043b\u0430\u0435\u0442\u0435 \u043f\u043e\u0445\u043e\u0436\u0438\u0439 \u0447\u0430\u0442 \u0441 \u0438\u0438 \u0434\u0435\u0432\u0443\u0448\u043a\u043e\u0439 \u0438 \u0443\u043f\u0451\u0440\u043b\u0438\u0441\u044c \u0432 \u0442\u0435 \u0436\u0435 \u043c\u0435\u0441\u0442\u0430 \u2014 \u0437\u0430\u0445\u043e\u0434\u0438\u0442\u0435 \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0438, \u0441\u0432\u0435\u0440\u0438\u043c \u0446\u0438\u0444\u0440\u044b.<\/p>\n<\/blockquote>\n<h3>\u0418\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0438<\/h3>\n<ul>\n<li>\n<p><a href=\"https:\/\/docs.inworld.ai\/\" rel=\"noopener noreferrer nofollow\">Inworld TTS \u2014 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f<\/a> \u2014 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b (<code>temperature<\/code>, <code>speakingRate<\/code>), \u043f\u043e\u0434\u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e SSML.<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/www.w3.org\/TR\/speech-synthesis11\/\" rel=\"noopener noreferrer nofollow\">W3C \u2014 Speech Synthesis Markup Language (SSML) 1.1<\/a> \u2014 <code>&lt;break&gt;<\/code>, <code>&lt;speak&gt;<\/code>, \u043f\u0440\u043e\u0441\u043e\u0434\u0438\u044f.<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/docs.trychroma.com\/\" rel=\"noopener noreferrer nofollow\">ChromaDB \u2014 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f<\/a> \u2014 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u043a\u044d\u0448\u0430 \u0441\u0435\u0433\u043c\u0435\u043d\u0442\u043e\u0432; \u0438\u0448\u044c\u044e <a href=\"https:\/\/github.com\/chroma-core\/chroma\/issues\/3336\" rel=\"noopener noreferrer nofollow\">#3336<\/a> \u0438 <a href=\"https:\/\/github.com\/chroma-core\/chroma\/issues\/5843\" rel=\"noopener noreferrer nofollow\">#5843<\/a> (\u0443\u0442\u0435\u0447\u043a\u0430 \u043f\u0430\u043c\u044f\u0442\u0438, open).<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/openrouter.ai\/docs\/features\/prompt-caching\" rel=\"noopener noreferrer nofollow\">OpenRouter \u2014 prompt caching<\/a> \u0438 <a href=\"https:\/\/openrouter.ai\/docs\/features\/model-routing\" rel=\"noopener noreferrer nofollow\">model routing<\/a>.<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/docs.anthropic.com\/en\/docs\/build-with-claude\/prompt-caching\" rel=\"noopener noreferrer nofollow\">Anthropic \u2014 prompt caching<\/a> \u2014 <code>cache_control<\/code>, ephemeral-\u043a\u044d\u0448, \u0442\u0430\u0440\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f.<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/platform.openai.com\/docs\/guides\/prompt-caching\" rel=\"noopener noreferrer nofollow\">OpenAI \u2014 prompt caching<\/a> \u2014 \u0430\u0432\u0442\u043e-\u043a\u044d\u0448, \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u0430\u044f \u0434\u043b\u0438\u043d\u0430 \u043f\u0440\u0435\u0444\u0438\u043a\u0441\u0430, <code>cached_tokens<\/code>.<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/ai.google.dev\/gemini-api\/docs\/safety-settings\" rel=\"noopener noreferrer nofollow\">Google \u2014 Gemini safety settings<\/a> \u2014 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0438 \u0444\u0438\u043b\u044c\u0442\u0440\u0430 \u0438 <code>BLOCK_NONE<\/code>.<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/redis.io\/docs\/latest\/commands\/ltrim\/\" rel=\"noopener noreferrer nofollow\">Redis \u2014 LTRIM<\/a> \u2014 \u043f\u0430\u0442\u0442\u0435\u0440\u043d \u00ab\u0445\u0432\u043e\u0441\u0442 \u0441\u043f\u0438\u0441\u043a\u0430\u00bb.<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/www.sbert.net\/\" rel=\"noopener noreferrer nofollow\">sentence-transformers<\/a> \u2014 \u044d\u043c\u0431\u0435\u0434\u0434\u0438\u043d\u0433\u0438 \u0434\u043b\u044f \u0441\u043c\u044b\u0441\u043b\u043e\u0432\u043e\u0433\u043e \u043f\u043e\u0438\u0441\u043a\u0430.<\/p>\n<\/li>\n<\/ul>\n<\/div>\n<p>\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/1049830\/\">https:\/\/habr.com\/ru\/articles\/1049830\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>19 \u0438\u044e\u043d\u044f 2026 \u042f\u043d\u0434\u0435\u043a\u0441 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043b \u0418\u0418-\u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0435\u0439 \u0432 \u0410\u043b\u0438\u0441\u0435 \u2014 \u0431\u043e\u043b\u044c\u0448\u0435 30 \u0441\u043e\u0431\u0435\u0441\u0435\u0434\u043d\u0438\u043a\u043e\u0432 \u0441 \u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u043e\u043c, \u043e\u0442 \u0431\u043b\u043e\u0433\u0435\u0440\u043e\u0432 \u0434\u043e \u0430\u043d\u0438\u043c\u0435-\u0433\u0435\u0440\u043e\u0438\u043d\u044c; \u043e\u043d\u0438 \u0437\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u044e\u0442 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442, \u0430 \u0433\u043e\u043b\u043e\u0441\u0430 \u0438 \u043e\u0431\u0441\u0443\u0436\u0434\u0435\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0441\u0442\u0435\u0439 \u043e\u0431\u0435\u0449\u0430\u044e\u0442 \u043f\u043e\u0437\u0436\u0435. \u0416\u0430\u043d\u0440 \u043d\u0435 \u043d\u043e\u0432\u044b\u0439: \u00ab\u0447\u0430\u0442 \u0441 \u0418\u0418-\u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0435\u043c\u00bb \u0443\u0436\u0435 \u043f\u0430\u0440\u0443 \u043b\u0435\u0442 \u0442\u044f\u043d\u0443\u0442 Character.AI, Replika \u0438 \u0434\u0435\u0441\u044f\u0442\u043a\u0438 Telegram-\u0431\u043e\u0442\u043e\u0432. \u0423\u0434\u0438\u0432\u043b\u044f\u0435\u0442 \u0434\u0440\u0443\u0433\u043e\u0435 \u2014 \u043d\u0430\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u0430\u043b\u043e \u043d\u0443\u0436\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u0442\u0430\u043a\u043e\u0435 \u0441\u0430\u043c\u043e\u043c\u0443. \u041f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c \u0432\u0441\u0435\u0433\u043e \u0442\u0440\u0438 \u043a\u0443\u0431\u0438\u043a\u0430: \u044f\u0437\u044b\u043a\u043e\u0432\u0430\u044f \u043c\u043e\u0434\u0435\u043b\u044c, \u043f\u0430\u043c\u044f\u0442\u044c \u0438 \u0441\u0438\u043d\u0442\u0435\u0437 \u0440\u0435\u0447\u0438.\u0421\u0434\u0435\u043b\u0430\u0442\u044c \u0447\u0430\u0442 \u0441 \u0418\u0418 \u0434\u0435\u0432\u0443\u0448\u043a\u043e\u0439 (\u0438\u043b\u0438 \u043b\u044e\u0431\u044b\u043c \u0434\u0440\u0443\u0433\u0438\u043c \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0435\u043c) \u043f\u043e\u0432\u0435\u0440\u0445 \u0433\u043e\u0442\u043e\u0432\u043e\u0439 \u043c\u043e\u0434\u0435\u043b\u0438 \u2014 \u044d\u0442\u043e \u0433\u0440\u0443\u0431\u043e \u0433\u043e\u0432\u043e\u0440\u044f \u0432\u0435\u0447\u0435\u0440 \u0440\u0430\u0431\u043e\u0442\u044b. \u0410 \u0432\u043e\u0442 \u0437\u0430\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0435\u0433\u043e \u043d\u0435 \u0437\u0430\u0431\u044b\u0432\u0430\u0442\u044c \u0432\u0447\u0435\u0440\u0430\u0448\u043d\u0438\u0439 \u0440\u0430\u0437\u0433\u043e\u0432\u043e\u0440, \u043d\u0435 \u043e\u0442\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043d\u0430 \u0440\u043e\u0432\u043d\u043e\u043c \u043c\u0435\u0441\u0442\u0435, \u0433\u043e\u0432\u043e\u0440\u0438\u0442\u044c \u0433\u043e\u043b\u043e\u0441\u043e\u043c \u0438 \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u043d\u0435 \u0440\u0430\u0437\u043e\u0440\u0438\u0442\u044c \u0432\u0430\u0441 \u043d\u0430 \u0441\u0447\u0435\u0442\u0430\u0445 \u0437\u0430 API \u2014 \u043d\u0430 \u044d\u0442\u043e \u0443\u0445\u043e\u0434\u0438\u0442 \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u0431\u043e\u043b\u044c\u0448\u0435 \u0432\u0440\u0435\u043c\u0435\u043d\u0438. \u042f \u043f\u043e\u043b\u0433\u043e\u0434\u0430 \u0432\u043e\u0436\u0443\u0441\u044c \u0441 \u0442\u0430\u043a\u0438\u043c \u0431\u043e\u0442\u043e\u043c \u0432 \u043f\u0440\u043e\u0434\u0435; \u043d\u0438\u0436\u0435 \u2014 \u0440\u0430\u0431\u043e\u0447\u0438\u0439 \u043a\u0430\u0440\u043a\u0430\u0441 \u043d\u0430 Python \u0438 \u0447\u0435\u0442\u044b\u0440\u0435 \u043c\u0435\u0441\u0442\u0430, \u0433\u0434\u0435 \u043c\u044b \u0441\u043f\u043e\u0442\u044b\u043a\u0430\u043b\u0438\u0441\u044c.\u041a\u0430\u0440\u043a\u0430\u0441: \u043e\u0434\u0438\u043d \u0437\u0430\u043f\u0440\u043e\u0441 \u043a \u043c\u043e\u0434\u0435\u043b\u0438\u041b\u044e\u0431\u043e\u0439 \u0447\u0430\u0442 \u0441 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0435\u043c \u2014 \u044d\u0442\u043e \u043e\u0434\u0438\u043d \u0438 \u0442\u043e\u0442 \u0436\u0435 \u0446\u0438\u043a\u043b: \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0439 \u043f\u0440\u043e\u043c\u043f\u0442, \u0438\u0441\u0442\u043e\u0440\u0438\u044f \u0434\u0438\u0430\u043b\u043e\u0433\u0430, \u043d\u043e\u0432\u0430\u044f \u0440\u0435\u043f\u043b\u0438\u043a\u0430 \u2014 \u0438 \u043e\u0442\u0432\u0435\u0442 \u043c\u043e\u0434\u0435\u043b\u0438. \u0421\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0439 \u043f\u0440\u043e\u043c\u043f\u0442 \u0443\u0434\u043e\u0431\u043d\u043e \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u0441\u043b\u043e\u044f\u043c\u0438: \u043a\u0442\u043e \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436, \u0441 \u043a\u0435\u043c \u0433\u043e\u0432\u043e\u0440\u0438\u0442, \u0432 \u043a\u0430\u043a\u043e\u043c \u0444\u043e\u0440\u043c\u0430\u0442\u0435 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442. \u0425\u043e\u0434\u0438\u0442\u044c \u043a \u043c\u043e\u0434\u0435\u043b\u044f\u043c \u044f \u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0438\u0442\u0430\u044e \u0447\u0435\u0440\u0435\u0437 OpenAI-\u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u044b\u0439 \u043a\u043b\u0438\u0435\u043d\u0442 \u2014 \u0442\u043e\u0442 \u0436\u0435 OpenRouter \u0434\u0430\u0451\u0442 \u0435\u0434\u0438\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043a \u0434\u0435\u0441\u044f\u0442\u043a\u0430\u043c \u043c\u043e\u0434\u0435\u043b\u0435\u0439, \u0438 \u043c\u0435\u043d\u044f\u0442\u044c \u0438\u0445 \u043c\u043e\u0436\u043d\u043e \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u043e\u0439.\u041a\u043b\u044e\u0447 \u0434\u043b\u044f OpenRouter. \u0417\u0430\u0432\u0435\u0434\u0438\u0442\u0435 \u043d\u0430 openrouter.ai\/keys (\u0432\u0445\u043e\u0434 \u0447\u0435\u0440\u0435\u0437 Google\/GitHub \u2192 Create Key), \u043f\u043e\u043b\u043e\u0436\u0438\u0442\u0435 \u043f\u0430\u0440\u0443 \u0434\u043e\u043b\u043b\u0430\u0440\u043e\u0432 \u043d\u0430 \u0431\u0430\u043b\u0430\u043d\u0441 \u0438\u043b\u0438 \u0432\u043e\u0437\u044c\u043c\u0438\u0442\u0435 \u043c\u043e\u0434\u0435\u043b\u044c \u0441 \u043f\u043e\u043c\u0435\u0442\u043a\u043e\u0439 free. \u041a\u043b\u044e\u0447 \u0434\u0435\u0440\u0436\u0438\u043c \u043d\u0435 \u0432 \u043a\u043e\u0434\u0435, \u0430 \u0432 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f OPENROUTER_API_KEY.from openai import AsyncOpenAIclient = AsyncOpenAI(base_url=&#187;https:\/\/openrouter.ai\/api\/v1&#8243;, api_key=API_KEY)def build_system_prompt(char, user):    # \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0439 \u043f\u0440\u043e\u043c\u043f\u0442 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u043c \u0441\u043b\u043e\u044f\u043c\u0438: \u043f\u0435\u0440\u0441\u043e\u043d\u0430 -&gt; \u043a\u0442\u043e \u0441\u043e\u0431\u0435\u0441\u0435\u0434\u043d\u0438\u043a -&gt; \u0444\u043e\u0440\u043c\u0430\u0442 \u043e\u0442\u0432\u0435\u0442\u0430    return &#171;\\n&#187;.join([        f&#187;\u0422\u044b \u2014 {char[&#8216;name&#8217;]}, {char[&#8216;persona&#8217;]}.&#187;,        f&#187;\u0421\u043e\u0431\u0435\u0441\u0435\u0434\u043d\u0438\u043a: {user[&#8216;name&#8217;]}.&#187;,        &#171;\u041e\u0442\u0432\u0435\u0447\u0430\u0439 2\u20134 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u043c\u0438. \u0414\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u2014 \u0432 *\u0437\u0432\u0451\u0437\u0434\u043e\u0447\u043a\u0430\u0445*, \u043c\u044b\u0441\u043b\u0438 \u2014 \u0432 ~\u0442\u0438\u043b\u044c\u0434\u0430\u0445~.&#187;,    ])async def reply(char, user, history, user_msg, model):    messages = [{&#171;role&#187;: &#171;system&#187;, &#171;content&#187;: build_system_prompt(char, user)}]    messages += history                       # \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u0440\u0435\u043f\u043b\u0438\u043a\u0438 \u0434\u0438\u0430\u043b\u043e\u0433\u0430    messages.append({&#171;role&#187;: &#171;user&#187;, &#171;content&#187;: user_msg})    resp = await client.chat.completions.create(model=model, messages=messages)    return resp.choices[0].message.content\u042d\u0442\u043e \u0443\u0436\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0439 \u0447\u0430\u0442. \u0412\u0441\u0451 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0435 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u0434\u0430\u043b\u044c\u0448\u0435.\u041a\u0430\u043a\u0443\u044e \u043c\u043e\u0434\u0435\u043b\u044c \u0432\u044b\u0431\u0440\u0430\u0442\u044c?\u041f\u043e\u0434 \u043a\u0430\u0436\u0434\u0443\u044e \u0440\u0435\u043f\u043b\u0438\u043a\u0443 \u043c\u043e\u0434\u0435\u043b\u044c \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u043f\u043e \u0434\u0432\u0443\u043c \u043f\u0440\u0438\u0437\u043d\u0430\u043a\u0430\u043c \u2014 \u0442\u0430\u0440\u0438\u0444 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438 \u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440 \u0441\u0446\u0435\u043d\u044b. \u0411\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u043c \u2014 \u0434\u0435\u0448\u0451\u0432\u0443\u044e, \u043f\u043b\u0430\u0442\u043d\u044b\u043c \u2014 \u043f\u043e\u0443\u043c\u043d\u0435\u0435, \u0434\u043b\u044f \u043e\u0442\u043a\u0440\u043e\u0432\u0435\u043d\u043d\u044b\u0445 \u0441\u0446\u0435\u043d \u2014 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e, \u0431\u0435\u0437 \u0436\u0451\u0441\u0442\u043a\u043e\u0439 \u0446\u0435\u043d\u0437\u0443\u0440\u044b. \u042f \u0434\u0435\u0440\u0436\u0443 \u044d\u0442\u043e \u043e\u0431\u044b\u0447\u043d\u044b\u043c \u0441\u043b\u043e\u0432\u0430\u0440\u0451\u043c, \u0431\u0435\u0437 \u0434\u0435\u0440\u0435\u0432\u0430 \u0438\u0437 if:MODEL_BY_ROUTE = {    (&#171;free&#187;, &#171;\u043e\u0431\u044b\u0447\u043d\u044b\u0439&#187;): &#171;\u0434\u0435\u0448\u0451\u0432\u0430\u044f-\u0431\u0430\u0437\u043e\u0432\u0430\u044f-\u043c\u043e\u0434\u0435\u043b\u044c&#187;,    (&#171;free&#187;, &#171;\u0433\u043e\u0440\u044f\u0447\u0438\u0439&#187;): &#171;\u043c\u043e\u0434\u0435\u043b\u044c-\u0431\u0435\u0437-\u0436\u0451\u0441\u0442\u043a\u043e\u0439-\u0446\u0435\u043d\u0437\u0443\u0440\u044b&#187;,    (&#171;paid&#187;, &#171;\u043e\u0431\u044b\u0447\u043d\u044b\u0439&#187;): &#171;\u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f-\u043c\u043e\u0434\u0435\u043b\u044c&#187;,    (&#171;paid&#187;, &#171;\u0433\u043e\u0440\u044f\u0447\u0438\u0439&#187;): &#171;\u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f-\u043c\u043e\u0434\u0435\u043b\u044c&#187;,}def select_model(tier: str, mode: str = &#171;\u043e\u0431\u044b\u0447\u043d\u044b\u0439&#187;) -&gt; str:    return MODEL_BY_ROUTE.get((tier, mode), MODEL_BY_ROUTE[(&#171;free&#187;, &#171;\u043e\u0431\u044b\u0447\u043d\u044b\u0439&#187;)])# \u0438 \u043f\u043e\u0442\u043e\u043b\u043e\u043a \u0434\u043b\u0438\u043d\u044b \u043e\u0442\u0432\u0435\u0442\u0430 \u0434\u0435\u0440\u0436\u0438\u043c \u043f\u043e \u0442\u0430\u0440\u0438\u0444\u0443 \u2014 \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u043f\u043b\u0430\u0442\u0438\u0442\u044c \u0437\u0430 \u043b\u0438\u0448\u043d\u0438\u0435 \u0442\u043e\u043a\u0435\u043d\u044bMAX_TOKENS = {&#171;free&#187;: 1500, &#171;paid&#187;: 3500}\u0423\u043c\u043d\u044b\u0435 \u043c\u043e\u0434\u0435\u043b\u0438 \u0441\u0442\u043e\u044f\u0442 \u0432 \u0440\u0430\u0437\u044b \u0434\u043e\u0440\u043e\u0436\u0435 \u0434\u0435\u0448\u0451\u0432\u044b\u0445, \u0430 \u043b\u0438\u043c\u0438\u0442 \u043d\u0430 \u0434\u043b\u0438\u043d\u0443 \u043e\u0442\u0432\u0435\u0442\u0430 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u0431\u044c\u0435\u0442 \u043f\u043e \u043a\u043e\u0448\u0435\u043b\u044c\u043a\u0443. \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u043e\u0432\u044b\u0439 \u0442\u0430\u0440\u0438\u0444 \u0438\u043b\u0438 \u0440\u0435\u0436\u0438\u043c \u2014 \u043e\u0434\u043d\u0430 \u0441\u0442\u0440\u043e\u043a\u0430 \u0432 \u0441\u043b\u043e\u0432\u0430\u0440\u0435, \u0430 \u043d\u0435 \u043d\u043e\u0432\u0430\u044f \u0432\u0435\u0442\u043a\u0430 \u0432 \u043a\u043e\u0434\u0435.\u041f\u043e\u0434\u0432\u043e\u0434\u043d\u044b\u0439 \u043a\u0430\u043c\u0435\u043d\u044c 1: \u043c\u043e\u0434\u0435\u043b\u044c \u043e\u0442\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043e\u0442\u0432\u0435\u0447\u0430\u0442\u044c\u0420\u0430\u043d\u043e \u0438\u043b\u0438 \u043f\u043e\u0437\u0434\u043d\u043e \u0444\u0438\u043b\u044c\u0442\u0440 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 \u0441\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043d\u0430 \u0431\u0435\u0437\u043e\u0431\u0438\u0434\u043d\u043e\u0439 \u0444\u0440\u0430\u0437\u0435, \u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0443\u043f\u0440\u0451\u0442\u0441\u044f \u0432 \u0441\u0442\u0435\u043d\u0443 \u00ab\u0418\u0437\u0432\u0438\u043d\u0438\u0442\u0435, \u044f \u043d\u0435 \u043c\u043e\u0433\u0443\u2026\u00bb. \u041d\u0430 \u043d\u0430\u0448\u0435\u043c \u0442\u0440\u0430\u0444\u0438\u043a\u0435 \u0442\u0430\u043a\u0438\u0435 \u043b\u043e\u0436\u043d\u044b\u0435 \u043e\u0442\u043a\u0430\u0437\u044b \u2014 \u044d\u0442\u043e 2\u20138% \u043e\u0442\u0432\u0435\u0442\u043e\u0432 (\u0443 \u0432\u0430\u0441 \u0446\u0438\u0444\u0440\u0430 \u0431\u0443\u0434\u0435\u0442 \u0441\u0432\u043e\u044f). \u0421\u043e\u0432\u0441\u0435\u043c \u0438\u0445 \u043d\u0435 \u0443\u0431\u0440\u0430\u0442\u044c, \u043d\u043e \u0431\u043e\u043b\u044c\u0448\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u043c\u043e\u0436\u043d\u043e \u0432\u0435\u0440\u043d\u0443\u0442\u044c, \u043f\u0440\u0438\u0447\u0451\u043c \u0434\u0451\u0448\u0435\u0432\u043e. \u041b\u043e\u0433\u0438\u043a\u0430 \u2014 \u043e\u0442 \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u043e\u0433\u043e \u043a \u0434\u043e\u0440\u043e\u0433\u043e\u043c\u0443: \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u0441\u043f\u0430\u0441\u0442\u0438 \u0442\u043e, \u0447\u0442\u043e \u043c\u043e\u0434\u0435\u043b\u044c \u0443\u0436\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u043b\u0430 \u0434\u043e \u043e\u0442\u043a\u0430\u0437\u0430, \u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u0435\u0441\u043b\u0438 \u043d\u0435 \u0432\u044b\u0448\u043b\u043e \u2014 \u0437\u043e\u0432\u0451\u043c \u0437\u0430\u043f\u0430\u0441\u043d\u0443\u044e \u043c\u043e\u0434\u0435\u043b\u044c.REFUSAL_MARKERS = (&#171;\u044f \u043d\u0435 \u043c\u043e\u0433\u0443&#187;, &#171;i can&#8217;t&#187;, &#171;as an ai&#187;, &#171;\u7533\u3057\u8a33&#187;)def salvage(text: str) -&gt; str | None:    # \u0447\u0430\u0441\u0442\u043e \u043f\u0435\u0440\u0435\u0434 \u0444\u0440\u0430\u0437\u043e\u0439-\u043e\u0442\u043a\u0430\u0437\u043e\u043c \u0443\u0436\u0435 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0439 \u0442\u0435\u043a\u0441\u0442 \u2014 \u043e\u0442\u0440\u0435\u0437\u0430\u0435\u043c \u0445\u0432\u043e\u0441\u0442    low = text.lower()    for m in REFUSAL_MARKERS:        i = low.rfind(m)        if i &gt; 150:            text = text[:i].rstrip()            break    return text if len(text) &gt;= 150 else Noneasync def reply_with_rescue(tier, messages):    raw = await call_model(PRIMARY_MODEL, messages)    if not is_refusal(raw):        return raw    if good := salvage(raw):                  # 0 \u043b\u0438\u0448\u043d\u0438\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432        return good    if tier == &#171;paid&#187;:                        # \u0437\u0430\u043f\u0430\u0441\u043d\u0443\u044e \u043c\u043e\u0434\u0435\u043b\u044c \u2014 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043b\u0430\u0442\u043d\u044b\u043c        return await call_model(BACKUP_MODEL, messages)    return in_character_refusal()             # \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u043c \u2014 \u043c\u044f\u0433\u043a\u0438\u0439 \u043e\u0442\u043a\u0430\u0437 \u0432 \u0440\u043e\u043b\u0438\u0422\u043e\u043d\u043a\u043e\u0441\u0442\u044c, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u044b \u043f\u043e\u043d\u044f\u043b\u0438 \u043d\u0435 \u0441\u0440\u0430\u0437\u0443: \u0437\u0430\u043f\u0430\u0441\u043d\u0443\u044e \u043c\u043e\u0434\u0435\u043b\u044c \u0438\u043c\u0435\u0435\u0442 \u0441\u043c\u044b\u0441\u043b \u0437\u0432\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043b\u0430\u0442\u043d\u044b\u043c. \u0418\u043d\u0430\u0447\u0435 \u043a\u0430\u0436\u0434\u044b\u0439 \u043e\u0442\u043a\u0430\u0437 \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0432 \u043b\u0438\u0448\u043d\u0438\u0439 \u0437\u0430\u043f\u0440\u043e\u0441, \u0430 \u043d\u0430 \u043e\u0431\u044a\u0451\u043c\u0435 \u044d\u0442\u043e \u0437\u0430\u043c\u0435\u0442\u043d\u0430\u044f \u0441\u0442\u0430\u0442\u044c\u044f \u0440\u0430\u0441\u0445\u043e\u0434\u043e\u0432. \u0411\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u043c \u043e\u0442\u0434\u0430\u0451\u043c \u043c\u044f\u0433\u043a\u0438\u0439 \u043e\u0442\u043a\u0430\u0437 \u00ab\u0432 \u0440\u043e\u043b\u0438\u00bb \u2014 \u043e\u043d \u0432\u0441\u0451 \u0440\u0430\u0432\u043d\u043e \u043f\u0440\u0438\u044f\u0442\u043d\u0435\u0435 \u0441\u044b\u0440\u043e\u0439 \u0441\u0442\u0435\u043d\u044b. \u0426\u0435\u043f\u043e\u0447\u043a\u0443 \u043c\u043e\u0436\u043d\u043e \u0443\u0441\u043b\u043e\u0436\u043d\u0438\u0442\u044c: \u043f\u0435\u0440\u0432\u044b\u043c \u0448\u0430\u0433\u043e\u043c, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u0440\u0438\u0441\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 \u0443 \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u0430, \u0435\u0441\u043b\u0438 \u043e\u043d \u044d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442.\u041a\u0430\u043a \u0434\u0430\u0442\u044c \u0447\u0430\u0442-\u0431\u043e\u0442\u0443 \u0434\u043e\u043b\u0433\u043e\u0441\u0440\u043e\u0447\u043d\u0443\u044e \u043f\u0430\u043c\u044f\u0442\u044c?\u041f\u0430\u043c\u044f\u0442\u044c \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u0438\u0437 \u0442\u0440\u0451\u0445 \u0441\u043b\u043e\u0451\u0432, \u0438 \u043a\u0430\u0436\u0434\u044b\u0439 \u0437\u0430\u043a\u0440\u044b\u0432\u0430\u0435\u0442 \u0441\u0432\u043e\u044e \u0437\u0430\u0434\u0430\u0447\u0443. \u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u0440\u0435\u043f\u043b\u0438\u043a\u0438 \u0434\u0435\u0440\u0436\u0438\u043c \u0432 Redis \u2014 \u044d\u0442\u043e \u0431\u044b\u0441\u0442\u0440\u043e. \u0427\u0442\u043e\u0431\u044b \u00ab\u0432\u0441\u043f\u043e\u043c\u043d\u0438\u0442\u044c, \u0447\u0442\u043e \u0431\u044b\u043b\u043e \u0441\u0442\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u043d\u0430\u0437\u0430\u0434\u00bb, \u043d\u0443\u0436\u0435\u043d \u043f\u043e\u0438\u0441\u043a \u043f\u043e \u0441\u043c\u044b\u0441\u043b\u0443, \u0430 \u043d\u0435 \u043f\u043e \u0441\u043b\u043e\u0432\u0430\u043c \u2014 \u0435\u0433\u043e \u0434\u0430\u0451\u0442 \u0432\u0435\u043a\u0442\u043e\u0440\u043d\u0430\u044f \u0431\u0430\u0437\u0430 \u0432\u0440\u043e\u0434\u0435 ChromaDB. \u0410 \u0447\u0442\u043e\u0431\u044b \u0434\u043b\u0438\u043d\u043d\u0430\u044f \u0438\u0441\u0442\u043e\u0440\u0438\u044f \u043d\u0435 \u0440\u0430\u0437\u0434\u0443\u0432\u0430\u043b\u0430 \u043f\u0440\u043e\u043c\u043f\u0442 \u0434\u043e \u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u043e\u0441\u0442\u0438, \u0435\u0451 \u043f\u0435\u0440\u0438\u043e\u0434\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u0436\u0438\u043c\u0430\u044e\u0442 \u0432 \u043d\u0430\u043a\u043e\u043f\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0441\u0430\u043c\u043c\u0430\u0440\u0438. \u041f\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u043d\u0438 \u043e\u0434\u0438\u043d \u0441\u043b\u043e\u0439 \u043d\u0435 \u0432\u044b\u0432\u043e\u0437\u0438\u0442.# \u0441\u043b\u043e\u0439 1 \u2014 \u0433\u043e\u0440\u044f\u0447\u0438\u0439: \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 N \u0440\u0435\u043f\u043b\u0438\u043a \u0432 Redis (\u0436\u0438\u0432\u0451\u0442 \u043c\u0438\u043b\u043b\u0438\u0441\u0435\u043a\u0443\u043d\u0434\u044b)async def remember_turn(r, key, text):    await r.rpush(key, text)    await r.ltrim(key, -20, -1)               # \u0434\u0435\u0440\u0436\u0438\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u0445\u0432\u043e\u0441\u0442# \u0441\u043b\u043e\u0439 2 \u2014 \u0441\u043c\u044b\u0441\u043b\u043e\u0432\u043e\u0439: \u0438\u0449\u0435\u043c \u0440\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d\u043e\u0435 \u043f\u0440\u043e\u0448\u043b\u043e\u0435 \u043f\u043e \u0441\u043c\u044b\u0441\u043b\u0443, \u0430 \u043d\u0435 \u043f\u043e \u0441\u043b\u043e\u0432\u0430\u043cdef recall(collection, query, k=3):    res = collection.query(query_texts=[query], n_results=k)    docs, dists = res[&#171;documents&#187;][0], res[&#171;distances&#187;][0]    return [d for d, dist in zip(docs, dists) if dist &lt;= 0.55]   # \u043f\u043e\u0440\u043e\u0433 \u0431\u043b\u0438\u0437\u043e\u0441\u0442\u0438# \u0441\u043b\u043e\u0439 3 \u2014 \u043d\u0430\u043a\u043e\u043f\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0441\u0430\u043c\u043c\u0430\u0440\u0438: \u0441\u0436\u0438\u043c\u0430\u0435\u043c \u0441\u0442\u0430\u0440\u043e\u0435 + \u0434\u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u043d\u043e\u0432\u043e\u0435async def update_summary(prev_summary, recent_msgs):    prompt = f&#187;\u0414\u043e\u043f\u043e\u043b\u043d\u0438 summary \u043d\u043e\u0432\u044b\u043c\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u044f\u043c\u0438.\\n\u0411\u044b\u043b\u043e: {prev_summary}\\n\u0414\u0438\u0430\u043b\u043e\u0433: {recent_msgs}&#187;    summary = await llm_summarize(prompt)    return summary[:900]                       # \u0434\u0435\u0440\u0436\u0438\u043c \u0432 \u0440\u0430\u043c\u043a\u0430\u0445, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0440\u0430\u0437\u0434\u0443\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u043c\u043f\u0442\u041f\u043e\u0440\u043e\u0433 \u0431\u043b\u0438\u0437\u043e\u0441\u0442\u0438 0.55 \u0438 \u043f\u043e\u0442\u043e\u043b\u043e\u043a \u0441\u0430\u043c\u043c\u0430\u0440\u0438 \u0432 900 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432 \u2014 \u044d\u0442\u043e \u043d\u0430\u0448\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, \u043f\u043e\u0434 \u0441\u0432\u043e\u0439 \u044d\u043c\u0431\u0435\u0434\u0434\u0435\u0440 \u043f\u043e\u0434\u0431\u0438\u0440\u0430\u0439\u0442\u0435 \u0441\u0432\u043e\u0438. \u0418 \u043f\u0440\u043e \u0438\u0437\u043e\u043b\u044f\u0446\u0438\u044e: \u0438\u043c\u044f \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438 \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 id \u0441\u0435\u0441\u0441\u0438\u0438 (mem_{user}_{char}_{session}), \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0444\u0430\u043a\u0442\u044b \u0438\u0437 \u043e\u0434\u043d\u043e\u0439 \u0441\u0446\u0435\u043d\u044b \u043d\u0435 \u043f\u0440\u043e\u0442\u0435\u043a\u0430\u044e\u0442 \u0432 \u0434\u0440\u0443\u0433\u0443\u044e \u2014 \u0432 \u043e\u0434\u043d\u043e\u0439 \u0441\u0446\u0435\u043d\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0441\u0442\u0443\u0434\u0435\u043d\u0442\u043a\u0430, \u0432 \u0434\u0440\u0443\u0433\u043e\u0439 \u043f\u0438\u043b\u043e\u0442, \u0441\u043c\u0435\u0448\u0438\u0432\u0430\u0442\u044c \u0438\u0445 \u043d\u0435\u043b\u044c\u0437\u044f.\u041f\u043e\u0434\u0432\u043e\u0434\u043d\u044b\u0439 \u043a\u0430\u043c\u0435\u043d\u044c 2: ChromaDB \u0438 \u043f\u0430\u043c\u044f\u0442\u044c \u0441\u0435\u0440\u0432\u0435\u0440\u0430\u041a\u043e\u0433\u0434\u0430 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0439 \u043c\u043d\u043e\u0433\u043e \u2014 \u0430 \u0443 \u043d\u0430\u0441 \u0438\u0445 \u0437\u0430 \u0447\u0435\u0442\u044b\u0440\u0435 \u0442\u044b\u0441\u044f\u0447\u0438, \u043f\u043e \u043e\u0434\u043d\u043e\u0439 \u043d\u0430 \u0441\u0446\u0435\u043d\u0443, \u2014 ChromaDB \u0441\u043f\u043e\u0441\u043e\u0431\u0435\u043d \u043d\u0435\u0437\u0430\u043c\u0435\u0442\u043d\u043e \u0441\u044a\u0435\u0441\u0442\u044c \u0432\u0441\u044e \u043f\u0430\u043c\u044f\u0442\u044c \u0445\u043e\u0441\u0442\u0430. \u041d\u0430 \u0432\u0435\u0442\u043a\u0435 0.5.x \u043a\u044d\u0448 \u0441\u0435\u0433\u043c\u0435\u043d\u0442\u043e\u0432 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u043d\u0435\u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d: \u043f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0438 \u043a \u0441\u0432\u0435\u0436\u0435\u0439 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438 RSS \u043f\u043e\u0434\u0440\u0430\u0441\u0442\u0430\u0435\u0442 \u0438 \u043e\u0431\u0440\u0430\u0442\u043d\u043e \u043d\u0435 \u043e\u0442\u0434\u0430\u0451\u0442\u0441\u044f. \u0423 \u043d\u0430\u0441 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0432\u044b\u0435\u0434\u0430\u043b \u0441\u0432\u043e\u0439 \u0431\u044e\u0434\u0436\u0435\u0442 \u0437\u0430 \u043f\u0430\u0440\u0443-\u0442\u0440\u043e\u0439\u043a\u0443 \u0434\u043d\u0435\u0439 \u0438 \u0443\u0445\u043e\u0434\u0438\u043b \u0432 OOM \u043f\u043e \u043d\u043e\u0447\u0430\u043c. \u0415\u0441\u043b\u0438 \u0432\u044b \u0437\u0430\u0441\u0442\u0440\u044f\u043b\u0438 \u043d\u0430 0.5.x, \u043b\u0435\u0447\u0438\u0442\u0441\u044f \u0434\u0432\u0443\u043c\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u043c\u0438 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u2014 \u0438 \u043f\u043e\u043c\u043d\u0438\u0442\u0435, \u0447\u0442\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u043e\u043d\u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430, restart \u0438\u0445 \u043d\u0435 \u043f\u043e\u0434\u0445\u0432\u0430\u0442\u0438\u0442:# docker-compose.yml \u2014 \u043e\u0431\u0445\u043e\u0434\u043d\u043e\u0439 \u043f\u0443\u0442\u044c, \u0435\u0441\u043b\u0438 \u0441\u0438\u0434\u0438\u0442\u0435 \u043d\u0430 0.5.xchromadb:  image: chromadb\/chroma:0.5.18  environment:    CHROMA_SEGMENT_CACHE_POLICY: &#171;LRU&#187;    CHROMA_MEMORY_LIMIT_BYTES: &#171;10737418240&#187;   # 10 \u0413\u0438\u0411\u041c\u043e\u0439 \u0441\u043e\u0432\u0435\u0442 &#8212; \u043d\u0435 \u043f\u044b\u0442\u0430\u0442\u044c\u0441\u044f \u043f\u0440\u0430\u0432\u0438\u0442\u044c 0.5.x, \u0430 \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c\u0441\u044f \u043d\u0430 \u0432\u0435\u0442\u043a\u0443 1.x: \u0435\u0451 \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u0430\u043b\u0438 \u043d\u0430 Rust, \u0438 \u044d\u0442\u043e \u0441\u043e\u0432\u0441\u0435\u043c \u0434\u0440\u0443\u0433\u043e\u0439 \u0440\u0430\u0437\u0433\u043e\u0432\u043e\u0440. \u041f\u043e\u0441\u043b\u0435 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 RSS \u0443 \u043d\u0430\u0441 \u0443\u043f\u0430\u043b \u0441 ~14 \u0413\u0411 \u0434\u043e ~300 \u041c\u0438\u0411, \u0441\u0432\u043e\u043f \u043d\u0430 \u0445\u043e\u0441\u0442\u0435 \u2014 \u0441\u043e 100% \u0434\u043e 2%, \u0430 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u043f\u043e\u0438\u0441\u043a\u0430 \u0438 \u0434\u0438\u0441\u0442\u0430\u043d\u0446\u0438\u0438 \u043e\u0441\u0442\u0430\u043b\u0438\u0441\u044c \u043f\u0440\u0435\u0436\u043d\u0438\u043c\u0438 (\u0442\u0435 \u0436\u0435 4,5 \u0442\u044b\u0441\u044f\u0447\u0438 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0439 \u043d\u0430 \u043c\u0435\u0441\u0442\u0435). \u0422\u043e\u043b\u044c\u043a\u043e \u0443 \u0430\u043f\u0433\u0440\u0435\u0439\u0434\u0430 \u0435\u0441\u0442\u044c \u0442\u0440\u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u043d\u0430\u043f\u043e\u0440\u043e\u043b\u0438\u0441\u044c:\u041c\u0438\u0433\u0440\u0430\u0446\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u043e\u0434\u043d\u043e\u0441\u0442\u043e\u0440\u043e\u043d\u043d\u044f\u044f. \u041d\u0430 \u043f\u0435\u0440\u0432\u043e\u043c \u0441\u0442\u0430\u0440\u0442\u0435 1.x \u043d\u0435\u043e\u0431\u0440\u0430\u0442\u0438\u043c\u043e \u043f\u0440\u0430\u0432\u0438\u0442 \u0441\u0445\u0435\u043c\u0443 sqlite \u2014 \u043e\u0442\u043a\u0430\u0442\u0438\u0442\u044c\u0441\u044f \u043d\u0430 0.5.x \u043f\u043e\u0432\u0435\u0440\u0445 \u0442\u0440\u043e\u043d\u0443\u0442\u043e\u0433\u043e \u0442\u043e\u043c\u0430 \u0443\u0436\u0435 \u043d\u0435 \u0432\u044b\u0439\u0434\u0435\u0442. \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0431\u044d\u043a\u0430\u043f (\u0443 \u043d\u0430\u0441 \u2014 tar \u0432 S3), \u043f\u043e\u0442\u043e\u043c \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435.\u041a\u043b\u0438\u0435\u043d\u0442 \u0438 \u0441\u0435\u0440\u0432\u0435\u0440 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043e\u0434\u043d\u0438\u043c \u0434\u0435\u043f\u043b\u043e\u0435\u043c. \u0421\u0442\u0430\u0440\u044b\u0439 \u043a\u043b\u0438\u0435\u043d\u0442 \u043f\u0440\u043e\u0442\u0438\u0432 \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043f\u0430\u0434\u0430\u0435\u0442 \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u043c \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0438 \u043a \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438. \u0423 \u043d\u0430\u0441 \u0432\u0435\u0440\u0441\u0438\u0438 \u043e\u0434\u043d\u0430\u0436\u0434\u044b \u0440\u0430\u0437\u044a\u0435\u0445\u0430\u043b\u0438\u0441\u044c \u0432 \u043f\u0440\u043e\u0434\u0435 \u2014 \u044d\u0442\u043e \u0441\u0442\u043e\u0438\u043b\u043e \u0434\u0432\u0435\u043d\u0430\u0434\u0446\u0430\u0442\u0438 \u0447\u0430\u0441\u043e\u0432 \u0442\u0438\u0445\u043e\u0439 \u043f\u043e\u0442\u0435\u0440\u0438 \u043f\u0430\u043c\u044f\u0442\u0438, \u043f\u043e\u043a\u0430 \u0447\u0430\u0441\u0442\u044c \u0432\u043e\u0440\u043a\u0435\u0440\u043e\u0432 \u043f\u0438\u0441\u0430\u043b\u0430 \u0432 \u043f\u0443\u0441\u0442\u043e\u0442\u0443.\u041b\u0438\u043c\u0438\u0442 \u0444\u0430\u0439\u043b\u043e\u0432\u044b\u0445 \u0434\u0435\u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0440\u043e\u0432. Rust-\u0432\u0435\u0440\u0441\u0438\u044f \u0434\u0435\u0440\u0436\u0438\u0442 \u043f\u043e sqlite-\u0444\u0430\u0439\u043b\u0443 \u043d\u0430 \u0441\u0435\u0433\u043c\u0435\u043d\u0442; \u043d\u0430 \u0442\u044b\u0441\u044f\u0447\u0430\u0445 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0439 \u043e\u043d\u0430 \u043f\u0440\u043e\u0431\u0438\u0432\u0430\u0435\u0442 \u0434\u0435\u0444\u043e\u043b\u0442\u043d\u044b\u0439 nofile=1024, \u0441\u0435\u0440\u0432\u0435\u0440 \u0432\u0441\u0442\u0430\u0451\u0442 \u043d\u0430\u043c\u0435\u0440\u0442\u0432\u043e \u2014 \u0430 \u043a\u043b\u0438\u0435\u043d\u0442 1.x \u0432\u0434\u043e\u0431\u0430\u0432\u043e\u043a \u0437\u0430\u0448\u0438\u0432\u0430\u0435\u0442 \u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0439 \u0442\u0430\u0439\u043c\u0430\u0443\u0442, \u0438 \u0442\u043e\u0433\u0434\u0430 \u0432\u0438\u0441\u043d\u0435\u0442 \u0443\u0436\u0435 \u0432\u0435\u0441\u044c \u0431\u043e\u0442, \u0443 \u0432\u0441\u0435\u0445 \u0441\u0440\u0430\u0437\u0443. \u041b\u0435\u0447\u0438\u0442\u0441\u044f \u043f\u043e\u0434\u043d\u044f\u0442\u0438\u0435\u043c \u043b\u0438\u043c\u0438\u0442\u0430 (\u0442\u043e\u0436\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0435\u0440\u0435\u0437 \u043f\u0435\u0440\u0435\u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435):chromadb:  image: chromadb\/chroma:1.5.9  ulimits:    nofile: 262144\u041a\u0430\u043a \u043e\u0437\u0432\u0443\u0447\u0438\u0442\u044c \u043e\u0442\u0432\u0435\u0442?\u0413\u043e\u043b\u043e\u0441 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0437\u0430 \u0432\u0435\u0447\u0435\u0440: \u0442\u0435\u043a\u0441\u0442 \u0443\u0445\u043e\u0434\u0438\u0442 \u0432 TTS-\u0441\u0435\u0440\u0432\u0438\u0441, \u043e\u0431\u0440\u0430\u0442\u043d\u043e \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 mp3. \u042f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e Inworld TTS, \u043d\u0430 \u043e\u0448\u0438\u0431\u043a\u0435 \u043e\u0442\u043a\u0430\u0442\u044b\u0432\u0430\u044e\u0441\u044c \u043d\u0430 \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u0439 gTTS \u2014 \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0445\u043e\u0442\u044f \u0431\u044b \u0447\u0442\u043e-\u0442\u043e \u0443\u0441\u043b\u044b\u0448\u0430\u043b.\u041a\u043b\u044e\u0447 \u0434\u043b\u044f Inworld. \u0421\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u0438 platform.inworld.ai (\u0440\u0430\u0437\u0434\u0435\u043b API Keys) \u2014 \u044d\u0442\u043e \u0441\u0442\u0440\u043e\u043a\u0430 \u0432 Base64, \u043e\u043d\u0430 \u0438\u0434\u0451\u0442 \u0432 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0435 Authorization: Basic. \u041a\u043b\u0430\u0434\u0451\u043c \u0432 INWORLD_API_KEY, \u0430 voiceId \u0431\u0435\u0440\u0451\u043c \u0442\u0430\u043c \u0436\u0435 \u0438\u0437 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0430 \u0433\u043e\u043b\u043e\u0441\u043e\u0432.import base64, httpxasync def text_to_speech(text, voice_id, lang=&#187;ru&#187;):    text = enrich_for_tts(text, lang)          # \u0433\u043e\u0442\u043e\u0432\u0438\u043c \u0442\u0435\u043a\u0441\u0442 (\u0441\u043c. \u043d\u0438\u0436\u0435)    body = {        &#171;text&#187;: text, &#171;voiceId&#187;: voice_id, &#171;modelId&#187;: TTS_MODEL,        &#171;audioConfig&#187;: {&#171;encoding&#187;: &#171;MP3&#187;, &#171;sampleRateHertz&#187;: 24000},    }    async with httpx.AsyncClient(timeout=30) as c:        r = await c.post(TTS_URL, json=body,                         headers={&#171;Authorization&#187;: f&#187;Basic {TTS_KEY}&#187;})    if r.status_code == 200:        return base64.b64decode(r.json()[&#171;audioContent&#187;])    return None                                # \u0434\u0430\u043b\u044c\u0448\u0435 \u2014 \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u0439 \u0437\u0430\u043f\u0430\u0441\u043d\u043e\u0439 gTTS\u041f\u043e\u0434\u0432\u043e\u0434\u043d\u044b\u0439 \u043a\u0430\u043c\u0435\u043d\u044c 3: \u0442\u0435\u0433\u0438 \u044d\u043c\u043e\u0446\u0438\u0439 [laugh]\/[sigh] \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442\u041f\u043e\u0447\u0442\u0438 \u043a\u0430\u0436\u0434\u044b\u0439 \u0433\u0430\u0439\u0434 \u043f\u043e TTS \u0441\u043e\u0432\u0435\u0442\u0443\u0435\u0442 \u0440\u0430\u0441\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u0442\u0435\u0433\u0438 \u0432\u0440\u043e\u0434\u0435 [laugh], [sigh], [breathe]. \u041c\u044b \u0442\u0430\u043a \u0438 \u0441\u0434\u0435\u043b\u0430\u043b\u0438 \u2014 \u0438 \u043a\u0430\u043a\u043e\u0435-\u0442\u043e \u0432\u0440\u0435\u043c\u044f \u043d\u0435\u0434\u043e\u0443\u043c\u0435\u0432\u0430\u043b\u0438, \u043f\u043e\u0447\u0435\u043c\u0443 \u0433\u043e\u043b\u043e\u0441 \u0437\u0432\u0443\u0447\u0438\u0442 \u0440\u043e\u0432\u043d\u043e \u0442\u0430\u043a \u0436\u0435, \u043a\u0430\u043a \u0431\u0435\u0437 \u043d\u0438\u0445. \u041a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e \u0443 Inworld TTS-1.5 Max \u044d\u0442\u0438\u0445 \u0442\u0435\u0433\u043e\u0432 \u043f\u043e\u043f\u0440\u043e\u0441\u0442\u0443 \u043d\u0435\u0442: \u0442\u0435\u0433 \u043b\u0438\u0431\u043e \u043f\u0440\u043e\u0433\u043b\u0430\u0442\u044b\u0432\u0430\u0435\u0442\u0441\u044f, \u043b\u0438\u0431\u043e \u2014 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u043d\u0430 \u0440\u0443\u0441\u0441\u043a\u043e\u043c \u2014 \u0437\u0430\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432\u0441\u043b\u0443\u0445 \u043a\u0430\u043a \u0442\u0435\u043a\u0441\u0442. \u0423 \u0434\u0440\u0443\u0433\u0438\u0445 \u0434\u0432\u0438\u0436\u043a\u043e\u0432, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 ElevenLabs, \u0430\u0443\u0434\u0438\u043e-\u0442\u0435\u0433\u0438 \u0431\u044b\u0432\u0430\u044e\u0442, \u0442\u0430\u043a \u0447\u0442\u043e \u0441\u0432\u0435\u0440\u044f\u0439\u0442\u0435\u0441\u044c \u0441\u043e \u0441\u0432\u043e\u0438\u043c.\u042d\u043c\u043e\u0446\u0438\u044e \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-484354","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/484354","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=484354"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/484354\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=484354"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=484354"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=484354"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}