diff --git a/deno.json b/deno.json index a7db0a4..381a795 100644 --- a/deno.json +++ b/deno.json @@ -1,11 +1,12 @@ { "tasks": { - "dev": "deno run --watch --allow-read --allow-net main.ts" + "dev": "deno run --watch --allow-read --allow-net --env-file main.ts" }, "imports": { "@std/assert": "jsr:@std/assert@1", "@std/fs": "jsr:@std/fs@^1.0.5", "@std/path": "jsr:@std/path@^1.0.8", + "openai": "npm:openai@^4.72.0", "tiddlywiki": "npm:tiddlywiki@^5.3.6", "tw5-typed": "npm:tw5-typed@^0.5.14" }, diff --git a/deno.lock b/deno.lock index 277ce54..a0f883f 100644 --- a/deno.lock +++ b/deno.lock @@ -6,6 +6,7 @@ "jsr:@std/internal@^1.0.5": "1.0.5", "jsr:@std/path@^1.0.7": "1.0.8", "jsr:@std/path@^1.0.8": "1.0.8", + "npm:openai@^4.72.0": "4.72.0", "npm:tiddlywiki@^5.3.6": "5.3.6", "npm:tw5-typed@*": "0.5.14", "npm:tw5-typed@~0.5.14": "0.5.14" @@ -46,10 +47,29 @@ "@types/estree@1.0.6": { "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==" }, + "@types/node-fetch@2.6.12": { + "integrity": "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==", + "dependencies": [ + "@types/node@22.5.4", + "form-data" + ] + }, + "@types/node@18.19.64": { + "integrity": "sha512-955mDqvO2vFf/oL7V3WiUtiz+BugyX8uVbaT2H8oj3+8dRyH2FLiNdowe7eNqRM7IOIZvzDH76EoAT+gwm6aIQ==", + "dependencies": [ + "undici-types@5.26.5" + ] + }, "@types/node@20.17.6": { "integrity": "sha512-VEI7OdvK2wP7XHnsuXbAJnEpEkF6NjSN45QJlL4VGqZSXsnicpesdTWsg9RISeSdYd3yeRj/y3k5KGjUXYnFwQ==", "dependencies": [ - "undici-types" + "undici-types@6.19.8" + ] + }, + "@types/node@22.5.4": { + "integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==", + "dependencies": [ + "undici-types@6.19.8" ] }, "@types/tern@0.23.9": { @@ -61,19 +81,122 @@ "@types/zrender@4.0.6": { "integrity": "sha512-1jZ9bJn2BsfmYFPBHtl5o3uV+ILejAtGrDcYSpT4qaVKEI/0YY+arw3XHU04Ebd8Nca3SQ7uNcLaqiL+tTFVMg==" }, + "abort-controller@3.0.0": { + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dependencies": [ + "event-target-shim" + ] + }, + "agentkeepalive@4.5.0": { + "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", + "dependencies": [ + "humanize-ms" + ] + }, + "asynckit@0.4.0": { + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "combined-stream@1.0.8": { + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": [ + "delayed-stream" + ] + }, + "delayed-stream@1.0.0": { + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" + }, + "event-target-shim@5.0.1": { + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" + }, + "form-data-encoder@1.7.2": { + "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==" + }, + "form-data@4.0.1": { + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "dependencies": [ + "asynckit", + "combined-stream", + "mime-types" + ] + }, + "formdata-node@4.4.1": { + "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", + "dependencies": [ + "node-domexception", + "web-streams-polyfill" + ] + }, + "humanize-ms@1.2.1": { + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dependencies": [ + "ms" + ] + }, + "mime-db@1.52.0": { + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types@2.1.35": { + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": [ + "mime-db" + ] + }, + "ms@2.1.3": { + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node-domexception@1.0.0": { + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==" + }, + "node-fetch@2.7.0": { + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": [ + "whatwg-url" + ] + }, + "openai@4.72.0": { + "integrity": "sha512-hFqG9BWCs7L7ifrhJXw7mJXmUBr7d9N6If3J9563o0jfwVA4wFANFDDaOIWFdgDdwgCXg5emf0Q+LoLCGszQYA==", + "dependencies": [ + "@types/node@18.19.64", + "@types/node-fetch", + "abort-controller", + "agentkeepalive", + "form-data-encoder", + "formdata-node", + "node-fetch" + ] + }, "tiddlywiki@5.3.6": { "integrity": "sha512-RfWt+Bo/UsTdzP5N4nEInjaJjgAzylUMf21hE4FL5v65c3x054+A+3g3sgW1m68lTJbTbiiqSZ6q6BEIZMwhSQ==" }, + "tr46@0.0.3": { + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, "tw5-typed@0.5.14": { "integrity": "sha512-9V3Fr9wBQxzdFD3eSAv8vzDHfAYAkweg8rB8mu8rRxgflpxib+saSi3UaiR/rH2NzMNU/dg9nHFa/EVI9WiGYA==", "dependencies": [ "@types/codemirror", "@types/echarts", - "@types/node" + "@types/node@20.17.6" ] }, + "undici-types@5.26.5": { + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, "undici-types@6.19.8": { "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==" + }, + "web-streams-polyfill@4.0.0-beta.3": { + "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==" + }, + "webidl-conversions@3.0.1": { + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "whatwg-url@5.0.0": { + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": [ + "tr46", + "webidl-conversions" + ] } }, "remote": { @@ -107,6 +230,7 @@ "jsr:@std/assert@1", "jsr:@std/fs@^1.0.5", "jsr:@std/path@^1.0.8", + "npm:openai@^4.72.0", "npm:tiddlywiki@^5.3.6", "npm:tw5-typed@~0.5.14" ] diff --git a/generateChatML.ts b/generateChatML.ts index e003e94..8a2f908 100644 --- a/generateChatML.ts +++ b/generateChatML.ts @@ -1,6 +1,12 @@ import { join } from "@std/path"; -import "tw5-typed"; +import type {} from "tw5-typed"; import { TiddlyWiki } from "tiddlywiki"; +import OpenAI from "openai"; + +const openai = new OpenAI({ + apiKey: Deno.env.get("DEEPSEEK_API_KEY"), + baseURL: "https://api.deepseek.com", +}); const wikiInstance = TiddlyWiki(); const wikiPath = join(Deno.cwd(), "wiki"); @@ -15,18 +21,23 @@ export async function generateChatML(tidContent: string): Promise { .filter((tiddler) => tiddler !== undefined) .filter((tiddler) => tiddler.fields.prompt !== undefined); - const chatmlContents = await Promise.all(dataPromptTiddlers.map(async (tiddler) => { - const prompt = tiddler.fields.prompt as string; - const AIOutput = await callLLM(prompt, tidContent); - const chatmlContent = wikiInstance.wiki.renderTiddler("text/plain", tiddler.fields.title, { - variables: { - prompt, - AIOutput, - } - }) - return chatmlContent; - })) - + const chatmlContents = await Promise.all( + dataPromptTiddlers.map(async (tiddler) => { + const prompt = tiddler.fields.prompt as string; + const AIOutput = await callLLM(prompt, tidContent); + const chatmlContent = wikiInstance.wiki.renderTiddler( + "text/plain", + tiddler.fields.title, + { + variables: { + prompt, + AIOutput, + }, + }, + ); + return chatmlContent; + }), + ); // 合并所有消息 return chatmlContents.join(""); @@ -36,7 +47,19 @@ async function callLLM( systemPrompt: string, userPrompt: string, ): Promise { - // 调用 LLM API 的逻辑,提取为可替换的函数 - // ...implementation... - return ""; // 返回助手的回复 + console.log("Calling LLM with systemPrompt:", systemPrompt); + console.log("Calling LLM with userPrompt:", userPrompt); + + const completion = await openai.chat.completions.create({ + model: "deepseek-chat", + messages: [ + { role: "system", content: systemPrompt }, + { role: "user", content: userPrompt }, + ], + "stream": false, + }); + + const assistantMessage = completion.choices[0]?.message?.content || ""; + console.log("Received assistantMessage:", assistantMessage); + return assistantMessage; } diff --git a/main.ts b/main.ts index a66ef58..14eda69 100644 --- a/main.ts +++ b/main.ts @@ -34,13 +34,8 @@ async function readTidFilesAndCreateChatML(folderPath: string) { await processFolder(folderPath); } -async function callLLM(systemPrompt: string, userPrompt: string): Promise { - // 调用 LLM API 的逻辑,提取为可替换的函数 - // ...implementation... - return ''; // 返回助手的回复 -} - +const subFolder = "core/wiki/config/ui"; if (import.meta.main) { - const folderPath = join(Deno.cwd(), '..', 'TiddlyWiki5'); + const folderPath = join(Deno.cwd(), '..', 'TiddlyWiki5', ...subFolder.split('/')); readTidFilesAndCreateChatML(folderPath); }