From 05513d6517cb716ab1f00f28004123b8398ae574 Mon Sep 17 00:00:00 2001 From: Yuto Terada Date: Sun, 27 Oct 2024 10:46:11 +0900 Subject: [PATCH 1/3] =?UTF-8?q?wanto-to-do=E3=81=AEAI=E5=88=86=E5=89=B2?= =?UTF-8?q?=E6=A9=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- task_yell/package-lock.json | 155 +++++++++++++++++++++++++++++++-- task_yell/package.json | 4 +- task_yell/src/app/api/route.ts | 10 +++ task_yell/src/lib/ai.ts | 47 ++++++++++ 4 files changed, 206 insertions(+), 10 deletions(-) create mode 100644 task_yell/src/app/api/route.ts create mode 100644 task_yell/src/lib/ai.ts diff --git a/task_yell/package-lock.json b/task_yell/package-lock.json index d586b61..d1bcc97 100644 --- a/task_yell/package-lock.json +++ b/task_yell/package-lock.json @@ -26,12 +26,14 @@ "googleapis": "^144.0.0", "lucide-react": "^0.453.0", "next": "14.2.15", + "openai": "^4.68.4", "react": "^18", "react-day-picker": "^8.10.1", "react-dom": "^18", "recharts": "^2.13.0", "tailwind-merge": "^2.5.4", - "tailwindcss-animate": "^1.0.7" + "tailwindcss-animate": "^1.0.7", + "zod": "^3.23.8" }, "devDependencies": { "@types/node": "^20", @@ -2302,6 +2304,30 @@ "undici-types": "~6.19.2" } }, + "node_modules/@types/node-fetch": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz", + "integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.0" + } + }, + "node_modules/@types/node-fetch/node_modules/form-data": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/@types/prop-types": { "version": "15.7.13", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", @@ -2611,7 +2637,6 @@ "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", "license": "MIT", - "optional": true, "dependencies": { "event-target-shim": "^5.0.0" }, @@ -2654,6 +2679,18 @@ "node": ">= 14" } }, + "node_modules/agentkeepalive": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", + "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", + "license": "MIT", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -2953,8 +2990,7 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/available-typed-arrays": { "version": "1.0.7", @@ -3387,7 +3423,6 @@ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "license": "MIT", - "optional": true, "dependencies": { "delayed-stream": "~1.0.0" }, @@ -3705,7 +3740,6 @@ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "license": "MIT", - "optional": true, "engines": { "node": ">=0.4.0" } @@ -4474,7 +4508,6 @@ "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", "license": "MIT", - "optional": true, "engines": { "node": ">=6" } @@ -4879,6 +4912,25 @@ "node": ">= 0.12" } }, + "node_modules/form-data-encoder": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", + "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==", + "license": "MIT" + }, + "node_modules/formdata-node": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", + "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", + "license": "MIT", + "dependencies": { + "node-domexception": "1.0.0", + "web-streams-polyfill": "4.0.0-beta.3" + }, + "engines": { + "node": ">= 12.20" + } + }, "node_modules/framer-motion": { "version": "11.11.10", "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.11.10.tgz", @@ -5502,6 +5554,15 @@ "node": ">=16.17.0" } }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.0.0" + } + }, "node_modules/husky": { "version": "9.1.6", "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.6.tgz", @@ -6796,7 +6857,6 @@ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "license": "MIT", - "optional": true, "engines": { "node": ">= 0.6" } @@ -6806,7 +6866,6 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "license": "MIT", - "optional": true, "dependencies": { "mime-db": "1.52.0" }, @@ -6990,6 +7049,25 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, "node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", @@ -7206,6 +7284,47 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/openai": { + "version": "4.68.4", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.68.4.tgz", + "integrity": "sha512-LRinV8iU9VQplkr25oZlyrsYGPGasIwYN8KFMAAFTHHLHjHhejtJ5BALuLFrkGzY4wfbKhOhuT+7lcHZ+F3iEA==", + "license": "Apache-2.0", + "dependencies": { + "@types/node": "^18.11.18", + "@types/node-fetch": "^2.6.4", + "abort-controller": "^3.0.0", + "agentkeepalive": "^4.2.1", + "form-data-encoder": "1.7.2", + "formdata-node": "^4.3.2", + "node-fetch": "^2.6.7" + }, + "bin": { + "openai": "bin/cli" + }, + "peerDependencies": { + "zod": "^3.23.8" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, + "node_modules/openai/node_modules/@types/node": { + "version": "18.19.59", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.59.tgz", + "integrity": "sha512-vizm2EqwV/7Zay+A6J3tGl9Lhr7CjZe2HmWS988sefiEmsyP9CeXEleho6i4hJk/8UtZAo0bWN4QPZZr83RxvQ==", + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/openai/node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "license": "MIT" + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -9126,6 +9245,15 @@ "d3-timer": "^3.0.1" } }, + "node_modules/web-streams-polyfill": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", + "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", @@ -9460,6 +9588,15 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zod": { + "version": "3.23.8", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } } } } diff --git a/task_yell/package.json b/task_yell/package.json index e39b471..9ee8263 100644 --- a/task_yell/package.json +++ b/task_yell/package.json @@ -38,12 +38,14 @@ "googleapis": "^144.0.0", "lucide-react": "^0.453.0", "next": "14.2.15", + "openai": "^4.68.4", "react": "^18", "react-day-picker": "^8.10.1", "react-dom": "^18", "recharts": "^2.13.0", "tailwind-merge": "^2.5.4", - "tailwindcss-animate": "^1.0.7" + "tailwindcss-animate": "^1.0.7", + "zod": "^3.23.8" }, "devDependencies": { "@types/node": "^20", diff --git a/task_yell/src/app/api/route.ts b/task_yell/src/app/api/route.ts new file mode 100644 index 0000000..0682e2e --- /dev/null +++ b/task_yell/src/app/api/route.ts @@ -0,0 +1,10 @@ +// import { splitWantToDo } from "@/lib/ai"; +// import { NextRequest, NextResponse } from "next/server"; + +// export async function GET(req: NextRequest) { +// const res = await splitWantToDo({ +// title: "キーボードを買う" +// }); + +// return NextResponse.json(res); +// } \ No newline at end of file diff --git a/task_yell/src/lib/ai.ts b/task_yell/src/lib/ai.ts new file mode 100644 index 0000000..e062edd --- /dev/null +++ b/task_yell/src/lib/ai.ts @@ -0,0 +1,47 @@ +import OpenAI from 'openai'; +import { WantTodo } from './types'; +import { z } from "zod"; +import { zodResponseFormat } from "openai/helpers/zod"; + +const client = new OpenAI({ + apiKey: process.env.OPENAI_API_KEY +}); + +const TasksScheme = z.object({ + tasks: z.array(z.object({ + content: z.string() + })) +}); + +const prompt = ` +ユーザーがやりたいことを送信するのでそれを実現するためにタスクに分割してください。 +出力は元の言語である日本語で出力してください。 +`; + +export async function splitWantToDo(wantTodo: WantTodo): Promise { + try { + const result = await client.chat.completions.create({ + model: 'gpt-4o', + messages: [ + { role: 'system', content: prompt }, + { + role: 'user', content: ` + { + "content": "${wantTodo.title}" + } + ` + } + ], + response_format: zodResponseFormat(TasksScheme, 'tasks') + }); + + console.log(result.choices[0].message.content); + const content = result.choices[0].message.content; + if (content) { + return JSON.parse(content).tasks.map((item: { content: string }) => ({ title: item.content })); + } + } catch (e: unknown) { + console.error(e); + } + return null; +} \ No newline at end of file From 1eb936e6bd3d315b496b911ec37a64c9e64f6469 Mon Sep 17 00:00:00 2001 From: Yuto Terada Date: Sun, 27 Oct 2024 10:46:52 +0900 Subject: [PATCH 2/3] format --- task_yell/src/app/api/route.ts | 2 +- task_yell/src/lib/ai.ts | 37 ++++++++++++++++++++-------------- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/task_yell/src/app/api/route.ts b/task_yell/src/app/api/route.ts index 0682e2e..dead9b6 100644 --- a/task_yell/src/app/api/route.ts +++ b/task_yell/src/app/api/route.ts @@ -7,4 +7,4 @@ // }); // return NextResponse.json(res); -// } \ No newline at end of file +// } diff --git a/task_yell/src/lib/ai.ts b/task_yell/src/lib/ai.ts index e062edd..c777077 100644 --- a/task_yell/src/lib/ai.ts +++ b/task_yell/src/lib/ai.ts @@ -1,16 +1,18 @@ -import OpenAI from 'openai'; -import { WantTodo } from './types'; +import OpenAI from "openai"; +import { WantTodo } from "./types"; import { z } from "zod"; import { zodResponseFormat } from "openai/helpers/zod"; const client = new OpenAI({ - apiKey: process.env.OPENAI_API_KEY + apiKey: process.env.OPENAI_API_KEY, }); const TasksScheme = z.object({ - tasks: z.array(z.object({ - content: z.string() - })) + tasks: z.array( + z.object({ + content: z.string(), + }), + ), }); const prompt = ` @@ -18,30 +20,35 @@ const prompt = ` 出力は元の言語である日本語で出力してください。 `; -export async function splitWantToDo(wantTodo: WantTodo): Promise { +export async function splitWantToDo( + wantTodo: WantTodo, +): Promise { try { const result = await client.chat.completions.create({ - model: 'gpt-4o', + model: "gpt-4o", messages: [ - { role: 'system', content: prompt }, + { role: "system", content: prompt }, { - role: 'user', content: ` + role: "user", + content: ` { "content": "${wantTodo.title}" } - ` - } + `, + }, ], - response_format: zodResponseFormat(TasksScheme, 'tasks') + response_format: zodResponseFormat(TasksScheme, "tasks"), }); console.log(result.choices[0].message.content); const content = result.choices[0].message.content; if (content) { - return JSON.parse(content).tasks.map((item: { content: string }) => ({ title: item.content })); + return JSON.parse(content).tasks.map((item: { content: string }) => ({ + title: item.content, + })); } } catch (e: unknown) { console.error(e); } return null; -} \ No newline at end of file +} From 6dd9555d9476d9bb0f872e8788ab8cc694534778 Mon Sep 17 00:00:00 2001 From: Yuto Terada Date: Sun, 27 Oct 2024 11:40:48 +0900 Subject: [PATCH 3/3] delete route.ts --- task_yell/src/app/api/route.ts | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 task_yell/src/app/api/route.ts diff --git a/task_yell/src/app/api/route.ts b/task_yell/src/app/api/route.ts deleted file mode 100644 index dead9b6..0000000 --- a/task_yell/src/app/api/route.ts +++ /dev/null @@ -1,10 +0,0 @@ -// import { splitWantToDo } from "@/lib/ai"; -// import { NextRequest, NextResponse } from "next/server"; - -// export async function GET(req: NextRequest) { -// const res = await splitWantToDo({ -// title: "キーボードを買う" -// }); - -// return NextResponse.json(res); -// }