{"id":376439,"date":"2024-05-21T06:50:56","date_gmt":"2024-05-21T06:50:56","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=376439"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=376439","title":{"rendered":"<span>\u041a\u0430\u043a \u0418\u0418 \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0435\u0442 \u043e \u0432\u0438\u0434\u0435\u043e \u0438\u0437 YouTube: \u0438\u043b\u0438 RAG Telegram \u0431\u043e\u0442 \u0441 langchain \u0438 \u0434\u043e\u043a\u0435\u0440\u0430\u043c\u0438<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<blockquote>\n<p>\u00ab\u0421\u0430\u043c\u044b\u0439 \u0446\u0435\u043d\u043d\u044b\u0439 \u0440\u0435\u0441\u0443\u0440\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c, \u2014 \u044d\u0442\u043e \u0432\u0440\u0435\u043c\u044f\u00bb. \u2014 \u0421\u0442\u0438\u0432 \u0414\u0436\u043e\u0431\u0441<\/p>\n<\/blockquote>\n<h2>\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435<\/h2>\n<p>\u0412 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u043e\u0441\u0432\u043e\u0435\u043d\u0438\u044f \u0438\u0441\u043a\u0443\u0441\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u043b\u043b\u0435\u043a\u0442\u0430 \u0438 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u043a\u0430\u0436\u0434\u044b\u0439 \u0448\u0430\u0433 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u0433\u0440\u0443\u0437\u0438\u0442\u044c\u0441\u044f \u0432 \u043c\u0438\u0440 \u043d\u043e\u0432\u044b\u0445 \u0437\u043d\u0430\u043d\u0438\u0439 \u0438 \u043d\u0430\u0432\u044b\u043a\u043e\u0432. <\/p>\n<p>\u0411\u043e\u0442 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043d \u0434\u043b\u044f \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b Telegram, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0447\u0430\u0442-\u0431\u043e\u0442\u043e\u0432, \u043d\u043e \u0438 \u043e\u0431\u043b\u0430\u0434\u0430\u0435\u0442 \u0448\u0438\u0440\u043e\u043a\u0438\u043c\u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044f\u043c\u0438 \u0434\u043b\u044f \u043e\u0431\u043c\u0435\u043d\u0430 \u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u0438\u043c \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u043e\u043c \u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u0433\u043e\u043b\u043e\u0441\u043e\u0432\u044b\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f. \u042d\u0442\u043e\u0442 \u043e\u043f\u044b\u0442 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u043e\u043b\u0435\u0437\u0435\u043d \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0447\u0430\u0442-\u0431\u043e\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u043e\u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0437\u0430\u043a\u0430\u0437\u0447\u0438\u043a\u0443 \u0440\u0430\u0431\u043e\u0442\u0443 \u043d\u0435\u0439\u0440\u043e\u043d\u043d\u043e\u0439 \u0441\u0435\u0442\u0438. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u043d\u0435\u0439\u0440\u043e\u0441\u0435\u0442\u044c, \u0434\u043b\u044f \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u044f \u043f\u043e\u0440\u043e\u0434\u044b \u043a\u043e\u0448\u0435\u043a \u043f\u043e \u0438\u0445 \u043c\u0443\u0440\u043b\u044b\u043a\u0430\u043d\u044c\u044e. <\/p>\n<p>\u0414\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0431\u043e\u0442\u0430 \u0431\u044b\u043b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a aiogram, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0432\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 Telegram API. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0430\u0441\u044c Large Language Model (LLM) \u043e\u0442 \u0421\u0431\u0435\u0440\u0430. \u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u044d\u0442\u0438\u043c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u043c \u0431\u043e\u0442 \u0441\u043f\u043e\u0441\u043e\u0431\u0435\u043d \u043a\u0440\u0430\u0442\u043a\u043e \u043f\u0435\u0440\u0435\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u0432\u0438\u0434\u0435\u043e \u0438 \u043e\u0442\u0432\u0435\u0447\u0430\u0442\u044c \u043d\u0430 \u0432\u043e\u043f\u0440\u043e\u0441\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u042f \u043f\u0440\u043e\u0431\u043e\u0432\u0430\u043b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c YandexGPT, \u043d\u043e GigaChat \u0432\u0441\u0435 \u0436\u0435 \u043f\u043e\u043a\u0430\u0437\u0430\u043b \u0441\u0435\u0431\u044f \u043b\u0443\u0447\u0448\u0435, \u0438 \u043c\u043e\u0439 \u0432\u044b\u0431\u043e\u0440 \u0431\u044b\u043b \u0441\u0434\u0435\u043b\u0430\u043d. \u041e\u0431\u0435 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442 \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u0439 \u043f\u0435\u0440\u0438\u043e\u0434 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f. \u041e\u0434\u043d\u0430\u043a\u043e, \u0435\u0441\u0442\u044c \u0438 \u043c\u0438\u043d\u0443\u0441 \u0432 GigaChat &#8212; \u0437\u0430 \u0435\u0433\u043e Embeddings \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u043f\u043b\u0430\u0442\u0438\u0442\u044c.<\/p>\n<p>RAG (Retrieval-Augmented Generation) \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u043c\u0435\u0442\u043e\u0434 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0435\u0441\u0442\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u044f\u0437\u044b\u043a\u0430 (NLP), \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u0435\u0442 \u0434\u0432\u0430 \u0432\u0430\u0436\u043d\u044b\u0445 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430: \u043f\u043e\u0438\u0441\u043a \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u0438 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044e \u0442\u0435\u043a\u0441\u0442\u0430. \u041f\u0440\u0435\u0436\u0434\u0435 \u0432\u0441\u0435\u0433\u043e, \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b RAG \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0432\u0435\u043a\u0442\u043e\u0440\u043d\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435, \u0433\u0434\u0435 \u043a\u0430\u0436\u0434\u043e\u043c\u0443 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u043c\u0443 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u0443 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0432\u0435\u043a\u0442\u043e\u0440 \u0432 \u043c\u043d\u043e\u0433\u043e\u043c\u0435\u0440\u043d\u043e\u043c \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0435. \u042d\u0442\u043e \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u0431\u044b\u0441\u0442\u0440\u044b\u0439 \u0438 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u044b\u0439 \u043f\u043e\u0438\u0441\u043a \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u0438\u0445 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u043e\u0432 \u0442\u0435\u043a\u0441\u0442\u0430 \u0434\u043b\u044f \u0437\u0430\u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430. \u0414\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0432\u0435\u043a\u0442\u043e\u0440\u0430 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043c\u0435\u0442\u043e\u0434 \u0432\u0435\u043a\u0442\u043e\u0440\u043d\u044b\u0445 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0439 (Embeddings). \u041c\u043e\u0434\u0443\u043b\u044c langchain \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u043c\u0438 \u0432\u0435\u043a\u0442\u043e\u0440\u043d\u044b\u043c\u0438 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f\u043c\u0438, \u0442\u0430\u043a\u0438\u043c\u0438 \u043a\u0430\u043a OpenAIEmbeddings, GigaChatEmbeddings, YandexGPTEmbeddings, HuggingFaceEmbeddings \u0438 \u0434\u0440\u0443\u0433\u0438\u043c\u0438. \u0422\u0430\u043a\u0436\u0435 langchain \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0432\u0435\u043a\u0442\u043e\u0440\u043d\u044b\u043c\u0438 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430\u043c\u0438, \u0442\u0430\u043a\u0438\u043c\u0438 \u043a\u0430\u043a Chroma, Faiss \u0438 \u0434\u0440\u0443\u0433\u0438\u043c\u0438.<\/p>\n<p>\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438\u0449\u0435\u0442 \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0440\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d\u044b\u0435 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u044b \u0442\u0435\u043a\u0441\u0442\u0430 \u0432 \u0432\u0435\u043a\u0442\u043e\u0440\u043d\u043e\u043c \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435. \u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u044d\u0442\u0430\u043f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438, \u0433\u0434\u0435 \u043c\u043e\u0434\u0435\u043b\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u043d\u0430\u0439\u0434\u0435\u043d\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u043e\u0442\u0432\u0435\u0442\u0430. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e langchain \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043a \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0443 \u0447\u0430\u0442-\u043c\u043e\u0434\u0435\u043b\u0435\u0439, \u0442\u0430\u043a\u0438\u0445 \u043a\u0430\u043a ChatOpenAI, ChatYandexGPT, GigaChat \u0438 \u0434\u0440\u0443\u0433\u0438\u0445.<\/p>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, RAG \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0432\u043d\u044b\u0435 \u0438 \u0433\u0440\u0430\u043c\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0435 \u043e\u0442\u0432\u0435\u0442\u044b, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u043a\u0430\u043a \u043d\u0430\u0439\u0434\u0435\u043d\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e, \u0442\u0430\u043a \u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0442\u0435\u043a\u0441\u0442\u0430 \u043c\u043e\u0434\u0435\u043b\u0438.<\/p>\n<p>\u0412\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u043c \u044d\u0442\u0430\u043f\u043e\u043c \u0434\u043b\u044f \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u044f \u0438\u0445 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0441\u0442\u0438 \u0438 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u043c\u043e\u0441\u0442\u0438, \u0438 Docker Compose \u0432\u044b\u0441\u0442\u0443\u043f\u0430\u0435\u0442 \u043a\u0430\u043a \u0443\u0434\u043e\u0431\u043d\u044b\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0432 \u044d\u0442\u043e\u0439 \u043e\u0431\u043b\u0430\u0441\u0442\u0438. Docker \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430\u0445. \u042d\u0442\u043e \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u0438\u0437\u043e\u043b\u044f\u0446\u0438\u044e, \u043b\u0435\u0433\u043a\u043e\u0441\u0442\u044c \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u0443\u043f\u0440\u043e\u0449\u0430\u0435\u0442 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438 \u0438 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435\u043c. <\/p>\n<h2>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h2>\n<p>\u041f\u0440\u043e\u0435\u043a\u0442 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0434\u0432\u0443\u0445 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432: \u043e\u0434\u0438\u043d \u0434\u043b\u044f Redis, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445, \u0430 \u0432\u0442\u043e\u0440\u043e\u0439 \u0434\u043b\u044f Python, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0438\u0440\u0443\u0435\u0442 Telegram \u0431\u043e\u0442.<\/p>\n<details class=\"spoiler\">\n<summary>\u0424\u0430\u0439\u043b\u043e\u0432\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430:<\/summary>\n<div class=\"spoiler__content\">\n<ul>\n<li>\n<p><strong>redis<\/strong>:<\/p>\n<ul>\n<li>\n<p>\u0414\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f Redis \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0444\u0430\u0439\u043b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 <code>redis.conf<\/code><\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>youtubot<\/strong>:<\/p>\n<ul>\n<li>\n<p>\u0414\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f Python \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0444\u0430\u0439\u043b\u044b Telegram \u0431\u043e\u0442\u0430: <\/p>\n<ul>\n<li>\n<p><code>Dockerfile<\/code>: \u0424\u0430\u0439\u043b, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0439 \u0434\u043b\u044f \u0441\u0431\u043e\u0440\u043a\u0438 Docker-\u043e\u0431\u0440\u0430\u0437\u0430 Python.<\/p>\n<\/li>\n<li>\n<p><code>requirements.txt<\/code>: \u0424\u0430\u0439\u043b, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0439 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 Python \u043f\u0440\u043e\u0435\u043a\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p><code>tests\/<\/code>: \u0414\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u044b \u043c\u043e\u0434\u0443\u043b\u044c\u043d\u044b\u0435 \u0442\u0435\u0441\u0442\u044b \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u043a\u043e\u0434\u0430.<\/p>\n<\/li>\n<li>\n<p><code>bot\/<\/code>: \u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f \u0431\u043e\u0442\u0430, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0430\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0444\u0430\u0439\u043b\u044b \u0438 \u043f\u043e\u0434\u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438: <\/p>\n<ul>\n<li>\n<p><code>handlers\/<\/code>: \u0414\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f \u0441 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439.<\/p>\n<\/li>\n<li>\n<p><code>llm.py<\/code>: \u0424\u0430\u0439\u043b, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u044b \u043c\u0435\u0442\u043e\u0434\u044b \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 Large Language Models.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><code>config.py<\/code>: \u0424\u0430\u0439\u043b \u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p><code>main.py<\/code>: \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0444\u0430\u0439\u043b, \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044e\u0449\u0438\u0439 \u0431\u043e\u0442\u0430.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>docker-compose.yml<\/strong>:<\/p>\n<ul>\n<li>\n<p>\u0424\u0430\u0439\u043b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 Docker Compose, \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430. \u042d\u0442\u043e\u0442 \u0444\u0430\u0439\u043b \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0438 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u0443\u0434\u043e\u0431\u043d\u044b\u0439 \u0437\u0430\u043f\u0443\u0441\u043a \u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430\u043c\u0438 Redis \u0438 Python.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/div>\n<\/details>\n<p><a href=\"http:\/\/main.py\" rel=\"noopener noreferrer nofollow\">main.py<\/a> \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043b\u043e\u0433\u0438\u043a\u0443 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043a Redis, \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0431\u043e\u0442\u0430, \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439, \u0437\u0430\u043f\u0443\u0441\u043a \u043f\u043e\u043b\u043b\u0438\u043d\u0433\u0430 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u043e\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u043d\u0435\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u043d\u044b\u0445 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439. \u0414\u043b\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043a Redis \u0432 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435 \u043d\u0443\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434\u043c\u043e\u0434\u0443\u043b\u044c <code>redis.asyncio<\/code>.<\/p>\n<details class=\"spoiler\">\n<summary>main.py<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">import os import asyncio import logging import redis.asyncio as redis import aiogram as ag import config as cf from bot.handlers import users  # \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f logger = logging.getLogger(__name__)  async def main():     # \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0443\u0440\u043e\u0432\u043d\u044f \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f DEBUG     if os.getenv('DEBUG'):         logging.basicConfig(level=logging.DEBUG, format=cf.logging_format)      # \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a Redis     db = redis.Redis(         host=os.getenv('REDIS_HOST', 'localhost'),         port=os.environ['REDIS_PORT'],         password=os.getenv('REDIS_PASSWORD'),         decode_responses=True  # \u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043e\u0442\u0432\u0435\u0442\u043e\u0432 \u0438\u0437 \u0431\u0430\u0439\u0442\u043e\u0432 \u0432 \u0441\u0442\u0440\u043e\u043a\u0438     )     logger.info('Redis connected.')      try:         # \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0431\u043e\u0442\u0430 \u0438 \u0434\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440\u0430         bot = ag.Bot(token=os.environ['TELEGRAM_BOT_TOKEN'])         dp = ag.Dispatcher(bot=bot, storage=ag.fsm.storage.memory.MemoryStorage())          # \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432         await users.setup(bot, dp, db)         logger.info('users.setup is done.')          # \u0423\u0434\u0430\u043b\u0435\u043d\u0438\u0435 webhook \u0438 \u0437\u0430\u043f\u0443\u0441\u043a \u043f\u043e\u043b\u043b\u0438\u043d\u0433\u0430         await bot.delete_webhook(drop_pending_updates=True)         logger.info('Starting polling...')         await dp.start_polling(bot, allowed_updates=dp.resolve_used_update_types())     finally:         # \u0417\u0430\u043a\u0440\u044b\u0442\u0438\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u0441 Redis         await db.aclose()  if __name__ == '__main__':     # \u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0438\u0437 \u0444\u0430\u0439\u043b\u0430 .env \u0438 \u0437\u0430\u043f\u0443\u0441\u043a \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438     import dotenv     dotenv.load_dotenv()     asyncio.run(main()) <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>users.py \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0432 \u0431\u043e\u0442\u0435. \u0412 \u043d\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u0440\u043e\u0443\u0442\u0435\u0440 (router), \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u044e \u0438 \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u043f\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c. \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u044b \u0434\u0432\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439. \u041f\u0435\u0440\u0432\u044b\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a start_handler \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u043d\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0443 &#171;\/start&#187;, \u0432\u0442\u043e\u0440\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a message_handler \u0434\u043b\u044f \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0445 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439. \u0414\u043b\u044f \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439, \u0432 aiogram \u0443\u0434\u043e\u0431\u043d\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u00ab\u043c\u0430\u0433\u0438\u0447\u0435\u0441\u043a\u0438\u043c F \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u043c\u00bb.<\/p>\n<pre><code class=\"python\">router.message.filter( ag.F.chat.type == 'private' )<\/code><\/pre>\n<p>\u0440\u0430\u0437\u0440\u0435\u0448\u0430\u0435\u0442 \u0432\u0441\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0443 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f <code>chat.type<\/code> == &#171;private&#187;. \u0410 \u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440<\/p>\n<pre><code class=\"python\">@router.message(ag.F.text, ag.filters.Command('start'))<\/code><\/pre>\n<p>\u0440\u0430\u0437\u0440\u0435\u0448\u0430\u0435\u0442 \u0432\u0441\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0443 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043d\u0435 \u043f\u0443\u0441\u0442\u0430\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f text \u0438 \u0438\u043c\u0435\u0435\u0442 \u0432\u0438\u0434 \u043a\u043e\u043c\u0430\u043d\u0434\u044b &#171;start&#187;. <\/p>\n<details class=\"spoiler\">\n<summary>users.py<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">import asyncio import aiogram as ag from typing import Any, Callable, Dict, Awaitable from aiogram.types import Message, TelegramObject from aiogram.utils.chat_action import ChatActionSender from .. import llm  # \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0440\u043e\u0443\u0442\u0435\u0440\u0430 \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 router = ag.Router() router.message.filter(ag.F.chat.type == 'private')  # \u0424\u0438\u043b\u044c\u0442\u0440 \u0434\u043b\u044f \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0445 \u0447\u0430\u0442\u043e\u0432  # \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043a\u043e\u043c\u0430\u043d\u0434\u044b '\/start' @router.message(ag.F.text, ag.filters.Command(\"start\")) async def start_handler(msg: Message):     await msg.answer(\"\u0417\u0434\u0440\u0430\u0432\u0441\u0442\u0432\u0443\u0439\u0442\u0435! \u042f \u043c\u043e\u0433\u0443 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043b\u044e\u0431\u043e\u0439 \u0440\u043e\u043b\u0438\u043a \u0438\u0437 YouTube \u0438 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u0442\u044c \u0432\u0430\u043c \u043e \u043d\u0435\u043c. \"                      \"\u041f\u0440\u0438\u0448\u043b\u0438\u0442\u0435 \u043c\u043d\u0435 \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u0440\u043e\u043b\u0438\u043a \u0438 \u0437\u0430\u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043b\u044e\u0431\u044b\u0435 \u0432\u043e\u043f\u0440\u043e\u0441\u044b.\")  # \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0432\u0441\u0435\u0445 \u043f\u0440\u043e\u0447\u0438\u0445 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 @router.message(ag.F.text) async def message_handler(msg: Message, llm_answer):     # \u041f\u0435\u0440\u0435\u0434\u0430\u0447\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u0437\u0430\u0434\u0430\u0447\u0443     await llm_answer.user_query(msg)  # Middleware \u0434\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 class UsersMiddleware(ag.BaseMiddleware):     def __init__(self, llm_answer):         super().__init__()         self.llm_answer = llm_answer          async def __call__(         self,         handler: Callable[[ag.types.TelegramObject, Dict[str, Any]], Awaitable[Any]],         event: ag.types.TelegramObject,         data: Dict[str, Any],     ) -> Any:         # \u041f\u0435\u0440\u0435\u0434\u0430\u0447\u0430 \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u0437\u0430\u0434\u0430\u0447\u0443 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0432 \u043a\u0430\u0436\u0434\u044b\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u0437\u0430\u043f\u0440\u043e\u0441         data['llm_answer'] = self.llm_answer         # \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0441\u0442\u0430\u0442\u0443\u0441\u0430 \"...\u043f\u0435\u0447\u0430\u0442\u0430\u0435\u0442\"         async with ChatActionSender(bot=data['bot'], chat_id=event.chat.id, action='typing'):             # \u0412\u044b\u0437\u043e\u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0433\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439             return await handler(event, data)  # \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u0438 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0442\u043e\u0440\u0430 async def setup(bot, dispatcher, db):     router.message.middleware(UsersMiddleware(llm.UsersLLMAnswer(db)))     dispatcher.include_routers(router) <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0422\u0430\u043a\u0436\u0435 <code>users.py<\/code> \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043a\u043b\u0430\u0441\u0441 <code>UsersMiddleware<\/code>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d \u043c\u0435\u0442\u043e\u0434 <code>__call__<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043a\u0430\u0436\u0434\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435, \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c, \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442 \u0435\u0433\u043e \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a. \u041a\u043b\u0430\u0441\u0441 <code>ChatActionSender<\/code> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0441\u0442\u0430\u0442\u0443\u0441 &#171;&#8230;\u043f\u0435\u0447\u0430\u0442\u0430\u0435\u0442&#187; \u0432 \u043c\u0435\u0441\u0441\u0435\u043d\u0434\u0436\u0435\u0440\u0435 \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439. \u0412 \u043c\u0435\u0442\u043e\u0434\u0435 <code>__call__<\/code> \u043a\u043b\u0430\u0441\u0441\u0430 <code>UsersMiddleware<\/code> \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f <code>data<\/code> \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u043b\u043e\u0432\u0430\u0440\u0435\u043c \u0438 \u043c\u043e\u0436\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0432 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438. \u0422\u0430\u043a, \u0447\u0435\u0440\u0435\u0437 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e <code>llm_answer<\/code> \u0432 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f \u043e\u0431\u044a\u0435\u043a\u0442 <code>UsersLLMAnswer<\/code>, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0439 \u043b\u043e\u0433\u0438\u043a\u0443 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 RAG. \u041a\u043b\u0430\u0441\u0441 <code>UsersLLMAnswer<\/code> \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u0432 \u0444\u0430\u0439\u043b\u0435 llm.py. \u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0435\u0433\u043e \u0434\u0435\u0442\u0430\u043b\u044c\u043d\u043e.<\/p>\n<details class=\"spoiler\">\n<summary>user_query<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">    async def user_query(self, msg):          # \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0443 (\u0435\u0441\u043b\u0438 \u043e\u043d\u0430 \u0435\u0441\u0442\u044c) \u043d\u0430 \u044e\u0442\u0443\u0431 \u0432\u0438\u0434\u0435\u043e \u0438\u0437 \u0437\u0430\u043f\u0440\u043e\u0441\u0430         query, ids = self.get_video_id(msg.text)         #~ print(query, ids)         if ids:              # \u0435\u0441\u043b\u0438 \u0437\u0430\u043f\u0440\u043e\u0441 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u0432\u0438\u0434\u0435\u043e             if len(ids) > 1:                 await self.a_post(msg, '\u042f \u0437\u0430\u043f\u043e\u043c\u043d\u0438\u043b \u0432\u0438\u0434\u0435\u043e \u043f\u043e \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0439 \u0441\u0441\u044b\u043b\u043a\u0435, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e '                                                         '\u043c\u043e\u0433\u0443 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u043e \u0432\u0438\u0434\u0435\u043e \u0437\u0430 \u0440\u0430\u0437.')             else:                 await self.a_post(msg, '\u042f \u0437\u0430\u043f\u043e\u043c\u043d\u0438\u043b \u044d\u0442\u043e \u0432\u0438\u0434\u0435\u043e.')              # \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043f\u043e id             user = self.user_info.setdefault(msg.from_user.id, {})              # \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 faiss db \u0438 \u043e\u0431\u044a\u0435\u043a\u0442 langchain             user['chain'], faiss = await self.create_chain(ids[-1])             if not query:                 # \u0435\u0441\u043b\u0438 \u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u0431\u044b\u043b\u0430 \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u0441\u044b\u043b\u043a\u0430                 # \u0441\u0443\u043c\u0430\u0440\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u0435\u0441\u044c \u0440\u043e\u043b\u0438\u043a                 await self.summarize(msg, ids[-1], faiss)                 await self.a_post(msg, '\u042f \u043c\u043e\u0433\u0443 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u0442\u044c \u0435\u0449\u0435 \u0447\u0442\u043e-\u043d\u0438\u0431\u0443\u0434\u044c \u043f\u043e \u044d\u0442\u043e\u043c\u0443 \u0432\u0438\u0434\u0435\u043e.')                 return          if (user := self.user_info.get(msg.from_user.id)) is None:             # \u0435\u0441\u043b\u0438 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0435\u0449\u0435 \u043d\u0435 \u0441\u043e\u0437\u0434\u0430\u043d             await self.a_post(msg, '\u042f \u043d\u0435 \u0437\u043d\u0430\u044e \u043a \u043a\u0430\u043a\u043e\u043c\u0443 \u0432\u0438\u0434\u0435\u043e \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0441\u044f \u0437\u0430\u043f\u0440\u043e\u0441.\\n'                                                     '\u041f\u0440\u0438\u0448\u043b\u0438\u0442\u0435 \u043f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430 \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u0432\u0438\u0434\u0435\u043e \u0438\u0437 YouTube.')         else:             await self.a_query_answer(msg, user['chain'], query) <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041f\u0440\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0432 \u043c\u0435\u0442\u043e\u0434\u0435 <code>get_video_id<\/code>, \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f &#171;\u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u044b\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f&#187;, \u0447\u0442\u043e\u0431\u044b \u043d\u0430\u0439\u0442\u0438 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 YouTube \u0432\u0438\u0434\u0435\u043e. \u0415\u0441\u043b\u0438 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u043d\u0430\u0439\u0434\u0435\u043d, \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u0432\u0435\u043a\u0442\u043e\u0440\u043d\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 FAISS \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0432\u0438\u0434\u0435\u043e. \u0415\u0441\u043b\u0438 \u0437\u0430\u043f\u0440\u043e\u0441 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u0432\u0438\u0434\u0435\u043e, \u0434\u0435\u043b\u0430\u0435\u0442\u0441\u044f \u043a\u0440\u0430\u0442\u043a\u0438\u0439 \u043f\u0435\u0440\u0435\u0441\u043a\u0430\u0437 \u0435\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f. \u0415\u0441\u043b\u0438 \u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u0435\u0441\u0442\u044c \u0442\u0435\u043a\u0441\u0442, \u0442\u043e \u0432\u043c\u0435\u0441\u0442\u043e \u043a\u0440\u0430\u0442\u043a\u043e\u0433\u043e \u043f\u0435\u0440\u0435\u0441\u043a\u0430\u0437\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043c\u0435\u0442\u043e\u0434 RAG \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u043e\u0442\u0432\u0435\u0442\u0430. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u0442\u0441\u044f RAG \u0446\u0435\u043f\u043e\u0447\u043a\u0430 \u0432 \u043c\u0435\u0442\u043e\u0434\u0435 <code>create_chain<\/code>.<\/p>\n<details class=\"spoiler\">\n<summary>create_chain<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">    async def create_chain(self, id):          faiss = await self.create_faiss(id)         faiss_cell = faiss.as_retriever(k=cf.chunks_by_query_from_faiss) | self.joiner         retrieval_pass = RunnableParallel( {             \"context\": faiss_cell,             \"query\": RunnablePassthrough() })         chain = retrieval_pass | self.prompt | self.llm | StrOutputParser()         return chain, faiss       def joiner(self, docs):         \"\"\" \u041e\u0431\u044a\u0435\u0434\u0435\u043d\u0438\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0447\u0430\u043d\u043a\u043e\u0432 \u0438\u0437 \u0432\u0435\u043a\u0442\u043e\u0440\u043d\u043e\u0433\u043e \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430 \"\"\"         sorted_docs = list(sorted(docs, key=lambda x: x.metadata['start']))         return ' '.join(d.page_content for d in sorted_docs)       async def create_faiss(self, video_id):          redis_key = f'faiss_db\/{video_id}'         faiss_db = await self.redis.get(redis_key)         if faiss_db:             # \u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0432\u0435\u043a\u0442\u043e\u0440\u043d\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0438\u0437 \u0444\u0430\u0439\u043b\u0430              return FAISS.deserialize_from_bytes( embeddings=self.embeddinger, serialized=faiss_db)                      # \u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u044b \u0438\u0437 \u0432\u0438\u0434\u0435\u043e          transcript, language_code = self.load_youtube_transcript(video_id)          # \u0421\u043e\u0437\u0434\u0430\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0438\u0437 \u0447\u0430\u043d\u043a\u043e\u0432 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043e\u0432         docs = self.join_transcript_to_docs(transcript, cf.max_chunk_size)          # \u0421\u043e\u0437\u0434\u0430\u0442\u044c \u0432\u0435\u043a\u0442\u043e\u0440\u043d\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435         search_index = await FAISS.afrom_documents( docs, self.embeddinger )          # \u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432 \u0444\u0430\u0439\u043b \u0432\u0435\u043a\u0442\u043e\u0440\u043d\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435         await self.redis.set(redis_key, search_index.serialize_to_bytes())      # serializes the faiss          return search_index<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0421\u043d\u0430\u0447\u0430\u043b\u0430, \u0432 \u043c\u0435\u0442\u043e\u0434\u0435 <code>create_faiss<\/code>, \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u0438\u043b\u0438 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442\u0441\u044f \u0440\u0430\u043d\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u0435 \u0432\u0435\u043a\u0442\u043e\u0440\u043d\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 FAISS \u0434\u043b\u044f \u0432\u0438\u0434\u0435\u043e \u043f\u043e \u0435\u0433\u043e \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0443 \u043d\u0430 YouTube. \u0424\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u044d\u0442\u043e \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0438\u0437 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043e\u0432 \u0432\u0438\u0434\u0435\u043e, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u044e\u0442\u0441\u044f \u0432 \u043c\u0435\u0442\u043e\u0434\u0435 <code>load_youtube_transcript<\/code>. \u0417\u0430\u0442\u0435\u043c \u044d\u0442\u0438 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u044b \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044e\u0442\u0441\u044f  \u0432 \u0431\u043e\u043b\u0435\u0435 \u043a\u0440\u0443\u043f\u043d\u044b\u0435 \u0431\u043b\u043e\u043a\u0438 \u0438 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0432\u0435\u043a\u0442\u043e\u0440\u043d\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 FAISS. \u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442\u0441\u044f \u0432 Redis.<\/p>\n<p>\u0417\u0430\u0442\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f RAG \u0446\u0435\u043f\u043e\u0447\u043a\u0430 \u0434\u043b\u044f \u043e\u0442\u0432\u0435\u0442\u043e\u0432 \u043d\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u044b. \u0424\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a <code>langchain<\/code> \u043f\u043e\u043c\u043e\u0433\u0430\u0435\u0442 \u0443\u0434\u043e\u0431\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u0431\u043b\u043e\u043a\u0438 LCEL \u0438 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u0442\u044c \u0438\u0445 \u0432 \u0446\u0435\u043f\u043e\u0447\u043a\u0438. \u041f\u0435\u0440\u0432\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0446\u0435\u043f\u043e\u0447\u043a\u0438 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430 FAISS \u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 <code>RunnablePassthrough<\/code>. \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u044f\u0447\u0435\u0439\u043a\u0443 <code>self.prompt<\/code>, \u0433\u0434\u0435 \u0437\u0430\u043f\u0440\u043e\u0441 \u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0440\u0430\u0431\u043e\u0442\u044b \u0432\u0435\u043a\u0442\u043e\u0440\u043d\u043e\u0433\u043e \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u044e\u0442\u0441\u044f \u0441 \u043f\u0440\u043e\u043c\u043f\u0442\u043e\u043c \u0438 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0432 LLM \u043c\u043e\u0434\u0435\u043b\u044c \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u043e\u0442\u0432\u0435\u0442\u0430. \u0417\u0430\u0442\u0435\u043c \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0439 \u044f\u0447\u0435\u0439\u043a\u043e\u0439 <code>StrOutputParser()<\/code> \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u0442\u0441\u044f \u0442\u0435\u043a\u0441\u0442 \u043e\u0442\u0432\u0435\u0442\u0430 \u0438\u0437 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u043e\u0442\u0432\u0435\u0442\u0430.<\/p>\n<p><code>Langchain<\/code> \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0435\u0434\u0438\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0434\u043b\u044f \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0439 \u0446\u0435\u043f\u043e\u0447\u0435\u043a. <\/p>\n<pre><code class=\"python\"># \u041f\u0440\u043e\u0441\u0442\u043e\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u043e\u0442\u0432\u0435\u0442 text = await \u0441hain.ainvoke(\"\u0426\u0432\u0435\u0442 \u0441\u043e\u043b\u043d\u0446\u0430\")  # \u041f\u043e\u0442\u043e\u043a\u043e\u0432\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441, \u043e\u0442\u0432\u0435\u0442 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 \u043f\u043e\u0440\u0446\u0438\u044f\u043c\u0438 async for chunk in chain.astream(\"\u0426\u0432\u0435\u0442 \u0441\u043e\u043b\u043d\u0446\u0430\"): print(chunk, end=\"\", flush=True)  # \u0421\u043f\u0438\u0441\u043e\u043a \u043e\u0442\u0432\u0435\u0442\u043e\u0432 \u043d\u0430 \u0441\u043f\u0438\u0441\u043e\u043a \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0435\u0434\u0438\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e text_list = await \u0441hain.abatch([\"\u0426\u0432\u0435\u0442 \u0441\u043e\u043b\u043d\u0446\u0430\",\"\u0426\u0432\u0435\u0442 \u043b\u0443\u043d\u044b\"])<\/code><\/pre>\n<p>\u0414\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0438\u0437 \u044d\u0442\u0438\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0432 langchain \u0435\u0441\u0442\u044c \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434, \u0441 \u0442\u0435\u043c \u0436\u0435 \u0438\u043c\u0435\u043d\u0435\u043c, \u043d\u043e \u0431\u0435\u0437 &#171;a&#187; \u0432\u043d\u0430\u0447\u0430\u043b\u0435.<\/p>\n<p>\u041e\u0434\u0438\u043d \u0438\u0437 \u044d\u0442\u0438\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 <code>a_query_answer<\/code>. <\/p>\n<details class=\"spoiler\">\n<summary>a_query_answer<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">    async def a_query_answer(self, msg, chain, query):         try:             # \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043e\u0442\u0432\u0435\u0442 \u043e\u0442 LLM \u043d\u0430 \u0437\u0430\u043f\u0440\u043e\u0441 \u043f\u043e\u043b\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f             text = await chain.ainvoke(query)         except GigaChatException:             # \u0417\u0430\u043f\u0438\u0441\u044c \u0432 \u043b\u043e\u0433 \u0432\u0441\u0435\u0445 \u043e\u0448\u0438\u0431\u043e\u043a aiogram \u043f\u0440\u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0435 \u0432 \u0447\u0430\u0442             logger.exception('GigaChatException!')         else:             await self.a_post(msg, text)             return text       async def a_post(self, msg, text):         \"\"\" \u041e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0442\u0435\u043a\u0441\u0442 \u0432 Telegram \u0447\u0430\u0442 \"\"\"         try:             await msg.answer(text)         except AiogramError:             # \u0417\u0430\u043f\u0438\u0441\u044c \u0432 \u043b\u043e\u0433 \u0432\u0441\u0435\u0445 \u043e\u0448\u0438\u0431\u043e\u043a aiogram \u043f\u0440\u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0435 \u0432 \u0447\u0430\u0442             logger.exception('AiogramError!') <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0412 \u043d\u0435\u043c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0430 \u0442\u0435\u043a\u0441\u0442\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0432 RAG \u0446\u0435\u043f\u043e\u0447\u043a\u0443, \u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 \u043e\u0442\u0432\u0435\u0442 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e Telegram \u0431\u043e\u0442\u0430.<\/p>\n<p>\u041a\u0440\u0430\u0442\u043a\u0438\u0439 \u043f\u0435\u0440\u0435\u0441\u043a\u0430\u0437 \u0432\u0438\u0434\u0435\u043e \u0440\u043e\u043b\u0438\u043a\u0430 \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c \u043c\u0435\u0442\u043e\u0434\u0435.<\/p>\n<details class=\"spoiler\">\n<summary>summarize<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">    async def summarize(self, msg, id, faiss):          redis_key = f'summarizing\/{id}'                  # \u041f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u043d\u0443\u044e \u0441\u0443\u043c\u0430\u0440\u0438\u0437\u0430\u0446\u0438\u044e \u0438\u0437 \u0411\u0414         text = await self.redis.get(redis_key)         if text:             for chunk in text.split(b'\\n'):                 await self.a_post(msg, chunk.decode())             return          # \u041f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a, \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u044b\u0445 \u043f\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u0447\u0430\u043d\u043a\u043e\u0432 \u0442\u0435\u043a\u0441\u0442\u0430 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043e\u0432 \u0438\u0437 Faiss \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430         docs = list(sorted(faiss.docstore._dict.values(), key=lambda x: x.metadata['start']))         join_docs = []          # \u0421\u0434\u0435\u043b\u0430\u0442\u044c \u043a\u0430\u0436\u0434\u044b\u0439 \u0431\u043b\u043e\u043a \u0434\u043b\u044f \u0441\u0443\u043c\u0430\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0438\u0437 `cf.chunks_by_query_from_faiss` \u0448\u0442\u0443\u043a Faiss \u0447\u0430\u043d\u043a\u043e\u0432          for i in range(0, len(docs), cf.chunks_by_query_from_faiss):             chunks = '\\n'.join(d.page_content for d in docs[i:i+cf.chunks_by_query_from_faiss])             join_docs.append( chunks )          # LLM \u0446\u0435\u043f\u043e\u0447\u043a\u0430 \u0434\u043b\u044f \u0441\u0443\u043c\u0430\u0440\u0438\u0437\u0430\u0446\u0438\u0438         chain = self.prompt_sum | self.llm | StrOutputParser()           chunks = []         for doc in join_docs:             # \u0421\u0443\u043c\u0430\u0440\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u043b\u043e\u043a \u0442\u0435\u043a\u0441\u0442\u0430 \u0434\u043e 25 \u0441\u043b\u043e\u0432 \u043f\u0440\u0438\u0431\u043b\u0438\u0437\u0438\u0442\u0435\u043b\u044c\u043d\u043e             text = await self.a_query_answer(msg, chain, {'max_words': '25', 'text': doc})             if text:                 chunks.append(text.encode())         if chunks:             # \u041e\u0431\u044a\u0435\u0434\u0435\u043d\u0438\u0442\u044c \u0441\u0443\u043c\u0430\u0440\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0431\u043b\u043e\u043a\u0438 \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0432 \u0411\u0414             await self.redis.set(redis_key, b'\\n'.join(chunks)) <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0414\u043b\u044f \u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0438, \u043a\u0440\u0430\u0442\u043a\u0438\u0439 \u043f\u0435\u0440\u0435\u0441\u043a\u0430\u0437 \u0442\u0430\u043a\u0436\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u0432 Redis \u0438 \u043d\u0435 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u0435\u0440\u0435\u0441\u043a\u0430\u0437\u0430 \u043d\u0435\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0432 \u043f\u043e\u0438\u0441\u043a\u0435 \u043f\u043e \u0432\u0435\u043a\u0442\u043e\u0440\u043d\u043e\u043c\u0443 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0443, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 langchain \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u0437 \u0442\u0440\u0435\u0445 \u044f\u0447\u0435\u0435\u043a: \u043f\u0440\u043e\u043c\u043f\u0442, \u043c\u043e\u0434\u0435\u043b\u0438 \u0438 \u0432\u044b\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u043f\u0430\u0440\u0441\u0435\u0440\u0430.<\/p>\n<p>\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043e\u0432 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432 \u043c\u0435\u0442\u043e\u0434\u0435 <code>load_youtube_transcript<\/code> \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043c\u043e\u0434\u0443\u043b\u044f youtube_transcript_api. \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u043c\u0435\u0442\u043e\u0434 <code>YouTubeTranscriptApi.list_transcripts<\/code> \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0435 \u0442\u0438\u043f\u044b \u0438 \u044f\u0437\u044b\u043a\u0438 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043e\u0432. \u041f\u0440\u0438\u043e\u0440\u0438\u0442\u0435\u0442 \u043e\u0442\u0434\u0430\u0435\u0442\u0441\u044f \u0430\u0432\u0442\u043e\u0440\u0441\u043a\u0438\u043c \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u0430\u043c \u043d\u0430 \u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u043e\u043c \u044f\u0437\u044b\u043a\u0435. \u0417\u0430\u0442\u0435\u043c \u043c\u0435\u0442\u043e\u0434 <code>YouTubeTranscriptApi.get_transcript<\/code> \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u0441\u0430\u043c\u0438 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u044b. <\/p>\n<details class=\"spoiler\">\n<summary>load_youtube_transcript<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">    def load_youtube_transcript(self, video_id):          # \u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043e\u0432 \u0438\u0437 youtube \u0432\u0438\u0434\u0435\u043e         transcript_list = yta.YouTubeTranscriptApi.list_transcripts(video_id)         generated = set()         manual = set()          for tra in transcript_list:             if tra.is_generated:                 # \u0421\u043e\u0437\u0434\u0430\u0442\u044c \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0445 \u044f\u0437\u044b\u043a\u043e\u0432 \u0442\u0435\u043a\u0441\u0442\u0430 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043e\u0432, \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0445 youtube \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u043c                 generated.add(tra.language_code)             else:                 # \u0421\u043e\u0437\u0434\u0430\u0442\u044c \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0445 \u044f\u0437\u044b\u043a\u043e\u0432 \u0442\u0435\u043a\u0441\u0442\u0430 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043e\u0432, \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0445 \u0430\u0432\u0442\u043e\u0440\u043e\u043c                 manual.add(tra.language_code)         if manual:             language_code = 'en' if 'en' in manual else manual.pop()         else:             language_code = 'en' if 'en' in generated else generated.pop()                  # \u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u044b \u0438\u0437 youtube \u0432\u0438\u0434\u0435\u043e         transcript = yta.YouTubeTranscriptApi.get_transcript(video_id, languages=[language_code]) # , proxies={\"https\": \"https:\/\/user:pass@domain:port\"} # format used by the requests library         return transcript, language_code <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u043a\u043b\u0430\u0441\u0441\u0430 <code>UsersLLMAnswer<\/code> \u043d\u0435 \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u044b \u0432 \u0441\u0442\u0430\u0442\u044c\u0435. \u041f\u043e\u043b\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0438 \u0432\u0435\u0441\u044c \u043f\u0440\u043e\u0435\u043a\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u043d\u0430 <a href=\"https:\/\/github.com\/stepvg\/youtubot\" rel=\"noopener noreferrer nofollow\">GitHub<\/a>. \u0422\u0430\u043a\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f Embeddings \u043e\u0442 HuggingFace. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0432 \u0444\u0430\u0439\u043b\u0435 .env, \u043f\u043e\u043c\u0438\u043c\u043e TELEGRAM_BOT_TOKEN \u0438 GIGACHAT_CREDENTIALS, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e HUGGING_FACE_EMBEDDINGS, \u0433\u0434\u0435 \u043c\u043e\u0436\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0438\u043c\u044f \u043c\u043e\u0434\u0435\u043b\u0438, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 &#171;sentence-transformers\/paraphrase-multilingual-MiniLM-L12-v2&#187;. \u0418\u043b\u0438 \u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e \u043f\u0443\u0441\u0442\u043e\u0439, \u0435\u0441\u043b\u0438 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u043f\u043b\u0430\u0442\u043d\u044b\u0439 \u0434\u043e\u0441\u0442\u0443\u043f \u043a GigaChat.  <\/p>\n<h2>\u0412\u044b\u0432\u043e\u0434\u044b<\/h2>\n<p>\u041f\u0440\u043e\u0435\u043a\u0442 \u0438\u043b\u043b\u044e\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u0442 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a GigaChat \u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432 langchain \u0438 aiogram \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f RAG Telegram \u0431\u043e\u0442\u0430 \u0434\u043b\u044f \u0430\u043d\u0430\u043b\u0438\u0437\u0430 \u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0432\u0438\u0434\u0435\u043e\u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0430 \u0441 YouTube. \u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u044d\u0442\u043e\u043c\u0443 \u0441\u043e\u0447\u0435\u0442\u0430\u043d\u0438\u044e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0441 \u043b\u0435\u0433\u043a\u043e\u0441\u0442\u044c\u044e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0431\u043e\u0442\u0430, \u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0433\u043e \u043a\u0440\u0430\u0442\u043a\u043e \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0438\u0437 \u0432\u0438\u0434\u0435\u043e \u0438 \u043e\u0442\u0432\u0435\u0447\u0430\u0442\u044c \u043d\u0430 \u0432\u043e\u043f\u0440\u043e\u0441\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439.<\/p>\n<p>\u0423\u0434\u043e\u0431\u0441\u0442\u0432\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f Docker Compose \u0434\u043b\u044f \u0434\u0435\u043f\u043b\u043e\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0431\u044b\u0441\u0442\u0440\u043e \u0438 \u043b\u0435\u0433\u043a\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0435\u0433\u043e \u0432 \u0441\u0432\u043e\u0435\u0439 \u0441\u0440\u0435\u0434\u0435. \u042d\u0442\u043e\u0442 \u043f\u043e\u0434\u0445\u043e\u0434 \u0434\u0435\u043b\u0430\u0435\u0442 \u043f\u0440\u043e\u0435\u043a\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u043c \u0434\u043b\u044f \u0448\u0438\u0440\u043e\u043a\u043e\u0433\u043e \u043a\u0440\u0443\u0433\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439, \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u0443 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f.<\/p>\n<p>\u041e\u0434\u043d\u0430\u043a\u043e \u0435\u0441\u0442\u044c \u0435\u0449\u0435 \u043c\u043d\u043e\u0433\u043e\u0435, \u043a\u0443\u0434\u0430 \u043c\u043e\u0436\u043d\u043e \u0441\u0442\u0440\u0435\u043c\u0438\u0442\u044c\u0441\u044f. \u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u0430 &#171;\u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u0441\u0442\u0438&#187; \u0432 \u043f\u0440\u043e\u0435\u043a\u0442 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u043b\u043e \u0431\u044b \u0431\u043e\u0442\u0443 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0441 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c\u0438 \u0431\u043e\u043b\u0435\u0435 \u0435\u0441\u0442\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0447\u0442\u043e \u043f\u043e\u0432\u044b\u0441\u0438\u043b\u043e \u0431\u044b \u0435\u0433\u043e \u043f\u043e\u043b\u0435\u0437\u043d\u043e\u0441\u0442\u044c \u0438 \u043f\u0440\u0438\u0432\u043b\u0435\u043a\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c. \u0423\u0447\u0435\u0442 \u0440\u043e\u0434\u043d\u043e\u0433\u043e \u044f\u0437\u044b\u043a\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u043e\u0442\u0432\u0435\u0442\u043e\u0432 \u043d\u0430 \u0435\u0433\u043e \u044f\u0437\u044b\u043a\u0435 \u0441\u0434\u0435\u043b\u0430\u043b \u0431\u044b \u0431\u043e\u0442\u0430 \u0431\u043e\u043b\u0435\u0435 \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u043c. \u0412 \u0446\u0435\u043b\u043e\u043c, \u043f\u0440\u043e\u0435\u043a\u0442 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442, \u0447\u0442\u043e \u0441 \u0434\u043e\u0441\u0442\u0443\u043f\u043e\u043c \u043a GigaChat \u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430\u043c langchain \u0438 aiogram \u043c\u043e\u0436\u043d\u043e \u043b\u0435\u0433\u043a\u043e \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0438\u043d\u043d\u043e\u0432\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u044f.<\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \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\/815187\/\"> https:\/\/habr.com\/ru\/articles\/815187\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<blockquote>\n<p>\u00ab\u0421\u0430\u043c\u044b\u0439 \u0446\u0435\u043d\u043d\u044b\u0439 \u0440\u0435\u0441\u0443\u0440\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c, \u2014 \u044d\u0442\u043e \u0432\u0440\u0435\u043c\u044f\u00bb. \u2014 \u0421\u0442\u0438\u0432 \u0414\u0436\u043e\u0431\u0441<\/p>\n<\/blockquote>\n<h2>\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435<\/h2>\n<p>\u0412 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u043e\u0441\u0432\u043e\u0435\u043d\u0438\u044f \u0438\u0441\u043a\u0443\u0441\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u043b\u043b\u0435\u043a\u0442\u0430 \u0438 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u043a\u0430\u0436\u0434\u044b\u0439 \u0448\u0430\u0433 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u0433\u0440\u0443\u0437\u0438\u0442\u044c\u0441\u044f \u0432 \u043c\u0438\u0440 \u043d\u043e\u0432\u044b\u0445 \u0437\u043d\u0430\u043d\u0438\u0439 \u0438 \u043d\u0430\u0432\u044b\u043a\u043e\u0432. <\/p>\n<p>\u0411\u043e\u0442 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043d \u0434\u043b\u044f \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b Telegram, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0447\u0430\u0442-\u0431\u043e\u0442\u043e\u0432, \u043d\u043e \u0438 \u043e\u0431\u043b\u0430\u0434\u0430\u0435\u0442 \u0448\u0438\u0440\u043e\u043a\u0438\u043c\u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044f\u043c\u0438 \u0434\u043b\u044f \u043e\u0431\u043c\u0435\u043d\u0430 \u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u0438\u043c \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u043e\u043c \u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u0433\u043e\u043b\u043e\u0441\u043e\u0432\u044b\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f. \u042d\u0442\u043e\u0442 \u043e\u043f\u044b\u0442 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u043e\u043b\u0435\u0437\u0435\u043d \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0447\u0430\u0442-\u0431\u043e\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u043e\u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0437\u0430\u043a\u0430\u0437\u0447\u0438\u043a\u0443 \u0440\u0430\u0431\u043e\u0442\u0443 \u043d\u0435\u0439\u0440\u043e\u043d\u043d\u043e\u0439 \u0441\u0435\u0442\u0438. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u043d\u0435\u0439\u0440\u043e\u0441\u0435\u0442\u044c, \u0434\u043b\u044f \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u044f \u043f\u043e\u0440\u043e\u0434\u044b \u043a\u043e\u0448\u0435\u043a \u043f\u043e \u0438\u0445 \u043c\u0443\u0440\u043b\u044b\u043a\u0430\u043d\u044c\u044e. <\/p>\n<p>\u0414\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0431\u043e\u0442\u0430 \u0431\u044b\u043b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a aiogram, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0432\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 Telegram API. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0430\u0441\u044c Large Language Model (LLM) \u043e\u0442 \u0421\u0431\u0435\u0440\u0430. \u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u044d\u0442\u0438\u043c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u043c \u0431\u043e\u0442 \u0441\u043f\u043e\u0441\u043e\u0431\u0435\u043d \u043a\u0440\u0430\u0442\u043a\u043e \u043f\u0435\u0440\u0435\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u0432\u0438\u0434\u0435\u043e \u0438 \u043e\u0442\u0432\u0435\u0447\u0430\u0442\u044c \u043d\u0430 \u0432\u043e\u043f\u0440\u043e\u0441\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u042f \u043f\u0440\u043e\u0431\u043e\u0432\u0430\u043b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c YandexGPT, \u043d\u043e GigaChat \u0432\u0441\u0435 \u0436\u0435 \u043f\u043e\u043a\u0430\u0437\u0430\u043b \u0441\u0435\u0431\u044f \u043b\u0443\u0447\u0448\u0435, \u0438 \u043c\u043e\u0439 \u0432\u044b\u0431\u043e\u0440 \u0431\u044b\u043b \u0441\u0434\u0435\u043b\u0430\u043d. \u041e\u0431\u0435 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442 \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u0439 \u043f\u0435\u0440\u0438\u043e\u0434 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f. \u041e\u0434\u043d\u0430\u043a\u043e, \u0435\u0441\u0442\u044c \u0438 \u043c\u0438\u043d\u0443\u0441 \u0432 GigaChat &#8212; \u0437\u0430 \u0435\u0433\u043e Embeddings \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u043f\u043b\u0430\u0442\u0438\u0442\u044c.<\/p>\n<p>RAG (Retrieval-Augmented Generation) \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u043c\u0435\u0442\u043e\u0434 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0435\u0441\u0442\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u044f\u0437\u044b\u043a\u0430 (NLP), \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u0435\u0442 \u0434\u0432\u0430 \u0432\u0430\u0436\u043d\u044b\u0445 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430: \u043f\u043e\u0438\u0441\u043a \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u0438 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044e \u0442\u0435\u043a\u0441\u0442\u0430. \u041f\u0440\u0435\u0436\u0434\u0435 \u0432\u0441\u0435\u0433\u043e, \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b RAG \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0432\u0435\u043a\u0442\u043e\u0440\u043d\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435, \u0433\u0434\u0435 \u043a\u0430\u0436\u0434\u043e\u043c\u0443 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u043c\u0443 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u0443 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0432\u0435\u043a\u0442\u043e\u0440 \u0432 \u043c\u043d\u043e\u0433\u043e\u043c\u0435\u0440\u043d\u043e\u043c \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0435. \u042d\u0442\u043e \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u0431\u044b\u0441\u0442\u0440\u044b\u0439 \u0438 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u044b\u0439 \u043f\u043e\u0438\u0441\u043a \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u0438\u0445 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u043e\u0432 \u0442\u0435\u043a\u0441\u0442\u0430 \u0434\u043b\u044f \u0437\u0430\u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430. \u0414\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0432\u0435\u043a\u0442\u043e\u0440\u0430 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043c\u0435\u0442\u043e\u0434 \u0432\u0435\u043a\u0442\u043e\u0440\u043d\u044b\u0445 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0439 (Embeddings). \u041c\u043e\u0434\u0443\u043b\u044c langchain \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u043c\u0438 \u0432\u0435\u043a\u0442\u043e\u0440\u043d\u044b\u043c\u0438 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f\u043c\u0438, \u0442\u0430\u043a\u0438\u043c\u0438 \u043a\u0430\u043a OpenAIEmbeddings, GigaChatEmbeddings, YandexGPTEmbeddings, HuggingFaceEmbeddings \u0438 \u0434\u0440\u0443\u0433\u0438\u043c\u0438. \u0422\u0430\u043a\u0436\u0435 langchain \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0432\u0435\u043a\u0442\u043e\u0440\u043d\u044b\u043c\u0438 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430\u043c\u0438, \u0442\u0430\u043a\u0438\u043c\u0438 \u043a\u0430\u043a Chroma, Faiss \u0438 \u0434\u0440\u0443\u0433\u0438\u043c\u0438.<\/p>\n<p>\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438\u0449\u0435\u0442 \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0440\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d\u044b\u0435 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u044b \u0442\u0435\u043a\u0441\u0442\u0430 \u0432 \u0432\u0435\u043a\u0442\u043e\u0440\u043d\u043e\u043c \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435. \u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u044d\u0442\u0430\u043f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438, \u0433\u0434\u0435 \u043c\u043e\u0434\u0435\u043b\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u043d\u0430\u0439\u0434\u0435\u043d\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u043e\u0442\u0432\u0435\u0442\u0430. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e langchain \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043a \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0443 \u0447\u0430\u0442-\u043c\u043e\u0434\u0435\u043b\u0435\u0439, \u0442\u0430\u043a\u0438\u0445 \u043a\u0430\u043a ChatOpenAI, ChatYandexGPT, GigaChat \u0438 \u0434\u0440\u0443\u0433\u0438\u0445.<\/p>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, RAG \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0432\u043d\u044b\u0435 \u0438 \u0433\u0440\u0430\u043c\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0435 \u043e\u0442\u0432\u0435\u0442\u044b, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u043a\u0430\u043a \u043d\u0430\u0439\u0434\u0435\u043d\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e, \u0442\u0430\u043a \u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0442\u0435\u043a\u0441\u0442\u0430 \u043c\u043e\u0434\u0435\u043b\u0438.<\/p>\n<p>\u0412\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u043c \u044d\u0442\u0430\u043f\u043e\u043c \u0434\u043b\u044f \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u044f \u0438\u0445 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0441\u0442\u0438 \u0438 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u043c\u043e\u0441\u0442\u0438, \u0438 Docker Compose \u0432\u044b\u0441\u0442\u0443\u043f\u0430\u0435\u0442 \u043a\u0430\u043a \u0443\u0434\u043e\u0431\u043d\u044b\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0432 \u044d\u0442\u043e\u0439 \u043e\u0431\u043b\u0430\u0441\u0442\u0438. Docker \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430\u0445. \u042d\u0442\u043e \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u0438\u0437\u043e\u043b\u044f\u0446\u0438\u044e, \u043b\u0435\u0433\u043a\u043e\u0441\u0442\u044c \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u0443\u043f\u0440\u043e\u0449\u0430\u0435\u0442 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438 \u0438 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435\u043c. <\/p>\n<h2>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h2>\n<p>\u041f\u0440\u043e\u0435\u043a\u0442 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0434\u0432\u0443\u0445 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432: \u043e\u0434\u0438\u043d \u0434\u043b\u044f Redis, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445, \u0430 \u0432\u0442\u043e\u0440\u043e\u0439 \u0434\u043b\u044f Python, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0438\u0440\u0443\u0435\u0442 Telegram \u0431\u043e\u0442.<\/p>\n<details class=\"spoiler\">\n<summary>\u0424\u0430\u0439\u043b\u043e\u0432\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430:<\/summary>\n<div class=\"spoiler__content\">\n<ul>\n<li>\n<p><strong>redis<\/strong>:<\/p>\n<ul>\n<li>\n<p>\u0414\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f Redis \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0444\u0430\u0439\u043b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 <code>redis.conf<\/code><\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>youtubot<\/strong>:<\/p>\n<ul>\n<li>\n<p>\u0414\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f Python \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0444\u0430\u0439\u043b\u044b Telegram \u0431\u043e\u0442\u0430: <\/p>\n<ul>\n<li>\n<p><code>Dockerfile<\/code>: \u0424\u0430\u0439\u043b, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0439 \u0434\u043b\u044f \u0441\u0431\u043e\u0440\u043a\u0438 Docker-\u043e\u0431\u0440\u0430\u0437\u0430 Python.<\/p>\n<\/li>\n<li>\n<p><code>requirements.txt<\/code>: \u0424\u0430\u0439\u043b, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0439 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 Python \u043f\u0440\u043e\u0435\u043a\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p><code>tests\/<\/code>: \u0414\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u044b \u043c\u043e\u0434\u0443\u043b\u044c\u043d\u044b\u0435 \u0442\u0435\u0441\u0442\u044b \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u043a\u043e\u0434\u0430.<\/p>\n<\/li>\n<li>\n<p><code>bot\/<\/code>: \u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f \u0431\u043e\u0442\u0430, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0430\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0444\u0430\u0439\u043b\u044b \u0438 \u043f\u043e\u0434\u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438: <\/p>\n<ul>\n<li>\n<p><code>handlers\/<\/code>: \u0414\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f \u0441 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439.<\/p>\n<\/li>\n<li>\n<p><code>llm.py<\/code>: \u0424\u0430\u0439\u043b, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u044b \u043c\u0435\u0442\u043e\u0434\u044b \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 Large Language Models.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><code>config.py<\/code>: \u0424\u0430\u0439\u043b \u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p><code>main.py<\/code>: \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0444\u0430\u0439\u043b, \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044e\u0449\u0438\u0439 \u0431\u043e\u0442\u0430.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>docker-compose.yml<\/strong>:<\/p>\n<ul>\n<li>\n<p>\u0424\u0430\u0439\u043b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 Docker Compose, \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430. \u042d\u0442\u043e\u0442 \u0444\u0430\u0439\u043b \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0438 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u0443\u0434\u043e\u0431\u043d\u044b\u0439 \u0437\u0430\u043f\u0443\u0441\u043a \u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430\u043c\u0438 Redis \u0438 Python.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/div>\n<\/details>\n<p><a href=\"http:\/\/main.py\" rel=\"noopener noreferrer nofollow\">main.py<\/a> \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043b\u043e\u0433\u0438\u043a\u0443 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043a Redis, \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0431\u043e\u0442\u0430, \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439, \u0437\u0430\u043f\u0443\u0441\u043a \u043f\u043e\u043b\u043b\u0438\u043d\u0433\u0430 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u043e\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u043d\u0435\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u043d\u044b\u0445 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439. \u0414\u043b\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043a Redis \u0432 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435 \u043d\u0443\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434\u043c\u043e\u0434\u0443\u043b\u044c <code>redis.asyncio<\/code>.<\/p>\n<details class=\"spoiler\">\n<summary>main.py<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">import os import asyncio import logging import redis.asyncio as redis import aiogram as ag import config as cf from bot.handlers import users  # \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f logger = logging.getLogger(__name__)  async def main():     # \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0443\u0440\u043e\u0432\u043d\u044f \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f DEBUG     if os.getenv('DEBUG'):         logging.basicConfig(level=logging.DEBUG, format=cf.logging_format)      # \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a Redis     db = redis.Redis(         host=os.getenv('REDIS_HOST', 'localhost'),         port=os.environ['REDIS_PORT'],         password=os.getenv('REDIS_PASSWORD'),         decode_responses=True  # \u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043e\u0442\u0432\u0435\u0442\u043e\u0432 \u0438\u0437 \u0431\u0430\u0439\u0442\u043e\u0432 \u0432 \u0441\u0442\u0440\u043e\u043a\u0438     )     logger.info('Redis connected.')      try:         # \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0431\u043e\u0442\u0430 \u0438 \u0434\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440\u0430         bot = ag.Bot(token=os.environ['TELEGRAM_BOT_TOKEN'])         dp = ag.Dispatcher(bot=bot, storage=ag.fsm.storage.memory.MemoryStorage())          # \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432         await users.setup(bot, dp, db)         logger.info('users.setup is done.')          # \u0423\u0434\u0430\u043b\u0435\u043d\u0438\u0435 webhook \u0438 \u0437\u0430\u043f\u0443\u0441\u043a \u043f\u043e\u043b\u043b\u0438\u043d\u0433\u0430         await bot.delete_webhook(drop_pending_updates=True)         logger.info('Starting polling...')         await dp.start_polling(bot, allowed_updates=dp.resolve_used_update_types())     finally:         # \u0417\u0430\u043a\u0440\u044b\u0442\u0438\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u0441 Redis         await db.aclose()  if __name__ == '__main__':     # \u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0438\u0437 \u0444\u0430\u0439\u043b\u0430 .env \u0438 \u0437\u0430\u043f\u0443\u0441\u043a \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438     import dotenv     dotenv.load_dotenv()     asyncio.run(main()) <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>users.py \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0432 \u0431\u043e\u0442\u0435. \u0412 \u043d\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u0440\u043e\u0443\u0442\u0435\u0440 (router), \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u044e \u0438 \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u043f\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c. \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u044b \u0434\u0432\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439. \u041f\u0435\u0440\u0432\u044b\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a start_handler \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u043d\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0443 &#171;\/start&#187;, \u0432\u0442\u043e\u0440\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a message_handler \u0434\u043b\u044f \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0445 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439. \u0414\u043b\u044f \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439, \u0432 aiogram \u0443\u0434\u043e\u0431\u043d\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u00ab\u043c\u0430\u0433\u0438\u0447\u0435\u0441\u043a\u0438\u043c F \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u043c\u00bb.<\/p>\n<pre><code class=\"python\">router.message.filter( ag.F.chat.type == 'private' )<\/code><\/pre>\n<p>\u0440\u0430\u0437\u0440\u0435\u0448\u0430\u0435\u0442 \u0432\u0441\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0443 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f <code>chat.type<\/code> == &#171;private&#187;. \u0410 \u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440<\/p>\n<pre><code class=\"python\">@router.message(ag.F.text, ag.filters.Command('start'))<\/code><\/pre>\n<p>\u0440\u0430\u0437\u0440\u0435\u0448\u0430\u0435\u0442 \u0432\u0441\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0443 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043d\u0435 \u043f\u0443\u0441\u0442\u0430\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f text \u0438 \u0438\u043c\u0435\u0435\u0442 \u0432\u0438\u0434 \u043a\u043e\u043c\u0430\u043d\u0434\u044b &#171;start&#187;. <\/p>\n<details class=\"spoiler\">\n<summary>users.py<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">import asyncio import aiogram as ag from typing import Any, Callable, Dict, Awaitable from aiogram.types import Message, TelegramObject from aiogram.utils.chat_action import ChatActionSender from .. import llm  # \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0440\u043e\u0443\u0442\u0435\u0440\u0430 \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 router = ag.Router() router.message.filter(ag.F.chat.type == 'private')  # \u0424\u0438\u043b\u044c\u0442\u0440 \u0434\u043b\u044f \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0445 \u0447\u0430\u0442\u043e\u0432  # \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043a\u043e\u043c\u0430\u043d\u0434\u044b '\/start' @router.message(ag.F.text, ag.filters.Command(\"start\")) async def start_handler(msg: Message):     await msg.answer(\"\u0417\u0434\u0440\u0430\u0432\u0441\u0442\u0432\u0443\u0439\u0442\u0435! \u042f \u043c\u043e\u0433\u0443 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043b\u044e\u0431\u043e\u0439 \u0440\u043e\u043b\u0438\u043a \u0438\u0437 YouTube \u0438 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u0442\u044c \u0432\u0430\u043c \u043e \u043d\u0435\u043c. \"                      \"\u041f\u0440\u0438\u0448\u043b\u0438\u0442\u0435 \u043c\u043d\u0435 \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u0440\u043e\u043b\u0438\u043a \u0438 \u0437\u0430\u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043b\u044e\u0431\u044b\u0435 \u0432\u043e\u043f\u0440\u043e\u0441\u044b.\")  # \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0432\u0441\u0435\u0445 \u043f\u0440\u043e\u0447\u0438\u0445 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 @router.message(ag.F.text) async def message_handler(msg: Message, llm_answer):     # \u041f\u0435\u0440\u0435\u0434\u0430\u0447\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u0437\u0430\u0434\u0430\u0447\u0443     await llm_answer.user_query(msg)  # Middleware \u0434\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 class UsersMiddleware(ag.BaseMiddleware):     def __init__(self, llm_answer):         super().__init__()         self.llm_answer = llm_answer          async def __call__(         self,         handler: Callable[[ag.types.TelegramObject, Dict[str, Any]], Awaitable[Any]],         event: ag.types.TelegramObject,         data: Dict[str, Any],     ) -> Any:         # \u041f\u0435\u0440\u0435\u0434\u0430\u0447\u0430 \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u0437\u0430\u0434\u0430\u0447\u0443 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0432 \u043a\u0430\u0436\u0434\u044b\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u0437\u0430\u043f\u0440\u043e\u0441         data['llm_answer'] = self.llm_answer         # \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0441\u0442\u0430\u0442\u0443\u0441\u0430 \"...\u043f\u0435\u0447\u0430\u0442\u0430\u0435\u0442\"         async with ChatActionSender(bot=data['bot'], chat_id=event.chat.id, action='typing'):             # \u0412\u044b\u0437\u043e\u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0433\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439             return await handler(event, data)  # \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u0438 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0442\u043e\u0440\u0430 async def setup(bot, dispatcher, db):     router.message.middleware(UsersMiddleware(llm.UsersLLMAnswer(db)))     dispatcher.include_routers(router) <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0422\u0430\u043a\u0436\u0435 <code>users.py<\/code> \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043a\u043b\u0430\u0441\u0441 <code>UsersMiddleware<\/code>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d \u043c\u0435\u0442\u043e\u0434 <code>__call__<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043a\u0430\u0436\u0434\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435, \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c, \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442 \u0435\u0433\u043e \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a. \u041a\u043b\u0430\u0441\u0441 <code>ChatActionSender<\/code> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0441\u0442\u0430\u0442\u0443\u0441 &#171;&#8230;\u043f\u0435\u0447\u0430\u0442\u0430\u0435\u0442&#187; \u0432 \u043c\u0435\u0441\u0441\u0435\u043d\u0434\u0436\u0435\u0440\u0435 \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439. \u0412 \u043c\u0435\u0442\u043e\u0434\u0435 <code>__call__<\/code> \u043a\u043b\u0430\u0441\u0441\u0430 <code>UsersMiddleware<\/code> \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f <code>data<\/code> \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u043b\u043e\u0432\u0430\u0440\u0435\u043c \u0438 \u043c\u043e\u0436\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0432 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438. \u0422\u0430\u043a, \u0447\u0435\u0440\u0435\u0437 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e <code>llm_answer<\/code> \u0432 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f \u043e\u0431\u044a\u0435\u043a\u0442 <code>UsersLLMAnswer<\/code>, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0439 \u043b\u043e\u0433\u0438\u043a\u0443 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 RAG. \u041a\u043b\u0430\u0441\u0441 <code>UsersLLMAnswer<\/code> \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u0432 \u0444\u0430\u0439\u043b\u0435 llm.py. \u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0435\u0433\u043e \u0434\u0435\u0442\u0430\u043b\u044c\u043d\u043e.<\/p>\n<details class=\"spoiler\">\n<summary>user_query<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">    async def user_query(self, msg):          # \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0443 (\u0435\u0441\u043b\u0438 \u043e\u043d\u0430 \u0435\u0441\u0442\u044c) \u043d\u0430 \u044e\u0442\u0443\u0431 \u0432\u0438\u0434\u0435\u043e \u0438\u0437 \u0437\u0430\u043f\u0440\u043e\u0441\u0430         query, ids = self.get_video_id(msg.text)         #~ print(query, ids)         if ids:              # \u0435\u0441\u043b\u0438 \u0437\u0430\u043f\u0440\u043e\u0441 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u0432\u0438\u0434\u0435\u043e             if len(ids) > 1:                 await self.a_post(msg, '\u042f \u0437\u0430\u043f\u043e\u043c\u043d\u0438\u043b \u0432\u0438\u0434\u0435\u043e \u043f\u043e \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0439 \u0441\u0441\u044b\u043b\u043a\u0435, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e '                                                         '\u043c\u043e\u0433\u0443 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u043e \u0432\u0438\u0434\u0435\u043e \u0437\u0430 \u0440\u0430\u0437.')             else:                 await self.a_post(msg, '\u042f \u0437\u0430\u043f\u043e\u043c\u043d\u0438\u043b \u044d\u0442\u043e \u0432\u0438\u0434\u0435\u043e.')              # \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043f\u043e id             user = self.user_info.setdefault(msg.from_user.id, {})              # \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 faiss db \u0438 \u043e\u0431\u044a\u0435\u043a\u0442 langchain             user['chain'], faiss = await self.create_chain(ids[-1])             if not query:                 #<\/code><\/pre>\n<\/div>\n<\/details>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-376439","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/376439","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=376439"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/376439\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=376439"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=376439"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=376439"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}