{"id":485463,"date":"2026-06-29T11:46:30","date_gmt":"2026-06-29T11:46:30","guid":{"rendered":"https:\/\/savepearlharbor.com\/?p=485463"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=485463","title":{"rendered":"\u041a\u0430\u043a\u00a0\u0437\u0430\u0441\u0442\u0430\u0432\u0438\u0442\u044c LLM \u043f\u0440\u043e\u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0438\u0437\u00a0\u0442\u044b\u0441\u044f\u0447 \u0437\u0430\u043c\u0435\u0442\u043e\u043a, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043d\u0435\u00a0\u0432\u043b\u0435\u0437\u0430\u0435\u0442 \u0432\u00a0\u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442"},"content":{"rendered":"<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/751\/a8a\/f91\/751a8af912478d11059bd083d6f7625a.png\" width=\"1672\" height=\"941\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/751\/a8a\/f91\/751a8af912478d11059bd083d6f7625a.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/751\/a8a\/f91\/751a8af912478d11059bd083d6f7625a.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<p>\u0423\u00a0\u043c\u0435\u043d\u044f \u0432\u00a0Obsidian \u043d\u0430\u043a\u043e\u043f\u0438\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u00a0\u0434\u0432\u0435 \u0442\u044b\u0441\u044f\u0447\u0438 \u0437\u0430\u043c\u0435\u0442\u043e\u043a. \u0415\u0436\u0435\u0434\u043d\u0435\u0432\u043d\u0438\u043a\u0438, \u043a\u043e\u043d\u0441\u043f\u0435\u043a\u0442\u044b, \u043e\u0431\u0440\u044b\u0432\u043a\u0438 \u0438\u0434\u0435\u0439, \u043d\u0435\u0434\u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0435 \u0447\u0435\u0440\u043d\u043e\u0432\u0438\u043a\u0438. \u0413\u0440\u0430\u0444\u2011\u0432\u044c\u044e \u0447\u0435\u0441\u0442\u043d\u043e \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043c\u043d\u0435 \u043e\u0431\u043b\u0430\u043a\u043e \u0442\u043e\u0447\u0435\u043a: \u043a\u0440\u0430\u0441\u0438\u0432\u043e, \u043d\u043e\u00a0\u0431\u0435\u0441\u043f\u043e\u043b\u0435\u0437\u043d\u043e. \u041a\u0430\u043a\u0438\u0435 \u0437\u0430\u043c\u0435\u0442\u043a\u0438 \u0432\u0438\u0441\u044f\u0442 \u0441\u0438\u0440\u043e\u0442\u0430\u043c\u0438 \u0431\u0435\u0437\u00a0\u0435\u0434\u0438\u043d\u043e\u0439 \u0441\u0432\u044f\u0437\u0438, \u043a\u0430\u043a\u0438\u0435 \u0434\u0443\u0431\u043b\u0438\u0440\u0443\u044e\u0442 \u0434\u0440\u0443\u0433 \u0434\u0440\u0443\u0433\u0430 \u043f\u043e\u0434\u00a0\u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u0442\u0435\u0433\u0430\u043c\u0438, \u043a\u0430\u043a\u0438\u0435 \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u044b \u0442\u0435\u043c \u0442\u0430\u043a \u0438 \u043d\u0435\u00a0\u0441\u043e\u0435\u0434\u0438\u043d\u0438\u043b\u0438\u0441\u044c, \u0438\u0437\u00a0\u0433\u0440\u0430\u0444\u0430 \u043d\u0435\u00a0\u0432\u044b\u0442\u0430\u0449\u0438\u0442\u044c.<\/p>\n<p>\u041e\u0447\u0435\u0432\u0438\u0434\u043d\u0430\u044f \u043c\u044b\u0441\u043b\u044c: \u00ab\u043e\u0442\u0434\u0430\u043c \u0432\u0441\u0451 LLM, \u043f\u0443\u0441\u0442\u044c \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u0442\u0441\u044f\u00bb. \u041d\u043e 2000\u00a0\u0437\u0430\u043c\u0435\u0442\u043e\u043a \u044d\u0442\u043e \u043c\u0438\u043b\u043b\u0438\u043e\u043d\u044b \u0442\u043e\u043a\u0435\u043d\u043e\u0432. \u041d\u0438 \u0432\u00a0\u043e\u0434\u0438\u043d \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u044d\u0442\u043e \u043d\u0435\u00a0\u0432\u043b\u0435\u0437\u0430\u0435\u0442, \u0430\u00a0\u0435\u0441\u043b\u0438\u00a0\u0431\u044b \u0438 \u0432\u043b\u0435\u0437\u043b\u043e, \u0441\u0442\u043e\u0438\u043b\u043e\u00a0\u0431\u044b \u043a\u0430\u043a\u00a0\u043a\u0440\u044b\u043b\u043e \u0441\u0430\u043c\u043e\u043b\u0451\u0442\u0430 \u0438 \u0443\u0442\u043e\u043d\u0443\u043b\u043e\u00a0\u0431\u044b \u0432\u00a0\u0448\u0443\u043c\u0435.<\/p>\n<p>\u0422\u0430\u043a \u043f\u043e\u044f\u0432\u0438\u043b\u0441\u044f \u0438\u0434\u0435\u044f \u043f\u043e\u00a0\u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e <strong>Vault Audit AI<\/strong>, \u043f\u043b\u0430\u0433\u0438\u043d \u0434\u043b\u044f\u00a0Obsidian, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u043e\u0432\u043e\u0434\u0438\u0442 \u0430\u0443\u0434\u0438\u0442 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430 \u0447\u0435\u0440\u0435\u0437 LLM: \u043d\u0430\u0445\u043e\u0434\u0438\u0442 \u0441\u0438\u0440\u043e\u0442\u044b, \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0438\u0437\u0443\u0435\u0442 \u0442\u0435\u043c\u044b, \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442 \u0442\u0435\u0433\u0438 \u0438 \u0441\u0432\u044f\u0437\u0438. \u042f \u0435\u0433\u043e <a href=\"https:\/\/obsidian.md\/plugins\" rel=\"noopener noreferrer nofollow\">\u043e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u043b \u0432\u00a0\u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u043c \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0435<\/a> \u0438 <a href=\"https:\/\/github.com\/zinverno\/obsidian-ai-hub\" rel=\"noopener noreferrer nofollow\">\u0432\u044b\u043b\u043e\u0436\u0438\u043b \u043d\u0430\u00a0GitHub<\/a>. \u0412\u00a0\u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0440\u0430\u0437\u0431\u0435\u0440\u0443 \u0438\u043d\u0436\u0435\u043d\u0435\u0440\u043d\u0443\u044e \u043d\u0430\u0447\u0438\u043d\u043a\u0443: \u043a\u0430\u043a\u00a0\u043e\u0431\u043e\u0439\u0442\u0438\u00a0\u043b\u0438\u043c\u0438\u0442 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u0447\u0435\u0440\u0435\u0437 MapReduce, \u043a\u0430\u043a\u00a0\u043d\u0435\u00a0\u043f\u043b\u0430\u0442\u0438\u0442\u044c \u0437\u0430\u00a0\u043f\u043e\u0432\u0442\u043e\u0440\u043d\u044b\u0439 \u0430\u043d\u0430\u043b\u0438\u0437, \u043a\u0430\u043a\u00a0\u0430\u0431\u0441\u0442\u0440\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0447\u0435\u0442\u044b\u0440\u0451\u0445 LLM\u2011\u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u043e\u0432 \u043f\u043e\u0434\u00a0\u043e\u0434\u043d\u0438\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u043c, \u0438 \u0447\u0442\u043e\u00a0\u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u043f\u0435\u0440\u0435\u0434\u0435\u043b\u0430\u0442\u044c, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u0439\u0442\u0438 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u0440\u0435\u0432\u044c\u044e \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0430.<\/p>\n<p>\u041a\u043e\u0434 \u043d\u0430\u00a0TypeScript, \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u044b \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0435 (\u0441\u043b\u0435\u0433\u043a\u0430 \u043f\u043e\u0447\u0438\u0449\u0435\u043d\u044b \u043e\u0442\u00a0\u043e\u0431\u0451\u0440\u0442\u043e\u043a \u043b\u043e\u043a\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0440\u0430\u0434\u0438 \u0447\u0438\u0442\u0430\u0435\u043c\u043e\u0441\u0442\u0438).<\/p>\n<h3>MapReduce \u043f\u043e\u0432\u0435\u0440\u0445 LLM<\/h3>\n<p>\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u0440\u043e\u00a0\u0442\u043e, \u0447\u0442\u043e\u00a0\u0432\u0438\u0434\u0438\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c. \u0410\u0443\u0434\u0438\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u0432\u00a0\u0442\u0440\u0451\u0445 \u0440\u0435\u0436\u0438\u043c\u0430\u0445 \u043f\u043e\u0434\u00a0\u0440\u0430\u0437\u043d\u044b\u0439 \u043e\u0431\u044a\u0451\u043c \u0438 \u0431\u044e\u0434\u0436\u0435\u0442. Single \u0410\u0443\u0434\u0438\u0442 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0435\u0442 \u043e\u0434\u043d\u0443 \u0437\u0430\u043c\u0435\u0442\u043a\u0443 \u0437\u0430\u00a0\u0437\u0430\u043f\u0440\u043e\u0441 \u0441\u00a0\u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u043c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043e\u043c, \u0434\u043b\u044f\u00a0\u0442\u043e\u0447\u0435\u0447\u043d\u043e\u0433\u043e \u0433\u043b\u0443\u0431\u043e\u043a\u043e\u0433\u043e \u0430\u043d\u0430\u043b\u0438\u0437\u0430. Single \u041f\u043e\u043b\u043d\u044b\u0439 \u043f\u0440\u043e\u0433\u043e\u043d\u044f\u0435\u0442 \u0432\u0441\u0435 \u0437\u0430\u043c\u0435\u0442\u043a\u0438 \u043f\u043e\u0434\u0440\u044f\u0434, \u0438\u0433\u043d\u043e\u0440\u0438\u0440\u0443\u044f \u043a\u044d\u0448, \u0434\u043b\u044f\u00a0\u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0438\u043b\u0438\u00a0\u043f\u043e\u043b\u043d\u043e\u0433\u043e \u043f\u0435\u0440\u0435\u0441\u0431\u043e\u0440\u0430. \u0418 Batch + \u041e\u0442\u0447\u0451\u0442, \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u043c\u044b\u0439 \u0440\u0435\u0436\u0438\u043c: \u0431\u0430\u0442\u0447\u0435\u0432\u044b\u0439 \u0430\u043d\u0430\u043b\u0438\u0437 \u0441\u00a0\u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0438\u0437\u0430\u0446\u0438\u0435\u0439, \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0438\u043d\u0441\u0430\u0439\u0442\u0430\u043c\u0438 \u0438 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u043e\u0439 \u0432\u00a0Markdown \u0438 Canvas. \u0418\u043c\u0435\u043d\u043d\u043e \u0435\u0433\u043e \u044f \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u044e \u0434\u0430\u043b\u044c\u0448\u0435, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e\u00a0\u044d\u0442\u043e \u0438 \u0435\u0441\u0442\u044c \u043f\u043e\u043b\u043d\u044b\u0439 MapReduce\u2011\u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d, \u0440\u0430\u0434\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0432\u0441\u0451 \u0437\u0430\u0442\u0435\u0432\u0430\u043b\u043e\u0441\u044c.<\/p>\n<p>\u0414\u0430\u043b\u044c\u0448\u0435 \u043f\u0440\u043e\u00a0\u0442\u043e, \u043a\u0430\u043a\u00a0\u044d\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0435\u043d\u043e \u0432\u043d\u0443\u0442\u0440\u0438. \u041a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043f\u0440\u0438\u0451\u043c \u0438\u0437\u00a0\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u043b\u043e\u0436\u0438\u0442\u0441\u044f \u043d\u0430\u00a0\u0437\u0430\u0434\u0430\u0447\u0443 \u043e\u0434\u0438\u043d \u0432\u00a0\u043e\u0434\u0438\u043d. \u0415\u0441\u043b\u0438 \u0432\u0435\u0441\u044c \u043a\u043e\u0440\u043f\u0443\u0441 \u043d\u0435\u00a0\u0432\u043b\u0435\u0437\u0430\u0435\u0442 \u0432\u00a0\u043e\u0434\u0438\u043d \u0437\u0430\u043f\u0440\u043e\u0441, \u0431\u044c\u0451\u043c \u0435\u0433\u043e \u043d\u0430\u00a0\u0447\u0430\u0441\u0442\u0438, \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c \u043a\u0430\u0436\u0434\u0443\u044e \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e (<strong>Map<\/strong>), \u043f\u043e\u0442\u043e\u043c \u0430\u0433\u0440\u0435\u0433\u0438\u0440\u0443\u0435\u043c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0432\u00a0\u043e\u0434\u0438\u043d \u043f\u0440\u043e\u0445\u043e\u0434 (<strong>Reduce<\/strong>).<\/p>\n<p>\u0412\u0435\u0440\u0445\u043d\u0435\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u044b\u0439 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439 \u0430\u0443\u0434\u0438\u0442\u0430 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:<\/p>\n<pre><code class=\"typescript\">async run(): Promise&lt;FinalAuditReport&gt; {  \/\/ 1. \u041e\u0442\u0431\u0438\u0440\u0430\u0435\u043c \u0444\u0430\u0439\u043b\u044b (\u0438\u0441\u043a\u043b\u044e\u0447\u0430\u044f \u0441\u043b\u0443\u0436\u0435\u0431\u043d\u044b\u0435 \u043f\u0430\u043f\u043a\u0438)  const files = this.collectFiles();  \/\/ 2. \u0424\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u0431\u0430\u0442\u0447\u0438 \u043f\u043e \u0431\u044e\u0434\u0436\u0435\u0442\u0443 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432  const batches = await this.buildBatches(files);  \/\/ 3. MAP: \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u044b\u0439 \u0430\u043d\u0430\u043b\u0438\u0437 \u0431\u0430\u0442\u0447\u0435\u0439  const mapResults = await this.runMapPhase(batches);  const allSummaries = mapResults.flatMap((b) =&gt; b.files);  \/\/ 4. REDUCE: \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u0441\u0432\u043e\u0434\u043e\u043a  const clusters = await this.runReducePhase(allSummaries);  \/\/ 5. \u0424\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u0441\u0438\u043d\u0442\u0435\u0437: \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u044b\u0435 \u0438\u043d\u0441\u0430\u0439\u0442\u044b \u0438 \u043f\u043b\u0430\u043d \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439  const { globalInsights, actionPlan } =    await this.runFinalSynthesis(clusters, ...);  return { clusters, globalInsights, actionPlan, ... };}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:87px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0413\u043b\u0430\u0432\u043d\u043e\u0435 \u0442\u0443\u0442 \u0432\u043e\u0442 \u0447\u0442\u043e: Map \u043d\u0435\u00a0\u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0442\u0435\u043a\u0441\u0442, \u043e\u043d \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443. \u041a\u0430\u0436\u0434\u0430\u044f \u0437\u0430\u043c\u0435\u0442\u043a\u0430 \u0443\u0436\u0438\u043c\u0430\u0435\u0442\u0441\u044f \u0434\u043e\u00a0\u043a\u043e\u043c\u043f\u0430\u043a\u0442\u043d\u043e\u0439 \u0441\u0432\u043e\u0434\u043a\u0438: \u0433\u043b\u0430\u0432\u043d\u0430\u044f \u043c\u044b\u0441\u043b\u044c, \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u0442\u0435\u0437\u0438\u0441\u044b, \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438, \u043e\u0446\u0435\u043d\u043a\u0430 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0430, \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u0435 \u0442\u0435\u0433\u0438. \u042d\u0442\u043e \u043d\u0430\u00a0\u043f\u043e\u0440\u044f\u0434\u043e\u043a \u0434\u0435\u0448\u0435\u0432\u043b\u0435, \u0447\u0435\u043c \u0442\u0430\u0449\u0438\u0442\u044c \u043f\u043e\u043b\u043d\u044b\u0439 \u0442\u0435\u043a\u0441\u0442 \u0432\u00a0\u0444\u0430\u0437\u0443 Reduce, \u0438 \u0438\u043c\u0435\u043d\u043d\u043e \u044d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 Reduce \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u0432\u0441\u0451 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0446\u0435\u043b\u0438\u043a\u043e\u043c.<\/p>\n<figure class=\"full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/245\/e87\/7f8\/245e877f8187060095b6df952aabfd3f.png\" alt=\"\u041a\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u044d\u0442\u043e \u0432 Obsidian\" title=\"\u041a\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u044d\u0442\u043e \u0432 Obsidian\" width=\"1920\" height=\"1080\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/245\/e87\/7f8\/245e877f8187060095b6df952aabfd3f.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/245\/e87\/7f8\/245e877f8187060095b6df952aabfd3f.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041a\u0430\u043a\u00a0\u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u044d\u0442\u043e \u0432\u00a0Obsidian<\/figcaption><\/div>\n<\/figure>\n<h4>\u0411\u0430\u0442\u0447\u0438\u043d\u0433 \u043f\u043e\u00a0\u0431\u044e\u0434\u0436\u0435\u0442\u0443, \u0430\u00a0\u043d\u0435\u00a0\u043f\u043e\u00a0\u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0443<\/h4>\n<p>\u041d\u0430\u0438\u0432\u043d\u044b\u0439 \u0431\u0430\u0442\u0447\u0438\u043d\u0433 \u00ab\u043f\u043e N \u0437\u0430\u043c\u0435\u0442\u043e\u043a\u00bb \u043b\u043e\u043c\u0430\u0435\u0442\u0441\u044f \u043d\u0430\u00a0\u0440\u0430\u0437\u043d\u043e\u0440\u043e\u0434\u043d\u043e\u043c \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0435: \u0434\u0435\u0441\u044f\u0442\u044c \u043e\u0434\u043d\u043e\u0441\u0442\u0440\u043e\u0447\u043d\u0438\u043a\u043e\u0432 \u0438 \u0434\u0435\u0441\u044f\u0442\u044c \u043b\u043e\u043d\u0433\u0440\u0438\u0434\u043e\u0432 \u044d\u0442\u043e \u0440\u0430\u0437\u043d\u0430\u044f \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043d\u0430\u00a0\u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0431\u0430\u0442\u0447\u0438 \u043d\u0430\u0431\u0438\u0440\u0430\u044e\u0442\u0441\u044f \u0436\u0430\u0434\u043d\u043e, \u043f\u043e\u00a0\u0431\u044e\u0434\u0436\u0435\u0442\u0443 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432:<\/p>\n<pre><code class=\"typescript\">private async buildBatches(files: TFile[]) {  const batches = [];  let currentBatch: TFile[] = [];  let currentPayload = \"\";  const flush = () =&gt; {    if (currentBatch.length === 0) return;    batches.push({ payload: currentPayload, files: currentBatch });    currentBatch = [];    currentPayload = \"\";  };  for (const file of files) {    \/\/ \u0415\u0441\u043b\u0438 \u0435\u0441\u0442\u044c \u0438\u043d\u0434\u0435\u043a\u0441 \u0438 \u0444\u0430\u0439\u043b \u043d\u0435 \u043c\u0435\u043d\u044f\u043b\u0441\u044f, \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u0430\u0435\u043c (\u0441\u043c. \u043d\u0438\u0436\u0435)    if (this.index &amp;&amp; !this.index.isStale(file)) continue;    const content = await this.app.vault.cachedRead(file);    const entry = this.formatForBatch(file, content);    if (currentPayload.length + entry.length &gt; this.config.batchCharBudget) {      flush();    }    currentBatch.push(file);    currentPayload += entry;  }  flush();  return batches;}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c\u00a0\u0436\u0435 \u0437\u0430\u0448\u0438\u0442\u0430 \u043f\u0435\u0440\u0432\u0430\u044f \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044f \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u0438: <code>this.app.vault.cachedRead<\/code> \u0432\u043c\u0435\u0441\u0442\u043e <code>read<\/code> (\u043e\u0442\u0434\u0430\u0451\u0442 \u0437\u0430\u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e, \u043d\u0435\u00a0\u043b\u0435\u0437\u0435\u0442 \u043d\u0430\u00a0\u0434\u0438\u0441\u043a\u00a0\u043b\u0438\u0448\u043d\u0438\u0439 \u0440\u0430\u0437) \u0438 \u043f\u0440\u043e\u043f\u0443\u0441\u043a \u043d\u0435\u0438\u0437\u043c\u0435\u043d\u0451\u043d\u043d\u044b\u0445 \u0444\u0430\u0439\u043b\u043e\u0432 \u0447\u0435\u0440\u0435\u0437 \u0438\u043d\u0434\u0435\u043a\u0441.<\/p>\n<h4>\u041f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0441\u00a0\u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435\u043c: \u0441\u0435\u043c\u0430\u0444\u043e\u0440 \u043d\u0430\u00a0\u0432\u043e\u0440\u043a\u0435\u0440\u0430\u0445<\/h4>\n<p>Map\u2011\u0444\u0430\u0437\u0430 \u044d\u0442\u043e \u0434\u0435\u0441\u044f\u0442\u043a\u0438 \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043a\u00a0API. \u0413\u043d\u0430\u0442\u044c \u0438\u0445 \u0432\u0441\u0435 \u0440\u0430\u0437\u043e\u043c \u043d\u0435\u043b\u044c\u0437\u044f, \u0443\u043f\u0440\u0451\u0448\u044c\u0441\u044f \u0432\u00a0rate limit \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u0430. \u0413\u043d\u0430\u0442\u044c \u043f\u043e\u00a0\u043e\u0434\u043d\u043e\u043c\u0443 \u043c\u0435\u0434\u043b\u0435\u043d\u043d\u043e. \u041d\u0443\u0436\u0435\u043d \u043f\u0443\u043b \u0432\u043e\u0440\u043a\u0435\u0440\u043e\u0432 \u0441\u00a0\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0439 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c\u044e. \u0420\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043b \u0431\u0435\u0437\u00a0\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a (\u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e\u00a0\u0438\u0445 \u043d\u0435\u00a0\u0437\u043d\u0430\u044e) ), \u0447\u0435\u0440\u0435\u0437 \u043e\u0431\u0449\u0443\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c:<\/p>\n<pre><code class=\"typescript\">private async runMapPhase(batches) {  const results = new Array(batches.length);  const queue = [...batches];  let completed = 0;  const worker = async () =&gt; {    while (queue.length &gt; 0) {      if (this.signal.aborted) return;      const batch = queue.shift();      if (!batch) return;      try {        \/\/ withRetry: \u044d\u043a\u0441\u043f\u043e\u043d\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 backoff \u043d\u0430 \u0441\u0435\u0442\u0435\u0432\u044b\u0445 \u0441\u0431\u043e\u044f\u0445        results[batch.index] = await withRetry(          () =&gt; this.analyzeBatch(batch),          this.config.maxRetries,          this.signal,        );      } catch (err) {        \/\/ \u041e\u0434\u0438\u043d \u0443\u043f\u0430\u0432\u0448\u0438\u0439 \u0431\u0430\u0442\u0447 \u043d\u0435 \u0434\u043e\u043b\u0436\u0435\u043d \u0440\u043e\u043d\u044f\u0442\u044c \u0432\u0435\u0441\u044c \u0430\u0443\u0434\u0438\u0442        results[batch.index] = { files: [], error: String(err) };      }      completed++;      this.report(\"mapping\", completed, batches.length);      if (this.config.delayBetweenBatchesMs &gt; 0) {        await new Promise((r) =&gt;          window.setTimeout(r, this.config.delayBetweenBatchesMs),        );      }    }  };  const concurrency = Math.min(this.config.maxConcurrent, batches.length);  const workers = Array.from({ length: concurrency }, () =&gt; worker());  await Promise.all(workers);  return results.filter((r) =&gt; !!r);}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u0443\u0442 \u0435\u0441\u0442\u044c \u0442\u0440\u0438 \u0440\u0435\u0448\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u044f \u0441\u0447\u0438\u0442\u0430\u044e \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0438\u0430\u043b\u044c\u043d\u044b\u043c\u0438.<\/p>\n<p>\u0418\u0437\u043e\u043b\u044f\u0446\u0438\u044f \u0441\u0431\u043e\u0435\u0432: \u0443\u043f\u0430\u0432\u0448\u0438\u0439 \u0431\u0430\u0442\u0447 \u043f\u0438\u0448\u0435\u0442 <code>{ files: [], error }<\/code>, \u0430\u00a0\u043d\u0435\u00a0\u0432\u044b\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0435\u0442 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043d\u0430\u0432\u0435\u0440\u0445. \u0410\u0443\u0434\u0438\u0442 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430 \u043d\u0430 2000\u00a0\u0437\u0430\u043c\u0435\u0442\u043e\u043a \u043d\u0435\u00a0\u0434\u043e\u043b\u0436\u0435\u043d \u0443\u043c\u0438\u0440\u0430\u0442\u044c \u0438\u0437\u2011\u0437\u0430 \u043e\u0434\u043d\u043e\u0433\u043e \u0442\u0430\u0439\u043c\u0430\u0443\u0442\u0430 \u043d\u0430 47-\u043c \u0431\u0430\u0442\u0447\u0435.<\/p>\n<p>\u041a\u043e\u043e\u043f\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u0430\u044f \u043e\u0442\u043c\u0435\u043d\u0430: <code>this.signal<\/code> (<code>AbortSignal<\/code>) \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0441\u044f \u0432\u00a0\u043d\u0430\u0447\u0430\u043b\u0435 \u043a\u0430\u0436\u0434\u043e\u0439 \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0438. \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043d\u0430\u0436\u0430\u043b \u00ab\u041e\u0442\u043c\u0435\u043d\u0430\u00bb, \u0432\u043e\u0440\u043a\u0435\u0440\u044b \u0434\u043e\u0435\u0434\u0430\u044e\u0442 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u0431\u0430\u0442\u0447 \u0438 \u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u044e\u0442\u0441\u044f.<\/p>\n<p>Rate limiting \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u043c\u043e\u0439 \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u043e\u0439 \u043c\u0435\u0436\u0434\u0443 \u0431\u0430\u0442\u0447\u0430\u043c\u0438, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e\u00a0\u0443\u00a0\u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u0445 \u0442\u0430\u0440\u0438\u0444\u043e\u0432\u00a0\u043b\u0438\u043c\u0438\u0442\u044b \u0436\u0451\u0441\u0442\u043a\u0438\u0435.<\/p>\n<h4>LLM \u0432\u0440\u0451\u0442 \u043f\u0440\u043e\u00a0JSON, \u0438 \u044d\u0442\u043e \u043d\u0430\u0434\u043e \u043f\u0435\u0440\u0435\u0436\u0438\u0432\u0430\u0442\u044c<\/h4>\n<p>\u041f\u0440\u043e\u0441\u0438\u0448\u044c \u043c\u043e\u0434\u0435\u043b\u044c \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0447\u0438\u0441\u0442\u044b\u0439 JSON, \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0448\u044c JSON, \u043e\u0431\u0451\u0440\u043d\u0443\u0442\u044b\u0439 \u0432 <code>```json<\/code>, \u0441\u00a0\u043f\u0440\u0435\u0430\u043c\u0431\u0443\u043b\u043e\u0439 \u00ab\u041a\u043e\u043d\u0435\u0447\u043d\u043e! \u0412\u043e\u0442 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442:\u00bb. \u041f\u0430\u0440\u0441\u0438\u0442\u044c \u044d\u0442\u043e \u043d\u0430\u0438\u0432\u043d\u044b\u043c <code>JSON.parse<\/code> \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442 \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043a\u0440\u0430\u0448\u0438 \u0432\u00a0\u043f\u0440\u043e\u0434\u0435. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432\u0435\u0441\u044c \u043f\u0430\u0440\u0441\u0438\u043d\u0433 \u0438\u0434\u0451\u0442 \u0447\u0435\u0440\u0435\u0437 \u0437\u0430\u0449\u0438\u0449\u0451\u043d\u043d\u044b\u0439 \u044d\u043a\u0441\u0442\u0440\u0430\u043a\u0442\u043e\u0440:<\/p>\n<pre><code class=\"typescript\">function extractJSON&lt;T&gt;(raw: string): T {  \/\/ \u0421\u0440\u0435\u0437\u0430\u0435\u043c markdown-\u043e\u0431\u0451\u0440\u0442\u043a\u0443  const cleaned = raw.replace(\/```json\\n?\/gi, \"\").replace(\/```\\n?\/g, \"\").trim();  \/\/ \u0418\u0449\u0435\u043c \u043f\u0435\u0440\u0432\u044b\u0439 { \u0438\u043b\u0438 [, \u043e\u0442\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0435\u043c \u0431\u043e\u043b\u0442\u043e\u0432\u043d\u044e \u043c\u043e\u0434\u0435\u043b\u0438 \u0434\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b  const jsonStart = Math.min(    ...[cleaned.indexOf(\"{\"), cleaned.indexOf(\"[\")].filter((i) =&gt; i &gt;= 0),  );  if (!Number.isFinite(jsonStart)) {    throw new Error(\"JSON \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d \u0432 \u043e\u0442\u0432\u0435\u0442\u0435 \u043c\u043e\u0434\u0435\u043b\u0438\");  }  return JSON.parse(cleaned.slice(jsonStart)) as T;}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u042d\u0442\u043e \u043d\u0435\u00a0\u043a\u0440\u0430\u0441\u0438\u0432\u043e, \u043d\u043e\u00a0\u044d\u0442\u043e \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u00a0LLM: \u0442\u0432\u043e\u0439 \u043f\u0430\u0440\u0441\u0435\u0440 \u043e\u0431\u044f\u0437\u0430\u043d\u00a0\u0431\u044b\u0442\u044c \u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u0435\u0435, \u0447\u0435\u043c \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0434\u0435\u043b\u044c \u00ab\u043e\u0431\u0435\u0449\u0430\u0435\u0442\u00bb \u0441\u043e\u0431\u043b\u044e\u0434\u0430\u0442\u044c.<\/p>\n<h4>Reduce: \u043a\u043e\u043c\u043f\u0430\u043a\u0442\u043d\u043e\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0440\u0435\u0448\u0430\u0435\u0442<\/h4>\n<p>\u0412\u00a0\u0444\u0430\u0437\u0435 Reduce \u0432\u0441\u0435 \u0441\u0432\u043e\u0434\u043a\u0438 \u0441\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0432\u00a0\u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0439 JSON (\u043a\u043e\u0440\u043e\u0442\u043a\u0438\u0435 \u043a\u043b\u044e\u0447\u0438 \u044d\u043a\u043e\u043d\u043e\u043c\u044f\u0442 \u0442\u043e\u043a\u0435\u043d\u044b \u043d\u0430\u00a0\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435) \u0438 \u0443\u0445\u043e\u0434\u044f\u0442 \u043e\u0434\u043d\u0438\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u043c \u043d\u0430\u00a0\u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0438\u0437\u0430\u0446\u0438\u044e. \u0415\u0441\u043b\u0438 \u0441\u0432\u043e\u0434\u043e\u043a \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043c\u043d\u043e\u0433\u043e, Reduce \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0438\u0435\u0440\u0430\u0440\u0445\u0438\u0447\u0435\u0441\u043a\u0438\u043c (\u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0438\u0437\u0443\u0435\u043c \u0433\u0440\u0443\u043f\u043f\u044b, \u043f\u043e\u0442\u043e\u043c \u0441\u043b\u0438\u0432\u0430\u0435\u043c \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u044b), \u043d\u043e\u00a0\u0432\u00a0\u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449 \u0445\u0432\u0430\u0442\u0430\u0435\u0442 \u043e\u0434\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0445\u043e\u0434\u0430:<\/p>\n<pre><code class=\"typescript\">private async runReducePhase(summaries) {  const compact = summaries.map((s) =&gt; ({    p: s.path, t: s.topics, k: s.keyIdeas, tags: s.suggestedTags,  }));  if (JSON.stringify(compact).length &lt; 40000) {    return await this.clusterize(compact); \/\/ \u043e\u0434\u0438\u043d \u043f\u0440\u043e\u0445\u043e\u0434  }  \/\/ \u0438\u043d\u0430\u0447\u0435 \u0438\u0435\u0440\u0430\u0440\u0445\u0438\u0447\u0435\u0441\u043a\u0438\u0439 reduce \u043f\u043e \u0433\u0440\u0443\u043f\u043f\u0430\u043c  ...}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h3>\u0418\u043d\u043a\u0440\u0435\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d\u0430\u044f \u0438\u043d\u0434\u0435\u043a\u0441\u0430\u0446\u0438\u044f: \u043d\u0435\u00a0\u043f\u043b\u0430\u0442\u0438\u0442\u044c \u0434\u0432\u0430\u0436\u0434\u044b<\/h3>\n<p>\u0410\u0443\u0434\u0438\u0442 \u0434\u043e\u0440\u043e\u0433\u0430\u044f \u043f\u043e\u00a0\u0442\u043e\u043a\u0435\u043d\u0430\u043c \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044f. \u041f\u0440\u043e\u0433\u043e\u043d\u044f\u0442\u044c \u0432\u0441\u0451 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0437\u0430\u043d\u043e\u0432\u043e \u043f\u0440\u0438\u00a0\u043a\u0430\u0436\u0434\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u0440\u0430\u0441\u0442\u043e\u0447\u0438\u0442\u0435\u043b\u044c\u0441\u0442\u0432\u043e, \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u043a\u043e\u0433\u0434\u0430 \u043c\u0435\u0436\u0434\u0443 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u043c\u0438 \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u043e\u0441\u044c \u0442\u0440\u0438 \u0437\u0430\u043c\u0435\u0442\u043a\u0438 \u0438\u0437\u00a0\u0434\u0432\u0443\u0445 \u0442\u044b\u0441\u044f\u0447. \u0420\u0435\u0448\u0435\u043d\u0438\u0435 \u044d\u0442\u043e \u043f\u0435\u0440\u0441\u0438\u0441\u0442\u0435\u043d\u0442\u043d\u044b\u0439 \u0438\u043d\u0434\u0435\u043a\u0441 \u0441\u00a0\u043f\u0440\u043e\u0432\u0435\u0440\u043a\u043e\u0439 \u043f\u043e <code>mtime<\/code>.<\/p>\n<p>\u0421\u0445\u0435\u043c\u0430 \u0437\u0430\u043f\u0438\u0441\u0438 \u043d\u0430\u00a0\u043e\u0434\u043d\u0443 \u0437\u0430\u043c\u0435\u0442\u043a\u0443:<\/p>\n<pre><code class=\"typescript\">export interface NoteRecord {  mtime: number;        \/\/ mtime \u0444\u0430\u0439\u043b\u0430 \u043d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u0430\u043d\u0430\u043b\u0438\u0437\u0430, \u043a\u043b\u044e\u0447 \u0438\u043d\u043a\u0440\u0435\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438  analyzedAt: number;  mainIdea: string;  keyPoints: string[];  entities: string[];  quality: \"draft\" | \"developed\" | \"polished\";  suggestedTags: string[];  \/\/ ...}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0412\u0441\u044f \u0438\u043d\u043a\u0440\u0435\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0434\u0435\u0440\u0436\u0438\u0442\u0441\u044f \u043d\u0430\u00a0\u043e\u0434\u043d\u043e\u0439 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0435:<\/p>\n<pre><code class=\"typescript\">isStale(file: TFile): boolean {  const rec = this.data.notes[file.path];  return !rec || rec.mtime !== file.stat.mtime;}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0415\u0441\u043b\u0438 \u0444\u0430\u0439\u043b \u043d\u0435\u00a0\u0432\u00a0\u0438\u043d\u0434\u0435\u043a\u0441\u0435 \u0438\u043b\u0438\u00a0\u0435\u0433\u043e <code>mtime<\/code> \u043d\u0435\u00a0\u0441\u043e\u0432\u043f\u0430\u0434\u0430\u0435\u0442 \u0441\u00a0\u0437\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u043c, \u0437\u043d\u0430\u0447\u0438\u0442, \u0435\u0433\u043e \u043d\u0430\u0434\u043e \u043f\u0435\u0440\u0435\u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c. \u0418\u043d\u0430\u0447\u0435 \u0431\u0435\u0440\u0451\u043c \u0433\u043e\u0442\u043e\u0432\u0443\u044e \u0441\u0432\u043e\u0434\u043a\u0443. \u041d\u0430\u00a0\u0432\u0442\u043e\u0440\u043e\u043c \u043f\u0440\u043e\u0433\u043e\u043d\u0435 \u043f\u043e\u00a0\u043d\u0435\u0438\u0437\u043c\u0435\u043d\u043d\u043e\u043c\u0443 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0443 \u0430\u0443\u0434\u0438\u0442 \u0441\u0442\u043e\u0438\u0442 \u043f\u043e\u0447\u0442\u0438 \u043d\u043e\u043b\u044c \u0442\u043e\u043a\u0435\u043d\u043e\u0432.<\/p>\n<p>\u0414\u0432\u0430 \u043c\u043e\u043c\u0435\u043d\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u044f \u0437\u0430\u043b\u043e\u0436\u0438\u043b \u0441\u00a0\u043f\u0440\u0438\u0446\u0435\u043b\u043e\u043c \u043d\u0430\u00a0\u0431\u0443\u0434\u0443\u0449\u0435\u0435.<\/p>\n<p>\u0412\u0435\u0440\u0441\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u0445\u0435\u043c\u044b. \u0423\u00a0\u0438\u043d\u0434\u0435\u043a\u0441\u0430 \u0435\u0441\u0442\u044c <code>SCHEMA_VERSION<\/code>. \u041a\u043e\u0433\u0434\u0430 \u044f \u043c\u0435\u043d\u044f\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 <code>NoteRecord<\/code>, \u0441\u0442\u0430\u0440\u044b\u0439 \u0438\u043d\u0434\u0435\u043a\u0441 \u043f\u0440\u043e\u0441\u0442\u043e \u0438\u0433\u043d\u043e\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f (\u0447\u0438\u0441\u0442\u044b\u0439 \u0441\u0442\u0430\u0440\u0442), \u0430\u00a0\u043d\u0435\u00a0\u0440\u043e\u043d\u044f\u0435\u0442 \u043f\u043b\u0430\u0433\u0438\u043d \u043d\u0430\u00a0\u043d\u0435\u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445:<\/p>\n<pre><code class=\"typescript\">async load(): Promise&lt;void&gt; {  try {    const parsed = JSON.parse(await this.app.vault.adapter.read(INDEX_PATH));    if (parsed.version === SCHEMA_VERSION &amp;&amp; parsed.notes) {      this.data = parsed;    }    \/\/ \u0434\u0440\u0443\u0433\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f, \u043c\u043e\u043b\u0447\u0430 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u043c \u0437\u0430\u043d\u043e\u0432\u043e  } catch {    \/\/ \u0444\u0430\u0439\u043b\u0430 \u043d\u0435\u0442 \u0438\u043b\u0438 \u0431\u0438\u0442\u044b\u0439 JSON, \u0447\u0438\u0441\u0442\u044b\u0439 \u0441\u0442\u0430\u0440\u0442 \u0431\u0435\u0437 \u043a\u0440\u0430\u0448\u0430  }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0424\u043b\u0430\u0433 <code>dirty<\/code> \u0438 <code>prune<\/code>. \u0418\u043d\u0434\u0435\u043a\u0441 \u043f\u0438\u0448\u0435\u0442\u0441\u044f \u043d\u0430\u00a0\u0434\u0438\u0441\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u0435\u0441\u043b\u0438 \u0440\u0435\u0430\u043b\u044c\u043d\u043e \u043c\u0435\u043d\u044f\u043b\u0441\u044f (<code>dirty<\/code>), \u0430 <code>prune<\/code> \u0447\u0438\u0441\u0442\u0438\u0442 \u0437\u0430\u043f\u0438\u0441\u0438 \u0434\u043b\u044f\u00a0\u0444\u0430\u0439\u043b\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435\u0442. \u041c\u0435\u043b\u043e\u0447\u0438, \u043d\u043e\u00a0\u0438\u043c\u0435\u043d\u043d\u043e \u043e\u043d\u0438 \u043e\u0442\u043b\u0438\u0447\u0430\u044e\u0442 \u00ab\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0443\u00a0\u043c\u0435\u043d\u044f\u00bb \u043e\u0442 \u00ab\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0443\u00a0\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0441\u00a0\u0436\u0438\u0432\u044b\u043c, \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e \u043c\u0435\u043d\u044f\u044e\u0449\u0438\u043c\u0441\u044f \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435\u043c\u00bb.<\/p>\n<h3>\u041e\u0434\u0438\u043d \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043d\u0430\u00a0\u0447\u0435\u0442\u044b\u0440\u0451\u0445 \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u043e\u0432<\/h3>\n<p>\u042f \u0445\u043e\u0442\u0435\u043b, \u0447\u0442\u043e\u0431\u044b \u043f\u043b\u0430\u0433\u0438\u043d \u0440\u0430\u0431\u043e\u0442\u0430\u043b \u0441\u00a0OpenRouter, OpenAI, Groq \u0438 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0439 Ollama(\u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u0432\u0430\u0436\u043d\u043e \u0432\u043e\u043f\u0440\u043e\u0441 \u0434\u043b\u044f\u00a0\u043c\u0435\u043d\u044f \u0441\u0442\u043e\u044f\u043b \u0441\u00a0\u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u043c,\u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e\u00a0\u043c\u043d\u043e\u0433\u0438\u043c \u0432\u0430\u0436\u043d\u0430 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u044b \u043d\u0430\u00a0\u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u043c LLM), \u0438 \u0447\u0442\u043e\u0431\u044b \u0435\u0441\u043b\u0438 \u0447\u0442\u043e\u00a0\u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u044f\u0442\u043e\u0433\u043e \u043c\u043e\u0436\u043d\u043e\u00a0\u0431\u044b\u043b\u043e, \u043d\u0435\u00a0\u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u044f \u044f\u0434\u0440\u043e. \u0421\u043f\u0430\u0441\u0430\u0435\u0442 \u0442\u043e, \u0447\u0442\u043e\u00a0\u043f\u043e\u0447\u0442\u0438 \u0432\u0441\u0435 \u043e\u043d\u0438 \u0433\u043e\u0432\u043e\u0440\u044f\u0442 \u043d\u0430\u00a0\u0434\u0438\u0430\u043b\u0435\u043a\u0442\u0435 OpenAI\u2011\u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u043e\u0433\u043e API. \u0420\u0430\u0437\u043b\u0438\u0447\u0438\u044f \u0432\u00a0\u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430\u0445 \u0438 \u043c\u0435\u043b\u043e\u0447\u0430\u0445 \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u0430 \u0438\u0437\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u0432\u00a0\u043e\u0434\u043d\u043e\u043c \u043c\u0435\u0441\u0442\u0435:<\/p>\n<pre><code class=\"typescript\">function buildHeaders(settings: AIHubSettings): Record&lt;string, string&gt; {  const provider = settings.provider ?? \"openrouter\";  const headers: Record&lt;string, string&gt; = { \"Content-Type\": \"application\/json\" };  if (provider === \"ollama\" &amp;&amp; !settings.apiKey.trim()) {    headers[\"Authorization\"] = \"Bearer ollama\"; \/\/ \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e \u043a\u043b\u044e\u0447 \u043d\u0435 \u043d\u0443\u0436\u0435\u043d  } else {    headers[\"Authorization\"] = `Bearer ${settings.apiKey}`;  }  if (provider === \"openrouter\") {    headers[\"HTTP-Referer\"] = \"https:\/\/obsidian.md\";    headers[\"X-Title\"] = \"Obsidian AI Hub\";  }  return headers;}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0412\u0441\u0451 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0435 \u044f\u0434\u0440\u043e \u043d\u0435\u00a0\u0437\u043d\u0430\u0435\u0442, \u0441\u00a0\u043a\u0435\u043c \u0440\u0430\u0437\u0433\u043e\u0432\u0430\u0440\u0438\u0432\u0430\u0435\u0442, \u043e\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u0448\u043b\u0451\u0442 <code>POST<\/code> \u043d\u0430 <code>${baseUrl}\/chat\/completions<\/code>. \u041d\u043e\u0432\u044b\u0439 \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440 \u044d\u0442\u043e \u043d\u043e\u0432\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c \u0432\u00a0\u043f\u0440\u043e\u0444\u0438\u043b\u044f\u0445 \u0441\u00a0\u0435\u0433\u043e <code>baseUrl<\/code> \u0438 \u0434\u0435\u0444\u043e\u043b\u0442\u043d\u043e\u0439 \u043c\u043e\u0434\u0435\u043b\u044c\u044e.<\/p>\n<figure class=\"full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/89d\/3aa\/8db\/89d3aa8db0b997913fe87db2b8c7f5f6.png\" alt=\"\u041a\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0432\u044b\u0431\u043e\u0440 \u043c\u043e\u0434\u0435\u043b\u0438 \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u0445\" title=\"\u041a\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0432\u044b\u0431\u043e\u0440 \u043c\u043e\u0434\u0435\u043b\u0438 \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u0445\" width=\"1920\" height=\"1080\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/89d\/3aa\/8db\/89d3aa8db0b997913fe87db2b8c7f5f6.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/89d\/3aa\/8db\/89d3aa8db0b997913fe87db2b8c7f5f6.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041a\u0430\u043a\u00a0\u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0432\u044b\u0431\u043e\u0440 \u043c\u043e\u0434\u0435\u043b\u0438 \u0432\u00a0\u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u0445<\/figcaption><\/div>\n<\/figure>\n<h4>\u0421\u0442\u0440\u0438\u043c\u0438\u043d\u0433 \u0441\u00a0\u0434\u0435\u0442\u0435\u043a\u0442\u043e\u0440\u043e\u043c \u043f\u0435\u0442\u0435\u043b\u044c<\/h4>\n<p>\u0422\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 (\u043f\u0435\u0440\u0435\u043f\u0438\u0441\u0430\u0442\u044c, \u0440\u0430\u0441\u0448\u0438\u0440\u0438\u0442\u044c, \u0441\u0443\u043c\u043c\u0430\u0440\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c),\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0442\u0430\u043a\u0436\u0435 \u0435\u0441\u0442\u044c \u0432\u00a0\u043c\u043e\u0435\u043c \u043f\u043b\u0430\u0433\u0438\u043d\u0435, \u0441\u0442\u0440\u0438\u043c\u044f\u0442\u0441\u044f \u0432\u00a0\u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440 \u043f\u043e\u00a0\u0442\u043e\u043a\u0435\u043d\u0443 \u0447\u0435\u0440\u0435\u0437 SSE. \u0417\u0434\u0435\u0441\u044c \u0434\u0432\u0435 \u043d\u0435\u043e\u0447\u0435\u0432\u0438\u0434\u043d\u044b\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b,\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u0440\u0442\u044f\u0442 \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0438\u043b\u0438\u00a0\u0432\u043e\u043e\u0431\u0449\u0435 \u0432\u0441\u0435 \u043b\u043e\u043c\u0430\u044e\u0442.<\/p>\n<p>\u041f\u0435\u0440\u0432\u0430\u044f, \u043f\u0430\u0440\u0441\u0438\u043d\u0433 SSE: \u0447\u0430\u043d\u043a\u0438 \u043f\u0440\u0438\u0445\u043e\u0434\u044f\u0442 \u043d\u0435\u00a0\u043f\u043e\u00a0\u0441\u0442\u0440\u043e\u043a\u0430\u043c, \u0441\u0442\u0440\u043e\u043a\u0430 \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u0439\u0442\u0438 \u0440\u0430\u0437\u0440\u0435\u0437\u0430\u043d\u043d\u043e\u0439 \u043c\u0435\u0436\u0434\u0443 \u0434\u0432\u0443\u043c\u044f <code>read()<\/code>. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0434\u0435\u0440\u0436\u0438\u043c \u0431\u0443\u0444\u0435\u0440 \u0438 \u0434\u043e\u0441\u0442\u0430\u0451\u043c \u0438\u0437\u00a0\u043d\u0435\u0433\u043e \u043f\u043e\u043b\u043d\u044b\u0435 \u0441\u0442\u0440\u043e\u043a\u0438, \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044f \u0445\u0432\u043e\u0441\u0442:<\/p>\n<pre><code class=\"typescript\">const reader = res.body.getReader();const decoder = new TextDecoder();let buffer = \"\";let generated = \"\";while (true) {  const { done, value } = await reader.read();  if (done) break;  buffer += decoder.decode(value, { stream: true });  const lines = buffer.split(\"\\n\");  buffer = lines.pop() ?? \"\"; \/\/ \u043d\u0435\u043f\u043e\u043b\u043d\u044b\u0439 \u0445\u0432\u043e\u0441\u0442 \u043e\u0431\u0440\u0430\u0442\u043d\u043e \u0432 \u0431\u0443\u0444\u0435\u0440  for (const line of lines) {    if (!line.startsWith(\"data: \")) continue;    const jsonStr = line.slice(6);    if (jsonStr === \"[DONE]\") return;    const content = JSON.parse(jsonStr).choices?.[0]?.delta?.content;    if (!content) continue;    generated += content;    if (detectRepetitionLoop(generated)) {      console.warn(\"\u041e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u0430 \u043f\u0435\u0442\u043b\u044f \u043f\u043e\u0432\u0442\u043e\u0440\u0435\u043d\u0438\u0439, \u0441\u0442\u0440\u0438\u043c \u043f\u0440\u0435\u0440\u0432\u0430\u043d\");      return; \/\/ \u0432\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430    }    onToken(content);  }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0412\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u044d\u0442\u043e \u0437\u0430\u043b\u0438\u043f\u0430\u043d\u0438\u0435 \u043c\u043e\u0434\u0435\u043b\u0438. \u0414\u0435\u0448\u0451\u0432\u044b\u0435 \u0438 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0435 \u043c\u043e\u0434\u0435\u043b\u0438 \u0438\u043d\u043e\u0433\u0434\u0430 \u0441\u0440\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0432\u00a0\u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u043e\u0435 \u043f\u043e\u0432\u0442\u043e\u0440\u0435\u043d\u0438\u0435 \u043e\u0434\u043d\u043e\u0433\u043e \u0438 \u0442\u043e\u0433\u043e\u00a0\u0436\u0435 \u0431\u043b\u043e\u043a\u0430(\u0441\u0430\u043c \u0441\u00a0\u044d\u0442\u0438\u043c \u0432\u00a0\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u043b\u0441\u044f \u043d\u0435\u00a0\u0440\u0430\u0437 \u0438 \u043f\u0440\u0438\u0447\u0438\u043d\u0443 \u044d\u0442\u043e\u0433\u043e \u044f\u0432\u043b\u0435\u043d\u0438\u044f \u0442\u043e\u0447\u043d\u043e \u0442\u0430\u043a \u0438 \u043d\u0435\u00a0\u043f\u043e\u043d\u044f\u043b). \u0412\u00a0\u0441\u0442\u0440\u0438\u043c\u0435 \u044d\u0442\u043e \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043a\u0430\u043a\u00a0\u0437\u0430\u043c\u0435\u0442\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0438\u0448\u0435\u0442 \u0441\u0430\u043c\u0430 \u0441\u0435\u0431\u044f \u0434\u043e\u00a0\u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u043e\u0441\u0442\u0438 (\u0438 \u0436\u0436\u0451\u0442 \u0442\u043e\u043a\u0435\u043d\u044b). \u0414\u0435\u0442\u0435\u043a\u0442\u043e\u0440 \u0438\u0449\u0435\u0442 \u0432\u00a0\u0445\u0432\u043e\u0441\u0442\u0435 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u0442\u0435\u043a\u0441\u0442\u0430 \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u044e\u0449\u0438\u0435\u0441\u044f \u0431\u043b\u043e\u043a\u0438 \u0440\u0430\u0437\u043d\u043e\u0439 \u0434\u043b\u0438\u043d\u044b \u0438 \u043f\u0440\u0435\u0440\u044b\u0432\u0430\u0435\u0442 \u0441\u0442\u0440\u0438\u043c, \u0435\u0441\u043b\u0438 \u0431\u043b\u043e\u043a \u043f\u043e\u0432\u0442\u043e\u0440\u0438\u043b\u0441\u044f N \u0440\u0430\u0437 \u043f\u043e\u0434\u0440\u044f\u0434:<\/p>\n<pre><code class=\"typescript\">export function detectRepetitionLoop(buffer, window, threshold): boolean {  if (buffer.length &lt; window * 2) return false;  const tail = buffer.slice(-window * threshold);  for (let chunkLen = 20; chunkLen &lt;= window \/ 2; chunkLen += 10) {    const probe = tail.slice(-chunkLen);    if (probe.trim().length &lt; 10) continue;    let count = 0, pos = tail.length - chunkLen;    while (pos &gt;= chunkLen) {      if (tail.slice(pos - chunkLen, pos) === probe) {        if (++count &gt;= threshold - 1) return true;        pos -= chunkLen;      } else break;    }  }  return false;}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h3>\u0427\u0442\u043e\u00a0\u0435\u0449\u0451 \u0443\u043c\u0435\u0435\u0442 \u043f\u043b\u0430\u0433\u0438\u043d<\/h3>\n<p>\u0412\u00a0\u0446\u0435\u043b\u043e\u043c,\u0435\u0441\u043b\u0438 \u0447\u0435\u0441\u0442\u043d\u043e \u0433\u043e\u0432\u043e\u0440\u0438\u0442\u044c,\u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u044f \u0445\u043e\u0442\u0435\u043b \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u0435\u043d\u044c\u043a\u0438\u0439 \u043f\u043b\u0430\u0433\u0438\u043d \u0434\u043b\u044f\u00a0\u0431\u0430\u0437\u043e\u0432\u044b\u0445 \u0418\u0418\u2011\u0444\u0443\u043d\u043a\u0446\u0438\u0439(\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0432\u00a0Obsidian \u043a\u0443\u0447\u0430),\u0438\u0434\u0435\u044f \u0441\u00a0\u0410\u0443\u0434\u0438\u0442\u043e\u043c \u043f\u0440\u0438\u0448\u043b\u0430 \u0447\u0443\u0442\u044c \u043f\u043e\u0437\u0436\u0435,\u043d\u043e,\u043f\u043e \u043c\u043e\u0435\u043c\u0443 \u043c\u043d\u0435\u043d\u0438\u044e,\u043e\u043d\u0430 \u0438 \u0441\u0442\u0430\u043b\u0430 \u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u0444\u0438\u0448\u043a\u043e\u0439. \u041f\u043e\u0432\u0435\u0440\u0445 \u0442\u043e\u0439\u00a0\u0436\u0435 \u043c\u0443\u043b\u044c\u0442\u0438\u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u043d\u043e\u0439 \u043e\u0431\u0432\u044f\u0437\u043a\u0438,\u043a\u0440\u043e\u043c\u0435 \u0410\u0443\u0434\u0438\u0442\u0430 \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u043e \u0435\u0449\u0451 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0435\u0449\u0435\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u044f \u0441\u0430\u043c \u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0441\u044c \u043a\u0430\u0436\u0434\u044b\u0439 \u0434\u0435\u043d\u044c.<\/p>\n<p><strong>\u041f\u0430\u043a\u0435\u0442\u043d\u0430\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430.<\/strong> \u0424\u0438\u043b\u044c\u0442\u0440\u0443\u0435\u0448\u044c \u0437\u0430\u043c\u0435\u0442\u043a\u0438 \u043f\u043e\u00a0\u043f\u0430\u043f\u043a\u0435, \u0442\u0435\u0433\u0430\u043c \u0438\u043b\u0438\u00a0\u0434\u0438\u0430\u043f\u0430\u0437\u043e\u043d\u0443 \u0434\u0430\u0442, \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u0448\u044c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 (\u0443\u043b\u0443\u0447\u0448\u0438\u0442\u044c \u0441\u0442\u0438\u043b\u044c, \u0441\u0443\u043c\u043c\u0430\u0440\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u043f\u0440\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0442\u0435\u0433\u0438, \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0433\u0440\u0430\u043c\u043c\u0430\u0442\u0438\u043a\u0443 \u0438\u043b\u0438\u00a0\u0441\u0432\u043e\u0439 \u043f\u0440\u043e\u043c\u043f\u0442) \u0438 \u043f\u0440\u043e\u0433\u043e\u043d\u044f\u0435\u0448\u044c \u0432\u0441\u0451 \u0440\u0430\u0437\u043e\u043c. \u041f\u043e\u0434\u00a0\u043a\u0430\u043f\u043e\u0442\u043e\u043c \u0442\u043e\u0442\u00a0\u0436\u0435 \u043f\u0443\u043b \u0432\u043e\u0440\u043a\u0435\u0440\u043e\u0432, \u0447\u0442\u043e\u00a0\u0438 \u0432\u00a0Map\u2011\u0444\u0430\u0437\u0435 \u0430\u0443\u0434\u0438\u0442\u0430: \u0441\u043e\u0442\u043d\u0438 \u0437\u0430\u043c\u0435\u0442\u043e\u043a \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e \u0441\u00a0\u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435\u043c \u043f\u043e\u00a0\u043a\u043e\u043d\u043a\u0443\u0440\u0435\u043d\u0446\u0438\u0438 \u0438 \u0440\u0435\u0442\u0440\u0430\u044f\u043c\u0438. \u041f\u043e\u00a0\u0441\u0443\u0442\u0438 \u044d\u0442\u043e \u0430\u0443\u0434\u0438\u0442 \u043d\u0430\u043e\u0431\u043e\u0440\u043e\u0442: \u0442\u0430\u043c \u0447\u0438\u0442\u0430\u0435\u043c \u0438 \u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c, \u0442\u0443\u0442 \u0447\u0438\u0442\u0430\u0435\u043c \u0438 \u043c\u043e\u0434\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u0435\u043c.<\/p>\n<p><strong>\u0418\u043d\u043b\u0430\u0439\u043d\u2011\u0440\u0430\u0431\u043e\u0442\u0430 \u0441\u00a0\u0442\u0435\u043a\u0441\u0442\u043e\u043c.<\/strong> \u041f\u0440\u044f\u043c\u043e \u0432\u00a0\u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0435 \u0438\u0437\u00a0\u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0433\u043e \u043c\u0435\u043d\u044e \u0438\u043b\u0438\u00a0\u043f\u043e\u00a0\u0433\u043e\u0440\u044f\u0447\u0435\u0439 \u043a\u043b\u0430\u0432\u0438\u0448\u0435: \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0442\u0435\u043a\u0441\u0442 \u0438 \u0432\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043f\u043e\u0434\u00a0\u043a\u0443\u0440\u0441\u043e\u0440, \u043f\u0440\u043e\u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u0438\u0435, \u0440\u0430\u0441\u0448\u0438\u0440\u0438\u0442\u044c, \u0441\u043e\u043a\u0440\u0430\u0442\u0438\u0442\u044c, \u043f\u0435\u0440\u0435\u0444\u043e\u0440\u043c\u0443\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c. \u0412\u0441\u0451 \u0441\u043e \u0441\u0442\u0440\u0438\u043c\u0438\u043d\u0433\u043e\u043c, \u0442\u0430\u043a \u0447\u0442\u043e\u00a0\u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043f\u0435\u0447\u0430\u0442\u0430\u0435\u0442\u0441\u044f \u043d\u0430\u00a0\u0433\u043b\u0430\u0437\u0430\u0445, \u0438 \u0442\u0435\u043c\u00a0\u0436\u0435 \u0434\u0435\u0442\u0435\u043a\u0442\u043e\u0440\u043e\u043c \u043f\u0435\u0442\u0435\u043b\u044c(\u043f\u0440\u043e \u0447\u0442\u043e\u00a0\u044f \u043f\u0438\u0441\u0430\u043b \u0432\u044b\u0448\u0435).<\/p>\n<figure class=\"full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/2ee\/b10\/32a\/2eeb1032af075e2f0a53ae0ffeddcdb2.png\" width=\"1920\" height=\"1080\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/2ee\/b10\/32a\/2eeb1032af075e2f0a53ae0ffeddcdb2.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/2ee\/b10\/32a\/2eeb1032af075e2f0a53ae0ffeddcdb2.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<p><strong>\u0413\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f Dataview\u2011\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432.<\/strong> \u041e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0448\u044c \u0441\u043b\u043e\u0432\u0430\u043c\u0438, \u0447\u0442\u043e\u00a0\u0445\u043e\u0447\u0435\u0448\u044c \u0432\u044b\u0442\u0430\u0449\u0438\u0442\u044c, \u043c\u043e\u0434\u0435\u043b\u044c \u043e\u0442\u0434\u0430\u0451\u0442 \u0433\u043e\u0442\u043e\u0432\u044b\u0439 Dataview\u2011\u0431\u043b\u043e\u043a. \u0423\u0434\u043e\u0431\u043d\u043e, \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u043c\u043d\u0438\u0448\u044c, \u0447\u0442\u043e\u00a0Dataview \u0443\u043c\u0435\u0435\u0442 \u043d\u0443\u0436\u043d\u043e\u0435, \u043d\u043e\u00a0\u043b\u0435\u043d\u044c \u0432\u0441\u043f\u043e\u043c\u0438\u043d\u0430\u0442\u044c \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441.<\/p>\n<p><strong>\u042d\u043a\u0441\u043f\u043e\u0440\u0442 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u0430\u0443\u0434\u0438\u0442\u0430.<\/strong> \u041a\u043b\u0430\u0441\u0442\u0435\u0440\u044b \u0442\u0435\u043c \u0432\u044b\u0433\u0440\u0443\u0436\u0430\u044e\u0442\u0441\u044f \u0432\u00a0Canvas (\u0432\u0438\u0437\u0443\u0430\u043b\u044c\u043d\u0430\u044f \u043a\u0430\u0440\u0442\u0430 \u0441\u0432\u044f\u0437\u0435\u0439 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430), \u0430\u00a0\u043f\u043e\u043b\u043d\u044b\u0439 \u043e\u0442\u0447\u0451\u0442 \u0432\u00a0\u043e\u0431\u044b\u0447\u043d\u0443\u044e markdown\u2011\u0437\u0430\u043c\u0435\u0442\u043a\u0443 \u0441\u00a0Dataview\u2011\u0432\u0441\u0442\u0430\u0432\u043a\u0430\u043c\u0438 \u0438 \u043f\u0440\u044f\u043c\u044b\u043c\u0438 \u0441\u0441\u044b\u043b\u043a\u0430\u043c\u0438 \u043d\u0430\u00a0\u043a\u0430\u0436\u0434\u044b\u0439 \u0443\u043f\u043e\u043c\u044f\u043d\u0443\u0442\u044b\u0439 \u0444\u0430\u0439\u043b. \u0422\u043e \u0435\u0441\u0442\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0430\u0443\u0434\u0438\u0442\u0430 \u044d\u0442\u043e \u043d\u0435\u00a0\u043c\u043e\u0434\u0430\u043b\u044c\u043d\u043e\u0435 \u043e\u043a\u043d\u043e, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0437\u0430\u043a\u0440\u044b\u043b \u0438 \u0437\u0430\u0431\u044b\u043b, \u0430\u00a0\u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f \u0432\u00a0\u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0438 \u043f\u043e\u00a0\u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c.<\/p>\n<p>\u041b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0440\u0435\u0436\u0438\u043c \u0447\u0435\u0440\u0435\u0437 Ollama \u0441\u0442\u043e\u0438\u0442 \u043f\u043e\u0434\u0447\u0435\u0440\u043a\u043d\u0443\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e: \u043f\u0440\u0438\u00a0\u043d\u0451\u043c \u043d\u0438 \u043e\u0434\u043d\u0430 \u0437\u0430\u043c\u0435\u0442\u043a\u0430 \u043d\u0435\u00a0\u043f\u043e\u043a\u0438\u0434\u0430\u0435\u0442 \u043c\u0430\u0448\u0438\u043d\u0443. \u0414\u043b\u044f\u00a0\u0442\u0435\u0445, \u0443\u00a0\u043a\u043e\u0433\u043e \u0432\u00a0\u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435\u00a0\u043b\u0438\u0447\u043d\u044b\u0435 \u0438\u043b\u0438\u00a0\u0440\u0430\u0431\u043e\u0447\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0435, \u044d\u0442\u043e \u043d\u0435 \u00ab\u043f\u0440\u0438\u044f\u0442\u043d\u044b\u0439 \u0431\u043e\u043d\u0443\u0441\u00bb, \u0430\u00a0\u0443\u0441\u043b\u043e\u0432\u0438\u0435, \u043f\u0440\u0438\u00a0\u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043f\u043b\u0430\u0433\u0438\u043d\u043e\u043c \u0432\u043e\u043e\u0431\u0449\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f.<\/p>\n<h3>\u041f\u0443\u0442\u044c \u0432\u00a0\u043a\u0430\u0442\u0430\u043b\u043e\u0433: 120\u00a0\u043e\u0448\u0438\u0431\u043e\u043a \u0440\u0435\u0432\u044c\u044e \u043a\u00a0\u043d\u0443\u043b\u044e<\/h3>\n<p>\u041e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u0442\u044c \u043f\u043b\u0430\u0433\u0438\u043d \u0432\u00a0\u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u043c \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0435 Obsidian \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442 \u043f\u0440\u043e\u0439\u0442\u0438 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0443\u044e \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443, \u0438 \u043e\u043d\u0430 \u0441\u0442\u0440\u043e\u0433\u0430\u044f,\u0430 \u044d\u0442\u043e\u00a0\u0431\u044b\u043b\u043e \u0434\u043b\u044f\u00a0\u043c\u0435\u043d\u044f \u0432\u0430\u0436\u043d\u044b\u043c \u044d\u0442\u0430\u043f\u043e\u043c,\u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0444\u0438\u043d\u0438\u0448\u043d\u044b\u043c,\u0447\u0442\u043e\u0431\u044b \u043f\u043b\u0430\u0433\u0438\u043d \u043c\u043e\u0433 \u0445\u043e\u0442\u044c \u043a\u0442\u043e\u2011\u0442\u043e \u0437\u0430\u043c\u0435\u0442\u0438\u0442\u044c,\u0430 \u043d\u0435\u00a0\u043b\u0435\u0436\u0430\u043b \u043f\u0440\u043e\u0441\u0442\u043e \u043c\u0435\u0440\u0442\u0432\u044b\u043c \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0435\u043c \u043d\u0430\u00a0\u043c\u043e\u0435\u043c \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u043e\u043c \u0433\u0438\u0442\u0445\u0430\u0431\u0435. \u041f\u0435\u0440\u0432\u044b\u0439 \u043f\u0440\u043e\u0433\u043e\u043d \u0434\u0430\u043b \u043e\u043a\u043e\u043b\u043e 120\u00a0\u0431\u043b\u043e\u043a\u0438\u0440\u0443\u044e\u0449\u0438\u0445 \u043e\u0448\u0438\u0431\u043e\u043a. \u0421\u0430\u043c\u043e\u0435 \u043f\u043e\u0443\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435:<\/p>\n<p>\u0418\u043d\u043b\u0430\u0439\u043d\u2011\u0441\u0442\u0438\u043b\u0438 \u0437\u0430\u043f\u0440\u0435\u0449\u0435\u043d\u044b. \u0414\u0435\u0441\u044f\u0442\u043a\u0438 <code>el.style.color = ...<\/code> \u0438 <code>el.style.cssText = ...<\/code> \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0432\u044b\u043d\u0435\u0441\u0442\u0438 \u0432\u00a0CSS\u2011\u043a\u043b\u0430\u0441\u0441\u044b. \u0414\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f (\u0446\u0432\u0435\u0442 \u0441\u0442\u0430\u0442\u0443\u0441\u0430, \u0448\u0438\u0440\u0438\u043d\u0430 \u043f\u0440\u043e\u0433\u0440\u0435\u0441\u0441\u2011\u0431\u0430\u0440\u0430) \u0447\u0435\u0440\u0435\u0437 CSS\u2011\u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0438 <code>setCssProps<\/code>, \u0441\u0442\u0430\u0442\u0438\u043a\u0443 \u0447\u0435\u0440\u0435\u0437 \u043a\u043b\u0430\u0441\u0441\u044b.\u0418\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u0438 \u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043b\u043e\u0441\u044c \u0432\u0441\u0435 \u0432\u044b\u043d\u0435\u0441\u0442\u0438 \u0441\u0440\u0430\u0437\u0443 \u0432\u00a0\u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0444\u0430\u0439\u043b,\u043d\u043e \u043d\u0430\u00a0\u044d\u0442\u0430\u043f\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043c\u043d\u0435\u00a0\u0431\u044b\u043b\u043e \u0442\u0430\u043a \u043f\u0440\u043e\u0449\u0435,\u043d\u043e \u044d\u0442\u0430 \u043f\u0440\u0438\u0432\u044b\u0447\u043a\u0430 \u043e\u0442\u00a0\u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043b\u0443\u0447\u0448\u0435 \u043e\u0442\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f,\u0438 \u043f\u044b\u0442\u0430\u0442\u044c\u0441\u044f \u0441\u0440\u0430\u0437\u0443 \u0432\u0441\u0435 \u0440\u0430\u0437\u0431\u0438\u0432\u0430\u0442\u044c \u0447\u0435\u0442\u043a\u043e \u043f\u043e\u00a0\u0444\u0430\u0439\u043b\u0430\u043c.<\/p>\n<p><code>innerHTML<\/code> \u0437\u0430\u043f\u0440\u0435\u0449\u0451\u043d (XSS\u2011\u0440\u0438\u0441\u043a). \u0421\u0431\u043e\u0440\u043a\u0443 DOM \u0438\u0437\u00a0\u0441\u0442\u0440\u043e\u043a \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u0430\u043b \u043d\u0430\u00a0\u043e\u0431\u0441\u0438\u0434\u0438\u0430\u043d\u043e\u0432\u0441\u043a\u0438\u0439 API (<code>createEl<\/code>, <code>appendText<\/code>, <code>empty()<\/code>).<\/p>\n<p>\u0421\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u043e\u0442\u0438\u0432 <code>!important<\/code>. \u041a\u043e\u0433\u0434\u0430 \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u0438\u043b \u0441\u0442\u0438\u043b\u0438 \u0432\u00a0\u0444\u0430\u0439\u043b <code>styles.css<\/code>, \u0434\u0435\u0444\u043e\u043b\u0442\u044b Obsidian \u043d\u0430\u0447\u0430\u043b\u0438 \u043f\u0435\u0440\u0435\u0431\u0438\u0432\u0430\u0442\u044c \u043c\u043e\u0438 \u043f\u0440\u0430\u0432\u0438\u043b\u0430, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e\u00a0\u0438\u043d\u043b\u0430\u0439\u043d\u2011\u0441\u0442\u0438\u043b\u0438 \u0440\u0430\u043d\u044c\u0448\u0435 \u0432\u044b\u0438\u0433\u0440\u044b\u0432\u0430\u043b\u0438 \u043f\u043e\u00a0\u043f\u0440\u0438\u043e\u0440\u0438\u0442\u0435\u0442\u0443 \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u043e\u00a0\u0444\u0430\u043a\u0442\u0443 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u00a0\u043e\u043d\u0438 \u0438\u043d\u043b\u0430\u0439\u043d. \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0437\u0430\u043a\u0440\u044b\u043b \u044d\u0442\u043e <code>!important<\/code>, \u043d\u043e\u00a0\u043b\u0438\u043d\u0442\u0435\u0440 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0430 \u0440\u0443\u0433\u0430\u0435\u0442\u0441\u044f \u0438 \u043d\u0430\u00a0\u043d\u0435\u0433\u043e. \u0424\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u044d\u0442\u043e \u043f\u043e\u0434\u043d\u044f\u0442\u044c \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u043d\u043e\u0441\u0442\u044c \u0441\u0435\u043b\u0435\u043a\u0442\u043e\u0440\u0430\u043c\u0438 (<code>.modal .ai-hub-filters .setting-item<\/code>) \u0432\u043c\u0435\u0441\u0442\u043e \u0441\u0438\u043b\u043e\u0432\u043e\u0433\u043e <code>!important<\/code>.<\/p>\n<p><code>setTimeout<\/code> \u043a <code>window.setTimeout<\/code>, \u0445\u0430\u0440\u0434\u043a\u043e\u0434 <code>.obsidian<\/code> \u043a <code>Vault#configDir<\/code>, \u044d\u0442\u043e \u043c\u0435\u043b\u043e\u0447\u0438 \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u043e\u0441\u0442\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0434\u0435\u0441\u044f\u0442\u043a\u0438. \u041a\u0430\u0442\u0430\u043b\u043e\u0433 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0438\u0445 \u0432\u0441\u0435.<\/p>\n<p>\u0412\u00a0\u0441\u0443\u043c\u043c\u0435: \u043e\u0442 120\u00a0\u043e\u0448\u0438\u0431\u043e\u043a \u0434\u043e\u00a0\u043d\u0443\u043b\u044f \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u044e\u0449\u0438\u0445, \u043f\u043b\u044e\u0441 \u043f\u043e\u043b\u043d\u0430\u044f \u043b\u043e\u043a\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f RU\/EN (\u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u044e\u0442\u0441\u044f \u0438 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441, \u0438 \u0441\u0430\u043c\u0438 \u043f\u0440\u043e\u043c\u043f\u0442\u044b, \u0442\u0430\u043a \u0447\u0442\u043e\u00a0\u043d\u0430\u00a0\u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u043e\u043c \u0430\u0441\u0441\u0438\u0441\u0442\u0435\u043d\u0442 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u043f\u043e\u2011\u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u0438).<\/p>\n<h3>\u0413\u0440\u0430\u0431\u043b\u0438, \u043d\u0430\u00a0\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u044f \u043f\u043e\u0441\u0438\u0434\u0435\u043b<\/h3>\n<p>\u041c\u0451\u0440\u0442\u0432\u044b\u0435 \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u0435 \u043c\u043e\u0434\u0435\u043b\u0438. \u0417\u0430\u0445\u0430\u0440\u0434\u043a\u043e\u0434\u0438\u043b \u0432\u00a0\u0434\u0435\u0444\u043e\u043b\u0442\u0430\u0445 \u043e\u0434\u043d\u0443 \u0438\u0437\u00a0\u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u0445 \u043c\u043e\u0434\u0435\u043b\u0435\u0439 OpenRouter, \u0447\u0435\u0440\u0435\u0437 \u043d\u0435\u0434\u0435\u043b\u044e \u0435\u0451 \u0443\u0431\u0440\u0430\u043b\u0438, \u0438 \u043d\u043e\u0432\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438\u00a0\u0431\u044b \u043d\u0430\u0447\u0430\u043b\u0438 \u043b\u043e\u0432\u0438\u0442\u044c 404\u00a0\u043f\u0440\u0438\u00a0\u043f\u0435\u0440\u0432\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435. \u0425\u0443\u0434\u0448\u0435\u0435 \u043f\u0435\u0440\u0432\u043e\u0435 \u0432\u043f\u0435\u0447\u0430\u0442\u043b\u0435\u043d\u0438\u0435. \u0420\u0435\u0448\u0435\u043d\u0438\u0435 \u044d\u0442\u043e \u043a\u043d\u043e\u043f\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0442\u044f\u043d\u0435\u0442 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u0445 \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u043f\u0440\u044f\u043c\u043e \u0438\u0437 <code>openrouter.ai\/api\/v1\/models<\/code> (\u043a\u043b\u044e\u0447 \u043d\u0435\u00a0\u043d\u0443\u0436\u0435\u043d), \u0444\u0438\u043b\u044c\u0442\u0440\u0443\u0435\u0442 \u043f\u043e\u00a0\u0441\u0443\u0444\u0444\u0438\u043a\u0441\u0443 <code>:free<\/code> \u0438 \u0441\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u0442 \u043f\u043e\u00a0\u0440\u0430\u0437\u043c\u0435\u0440\u0443 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430. \u0417\u0430\u0445\u0430\u0440\u0434\u043a\u043e\u0436\u0435\u043d\u043d\u044b\u0435 \u0441\u043f\u0438\u0441\u043a\u0438 \u0432\u00a0LLM\u2011\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445 \u0433\u043d\u0438\u044e\u0442, \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043e\u043b\u0436\u043d\u044b\u00a0\u0431\u044b\u0442\u044c \u0436\u0438\u0432\u044b\u043c\u0438.<\/p>\n<p>\u041a\u043e\u043d\u0444\u0438\u0433\u2011\u043f\u0430\u043f\u043a\u0430 \u043d\u0435\u00a0\u0432\u0441\u0435\u0433\u0434\u0430 <code>.obsidian<\/code>. \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043c\u043e\u0436\u0435\u0442 \u0435\u0451 \u043f\u0435\u0440\u0435\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u0442\u044c. \u0425\u0430\u0440\u0434\u043a\u043e\u0434 <code>.obsidian\/...<\/code> \u043b\u043e\u043c\u0430\u0435\u0442\u0441\u044f \u0443\u00a0\u0442\u0430\u043a\u0438\u0445 \u043b\u044e\u0434\u0435\u0439 \u043c\u043e\u043b\u0447\u0430. \u041f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u044d\u0442\u043e <code>this.app.vault.configDir<\/code>.<\/p>\n<p><code>requestUrl<\/code> \u043f\u0440\u043e\u0442\u0438\u0432 <code>fetch<\/code>. Obsidian \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u0442 \u0441\u0432\u043e\u0439 <code>requestUrl<\/code> \u0432\u043c\u0435\u0441\u0442\u043e \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u043e\u0433\u043e <code>fetch<\/code> (\u043e\u0431\u0445\u043e\u0434\u0438\u0442 CORS \u043d\u0430\u00a0\u0434\u0435\u0441\u043a\u0442\u043e\u043f\u0435). \u041d\u043e <code>requestUrl<\/code> \u043d\u0435\u00a0\u0443\u043c\u0435\u0435\u0442 \u0441\u0442\u0440\u0438\u043c\u0438\u043d\u0433, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0434\u043b\u044f\u00a0\u043f\u043e\u0442\u043e\u043a\u043e\u0432\u043e\u0439 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u044f \u043e\u0441\u043e\u0437\u043d\u0430\u043d\u043d\u043e \u043e\u0441\u0442\u0430\u0432\u0438\u043b <code>fetch<\/code>. \u041d\u0435\u00a0\u043b\u044e\u0431\u0443\u044e \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0430\u0446\u0438\u044e\u00a0\u043b\u0438\u043d\u0442\u0435\u0440\u0430 \u043d\u0430\u0434\u043e \u0441\u043b\u0435\u043f\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c, \u0438\u043d\u043e\u0433\u0434\u0430 \u0443\u00a0\u0442\u0435\u0431\u044f \u0435\u0441\u0442\u044c \u043f\u0440\u0438\u0447\u0438\u043d\u0430, \u0438 \u0435\u0451 \u043d\u0430\u0434\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c.<\/p>\n<h3>\u0418\u0442\u043e\u0433\u0438<\/h3>\n<p>\u0427\u0442\u043e\u00a0\u043e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u0435\u0435 \u0432\u0441\u0435\u0433\u043e \u0441\u00a0\u0438\u043d\u0436\u0435\u043d\u0435\u0440\u043d\u043e\u0439 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f:<\/p>\n<p>MapReduce \u044d\u0442\u043e \u043d\u0435\u00a0\u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u043e\u00a0Hadoop. \u0422\u043e\u0442\u00a0\u0436\u0435 \u043f\u0430\u0442\u0442\u0435\u0440\u043d \u00ab\u0440\u0430\u0437\u0431\u0435\u0439, \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u0439 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e, \u0441\u0432\u0435\u0440\u043d\u0438\u00bb \u043e\u0442\u043b\u0438\u0447\u043d\u043e \u0440\u0435\u0448\u0430\u0435\u0442 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u00ab\u043a\u043e\u0440\u043f\u0443\u0441 \u043d\u0435\u00a0\u0432\u043b\u0435\u0437\u0430\u0435\u0442 \u0432\u00a0\u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 LLM\u00bb.<\/p>\n<p>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u044b\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 (\u0441\u0432\u043e\u0434\u043a\u0430 \u0432\u043c\u0435\u0441\u0442\u043e \u0442\u0435\u043a\u0441\u0442\u0430) \u044d\u0442\u043e \u0442\u043e, \u0447\u0442\u043e\u00a0\u0434\u0435\u043b\u0430\u0435\u0442 Reduce\u2011\u0444\u0430\u0437\u0443 \u0434\u0435\u0448\u0451\u0432\u043e\u0439 \u0438 \u043e\u0441\u043c\u044b\u0441\u043b\u0435\u043d\u043d\u043e\u0439.<\/p>\n<p>\u0418\u0434\u0435\u043c\u043f\u043e\u0442\u0435\u043d\u0442\u043d\u043e\u0441\u0442\u044c \u0447\u0435\u0440\u0435\u0437 <code>mtime<\/code>\u2011\u0438\u043d\u0434\u0435\u043a\u0441 \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0434\u043e\u0440\u043e\u0433\u0443\u044e \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044e \u0432\u00a0\u043f\u043e\u0447\u0442\u0438 \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u0443\u044e \u043d\u0430\u00a0\u043f\u043e\u0432\u0442\u043e\u0440\u043d\u044b\u0445 \u043f\u0440\u043e\u0433\u043e\u043d\u0430\u0445.<\/p>\n<p>\u041f\u0430\u0440\u0441\u0435\u0440 \u0434\u043e\u043b\u0436\u0435\u043d\u00a0\u0431\u044b\u0442\u044c \u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u0435\u0435 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 \u043c\u043e\u0434\u0435\u043b\u0438, \u0432\u0441\u0435\u0433\u0434\u0430.<\/p>\n<p>\u041f\u043b\u0430\u0433\u0438\u043d \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f <strong>Vault Audit AI<\/strong>, <a href=\"https:\/\/github.com\/zinverno\/obsidian-ai-hub\" rel=\"noopener noreferrer nofollow\">\u043a\u043e\u0434 \u043e\u0442\u043a\u0440\u044b\u0442 \u043d\u0430\u00a0GitHub<\/a>, \u043f\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043c\u043e\u0436\u043d\u043e \u0438\u0437\u00a0\u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u0430 Obsidian. \u0415\u0441\u043b\u0438 \u0443\u00a0\u0432\u0430\u0441 \u0442\u043e\u0436\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0440\u0430\u0437\u0440\u043e\u0441\u043b\u043e\u0441\u044c \u0432\u00a0\u0445\u0430\u043e\u0441, \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435, \u0438 \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0438\u0442\u0435, \u0447\u0442\u043e\u00a0\u043d\u0430\u0448\u0451\u043b \u0430\u0443\u0434\u0438\u0442.<\/p>\n<p>\u0411\u0443\u0434\u0443 \u0440\u0430\u0434 \u043e\u0431\u0441\u0443\u0434\u0438\u0442\u044c \u0441\u00a0\u0432\u0430\u043c\u0438 \u043f\u043b\u0430\u0433\u0438\u043d \u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c\u044e \u043f\u043e\u00a0\u0435\u0433\u043e \u0443\u043b\u0443\u0447\u0448\u0435\u043d\u0438\u044e \u0432\u00a0\u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445.<\/p>\n<\/div>\n<p>\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/1053366\/\">https:\/\/habr.com\/ru\/articles\/1053366\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u0423\u00a0\u043c\u0435\u043d\u044f \u0432\u00a0Obsidian \u043d\u0430\u043a\u043e\u043f\u0438\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u00a0\u0434\u0432\u0435 \u0442\u044b\u0441\u044f\u0447\u0438 \u0437\u0430\u043c\u0435\u0442\u043e\u043a. \u0415\u0436\u0435\u0434\u043d\u0435\u0432\u043d\u0438\u043a\u0438, \u043a\u043e\u043d\u0441\u043f\u0435\u043a\u0442\u044b, \u043e\u0431\u0440\u044b\u0432\u043a\u0438 \u0438\u0434\u0435\u0439, \u043d\u0435\u0434\u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0435 \u0447\u0435\u0440\u043d\u043e\u0432\u0438\u043a\u0438. \u0413\u0440\u0430\u0444\u2011\u0432\u044c\u044e \u0447\u0435\u0441\u0442\u043d\u043e \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043c\u043d\u0435 \u043e\u0431\u043b\u0430\u043a\u043e \u0442\u043e\u0447\u0435\u043a: \u043a\u0440\u0430\u0441\u0438\u0432\u043e, \u043d\u043e\u00a0\u0431\u0435\u0441\u043f\u043e\u043b\u0435\u0437\u043d\u043e. \u041a\u0430\u043a\u0438\u0435 \u0437\u0430\u043c\u0435\u0442\u043a\u0438 \u0432\u0438\u0441\u044f\u0442 \u0441\u0438\u0440\u043e\u0442\u0430\u043c\u0438 \u0431\u0435\u0437\u00a0\u0435\u0434\u0438\u043d\u043e\u0439 \u0441\u0432\u044f\u0437\u0438, \u043a\u0430\u043a\u0438\u0435 \u0434\u0443\u0431\u043b\u0438\u0440\u0443\u044e\u0442 \u0434\u0440\u0443\u0433 \u0434\u0440\u0443\u0433\u0430 \u043f\u043e\u0434\u00a0\u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u0442\u0435\u0433\u0430\u043c\u0438, \u043a\u0430\u043a\u0438\u0435 \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u044b \u0442\u0435\u043c \u0442\u0430\u043a \u0438 \u043d\u0435\u00a0\u0441\u043e\u0435\u0434\u0438\u043d\u0438\u043b\u0438\u0441\u044c, \u0438\u0437\u00a0\u0433\u0440\u0430\u0444\u0430 \u043d\u0435\u00a0\u0432\u044b\u0442\u0430\u0449\u0438\u0442\u044c.\u041e\u0447\u0435\u0432\u0438\u0434\u043d\u0430\u044f \u043c\u044b\u0441\u043b\u044c: \u00ab\u043e\u0442\u0434\u0430\u043c \u0432\u0441\u0451 LLM, \u043f\u0443\u0441\u0442\u044c \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u0442\u0441\u044f\u00bb. \u041d\u043e 2000\u00a0\u0437\u0430\u043c\u0435\u0442\u043e\u043a \u044d\u0442\u043e \u043c\u0438\u043b\u043b\u0438\u043e\u043d\u044b \u0442\u043e\u043a\u0435\u043d\u043e\u0432. \u041d\u0438 \u0432\u00a0\u043e\u0434\u0438\u043d \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u044d\u0442\u043e \u043d\u0435\u00a0\u0432\u043b\u0435\u0437\u0430\u0435\u0442, \u0430\u00a0\u0435\u0441\u043b\u0438\u00a0\u0431\u044b \u0438 \u0432\u043b\u0435\u0437\u043b\u043e, \u0441\u0442\u043e\u0438\u043b\u043e\u00a0\u0431\u044b \u043a\u0430\u043a\u00a0\u043a\u0440\u044b\u043b\u043e \u0441\u0430\u043c\u043e\u043b\u0451\u0442\u0430 \u0438 \u0443\u0442\u043e\u043d\u0443\u043b\u043e\u00a0\u0431\u044b \u0432\u00a0\u0448\u0443\u043c\u0435.\u0422\u0430\u043a \u043f\u043e\u044f\u0432\u0438\u043b\u0441\u044f \u0438\u0434\u0435\u044f \u043f\u043e\u00a0\u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e Vault Audit AI, \u043f\u043b\u0430\u0433\u0438\u043d \u0434\u043b\u044f\u00a0Obsidian, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u043e\u0432\u043e\u0434\u0438\u0442 \u0430\u0443\u0434\u0438\u0442 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430 \u0447\u0435\u0440\u0435\u0437 LLM: \u043d\u0430\u0445\u043e\u0434\u0438\u0442 \u0441\u0438\u0440\u043e\u0442\u044b, \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0438\u0437\u0443\u0435\u0442 \u0442\u0435\u043c\u044b, \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442 \u0442\u0435\u0433\u0438 \u0438 \u0441\u0432\u044f\u0437\u0438. \u042f \u0435\u0433\u043e \u043e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u043b \u0432\u00a0\u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u043c \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0435 \u0438 \u0432\u044b\u043b\u043e\u0436\u0438\u043b \u043d\u0430\u00a0GitHub. \u0412\u00a0\u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0440\u0430\u0437\u0431\u0435\u0440\u0443 \u0438\u043d\u0436\u0435\u043d\u0435\u0440\u043d\u0443\u044e \u043d\u0430\u0447\u0438\u043d\u043a\u0443: \u043a\u0430\u043a\u00a0\u043e\u0431\u043e\u0439\u0442\u0438\u00a0\u043b\u0438\u043c\u0438\u0442 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u0447\u0435\u0440\u0435\u0437 MapReduce, \u043a\u0430\u043a\u00a0\u043d\u0435\u00a0\u043f\u043b\u0430\u0442\u0438\u0442\u044c \u0437\u0430\u00a0\u043f\u043e\u0432\u0442\u043e\u0440\u043d\u044b\u0439 \u0430\u043d\u0430\u043b\u0438\u0437, \u043a\u0430\u043a\u00a0\u0430\u0431\u0441\u0442\u0440\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0447\u0435\u0442\u044b\u0440\u0451\u0445 LLM\u2011\u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u043e\u0432 \u043f\u043e\u0434\u00a0\u043e\u0434\u043d\u0438\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u043c, \u0438 \u0447\u0442\u043e\u00a0\u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u043f\u0435\u0440\u0435\u0434\u0435\u043b\u0430\u0442\u044c, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u0439\u0442\u0438 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u0440\u0435\u0432\u044c\u044e \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0430.\u041a\u043e\u0434 \u043d\u0430\u00a0TypeScript, \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u044b \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0435 (\u0441\u043b\u0435\u0433\u043a\u0430 \u043f\u043e\u0447\u0438\u0449\u0435\u043d\u044b \u043e\u0442\u00a0\u043e\u0431\u0451\u0440\u0442\u043e\u043a \u043b\u043e\u043a\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0440\u0430\u0434\u0438 \u0447\u0438\u0442\u0430\u0435\u043c\u043e\u0441\u0442\u0438).MapReduce \u043f\u043e\u0432\u0435\u0440\u0445 LLM\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u0440\u043e\u00a0\u0442\u043e, \u0447\u0442\u043e\u00a0\u0432\u0438\u0434\u0438\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c. \u0410\u0443\u0434\u0438\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u0432\u00a0\u0442\u0440\u0451\u0445 \u0440\u0435\u0436\u0438\u043c\u0430\u0445 \u043f\u043e\u0434\u00a0\u0440\u0430\u0437\u043d\u044b\u0439 \u043e\u0431\u044a\u0451\u043c \u0438 \u0431\u044e\u0434\u0436\u0435\u0442. Single \u0410\u0443\u0434\u0438\u0442 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0435\u0442 \u043e\u0434\u043d\u0443 \u0437\u0430\u043c\u0435\u0442\u043a\u0443 \u0437\u0430\u00a0\u0437\u0430\u043f\u0440\u043e\u0441 \u0441\u00a0\u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u043c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043e\u043c, \u0434\u043b\u044f\u00a0\u0442\u043e\u0447\u0435\u0447\u043d\u043e\u0433\u043e \u0433\u043b\u0443\u0431\u043e\u043a\u043e\u0433\u043e \u0430\u043d\u0430\u043b\u0438\u0437\u0430. Single \u041f\u043e\u043b\u043d\u044b\u0439 \u043f\u0440\u043e\u0433\u043e\u043d\u044f\u0435\u0442 \u0432\u0441\u0435 \u0437\u0430\u043c\u0435\u0442\u043a\u0438 \u043f\u043e\u0434\u0440\u044f\u0434, \u0438\u0433\u043d\u043e\u0440\u0438\u0440\u0443\u044f \u043a\u044d\u0448, \u0434\u043b\u044f\u00a0\u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0438\u043b\u0438\u00a0\u043f\u043e\u043b\u043d\u043e\u0433\u043e \u043f\u0435\u0440\u0435\u0441\u0431\u043e\u0440\u0430. \u0418 Batch + \u041e\u0442\u0447\u0451\u0442, \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u043c\u044b\u0439 \u0440\u0435\u0436\u0438\u043c: \u0431\u0430\u0442\u0447\u0435\u0432\u044b\u0439 \u0430\u043d\u0430\u043b\u0438\u0437 \u0441\u00a0\u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0438\u0437\u0430\u0446\u0438\u0435\u0439, \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0438\u043d\u0441\u0430\u0439\u0442\u0430\u043c\u0438 \u0438 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u043e\u0439 \u0432\u00a0Markdown \u0438 Canvas. \u0418\u043c\u0435\u043d\u043d\u043e \u0435\u0433\u043e \u044f \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u044e \u0434\u0430\u043b\u044c\u0448\u0435, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e\u00a0\u044d\u0442\u043e \u0438 \u0435\u0441\u0442\u044c \u043f\u043e\u043b\u043d\u044b\u0439 MapReduce\u2011\u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d, \u0440\u0430\u0434\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0432\u0441\u0451 \u0437\u0430\u0442\u0435\u0432\u0430\u043b\u043e\u0441\u044c.\u0414\u0430\u043b\u044c\u0448\u0435 \u043f\u0440\u043e\u00a0\u0442\u043e, \u043a\u0430\u043a\u00a0\u044d\u0442\u043e \u0443\u0441\u0442\u0440\u043e\u0435\u043d\u043e \u0432\u043d\u0443\u0442\u0440\u0438. \u041a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043f\u0440\u0438\u0451\u043c \u0438\u0437\u00a0\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u043b\u043e\u0436\u0438\u0442\u0441\u044f \u043d\u0430\u00a0\u0437\u0430\u0434\u0430\u0447\u0443 \u043e\u0434\u0438\u043d \u0432\u00a0\u043e\u0434\u0438\u043d. \u0415\u0441\u043b\u0438 \u0432\u0435\u0441\u044c \u043a\u043e\u0440\u043f\u0443\u0441 \u043d\u0435\u00a0\u0432\u043b\u0435\u0437\u0430\u0435\u0442 \u0432\u00a0\u043e\u0434\u0438\u043d \u0437\u0430\u043f\u0440\u043e\u0441, \u0431\u044c\u0451\u043c \u0435\u0433\u043e \u043d\u0430\u00a0\u0447\u0430\u0441\u0442\u0438, \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c \u043a\u0430\u0436\u0434\u0443\u044e \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e (Map), \u043f\u043e\u0442\u043e\u043c \u0430\u0433\u0440\u0435\u0433\u0438\u0440\u0443\u0435\u043c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0432\u00a0\u043e\u0434\u0438\u043d \u043f\u0440\u043e\u0445\u043e\u0434 (Reduce).\u0412\u0435\u0440\u0445\u043d\u0435\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u044b\u0439 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439 \u0430\u0443\u0434\u0438\u0442\u0430 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:async run(): Promise&lt;FinalAuditReport&gt; {  \/\/ 1. \u041e\u0442\u0431\u0438\u0440\u0430\u0435\u043c \u0444\u0430\u0439\u043b\u044b (\u0438\u0441\u043a\u043b\u044e\u0447\u0430\u044f \u0441\u043b\u0443\u0436\u0435\u0431\u043d\u044b\u0435 \u043f\u0430\u043f\u043a\u0438)  const files = this.collectFiles();  \/\/ 2. \u0424\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u0431\u0430\u0442\u0447\u0438 \u043f\u043e \u0431\u044e\u0434\u0436\u0435\u0442\u0443 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432  const batches = await this.buildBatches(files);  \/\/ 3. MAP: \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u044b\u0439 \u0430\u043d\u0430\u043b\u0438\u0437 \u0431\u0430\u0442\u0447\u0435\u0439  const mapResults = await this.runMapPhase(batches);  const allSummaries = mapResults.flatMap((b) =&gt; b.files);  \/\/ 4. REDUCE: \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u0441\u0432\u043e\u0434\u043e\u043a  const clusters = await this.runReducePhase(allSummaries);  \/\/ 5. \u0424\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u0441\u0438\u043d\u0442\u0435\u0437: \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u044b\u0435 \u0438\u043d\u0441\u0430\u0439\u0442\u044b \u0438 \u043f\u043b\u0430\u043d \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439  const { globalInsights, actionPlan } =    await this.runFinalSynthesis(clusters, &#8230;);  return { clusters, globalInsights, actionPlan, &#8230; };}\u0413\u043b\u0430\u0432\u043d\u043e\u0435 \u0442\u0443\u0442 \u0432\u043e\u0442 \u0447\u0442\u043e: Map \u043d\u0435\u00a0\u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0442\u0435\u043a\u0441\u0442, \u043e\u043d \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443. \u041a\u0430\u0436\u0434\u0430\u044f \u0437\u0430\u043c\u0435\u0442\u043a\u0430 \u0443\u0436\u0438\u043c\u0430\u0435\u0442\u0441\u044f \u0434\u043e\u00a0\u043a\u043e\u043c\u043f\u0430\u043a\u0442\u043d\u043e\u0439 \u0441\u0432\u043e\u0434\u043a\u0438: \u0433\u043b\u0430\u0432\u043d\u0430\u044f \u043c\u044b\u0441\u043b\u044c, \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u0442\u0435\u0437\u0438\u0441\u044b, \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438, \u043e\u0446\u0435\u043d\u043a\u0430 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0430, \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u0435 \u0442\u0435\u0433\u0438. \u042d\u0442\u043e \u043d\u0430\u00a0\u043f\u043e\u0440\u044f\u0434\u043e\u043a \u0434\u0435\u0448\u0435\u0432\u043b\u0435, \u0447\u0435\u043c \u0442\u0430\u0449\u0438\u0442\u044c \u043f\u043e\u043b\u043d\u044b\u0439 \u0442\u0435\u043a\u0441\u0442 \u0432\u00a0\u0444\u0430\u0437\u0443 Reduce, \u0438 \u0438\u043c\u0435\u043d\u043d\u043e \u044d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 Reduce \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u0432\u0441\u0451 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0446\u0435\u043b\u0438\u043a\u043e\u043c.\u041a\u0430\u043a\u00a0\u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u044d\u0442\u043e \u0432\u00a0Obsidian\u0411\u0430\u0442\u0447\u0438\u043d\u0433 \u043f\u043e\u00a0\u0431\u044e\u0434\u0436\u0435\u0442\u0443, \u0430\u00a0\u043d\u0435\u00a0\u043f\u043e\u00a0\u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0443\u041d\u0430\u0438\u0432\u043d\u044b\u0439 \u0431\u0430\u0442\u0447\u0438\u043d\u0433 \u00ab\u043f\u043e N \u0437\u0430\u043c\u0435\u0442\u043e\u043a\u00bb \u043b\u043e\u043c\u0430\u0435\u0442\u0441\u044f \u043d\u0430\u00a0\u0440\u0430\u0437\u043d\u043e\u0440\u043e\u0434\u043d\u043e\u043c \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0435: \u0434\u0435\u0441\u044f\u0442\u044c \u043e\u0434\u043d\u043e\u0441\u0442\u0440\u043e\u0447\u043d\u0438\u043a\u043e\u0432 \u0438 \u0434\u0435\u0441\u044f\u0442\u044c \u043b\u043e\u043d\u0433\u0440\u0438\u0434\u043e\u0432 \u044d\u0442\u043e \u0440\u0430\u0437\u043d\u0430\u044f \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043d\u0430\u00a0\u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0431\u0430\u0442\u0447\u0438 \u043d\u0430\u0431\u0438\u0440\u0430\u044e\u0442\u0441\u044f \u0436\u0430\u0434\u043d\u043e, \u043f\u043e\u00a0\u0431\u044e\u0434\u0436\u0435\u0442\u0443 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432:private async buildBatches(files: TFile[]) {  const batches = [];  let currentBatch: TFile[] = [];  let currentPayload = &#171;&#187;;  const flush = () =&gt; {    if (currentBatch.length === 0) return;    batches.push({ payload: currentPayload, files: currentBatch });    currentBatch = [];    currentPayload = &#171;&#187;;  };  for (const file of files) {    \/\/ \u0415\u0441\u043b\u0438 \u0435\u0441\u0442\u044c \u0438\u043d\u0434\u0435\u043a\u0441 \u0438 \u0444\u0430\u0439\u043b \u043d\u0435 \u043c\u0435\u043d\u044f\u043b\u0441\u044f, \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u0430\u0435\u043c (\u0441\u043c. \u043d\u0438\u0436\u0435)    if (this.index &amp;&amp; !this.index.isStale(file)) continue;    const content = await this.app.vault.cachedRead(file);    const entry = this.formatForBatch(file, content);    if (currentPayload.length + entry.length &gt; this.config.batchCharBudget) {      flush();    }    currentBatch.push(file);    currentPayload += entry;  }  flush();  return batches;}\u0417\u0434\u0435\u0441\u044c\u00a0\u0436\u0435 \u0437\u0430\u0448\u0438\u0442\u0430 \u043f\u0435\u0440\u0432\u0430\u044f \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044f \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u0438: this.app.vault.cachedRead \u0432\u043c\u0435\u0441\u0442\u043e read (\u043e\u0442\u0434\u0430\u0451\u0442 \u0437\u0430\u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e, \u043d\u0435\u00a0\u043b\u0435\u0437\u0435\u0442 \u043d\u0430\u00a0\u0434\u0438\u0441\u043a\u00a0\u043b\u0438\u0448\u043d\u0438\u0439 \u0440\u0430\u0437) \u0438 \u043f\u0440\u043e\u043f\u0443\u0441\u043a \u043d\u0435\u0438\u0437\u043c\u0435\u043d\u0451\u043d\u043d\u044b\u0445 \u0444\u0430\u0439\u043b\u043e\u0432 \u0447\u0435\u0440\u0435\u0437 \u0438\u043d\u0434\u0435\u043a\u0441.\u041f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0441\u00a0\u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435\u043c: \u0441\u0435\u043c\u0430\u0444\u043e\u0440 \u043d\u0430\u00a0\u0432\u043e\u0440\u043a\u0435\u0440\u0430\u0445Map\u2011\u0444\u0430\u0437\u0430 \u044d\u0442\u043e \u0434\u0435\u0441\u044f\u0442\u043a\u0438 \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043a\u00a0API. \u0413\u043d\u0430\u0442\u044c \u0438\u0445 \u0432\u0441\u0435 \u0440\u0430\u0437\u043e\u043c \u043d\u0435\u043b\u044c\u0437\u044f, \u0443\u043f\u0440\u0451\u0448\u044c\u0441\u044f \u0432\u00a0rate limit \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u0430. \u0413\u043d\u0430\u0442\u044c \u043f\u043e\u00a0\u043e\u0434\u043d\u043e\u043c\u0443 \u043c\u0435\u0434\u043b\u0435\u043d\u043d\u043e. \u041d\u0443\u0436\u0435\u043d \u043f\u0443\u043b \u0432\u043e\u0440\u043a\u0435\u0440\u043e\u0432 \u0441\u00a0\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0439 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c\u044e. \u0420\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043b \u0431\u0435\u0437\u00a0\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a (\u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e\u00a0\u0438\u0445 \u043d\u0435\u00a0\u0437\u043d\u0430\u044e) ), \u0447\u0435\u0440\u0435\u0437 \u043e\u0431\u0449\u0443\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c:private async runMapPhase(batches) {  const results = new Array(batches.length);  const queue = [&#8230;batches];  let completed = 0;  const worker = async () =&gt; {    while (queue.length &gt; 0) {      if (this.signal.aborted) return;      const batch = queue.shift();      if (!batch) return;      try {        \/\/ withRetry: \u044d\u043a\u0441\u043f\u043e\u043d\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 backoff \u043d\u0430 \u0441\u0435\u0442\u0435\u0432\u044b\u0445 \u0441\u0431\u043e\u044f\u0445        results[batch.index] = await withRetry(          () =&gt; this.analyzeBatch(batch),          this.config.maxRetries,          this.signal,        );      } catch (err) {        \/\/ \u041e\u0434\u0438\u043d \u0443\u043f\u0430\u0432\u0448\u0438\u0439 \u0431\u0430\u0442\u0447 \u043d\u0435 \u0434\u043e\u043b\u0436\u0435\u043d \u0440\u043e\u043d\u044f\u0442\u044c \u0432\u0435\u0441\u044c \u0430\u0443\u0434\u0438\u0442        results[batch.index] = { files: [], error: String(err) };      }      completed++;      this.report(&#171;mapping&#187;, completed, batches.length);      if (this.config.delayBetweenBatchesMs &gt; 0) {        await new Promise((r) =&gt;          window.setTimeout(r, this.config.delayBetweenBatchesMs),        );      }    }  };  const concurrency = Math.min(this.config.maxConcurrent, batches.length);  const workers = Array.from({ length: concurrency }, () =&gt; worker());  await Promise.all(workers);  return results.filter((r) =&gt; !!r);}\u0422\u0443\u0442 \u0435\u0441\u0442\u044c \u0442\u0440\u0438 \u0440\u0435\u0448\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u044f \u0441\u0447\u0438\u0442\u0430\u044e \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0438\u0430\u043b\u044c\u043d\u044b\u043c\u0438.\u0418\u0437\u043e\u043b\u044f\u0446\u0438\u044f \u0441\u0431\u043e\u0435\u0432: \u0443\u043f\u0430\u0432\u0448\u0438\u0439 \u0431\u0430\u0442\u0447 \u043f\u0438\u0448\u0435\u0442 { files: [], error }, \u0430\u00a0\u043d\u0435\u00a0\u0432\u044b\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0435\u0442 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043d\u0430\u0432\u0435\u0440\u0445. \u0410\u0443\u0434\u0438\u0442 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430 \u043d\u0430 2000\u00a0\u0437\u0430\u043c\u0435\u0442\u043e\u043a \u043d\u0435\u00a0\u0434\u043e\u043b\u0436\u0435\u043d \u0443\u043c\u0438\u0440\u0430\u0442\u044c \u0438\u0437\u2011\u0437\u0430 \u043e\u0434\u043d\u043e\u0433\u043e \u0442\u0430\u0439\u043c\u0430\u0443\u0442\u0430 \u043d\u0430 47-\u043c \u0431\u0430\u0442\u0447\u0435.\u041a\u043e\u043e\u043f\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u0430\u044f \u043e\u0442\u043c\u0435\u043d\u0430: this.signal (AbortSignal) \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0441\u044f \u0432\u00a0\u043d\u0430\u0447\u0430\u043b\u0435 \u043a\u0430\u0436\u0434\u043e\u0439 \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0438. \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043d\u0430\u0436\u0430\u043b \u00ab\u041e\u0442\u043c\u0435\u043d\u0430\u00bb, \u0432\u043e\u0440\u043a\u0435\u0440\u044b \u0434\u043e\u0435\u0434\u0430\u044e\u0442 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u0431\u0430\u0442\u0447 \u0438 \u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u044e\u0442\u0441\u044f.Rate limiting \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u043c\u043e\u0439 \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u043e\u0439 \u043c\u0435\u0436\u0434\u0443 \u0431\u0430\u0442\u0447\u0430\u043c\u0438, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e\u00a0\u0443\u00a0\u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u0445 \u0442\u0430\u0440\u0438\u0444\u043e\u0432\u00a0\u043b\u0438\u043c\u0438\u0442\u044b \u0436\u0451\u0441\u0442\u043a\u0438\u0435.LLM \u0432\u0440\u0451\u0442 \u043f\u0440\u043e\u00a0JSON, \u0438 \u044d\u0442\u043e \u043d\u0430\u0434\u043e \u043f\u0435\u0440\u0435\u0436\u0438\u0432\u0430\u0442\u044c\u041f\u0440\u043e\u0441\u0438\u0448\u044c \u043c\u043e\u0434\u0435\u043b\u044c \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0447\u0438\u0441\u0442\u044b\u0439 JSON, \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0448\u044c JSON, \u043e\u0431\u0451\u0440\u043d\u0443\u0442\u044b\u0439 \u0432 &#171;`json, \u0441\u00a0\u043f\u0440\u0435\u0430\u043c\u0431\u0443\u043b\u043e\u0439 \u00ab\u041a\u043e\u043d\u0435\u0447\u043d\u043e! \u0412\u043e\u0442 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442:\u00bb. \u041f\u0430\u0440\u0441\u0438\u0442\u044c \u044d\u0442\u043e \u043d\u0430\u0438\u0432\u043d\u044b\u043c JSON.parse \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442 \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043a\u0440\u0430\u0448\u0438 \u0432\u00a0\u043f\u0440\u043e\u0434\u0435. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432\u0435\u0441\u044c \u043f\u0430\u0440\u0441\u0438\u043d\u0433 \u0438\u0434\u0451\u0442 \u0447\u0435\u0440\u0435\u0437 \u0437\u0430\u0449\u0438\u0449\u0451\u043d\u043d\u044b\u0439 \u044d\u043a\u0441\u0442\u0440\u0430\u043a\u0442\u043e\u0440:function extractJSON&lt;T&gt;(raw: string): T {  \/\/ \u0421\u0440\u0435\u0437\u0430\u0435\u043c markdown-\u043e\u0431\u0451\u0440\u0442\u043a\u0443  const cleaned = raw.replace(\/&#171;`json\\n?\/gi, &#171;&#187;).replace(\/&#171;`\\n?\/g, &#171;&#187;).trim();  \/\/ \u0418\u0449\u0435\u043c \u043f\u0435\u0440\u0432\u044b\u0439 { \u0438\u043b\u0438 [, \u043e\u0442\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0435\u043c \u0431\u043e\u043b\u0442\u043e\u0432\u043d\u044e \u043c\u043e\u0434\u0435\u043b\u0438 \u0434\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b  const jsonStart = Math.min(    &#8230;[cleaned.indexOf(&#171;{&#171;), cleaned.indexOf(&#171;[&#171;)].filter((i) =&gt; i &gt;= 0),  );  if (!Number.isFinite(jsonStart)) {    throw new Error(&#171;JSON \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d \u0432 \u043e\u0442\u0432\u0435\u0442\u0435 \u043c\u043e\u0434\u0435\u043b\u0438&#187;);  }  return JSON.parse(cleaned.slice(jsonStart)) as T;}\u042d\u0442\u043e \u043d\u0435\u00a0\u043a\u0440\u0430\u0441\u0438\u0432\u043e, \u043d\u043e\u00a0\u044d\u0442\u043e \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u00a0LLM: \u0442\u0432\u043e\u0439 \u043f\u0430\u0440\u0441\u0435\u0440 \u043e\u0431\u044f\u0437\u0430\u043d\u00a0\u0431\u044b\u0442\u044c \u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u0435\u0435, \u0447\u0435\u043c \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0434\u0435\u043b\u044c \u00ab\u043e\u0431\u0435\u0449\u0430\u0435\u0442\u00bb \u0441\u043e\u0431\u043b\u044e\u0434\u0430\u0442\u044c.Reduce: \u043a\u043e\u043c\u043f\u0430\u043a\u0442\u043d\u043e\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0440\u0435\u0448\u0430\u0435\u0442\u0412\u00a0\u0444\u0430\u0437\u0435 Reduce \u0432\u0441\u0435 \u0441\u0432\u043e\u0434\u043a\u0438 \u0441\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0432\u00a0\u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0439 JSON (\u043a\u043e\u0440\u043e\u0442\u043a\u0438\u0435 \u043a\u043b\u044e\u0447\u0438 \u044d\u043a\u043e\u043d\u043e\u043c\u044f\u0442 \u0442\u043e\u043a\u0435\u043d\u044b \u043d\u0430\u00a0\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435) \u0438 \u0443\u0445\u043e\u0434\u044f\u0442 \u043e\u0434\u043d\u0438\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u043c \u043d\u0430\u00a0\u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0438\u0437\u0430\u0446\u0438\u044e. \u0415\u0441\u043b\u0438 \u0441\u0432\u043e\u0434\u043e\u043a \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043c\u043d\u043e\u0433\u043e, Reduce \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0438\u0435\u0440\u0430\u0440\u0445\u0438\u0447\u0435\u0441\u043a\u0438\u043c (\u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0438\u0437\u0443\u0435\u043c \u0433\u0440\u0443\u043f\u043f\u044b, \u043f\u043e\u0442\u043e\u043c \u0441\u043b\u0438\u0432\u0430\u0435\u043c \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u044b), \u043d\u043e\u00a0\u0432\u00a0\u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449 \u0445\u0432\u0430\u0442\u0430\u0435\u0442 \u043e\u0434\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0445\u043e\u0434\u0430:private async runReducePhase(summaries) {  const compact = summaries.map((s) =&gt; ({    p: s.path, t: s.topics, k: s.keyIdeas, tags: s.suggestedTags,  }));  if (JSON.stringify(compact).length &lt; 40000) {    return await this.clusterize(compact); \/\/ \u043e\u0434\u0438\u043d \u043f\u0440\u043e\u0445\u043e\u0434  }  \/\/ \u0438\u043d\u0430\u0447\u0435 \u0438\u0435\u0440\u0430\u0440\u0445\u0438\u0447\u0435\u0441\u043a\u0438\u0439 reduce \u043f\u043e \u0433\u0440\u0443\u043f\u043f\u0430\u043c  &#8230;}\u0418\u043d\u043a\u0440\u0435\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d\u0430\u044f \u0438\u043d\u0434\u0435\u043a\u0441\u0430\u0446\u0438\u044f: \u043d\u0435\u00a0\u043f\u043b\u0430\u0442\u0438\u0442\u044c \u0434\u0432\u0430\u0436\u0434\u044b\u0410\u0443\u0434\u0438\u0442 \u0434\u043e\u0440\u043e\u0433\u0430\u044f \u043f\u043e\u00a0\u0442\u043e\u043a\u0435\u043d\u0430\u043c \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044f. \u041f\u0440\u043e\u0433\u043e\u043d\u044f\u0442\u044c \u0432\u0441\u0451 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0437\u0430\u043d\u043e\u0432\u043e \u043f\u0440\u0438\u00a0\u043a\u0430\u0436\u0434\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u0440\u0430\u0441\u0442\u043e\u0447\u0438\u0442\u0435\u043b\u044c\u0441\u0442\u0432\u043e, \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u043a\u043e\u0433\u0434\u0430 \u043c\u0435\u0436\u0434\u0443 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u043c\u0438 \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u043e\u0441\u044c \u0442\u0440\u0438 \u0437\u0430\u043c\u0435\u0442\u043a\u0438 \u0438\u0437\u00a0\u0434\u0432\u0443\u0445 \u0442\u044b\u0441\u044f\u0447. \u0420\u0435\u0448\u0435\u043d\u0438\u0435 \u044d\u0442\u043e \u043f\u0435\u0440\u0441\u0438\u0441\u0442\u0435\u043d\u0442\u043d\u044b\u0439 \u0438\u043d\u0434\u0435\u043a\u0441 \u0441\u00a0\u043f\u0440\u043e\u0432\u0435\u0440\u043a\u043e\u0439 \u043f\u043e mtime.\u0421\u0445\u0435\u043c\u0430 \u0437\u0430\u043f\u0438\u0441\u0438 \u043d\u0430\u00a0\u043e\u0434\u043d\u0443 \u0437\u0430\u043c\u0435\u0442\u043a\u0443:export interface NoteRecord {  mtime: number;        \/\/ mtime \u0444\u0430\u0439\u043b\u0430 \u043d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u0430\u043d\u0430\u043b\u0438\u0437\u0430, \u043a\u043b\u044e\u0447 \u0438\u043d\u043a\u0440\u0435\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438  analyzedAt: number;  mainIdea: string;  keyPoints: string[];  entities: string[];  quality: &#171;draft&#187; | &#171;developed&#187; | &#171;polished&#187;;  suggestedTags: string[];  \/\/ &#8230;}\u0412\u0441\u044f \u0438\u043d\u043a\u0440\u0435\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0434\u0435\u0440\u0436\u0438\u0442\u0441\u044f \u043d\u0430\u00a0\u043e\u0434\u043d\u043e\u0439 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0435:isStale(file: TFile): boolean {  const rec = this.data.notes[file.path];  return !rec || rec.mtime !== file.stat.mtime;}\u0415\u0441\u043b\u0438 \u0444\u0430\u0439\u043b \u043d\u0435\u00a0\u0432\u00a0\u0438\u043d\u0434\u0435\u043a\u0441\u0435 \u0438\u043b\u0438\u00a0\u0435\u0433\u043e mtime \u043d\u0435\u00a0\u0441\u043e\u0432\u043f\u0430\u0434\u0430\u0435\u0442 \u0441\u00a0\u0437\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u043c, \u0437\u043d\u0430\u0447\u0438\u0442, \u0435\u0433\u043e \u043d\u0430\u0434\u043e \u043f\u0435\u0440\u0435\u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c. \u0418\u043d\u0430\u0447\u0435 \u0431\u0435\u0440\u0451\u043c \u0433\u043e\u0442\u043e\u0432\u0443\u044e \u0441\u0432\u043e\u0434\u043a\u0443. \u041d\u0430\u00a0\u0432\u0442\u043e\u0440\u043e\u043c \u043f\u0440\u043e\u0433\u043e\u043d\u0435 \u043f\u043e\u00a0\u043d\u0435\u0438\u0437\u043c\u0435\u043d\u043d\u043e\u043c\u0443 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0443 \u0430\u0443\u0434\u0438\u0442 \u0441\u0442\u043e\u0438\u0442 \u043f\u043e\u0447\u0442\u0438 \u043d\u043e\u043b\u044c \u0442\u043e\u043a\u0435\u043d\u043e\u0432.\u0414\u0432\u0430 \u043c\u043e\u043c\u0435\u043d\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u044f \u0437\u0430\u043b\u043e\u0436\u0438\u043b \u0441\u00a0\u043f\u0440\u0438\u0446\u0435\u043b\u043e\u043c \u043d\u0430\u00a0\u0431\u0443\u0434\u0443\u0449\u0435\u0435.\u0412\u0435\u0440\u0441\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u0445\u0435\u043c\u044b. \u0423\u00a0\u0438\u043d\u0434\u0435\u043a\u0441\u0430 \u0435\u0441\u0442\u044c SCHEMA_VERSION. \u041a\u043e\u0433\u0434\u0430 \u044f \u043c\u0435\u043d\u044f\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 NoteRecord, \u0441\u0442\u0430\u0440\u044b\u0439 \u0438\u043d\u0434\u0435\u043a\u0441 \u043f\u0440\u043e\u0441\u0442\u043e \u0438\u0433\u043d\u043e\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f (\u0447\u0438\u0441\u0442\u044b\u0439 \u0441\u0442\u0430\u0440\u0442), \u0430\u00a0\u043d\u0435\u00a0\u0440\u043e\u043d\u044f\u0435\u0442 \u043f\u043b\u0430\u0433\u0438\u043d \u043d\u0430\u00a0\u043d\u0435\u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445:async load(): Promise&lt;void&gt; {  try {    const parsed = JSON.parse(await this.app.vault.adapter.read(INDEX_PATH));    if (parsed.version === SCHEMA_VERSION &amp;&amp; parsed.notes) {      this.data = parsed;    }    \/\/ \u0434\u0440\u0443\u0433\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f, \u043c\u043e\u043b\u0447\u0430 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u043c \u0437\u0430\u043d\u043e\u0432\u043e  } catch {    \/\/ \u0444\u0430\u0439\u043b\u0430 \u043d\u0435\u0442 \u0438\u043b\u0438 \u0431\u0438\u0442\u044b\u0439 JSON, \u0447\u0438\u0441\u0442\u044b\u0439 \u0441\u0442\u0430\u0440\u0442 \u0431\u0435\u0437 \u043a\u0440\u0430\u0448\u0430  }}\u0424\u043b\u0430\u0433 dirty \u0438 prune. \u0418\u043d\u0434\u0435\u043a\u0441 \u043f\u0438\u0448\u0435\u0442\u0441\u044f \u043d\u0430\u00a0\u0434\u0438\u0441\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u0435\u0441\u043b\u0438 \u0440\u0435\u0430\u043b\u044c\u043d\u043e \u043c\u0435\u043d\u044f\u043b\u0441\u044f (dirty), \u0430 prune \u0447\u0438\u0441\u0442\u0438\u0442 \u0437\u0430\u043f\u0438\u0441\u0438 \u0434\u043b\u044f\u00a0\u0444\u0430\u0439\u043b\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435\u0442. \u041c\u0435\u043b\u043e\u0447\u0438, \u043d\u043e\u00a0\u0438\u043c\u0435\u043d\u043d\u043e \u043e\u043d\u0438 \u043e\u0442\u043b\u0438\u0447\u0430\u044e\u0442 \u00ab\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0443\u00a0\u043c\u0435\u043d\u044f\u00bb \u043e\u0442 \u00ab\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0443\u00a0\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0441\u00a0\u0436\u0438\u0432\u044b\u043c, \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e \u043c\u0435\u043d\u044f\u044e\u0449\u0438\u043c\u0441\u044f \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435\u043c\u00bb.\u041e\u0434\u0438\u043d \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043d\u0430\u00a0\u0447\u0435\u0442\u044b\u0440\u0451\u0445 \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u043e\u0432\u042f \u0445\u043e\u0442\u0435\u043b, \u0447\u0442\u043e\u0431\u044b \u043f\u043b\u0430\u0433\u0438\u043d \u0440\u0430\u0431\u043e\u0442\u0430\u043b \u0441\u00a0OpenRouter, OpenAI, Groq \u0438 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0439 Ollama(\u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u0432\u0430\u0436\u043d\u043e \u0432\u043e\u043f\u0440\u043e\u0441 \u0434\u043b\u044f\u00a0\u043c\u0435\u043d\u044f \u0441\u0442\u043e\u044f\u043b \u0441\u00a0\u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u043c,\u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e\u00a0\u043c\u043d\u043e\u0433\u0438\u043c \u0432\u0430\u0436\u043d\u0430 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u044b \u043d\u0430\u00a0\u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u043c LLM), \u0438 \u0447\u0442\u043e\u0431\u044b \u0435\u0441\u043b\u0438 \u0447\u0442\u043e\u00a0\u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u044f\u0442\u043e\u0433\u043e \u043c\u043e\u0436\u043d\u043e\u00a0\u0431\u044b\u043b\u043e, \u043d\u0435\u00a0\u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u044f \u044f\u0434\u0440\u043e. \u0421\u043f\u0430\u0441\u0430\u0435\u0442 \u0442\u043e, \u0447\u0442\u043e\u00a0\u043f\u043e\u0447\u0442\u0438 \u0432\u0441\u0435 \u043e\u043d\u0438 \u0433\u043e\u0432\u043e\u0440\u044f\u0442 \u043d\u0430\u00a0\u0434\u0438\u0430\u043b\u0435\u043a\u0442\u0435 OpenAI\u2011\u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u043e\u0433\u043e API. \u0420\u0430\u0437\u043b\u0438\u0447\u0438\u044f \u0432\u00a0\u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430\u0445 \u0438 \u043c\u0435\u043b\u043e\u0447\u0430\u0445 \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u0430 \u0438\u0437\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u0432\u00a0\u043e\u0434\u043d\u043e\u043c \u043c\u0435\u0441\u0442\u0435:function buildHeaders(settings: AIHubSettings): Record&lt;string, string&gt; {  const provider =&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-485463","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/485463","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=485463"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/485463\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=485463"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=485463"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=485463"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}