├── .gitignore ├── README.md ├── next.config.js ├── package-lock.json ├── package.json ├── public ├── favicon.ico ├── next.svg └── vercel.svg ├── src ├── pages │ ├── _app.tsx │ ├── _document.tsx │ ├── api │ │ ├── hello.ts │ │ └── telegram-webhook.ts │ └── index.tsx ├── services │ └── telegram.service.ts ├── styles │ └── globals.css └── utils │ ├── replicate.utils.ts │ └── translate.utils.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env*.local 29 | 30 | # vercel 31 | .vercel 32 | 33 | # typescript 34 | *.tsbuildinfo 35 | next-env.d.ts 36 | 37 | .idea 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MidJourney Bot with NextJs 2 | Author: [@monokaijs](https://monokaijs.com) 3 | 4 | [![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fmonokaijs%2Fmidjourney-telegram-bot) 5 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | } 5 | 6 | module.exports = nextConfig 7 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "midjourney-telegram-bot", 3 | "version": "0.1.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "midjourney-telegram-bot", 9 | "version": "0.1.0", 10 | "dependencies": { 11 | "@types/node": "18.15.11", 12 | "@types/react": "18.0.33", 13 | "@types/react-dom": "18.0.11", 14 | "next": "13.3.0", 15 | "react": "18.2.0", 16 | "react-dom": "18.2.0", 17 | "typescript": "5.0.3" 18 | } 19 | }, 20 | "node_modules/@next/env": { 21 | "version": "13.3.0", 22 | "resolved": "https://registry.npmjs.org/@next/env/-/env-13.3.0.tgz", 23 | "integrity": "sha512-AjppRV4uG3No7L1plinoTQETH+j2F10TEnrMfzbTUYwze5sBUPveeeBAPZPm8OkJZ1epq9OyYKhZrvbD6/9HCQ==" 24 | }, 25 | "node_modules/@next/swc-darwin-arm64": { 26 | "version": "13.3.0", 27 | "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.3.0.tgz", 28 | "integrity": "sha512-DmIQCNq6JtccLPPBzf0dgh2vzMWt5wjxbP71pCi5EWpWYE3MsP6FcRXi4MlAmFNDQOfcFXR2r7kBeG1LpZUh1w==", 29 | "cpu": [ 30 | "arm64" 31 | ], 32 | "optional": true, 33 | "os": [ 34 | "darwin" 35 | ], 36 | "engines": { 37 | "node": ">= 10" 38 | } 39 | }, 40 | "node_modules/@next/swc-darwin-x64": { 41 | "version": "13.3.0", 42 | "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.3.0.tgz", 43 | "integrity": "sha512-oQoqFa88OGgwnYlnAGHVct618FRI/749se0N3S8t9Bzdv5CRbscnO0RcX901+YnNK4Q6yeiizfgO3b7kogtsZg==", 44 | "cpu": [ 45 | "x64" 46 | ], 47 | "optional": true, 48 | "os": [ 49 | "darwin" 50 | ], 51 | "engines": { 52 | "node": ">= 10" 53 | } 54 | }, 55 | "node_modules/@next/swc-linux-arm64-gnu": { 56 | "version": "13.3.0", 57 | "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.3.0.tgz", 58 | "integrity": "sha512-Wzz2p/WqAJUqTVoLo6H18WMeAXo3i+9DkPDae4oQG8LMloJ3if4NEZTnOnTUlro6cq+S/W4pTGa97nWTrOjbGw==", 59 | "cpu": [ 60 | "arm64" 61 | ], 62 | "optional": true, 63 | "os": [ 64 | "linux" 65 | ], 66 | "engines": { 67 | "node": ">= 10" 68 | } 69 | }, 70 | "node_modules/@next/swc-linux-arm64-musl": { 71 | "version": "13.3.0", 72 | "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.3.0.tgz", 73 | "integrity": "sha512-xPVrIQOQo9WXJYgmoTlMnAD/HlR/1e1ZIWGbwIzEirXBVBqMARUulBEIKdC19zuvoJ477qZJgBDCKtKEykCpyQ==", 74 | "cpu": [ 75 | "arm64" 76 | ], 77 | "optional": true, 78 | "os": [ 79 | "linux" 80 | ], 81 | "engines": { 82 | "node": ">= 10" 83 | } 84 | }, 85 | "node_modules/@next/swc-linux-x64-gnu": { 86 | "version": "13.3.0", 87 | "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.3.0.tgz", 88 | "integrity": "sha512-jOFlpGuPD7W2tuXVJP4wt9a3cpNxWAPcloq5EfMJRiXsBBOjLVFZA7boXYxEBzSVgUiVVr1V9T0HFM7pULJ1qA==", 89 | "cpu": [ 90 | "x64" 91 | ], 92 | "optional": true, 93 | "os": [ 94 | "linux" 95 | ], 96 | "engines": { 97 | "node": ">= 10" 98 | } 99 | }, 100 | "node_modules/@next/swc-linux-x64-musl": { 101 | "version": "13.3.0", 102 | "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.3.0.tgz", 103 | "integrity": "sha512-2OwKlzaBgmuet9XYHc3KwsEilzb04F540rlRXkAcjMHL7eCxB7uZIGtsVvKOnQLvC/elrUegwSw1+5f7WmfyOw==", 104 | "cpu": [ 105 | "x64" 106 | ], 107 | "optional": true, 108 | "os": [ 109 | "linux" 110 | ], 111 | "engines": { 112 | "node": ">= 10" 113 | } 114 | }, 115 | "node_modules/@next/swc-win32-arm64-msvc": { 116 | "version": "13.3.0", 117 | "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.3.0.tgz", 118 | "integrity": "sha512-OeHiA6YEvndxT46g+rzFK/MQTfftKxJmzslERMu9LDdC6Kez0bdrgEYed5eXFK2Z1viKZJCGRlhd06rBusyztA==", 119 | "cpu": [ 120 | "arm64" 121 | ], 122 | "optional": true, 123 | "os": [ 124 | "win32" 125 | ], 126 | "engines": { 127 | "node": ">= 10" 128 | } 129 | }, 130 | "node_modules/@next/swc-win32-ia32-msvc": { 131 | "version": "13.3.0", 132 | "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.3.0.tgz", 133 | "integrity": "sha512-4aB7K9mcVK1lYEzpOpqWrXHEZympU3oK65fnNcY1Qc4HLJFLJj8AViuqQd4jjjPNuV4sl8jAwTz3gN5VNGWB7w==", 134 | "cpu": [ 135 | "ia32" 136 | ], 137 | "optional": true, 138 | "os": [ 139 | "win32" 140 | ], 141 | "engines": { 142 | "node": ">= 10" 143 | } 144 | }, 145 | "node_modules/@next/swc-win32-x64-msvc": { 146 | "version": "13.3.0", 147 | "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.3.0.tgz", 148 | "integrity": "sha512-Reer6rkLLcoOvB0dd66+Y7WrWVFH7sEEkF/4bJCIfsSKnTStTYaHtwIJAwbqnt9I392Tqvku0KkoqZOryWV9LQ==", 149 | "cpu": [ 150 | "x64" 151 | ], 152 | "optional": true, 153 | "os": [ 154 | "win32" 155 | ], 156 | "engines": { 157 | "node": ">= 10" 158 | } 159 | }, 160 | "node_modules/@swc/helpers": { 161 | "version": "0.4.14", 162 | "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.14.tgz", 163 | "integrity": "sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==", 164 | "dependencies": { 165 | "tslib": "^2.4.0" 166 | } 167 | }, 168 | "node_modules/@types/node": { 169 | "version": "18.15.11", 170 | "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz", 171 | "integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==" 172 | }, 173 | "node_modules/@types/prop-types": { 174 | "version": "15.7.5", 175 | "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", 176 | "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" 177 | }, 178 | "node_modules/@types/react": { 179 | "version": "18.0.33", 180 | "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.33.tgz", 181 | "integrity": "sha512-sHxzVxeanvQyQ1lr8NSHaj0kDzcNiGpILEVt69g9S31/7PfMvNCKLKcsHw4lYKjs3cGNJjXSP4mYzX43QlnjNA==", 182 | "dependencies": { 183 | "@types/prop-types": "*", 184 | "@types/scheduler": "*", 185 | "csstype": "^3.0.2" 186 | } 187 | }, 188 | "node_modules/@types/react-dom": { 189 | "version": "18.0.11", 190 | "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.11.tgz", 191 | "integrity": "sha512-O38bPbI2CWtgw/OoQoY+BRelw7uysmXbWvw3nLWO21H1HSh+GOlqPuXshJfjmpNlKiiSDG9cc1JZAaMmVdcTlw==", 192 | "dependencies": { 193 | "@types/react": "*" 194 | } 195 | }, 196 | "node_modules/@types/scheduler": { 197 | "version": "0.16.3", 198 | "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", 199 | "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==" 200 | }, 201 | "node_modules/busboy": { 202 | "version": "1.6.0", 203 | "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", 204 | "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", 205 | "dependencies": { 206 | "streamsearch": "^1.1.0" 207 | }, 208 | "engines": { 209 | "node": ">=10.16.0" 210 | } 211 | }, 212 | "node_modules/caniuse-lite": { 213 | "version": "1.0.30001474", 214 | "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001474.tgz", 215 | "integrity": "sha512-iaIZ8gVrWfemh5DG3T9/YqarVZoYf0r188IjaGwx68j4Pf0SGY6CQkmJUIE+NZHkkecQGohzXmBGEwWDr9aM3Q==", 216 | "funding": [ 217 | { 218 | "type": "opencollective", 219 | "url": "https://opencollective.com/browserslist" 220 | }, 221 | { 222 | "type": "tidelift", 223 | "url": "https://tidelift.com/funding/github/npm/caniuse-lite" 224 | }, 225 | { 226 | "type": "github", 227 | "url": "https://github.com/sponsors/ai" 228 | } 229 | ] 230 | }, 231 | "node_modules/client-only": { 232 | "version": "0.0.1", 233 | "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", 234 | "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" 235 | }, 236 | "node_modules/csstype": { 237 | "version": "3.1.2", 238 | "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", 239 | "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" 240 | }, 241 | "node_modules/js-tokens": { 242 | "version": "4.0.0", 243 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 244 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" 245 | }, 246 | "node_modules/loose-envify": { 247 | "version": "1.4.0", 248 | "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", 249 | "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", 250 | "dependencies": { 251 | "js-tokens": "^3.0.0 || ^4.0.0" 252 | }, 253 | "bin": { 254 | "loose-envify": "cli.js" 255 | } 256 | }, 257 | "node_modules/nanoid": { 258 | "version": "3.3.6", 259 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", 260 | "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", 261 | "funding": [ 262 | { 263 | "type": "github", 264 | "url": "https://github.com/sponsors/ai" 265 | } 266 | ], 267 | "bin": { 268 | "nanoid": "bin/nanoid.cjs" 269 | }, 270 | "engines": { 271 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 272 | } 273 | }, 274 | "node_modules/next": { 275 | "version": "13.3.0", 276 | "resolved": "https://registry.npmjs.org/next/-/next-13.3.0.tgz", 277 | "integrity": "sha512-OVTw8MpIPa12+DCUkPqRGPS3thlJPcwae2ZL4xti3iBff27goH024xy4q2lhlsdoYiKOi8Kz6uJoLW/GXwgfOA==", 278 | "dependencies": { 279 | "@next/env": "13.3.0", 280 | "@swc/helpers": "0.4.14", 281 | "busboy": "1.6.0", 282 | "caniuse-lite": "^1.0.30001406", 283 | "postcss": "8.4.14", 284 | "styled-jsx": "5.1.1" 285 | }, 286 | "bin": { 287 | "next": "dist/bin/next" 288 | }, 289 | "engines": { 290 | "node": ">=14.6.0" 291 | }, 292 | "optionalDependencies": { 293 | "@next/swc-darwin-arm64": "13.3.0", 294 | "@next/swc-darwin-x64": "13.3.0", 295 | "@next/swc-linux-arm64-gnu": "13.3.0", 296 | "@next/swc-linux-arm64-musl": "13.3.0", 297 | "@next/swc-linux-x64-gnu": "13.3.0", 298 | "@next/swc-linux-x64-musl": "13.3.0", 299 | "@next/swc-win32-arm64-msvc": "13.3.0", 300 | "@next/swc-win32-ia32-msvc": "13.3.0", 301 | "@next/swc-win32-x64-msvc": "13.3.0" 302 | }, 303 | "peerDependencies": { 304 | "@opentelemetry/api": "^1.1.0", 305 | "fibers": ">= 3.1.0", 306 | "node-sass": "^6.0.0 || ^7.0.0", 307 | "react": "^18.2.0", 308 | "react-dom": "^18.2.0", 309 | "sass": "^1.3.0" 310 | }, 311 | "peerDependenciesMeta": { 312 | "@opentelemetry/api": { 313 | "optional": true 314 | }, 315 | "fibers": { 316 | "optional": true 317 | }, 318 | "node-sass": { 319 | "optional": true 320 | }, 321 | "sass": { 322 | "optional": true 323 | } 324 | } 325 | }, 326 | "node_modules/picocolors": { 327 | "version": "1.0.0", 328 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", 329 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" 330 | }, 331 | "node_modules/postcss": { 332 | "version": "8.4.14", 333 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", 334 | "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", 335 | "funding": [ 336 | { 337 | "type": "opencollective", 338 | "url": "https://opencollective.com/postcss/" 339 | }, 340 | { 341 | "type": "tidelift", 342 | "url": "https://tidelift.com/funding/github/npm/postcss" 343 | } 344 | ], 345 | "dependencies": { 346 | "nanoid": "^3.3.4", 347 | "picocolors": "^1.0.0", 348 | "source-map-js": "^1.0.2" 349 | }, 350 | "engines": { 351 | "node": "^10 || ^12 || >=14" 352 | } 353 | }, 354 | "node_modules/react": { 355 | "version": "18.2.0", 356 | "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", 357 | "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", 358 | "dependencies": { 359 | "loose-envify": "^1.1.0" 360 | }, 361 | "engines": { 362 | "node": ">=0.10.0" 363 | } 364 | }, 365 | "node_modules/react-dom": { 366 | "version": "18.2.0", 367 | "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", 368 | "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", 369 | "dependencies": { 370 | "loose-envify": "^1.1.0", 371 | "scheduler": "^0.23.0" 372 | }, 373 | "peerDependencies": { 374 | "react": "^18.2.0" 375 | } 376 | }, 377 | "node_modules/scheduler": { 378 | "version": "0.23.0", 379 | "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", 380 | "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", 381 | "dependencies": { 382 | "loose-envify": "^1.1.0" 383 | } 384 | }, 385 | "node_modules/source-map-js": { 386 | "version": "1.0.2", 387 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", 388 | "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", 389 | "engines": { 390 | "node": ">=0.10.0" 391 | } 392 | }, 393 | "node_modules/streamsearch": { 394 | "version": "1.1.0", 395 | "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", 396 | "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", 397 | "engines": { 398 | "node": ">=10.0.0" 399 | } 400 | }, 401 | "node_modules/styled-jsx": { 402 | "version": "5.1.1", 403 | "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", 404 | "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", 405 | "dependencies": { 406 | "client-only": "0.0.1" 407 | }, 408 | "engines": { 409 | "node": ">= 12.0.0" 410 | }, 411 | "peerDependencies": { 412 | "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0" 413 | }, 414 | "peerDependenciesMeta": { 415 | "@babel/core": { 416 | "optional": true 417 | }, 418 | "babel-plugin-macros": { 419 | "optional": true 420 | } 421 | } 422 | }, 423 | "node_modules/tslib": { 424 | "version": "2.5.0", 425 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", 426 | "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" 427 | }, 428 | "node_modules/typescript": { 429 | "version": "5.0.3", 430 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.3.tgz", 431 | "integrity": "sha512-xv8mOEDnigb/tN9PSMTwSEqAnUvkoXMQlicOb0IUVDBSQCgBSaAAROUZYy2IcUy5qU6XajK5jjjO7TMWqBTKZA==", 432 | "bin": { 433 | "tsc": "bin/tsc", 434 | "tsserver": "bin/tsserver" 435 | }, 436 | "engines": { 437 | "node": ">=12.20" 438 | } 439 | } 440 | } 441 | } 442 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "midjourney-telegram-bot", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@types/node": "18.15.11", 13 | "@types/react": "18.0.33", 14 | "@types/react-dom": "18.0.11", 15 | "next": "13.3.0", 16 | "react": "18.2.0", 17 | "react-dom": "18.2.0", 18 | "typescript": "5.0.3" 19 | }, 20 | "devDependencies": {} 21 | } 22 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monokaijs/midjourney-telegram-bot/f245865b7c792e925d21933a908fe6a08809ea94/public/favicon.ico -------------------------------------------------------------------------------- /public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import '@/styles/globals.css' 2 | import type { AppProps } from 'next/app' 3 | 4 | export default function App({ Component, pageProps }: AppProps) { 5 | return 6 | } 7 | -------------------------------------------------------------------------------- /src/pages/_document.tsx: -------------------------------------------------------------------------------- 1 | import { Html, Head, Main, NextScript } from 'next/document' 2 | 3 | export default function Document() { 4 | return ( 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /src/pages/api/hello.ts: -------------------------------------------------------------------------------- 1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction 2 | import type { NextApiRequest, NextApiResponse } from 'next' 3 | 4 | type Data = { 5 | name: string 6 | } 7 | 8 | export default function handler( 9 | req: NextApiRequest, 10 | res: NextApiResponse 11 | ) { 12 | res.status(200).json({ name: 'John Doe' }) 13 | } 14 | -------------------------------------------------------------------------------- /src/pages/api/telegram-webhook.ts: -------------------------------------------------------------------------------- 1 | import type { NextApiRequest } from 'next'; 2 | import {ReplicateUtils} from "@/utils/replicate.utils"; 3 | import TelegramService from "@/services/telegram.service"; 4 | import {NextRequest} from "next/server"; 5 | 6 | export const config = { 7 | runtime: 'edge', 8 | } 9 | 10 | const model = "prompthero/openjourney:9936c2001faa2194a261c01381f90e65261879985476014a0a37a334593a05eb"; 11 | const midJourney = async (prompt: string, parameters = {}) => 12 | await ReplicateUtils.run(model, { prompt, ...parameters }); 13 | 14 | export default function handler(req: NextRequest) { 15 | return new Promise(async resolve => { 16 | const telegram = new TelegramService(); 17 | const vercelUrl = process.env.VERCEL_URL; 18 | const webhookPath = `https://${vercelUrl}/api/telegram-webhook`; 19 | const functionStartTime = new Date().getTime(); 20 | if (req.method === 'GET') { 21 | try { 22 | await telegram.setWebhook(webhookPath); 23 | resolve(new Response(JSON.stringify({ 24 | message: 'Telegram Webhook has been successfully set' 25 | }))); 26 | } catch (e: any) { 27 | resolve(new Response(JSON.stringify({ 28 | message: 'Failed to setup Telegram Webhook. ' + e.message 29 | }))); 30 | } 31 | } else { 32 | console.log('processing message'); 33 | const body = JSON.parse(await req.text()); 34 | const msg = body.message as any; 35 | if (!msg || !msg.chat) { 36 | resolve(new Response(JSON.stringify({ 37 | message: "Invalid chat" 38 | }))); 39 | return; 40 | } 41 | const chatId = msg.chat.id; 42 | 43 | if (msg.text && msg.text.startsWith('/draw ')) { 44 | 45 | let timeout = setTimeout(() => { 46 | telegram.sendMessage(chatId, "Timed out. If you're using free plan of Vercel, please upgrade for more processing time. After upgrade, please set variable `FUNCTION_TIMEOUT` on vercel to a number larger than 15000 (15 seconds) to break this limit."); 47 | resolve(new Response(JSON.stringify({ 48 | message: "timeout" 49 | }))) 50 | }, parseInt(process.env.FUNCTION_TIMEOUT as string || "25000")); 51 | 52 | const sentMsg = await telegram.sendMessage(chatId, 'Image is being drawn...'); 53 | // Temporarily disable translation due to limitations 54 | // const translation = await translate(msg.text.slice(6), { 55 | // to: 'en' 56 | // }); 57 | // const translatedPrompt = translation.text; 58 | try { 59 | const mjResponse = await midJourney(msg.text.slice(6)); 60 | await Promise.all([ 61 | telegram.sendPhoto(chatId, mjResponse[0]), 62 | telegram.deleteMessage(chatId, sentMsg.message_id) 63 | ]); 64 | } catch (e) { 65 | await telegram.editMessageText(chatId, sentMsg.message_id, 'Failed to draw. Please check server logs for more details.'); 66 | } 67 | console.log('Taken', new Date().getTime() - functionStartTime, 'ms to execute'); 68 | clearTimeout(timeout); 69 | resolve(new Response(JSON.stringify({ 70 | success: true 71 | }))) 72 | } 73 | } 74 | }); 75 | } 76 | -------------------------------------------------------------------------------- /src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import Head from 'next/head' 2 | 3 | export default function Home() { 4 | return ( 5 | <> 6 | 7 | MidJourney Telegram Bot Tutorial 8 | 9 | 10 | 11 | 12 | 13 |
14 |

15 | Hello there. Your bot does not work? Visit this page to complete setup. 16 |

17 |
18 | 19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /src/services/telegram.service.ts: -------------------------------------------------------------------------------- 1 | class TelegramService { 2 | apiBase = 'https://api.telegram.org/bot'; 3 | 4 | constructor() { 5 | const telegramToken = process.env.TELEGRAM_KEY as string; 6 | this.apiBase += telegramToken; 7 | } 8 | sendMessage(chat_id, text, parse_mode = undefined) { 9 | return fetch(`${this.apiBase}/sendMessage`, { 10 | method: 'POST', 11 | headers: { 12 | 'Content-Type': 'application/json' 13 | }, 14 | body: JSON.stringify({ 15 | chat_id, 16 | text, 17 | parse_mode 18 | }) 19 | }).then(r => r.json()) 20 | } 21 | setWebhook(url: string) { 22 | return fetch(`${this.apiBase}/setWebhook`, { 23 | method: 'POST', 24 | headers: { 25 | 'Content-Type': 'application/json' 26 | }, 27 | body: JSON.stringify({ 28 | url, 29 | drop_pending_updates: true 30 | }) 31 | }) 32 | } 33 | sendPhoto(chat_id, photo_url, caption = '') { 34 | return fetch(`${this.apiBase}/sendPhoto`, { 35 | method: 'POST', 36 | headers: { 37 | 'Content-Type': 'application/json' 38 | }, 39 | body: JSON.stringify({ 40 | chat_id, 41 | photo: photo_url, 42 | caption, 43 | }) 44 | }) 45 | } 46 | deleteMessage(chat_id, message_id) { 47 | return fetch(`${this.apiBase}/deleteMessage`, { 48 | method: 'POST', 49 | headers: { 50 | 'Content-Type': 'application/json' 51 | }, 52 | body: JSON.stringify({ 53 | chat_id, 54 | message_id, 55 | }) 56 | }) 57 | } 58 | editMessageText(chat_id, message_id, text) { 59 | return fetch(`${this.apiBase}/editMessageText`, { 60 | method: 'POST', 61 | headers: { 62 | 'Content-Type': 'application/json' 63 | }, 64 | body: JSON.stringify({ 65 | chat_id, 66 | message_id, 67 | text, 68 | }) 69 | }) 70 | } 71 | } 72 | 73 | export default TelegramService; 74 | -------------------------------------------------------------------------------- /src/styles/globals.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monokaijs/midjourney-telegram-bot/f245865b7c792e925d21933a908fe6a08809ea94/src/styles/globals.css -------------------------------------------------------------------------------- /src/utils/replicate.utils.ts: -------------------------------------------------------------------------------- 1 | export const ReplicateUtils = { 2 | run: async function(model: string, inputs: any) { 3 | let prediction = await this.create(model, inputs) 4 | 5 | while (! [ 6 | 'canceled', 7 | 'succeeded', 8 | 'failed' 9 | ].includes(prediction.status)) { 10 | await new Promise(_ => setTimeout(_, 250)) 11 | prediction = await this.get(prediction) 12 | } 13 | 14 | return prediction.output 15 | }, 16 | 17 | async get(prediction: any) { 18 | const controller = new AbortController(); 19 | const id = setTimeout(() => controller.abort(), 29000); 20 | const response = await fetch(`https://replicate.com/api/models${prediction.version.model.absolute_url}/versions/${prediction.version_id}/predictions/${prediction.uuid}`, ) 21 | .then(r => r.json()).then(response => response.prediction); 22 | clearTimeout(id); 23 | return response; 24 | }, 25 | 26 | create(model: string, inputs: any) { 27 | const [path, version] = model.split(':') 28 | 29 | return fetch(`https://replicate.com/api/models/${path}/versions/${version}/predictions`, { 30 | method: 'POST', 31 | headers: { 32 | 'Content-Type': 'application/json', 33 | }, 34 | body: JSON.stringify({ inputs }), 35 | }).then(response => response.json()) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/utils/translate.utils.ts: -------------------------------------------------------------------------------- 1 | const TRANSLATE_PATH = 'https://translate.google.'; 2 | 3 | const DEFAULT_OPTIONS = { 4 | from: 'auto', 5 | to: 'en', 6 | autoCorrect: false, 7 | tld: 'com', 8 | requestFunction(url: string, fetchInit: RequestInit) { return fetch(url, fetchInit); }, 9 | requestOptions: { 10 | credentials: 'omit', 11 | headers: {} 12 | }, 13 | fallbackBatch: true, 14 | forceBatch: true, 15 | forceFrom: false, 16 | forceTo: false 17 | }; 18 | 19 | Object.freeze(DEFAULT_OPTIONS.requestOptions); 20 | Object.freeze(DEFAULT_OPTIONS); 21 | 22 | class TranslationResult { 23 | text = ''; 24 | pronunciation = undefined; 25 | from = { 26 | language: { 27 | didYouMean: undefined, 28 | iso: '' 29 | }, 30 | text: { 31 | autoCorrected: undefined, 32 | value: '', 33 | didYouMean: undefined 34 | } 35 | }; 36 | to = ''; 37 | raw = undefined; 38 | constructor(raw: any) { 39 | this.raw = raw; 40 | } 41 | }; 42 | 43 | const langs = { 44 | 'auto': 'Automatic', 45 | 'af': 'Afrikaans', 46 | 'sq': 'Albanian', 47 | 'am': 'Amharic', 48 | 'ar': 'Arabic', 49 | 'hy': 'Armenian', 50 | 'as': 'Assamese', 51 | 'ay': 'Aymara', 52 | 'az': 'Azerbaijani', 53 | 'bm': 'Bambara', 54 | 'eu': 'Basque', 55 | 'be': 'Belarusian', 56 | 'bn': 'Bengali', 57 | 'bho': 'Bhojpuri', 58 | 'bs': 'Bosnian', 59 | 'bg': 'Bulgarian', 60 | 'ca': 'Catalan', 61 | 'ceb': 'Cebuano', 62 | 'ny': 'Chichewa', 63 | 'zh-CN': 'Chinese (Simplified)', 64 | 'zh-TW': 'Chinese (Traditional)', 65 | 'co': 'Corsican', 66 | 'hr': 'Croatian', 67 | 'cs': 'Czech', 68 | 'da': 'Danish', 69 | 'dv': 'Dhivehi', 70 | 'doi': 'Dogri', 71 | 'nl': 'Dutch', 72 | 'en': 'English', 73 | 'eo': 'Esperanto', 74 | 'et': 'Estonian', 75 | 'ee': 'Ewe', 76 | 'tl': 'Filipino', 77 | 'fi': 'Finnish', 78 | 'fr': 'French', 79 | 'fy': 'Frisian', 80 | 'gl': 'Galician', 81 | 'ka': 'Georgian', 82 | 'de': 'German', 83 | 'el': 'Greek', 84 | 'gn': 'Guarani', 85 | 'gu': 'Gujarati', 86 | 'ht': 'Haitian Creole', 87 | 'ha': 'Hausa', 88 | 'haw': 'Hawaiian', 89 | 'iw': 'Hebrew', 90 | 'he': 'Hebrew', 91 | 'hi': 'Hindi', 92 | 'hmn': 'Hmong', 93 | 'hu': 'Hungarian', 94 | 'is': 'Icelandic', 95 | 'ig': 'Igbo', 96 | 'ilo': 'Ilocano', 97 | 'id': 'Indonesian', 98 | 'ga': 'Irish', 99 | 'it': 'Italian', 100 | 'ja': 'Japanese', 101 | 'jw': 'Javanese', 102 | 'kn': 'Kannada', 103 | 'kk': 'Kazakh', 104 | 'km': 'Khmer', 105 | 'rw': 'Kinyarwanda', 106 | 'gom': 'Konkani', 107 | 'ko': 'Korean', 108 | 'kri': 'Krio', 109 | 'ku': 'Kurdish (Kurmanji)', 110 | 'ckb': 'Kurdish (Sorani)', 111 | 'ky': 'Kyrgyz', 112 | 'lo': 'Lao', 113 | 'la': 'Latin', 114 | 'lv': 'Latvian', 115 | 'ln': 'Lingala', 116 | 'lt': 'Lithuanian', 117 | 'lg': 'Luganda', 118 | 'lb': 'Luxembourgish', 119 | 'mk': 'Macedonian', 120 | 'mai': 'Maithili', 121 | 'mg': 'Malagasy', 122 | 'ms': 'Malay', 123 | 'ml': 'Malayalam', 124 | 'mt': 'Maltese', 125 | 'mi': 'Maori', 126 | 'mr': 'Marathi', 127 | 'mni-Mtei': 'Meiteilon (Manipuri)', 128 | 'lus': 'Mizo', 129 | 'mn': 'Mongolian', 130 | 'my': 'Myanmar (Burmese)', 131 | 'ne': 'Nepali', 132 | 'no': 'Norwegian', 133 | 'or': 'Odia (Oriya)', 134 | 'om': 'Oromo', 135 | 'ps': 'Pashto', 136 | 'fa': 'Persian', 137 | 'pl': 'Polish', 138 | 'pt': 'Portuguese', 139 | 'pa': 'Punjabi', 140 | 'qu': 'Quechua', 141 | 'ro': 'Romanian', 142 | 'ru': 'Russian', 143 | 'sm': 'Samoan', 144 | 'sa': 'Sanskrit', 145 | 'gd': 'Scots Gaelic', 146 | 'nso': 'Sepedi', 147 | 'sr': 'Serbian', 148 | 'st': 'Sesotho', 149 | 'sn': 'Shona', 150 | 'sd': 'Sindhi', 151 | 'si': 'Sinhala', 152 | 'sk': 'Slovak', 153 | 'sl': 'Slovenian', 154 | 'so': 'Somali', 155 | 'es': 'Spanish', 156 | 'su': 'Sundanese', 157 | 'sw': 'Swahili', 158 | 'sv': 'Swedish', 159 | 'tg': 'Tajik', 160 | 'ta': 'Tamil', 161 | 'tt': 'Tatar', 162 | 'te': 'Telugu', 163 | 'th': 'Thai', 164 | 'ti': 'Tigrinya', 165 | 'ts': 'Tsonga', 166 | 'tr': 'Turkish', 167 | 'tk': 'Turkmen', 168 | 'ak': 'Twi', 169 | 'uk': 'Ukrainian', 170 | 'ur': 'Urdu', 171 | 'ug': 'Uyghur', 172 | 'uz': 'Uzbek', 173 | 'vi': 'Vietnamese', 174 | 'cy': 'Welsh', 175 | 'xh': 'Xhosa', 176 | 'yi': 'Yiddish', 177 | 'yo': 'Yoruba', 178 | 'zu': 'Zulu' 179 | }; 180 | type Codes = keyof typeof langs; 181 | function getCode(desiredLang: Codes) { 182 | if (langs[desiredLang]) { 183 | return desiredLang; 184 | } 185 | 186 | const keys = Object.keys(langs).filter(function (key) { 187 | let k = key as Codes; 188 | if (typeof langs[k] !== 'string') { 189 | return false; 190 | } 191 | 192 | return langs[k].toLowerCase() === desiredLang.toLowerCase(); 193 | }); 194 | 195 | return keys[0] ?? null; 196 | } 197 | 198 | function isSupported(desiredLang: Codes) { 199 | return getCode(desiredLang) !== null; 200 | } 201 | 202 | export function translate(input: any, options: any) { 203 | options = {...DEFAULT_OPTIONS, ...options, ...input.options}; 204 | const requestOptions = {...DEFAULT_OPTIONS.requestOptions, ...options.requestOptions}; 205 | requestOptions.method = 'POST'; 206 | requestOptions.headers['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8'; 207 | 208 | const fromIso = options.forceFrom ? options.from : getCode(options.from); 209 | if (fromIso === null) { 210 | return new Promise(() => { 211 | throw new Error(`From language ${options.from} unsupported, bypass this with setting forceFrom to true if you're certain the iso is correct`); 212 | }); 213 | } 214 | 215 | const toIso = options.forceTo ? options.to : getCode(options.to); 216 | if (toIso === null) { 217 | return new Promise(() => { 218 | throw new Error(`To language ${options.to} unsupported, bypass this with setting forceTo to true if you're certain the iso is correct`); 219 | }); 220 | } 221 | 222 | const params = { 223 | sl: fromIso, 224 | tl: toIso, 225 | q: input.text ?? input 226 | }; 227 | requestOptions.body = new URLSearchParams(params).toString(); 228 | 229 | const url = TRANSLATE_PATH + options.tld + '/translate_a/single?client=at&dt=t&dt=rm&dj=1'; 230 | 231 | return options.requestFunction(url, requestOptions).then((res: Response) => { 232 | if (res.ok) { 233 | return res.json(); 234 | } 235 | throw new Error(res.statusText); 236 | }).then((res: any) => { 237 | const result = new TranslationResult(res); 238 | result.from = res.src ?? options.from; 239 | result.to = options.to; 240 | for (const sentence of res.sentences) { 241 | if (typeof sentence.trans !== 'undefined') { 242 | result.text += sentence.trans; 243 | } else if (typeof sentence.translit !== 'undefined') { 244 | result.pronunciation = sentence.translit; 245 | } 246 | } 247 | return result; 248 | }); 249 | } 250 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "strictPropertyInitialization": false, 9 | "forceConsistentCasingInFileNames": true, 10 | "noEmit": true, 11 | "esModuleInterop": true, 12 | "module": "esnext", 13 | "moduleResolution": "node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "jsx": "preserve", 17 | "noImplicitAny": false, 18 | "incremental": true, 19 | "paths": { 20 | "@/*": ["./src/*"] 21 | } 22 | }, 23 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], 24 | "exclude": ["node_modules"] 25 | } 26 | --------------------------------------------------------------------------------