From 966491c6da66d3059a38dfdaf96920eaa802c5e5 Mon Sep 17 00:00:00 2001 From: sakuyacatcat Date: Sat, 23 Mar 2024 23:21:30 +0900 Subject: [PATCH 1/5] wip: generate button backend --- app/api/frames/createStamp/route.tsx | 27 +++++++++++++++++++++++++++ app/page.tsx | 6 +++++- 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 app/api/frames/createStamp/route.tsx diff --git a/app/api/frames/createStamp/route.tsx b/app/api/frames/createStamp/route.tsx new file mode 100644 index 0000000..29f3a78 --- /dev/null +++ b/app/api/frames/createStamp/route.tsx @@ -0,0 +1,27 @@ +import { Button, createFrames } from 'frames.js/next'; + +const frames = createFrames({ + basePath: '/api/frames/createStamp', +}); + +const handleRequest = frames(async (ctx) => { + console.log(ctx); + + return { + image: ( +
+
hogehoge
+
+ ), + imageOptions: { + aspectRatio: '1:1', + }, + buttons: [ + , + ], + }; +}); + +export const POST = handleRequest; diff --git a/app/page.tsx b/app/page.tsx index 5acd83f..74b0f08 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -80,7 +80,11 @@ export default async function Home({ searchParams }: NextServerPageProps) { - {!state.generated ? generate : null} + {!state.generated ? ( + + generate + + ) : null} {state.generated ? initialize : null} {state.generated ? Mint : null} {state.generated ? Share : null} From b59a0b13b1e5d9ca7d22ce5a5e06fd7bed315b4d Mon Sep 17 00:00:00 2001 From: sakuyacatcat Date: Sun, 24 Mar 2024 00:23:50 +0900 Subject: [PATCH 2/5] wip --- app/api/frames/createStamp/route.tsx | 9 +- app/repository/stampRepository.ts | 19 ++++ app/service/stampService.ts | 12 +++ package.json | 7 +- yarn.lock | 134 ++++++++++++++++++++++++++- 5 files changed, 169 insertions(+), 12 deletions(-) create mode 100644 app/repository/stampRepository.ts create mode 100644 app/service/stampService.ts diff --git a/app/api/frames/createStamp/route.tsx b/app/api/frames/createStamp/route.tsx index 29f3a78..a664641 100644 --- a/app/api/frames/createStamp/route.tsx +++ b/app/api/frames/createStamp/route.tsx @@ -1,18 +1,15 @@ import { Button, createFrames } from 'frames.js/next'; +import { generateImageUrl } from '../../../service/stampService'; const frames = createFrames({ basePath: '/api/frames/createStamp', }); const handleRequest = frames(async (ctx) => { - console.log(ctx); + const image_url = await generateImageUrl(ctx.message?.inputText); return { - image: ( -
-
hogehoge
-
- ), + image: image_url, imageOptions: { aspectRatio: '1:1', }, diff --git a/app/repository/stampRepository.ts b/app/repository/stampRepository.ts new file mode 100644 index 0000000..b795090 --- /dev/null +++ b/app/repository/stampRepository.ts @@ -0,0 +1,19 @@ +import OpenAI from 'openai'; + +const openai = new OpenAI(); + +export async function generateImage(prompt: string) { + try { + const imageResponse = await openai.images.generate({ + model: 'dall-e-3', + prompt: prompt, + n: 1, + size: '1024x1024', + }); + const imageUrl = imageResponse.data[0]?.url || ''; + return imageUrl; + } catch (error) { + console.error('Error generating image:', error); + throw error; + } +} diff --git a/app/service/stampService.ts b/app/service/stampService.ts new file mode 100644 index 0000000..884584a --- /dev/null +++ b/app/service/stampService.ts @@ -0,0 +1,12 @@ +import { generateImage } from '../repository/stampRepository'; + +export async function generateImageUrl(input: string): Promise { + const template = + 'スタイルはキティちゃんのようにシンプルで愛らしいキャラクターのLINEスタンプを生成してください。ポーズはセリフに合わせて適切に変化させてください。セリフ:'; + + const prompt = template + input; + + const imageUrl = await generateImage(prompt); + + return imageUrl; +} diff --git a/package.json b/package.json index 00fc0c2..c5c2cd4 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "frames.js": "^0.9.3", "lucide-react": "^0.331.0", "next": "^14.1.0", + "openai": "^4.29.2", "react": "^18.2.0", "react-dom": "^18.2.0", "tailwindcss-animate": "^1.0.7" @@ -57,12 +58,12 @@ "rimraf": "^5.0.5", "tailwindcss": "^3.3.0", "textlint": "^14.0.4", - "ts-jest": "^29.1.2", - "typescript": "^5.3.3", "textlint-rule-no-mixed-zenkaku-and-hankaku-alphabet": "^1.0.1", "textlint-rule-no-mixed-zenkaku-and-hankaku-number": "^1.0.0", "textlint-rule-preset-ja-spacing": "^2.2.0", "textlint-rule-preset-ja-technical-writing": "^10.0.1", - "textlint-rule-spellcheck-tech-word": "^5.0.0" + "textlint-rule-spellcheck-tech-word": "^5.0.0", + "ts-jest": "^29.1.2", + "typescript": "^5.3.3" } } diff --git a/yarn.lock b/yarn.lock index 9102cd4..6b26872 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2387,6 +2387,14 @@ resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.34.tgz#10964ba0dee6ac4cd462e2795b6bebd407303433" integrity sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g== +"@types/node-fetch@^2.6.4": + version "2.6.11" + resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.11.tgz#9b39b78665dae0e82a08f02f4967d62c66f95d24" + integrity sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g== + dependencies: + "@types/node" "*" + form-data "^4.0.0" + "@types/node@*", "@types/node@>=13.7.0", "@types/node@^20.11.30": version "20.11.30" resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.30.tgz#9c33467fc23167a347e73834f788f4b9f399d66f" @@ -2394,7 +2402,7 @@ dependencies: undici-types "~5.26.4" -"@types/node@^18.17.0": +"@types/node@^18.11.18", "@types/node@^18.17.0": version "18.19.26" resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.26.tgz#18991279d0a0e53675285e8cf4a0823766349729" integrity sha512-+wiMJsIwLOYCvUqSdKTrfkS8mpTp+MPINe6+Np4TAGFWWRWiBQ5kSq9nZGCSPkzx9mvT+uEukzpX4MOSCydcvw== @@ -2887,6 +2895,13 @@ abitype@1.0.0: resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.0.0.tgz#237176dace81d90d018bebf3a45cb42f2a2d9e97" integrity sha512-NMeMah//6bJ56H5XRj8QCV4AwuW6hB6zqz2LnhhLdcWVQOsXki6/Pn3APeqxCma62nXIcmZWdu1DlHWS74umVQ== +abort-controller@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" + integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== + dependencies: + event-target-shim "^5.0.0" + acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" @@ -2897,6 +2912,13 @@ acorn@^8.11.3, acorn@^8.9.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== +agentkeepalive@^4.2.1: + version "4.5.0" + resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.5.0.tgz#2673ad1389b3c418c5a20c5d7364f93ca04be923" + integrity sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew== + dependencies: + humanize-ms "^1.2.1" + ajv@^6.12.4: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" @@ -3147,6 +3169,11 @@ async@^2.0.1: dependencies: lodash "^4.17.14" +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + atomic-sleep@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b" @@ -3262,6 +3289,11 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +base-64@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/base-64/-/base-64-0.1.0.tgz#780a99c84e7d600260361511c4877613bf24f6bb" + integrity sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA== + base-x@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/base-x/-/base-x-4.0.0.tgz#d0e3b7753450c73f8ad2389b5c018a4af7b2224a" @@ -3659,6 +3691,13 @@ color-name@^1.1.4, color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + comma-separated-tokens@^1.0.0: version "1.0.8" resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz#632b80b6117867a158f1080ad498b2fbe7e3f5ea" @@ -3973,6 +4012,11 @@ defu@^6.1.3, defu@^6.1.4: resolved "https://registry.yarnpkg.com/defu/-/defu-6.1.4.tgz#4e0c9cf9ff68fe5f3d7f2765cc1a012dfdcb0479" integrity sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg== +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + dequal@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" @@ -4023,6 +4067,14 @@ diff@^5.2.0: resolved "https://registry.yarnpkg.com/diff/-/diff-5.2.0.tgz#26ded047cd1179b78b9537d5ef725503ce1ae531" integrity sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A== +digest-fetch@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/digest-fetch/-/digest-fetch-1.3.0.tgz#898e69264d00012a23cf26e8a3e40320143fc661" + integrity sha512-CGJuv6iKNM7QyZlM2T3sPAdZWd/p9zQiRNS9G+9COUCwzWFTs0Xp8NF5iePx7wtvhDykReiRRrSeNb4oMmB8lA== + dependencies: + base-64 "^0.1.0" + md5 "^2.3.0" + dijkstrajs@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/dijkstrajs/-/dijkstrajs-1.0.3.tgz#4c8dbdea1f0f6478bff94d9c49c784d623e4fc23" @@ -4605,6 +4657,11 @@ ethereum-cryptography@^2.0.0: "@scure/bip32" "1.3.3" "@scure/bip39" "1.2.2" +event-target-shim@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" + integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== + eventemitter2@^6.4.5, eventemitter2@^6.4.7: version "6.4.9" resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-6.4.9.tgz#41f2750781b4230ed58827bc119d293471ecb125" @@ -4869,11 +4926,33 @@ foreground-child@^3.1.0: cross-spawn "^7.0.0" signal-exit "^4.0.1" +form-data-encoder@1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/form-data-encoder/-/form-data-encoder-1.7.2.tgz#1f1ae3dccf58ed4690b86d87e4f57c654fbab040" + integrity sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A== + +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + format@^0.2.0: version "0.2.2" resolved "https://registry.yarnpkg.com/format/-/format-0.2.2.tgz#d6170107e9efdc4ed30c9dc39016df942b5cb58b" integrity sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww== +formdata-node@^4.3.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/formdata-node/-/formdata-node-4.4.1.tgz#23f6a5cb9cb55315912cbec4ff7b0f59bbd191e2" + integrity sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ== + dependencies: + node-domexception "1.0.0" + web-streams-polyfill "4.0.0-beta.3" + fraction.js@^4.3.7: version "4.3.7" resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.3.7.tgz#06ca0085157e42fda7f9e726e79fefc4068840f7" @@ -5241,6 +5320,13 @@ human-signals@^5.0.0: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-5.0.0.tgz#42665a284f9ae0dade3ba41ebc37eb4b852f3a28" integrity sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ== +humanize-ms@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" + integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ== + dependencies: + ms "^2.0.0" + husky@^9.0.11: version "9.0.11" resolved "https://registry.yarnpkg.com/husky/-/husky-9.0.11.tgz#fc91df4c756050de41b3e478b2158b87c1e79af9" @@ -6769,6 +6855,18 @@ micromatch@^4.0.4, micromatch@^4.0.5: braces "^3.0.2" picomatch "^2.3.1" +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + mime@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/mime/-/mime-3.0.0.tgz#b374550dca3a0c18443b0c950a6a58f1931cf7a7" @@ -6896,7 +6994,7 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@^2.1.1: +ms@^2.0.0, ms@^2.1.1: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -6973,12 +7071,17 @@ node-addon-api@^7.0.0: resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-7.1.0.tgz#71f609369379c08e251c558527a107107b5e0fdb" integrity sha512-mNcltoe1R8o7STTegSOHdnJNN7s5EUvhoS7ShnTHDyOSd+8H+UdWODq6qSv67PjC8Zc5JRT8+oLAMCr0SIXw7g== +node-domexception@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" + integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== + node-fetch-native@^1.6.1, node-fetch-native@^1.6.2, node-fetch-native@^1.6.3: version "1.6.4" resolved "https://registry.yarnpkg.com/node-fetch-native/-/node-fetch-native-1.6.4.tgz#679fc8fd8111266d47d7e72c379f1bed9acff06e" integrity sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ== -node-fetch@^2.6.1, node-fetch@^2.6.12: +node-fetch@^2.6.1, node-fetch@^2.6.12, node-fetch@^2.6.7: version "2.7.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== @@ -7195,6 +7298,21 @@ open@^8.4.0: is-docker "^2.1.1" is-wsl "^2.2.0" +openai@^4.29.2: + version "4.29.2" + resolved "https://registry.yarnpkg.com/openai/-/openai-4.29.2.tgz#45e83cb49dbd052626637b267c749785a24f411c" + integrity sha512-cPkT6zjEcE4qU5OW/SoDDuXEsdOLrXlAORhzmaguj5xZSPlgKvLhi27sFWhLKj07Y6WKNWxcwIbzm512FzTBNQ== + dependencies: + "@types/node" "^18.11.18" + "@types/node-fetch" "^2.6.4" + abort-controller "^3.0.0" + agentkeepalive "^4.2.1" + digest-fetch "^1.3.0" + form-data-encoder "1.7.2" + formdata-node "^4.3.2" + node-fetch "^2.6.7" + web-streams-polyfill "^3.2.1" + optionator@^0.9.3: version "0.9.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" @@ -9684,6 +9802,16 @@ web-namespaces@^1.1.2: resolved "https://registry.yarnpkg.com/web-namespaces/-/web-namespaces-1.1.4.tgz#bc98a3de60dadd7faefc403d1076d529f5e030ec" integrity sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw== +web-streams-polyfill@4.0.0-beta.3: + version "4.0.0-beta.3" + resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz#2898486b74f5156095e473efe989dcf185047a38" + integrity sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug== + +web-streams-polyfill@^3.2.1: + version "3.3.3" + resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz#2073b91a2fdb1fbfbd401e7de0ac9f8214cecb4b" + integrity sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw== + webextension-polyfill-ts@^0.25.0: version "0.25.0" resolved "https://registry.yarnpkg.com/webextension-polyfill-ts/-/webextension-polyfill-ts-0.25.0.tgz#fff041626365dbd0e29c40b197e989a55ec221ca" From 3d157f3b85dbb98d0bf9d6bd09d366100115c046 Mon Sep 17 00:00:00 2001 From: sakuyacatcat Date: Sun, 24 Mar 2024 00:36:42 +0900 Subject: [PATCH 3/5] refactor generate button backend --- Makefile | 4 +++ app/api/frames/createStamp/route.tsx | 7 ++-- app/repository/stampRepository.ts | 30 ++++++++-------- app/service/stampService.ts | 23 +++++++----- tests/stampRepository.test.ts_tmp | 54 ++++++++++++++++++++++++++++ tests/stampService.test.ts_tmp | 0 6 files changed, 94 insertions(+), 24 deletions(-) create mode 100644 tests/stampRepository.test.ts_tmp create mode 100644 tests/stampService.test.ts_tmp diff --git a/Makefile b/Makefile index 6e50c07..1ce5539 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,10 @@ clean: test: yarn test +.PHONY: test_watch +test_watch: + yarn test:watch + .PHONY: test_coverage test_coverage: yarn test:coverage diff --git a/app/api/frames/createStamp/route.tsx b/app/api/frames/createStamp/route.tsx index a664641..e2b6988 100644 --- a/app/api/frames/createStamp/route.tsx +++ b/app/api/frames/createStamp/route.tsx @@ -1,12 +1,15 @@ import { Button, createFrames } from 'frames.js/next'; -import { generateImageUrl } from '../../../service/stampService'; +import { StampService } from '../../../service/stampService'; const frames = createFrames({ basePath: '/api/frames/createStamp', }); const handleRequest = frames(async (ctx) => { - const image_url = await generateImageUrl(ctx.message?.inputText); + const template = + 'スタイルはキティちゃんのようにシンプルで愛らしいキャラクターのLINEスタンプを生成してください。ポーズはセリフに合わせて適切に変化させてください。セリフ:'; + const service = new StampService(template); + const image_url = await service.generateImageUrl(ctx.message?.inputText); return { image: image_url, diff --git a/app/repository/stampRepository.ts b/app/repository/stampRepository.ts index b795090..d4d1edf 100644 --- a/app/repository/stampRepository.ts +++ b/app/repository/stampRepository.ts @@ -1,19 +1,21 @@ import OpenAI from 'openai'; -const openai = new OpenAI(); +export class StampRepository { + constructor(private openai = new OpenAI()) {} -export async function generateImage(prompt: string) { - try { - const imageResponse = await openai.images.generate({ - model: 'dall-e-3', - prompt: prompt, - n: 1, - size: '1024x1024', - }); - const imageUrl = imageResponse.data[0]?.url || ''; - return imageUrl; - } catch (error) { - console.error('Error generating image:', error); - throw error; + async generateImage(prompt: string): Promise { + try { + const imageResponse = await this.openai.images.generate({ + model: 'dall-e-3', + prompt: prompt, + n: 1, + size: '1024x1024', + }); + const imageUrl = imageResponse.data[0]?.url || ''; + return imageUrl; + } catch (error) { + console.error('Error generating image:', error); + throw new Error('Image generation failed'); + } } } diff --git a/app/service/stampService.ts b/app/service/stampService.ts index 884584a..d98cfb1 100644 --- a/app/service/stampService.ts +++ b/app/service/stampService.ts @@ -1,12 +1,19 @@ -import { generateImage } from '../repository/stampRepository'; +// stampService.js +import { StampRepository } from '../repository/stampRepository'; -export async function generateImageUrl(input: string): Promise { - const template = - 'スタイルはキティちゃんのようにシンプルで愛らしいキャラクターのLINEスタンプを生成してください。ポーズはセリフに合わせて適切に変化させてください。セリフ:'; +export class StampService { + private template: string; - const prompt = template + input; + constructor( + template: string, + private stampRepository: StampRepository = new StampRepository() + ) { + this.template = template; + } - const imageUrl = await generateImage(prompt); - - return imageUrl; + async generateImageUrl(input: string): Promise { + const prompt = this.template + input; + const imageUrl = await this.stampRepository.generateImage(prompt); + return imageUrl; + } } diff --git a/tests/stampRepository.test.ts_tmp b/tests/stampRepository.test.ts_tmp new file mode 100644 index 0000000..92fd122 --- /dev/null +++ b/tests/stampRepository.test.ts_tmp @@ -0,0 +1,54 @@ +// import OpenAI from 'openai'; +// import { StampRepository } from '../app/repository/stampRepository'; + +// jest.mock('openai', () => { +// return { +// OpenAI: jest.fn().mockImplementation(() => { +// return { +// images: { +// generate: jest.fn().mockResolvedValue({ +// data: [ +// { +// url: 'mockImageUrl', +// }, +// ], +// }), +// }, +// }; +// }), +// }; +// }); + +// describe('StampRepository', () => { +// let stampRepository: StampRepository; + +// beforeEach(() => { +// stampRepository = new StampRepository(); +// }); + +// it('should return an image URL when generateImage is called', async () => { +// const prompt = 'test prompt'; +// const imageUrl = await stampRepository.generateImage(prompt); + +// // 正しい画像URLが返されることを確認 +// expect(imageUrl).toBe('mockImageUrl'); +// // OpenAI.images.generateが適切な引数で呼び出されたことを確認 +// expect(OpenAI.prototype.images.generate).toHaveBeenCalledWith({ +// model: 'dall-e-3', +// prompt: prompt, +// n: 1, +// size: '1024x1024', +// }); +// }); + +// it('should throw an error if the OpenAI API call fails', async () => { +// // OpenAI.images.generate メソッドを失敗させるようにモックを設定 +// OpenAI.prototype.images.generate.mockRejectedValue( +// new Error('API call failed') +// ); + +// await expect(stampRepository.generateImage('test prompt')).rejects.toThrow( +// 'Image generation failed' +// ); +// }); +// }); diff --git a/tests/stampService.test.ts_tmp b/tests/stampService.test.ts_tmp new file mode 100644 index 0000000..e69de29 From fbb45bdef81caa053bb23e48fdc65fec8f6a96d1 Mon Sep 17 00:00:00 2001 From: sakuyacatcat Date: Sun, 24 Mar 2024 00:37:34 +0900 Subject: [PATCH 4/5] refactor --- app/repository/stampRepository.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/app/repository/stampRepository.ts b/app/repository/stampRepository.ts index d4d1edf..45e0257 100644 --- a/app/repository/stampRepository.ts +++ b/app/repository/stampRepository.ts @@ -12,6 +12,7 @@ export class StampRepository { size: '1024x1024', }); const imageUrl = imageResponse.data[0]?.url || ''; + return imageUrl; } catch (error) { console.error('Error generating image:', error); From 6539aab19ac1b00ba14235d907ce0b7a548b1087 Mon Sep 17 00:00:00 2001 From: sakuyacatcat Date: Sun, 24 Mar 2024 00:48:42 +0900 Subject: [PATCH 5/5] add key property to generate button --- .husky/pre-commit | 4 ++++ app/api/frames/createStamp/route.tsx | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100755 .husky/pre-commit diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000..ce85141 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + +make before_commit diff --git a/app/api/frames/createStamp/route.tsx b/app/api/frames/createStamp/route.tsx index e2b6988..d383a46 100644 --- a/app/api/frames/createStamp/route.tsx +++ b/app/api/frames/createStamp/route.tsx @@ -17,7 +17,7 @@ const handleRequest = frames(async (ctx) => { aspectRatio: '1:1', }, buttons: [ - , ],