├── .github └── workflows │ ├── deploy.yml │ └── deployNew.yml ├── .gitignore ├── LICENSE ├── README.md ├── docs.json ├── docs ├── audio │ ├── music │ │ └── index.mdx │ ├── stt │ │ └── index.mdx │ └── tts │ │ └── index.mdx ├── image │ ├── anything │ │ └── index.mdx │ ├── controlnet │ │ └── index.mdx │ ├── dall-e │ │ └── index.mdx │ ├── fast_sdxl │ │ └── index.mdx │ ├── fasts-sdxl │ │ └── index.mdx │ ├── kandinsky │ │ └── index.mdx │ ├── sdxl │ │ └── index.mdx │ ├── sh │ │ └── index.mdx │ ├── upscale │ │ └── index.mdx │ └── vision │ │ └── index.mdx ├── index.mdx ├── text │ ├── alan │ │ └── index.mdx │ ├── anthropic │ │ └── index.mdx │ ├── filter │ │ └── index.mdx │ ├── google │ │ └── index.mdx │ ├── gpt-new │ │ └── index.mdx │ ├── groq │ │ └── index.mdx │ ├── huggingface │ │ └── index.mdx │ ├── openchat │ │ └── index.mdx │ ├── other │ │ └── index.mdx │ ├── pawan │ │ └── index.mdx │ └── translate │ │ └── index.mdx └── video │ └── zelescope │ └── index.mdx ├── package-lock.json ├── package.json ├── src ├── db │ ├── mq.ts │ ├── redis.ts │ └── supabase.ts ├── handlers │ ├── audio.ts │ ├── image.ts │ ├── text.ts │ └── video.ts ├── index.ts ├── middlewares │ ├── captchas │ │ ├── hcaptchas.ts │ │ └── turnstile.ts │ ├── geo.ts │ └── key.ts ├── models │ ├── audio │ │ ├── music.ts │ │ ├── stt.ts │ │ └── tts.ts │ ├── image │ │ ├── anything.ts │ │ ├── controlnet.ts │ │ ├── dall-e.ts │ │ ├── sh.ts │ │ ├── upscale.ts │ │ └── vision.ts │ ├── text │ │ ├── alan.ts │ │ ├── anthropic.ts │ │ ├── filter.ts │ │ ├── google.ts │ │ ├── gpt-new.ts │ │ ├── groq.ts │ │ ├── openchat.ts │ │ └── pawan.ts │ └── video │ │ └── zelescope.ts ├── routes │ ├── chart.routes.ts │ ├── data.routes.ts │ ├── dataset.routes.ts │ ├── key.routes.ts │ ├── models.routes.ts │ ├── other.routes.ts │ ├── payment.routes.ts │ ├── runpod.routes.ts │ └── storage.routes.ts ├── rundocs.ts └── utils │ ├── chart.ts │ ├── ciclic.ts │ ├── datasets.ts │ ├── db.ts │ ├── docs.ts │ ├── key.ts │ ├── keywords.ts │ ├── log.ts │ ├── ms.ts │ ├── plugins.ts │ ├── runpod.ts │ ├── stats.ts │ └── tokenizer.ts └── tsconfig.json /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy to SSH VPS 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | deploy: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | # Checkout code from the main branch 14 | - name: Checkout code 15 | uses: actions/checkout@v2 16 | 17 | # Install Node.js and PM2 18 | 19 | # Connect to remote server via SSH to start the bot using PM2 20 | - name: Start API with PM2 21 | uses: appleboy/ssh-action@master 22 | with: 23 | host: ${{ secrets.HOST }} 24 | username: ${{ secrets.USERNAME }} 25 | password: ${{ secrets.PASSWORD }} 26 | script: | 27 | cd /home/loick/github/turing-api 28 | npm run git 29 | npm i 30 | npm run build 31 | nvm use 18 32 | pm2 reload TuringAPI 33 | -------------------------------------------------------------------------------- /.github/workflows/deployNew.yml: -------------------------------------------------------------------------------- 1 | name: Deploy to SSH VPS 2 | 3 | on: 4 | push: 5 | branches: 6 | - new 7 | 8 | jobs: 9 | deploy: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | # Checkout code from the main branch 14 | - name: Checkout code 15 | uses: actions/checkout@v2 16 | 17 | # Connect to remote server via SSH to start the bot using PM2 18 | - name: Build and reload API 19 | uses: appleboy/ssh-action@master 20 | with: 21 | host: ${{ secrets.HOST }} 22 | username: ${{ secrets.USERNAME }} 23 | password: ${{ secrets.PASSWORD }} 24 | script: | 25 | export NVM_DIR="$HOME/.nvm" 26 | [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" 27 | [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" 28 | cd /home/trident/github/turing-api-new 29 | nvm use 20 30 | PATH="$HOME/.nvm/versions/node/v20.0.0/bin:$PATH" 31 | npm run git 32 | npm i 33 | rm -r dist 34 | npm run build 35 | pm2 reload TuringAPINew 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | guilds.txt 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | *.lcov 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (https://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # TypeScript v1 declaration files 46 | typings/ 47 | 48 | # TypeScript cache 49 | *.tsbuildinfo 50 | 51 | # Optional npm cache directory 52 | .npm 53 | 54 | # Optional eslint cache 55 | .eslintcache 56 | 57 | # Microbundle cache 58 | .rpt2_cache/ 59 | .rts2_cache_cjs/ 60 | .rts2_cache_es/ 61 | .rts2_cache_umd/ 62 | 63 | # Optional REPL history 64 | .node_repl_history 65 | 66 | # Output of 'npm pack' 67 | *.tgz 68 | 69 | # Yarn Integrity file 70 | .yarn-integrity 71 | 72 | # dotenv environment variables file 73 | .env 74 | .env.test 75 | 76 | # parcel-bundler cache (https://parceljs.org/) 77 | .cache 78 | 79 | # Next.js build output 80 | .next 81 | 82 | # Nuxt.js build / generate output 83 | .nuxt 84 | dist 85 | 86 | # Gatsby files 87 | .cache/ 88 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 89 | # https://nextjs.org/blog/next-9-1#public-directory-support 90 | # public 91 | 92 | # vuepress build output 93 | .vuepress/dist 94 | 95 | # Serverless directories 96 | .serverless/ 97 | 98 | # FuseBox cache 99 | .fusebox/ 100 | 101 | # DynamoDB Local files 102 | .dynamodb/ 103 | 104 | # TernJS port file 105 | .tern-port 106 | 107 | temp/ 108 | temp/**/* 109 | g-keyfile.json -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Turing API 2 | 3 | ![Discord](https://img.shields.io/discord/899761438996963349?style=for-the-badge&label=Support%20Server) 4 | 5 | Turing API is the official API from TuringAI and the best API for AI. 6 | 7 | ## Guide 8 | 9 | We are working on libraries/sdks for the most famous programming languages. 10 | 11 | Right now you can use the API by doing normal HTTP requests. 12 | 13 | You can find the documentation [here](https://docs.turing.sh). 14 | 15 | ## Contributing 16 | 17 | You can contribute to the API by making a pull request. 18 | 19 | If you want to contribute to our libraries you need to go to the next repos: 20 | 21 | - [JavaScript](https://github.com/TuringAI-Team/turing-library/tree/typescript) 22 | - [Python](https://github.com/TuringAI-Team/turing-library/tree/python) 23 | 24 | If you want to contribute to the documentation you need to go to the [models folder in this repo](https://github.com/TuringAI-Team/turing-ai-api/tree/new/src/models) or the docs file under the utils folder. You cannot contribute to the documentation by modifying the docs folder since the docs folder is autogenerated using the docs.ts filter based on the data extracted by the models. 25 | You can run the docs.ts file by doing `npm run docs` and you can check [docs.page documentation](https://docs.page) to learn how to use the docs.ts file. 26 | -------------------------------------------------------------------------------- /docs.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "TuringAI API", 3 | "description": "TuringAI API Documentation. The best API for AI.", 4 | "theme": "#A179D9", 5 | "favicon": "https://turing.sh/neon.png", 6 | "logo": "https://turing.sh/neon.png", 7 | "twitter": "Turing_AI_", 8 | "anchors": [ 9 | { 10 | "title": "Homepage", 11 | "icon": "house", 12 | "link": "/" 13 | }, 14 | { 15 | "title": "Discord", 16 | "icon": "discord", 17 | "link": "https://link.turing.sh/discord" 18 | } 19 | ], 20 | "docsearch": { 21 | "appId": "57EGN36JTA", 22 | "apiKey": "64c360c5620075061cf3018f0c801aaa", 23 | "indexName": "TuringAI-Team" 24 | }, 25 | "sidebar": [ 26 | [ 27 | "Text Models", 28 | [ 29 | [ 30 | "Alan", 31 | "/text/alan" 32 | ], 33 | [ 34 | "Anthropic Models", 35 | "/text/anthropic" 36 | ], 37 | [ 38 | "Text Filter", 39 | "/text/filter" 40 | ], 41 | [ 42 | "Google Models", 43 | "/text/google" 44 | ], 45 | [ 46 | "OpenAI models", 47 | "/text/gpt-new" 48 | ], 49 | [ 50 | "GroqCloud models", 51 | "/text/groq" 52 | ], 53 | [ 54 | "OpenChat models", 55 | "/text/openchat" 56 | ], 57 | [ 58 | "Pawan.krd models", 59 | "/text/pawan" 60 | ] 61 | ] 62 | ], 63 | [ 64 | "Image Models", 65 | [ 66 | [ 67 | "Anything models", 68 | "/image/anything" 69 | ], 70 | [ 71 | "Controlnet", 72 | "/image/controlnet" 73 | ], 74 | [ 75 | "Dall-e 3", 76 | "/image/dall-e" 77 | ], 78 | [ 79 | "Fast SDXL", 80 | "/image/fast_sdxl" 81 | ], 82 | [ 83 | "Kandinsky 2.1", 84 | "/image/kandinsky" 85 | ], 86 | [ 87 | "Stablehorde", 88 | "/image/sh" 89 | ], 90 | [ 91 | "Upscale models", 92 | "/image/upscale" 93 | ], 94 | [ 95 | "Image vision", 96 | "/image/vision" 97 | ] 98 | ] 99 | ], 100 | [ 101 | "Audio Models", 102 | [ 103 | [ 104 | "Music generation", 105 | "/audio/music" 106 | ], 107 | [ 108 | "Speech to text", 109 | "/audio/stt" 110 | ], 111 | [ 112 | "Text to speech", 113 | "/audio/tts" 114 | ] 115 | ] 116 | ], 117 | [ 118 | "Video Models", 119 | [ 120 | [ 121 | "Zelescope", 122 | "/video/zelescope" 123 | ] 124 | ] 125 | ] 126 | ] 127 | } -------------------------------------------------------------------------------- /docs/audio/music/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Music generation 3 | --- 4 | 5 | # Music generation 6 | POST *https://api.turing.sh/audio/music* 7 | 8 | ## Parameters 9 | 10 | 11 | - **prompt** 12 | - Type: string 13 | - Required: true 14 | 15 | - **model** 16 | - Type: string 17 | - Required: false 18 | - Options: small, medium, melody, large 19 | - Default: small 20 | 21 | - **duration** 22 | - Type: number 23 | - Required: false 24 | - Default: 8 25 | 26 | - **stream** 27 | - Type: boolean 28 | - Required: false 29 | 30 | ## Response 31 | 32 | Response not defined yet 33 | 34 | 35 | ## Examples 36 | 37 | 38 | ```typescript 39 | import axios from "axios"; 40 | (async () => { 41 | let response = await axios({ 42 | method: "post", 43 | url: 'https://api.turing.sh/audio/music', 44 | headers: { 45 | "Content-Type": "application/json", 46 | Authorization: "Bearer YOUR_API_KEY", 47 | "x-captcha-token": "Captcha key" 48 | }, 49 | data: { 50 | "prompt": "string", 51 | "model": "small", 52 | "duration": 8 53 | }, 54 | }) 55 | })(); 56 | ``` 57 | ```python 58 | import requests 59 | import json 60 | response = requests.post( 61 | "https://api.turing.sh/audio/music", 62 | headers={ 63 | "Content-Type": "application/json", 64 | "Authorization": "Bearer YOUR_API_KEY", 65 | "x-captcha-token": "Captcha key" 66 | }, 67 | data=json.dumps({ 68 | "prompt": "string", 69 | "model": "small", 70 | "duration": 8 71 | }), 72 | ) 73 | ``` 74 | -------------------------------------------------------------------------------- /docs/audio/stt/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Speech to text 3 | --- 4 | 5 | # Speech to text 6 | POST *https://api.turing.sh/audio/stt* 7 | 8 | ## Parameters 9 | 10 | 11 | - **model** 12 | - Type: string 13 | - Required: false 14 | - Description: Model to use for speech to text 15 | - Options: whisper, fast-whisper, gladia 16 | - Default: fast-whisper 17 | 18 | - **audio** 19 | - Type: string 20 | - Required: true 21 | - Description: Audio URL to transcribe 22 | 23 | - **diarization** 24 | - Type: boolean 25 | - Required: false 26 | - Description: Whether to use diarization or not 27 | 28 | - **type** 29 | - Type: string 30 | - Required: false 31 | - Options: tiny, base, small, medium, large-v1, large-v2 32 | - Default: base 33 | 34 | - **stream** 35 | - Type: boolean 36 | - Required: false 37 | 38 | ## Response 39 | 40 | Response not defined yet 41 | 42 | 43 | ## Examples 44 | 45 | 46 | ```typescript 47 | import axios from "axios"; 48 | (async () => { 49 | let response = await axios({ 50 | method: "post", 51 | url: 'https://api.turing.sh/audio/stt', 52 | headers: { 53 | "Content-Type": "application/json", 54 | Authorization: "Bearer YOUR_API_KEY", 55 | "x-captcha-token": "Captcha key" 56 | }, 57 | data: { 58 | "model": "fast-whisper", 59 | "audio": "string", 60 | "type": "base" 61 | }, 62 | }) 63 | })(); 64 | ``` 65 | ```python 66 | import requests 67 | import json 68 | response = requests.post( 69 | "https://api.turing.sh/audio/stt", 70 | headers={ 71 | "Content-Type": "application/json", 72 | "Authorization": "Bearer YOUR_API_KEY", 73 | "x-captcha-token": "Captcha key" 74 | }, 75 | data=json.dumps({ 76 | "model": "fast-whisper", 77 | "audio": "string", 78 | "type": "base" 79 | }), 80 | ) 81 | ``` 82 | -------------------------------------------------------------------------------- /docs/audio/tts/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Text to speech 3 | --- 4 | 5 | # Text to speech 6 | POST *https://api.turing.sh/audio/tts* 7 | 8 | ## Parameters 9 | 10 | 11 | - **model** 12 | - Type: string 13 | - Required: true 14 | - Options: google, elevenlabs 15 | - Default: google 16 | 17 | - **voice** 18 | - Type: string 19 | - Required: true 20 | - Description: Voice to use (elevenlabs only) 21 | - Default: adam 22 | 23 | - **text** 24 | - Type: string 25 | - Required: true 26 | - Description: Text to convert to speech 27 | 28 | - **language** 29 | - Type: string 30 | - Required: true 31 | - Description: Language code to use (google only) 32 | - Default: en 33 | 34 | - **slow** 35 | - Type: boolean 36 | - Required: false 37 | - Description: Speak slowly (google only) 38 | 39 | - **stream** 40 | - Type: boolean 41 | - Required: false 42 | 43 | ## Response 44 | 45 | Response not defined yet 46 | 47 | 48 | ## Examples 49 | 50 | 51 | ```typescript 52 | import axios from "axios"; 53 | (async () => { 54 | let response = await axios({ 55 | method: "post", 56 | url: 'https://api.turing.sh/audio/tts', 57 | headers: { 58 | "Content-Type": "application/json", 59 | Authorization: "Bearer YOUR_API_KEY", 60 | "x-captcha-token": "Captcha key" 61 | }, 62 | data: { 63 | "model": "google", 64 | "voice": "adam", 65 | "text": "string", 66 | "language": "en" 67 | }, 68 | }) 69 | })(); 70 | ``` 71 | ```python 72 | import requests 73 | import json 74 | response = requests.post( 75 | "https://api.turing.sh/audio/tts", 76 | headers={ 77 | "Content-Type": "application/json", 78 | "Authorization": "Bearer YOUR_API_KEY", 79 | "x-captcha-token": "Captcha key" 80 | }, 81 | data=json.dumps({ 82 | "model": "google", 83 | "voice": "adam", 84 | "text": "string", 85 | "language": "en" 86 | }), 87 | ) 88 | ``` 89 | -------------------------------------------------------------------------------- /docs/image/anything/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Anything models 3 | --- 4 | 5 | # Anything models 6 | POST *https://api.turing.sh/image/anything* 7 | 8 | ## Parameters 9 | 10 | 11 | - **prompt** 12 | - Type: string 13 | - Required: true 14 | - Description: Prompt to generate the image 15 | 16 | - **steps** 17 | - Type: number 18 | - Required: false 19 | - Default: 100 20 | 21 | - **number** 22 | - Type: number 23 | - Required: false 24 | - Default: 1 25 | 26 | - **negative_prompt** 27 | - Type: string 28 | - Required: false 29 | - Default: disfigured mouth, disfigured teeth, half head, half face, blury, side looking, old, wrinkle, child, no face, pencil, full body, sharp, far away, overlapping, duplication, nude, disfigured, kitsch, oversaturated, grain, low-res, Deformed, blurry, bad anatomy, poorly drawn face, mutation, mutated, extra limb, ugly, poorly drawn hands, missing limb, blurry, floating limbs, disconnected limbs, malformed hands, blur, out of focus, long body, disgusting, poorly drawn, childish, mutilated, mangled, surreal, out of frame, duplicate, 2 faces 30 | 31 | - **guidance_scale** 32 | - Type: number 33 | - Required: false 34 | - Default: 4 35 | 36 | - **width** 37 | - Type: number 38 | - Required: false 39 | - Default: 512 40 | 41 | - **height** 42 | - Type: number 43 | - Required: false 44 | - Default: 512 45 | 46 | - **cfg_scale** 47 | - Type: number 48 | - Required: false 49 | - Default: 4 50 | 51 | - **stream** 52 | - Type: boolean 53 | - Required: false 54 | - Default: true 55 | 56 | ## Response 57 | 58 | Response not defined yet 59 | 60 | 61 | ## Examples 62 | 63 | 64 | ```typescript 65 | import axios from "axios"; 66 | (async () => { 67 | let response = await axios({ 68 | method: "post", 69 | url: 'https://api.turing.sh/image/anything', 70 | headers: { 71 | "Content-Type": "application/json", 72 | Authorization: "Bearer YOUR_API_KEY", 73 | "x-captcha-token": "Captcha key" 74 | }, 75 | data: { 76 | "prompt": "string", 77 | "steps": 100, 78 | "number": 1, 79 | "negative_prompt": "disfigured mouth, disfigured teeth, half head, half face, blury, side looking, old, wrinkle, child, no face, pencil, full body, sharp, far away, overlapping, duplication, nude, disfigured, kitsch, oversaturated, grain, low-res, Deformed, blurry, bad anatomy, poorly drawn face, mutation, mutated, extra limb, ugly, poorly drawn hands, missing limb, blurry, floating limbs, disconnected limbs, malformed hands, blur, out of focus, long body, disgusting, poorly drawn, childish, mutilated, mangled, surreal, out of frame, duplicate, 2 faces", 80 | "guidance_scale": 4, 81 | "width": 512, 82 | "height": 512, 83 | "cfg_scale": 4, 84 | "stream": true 85 | }, 86 | }) 87 | })(); 88 | ``` 89 | ```python 90 | import requests 91 | import json 92 | response = requests.post( 93 | "https://api.turing.sh/image/anything", 94 | headers={ 95 | "Content-Type": "application/json", 96 | "Authorization": "Bearer YOUR_API_KEY", 97 | "x-captcha-token": "Captcha key" 98 | }, 99 | data=json.dumps({ 100 | "prompt": "string", 101 | "steps": 100, 102 | "number": 1, 103 | "negative_prompt": "disfigured mouth, disfigured teeth, half head, half face, blury, side looking, old, wrinkle, child, no face, pencil, full body, sharp, far away, overlapping, duplication, nude, disfigured, kitsch, oversaturated, grain, low-res, Deformed, blurry, bad anatomy, poorly drawn face, mutation, mutated, extra limb, ugly, poorly drawn hands, missing limb, blurry, floating limbs, disconnected limbs, malformed hands, blur, out of focus, long body, disgusting, poorly drawn, childish, mutilated, mangled, surreal, out of frame, duplicate, 2 faces", 104 | "guidance_scale": 4, 105 | "width": 512, 106 | "height": 512, 107 | "cfg_scale": 4, 108 | "stream": true 109 | }), 110 | ) 111 | ``` 112 | -------------------------------------------------------------------------------- /docs/image/controlnet/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Controlnet 3 | --- 4 | 5 | # Controlnet 6 | POST *https://api.turing.sh/image/controlnet* 7 | 8 | ## Parameters 9 | 10 | 11 | - **prompt** 12 | - Type: string 13 | - Required: true 14 | 15 | - **model** 16 | - Type: string 17 | - Required: true 18 | - Options: normal, canny, hough, hed, depth2img, pose, seg 19 | - Default: normal 20 | 21 | - **image** 22 | - Type: string 23 | - Required: true 24 | 25 | - **stream** 26 | - Type: boolean 27 | - Required: false 28 | 29 | ## Response 30 | 31 | Response not defined yet 32 | 33 | 34 | ## Examples 35 | 36 | 37 | ```typescript 38 | import axios from "axios"; 39 | (async () => { 40 | let response = await axios({ 41 | method: "post", 42 | url: 'https://api.turing.sh/image/controlnet', 43 | headers: { 44 | "Content-Type": "application/json", 45 | Authorization: "Bearer YOUR_API_KEY", 46 | "x-captcha-token": "Captcha key" 47 | }, 48 | data: { 49 | "prompt": "string", 50 | "model": "normal", 51 | "image": "string" 52 | }, 53 | }) 54 | })(); 55 | ``` 56 | ```python 57 | import requests 58 | import json 59 | response = requests.post( 60 | "https://api.turing.sh/image/controlnet", 61 | headers={ 62 | "Content-Type": "application/json", 63 | "Authorization": "Bearer YOUR_API_KEY", 64 | "x-captcha-token": "Captcha key" 65 | }, 66 | data=json.dumps({ 67 | "prompt": "string", 68 | "model": "normal", 69 | "image": "string" 70 | }), 71 | ) 72 | ``` 73 | -------------------------------------------------------------------------------- /docs/image/dall-e/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Dall-e 3 3 | --- 4 | 5 | # Dall-e 3 6 | POST *https://api.turing.sh/image/dall-e* 7 | 8 | ## Parameters 9 | 10 | 11 | - **prompt** 12 | - Type: string 13 | - Required: false 14 | 15 | - **number** 16 | - Type: number 17 | - Required: true 18 | - Description: Number of images to generate 19 | - Options: 1, 2, 3, 4 20 | - Default: 1 21 | 22 | - **size** 23 | - Type: string 24 | - Required: false 25 | - Options: 512x512, 256x256, 1024x1024 26 | - Default: 512x512 27 | 28 | - **image** 29 | - Type: string 30 | - Required: false 31 | - Description: Image you want to vary 32 | 33 | - **stream** 34 | - Type: boolean 35 | - Required: false 36 | 37 | ## Response 38 | 39 | 40 | - **cost** 41 | - Type: number 42 | 43 | - **results** 44 | - Type: array 45 | 46 | - **status** 47 | - Type: string 48 | 49 | - **progress** 50 | - Type: number 51 | 52 | - **id** 53 | - Type: string 54 | 55 | - **done** 56 | - Type: boolean 57 | 58 | ## Examples 59 | 60 | 61 | ```typescript 62 | import axios from "axios"; 63 | (async () => { 64 | let response = await axios({ 65 | method: "post", 66 | url: 'https://api.turing.sh/image/dall-e', 67 | headers: { 68 | "Content-Type": "application/json", 69 | Authorization: "Bearer YOUR_API_KEY", 70 | "x-captcha-token": "Captcha key" 71 | }, 72 | data: { 73 | "number": 1, 74 | "size": "512x512" 75 | }, 76 | }) 77 | })(); 78 | ``` 79 | ```python 80 | import requests 81 | import json 82 | response = requests.post( 83 | "https://api.turing.sh/image/dall-e", 84 | headers={ 85 | "Content-Type": "application/json", 86 | "Authorization": "Bearer YOUR_API_KEY", 87 | "x-captcha-token": "Captcha key" 88 | }, 89 | data=json.dumps({ 90 | "number": 1, 91 | "size": "512x512" 92 | }), 93 | ) 94 | ``` 95 | -------------------------------------------------------------------------------- /docs/image/fast_sdxl/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Fast SDXL 3 | --- 4 | 5 | # Fast SDXL 6 | POST *https://api.turing.sh/image/fast_sdxl* 7 | 8 | ## Parameters 9 | 10 | 11 | - **prompt** 12 | - Type: string 13 | - Required: true 14 | - Description: Prompt to generate the image 15 | 16 | - **steps** 17 | - Type: number 18 | - Required: false 19 | - Default: 4 20 | 21 | - **number** 22 | - Type: number 23 | - Required: false 24 | - Description: Number of images to generate 25 | - Default: 1 26 | 27 | - **negative_prompt** 28 | - Type: string 29 | - Required: false 30 | - Default: disfigured mouth, disfigured teeth, half head, half face, blury, side looking, old, wrinkle, child, no face, pencil, full body, sharp, far away, overlapping, duplication, nude, disfigured, kitsch, oversaturated, grain, low-res, Deformed, blurry, bad anatomy, poorly drawn face, mutation, mutated, extra limb, ugly, poorly drawn hands, missing limb, blurry, floating limbs, disconnected limbs, malformed hands, blur, out of focus, long body, disgusting, poorly drawn, childish, mutilated, mangled, surreal, out of frame, duplicate, 2 faces 31 | 32 | - **width** 33 | - Type: number 34 | - Required: false 35 | - Default: 1024 36 | 37 | - **height** 38 | - Type: number 39 | - Required: false 40 | - Default: 1024 41 | 42 | - **model_version** 43 | - Type: string 44 | - Required: false 45 | - Options: lcm, turbo 46 | - Default: lcm 47 | 48 | - **stream** 49 | - Type: boolean 50 | - Required: false 51 | - Default: true 52 | 53 | ## Response 54 | 55 | 56 | - **cost** 57 | - Type: number 58 | 59 | - **results** 60 | - Type: array 61 | 62 | - **status** 63 | - Type: string 64 | 65 | - **progress** 66 | - Type: number 67 | 68 | - **id** 69 | - Type: string 70 | 71 | ## Examples 72 | 73 | 74 | ```typescript 75 | import axios from "axios"; 76 | (async () => { 77 | let response = await axios({ 78 | method: "post", 79 | url: 'https://api.turing.sh/image/fast_sdxl', 80 | headers: { 81 | "Content-Type": "application/json", 82 | Authorization: "Bearer YOUR_API_KEY", 83 | "x-captcha-token": "Captcha key" 84 | }, 85 | data: { 86 | "prompt": "string", 87 | "steps": 4, 88 | "number": 1, 89 | "negative_prompt": "disfigured mouth, disfigured teeth, half head, half face, blury, side looking, old, wrinkle, child, no face, pencil, full body, sharp, far away, overlapping, duplication, nude, disfigured, kitsch, oversaturated, grain, low-res, Deformed, blurry, bad anatomy, poorly drawn face, mutation, mutated, extra limb, ugly, poorly drawn hands, missing limb, blurry, floating limbs, disconnected limbs, malformed hands, blur, out of focus, long body, disgusting, poorly drawn, childish, mutilated, mangled, surreal, out of frame, duplicate, 2 faces", 90 | "width": 1024, 91 | "height": 1024, 92 | "model_version": "lcm", 93 | "stream": true 94 | }, 95 | }) 96 | })(); 97 | ``` 98 | ```python 99 | import requests 100 | import json 101 | response = requests.post( 102 | "https://api.turing.sh/image/fast_sdxl", 103 | headers={ 104 | "Content-Type": "application/json", 105 | "Authorization": "Bearer YOUR_API_KEY", 106 | "x-captcha-token": "Captcha key" 107 | }, 108 | data=json.dumps({ 109 | "prompt": "string", 110 | "steps": 4, 111 | "number": 1, 112 | "negative_prompt": "disfigured mouth, disfigured teeth, half head, half face, blury, side looking, old, wrinkle, child, no face, pencil, full body, sharp, far away, overlapping, duplication, nude, disfigured, kitsch, oversaturated, grain, low-res, Deformed, blurry, bad anatomy, poorly drawn face, mutation, mutated, extra limb, ugly, poorly drawn hands, missing limb, blurry, floating limbs, disconnected limbs, malformed hands, blur, out of focus, long body, disgusting, poorly drawn, childish, mutilated, mangled, surreal, out of frame, duplicate, 2 faces", 113 | "width": 1024, 114 | "height": 1024, 115 | "model_version": "lcm", 116 | "stream": true 117 | }), 118 | ) 119 | ``` 120 | -------------------------------------------------------------------------------- /docs/image/fasts-sdxl/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Fast SDXL 3 | --- 4 | 5 | # Fast SDXL 6 | POST *https://api.turing.sh/image/fasts-sdxl* 7 | 8 | ## Parameters 9 | 10 | 11 | - **prompt** 12 | - Type: string 13 | - Required: true 14 | - Description: Prompt to generate the image 15 | 16 | - **steps** 17 | - Type: number 18 | - Required: false 19 | - Default: 4 20 | 21 | - **number** 22 | - Type: number 23 | - Required: false 24 | - Description: Number of images to generate 25 | - Default: 1 26 | 27 | - **negative_prompt** 28 | - Type: string 29 | - Required: false 30 | - Default: disfigured mouth, disfigured teeth, half head, half face, blury, side looking, old, wrinkle, child, no face, pencil, full body, sharp, far away, overlapping, duplication, nude, disfigured, kitsch, oversaturated, grain, low-res, Deformed, blurry, bad anatomy, poorly drawn face, mutation, mutated, extra limb, ugly, poorly drawn hands, missing limb, blurry, floating limbs, disconnected limbs, malformed hands, blur, out of focus, long body, disgusting, poorly drawn, childish, mutilated, mangled, surreal, out of frame, duplicate, 2 faces 31 | 32 | - **width** 33 | - Type: number 34 | - Required: false 35 | - Default: 1024 36 | 37 | - **height** 38 | - Type: number 39 | - Required: false 40 | - Default: 1024 41 | 42 | - **model_version** 43 | - Type: string 44 | - Required: false 45 | - Options: lcm, turbo 46 | - Default: lcm 47 | 48 | - **stream** 49 | - Type: boolean 50 | - Required: false 51 | - Default: true 52 | 53 | ## Response 54 | 55 | 56 | - **cost** 57 | - Type: number 58 | 59 | - **results** 60 | - Type: array 61 | 62 | - **status** 63 | - Type: string 64 | 65 | - **progress** 66 | - Type: number 67 | 68 | - **id** 69 | - Type: string 70 | 71 | ## Examples 72 | 73 | 74 | ```typescript 75 | import axios from "axios"; 76 | (async () => { 77 | let response = await axios({ 78 | method: "post", 79 | url: 'https://api.turing.sh/image/fasts-sdxl', 80 | headers: { 81 | "Content-Type": "application/json", 82 | Authorization: "Bearer YOUR_API_KEY", 83 | "x-captcha-token": "Captcha key" 84 | }, 85 | data: { 86 | "prompt": "string", 87 | "steps": 4, 88 | "number": 1, 89 | "negative_prompt": "disfigured mouth, disfigured teeth, half head, half face, blury, side looking, old, wrinkle, child, no face, pencil, full body, sharp, far away, overlapping, duplication, nude, disfigured, kitsch, oversaturated, grain, low-res, Deformed, blurry, bad anatomy, poorly drawn face, mutation, mutated, extra limb, ugly, poorly drawn hands, missing limb, blurry, floating limbs, disconnected limbs, malformed hands, blur, out of focus, long body, disgusting, poorly drawn, childish, mutilated, mangled, surreal, out of frame, duplicate, 2 faces", 90 | "width": 1024, 91 | "height": 1024, 92 | "model_version": "lcm", 93 | "stream": true 94 | }, 95 | }) 96 | })(); 97 | ``` 98 | ```python 99 | import requests 100 | import json 101 | response = requests.post( 102 | "https://api.turing.sh/image/fasts-sdxl", 103 | headers={ 104 | "Content-Type": "application/json", 105 | "Authorization": "Bearer YOUR_API_KEY", 106 | "x-captcha-token": "Captcha key" 107 | }, 108 | data=json.dumps({ 109 | "prompt": "string", 110 | "steps": 4, 111 | "number": 1, 112 | "negative_prompt": "disfigured mouth, disfigured teeth, half head, half face, blury, side looking, old, wrinkle, child, no face, pencil, full body, sharp, far away, overlapping, duplication, nude, disfigured, kitsch, oversaturated, grain, low-res, Deformed, blurry, bad anatomy, poorly drawn face, mutation, mutated, extra limb, ugly, poorly drawn hands, missing limb, blurry, floating limbs, disconnected limbs, malformed hands, blur, out of focus, long body, disgusting, poorly drawn, childish, mutilated, mangled, surreal, out of frame, duplicate, 2 faces", 113 | "width": 1024, 114 | "height": 1024, 115 | "model_version": "lcm", 116 | "stream": true 117 | }), 118 | ) 119 | ``` 120 | -------------------------------------------------------------------------------- /docs/image/kandinsky/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Kandinsky 2.1 3 | --- 4 | 5 | # Kandinsky 2.1 6 | POST *https://api.turing.sh/image/kandinsky* 7 | 8 | ## Parameters 9 | 10 | 11 | - **prompt** 12 | - Type: string 13 | - Required: true 14 | - Description: Prompt to generate the image 15 | 16 | - **steps** 17 | - Type: number 18 | - Required: false 19 | - Default: 100 20 | 21 | - **number** 22 | - Type: number 23 | - Required: false 24 | - Description: Number of images to generate 25 | - Default: 1 26 | 27 | - **negative_prompt** 28 | - Type: string 29 | - Required: false 30 | - Default: disfigured mouth, disfigured teeth, half head, half face, blury, side looking, old, wrinkle, child, no face, pencil, full body, sharp, far away, overlapping, duplication, nude, disfigured, kitsch, oversaturated, grain, low-res, Deformed, blurry, bad anatomy, poorly drawn face, mutation, mutated, extra limb, ugly, poorly drawn hands, missing limb, blurry, floating limbs, disconnected limbs, malformed hands, blur, out of focus, long body, disgusting, poorly drawn, childish, mutilated, mangled, surreal, out of frame, duplicate, 2 faces 31 | 32 | - **guidance_scale** 33 | - Type: number 34 | - Required: false 35 | - Default: 4 36 | 37 | - **width** 38 | - Type: number 39 | - Required: false 40 | - Default: 512 41 | 42 | - **height** 43 | - Type: number 44 | - Required: false 45 | - Default: 512 46 | 47 | - **cfg_scale** 48 | - Type: number 49 | - Required: false 50 | - Default: 4 51 | 52 | - **model_version** 53 | - Type: string 54 | - Required: false 55 | - Options: 2.1, 2.2 56 | - Default: 2.2 57 | 58 | - **stream** 59 | - Type: boolean 60 | - Required: false 61 | - Default: true 62 | 63 | ## Response 64 | 65 | 66 | - **cost** 67 | - Type: number 68 | 69 | - **results** 70 | - Type: array 71 | 72 | - **status** 73 | - Type: string 74 | 75 | - **progress** 76 | - Type: number 77 | 78 | - **id** 79 | - Type: string 80 | 81 | ## Examples 82 | 83 | 84 | ```typescript 85 | import axios from "axios"; 86 | (async () => { 87 | let response = await axios({ 88 | method: "post", 89 | url: 'https://api.turing.sh/image/kandinsky', 90 | headers: { 91 | "Content-Type": "application/json", 92 | Authorization: "Bearer YOUR_API_KEY", 93 | "x-captcha-token": "Captcha key" 94 | }, 95 | data: { 96 | "prompt": "string", 97 | "steps": 100, 98 | "number": 1, 99 | "negative_prompt": "disfigured mouth, disfigured teeth, half head, half face, blury, side looking, old, wrinkle, child, no face, pencil, full body, sharp, far away, overlapping, duplication, nude, disfigured, kitsch, oversaturated, grain, low-res, Deformed, blurry, bad anatomy, poorly drawn face, mutation, mutated, extra limb, ugly, poorly drawn hands, missing limb, blurry, floating limbs, disconnected limbs, malformed hands, blur, out of focus, long body, disgusting, poorly drawn, childish, mutilated, mangled, surreal, out of frame, duplicate, 2 faces", 100 | "guidance_scale": 4, 101 | "width": 512, 102 | "height": 512, 103 | "cfg_scale": 4, 104 | "model_version": "2.2", 105 | "stream": true 106 | }, 107 | }) 108 | })(); 109 | ``` 110 | ```python 111 | import requests 112 | import json 113 | response = requests.post( 114 | "https://api.turing.sh/image/kandinsky", 115 | headers={ 116 | "Content-Type": "application/json", 117 | "Authorization": "Bearer YOUR_API_KEY", 118 | "x-captcha-token": "Captcha key" 119 | }, 120 | data=json.dumps({ 121 | "prompt": "string", 122 | "steps": 100, 123 | "number": 1, 124 | "negative_prompt": "disfigured mouth, disfigured teeth, half head, half face, blury, side looking, old, wrinkle, child, no face, pencil, full body, sharp, far away, overlapping, duplication, nude, disfigured, kitsch, oversaturated, grain, low-res, Deformed, blurry, bad anatomy, poorly drawn face, mutation, mutated, extra limb, ugly, poorly drawn hands, missing limb, blurry, floating limbs, disconnected limbs, malformed hands, blur, out of focus, long body, disgusting, poorly drawn, childish, mutilated, mangled, surreal, out of frame, duplicate, 2 faces", 125 | "guidance_scale": 4, 126 | "width": 512, 127 | "height": 512, 128 | "cfg_scale": 4, 129 | "model_version": "2.2", 130 | "stream": true 131 | }), 132 | ) 133 | ``` 134 | -------------------------------------------------------------------------------- /docs/image/sdxl/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Stable Diffusion XL 3 | --- 4 | 5 | # Stable Diffusion XL 6 | POST *https://api.turing.sh/image/sdxl* 7 | 8 | ## Parameters 9 | 10 | 11 | - **prompt** 12 | - Type: string 13 | - Required: true 14 | 15 | - **negative_prompt** 16 | - Type: string 17 | - Required: false 18 | 19 | - **image** 20 | - Type: string 21 | - Required: false 22 | 23 | - **action** 24 | - Type: string 25 | - Required: true 26 | - Options: generate, img2img, upscale 27 | - Default: generate 28 | 29 | - **width** 30 | - Type: number 31 | - Required: false 32 | - Default: 512 33 | 34 | - **height** 35 | - Type: number 36 | - Required: false 37 | - Default: 512 38 | 39 | - **steps** 40 | - Type: number 41 | - Required: false 42 | - Default: 100 43 | 44 | - **number** 45 | - Type: number 46 | - Required: false 47 | - Default: 1 48 | 49 | - **sampler** 50 | - Type: string 51 | - Required: false 52 | - Options: DDIM, DDPM, K_DPMPP_2M, K_DPMPP_2S_ANCESTRAL, K_DPM_2, K_DPM_2_ANCESTRAL, K_EULER, K_EULER_ANCESTRAL, K_HEUN, K_LMS 53 | 54 | - **cfg_scale** 55 | - Type: number 56 | - Required: false 57 | - Default: 7 58 | 59 | - **seed** 60 | - Type: number 61 | - Required: false 62 | 63 | - **style** 64 | - Type: string 65 | - Required: false 66 | - Description: Style to use for generating the image 67 | - Options: 3d-model, analog-film, anime, cinematic, comic-book, digital-art, enhance, fantasy-art, isometric, line-art, low-poly, modeling-compound, neon-punk, origami, photographic, pixel-art, title-texture 68 | 69 | - **model** 70 | - Type: string 71 | - Required: false 72 | - Options: sdxl, sd-1.5, sd, sd-768, stable-diffusion-xl-1024-v0-9, stable-diffusion-v1, stable-diffusion-v1-5, stable-diffusion-512-v2-0, stable-diffusion-768-v2-0, stable-diffusion-depth-v2-0, stable-diffusion-512-v2-1, stable-diffusion-768-v2-1, stable-diffusion-xl-beta-v2-2-2 73 | - Default: sdxl 74 | 75 | - **strength** 76 | - Type: number 77 | - Required: false 78 | 79 | - **stream** 80 | - Type: boolean 81 | - Required: false 82 | - Default: true 83 | 84 | ## Response 85 | 86 | 87 | - **cost** 88 | - Type: number 89 | - Description: Cost of the request in USD 90 | 91 | - **results** 92 | - Type: array 93 | - Description: Results of the request 94 | 95 | - **status** 96 | - Type: string 97 | - Description: Status of the request 98 | 99 | - **progress** 100 | - Type: number 101 | - Description: Progress of the request 102 | 103 | - **id** 104 | - Type: string 105 | - Description: ID of the request 106 | 107 | - **error** 108 | - Type: string 109 | - Description: Error of the request 110 | 111 | ## Examples 112 | 113 | 114 | ```typescript 115 | import axios from "axios"; 116 | (async () => { 117 | let response = await axios({ 118 | method: "post", 119 | url: 'https://api.turing.sh/image/sdxl', 120 | headers: { 121 | "Content-Type": "application/json", 122 | Authorization: "Bearer YOUR_API_KEY", 123 | "x-captcha-token": "Captcha key" 124 | }, 125 | data: { 126 | "prompt": "string", 127 | "action": "generate", 128 | "width": 512, 129 | "height": 512, 130 | "steps": 100, 131 | "number": 1, 132 | "sampler": "DDIM", 133 | "cfg_scale": 7, 134 | "style": "3d-model", 135 | "model": "sdxl", 136 | "stream": true 137 | }, 138 | }) 139 | })(); 140 | ``` 141 | ```python 142 | import requests 143 | import json 144 | response = requests.post( 145 | "https://api.turing.sh/image/sdxl", 146 | headers={ 147 | "Content-Type": "application/json", 148 | "Authorization": "Bearer YOUR_API_KEY", 149 | "x-captcha-token": "Captcha key" 150 | }, 151 | data=json.dumps({ 152 | "prompt": "string", 153 | "action": "generate", 154 | "width": 512, 155 | "height": 512, 156 | "steps": 100, 157 | "number": 1, 158 | "sampler": "DDIM", 159 | "cfg_scale": 7, 160 | "style": "3d-model", 161 | "model": "sdxl", 162 | "stream": true 163 | }), 164 | ) 165 | ``` 166 | -------------------------------------------------------------------------------- /docs/image/sh/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Stablehorde 3 | --- 4 | 5 | # Stablehorde 6 | POST *https://api.turing.sh/image/sh* 7 | 8 | ## Parameters 9 | 10 | 11 | - **prompt** 12 | - Type: string 13 | - Required: true 14 | - Description: Prompt to generate the image 15 | 16 | - **negative_prompt** 17 | - Type: string 18 | - Required: false 19 | 20 | - **image** 21 | - Type: string 22 | - Required: false 23 | - Description: Image URL for the model to use when doing img2img 24 | 25 | - **width** 26 | - Type: number 27 | - Required: false 28 | - Default: 512 29 | 30 | - **height** 31 | - Type: number 32 | - Required: false 33 | - Default: 512 34 | 35 | - **steps** 36 | - Type: number 37 | - Required: false 38 | - Default: 50 39 | 40 | - **number** 41 | - Type: number 42 | - Required: false 43 | - Description: Number of images to generate 44 | - Default: 1 45 | 46 | - **strength** 47 | - Type: number 48 | - Required: false 49 | 50 | - **sampler** 51 | - Type: string 52 | - Required: false 53 | - Options: k_lms, k_heun, k_euler, k_euler_a, k_dpm_2, k_dpm_2_a, DDIM, k_dpm_fast, k_dpm_adaptive, k_dpmpp_2m, k_dpmpp_2s_a, k_dpmpp_sde 54 | 55 | - **cfg_scale** 56 | - Type: number 57 | - Required: false 58 | 59 | - **seed** 60 | - Type: number 61 | - Required: false 62 | 63 | - **model** 64 | - Type: string 65 | - Required: false 66 | - Options: SDXL 1.0, AlbedoBase XL (SDXL), ICBINP XL, TURBO XL, Fustercluck, stable_cascade 67 | - Default: stable_cascade 68 | 69 | - **nsfw** 70 | - Type: boolean 71 | - Required: false 72 | 73 | - **stream** 74 | - Type: boolean 75 | - Required: false 76 | - Default: true 77 | 78 | ## Response 79 | 80 | 81 | - **cost** 82 | - Type: number 83 | - Description: Cost of the request in USD 84 | 85 | - **id** 86 | - Type: string 87 | - Description: ID of the request 88 | 89 | - **status** 90 | - Type: string 91 | - Description: Status of the request 92 | 93 | - **progress** 94 | - Type: number 95 | - Description: Progress of the request 96 | 97 | - **queue_position** 98 | - Type: number 99 | - Description: Queue position of the request 100 | 101 | - **results** 102 | - Type: array 103 | - Description: Results of the request 104 | 105 | ## Examples 106 | 107 | 108 | ```typescript 109 | import axios from "axios"; 110 | (async () => { 111 | let response = await axios({ 112 | method: "post", 113 | url: 'https://api.turing.sh/image/sh', 114 | headers: { 115 | "Content-Type": "application/json", 116 | Authorization: "Bearer YOUR_API_KEY", 117 | "x-captcha-token": "Captcha key" 118 | }, 119 | data: { 120 | "prompt": "string", 121 | "width": 512, 122 | "height": 512, 123 | "steps": 50, 124 | "number": 1, 125 | "sampler": "k_lms", 126 | "model": "stable_cascade", 127 | "stream": true 128 | }, 129 | }) 130 | })(); 131 | ``` 132 | ```python 133 | import requests 134 | import json 135 | response = requests.post( 136 | "https://api.turing.sh/image/sh", 137 | headers={ 138 | "Content-Type": "application/json", 139 | "Authorization": "Bearer YOUR_API_KEY", 140 | "x-captcha-token": "Captcha key" 141 | }, 142 | data=json.dumps({ 143 | "prompt": "string", 144 | "width": 512, 145 | "height": 512, 146 | "steps": 50, 147 | "number": 1, 148 | "sampler": "k_lms", 149 | "model": "stable_cascade", 150 | "stream": true 151 | }), 152 | ) 153 | ``` 154 | -------------------------------------------------------------------------------- /docs/image/upscale/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Upscale models 3 | --- 4 | 5 | # Upscale models 6 | POST *https://api.turing.sh/image/upscale* 7 | 8 | ## Pricing 9 | 10 | 11 | - **Average:** 0.01 12 | 13 | ## Parameters 14 | 15 | 16 | - **upscaler** 17 | - Type: string 18 | - Required: false 19 | - Description: Upscaler to use, by selecting this you won't generate any image but you will upscale the image you provide 20 | - Options: GFPGAN, RealESRGAN_x4plus, RealESRGAN_x2plus, RealESRGAN_x4plus_anime_6B, NMKD_Siax, 4x_AnimeSharp 21 | - Default: RealESRGAN_x2plus 22 | 23 | - **image** 24 | - Type: string 25 | - Required: true 26 | - Description: Image URL for the model to use when doing the upscaling 27 | 28 | ## Response 29 | 30 | 31 | - **cost** 32 | - Type: number 33 | - Description: Cost of the request in USD 34 | 35 | - **result** 36 | - Type: string 37 | - Description: Object containing the upscaled image URL 38 | 39 | - **status** 40 | - Type: string 41 | - Description: Status of the request 42 | 43 | - **done** 44 | - Type: boolean 45 | - Description: Whether the request is done or not 46 | 47 | ## Examples 48 | 49 | 50 | ```typescript 51 | import axios from "axios"; 52 | (async () => { 53 | let response = await axios({ 54 | method: "post", 55 | url: 'https://api.turing.sh/image/upscale', 56 | headers: { 57 | "Content-Type": "application/json", 58 | Authorization: "Bearer YOUR_API_KEY", 59 | "x-captcha-token": "Captcha key" 60 | }, 61 | data: { 62 | "upscaler": "RealESRGAN_x2plus", 63 | "image": "string" 64 | }, 65 | }) 66 | })(); 67 | ``` 68 | ```python 69 | import requests 70 | import json 71 | response = requests.post( 72 | "https://api.turing.sh/image/upscale", 73 | headers={ 74 | "Content-Type": "application/json", 75 | "Authorization": "Bearer YOUR_API_KEY", 76 | "x-captcha-token": "Captcha key" 77 | }, 78 | data=json.dumps({ 79 | "upscaler": "RealESRGAN_x2plus", 80 | "image": "string" 81 | }), 82 | ) 83 | ``` 84 | -------------------------------------------------------------------------------- /docs/image/vision/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Image vision 3 | --- 4 | 5 | # Image vision 6 | POST *https://api.turing.sh/image/vision* 7 | 8 | ## Parameters 9 | 10 | 11 | - **model** 12 | - Type: array 13 | - Required: true 14 | - Description: Model to use for the analysis 15 | - Options: blip2, ocr, gemini 16 | - Default: gemini 17 | 18 | - **image** 19 | - Type: string 20 | - Required: true 21 | - Description: Image URL for the model to process 22 | 23 | - **typeImage** 24 | - Type: string 25 | - Required: false 26 | - Description: Type of image to process 27 | - Options: anything, person 28 | - Default: anything 29 | 30 | ## Response 31 | 32 | 33 | - **cost** 34 | - Type: number 35 | - Description: Cost of the request in USD 36 | 37 | - **description** 38 | - Type: string 39 | - Description: Description of the image 40 | 41 | - **text** 42 | - Type: string 43 | - Description: Text extracted from the image 44 | 45 | - **done** 46 | - Type: boolean 47 | - Description: Whether the request is done or not 48 | 49 | ## Examples 50 | 51 | 52 | ```typescript 53 | import axios from "axios"; 54 | (async () => { 55 | let response = await axios({ 56 | method: "post", 57 | url: 'https://api.turing.sh/image/vision', 58 | headers: { 59 | "Content-Type": "application/json", 60 | Authorization: "Bearer YOUR_API_KEY", 61 | "x-captcha-token": "Captcha key" 62 | }, 63 | data: { 64 | "model": [ 65 | "gemini" 66 | ], 67 | "image": "string", 68 | "typeImage": "anything" 69 | }, 70 | }) 71 | })(); 72 | ``` 73 | ```python 74 | import requests 75 | import json 76 | response = requests.post( 77 | "https://api.turing.sh/image/vision", 78 | headers={ 79 | "Content-Type": "application/json", 80 | "Authorization": "Bearer YOUR_API_KEY", 81 | "x-captcha-token": "Captcha key" 82 | }, 83 | data=json.dumps({ 84 | "model": [ 85 | "gemini" 86 | ], 87 | "image": "string", 88 | "typeImage": "anything" 89 | }), 90 | ) 91 | ``` 92 | -------------------------------------------------------------------------------- /docs/index.mdx: -------------------------------------------------------------------------------- 1 | # TuringAI API 2 | 3 | The best tool for developers to create AI-powered apps. 4 | 5 | ## What is TuringAI? 6 | 7 | TuringAI is an organization that bring the best AI models to the mass public for free. We believe that AI should be accessible to everyone, and we are working hard to make it happen. 8 | 9 | ## How to use TuringAI API? 10 | 11 | TuringAI API right now is still closed. We are working hard to make it public as soon as possible. If you want to use TuringAI API, please contact us in our [Discord server](https://discord.gg/turing). 12 | When the API is launched we will release some sdk for you to use in various languages such as Python, Javascript. In addition to that, we will also release some sample code for you to use. And the actual documentation containing all the information about the API will be released as well. 13 | 14 | ## How to contribute to TuringAI? 15 | 16 | You can support us by donating at [our page](https://app.turing.sh/pay). If you want to contribute to TuringAI as a developer, please contact us in our [Discord server](https://discord.gg/turing). 17 | 18 | ## How to contact TuringAI? 19 | 20 | The fastest way to contact us is through our [Discord server](https://discord.gg/turing). You can also contact us through our [Twitter](https://twitter.com/turing_ai_) 21 | -------------------------------------------------------------------------------- /docs/text/alan/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Alan 3 | --- 4 | 5 | # Alan 6 | POST *https://api.turing.sh/text/alan* 7 | This model is unfinished and is not working yet. 8 | 9 | 10 | ## Parameters 11 | 12 | 13 | - **userName** 14 | - Type: string 15 | - Required: true 16 | 17 | - **messages** 18 | - Type: array 19 | - Required: true 20 | 21 | - **searchEngine** 22 | - Type: string 23 | - Required: false 24 | - Options: google, none 25 | 26 | - **image** 27 | - Type: string 28 | - Required: false 29 | 30 | - **imageDescription** 31 | - Type: string 32 | - Required: false 33 | 34 | - **imageGenerator** 35 | - Type: string 36 | - Required: false 37 | - Options: sdxl, kandinsky, none 38 | 39 | - **nsfw** 40 | - Type: boolean 41 | - Required: false 42 | 43 | - **audioGenerator** 44 | - Type: string 45 | - Required: false 46 | - Options: musicgen 47 | 48 | - **imageModificator** 49 | - Type: string 50 | - Required: false 51 | - Options: controlnet, none 52 | 53 | - **max_tokens** 54 | - Type: number 55 | - Required: false 56 | - Default: 250 57 | 58 | ## Response 59 | 60 | Response not defined yet 61 | 62 | 63 | ## Examples 64 | 65 | 66 | ```typescript 67 | import axios from "axios"; 68 | (async () => { 69 | let response = await axios({ 70 | method: "post", 71 | url: 'https://api.turing.sh/text/alan', 72 | headers: { 73 | "Content-Type": "application/json", 74 | Authorization: "Bearer YOUR_API_KEY", 75 | "x-captcha-token": "Captcha key" 76 | }, 77 | data: { 78 | "userName": "string", 79 | "messages": "array", 80 | "searchEngine": "google", 81 | "imageGenerator": "sdxl", 82 | "audioGenerator": "musicgen", 83 | "imageModificator": "controlnet", 84 | "max_tokens": 250 85 | }, 86 | }) 87 | })(); 88 | ``` 89 | ```python 90 | import requests 91 | import json 92 | response = requests.post( 93 | "https://api.turing.sh/text/alan", 94 | headers={ 95 | "Content-Type": "application/json", 96 | "Authorization": "Bearer YOUR_API_KEY", 97 | "x-captcha-token": "Captcha key" 98 | }, 99 | data=json.dumps({ 100 | "userName": "string", 101 | "messages": "array", 102 | "searchEngine": "google", 103 | "imageGenerator": "sdxl", 104 | "audioGenerator": "musicgen", 105 | "imageModificator": "controlnet", 106 | "max_tokens": 250 107 | }), 108 | ) 109 | ``` 110 | -------------------------------------------------------------------------------- /docs/text/anthropic/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Anthropic Models 3 | --- 4 | 5 | # Anthropic Models 6 | POST *https://api.turing.sh/text/anthropic* 7 | 8 | ## Parameters 9 | 10 | 11 | - **messages** 12 | - Type: array 13 | - Required: true 14 | 15 | - **model** 16 | - Type: string 17 | - Required: false 18 | - Options: claude-instant-1.2, claude-2.1 19 | - Default: claude-instant-1.2 20 | 21 | - **max_tokens** 22 | - Type: number 23 | - Required: false 24 | - Default: 512 25 | 26 | - **temperature** 27 | - Type: number 28 | - Required: false 29 | - Default: 0.9 30 | 31 | - **stream** 32 | - Type: boolean 33 | - Required: false 34 | 35 | ## Response 36 | 37 | 38 | - **cost** 39 | - Type: number 40 | - Description: Cost of the request in USD 41 | 42 | - **result** 43 | - Type: string 44 | - Description: Result of the request 45 | 46 | ## Examples 47 | 48 | 49 | ```typescript 50 | import axios from "axios"; 51 | (async () => { 52 | let response = await axios({ 53 | method: "post", 54 | url: 'https://api.turing.sh/text/anthropic', 55 | headers: { 56 | "Content-Type": "application/json", 57 | Authorization: "Bearer YOUR_API_KEY", 58 | "x-captcha-token": "Captcha key" 59 | }, 60 | data: { 61 | "messages": "array", 62 | "model": "claude-instant-1.2", 63 | "max_tokens": 512, 64 | "temperature": 0.9 65 | }, 66 | }) 67 | })(); 68 | ``` 69 | ```python 70 | import requests 71 | import json 72 | response = requests.post( 73 | "https://api.turing.sh/text/anthropic", 74 | headers={ 75 | "Content-Type": "application/json", 76 | "Authorization": "Bearer YOUR_API_KEY", 77 | "x-captcha-token": "Captcha key" 78 | }, 79 | data=json.dumps({ 80 | "messages": "array", 81 | "model": "claude-instant-1.2", 82 | "max_tokens": 512, 83 | "temperature": 0.9 84 | }), 85 | ) 86 | ``` 87 | -------------------------------------------------------------------------------- /docs/text/filter/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Text Filter 3 | --- 4 | 5 | # Text Filter 6 | POST *https://api.turing.sh/text/filter* 7 | 8 | ## Parameters 9 | 10 | 11 | - **text** 12 | - Type: string 13 | - Required: true 14 | - Description: Text you want to filter 15 | 16 | - **filters** 17 | - Type: array 18 | - Required: true 19 | - Description: Filters you want to apply 20 | - Options: nsfw, cp, toxicity 21 | 22 | - **stream** 23 | - Type: boolean 24 | - Required: false 25 | 26 | ## Response 27 | 28 | 29 | - **nsfw** 30 | - Type: boolean 31 | - Description: Whether the text is nsfw or not 32 | 33 | - **youth** 34 | - Type: boolean 35 | - Description: Whether the text is youth or not 36 | 37 | - **cp** 38 | - Type: boolean 39 | - Description: Whether the text is cp or not 40 | 41 | - **toxic** 42 | - Type: boolean 43 | - Description: Whether the text is toxic or not 44 | 45 | - **done** 46 | - Type: boolean 47 | - Description: Whether the request is done or not 48 | 49 | ## Examples 50 | 51 | 52 | ```typescript 53 | import axios from "axios"; 54 | (async () => { 55 | let response = await axios({ 56 | method: "post", 57 | url: 'https://api.turing.sh/text/filter', 58 | headers: { 59 | "Content-Type": "application/json", 60 | Authorization: "Bearer YOUR_API_KEY", 61 | "x-captcha-token": "Captcha key" 62 | }, 63 | data: { 64 | "text": "string", 65 | "filters": "nsfw" 66 | }, 67 | }) 68 | })(); 69 | ``` 70 | ```python 71 | import requests 72 | import json 73 | response = requests.post( 74 | "https://api.turing.sh/text/filter", 75 | headers={ 76 | "Content-Type": "application/json", 77 | "Authorization": "Bearer YOUR_API_KEY", 78 | "x-captcha-token": "Captcha key" 79 | }, 80 | data=json.dumps({ 81 | "text": "string", 82 | "filters": "nsfw" 83 | }), 84 | ) 85 | ``` 86 | -------------------------------------------------------------------------------- /docs/text/google/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Google Models 3 | --- 4 | 5 | # Google Models 6 | POST *https://api.turing.sh/text/google* 7 | 8 | ## Parameters 9 | 10 | 11 | - **messages** 12 | - Type: array 13 | - Required: true 14 | 15 | - **model** 16 | - Type: string 17 | - Required: false 18 | - Options: gemini-pro, gemini-pro-vision 19 | - Default: gemini-pro 20 | 21 | - **max_tokens** 22 | - Type: number 23 | - Required: false 24 | - Default: 512 25 | 26 | - **temperature** 27 | - Type: number 28 | - Required: false 29 | - Default: 0.9 30 | 31 | - **id** 32 | - Type: string 33 | - Required: false 34 | - Description: ID of the conversation (used for data saving) 35 | - Default: bfb34ea4-dc9d-4f8e-b07d-e169e113d951 36 | 37 | ## Response 38 | 39 | 40 | - **cost** 41 | - Type: number 42 | - Description: Cost of the request in USD 43 | 44 | - **result** 45 | - Type: string 46 | - Description: Result of the request 47 | 48 | - **done** 49 | - Type: boolean 50 | - Description: Whether the request is done or not 51 | 52 | - **id** 53 | - Type: string 54 | - Description: ID of the conversation (used for data saving) 55 | 56 | ## Examples 57 | 58 | 59 | ```typescript 60 | import axios from "axios"; 61 | (async () => { 62 | let response = await axios({ 63 | method: "post", 64 | url: 'https://api.turing.sh/text/google', 65 | headers: { 66 | "Content-Type": "application/json", 67 | Authorization: "Bearer YOUR_API_KEY", 68 | "x-captcha-token": "Captcha key" 69 | }, 70 | data: { 71 | "messages": "array", 72 | "model": "gemini-pro", 73 | "max_tokens": 512, 74 | "temperature": 0.9, 75 | "id": "bfb34ea4-dc9d-4f8e-b07d-e169e113d951" 76 | }, 77 | }) 78 | })(); 79 | ``` 80 | ```python 81 | import requests 82 | import json 83 | response = requests.post( 84 | "https://api.turing.sh/text/google", 85 | headers={ 86 | "Content-Type": "application/json", 87 | "Authorization": "Bearer YOUR_API_KEY", 88 | "x-captcha-token": "Captcha key" 89 | }, 90 | data=json.dumps({ 91 | "messages": "array", 92 | "model": "gemini-pro", 93 | "max_tokens": 512, 94 | "temperature": 0.9, 95 | "id": "bfb34ea4-dc9d-4f8e-b07d-e169e113d951" 96 | }), 97 | ) 98 | ``` 99 | -------------------------------------------------------------------------------- /docs/text/gpt-new/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: OpenAI models 3 | --- 4 | 5 | # OpenAI models 6 | POST *https://api.turing.sh/text/gpt-new* 7 | 8 | ## Parameters 9 | 10 | 11 | - **messages** 12 | - Type: array 13 | - Required: true 14 | 15 | - **model** 16 | - Type: string 17 | - Required: true 18 | - Options: gpt-3.5-turbo, gpt-4, gpt-3.5-turbo-16k 19 | 20 | - **max_tokens** 21 | - Type: number 22 | - Required: false 23 | - Default: 512 24 | 25 | - **temperature** 26 | - Type: number 27 | - Required: false 28 | - Default: 0.9 29 | 30 | - **plugins** 31 | - Type: array 32 | - Required: false 33 | - Options: google, youtube-search, weather, wikipedia, tenor, alphavantage-stocks, alphavantage-crypto, alphavantage-forex, free-games, tasty, world-news, calculator, github, code-interpreter, diagrams, render-diagrams, planfit, wolfram, image, music 34 | - Default: 35 | 36 | - **id** 37 | - Type: string 38 | - Required: false 39 | - Description: ID of the conversation (used for data saving) 40 | - Default: b62f4cc5-0a7b-4044-9267-065c63c24469 41 | 42 | ## Response 43 | 44 | 45 | - **result** 46 | - Type: string 47 | 48 | - **done** 49 | - Type: boolean 50 | 51 | - **cost** 52 | - Type: number 53 | 54 | - **tool** 55 | - Type: object 56 | 57 | - **finishReason** 58 | - Type: string 59 | 60 | - **id** 61 | - Type: string 62 | - Description: ID of the conversation (used for data saving) 63 | 64 | ## Examples 65 | 66 | 67 | ```typescript 68 | import axios from "axios"; 69 | (async () => { 70 | let response = await axios({ 71 | method: "post", 72 | url: 'https://api.turing.sh/text/gpt-new', 73 | headers: { 74 | "Content-Type": "application/json", 75 | Authorization: "Bearer YOUR_API_KEY", 76 | "x-captcha-token": "Captcha key" 77 | }, 78 | data: { 79 | "messages": "array", 80 | "model": "gpt-3.5-turbo", 81 | "max_tokens": 512, 82 | "temperature": 0.9, 83 | "plugins": [], 84 | "id": "b62f4cc5-0a7b-4044-9267-065c63c24469" 85 | }, 86 | }) 87 | })(); 88 | ``` 89 | ```python 90 | import requests 91 | import json 92 | response = requests.post( 93 | "https://api.turing.sh/text/gpt-new", 94 | headers={ 95 | "Content-Type": "application/json", 96 | "Authorization": "Bearer YOUR_API_KEY", 97 | "x-captcha-token": "Captcha key" 98 | }, 99 | data=json.dumps({ 100 | "messages": "array", 101 | "model": "gpt-3.5-turbo", 102 | "max_tokens": 512, 103 | "temperature": 0.9, 104 | "plugins": [], 105 | "id": "b62f4cc5-0a7b-4044-9267-065c63c24469" 106 | }), 107 | ) 108 | ``` 109 | -------------------------------------------------------------------------------- /docs/text/groq/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: GroqCloud models 3 | --- 4 | 5 | # GroqCloud models 6 | POST *https://api.turing.sh/text/groq* 7 | 8 | ## Parameters 9 | 10 | 11 | - **messages** 12 | - Type: array 13 | - Required: true 14 | 15 | - **model** 16 | - Type: string 17 | - Required: false 18 | - Options: mixtral-8x7b-32768 19 | - Default: mixtral-8x7b-32768 20 | 21 | - **max_tokens** 22 | - Type: number 23 | - Required: false 24 | - Default: 512 25 | 26 | - **temperature** 27 | - Type: number 28 | - Required: false 29 | - Default: 0.9 30 | 31 | - **id** 32 | - Type: string 33 | - Required: false 34 | - Description: ID of the conversation (used for data saving) 35 | - Default: 7ab7480c-8e5d-4177-89a1-f90444798ae5 36 | 37 | ## Response 38 | 39 | 40 | - **result** 41 | - Type: string 42 | 43 | - **done** 44 | - Type: boolean 45 | 46 | - **cost** 47 | - Type: number 48 | 49 | - **finishReason** 50 | - Type: string 51 | 52 | - **id** 53 | - Type: string 54 | - Description: ID of the conversation (used for data saving) 55 | 56 | ## Examples 57 | 58 | 59 | ```typescript 60 | import axios from "axios"; 61 | (async () => { 62 | let response = await axios({ 63 | method: "post", 64 | url: 'https://api.turing.sh/text/groq', 65 | headers: { 66 | "Content-Type": "application/json", 67 | Authorization: "Bearer YOUR_API_KEY", 68 | "x-captcha-token": "Captcha key" 69 | }, 70 | data: { 71 | "messages": "array", 72 | "model": "mixtral-8x7b-32768", 73 | "max_tokens": 512, 74 | "temperature": 0.9, 75 | "id": "7ab7480c-8e5d-4177-89a1-f90444798ae5" 76 | }, 77 | }) 78 | })(); 79 | ``` 80 | ```python 81 | import requests 82 | import json 83 | response = requests.post( 84 | "https://api.turing.sh/text/groq", 85 | headers={ 86 | "Content-Type": "application/json", 87 | "Authorization": "Bearer YOUR_API_KEY", 88 | "x-captcha-token": "Captcha key" 89 | }, 90 | data=json.dumps({ 91 | "messages": "array", 92 | "model": "mixtral-8x7b-32768", 93 | "max_tokens": 512, 94 | "temperature": 0.9, 95 | "id": "7ab7480c-8e5d-4177-89a1-f90444798ae5" 96 | }), 97 | ) 98 | ``` 99 | -------------------------------------------------------------------------------- /docs/text/huggingface/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Huggingface based models 3 | --- 4 | 5 | # Huggingface based models 6 | POST *https://api.turing.sh/text/huggingface* 7 | 8 | ## Parameters 9 | 10 | 11 | - **messages** 12 | - Type: array 13 | - Required: false 14 | 15 | - **prompt** 16 | - Type: string 17 | - Required: false 18 | 19 | - **chat** 20 | - Type: boolean 21 | - Required: false 22 | 23 | - **model** 24 | - Type: string 25 | - Required: true 26 | - Options: OpenAssistant/oasst-sft-4-pythia-12b-epoch-3.5 27 | 28 | - **stop** 29 | - Type: string 30 | - Required: false 31 | 32 | ## Response 33 | 34 | 35 | - **cost** 36 | - Type: number 37 | - Description: Cost of the request in USD 38 | 39 | - **result** 40 | - Type: string 41 | - Description: Result of the request 42 | 43 | - **done** 44 | - Type: boolean 45 | - Description: Whether the request is done or not 46 | 47 | ## Examples 48 | 49 | 50 | ```typescript 51 | import axios from "axios"; 52 | (async () => { 53 | let response = await axios({ 54 | method: "post", 55 | url: 'https://api.turing.sh/text/huggingface', 56 | headers: { 57 | "Content-Type": "application/json", 58 | Authorization: "Bearer YOUR_API_KEY", 59 | "x-captcha-token": "Captcha key" 60 | }, 61 | data: { 62 | "model": "OpenAssistant/oasst-sft-4-pythia-12b-epoch-3.5" 63 | }, 64 | }) 65 | })(); 66 | ``` 67 | ```python 68 | import requests 69 | import json 70 | response = requests.post( 71 | "https://api.turing.sh/text/huggingface", 72 | headers={ 73 | "Content-Type": "application/json", 74 | "Authorization": "Bearer YOUR_API_KEY", 75 | "x-captcha-token": "Captcha key" 76 | }, 77 | data=json.dumps({ 78 | "model": "OpenAssistant/oasst-sft-4-pythia-12b-epoch-3.5" 79 | }), 80 | ) 81 | ``` 82 | -------------------------------------------------------------------------------- /docs/text/openchat/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: OpenChat models 3 | --- 4 | 5 | # OpenChat models 6 | POST *https://api.turing.sh/text/openchat* 7 | 8 | ## Parameters 9 | 10 | 11 | - **messages** 12 | - Type: array 13 | - Required: true 14 | 15 | - **model** 16 | - Type: string 17 | - Required: false 18 | - Options: openchat_v3.2_mistral 19 | - Default: openchat_v3.2_mistral 20 | 21 | - **max_tokens** 22 | - Type: number 23 | - Required: false 24 | - Default: 512 25 | 26 | - **temperature** 27 | - Type: number 28 | - Required: false 29 | - Default: 0.9 30 | 31 | - **id** 32 | - Type: string 33 | - Required: false 34 | - Description: ID of the conversation (used for data saving) 35 | - Default: a582c198-c87a-4180-bfc1-4b316bd21fb0 36 | 37 | - **autoSystemMessage** 38 | - Type: boolean 39 | - Required: false 40 | - Description: Send system messages automatically 41 | - Default: true 42 | 43 | ## Response 44 | 45 | 46 | - **result** 47 | - Type: string 48 | 49 | - **done** 50 | - Type: boolean 51 | 52 | - **cost** 53 | - Type: number 54 | 55 | - **finishReason** 56 | - Type: string 57 | 58 | - **id** 59 | - Type: string 60 | - Description: ID of the conversation (used for data saving) 61 | 62 | ## Examples 63 | 64 | 65 | ```typescript 66 | import axios from "axios"; 67 | (async () => { 68 | let response = await axios({ 69 | method: "post", 70 | url: 'https://api.turing.sh/text/openchat', 71 | headers: { 72 | "Content-Type": "application/json", 73 | Authorization: "Bearer YOUR_API_KEY", 74 | "x-captcha-token": "Captcha key" 75 | }, 76 | data: { 77 | "messages": "array", 78 | "model": "openchat_v3.2_mistral", 79 | "max_tokens": 512, 80 | "temperature": 0.9, 81 | "id": "a582c198-c87a-4180-bfc1-4b316bd21fb0", 82 | "autoSystemMessage": true 83 | }, 84 | }) 85 | })(); 86 | ``` 87 | ```python 88 | import requests 89 | import json 90 | response = requests.post( 91 | "https://api.turing.sh/text/openchat", 92 | headers={ 93 | "Content-Type": "application/json", 94 | "Authorization": "Bearer YOUR_API_KEY", 95 | "x-captcha-token": "Captcha key" 96 | }, 97 | data=json.dumps({ 98 | "messages": "array", 99 | "model": "openchat_v3.2_mistral", 100 | "max_tokens": 512, 101 | "temperature": 0.9, 102 | "id": "a582c198-c87a-4180-bfc1-4b316bd21fb0", 103 | "autoSystemMessage": true 104 | }), 105 | ) 106 | ``` 107 | -------------------------------------------------------------------------------- /docs/text/other/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Other models 3 | --- 4 | 5 | # Other models 6 | POST *https://api.turing.sh/text/other* 7 | 8 | ## Parameters 9 | 10 | 11 | - **messages** 12 | - Type: array 13 | - Required: true 14 | 15 | - **model** 16 | - Type: string 17 | - Required: true 18 | - Options: llama2 19 | 20 | - **max_tokens** 21 | - Type: number 22 | - Required: false 23 | - Default: 300 24 | 25 | - **temperature** 26 | - Type: number 27 | - Required: false 28 | - Default: 0.7 29 | 30 | - **stream** 31 | - Type: boolean 32 | - Required: false 33 | 34 | ## Response 35 | 36 | 37 | - **cost** 38 | - Type: number 39 | - Description: Cost of the request in USD 40 | 41 | - **result** 42 | - Type: string 43 | - Description: Result of the request 44 | 45 | - **status** 46 | - Type: string 47 | - Description: Status of the request 48 | 49 | - **done** 50 | - Type: boolean 51 | - Description: Whether the request is done or not 52 | 53 | ## Examples 54 | 55 | 56 | ```typescript 57 | import axios from "axios"; 58 | (async () => { 59 | let response = await axios({ 60 | method: "post", 61 | url: 'https://api.turing.sh/text/other', 62 | headers: { 63 | "Content-Type": "application/json", 64 | Authorization: "Bearer YOUR_API_KEY", 65 | "x-captcha-token": "Captcha key" 66 | }, 67 | data: { 68 | "messages": "array", 69 | "model": "llama2", 70 | "max_tokens": 300, 71 | "temperature": 0.7 72 | }, 73 | }) 74 | })(); 75 | ``` 76 | ```python 77 | import requests 78 | import json 79 | response = requests.post( 80 | "https://api.turing.sh/text/other", 81 | headers={ 82 | "Content-Type": "application/json", 83 | "Authorization": "Bearer YOUR_API_KEY", 84 | "x-captcha-token": "Captcha key" 85 | }, 86 | data=json.dumps({ 87 | "messages": "array", 88 | "model": "llama2", 89 | "max_tokens": 300, 90 | "temperature": 0.7 91 | }), 92 | ) 93 | ``` 94 | -------------------------------------------------------------------------------- /docs/text/pawan/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Pawan.krd models 3 | --- 4 | 5 | # Pawan.krd models 6 | POST *https://api.turing.sh/text/pawan* 7 | 8 | ## Parameters 9 | 10 | 11 | - **messages** 12 | - Type: array 13 | - Required: true 14 | 15 | - **model** 16 | - Type: string 17 | - Required: false 18 | - Options: zephyr-7b-beta, pai-001-light-beta 19 | - Default: zephyr-7b-beta 20 | 21 | - **max_tokens** 22 | - Type: number 23 | - Required: false 24 | - Default: 512 25 | 26 | - **temperature** 27 | - Type: number 28 | - Required: false 29 | - Default: 0.9 30 | 31 | - **id** 32 | - Type: string 33 | - Required: false 34 | - Description: ID of the conversation (used for data saving) 35 | - Default: 9bed6ed8-6040-4cd1-84a3-68a414d7a731 36 | 37 | - **autoSystemMessage** 38 | - Type: boolean 39 | - Required: false 40 | - Description: Send system messages automatically 41 | - Default: true 42 | 43 | ## Response 44 | 45 | 46 | - **result** 47 | - Type: string 48 | 49 | - **done** 50 | - Type: boolean 51 | 52 | - **cost** 53 | - Type: number 54 | 55 | - **finishReason** 56 | - Type: string 57 | 58 | - **id** 59 | - Type: string 60 | - Description: ID of the conversation (used for data saving) 61 | 62 | ## Examples 63 | 64 | 65 | ```typescript 66 | import axios from "axios"; 67 | (async () => { 68 | let response = await axios({ 69 | method: "post", 70 | url: 'https://api.turing.sh/text/pawan', 71 | headers: { 72 | "Content-Type": "application/json", 73 | Authorization: "Bearer YOUR_API_KEY", 74 | "x-captcha-token": "Captcha key" 75 | }, 76 | data: { 77 | "messages": "array", 78 | "model": "zephyr-7b-beta", 79 | "max_tokens": 512, 80 | "temperature": 0.9, 81 | "id": "9bed6ed8-6040-4cd1-84a3-68a414d7a731", 82 | "autoSystemMessage": true 83 | }, 84 | }) 85 | })(); 86 | ``` 87 | ```python 88 | import requests 89 | import json 90 | response = requests.post( 91 | "https://api.turing.sh/text/pawan", 92 | headers={ 93 | "Content-Type": "application/json", 94 | "Authorization": "Bearer YOUR_API_KEY", 95 | "x-captcha-token": "Captcha key" 96 | }, 97 | data=json.dumps({ 98 | "messages": "array", 99 | "model": "zephyr-7b-beta", 100 | "max_tokens": 512, 101 | "temperature": 0.9, 102 | "id": "9bed6ed8-6040-4cd1-84a3-68a414d7a731", 103 | "autoSystemMessage": true 104 | }), 105 | ) 106 | ``` 107 | -------------------------------------------------------------------------------- /docs/text/translate/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Translate text 3 | --- 4 | 5 | # Translate text 6 | POST *https://api.turing.sh/text/translate* 7 | 8 | ## Parameters 9 | 10 | 11 | - **text** 12 | - Type: string 13 | - Required: true 14 | - Description: Text to translate 15 | 16 | - **from** 17 | - Type: string 18 | - Required: false 19 | - Description: Language code to translate from 20 | - Default: auto 21 | 22 | - **to** 23 | - Type: string 24 | - Required: true 25 | - Description: Language code to translate to 26 | 27 | - **ai** 28 | - Type: string 29 | - Required: true 30 | - Options: google, microsoft 31 | - Default: google 32 | 33 | ## Response 34 | 35 | Response not defined yet 36 | 37 | 38 | ## Examples 39 | 40 | 41 | ```typescript 42 | import axios from "axios"; 43 | (async () => { 44 | let response = await axios({ 45 | method: "post", 46 | url: 'https://api.turing.sh/text/translate', 47 | headers: { 48 | "Content-Type": "application/json", 49 | Authorization: "Bearer YOUR_API_KEY", 50 | "x-captcha-token": "Captcha key" 51 | }, 52 | data: { 53 | "text": "string", 54 | "from": "auto", 55 | "to": "string", 56 | "ai": "google" 57 | }, 58 | }) 59 | })(); 60 | ``` 61 | ```python 62 | import requests 63 | import json 64 | response = requests.post( 65 | "https://api.turing.sh/text/translate", 66 | headers={ 67 | "Content-Type": "application/json", 68 | "Authorization": "Bearer YOUR_API_KEY", 69 | "x-captcha-token": "Captcha key" 70 | }, 71 | data=json.dumps({ 72 | "text": "string", 73 | "from": "auto", 74 | "to": "string", 75 | "ai": "google" 76 | }), 77 | ) 78 | ``` 79 | -------------------------------------------------------------------------------- /docs/video/zelescope/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Zelescope 3 | --- 4 | 5 | # Zelescope 6 | POST *https://api.turing.sh/video/zelescope* 7 | This model is not yet implemented 8 | 9 | 10 | ## Parameters 11 | 12 | 13 | - **prompt** 14 | - Type: string 15 | - Required: true 16 | 17 | - **duration** 18 | - Type: number 19 | - Required: false 20 | - Default: 10 21 | 22 | ## Response 23 | 24 | Response not defined yet 25 | 26 | 27 | ## Examples 28 | 29 | 30 | ```typescript 31 | import axios from "axios"; 32 | (async () => { 33 | let response = await axios({ 34 | method: "post", 35 | url: 'https://api.turing.sh/video/zelescope', 36 | headers: { 37 | "Content-Type": "application/json", 38 | Authorization: "Bearer YOUR_API_KEY", 39 | "x-captcha-token": "Captcha key" 40 | }, 41 | data: { 42 | "prompt": "string", 43 | "duration": 10 44 | }, 45 | }) 46 | })(); 47 | ``` 48 | ```python 49 | import requests 50 | import json 51 | response = requests.post( 52 | "https://api.turing.sh/video/zelescope", 53 | headers={ 54 | "Content-Type": "application/json", 55 | "Authorization": "Bearer YOUR_API_KEY", 56 | "x-captcha-token": "Captcha key" 57 | }, 58 | data=json.dumps({ 59 | "prompt": "string", 60 | "duration": 10 61 | }), 62 | ) 63 | ``` 64 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "turing-api", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "dist/index.js", 6 | "type": "module", 7 | "scripts": { 8 | "build": "tsc", 9 | "start": "tsc && node dist/index.js", 10 | "git": "git fetch && git pull", 11 | "docs": "tsc && node dist/rundocs.js" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/TuringAI-Team/turing-ai-api.git" 16 | }, 17 | "author": "TuringAI", 18 | "license": "Apache-2.0", 19 | "bugs": { 20 | "url": "https://github.com/TuringAI-Team/turing-ai-api/issues" 21 | }, 22 | "homepage": "https://github.com/TuringAI-Team/turing-ai-api#readme", 23 | "dependencies": { 24 | "@anthropic-ai/sdk": "^0.6.2", 25 | "@dqbd/tiktoken": "^1.0.7", 26 | "@google-cloud/vertexai": "^0.1.3", 27 | "@huggingface/inference": "^2.5.2", 28 | "@mermaid-js/mermaid-cli": "^10.3.0", 29 | "@octokit/rest": "^19.0.13", 30 | "@sellix/node-sdk": "^1.0.9", 31 | "@supabase/supabase-js": "^2.33.1", 32 | "@waylaidwanderer/fetch-event-source": "^3.0.1", 33 | "axios": "^1.5.0", 34 | "canvas": "^2.11.2", 35 | "chalk": "^5.3.0", 36 | "chartjs-to-image": "^1.2.1", 37 | "cors": "^2.8.5", 38 | "delay": "^6.0.0", 39 | "dotenv": "^16.3.1", 40 | "express": "^4.18.2", 41 | "express-rate-limit": "^6.11.0", 42 | "fluent-ffmpeg": "^2.1.2", 43 | "google-auth-library": "^8.9.0", 44 | "google-tts-api": "^2.0.2", 45 | "googlethis": "^1.7.1", 46 | "groq-sdk": "^0.3.1", 47 | "hcaptcha": "^0.1.1", 48 | "helmet": "^7.0.0", 49 | "jsonwebtoken": "^9.0.2", 50 | "lang-detector": "^1.0.6", 51 | "mathjs": "^11.11.0", 52 | "openai": "^3.3.0", 53 | "puppeteer": "^19.11.1", 54 | "puppeteer-core": "^21.1.1", 55 | "rabbitmq-client": "^4.3.0", 56 | "redis": "^4.6.8", 57 | "replicate-api": "^0.4.4", 58 | "turing.sh": "^0.0.9", 59 | "uuid": "^9.0.0", 60 | "wandbox-api-updated": "^1.0.3", 61 | "yt-search": "^2.10.4" 62 | }, 63 | "devDependencies": { 64 | "@types/node": "^20.5.9", 65 | "typescript": "^5.2.2" 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/db/mq.ts: -------------------------------------------------------------------------------- 1 | import { Connection } from "rabbitmq-client"; 2 | import log from "../utils/log.js"; 3 | const rabbit = new Connection(process.env.MQ_URL); 4 | rabbit.on("error", (err) => { 5 | log("error", "RabbitMQ connection error", err); 6 | }); 7 | rabbit.on("connection", () => { 8 | log("info", "RabbitMQ connected"); 9 | }); 10 | 11 | const pub = rabbit.createPublisher({ 12 | // Enable publish confirmations, similar to consumer acknowledgements 13 | confirm: true, 14 | // Enable retries 15 | maxAttempts: 2, 16 | // Optionally ensure the existence of an exchange before we use it 17 | exchanges: [{ exchange: "db", type: "topic" }], 18 | }); 19 | export { pub }; 20 | export default rabbit; 21 | -------------------------------------------------------------------------------- /src/db/redis.ts: -------------------------------------------------------------------------------- 1 | import { createClient, defineScript } from "redis"; 2 | 3 | let port: any = process.env.REDIS_PORT; 4 | const redisClient = createClient({ 5 | password: process.env.REDIS_PASSWORD || "password", 6 | socket: { 7 | host: process.env.REDIS_HOST || "localhost", 8 | port: port, 9 | }, 10 | }); 11 | 12 | redisClient.on("error", (err) => console.log("Client error: Redis", err)); 13 | 14 | await redisClient.connect(); 15 | 16 | export default redisClient; 17 | -------------------------------------------------------------------------------- /src/db/supabase.ts: -------------------------------------------------------------------------------- 1 | import { createClient } from "@supabase/supabase-js"; 2 | 3 | const supabaseUrl = process.env.SUPABASE_URL as string; 4 | const supabaseKey = process.env.SUPABASE_KEY as string; 5 | const supabase = createClient(supabaseUrl, supabaseKey); 6 | 7 | export default supabase; -------------------------------------------------------------------------------- /src/handlers/audio.ts: -------------------------------------------------------------------------------- 1 | import path from "node:path"; 2 | import fs from "node:fs"; 3 | import { fileURLToPath } from "url"; 4 | import log from "../utils/log.js"; 5 | const __filename = fileURLToPath(import.meta.url); 6 | const __dirname = path.dirname(__filename); 7 | 8 | export default async function audioHandler(client) { 9 | if (client.audio.length > 0) return; 10 | const audios = []; 11 | const audioPath = path.join(__dirname, "../models/audio"); 12 | 13 | const audioFils = fs 14 | .readdirSync(audioPath) 15 | .filter((file) => file.endsWith(".js")); 16 | 17 | for (const file of audioFils) { 18 | const filePath = `../models/audio/${file}`; 19 | const { default: audio } = await import(filePath); 20 | // Set a new item in the Collection with the key as the command name and the value as the exported module 21 | if ("data" in audio && "execute" in audio) { 22 | audios.push(audio); 23 | } else { 24 | log( 25 | "warning", 26 | `The command at ${filePath} is missing a required "data" or "execute" property.` 27 | ); 28 | } 29 | } 30 | client.audio = audios; 31 | log("info", `Loaded ${audios.length} audio models.`); 32 | } 33 | -------------------------------------------------------------------------------- /src/handlers/image.ts: -------------------------------------------------------------------------------- 1 | import path from "node:path"; 2 | import fs from "node:fs"; 3 | import { fileURLToPath } from "url"; 4 | import log from "../utils/log.js"; 5 | const __filename = fileURLToPath(import.meta.url); 6 | const __dirname = path.dirname(__filename); 7 | 8 | export default async function imageHandler(client) { 9 | if (client.image.length > 0) return; 10 | const images = []; 11 | const imagePath = path.join(__dirname, "../models/image"); 12 | 13 | const imageFiles = fs 14 | .readdirSync(imagePath) 15 | .filter((file) => file.endsWith(".js")); 16 | 17 | for (const file of imageFiles) { 18 | const filePath = `../models/image/${file}`; 19 | const { default: image } = await import(filePath); 20 | if (!image) { 21 | log( 22 | "warning", 23 | `The command at ${filePath} is missing a required "data" or "execute" property.` 24 | ); 25 | continue; 26 | } 27 | // Set a new item in the Collection with the key as the command name and the value as the exported module 28 | if ("data" in image && "execute" in image) { 29 | images.push(image); 30 | } else { 31 | log( 32 | "warning", 33 | `The command at ${filePath} is missing a required "data" or "execute" property.` 34 | ); 35 | } 36 | } 37 | client.image = images; 38 | log("info", `Loaded ${images.length} image models.`); 39 | } 40 | -------------------------------------------------------------------------------- /src/handlers/text.ts: -------------------------------------------------------------------------------- 1 | import path from "node:path"; 2 | import fs from "node:fs"; 3 | import { fileURLToPath } from "url"; 4 | import log from "../utils/log.js"; 5 | const __filename = fileURLToPath(import.meta.url); 6 | const __dirname = path.dirname(__filename); 7 | 8 | export default async function textHandler(client) { 9 | if (client.text.length > 0) return; 10 | const texts = []; 11 | const textPath = path.join(__dirname, "../models/text"); 12 | 13 | const textFiles = fs 14 | .readdirSync(textPath) 15 | .filter((file) => file.endsWith(".js")); 16 | 17 | for (const file of textFiles) { 18 | const filePath = `../models/text/${file}`; 19 | const { default: text } = await import(filePath); 20 | // Set a new item in the Collection with the key as the command name and the value as the exported module 21 | if ("data" in text && "execute" in text) { 22 | texts.push(text); 23 | } else { 24 | log( 25 | "warning", 26 | `The command at ${filePath} is missing a required "data" or "execute" property.` 27 | ); 28 | } 29 | } 30 | client.text = texts; 31 | log("info", `Loaded ${texts.length} text models.`); 32 | } 33 | -------------------------------------------------------------------------------- /src/handlers/video.ts: -------------------------------------------------------------------------------- 1 | import path from "node:path"; 2 | import fs from "node:fs"; 3 | import { fileURLToPath } from "url"; 4 | import log from "../utils/log.js"; 5 | const __filename = fileURLToPath(import.meta.url); 6 | const __dirname = path.dirname(__filename); 7 | 8 | export default async function videoHandler(client) { 9 | if (client.video.length > 0) return; 10 | const videos = []; 11 | const videoPath = path.join(__dirname, "../models/video"); 12 | 13 | const videoFiles = fs 14 | .readdirSync(videoPath) 15 | .filter((file) => file.endsWith(".js")); 16 | 17 | for (const file of videoFiles) { 18 | const filePath = `../models/video/${file}`; 19 | const { default: video } = await import(filePath); 20 | if (!video) { 21 | log( 22 | "warning", 23 | `The command at ${filePath} is missing a required "data" or "execute" property.` 24 | ); 25 | continue; 26 | } 27 | // Set a new item in the Collection with the key as the command name and the value as the exported module 28 | if ("data" in video && "execute" in video) { 29 | videos.push(video); 30 | } else { 31 | log( 32 | "warning", 33 | `The command at ${filePath} is missing a required "data" or "execute" property.` 34 | ); 35 | } 36 | } 37 | client.video = videos; 38 | log("info", `Loaded ${videos.length} video models.`); 39 | } 40 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import express, { Application, Request, Response } from "express"; 2 | import helmet from "helmet"; 3 | import cors from "cors"; 4 | import "dotenv/config"; 5 | import { generateKey } from "./utils/key.js"; 6 | import rateLimit from "express-rate-limit"; 7 | 8 | // routes 9 | import OtherRoutes from "./routes/other.routes.js"; 10 | import ChartRoutes from "./routes/chart.routes.js"; 11 | import PaymentRoutes from "./routes/payment.routes.js"; 12 | import DataRoutes from "./routes/data.routes.js"; 13 | import RunpodRoutes from "./routes/runpod.routes.js"; 14 | import ModelRoutes from "./routes/models.routes.js"; 15 | import KeyRoutes from "./routes/key.routes.js"; 16 | 17 | const app: Application = express(); 18 | 19 | import { verifyToken } from "./middlewares/key.js"; 20 | import Ciclic from "./utils/ciclic.js"; 21 | import textHandler from "./handlers/text.js"; 22 | import imageHandler from "./handlers/image.js"; 23 | import audioHandler from "./handlers/audio.js"; 24 | import { autogenerateDocs } from "./utils/docs.js"; 25 | import log from "./utils/log.js"; 26 | import videoHandler from "./handlers/video.js"; 27 | const client = { 28 | text: [], 29 | image: [], 30 | audio: [], 31 | video: [], 32 | }; 33 | 34 | const limiter = rateLimit({ 35 | windowMs: 1000, // 15 minutes 36 | max: 20, // Limit each IP to 100 requests per `window` (here, per 15 minutes) 37 | standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers 38 | legacyHeaders: false, // Disable the `X-RateLimit-*` headers 39 | }); 40 | 41 | // Apply the rate limiting middleware to all requests 42 | app.use(limiter); 43 | app.use(helmet()); 44 | app.use( 45 | cors({ 46 | origin: [ 47 | "http://localhost:3000", 48 | "https://app.turing-ai.xyz", 49 | "https://app.turing.sh", 50 | "https://sellix.io", 51 | "https://sellix.pw", 52 | "https://sellix.xyz", 53 | "https://sellix.gg", 54 | ], 55 | methods: ["GET", "POST", "PUT", "DELETE"], 56 | allowedHeaders: ["Content-Type", "Authorization", "x-captcha-token"], 57 | }) 58 | ); 59 | app.use(express.json({ limit: "50mb" })); 60 | app.use(express.urlencoded({ limit: "50mb", extended: true })); 61 | app.set("port", process.env.PORT || 3000); 62 | 63 | app.use("/key", KeyRoutes); 64 | app.use("/other", OtherRoutes); 65 | app.use("/chart", ChartRoutes); 66 | app.use("/payments", PaymentRoutes); 67 | app.use("/data", DataRoutes); 68 | app.use("/runpod", RunpodRoutes); 69 | app.use("/", ModelRoutes); 70 | 71 | app.listen(app.get("port"), async () => { 72 | log("info", `Server is running on port ${app.get("port")}`); 73 | await textHandler(client); 74 | await imageHandler(client); 75 | await audioHandler(client); 76 | await videoHandler(client); 77 | await Ciclic(); 78 | 79 | if (process.env.NODE_ENV != "production") { 80 | await autogenerateDocs(client); 81 | } 82 | }); 83 | 84 | export default client; 85 | -------------------------------------------------------------------------------- /src/middlewares/captchas/hcaptchas.ts: -------------------------------------------------------------------------------- 1 | import { verify } from "hcaptcha"; 2 | import { checkCaptchaToken } from "../../utils/key.js"; 3 | 4 | export default async function (req, res, next) { 5 | // captcha token is on headers 6 | const token = req.headers["x-captcha-token"]; 7 | if (!token) { 8 | return res.status(400).json({ error: "Captcha token is required" }); 9 | } 10 | try { 11 | let valid = await checkCaptchaToken(token, req); 12 | if (valid) { 13 | return next(); 14 | } 15 | const data = await verify(process.env.HCAPTCHA_SECRET as string, token); 16 | if (data.success) { 17 | return next(); 18 | } 19 | return res.status(400).json({ error: "Invalid captcha" }); 20 | } catch (err) { 21 | return res.status(400).json({ error: "Invalid captcha" }); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/middlewares/captchas/turnstile.ts: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import { checkCaptchaToken } from "../../utils/key.js"; 3 | export default async function (req, res, next) { 4 | // captcha token is on headers 5 | const token = req.headers["x-captcha-token"]; 6 | if (!token) { 7 | return res.status(400).json({ error: "Captcha token is required" }); 8 | } 9 | try { 10 | let valid: any = await checkCaptchaToken(token, req); 11 | if (valid.error) { 12 | return res.status(400).json({ error: valid.error }); 13 | } 14 | if (valid.user) { 15 | req.user = valid.user; 16 | req.keyId = valid.apiId; 17 | return next(); 18 | } 19 | if (valid) { 20 | return next(); 21 | } 22 | const data = await validate(process.env.TURNSTILE_SECRET as string, token); 23 | if (data.success) { 24 | return next(); 25 | } 26 | return res.status(400).json({ error: "Invalid captcha" }); 27 | } catch (err) { 28 | console.log(err); 29 | return res.status(400).json({ error: "Invalid captcha" }); 30 | } 31 | } 32 | const API_URL: string = 33 | "https://challenges.cloudflare.com/turnstile/v0/siteverify"; 34 | async function validate(secret: string, token: string, ip?: string) { 35 | let formData = new URLSearchParams(); 36 | formData.append("secret", secret); 37 | formData.append("response", token); 38 | if (ip) { 39 | formData.append("remoteip", ip); 40 | } 41 | 42 | var res = await axios({ 43 | url: API_URL, 44 | data: formData, 45 | method: "POST", 46 | headers: { "Content-Type": "application/x-www-form-urlencoded" }, 47 | }); 48 | var data: { 49 | success: boolean; 50 | "error-codes": Array; 51 | challenge_ts?: string; 52 | hostname?: string; 53 | action?: string; 54 | cdata?: string; 55 | } = res.data; 56 | /* Error descriptions */ 57 | var error = data["error-codes"][0]; 58 | if (error) { 59 | switch (error) { 60 | case "missing-input-secret": 61 | return { 62 | error: "The secret parameter was not passed.", 63 | ...data, 64 | }; 65 | case "invalid-input-secret": 66 | return { 67 | error: "The secret parameter was invalid or did not exist.", 68 | ...data, 69 | }; 70 | case "missing-input-response": 71 | return { 72 | error: "The response(token) parameter was not passed.", 73 | ...data, 74 | }; 75 | case "invalid-input-response": 76 | return { 77 | error: "The response(token) parameter is invalid or has expired.", 78 | ...data, 79 | }; 80 | case "bad-request": 81 | return { 82 | error: "The request was rejected because it was malformed.", 83 | ...data, 84 | }; 85 | case "timeout-or-duplicate": 86 | return { 87 | error: "The response parameter has already been validated before.", 88 | ...data, 89 | }; 90 | case "internal-error": 91 | return { 92 | error: 93 | "An internal error happened while validating the response. The request can be retried.", 94 | ...data, 95 | }; 96 | } 97 | } 98 | return data; 99 | } 100 | -------------------------------------------------------------------------------- /src/middlewares/geo.ts: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import { Request, Response, NextFunction } from "express"; 3 | 4 | export default async function geo(req: any, res: Response, next: NextFunction) { 5 | var ip = 6 | (req.headers["x-forwarded-for"] as string) || 7 | (req.socket.remoteAddress as string); 8 | ip = ip.split(", ")[1]; 9 | try { 10 | const apiUrl = `http://ip-api.com/json/${ip}`; 11 | const { data } = await axios.get(apiUrl); 12 | req.geo = data; 13 | // log geo and user agent 14 | console.log(data, req.headers["user-agent"]); 15 | next(); 16 | } catch (error) { 17 | console.log(error); 18 | req.geo = { 19 | country_name: "Unknown", 20 | }; 21 | next(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/middlewares/key.ts: -------------------------------------------------------------------------------- 1 | import jwt from "jsonwebtoken"; 2 | import supabase from "../db/supabase.js"; 3 | import { Request, Response } from "express"; 4 | import redisClient from "../db/redis.js"; 5 | 6 | export async function verifyToken(token: string, req) { 7 | // verify token 8 | try { 9 | let decoded = jwt.verify(token, process.env.SECRET_KEY); 10 | if (!decoded) { 11 | // decode supabase access token 12 | const { data, error } = await supabase.auth.getUser(token); 13 | if (error) { 14 | console.log(error); 15 | return false; 16 | } 17 | return true; 18 | } else { 19 | let data: any = await redisClient.get(`api:${token}`); 20 | data = JSON.parse(data); 21 | if (!data) { 22 | return false; 23 | } 24 | if (data.allowedPaths && data.userId != "530102778408861706") { 25 | let allowed = false; 26 | if (data.allowedPaths.find((path) => path == "*")) { 27 | allowed = true; 28 | } else { 29 | for (let path of data.allowedPaths) { 30 | path = path.replace("*", ""); 31 | if (req.path.startsWith(path)) { 32 | allowed = true; 33 | } 34 | } 35 | } 36 | if (!allowed) { 37 | return { 38 | error: "You don't have permissions to use this endpoint", 39 | }; 40 | } 41 | } 42 | return { 43 | apiData: data, 44 | }; 45 | } 46 | } catch (err) { 47 | const { data, error } = await supabase.auth.getUser(token); 48 | if (error) { 49 | console.log(error); 50 | return false; 51 | } 52 | return true; 53 | } 54 | } 55 | export default async (req: Request, res: Response, next) => { 56 | if (req.headers.authorization) { 57 | const token = req.headers.authorization; 58 | if (token) { 59 | var isvalid: any = await verifyToken( 60 | token.replaceAll("Bearer ", ""), 61 | req 62 | ); 63 | if (isvalid.error) { 64 | res.status(401).send({ error: isvalid.error }); 65 | return; 66 | } 67 | if (isvalid.apiData) { 68 | req.apiData = isvalid.apiData; 69 | next(); 70 | return; 71 | } 72 | if (isvalid) { 73 | next(); 74 | } else { 75 | res.status(401).send({ error: "Unauthorized, no valid token" }); 76 | } 77 | } else { 78 | res.status(401).send({ error: "Unauthorized, no token provided(1)" }); 79 | } 80 | } else { 81 | res.status(401).send({ error: "Unauthorized, no token provided" }); 82 | } 83 | }; 84 | -------------------------------------------------------------------------------- /src/models/audio/music.ts: -------------------------------------------------------------------------------- 1 | import { request, translateModels } from "../../utils/runpod.js"; 2 | import { EventEmitter } from "events"; 3 | 4 | export default { 5 | data: { 6 | name: "music", 7 | fullName: "Music generation", 8 | parameters: { 9 | prompt: { 10 | type: "string", 11 | required: true, 12 | }, 13 | model: { 14 | type: "string", 15 | required: false, 16 | options: ["small", "medium", "melody", "large"], 17 | default: "small", 18 | }, 19 | duration: { 20 | type: "number", 21 | required: false, 22 | default: 8, 23 | }, 24 | stream: { 25 | type: "boolean", 26 | required: false, 27 | default: false, 28 | }, 29 | }, 30 | }, 31 | execute: async (data) => { 32 | let { prompt, model, duration, stream } = data; 33 | if (!model) { 34 | model = "small"; 35 | } 36 | if (!duration) { 37 | duration = 8; 38 | } 39 | let url = await translateModels("musicgen"); 40 | let res = await request(url, "run", { 41 | input: { 42 | descriptions: [prompt], 43 | duration: duration, 44 | modelName: model, 45 | }, 46 | }); 47 | let emitter = new EventEmitter(); 48 | let id = res.id; 49 | let result = { 50 | id: id, 51 | status: "queued", 52 | results: [], 53 | cost: null, 54 | }; 55 | emitter.emit("data", result); 56 | let interval = setInterval(async () => { 57 | let check = await request(url, `status/${id}`, {}); 58 | if (check) { 59 | } 60 | }, 1000); 61 | }, 62 | }; 63 | -------------------------------------------------------------------------------- /src/models/audio/stt.ts: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import FormData from "form-data"; 3 | import { EventEmitter } from "events"; 4 | 5 | export default { 6 | data: { 7 | name: "stt", 8 | fullName: "Speech to text", 9 | parameters: { 10 | model: { 11 | type: "string", 12 | required: false, 13 | options: ["whisper", "fast-whisper", "gladia"], 14 | default: "fast-whisper", 15 | description: "Model to use for speech to text", 16 | }, 17 | audio: { 18 | type: "string", 19 | required: true, 20 | description: "Audio URL to transcribe", 21 | }, 22 | diarization: { 23 | type: "boolean", 24 | required: false, 25 | default: false, 26 | description: "Whether to use diarization or not", 27 | }, 28 | type: { 29 | type: "string", 30 | required: false, 31 | options: ["tiny", "base", "small", "medium", "large-v1", "large-v2"], 32 | default: "base", 33 | }, 34 | stream: { 35 | type: "boolean", 36 | required: false, 37 | default: false, 38 | }, 39 | }, 40 | }, 41 | execute: async (data) => { 42 | let { model, audio, diarization, type } = data; 43 | const event = new EventEmitter(); 44 | let result = { 45 | cost: 0, 46 | result: "", 47 | done: false, 48 | }; 49 | event.emit("data", result); 50 | if (model == "gladia") { 51 | const form = new FormData(); 52 | form.append("audio_url", audio); 53 | form.append("language_behaviour", "automatic single language"); 54 | if (!diarization) diarization = false; 55 | form.append("toggle_diarization", diarization); 56 | 57 | result.cost = 0.01; 58 | axios 59 | .post("https://api.gladia.io/audio/text/audio-transcription/", form, { 60 | params: { 61 | model: "large-v2", 62 | }, 63 | headers: { 64 | ...form.getHeaders(), 65 | accept: "application/json", 66 | "x-gladia-key": process.env.GLADIA_API_KEY, 67 | "Content-Type": "multipart/form-data", 68 | }, 69 | }) 70 | .then((response) => { 71 | var res = response.data; 72 | result.result = res; 73 | result.done = true; 74 | event.emit("data", result); 75 | }); 76 | 77 | return event; 78 | } 79 | if (model == "whisper-fast" || model == "whisper") { 80 | let models = ["tiny", "base", "small", "medium", "large-v1", "large-v2"]; 81 | let modelName = models.includes(type) ? type : "base"; 82 | axios({ 83 | url: `https://api.runpod.ai/v2/${ 84 | model == "whisper-fast" ? "faster-" : "" 85 | }whisper/runsync`, 86 | method: "post", 87 | headers: { 88 | "Content-Type": "application/json", 89 | Authorization: `${process.env.RUNPOD_API_KEY}`, 90 | accept: "application/json", 91 | }, 92 | data: { 93 | input: { 94 | audio: audio, 95 | model: modelName, 96 | transcription: "plain text", 97 | translate: false, 98 | temperature: 0, 99 | best_of: 5, 100 | beam_size: 5, 101 | suppress_tokens: "-1", 102 | condition_on_previous_text: false, 103 | temperature_increment_on_fallback: 0.2, 104 | compression_ratio_threshold: 2.4, 105 | logprob_threshold: -1, 106 | no_speech_threshold: 0.6, 107 | }, 108 | }, 109 | }).then((response) => { 110 | let data = response.data; 111 | let price = 0.00025; 112 | result.cost = (data.executionTime / 1000) * price; 113 | result.result = data.output; 114 | event.emit("data", result); 115 | }); 116 | return event; 117 | } 118 | }, 119 | }; 120 | -------------------------------------------------------------------------------- /src/models/audio/tts.ts: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import * as googleTTS from "google-tts-api"; 3 | import { EventEmitter } from "events"; 4 | 5 | export default { 6 | data: { 7 | name: "tts", 8 | fullName: "Text to speech", 9 | parameters: { 10 | model: { 11 | type: "string", 12 | required: true, 13 | options: ["google", "elevenlabs"], 14 | default: "google", 15 | }, 16 | voice: { 17 | type: "string", 18 | required: true, 19 | default: "adam", 20 | description: "Voice to use (elevenlabs only)", 21 | }, 22 | text: { 23 | type: "string", 24 | required: true, 25 | description: "Text to convert to speech", 26 | }, 27 | language: { 28 | type: "string", 29 | required: true, 30 | default: "en", 31 | description: "Language code to use (google only)", 32 | }, 33 | slow: { 34 | type: "boolean", 35 | required: false, 36 | default: false, 37 | description: "Speak slowly (google only)", 38 | }, 39 | stream: { 40 | type: "boolean", 41 | required: false, 42 | default: false, 43 | }, 44 | }, 45 | }, 46 | execute: async (data) => { 47 | let event = new EventEmitter(); 48 | let result = { 49 | cost: 0, 50 | base64: "", 51 | done: false, 52 | }; 53 | if (data.model == "google") { 54 | event.emit("data", result); 55 | let { text, language, slow } = data; 56 | google(text, language, slow).then((res) => { 57 | result.base64 = res; 58 | result.done = true; 59 | event.emit("data", result); 60 | }); 61 | } else if (data.model == "elevenlabs") { 62 | let { text, voice } = data; 63 | event.emit("data", result); 64 | elevenlabs(text, voice).then((res) => { 65 | result.base64 = res.base64; 66 | result.done = true; 67 | event.emit("data", result); 68 | }); 69 | } 70 | return event; 71 | }, 72 | }; 73 | 74 | async function elevenlabs(text: string, voice: string) { 75 | const voices = [ 76 | "adam", 77 | "antoni", 78 | "arnold", 79 | "bella", 80 | "josh", 81 | "rachel", 82 | "domi", 83 | "elli", 84 | "sam", 85 | ]; 86 | if (!voices.includes(voice)) { 87 | throw new Error("Voice not found"); 88 | } 89 | let response = await axios({ 90 | url: "https://api.pawan.krd/tts", 91 | data: { 92 | text, 93 | voice, 94 | }, 95 | responseType: "arraybuffer", 96 | method: "POST", 97 | headers: { 98 | "Content-Type": "application/json", 99 | }, 100 | }); 101 | let base64 = Buffer.from(response.data, "binary").toString("base64"); 102 | return { 103 | base64: base64, 104 | }; 105 | } 106 | async function google( 107 | text: string, 108 | language: string = "en", 109 | slow: boolean = false 110 | ) { 111 | const results = googleTTS.getAudioBase64(text, { 112 | lang: language, 113 | slow: slow, 114 | host: "https://translate.google.com", 115 | }); 116 | return results; 117 | } 118 | -------------------------------------------------------------------------------- /src/models/image/anything.ts: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import { randomUUID } from "crypto"; 3 | import { EventEmitter } from "events"; 4 | export default { 5 | data: { 6 | name: "anything", 7 | fullName: "Anything models", 8 | parameters: { 9 | prompt: { 10 | type: "string", 11 | required: true, 12 | description: "Prompt to generate the image", 13 | }, 14 | steps: { 15 | type: "number", 16 | required: false, 17 | default: 100, 18 | }, 19 | number: { 20 | type: "number", 21 | required: false, 22 | default: 1, 23 | }, 24 | negative_prompt: { 25 | type: "string", 26 | required: false, 27 | default: 28 | "disfigured mouth, disfigured teeth, half head, half face, blury, side looking, old, wrinkle, child, no face, pencil, full body, sharp, far away, overlapping, duplication, nude, disfigured, kitsch, oversaturated, grain, low-res, Deformed, blurry, bad anatomy, poorly drawn face, mutation, mutated, extra limb, ugly, poorly drawn hands, missing limb, blurry, floating limbs, disconnected limbs, malformed hands, blur, out of focus, long body, disgusting, poorly drawn, childish, mutilated, mangled, surreal, out of frame, duplicate, 2 faces", 29 | }, 30 | guidance_scale: { 31 | type: "number", 32 | required: false, 33 | default: 4, 34 | }, 35 | width: { 36 | type: "number", 37 | required: false, 38 | default: 512, 39 | }, 40 | height: { 41 | type: "number", 42 | required: false, 43 | default: 512, 44 | }, 45 | cfg_scale: { 46 | type: "number", 47 | required: false, 48 | default: 4, 49 | }, 50 | stream: { 51 | type: "boolean", 52 | required: false, 53 | default: true, 54 | }, 55 | }, 56 | }, 57 | execute: async (data) => { 58 | let { prompt, steps, negative_prompt, guidance_scale, stream } = data; 59 | if (!negative_prompt) 60 | negative_prompt = 61 | "disfigured mouth, disfigured teeth, half head, half face, blury, side looking, old, wrinkle, child, no face, pencil, full body, sharp, far away, overlapping, duplication, nude, disfigured, kitsch, oversaturated, grain, low-res, Deformed, blurry, bad anatomy, poorly drawn face, mutation, mutated, extra limb, ugly, poorly drawn hands, missing limb, blurry, floating limbs, disconnected limbs, malformed hands, blur, out of focus, long body, disgusting, poorly drawn, childish, mutilated, mangled, surreal, out of frame, duplicate, 2 faces"; 62 | let event = null; 63 | if (stream == null) { 64 | stream = true; 65 | } 66 | let result = { 67 | cost: null, 68 | results: [], 69 | status: "generating", 70 | progress: 0, 71 | id: randomUUID(), 72 | }; 73 | event = new EventEmitter(); 74 | event.emit("data", result); 75 | // after 5s change progress to 0.46 76 | setTimeout(() => { 77 | result.progress = 0.46; 78 | event.emit("data", result); 79 | }, 5000); 80 | // after 10s change progress to 0.92 81 | setTimeout(() => { 82 | result.progress = 0.92; 83 | event.emit("data", result); 84 | }, 10000); 85 | let start = Date.now(); 86 | 87 | axios({ 88 | url: "https://api.runpod.ai/v2/sd-anything-v4/runsync", 89 | method: "POST", 90 | headers: { 91 | Accept: "application/json", 92 | "Content-Type": "application/json", 93 | Authorization: `Bearer ${process.env.RUNPOD_KEY}`, 94 | }, 95 | data: { 96 | input: { 97 | prompt: prompt, 98 | num_inference_steps: steps || 50, 99 | guidance_scale: guidance_scale, 100 | negative_prompt: negative_prompt, 101 | num_outputs: data.number || 1, 102 | width: data.width || 512, 103 | height: data.height || 512, 104 | }, 105 | }, 106 | }).then(async (response) => { 107 | let spentInSec = (Date.now() - start) / 1000; 108 | let cost = spentInSec * 0.00025; 109 | result.cost = cost; 110 | if (data.number && data.number > 1) { 111 | result.results = await Promise.all( 112 | response.data.output.map(async (x) => { 113 | let res = await axios.get(x.image, { 114 | responseType: "arraybuffer", 115 | // change time out to 2 min 116 | timeout: 120000, 117 | }); 118 | let base64 = Buffer.from(res.data, "binary").toString("base64"); 119 | return { 120 | base64: base64, 121 | id: randomUUID(), 122 | seed: x.seed, 123 | status: "success", 124 | }; 125 | }) 126 | ); 127 | } else { 128 | let res = await axios.get(response.data.output.image, { 129 | responseType: "arraybuffer", 130 | timeout: 120000, 131 | }); 132 | let base64 = Buffer.from(res.data, "binary").toString("base64"); 133 | result.results.push({ 134 | base64: base64, 135 | id: randomUUID(), 136 | seed: response.data.output.seed, 137 | status: "success", 138 | }); 139 | } 140 | result.status = "done"; 141 | result.progress = null; 142 | event.emit("data", result); 143 | }); 144 | return event; 145 | }, 146 | }; 147 | -------------------------------------------------------------------------------- /src/models/image/controlnet.ts: -------------------------------------------------------------------------------- 1 | import { predict } from "replicate-api"; 2 | import { EventEmitter } from "events"; 3 | 4 | export default { 5 | data: { 6 | name: "controlnet", 7 | fullName: "Controlnet", 8 | parameters: { 9 | prompt: { 10 | type: "string", 11 | required: true, 12 | }, 13 | model: { 14 | type: "string", 15 | required: true, 16 | options: [ 17 | "normal", 18 | "canny", 19 | "hough", 20 | "hed", 21 | "depth2img", 22 | "pose", 23 | "seg", 24 | ], 25 | default: "normal", 26 | }, 27 | image: { 28 | type: "string", 29 | required: true, 30 | }, 31 | stream: { 32 | type: "boolean", 33 | required: false, 34 | default: false, 35 | }, 36 | }, 37 | }, 38 | execute: async (data) => { 39 | let { 40 | prompt, 41 | model, 42 | image, 43 | }: { prompt: string; model: string; image: any } = data; 44 | let event = new EventEmitter(); 45 | let result = { 46 | cost: 0, 47 | url: "", 48 | done: false, 49 | }; 50 | event.emit("data", result); 51 | predict({ 52 | model: `jagilley/controlnet-${model}`, // The model name 53 | input: { 54 | image: image, 55 | prompt: prompt, 56 | }, // The model specific input 57 | token: process.env.REPLICATE_API_KEY, // You need a token from replicate.com 58 | poll: true, // Wait for the model to finish 59 | }).then((prediction: any) => { 60 | if (prediction.error) throw new Error(prediction.error); 61 | result.url = prediction.output; 62 | result.done = true; 63 | result.cost = 0.003; 64 | event.emit("data", result); 65 | }); 66 | return event; 67 | }, 68 | }; 69 | -------------------------------------------------------------------------------- /src/models/image/dall-e.ts: -------------------------------------------------------------------------------- 1 | import { Configuration, OpenAIApi } from "openai"; 2 | import { EventEmitter } from "events"; 3 | import { randomUUID } from "crypto"; 4 | 5 | const configuration = new Configuration({ 6 | apiKey: process.env.OPENAI_KEY, 7 | }); 8 | const openai = new OpenAIApi(configuration); 9 | 10 | export default { 11 | data: { 12 | name: "dall-e", 13 | fullName: "Dall-e 3", 14 | parameters: { 15 | prompt: { 16 | type: "string", 17 | required: false, 18 | }, 19 | number: { 20 | type: "number", 21 | required: true, 22 | options: [1, 2, 3, 4], 23 | default: 1, 24 | description: "Number of images to generate", 25 | }, 26 | size: { 27 | type: "string", 28 | required: false, 29 | options: ["512x512", "256x256", "1024x1024"], 30 | default: "512x512", 31 | }, 32 | image: { 33 | type: "string", 34 | required: false, 35 | description: "Image you want to vary", 36 | }, 37 | stream: { 38 | type: "boolean", 39 | required: false, 40 | default: false, 41 | }, 42 | }, 43 | response: { 44 | cost: { 45 | type: "number", 46 | required: true, 47 | }, 48 | results: { 49 | type: "array", 50 | required: true, 51 | }, 52 | status: { 53 | type: "string", 54 | required: true, 55 | }, 56 | progress: { 57 | type: "number", 58 | required: false, 59 | }, 60 | id: { 61 | type: "string", 62 | required: true, 63 | }, 64 | done: { 65 | type: "boolean", 66 | required: true, 67 | }, 68 | }, 69 | }, 70 | execute: async (data) => { 71 | let { 72 | prompt, 73 | number, 74 | size, 75 | image, 76 | }: { 77 | prompt: string; 78 | number: number; 79 | size: any; 80 | image: File; 81 | } = data; 82 | let event = new EventEmitter(); 83 | let result = { 84 | cost: null, 85 | results: [], 86 | status: "generating", 87 | progress: 0, 88 | id: randomUUID(), 89 | done: false, 90 | record: null, 91 | }; 92 | event.emit("data", result); 93 | if (size == "512x512") result.cost = 0.018; 94 | if (size == "256x256") result.cost = 0.016; 95 | if (size == "1024x1024") result.cost = 0.02; 96 | 97 | if (!image) { 98 | openai 99 | .createImage({ 100 | prompt, 101 | n: number, 102 | size, 103 | }) 104 | .then((res) => { 105 | var imagesArr = res.data.data.map((d, i) => { 106 | return { 107 | attachment: d.url, 108 | name: `result-${i}.png`, 109 | id: randomUUID(), 110 | }; 111 | }); 112 | result.results = imagesArr; 113 | result.status = "done"; 114 | result.progress = null; 115 | result.done = true; 116 | result.record = result.results.map((r) => { 117 | return { 118 | ...r, 119 | prompt, 120 | number, 121 | size, 122 | }; 123 | }); 124 | event.emit("data", result); 125 | }); 126 | 127 | return event; 128 | } else { 129 | openai.createImageVariation(image, number, size).then((res) => { 130 | var imagesArr = res.data.data.map((d, i) => { 131 | return { 132 | attachment: d.url, 133 | name: `result-${i}.png`, 134 | id: randomUUID(), 135 | }; 136 | }); 137 | result.results = imagesArr; 138 | result.status = "done"; 139 | result.progress = null; 140 | result.done = true; 141 | event.emit("data", result); 142 | }); 143 | 144 | return event; 145 | } 146 | }, 147 | }; 148 | -------------------------------------------------------------------------------- /src/models/image/sh.ts: -------------------------------------------------------------------------------- 1 | import { EventEmitter } from "events"; 2 | import axios from "axios"; 3 | 4 | export default { 5 | data: { 6 | name: "sh", 7 | fullName: "Stablehorde", 8 | parameters: { 9 | prompt: { 10 | type: "string", 11 | required: true, 12 | description: "Prompt to generate the image", 13 | }, 14 | negative_prompt: { 15 | type: "string", 16 | required: false, 17 | }, 18 | image: { 19 | type: "string", 20 | required: false, 21 | description: "Image URL for the model to use when doing img2img", 22 | }, 23 | width: { 24 | type: "number", 25 | required: false, 26 | default: 512, 27 | }, 28 | height: { 29 | type: "number", 30 | required: false, 31 | default: 512, 32 | }, 33 | steps: { 34 | type: "number", 35 | required: false, 36 | default: 50, 37 | }, 38 | number: { 39 | type: "number", 40 | required: false, 41 | description: "Number of images to generate", 42 | default: 1, 43 | }, 44 | strength: { 45 | type: "number", 46 | required: false, 47 | }, 48 | sampler: { 49 | type: "string", 50 | required: false, 51 | options: [ 52 | "k_lms", 53 | "k_heun", 54 | "k_euler", 55 | "k_euler_a", 56 | "k_dpm_2", 57 | "k_dpm_2_a", 58 | "DDIM", 59 | "k_dpm_fast", 60 | "k_dpm_adaptive", 61 | "k_dpmpp_2m", 62 | "k_dpmpp_2s_a", 63 | "k_dpmpp_sde", 64 | ], 65 | }, 66 | cfg_scale: { 67 | type: "number", 68 | required: false, 69 | }, 70 | seed: { 71 | type: "number", 72 | required: false, 73 | }, 74 | model: { 75 | type: "string", 76 | required: false, 77 | options: [ 78 | "SDXL 1.0", 79 | "AlbedoBase XL (SDXL)", 80 | "ICBINP XL", 81 | "TURBO XL", 82 | "Fustercluck", 83 | "stable_cascade", 84 | ], 85 | default: "stable_cascade", 86 | }, 87 | nsfw: { 88 | type: "boolean", 89 | required: false, 90 | default: false, 91 | }, 92 | stream: { 93 | type: "boolean", 94 | required: false, 95 | default: true, 96 | }, 97 | }, 98 | response: { 99 | cost: { 100 | type: "number", 101 | description: "Cost of the request in USD", 102 | }, 103 | id: { 104 | type: "string", 105 | description: "ID of the request", 106 | }, 107 | status: { 108 | type: "string", 109 | description: "Status of the request", 110 | options: ["generating", "queued", "done", "failed"], 111 | }, 112 | progress: { 113 | type: "number", 114 | description: "Progress of the request", 115 | }, 116 | queue_position: { 117 | type: "number", 118 | description: "Queue position of the request", 119 | }, 120 | results: { 121 | type: "array", 122 | description: "Results of the request", 123 | }, 124 | }, 125 | }, 126 | execute: async (data) => { 127 | let res = await generateAsync(data); 128 | let result: any = { 129 | id: res.id, 130 | cost: res.kudos / 1000, 131 | status: "generating", 132 | progress: 0, 133 | queue_position: res.queue_position, 134 | results: [], 135 | record: null, 136 | }; 137 | let maxTime = 45; 138 | if (res.id) { 139 | let stream = new EventEmitter(); 140 | stream.emit("data", result); 141 | checkRequest(res.id).then((check) => { 142 | result.progress = ((check.wait_time / maxTime) * 100) / 100; 143 | result.queue_position = check.queue_position; 144 | if (check.queue_position >= 1) result.status = "queued"; 145 | if (check.wait_time == 0) { 146 | result.status = "generating"; 147 | result.progress = 0.99; 148 | } 149 | if (check.done) { 150 | result.status = "done"; 151 | result.progress = null; 152 | result.results = check.generations.map((x) => { 153 | return { 154 | seed: x.seed, 155 | id: x.id, 156 | base64: x.img, 157 | status: x.censored ? "filtered" : "success", 158 | }; 159 | }); 160 | result.record = result.results.map((x) => { 161 | return { 162 | ...x, 163 | prompt: data.prompt, 164 | model: data.model, 165 | sampler: data.sampler, 166 | cfg_scale: data.cfg_scale, 167 | nsfw: data.nsfw, 168 | width: data.width, 169 | height: data.height, 170 | steps: data.steps, 171 | number: data.number, 172 | strength: data.strength, 173 | negative_prompt: data.negative_prompt, 174 | }; 175 | }); 176 | stream.emit("data", result); 177 | return; 178 | } 179 | }); 180 | 181 | let interval = setInterval(async () => { 182 | try { 183 | let check = await checkRequest(res.id); 184 | result.progress = ((check.wait_time / maxTime) * 100) / 100; 185 | result.wait_time = check.wait_time; 186 | result.queue_position = check.queue_position; 187 | if (check.queue_position >= 1) result.status = "queued"; 188 | if (check.wait_time == 0) { 189 | result.status = "generating"; 190 | result.progress = 0.99; 191 | } 192 | if (check.done) { 193 | result.status = "done"; 194 | result.progress = null; 195 | result.results = check.generations.map((x) => { 196 | return { 197 | seed: x.seed, 198 | id: x.id, 199 | base64: x.img, 200 | status: x.censored ? "filtered" : "success", 201 | }; 202 | }); 203 | result.record = result.results.map((x) => { 204 | return { 205 | ...x, 206 | prompt: data.prompt, 207 | model: data.model, 208 | sampler: data.sampler, 209 | cfg_scale: data.cfg_scale, 210 | nsfw: data.nsfw, 211 | width: data.width, 212 | height: data.height, 213 | steps: data.steps, 214 | number: data.number, 215 | strength: data.strength, 216 | negative_prompt: data.negative_prompt, 217 | }; 218 | }); 219 | clearInterval(interval); 220 | } 221 | stream.emit("data", result); 222 | } catch (e) { 223 | clearInterval(interval); 224 | stream.emit("data", { 225 | status: "failed", 226 | error: e, 227 | }); 228 | } 229 | }, 10000); 230 | return stream; 231 | } else { 232 | throw new Error("Failed to generate image"); 233 | } 234 | }, 235 | }; 236 | 237 | async function generateAsync(data) { 238 | let formatData: any = { 239 | params: {}, 240 | }; 241 | let fullPrompt = data.prompt; 242 | if (data.negative_prompt) { 243 | fullPrompt = `${data.prompt} ### ${data.negative_prompt}`; 244 | } 245 | formatData.prompt = fullPrompt; 246 | if (data.image) { 247 | formatData.source_image = data.image; 248 | formatData.source_processing = "img2img"; 249 | } 250 | if (data.sampler) { 251 | formatData.params.sampler_name = data.sampler; 252 | } 253 | if (data.cfg_scale) { 254 | formatData.params.cfg_scale = data.cfg_scale; 255 | } 256 | if (data.seed) { 257 | formatData.params.seed = data.seed; 258 | } 259 | 260 | if (data.nsfw) { 261 | formatData.nsfw = true; 262 | } 263 | if (data.width) { 264 | formatData.params.width = data.width; 265 | } 266 | if (data.height) { 267 | formatData.params.height = data.height; 268 | } 269 | if (data.steps) { 270 | formatData.params.steps = data.steps; 271 | } 272 | if (data.number) { 273 | formatData.params.n = data.number; 274 | } else { 275 | formatData.params.n = 1; 276 | if (data.model.includes("XL")) { 277 | formatData.params.n = 2; 278 | } 279 | } 280 | if (data.model.includes("XL")) { 281 | formatData.params.width = 1024; 282 | formatData.params.height = 1024; 283 | } 284 | if (data.strength) { 285 | formatData.params.denoising_strength = data.strength; 286 | } 287 | if (data.model) { 288 | if (data.model == "TURBO XL") { 289 | formatData.model = "SDXL 1.0"; 290 | formatData.params.steps = 8; 291 | formatData.params = { 292 | ...formatData.params, 293 | loras: [ 294 | { 295 | name: "246747", 296 | model: 1, 297 | clip: 1, 298 | is_version: true, 299 | }, 300 | ], 301 | }; 302 | } else { 303 | formatData.models = [data.model]; 304 | } 305 | } else { 306 | formatData.models = ["SDXL 1.0"]; 307 | } 308 | 309 | formatData.shared = true; 310 | formatData.r2 = false; 311 | let res = await axios({ 312 | url: `https://stablehorde.net/api/v2/generate/async`, 313 | method: "POST", 314 | headers: { 315 | "Content-Type": "application/json", 316 | apiKey: process.env.STABLE_HORDE, 317 | Accept: "application/json", 318 | "Client-Agent": "turing-api:v1.0.0:@mrlol.dev", 319 | }, 320 | data: formatData, 321 | }); 322 | return res.data; 323 | } 324 | 325 | async function checkRequest(id: string) { 326 | let res = await axios({ 327 | url: `https://stablehorde.net/api/v2/generate/status/${id}`, 328 | method: "GET", 329 | headers: { 330 | "Content-Type": "application/json", 331 | apiKey: process.env.STABLE_HORDE, 332 | Accept: "application/json", 333 | "Client-Agent": "turing-api:v1.0.0:@mrlol.dev", 334 | }, 335 | }); 336 | return res.data; 337 | } 338 | -------------------------------------------------------------------------------- /src/models/image/upscale.ts: -------------------------------------------------------------------------------- 1 | import delay from "delay"; 2 | import { translateModels, request } from "../../utils/runpod.js"; 3 | import EventEmitter from "events"; 4 | import axios from "axios"; 5 | 6 | export default { 7 | data: { 8 | name: "upscale", 9 | fullName: "Upscale models", 10 | parameters: { 11 | upscaler: { 12 | type: "string", 13 | required: false, 14 | description: 15 | "Upscaler to use, by selecting this you won't generate any image but you will upscale the image you provide", 16 | default: "RealESRGAN_x2plus", 17 | options: [ 18 | "GFPGAN", 19 | "RealESRGAN_x4plus", 20 | "RealESRGAN_x2plus", 21 | "RealESRGAN_x4plus_anime_6B", 22 | "NMKD_Siax", 23 | "4x_AnimeSharp", 24 | ], 25 | }, 26 | image: { 27 | type: "string", 28 | required: true, 29 | description: "Image URL for the model to use when doing the upscaling", 30 | }, 31 | }, 32 | response: { 33 | cost: { 34 | type: "number", 35 | description: "Cost of the request in USD", 36 | }, 37 | result: { 38 | type: "string", 39 | description: "Object containing the upscaled image URL", 40 | }, 41 | status: { 42 | type: "string", 43 | description: "Status of the request", 44 | options: ["queued", "generating", "done"], 45 | }, 46 | done: { 47 | type: "boolean", 48 | description: "Whether the request is done or not", 49 | }, 50 | }, 51 | pricing: { 52 | average: 0.01, 53 | }, 54 | }, 55 | execute: async (data) => { 56 | if (!data.upscaler) data.upscaler = "RealESRGAN_x2plus"; 57 | let res = await generateAsync(data); 58 | let result: any = { 59 | id: res.id, 60 | cost: 10 / 1000, 61 | status: "generating", 62 | progress: 0, 63 | }; 64 | let maxTime = 45; 65 | if (res.id) { 66 | let stream = new EventEmitter(); 67 | stream.emit("data", result); 68 | checkRequest(res.id).then(async (check) => { 69 | result.progress = ((check.wait_time / maxTime) * 100) / 100; 70 | if (check.state == "waiting") result.status = "queued"; 71 | if (check.state == "processing") result.status = "generating"; 72 | if (check.state == "done") { 73 | result.status = "done"; 74 | result.progress = null; 75 | if (data.upscaler != "caption") { 76 | let url = check.forms[0].result[data.upscaler]; 77 | let base64; 78 | let buffer = await axios.get(url, { responseType: "arraybuffer" }); 79 | base64 = Buffer.from(buffer.data, "binary").toString("base64"); 80 | result.result = { 81 | url: url, 82 | base64: base64, 83 | }; 84 | } else { 85 | result.result = check.forms[0].result.caption; 86 | } 87 | stream.emit("data", result); 88 | return; 89 | } 90 | }); 91 | 92 | let interval = setInterval(async () => { 93 | try { 94 | let check = await checkRequest(res.id); 95 | result.progress = ((check.wait_time / maxTime) * 100) / 100; 96 | if (check.state == "waiting") result.status = "queued"; 97 | if (check.state == "processing") result.status = "generating"; 98 | if (check.state == "done") { 99 | clearInterval(interval); 100 | result.status = "done"; 101 | result.progress = null; 102 | if (data.upscaler != "caption") { 103 | let url = check.forms[0].result[data.upscaler]; 104 | let base64; 105 | let buffer = await axios.get(url, { 106 | responseType: "arraybuffer", 107 | }); 108 | base64 = Buffer.from(buffer.data, "binary").toString("base64"); 109 | result.result = { 110 | url: url, 111 | base64: base64, 112 | }; 113 | } else { 114 | result.result = check.forms[0].result.caption; 115 | } 116 | stream.emit("data", result); 117 | return; 118 | } 119 | stream.emit("data", result); 120 | } catch (e) { 121 | clearInterval(interval); 122 | stream.emit("data", { 123 | status: "failed", 124 | error: e, 125 | }); 126 | } 127 | }, 10000); 128 | return stream; 129 | } else { 130 | throw new Error("Failed to generate image"); 131 | } 132 | }, 133 | }; 134 | 135 | async function generateAsync(data) { 136 | let formatData: any = { 137 | source_image: data.image, 138 | slow_workers: false, 139 | forms: [ 140 | { 141 | name: data.upscaler, 142 | }, 143 | ], 144 | }; 145 | 146 | let res = await axios({ 147 | url: `https://stablehorde.net/api/v2/interrogate/async`, 148 | method: "POST", 149 | headers: { 150 | "Content-Type": "application/json", 151 | apiKey: process.env.STABLE_HORDE, 152 | Accept: "application/json", 153 | "Client-Agent": "turing-api:v1.0.0:@mrlol.dev", 154 | }, 155 | data: formatData, 156 | }); 157 | return res.data; 158 | } 159 | 160 | async function checkRequest(id: string) { 161 | let res = await axios({ 162 | url: `https://stablehorde.net/api/v2/interrogate/status/${id}`, 163 | method: "GET", 164 | headers: { 165 | "Content-Type": "application/json", 166 | apiKey: process.env.STABLE_HORDE, 167 | Accept: "application/json", 168 | "Client-Agent": "turing-api:v1.0.0:@mrlol.dev", 169 | }, 170 | }); 171 | return res.data; 172 | } 173 | -------------------------------------------------------------------------------- /src/models/image/vision.ts: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import { request, translateModels } from "../../utils/runpod.js"; 3 | import { EventEmitter } from "events"; 4 | import upscale from "./upscale.js"; 5 | import { 6 | GenerateContentRequest, 7 | HarmBlockThreshold, 8 | HarmCategory, 9 | VertexAI, 10 | } from "@google-cloud/vertexai"; 11 | import delay from "delay"; 12 | const regions = [ 13 | "us-central1", 14 | "northamerica-northeast1", 15 | "us-east4", 16 | "us-west1", 17 | "us-west4", 18 | /* 19 | "europe-west4", 20 | "europe-west2", 21 | "europe-west3", 22 | "europe-west4", 23 | "europe-west9",*/ 24 | "asia-northeast1", 25 | "asia-northeast3", 26 | "asia-southeast1", 27 | ]; 28 | export default { 29 | data: { 30 | name: "vision", 31 | fullName: "Image vision", 32 | description: "Image analysis to extract text and description", 33 | parameters: { 34 | model: { 35 | type: "array", 36 | required: true, 37 | options: ["blip2", "ocr", "gemini"], 38 | default: ["gemini"], 39 | description: "Model to use for the analysis", 40 | }, 41 | image: { 42 | type: "string", 43 | required: true, 44 | description: "Image URL for the model to process", 45 | }, 46 | typeImage: { 47 | type: "string", 48 | required: false, 49 | options: ["anything", "person"], 50 | default: "anything", 51 | description: "Type of image to process", 52 | }, 53 | }, 54 | response: { 55 | cost: { 56 | type: "number", 57 | description: "Cost of the request in USD", 58 | }, 59 | description: { 60 | type: "string", 61 | description: "Description of the image", 62 | }, 63 | text: { 64 | type: "string", 65 | description: "Text extracted from the image", 66 | }, 67 | done: { 68 | type: "boolean", 69 | description: "Whether the request is done or not", 70 | }, 71 | }, 72 | }, 73 | execute: async (data) => { 74 | let result = { 75 | description: null, 76 | text: null, 77 | cost: 0, 78 | done: false, 79 | lines: null, 80 | record: null, 81 | }; 82 | let { model, image, typeImage } = data; 83 | let cost = 0; 84 | let event = new EventEmitter(); 85 | event.emit("data", result); 86 | 87 | if (model.includes("blip2")) { 88 | upscale 89 | .execute({ 90 | upscaler: "caption", 91 | image: image, 92 | }) 93 | .then((ev) => { 94 | result.description = ""; 95 | ev.on("data", (data) => { 96 | event.emit("data", result); 97 | if (data.status == "done") { 98 | result.description = data.result; 99 | result.cost += data.cost; 100 | if (model.length == 1 || result.text) result.done = true; 101 | event.emit("data", result); 102 | } 103 | }); 104 | }) 105 | .catch((e) => { 106 | console.log(e); 107 | }); 108 | } 109 | if (model.includes("ocr")) { 110 | // OCR_KEY 111 | axios({ 112 | url: `https://api.ocr.space/parse/ImageUrl`, 113 | method: "GET", 114 | headers: { 115 | apikey: process.env.OCR_KEY, 116 | }, 117 | params: { 118 | url: image, 119 | apikey: process.env.OCR_KEY, 120 | }, 121 | }).then((res) => { 122 | let body = res.data; 123 | if (!body.ParsedResults || body.ParsedResults?.length == 0) { 124 | console.log(body); 125 | if (model.length == 1 || result.description) { 126 | result.done = true; 127 | } 128 | event.emit("data", result); 129 | return; 130 | } 131 | const lines = body.ParsedResults[0]?.TextOverlay?.Lines?.map((l) => ({ 132 | text: l.LineText, 133 | 134 | words: l.Words.map((w) => ({ 135 | text: w.WordText, 136 | left: w.Left, 137 | top: w.Top, 138 | width: w.Width, 139 | height: w.Height, 140 | })), 141 | 142 | maxHeight: l.MaxHeight, 143 | minTop: l.MinTop, 144 | })); 145 | 146 | /* The entire detected text in the image */ 147 | const text: string = body.ParsedResults[0].ParsedText.replaceAll( 148 | "\r\n", 149 | "\n" 150 | ).trim(); 151 | 152 | result.text = text; 153 | result.cost += 0.00004; 154 | result.lines = lines; 155 | if (model.length == 1 || result.description) { 156 | result.done = true; 157 | } 158 | event.emit("data", result); 159 | }); 160 | } 161 | if (model.includes("gemini")) { 162 | let prompt = `Don't forget these rules:\n\n1. **Be Direct and Concise**: Provide straightforward descriptions without adding interpretative or speculative elements.\n2. **Use Segmented Details**: Break down details about different elements of an image into distinct sentences, focusing on one aspect at a time.\n3. **Maintain a Descriptive Focus**: Prioritize purely visible elements of the image, avoiding conclusions or inferences.\n4. **Follow a Logical Structure**: Begin with the central figure or subject and expand outward, detailing its appearance before addressing the surrounding setting.\n5. **Avoid Juxtaposition**: Do not use comparison or contrast language; keep the description purely factual.\n6. **Incorporate Specificity**: Mention age, gender, race, and specific brands or notable features when present, and clearly identify the medium if it's discernible.\n\nWhen writing descriptions, prioritize clarity and direct observation over embellishment or interpretation.\n\n Write a detailed description of this image, do not forget about the texts on it if they exist. Also, do not forget to mention the type / style of the image. No bullet points.`; 163 | if (typeImage == "person") { 164 | prompt = 165 | "Describe with high details which emotions the person in the picture seems to be experiencing from what the micro expressions in the face and the body language seem to indicate. Write only details that can be clearly observed and draw conclusions from this that have visible evidence in the picture. Also consider if the person could be trying to convey other emotions to his/her social environment than he/she is actually feeling by looking for close how genuine the displayed emotions seems to be. Provide a detailed reply that reflects high emotional intelligence, empathy and accuracy. "; 166 | } 167 | const region = regions[Math.floor(Math.random() * regions.length)]; 168 | const vertexAI = new VertexAI({ 169 | project: process.env.GOOGLE_PROJECT_ID, 170 | location: region, 171 | }); 172 | const generativeModel = vertexAI.preview.getGenerativeModel({ 173 | model: model, 174 | // The following parameters are optional 175 | // They can also be passed to individual content generation requests 176 | safety_settings: [ 177 | { 178 | category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, 179 | threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE, 180 | }, 181 | ], 182 | generation_config: { max_output_tokens: 150 }, 183 | }); 184 | const request: GenerateContentRequest = { 185 | contents: [ 186 | { 187 | role: "user", 188 | parts: [ 189 | { text: prompt }, 190 | { 191 | inline_data: { 192 | mime_type: "image/jpeg", 193 | data: image, 194 | }, 195 | }, 196 | ], 197 | }, 198 | ], 199 | }; 200 | let promptLength = 0; 201 | await delay(500); 202 | const res = await generativeModel.generateContent(request); 203 | result.description = res.response.candidates[0].content.parts[0].text; 204 | } 205 | result.record = { 206 | description: result.description, 207 | text: result.text, 208 | model: model, 209 | image: image, 210 | }; 211 | event.emit("data", result); 212 | return event; 213 | }, 214 | }; 215 | -------------------------------------------------------------------------------- /src/models/text/alan.ts: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import { 3 | getChatMessageLength, 4 | getPromptLength, 5 | } from "../../utils/tokenizer.js"; 6 | import { EventEmitter } from "events"; 7 | import supabase from "../../db/supabase.js"; 8 | import { getToday } from "../../utils/ms.js"; 9 | 10 | //MODELS 11 | import dall_e from "../image/dall-e.js"; 12 | import music from "../audio/music.js"; 13 | import controlnet from "../image/controlnet.js"; 14 | 15 | import gptNew from "./gpt-new.js"; 16 | 17 | export default { 18 | data: { 19 | name: "alan", 20 | fullName: "Alan", 21 | alert: "This model is unfinished and is not working yet.", 22 | parameters: { 23 | userName: { 24 | type: "string", 25 | required: true, 26 | }, 27 | messages: { 28 | type: "array", 29 | required: true, 30 | }, 31 | searchEngine: { 32 | type: "string", 33 | required: false, 34 | options: ["google", "none"], 35 | }, 36 | image: { 37 | type: "string", 38 | required: false, 39 | }, 40 | imageDescription: { 41 | type: "string", 42 | required: false, 43 | }, 44 | imageGenerator: { 45 | type: "string", 46 | required: false, 47 | options: ["sdxl", "kandinsky", "none"], 48 | }, 49 | nsfw: { 50 | type: "boolean", 51 | default: false, 52 | required: false, 53 | }, 54 | audioGenerator: { 55 | type: "string", 56 | options: ["musicgen"], 57 | required: false, 58 | }, 59 | imageModificator: { 60 | type: "string", 61 | options: ["controlnet", "none"], 62 | required: false, 63 | }, 64 | max_tokens: { 65 | type: "number", 66 | default: 250, 67 | required: false, 68 | }, 69 | }, 70 | }, 71 | execute: async (data) => { 72 | let { searchEngine, imageGenerator, imageModificator, userName } = data; 73 | let plugins = []; 74 | if (searchEngine == "google") plugins.push("google"); 75 | if (imageGenerator) plugins.push("image"); 76 | 77 | return await gptNew.execute({ 78 | messages: [ 79 | { 80 | role: "system", 81 | content: `You are an AI named Alan which have been developed by TuringAI (discord.gg/turing). You are running as a discord bot with the id "1053015370115588147", the bot invite link is "https://link.turing.sh/bot".\nYou can view images, execute code and search in internet for real-time information. YOU CAN DISPLAY AND GENERATE IMAGES, VIDEOS AND SONGS.\nConsider the following in your responses:\n- Be conversational\n- Add unicode emoji to be more playful in your responses\n- Current date: ${getToday()}\n- Name of the user talking to: ${userName}`, 82 | }, 83 | ...data.messages, 84 | ], 85 | model: "gpt-3.5-turbo", 86 | max_tokens: data.max_tokens || 250, 87 | temperature: 0.7, 88 | plugins: plugins, 89 | }); 90 | }, 91 | }; 92 | -------------------------------------------------------------------------------- /src/models/text/anthropic.ts: -------------------------------------------------------------------------------- 1 | import Anthropic from "@anthropic-ai/sdk"; 2 | import { EventEmitter } from "events"; 3 | import { getPromptLength } from "../../utils/tokenizer.js"; 4 | const anthropic = new Anthropic({ 5 | apiKey: process.env.ANTHROPIC_API_KEY, 6 | }); 7 | 8 | export default { 9 | data: { 10 | name: "anthropic", 11 | fullName: "Anthropic Models", 12 | disabled: true, 13 | parameters: { 14 | messages: { 15 | type: "array", 16 | required: true, 17 | }, 18 | model: { 19 | type: "string", 20 | required: false, 21 | options: ["claude-instant-1.2", "claude-2.1"], 22 | default: "claude-instant-1.2", 23 | }, 24 | max_tokens: { 25 | type: "number", 26 | required: false, 27 | default: 512, 28 | }, 29 | temperature: { 30 | type: "number", 31 | required: false, 32 | default: 0.9, 33 | }, 34 | stream: { 35 | type: "boolean", 36 | required: false, 37 | default: false, 38 | }, 39 | }, 40 | response: { 41 | cost: { 42 | type: "number", 43 | description: "Cost of the request in USD", 44 | }, 45 | result: { 46 | type: "string", 47 | description: "Result of the request", 48 | }, 49 | }, 50 | }, 51 | execute: async (data) => { 52 | let { messages, model, max_tokens, temperature, stream } = data; 53 | if (!model) model = "claude-instant-1.2"; 54 | if (!max_tokens) max_tokens = 512; 55 | if (!temperature) temperature = 0.9; 56 | let prompt = ""; 57 | messages.forEach((message) => { 58 | if (message.role == "user") 59 | prompt += `${Anthropic.HUMAN_PROMPT} ${message.content}`; 60 | else prompt += `${Anthropic.AI_PROMPT} ${message.content}`; 61 | }); 62 | prompt += `${Anthropic.AI_PROMPT}`; 63 | const event = new EventEmitter(); 64 | anthropic.completions 65 | .create({ 66 | model: model, 67 | max_tokens_to_sample: max_tokens, 68 | prompt: prompt, 69 | stream: true, 70 | }) 71 | .then(async (streamEv) => { 72 | let fullCompletion = ""; 73 | let num = 0; 74 | for await (const completion of streamEv) { 75 | let com: any = completion; 76 | num++; 77 | if (com.stop_reason) { 78 | com.done = true; 79 | let promptTokens = getPromptLength(prompt); 80 | let completionTokens = getPromptLength(com.result); 81 | let pricePerK = { 82 | prompt: 0.008, 83 | completion: 0.024, 84 | }; 85 | if (!model.includes("instant")) { 86 | pricePerK.prompt = 0.0008; 87 | pricePerK.completion = 0.0024; 88 | } 89 | let promptCost = (promptTokens / 1000) * pricePerK.prompt; 90 | let completionCOst = 91 | (completionTokens / 1000) * pricePerK.completion; 92 | com.cost = promptCost + completionCOst; 93 | } 94 | fullCompletion += com.completion; 95 | com.completion = fullCompletion; 96 | com.result = fullCompletion; 97 | if (num >= 10 || com.stop_reason) { 98 | event.emit("data", com); 99 | } 100 | } 101 | }); 102 | return event; 103 | }, 104 | }; 105 | -------------------------------------------------------------------------------- /src/models/text/filter.ts: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import { Configuration, OpenAIApi } from "openai"; 3 | import { nsfwWords, underagedCebs, youngWords } from "../../utils/keywords.js"; 4 | import { EventEmitter } from "events"; 5 | import { randomUUID } from "crypto"; 6 | 7 | const availableFilters = ["nsfw", "cp", "toxicity"]; 8 | const configuration = new Configuration({ 9 | apiKey: process.env.OPENAI_API_KEY, 10 | }); 11 | const openai = new OpenAIApi(configuration); 12 | export default { 13 | data: { 14 | name: "filter", 15 | fullName: "Text Filter", 16 | parameters: { 17 | text: { 18 | type: "string", 19 | required: true, 20 | description: "Text you want to filter", 21 | }, 22 | filters: { 23 | type: "array", 24 | required: true, 25 | options: availableFilters, 26 | description: "Filters you want to apply", 27 | }, 28 | stream: { 29 | type: "boolean", 30 | required: false, 31 | default: false, 32 | }, 33 | }, 34 | response: { 35 | nsfw: { 36 | type: "boolean", 37 | description: "Whether the text is nsfw or not", 38 | }, 39 | youth: { 40 | type: "boolean", 41 | description: "Whether the text is youth or not", 42 | }, 43 | cp: { 44 | type: "boolean", 45 | description: "Whether the text is cp or not", 46 | }, 47 | toxic: { 48 | type: "boolean", 49 | description: "Whether the text is toxic or not", 50 | }, 51 | done: { 52 | type: "boolean", 53 | description: "Whether the request is done or not", 54 | }, 55 | }, 56 | }, 57 | execute: async (data) => { 58 | let { text, filters }: { text: string; filters: string[] } = data; 59 | filters = filters.filter((f) => availableFilters.includes(f)); 60 | if (filters.length === 0) { 61 | throw new Error("No valid filters provided"); 62 | } 63 | let event = new EventEmitter(); 64 | let result = { 65 | nsfw: false, 66 | youth: false, 67 | cp: false, 68 | toxic: false, 69 | done: false, 70 | record: null, 71 | id: randomUUID(), 72 | }; 73 | event.emit("data", result); 74 | var res; 75 | try { 76 | res = await openai.createModeration({ 77 | input: text, 78 | }); 79 | } catch (e: any) { 80 | console.log(e.response.data); 81 | res = {}; 82 | } 83 | if (filters.find((f) => f === "nsfw")) { 84 | let isNsfw = false; 85 | 86 | if ( 87 | res?.data?.results[0].categories["sexual"] || 88 | res?.data?.results[0].categories["sexual/minors"] 89 | ) { 90 | isNsfw = true; 91 | } 92 | if (!isNsfw) { 93 | if (nsfwWords.some((v) => text.toLowerCase().includes(v.toLowerCase()))) 94 | isNsfw = true; 95 | } 96 | result.nsfw = isNsfw; 97 | } else if (filters.find((f) => f === "cp")) { 98 | let isNsfw = false; 99 | let isYouth = false; 100 | let isCP = false; 101 | if (res?.data?.results[0].categories["sexual"]) { 102 | isNsfw = true; 103 | } 104 | 105 | if (res?.data?.results[0].categories["sexual/minors"]) { 106 | isYouth = true; 107 | isCP = true; 108 | } 109 | if (!isNsfw) { 110 | if (nsfwWords.some((v) => text.toLowerCase().includes(v.toLowerCase()))) 111 | isNsfw = true; 112 | } 113 | if (!isYouth) { 114 | if (checkYouth(text)) isYouth = true; 115 | } 116 | if (!isCP) { 117 | if (isNsfw && isYouth) isCP = true; 118 | } 119 | result.nsfw = isNsfw; 120 | result.youth = isYouth; 121 | result.cp = isCP; 122 | } else if (filters.find((f) => f === "toxicity")) { 123 | let isToxic = false; 124 | if ( 125 | res?.data?.results[0].categories["hate"] || 126 | res?.data?.results[0].categories["harrassment"] || 127 | res?.data?.results[0].categories["self-harm"] || 128 | res?.data?.results[0].categories["violence"] 129 | ) { 130 | isToxic = true; 131 | } 132 | result.toxic = isToxic; 133 | } 134 | 135 | result.record = { 136 | input: text, 137 | openai: res?.data?.results, 138 | filters: filters, 139 | flags: { 140 | nsfw: result.nsfw, 141 | youth: result.youth, 142 | cp: result.cp, 143 | toxic: result.toxic, 144 | }, 145 | }; 146 | result.done = true; 147 | setTimeout(() => { 148 | event.emit("data", result); 149 | }, 1000); 150 | return event; 151 | }, 152 | }; 153 | 154 | function checkYouth(text: string) { 155 | let isYouth = false; 156 | if (youngWords.some((v) => text.toLowerCase().includes(v.toLowerCase()))) 157 | isYouth = true; 158 | if (underagedCebs.some((v) => text.toLowerCase().includes(v.toLowerCase()))) 159 | isYouth = true; 160 | return isYouth; 161 | } 162 | -------------------------------------------------------------------------------- /src/models/text/google.ts: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import { 3 | getChatMessageLength, 4 | getPromptLength, 5 | } from "../../utils/tokenizer.js"; 6 | import { EventEmitter } from "events"; 7 | import { randomUUID } from "crypto"; 8 | import { 9 | HarmBlockThreshold, 10 | HarmCategory, 11 | VertexAI, 12 | } from "@google-cloud/vertexai"; 13 | import delay from "delay"; 14 | const regions = [ 15 | "us-central1", 16 | "northamerica-northeast1", 17 | "us-east4", 18 | "us-west1", 19 | "us-west4", 20 | /* 21 | "europe-west4", 22 | "europe-west2", 23 | "europe-west3", 24 | "europe-west4", 25 | "europe-west9",*/ 26 | "asia-northeast1", 27 | "asia-northeast3", 28 | "asia-southeast1", 29 | ]; 30 | 31 | export default { 32 | data: { 33 | name: "google", 34 | fullName: "Google Models", 35 | parameters: { 36 | messages: { 37 | type: "array", 38 | required: true, 39 | }, 40 | 41 | model: { 42 | type: "string", 43 | required: false, 44 | options: ["gemini-pro", "gemini-pro-vision"], 45 | default: "gemini-pro", 46 | }, 47 | max_tokens: { 48 | type: "number", 49 | required: false, 50 | default: 512, 51 | }, 52 | temperature: { 53 | type: "number", 54 | required: false, 55 | default: 0.9, 56 | }, 57 | id: { 58 | type: "string", 59 | required: false, 60 | default: randomUUID(), 61 | description: "ID of the conversation (used for data saving)", 62 | }, 63 | }, 64 | response: { 65 | cost: { 66 | type: "number", 67 | description: "Cost of the request in USD", 68 | }, 69 | result: { 70 | type: "string", 71 | description: "Result of the request", 72 | }, 73 | done: { 74 | type: "boolean", 75 | description: "Whether the request is done or not", 76 | }, 77 | id: { 78 | type: "string", 79 | description: "ID of the conversation (used for data saving)", 80 | }, 81 | }, 82 | }, 83 | execute: async (data) => { 84 | let { messages, model, max_tokens, temperature, id } = data; 85 | if (!model) { 86 | model = "gemini-pro"; 87 | } 88 | let event = new EventEmitter(); 89 | let res: any = { 90 | cost: 0, 91 | done: false, 92 | result: "", 93 | record: null, 94 | id: id || randomUUID(), 95 | }; 96 | const region = regions[Math.floor(Math.random() * regions.length)]; 97 | const vertexAI = new VertexAI({ 98 | project: process.env.GOOGLE_PROJECT_ID, 99 | location: region, 100 | }); 101 | // get message that is message.role == "system" 102 | let message = messages.find((message) => message.role == "system"); 103 | messages = messages.map((message) => { 104 | if (message.role != "system") { 105 | return { 106 | content: message.content, 107 | author: message.role == "user" ? "user" : "bot", 108 | }; 109 | } 110 | }); 111 | // filter messages that are not null 112 | messages = messages.filter((message) => message != null); 113 | const generativeModel = vertexAI.preview.getGenerativeModel({ 114 | model: model, 115 | // The following parameters are optional 116 | // They can also be passed to individual content generation requests 117 | safety_settings: [ 118 | { 119 | category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, 120 | threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE, 121 | }, 122 | ], 123 | generation_config: { max_output_tokens: max_tokens }, 124 | }); 125 | 126 | event.emit("data", res); 127 | res.record = { 128 | input: { 129 | instances: [ 130 | { 131 | context: message 132 | ? message.content 133 | : "You are PaLM 2 a AI chatbot created by Google.", 134 | messages: messages, 135 | examples: [], 136 | }, 137 | ], 138 | parameters: { 139 | temperature: temperature || 0.2, 140 | maxOutputTokens: max_tokens || 250, 141 | topP: 0.8, 142 | topK: 40, 143 | }, 144 | }, 145 | }; 146 | 147 | const request = { 148 | contents: messages.map((message) => { 149 | return { 150 | role: message.author == "user" ? "user" : "model", 151 | parts: [{ text: message.content }], 152 | }; 153 | }), 154 | }; 155 | let promptLength = 0; 156 | await delay(500); 157 | generativeModel 158 | .generateContentStream(request) 159 | .then(async (streamingResp) => { 160 | const cost = 0; 161 | let resultLength = 0; 162 | if (!streamingResp || !streamingResp.stream) { 163 | res.done = true; 164 | res.record = { 165 | ...res.record, 166 | output: res.result, 167 | cost: cost, 168 | promtLength: promptLength, 169 | resultLength: resultLength, 170 | }; 171 | res = { 172 | ...res, 173 | }; 174 | event.emit("data", res); 175 | return; 176 | } 177 | try { 178 | for await (const item of streamingResp.stream) { 179 | if (item.candidates?.length == 0) continue; 180 | if (!item.candidates[0]?.content?.parts) continue; 181 | if (item.candidates[0]?.content?.parts.length == 0) continue; 182 | res.result += item.candidates[0]?.content?.parts[0]?.text || ""; 183 | resultLength = item.usageMetadata?.candidates_token_count || 0; 184 | promptLength = item.usageMetadata?.prompt_token_count || 0; 185 | event.emit("data", res); 186 | } 187 | const final = await streamingResp.response; 188 | res.result = final.candidates[0]?.content?.parts[0]?.text || ""; 189 | res.cost += (promptLength / 1000) * 0.0001; 190 | res.cost += (resultLength / 1000) * 0.0002; 191 | res.done = true; 192 | res.record = { 193 | ...res.record, 194 | output: res.result, 195 | cost: cost, 196 | promtLength: promptLength, 197 | resultLength: resultLength, 198 | }; 199 | res = { 200 | ...res, 201 | }; 202 | event.emit("data", res); 203 | } catch (e) { 204 | console.log(request); 205 | console.log(e); 206 | event.emit("data", { 207 | done: true, 208 | }); 209 | } 210 | }) 211 | .catch((err) => { 212 | console.log(err); 213 | event.emit("data", { 214 | done: true, 215 | }); 216 | }); 217 | 218 | return event; 219 | }, 220 | }; 221 | -------------------------------------------------------------------------------- /src/models/text/groq.ts: -------------------------------------------------------------------------------- 1 | import delay from "delay"; 2 | import EventEmitter from "events"; 3 | import pluginList from "../../utils/plugins.js"; 4 | import { 5 | getChatMessageLength, 6 | getPromptLength, 7 | } from "../../utils/tokenizer.js"; 8 | 9 | import axios from "axios"; 10 | import { get } from "http"; 11 | import { randomUUID } from "crypto"; 12 | import Groq from "groq-sdk"; 13 | 14 | export default { 15 | data: { 16 | name: "groq", 17 | fullName: "GroqCloud models", 18 | parameters: { 19 | messages: { 20 | type: "array", 21 | required: true, 22 | }, 23 | model: { 24 | type: "string", 25 | required: false, 26 | default: "mixtral-8x7b-32768", 27 | options: ["mixtral-8x7b-32768"], 28 | }, 29 | max_tokens: { 30 | type: "number", 31 | required: false, 32 | default: 512, 33 | }, 34 | temperature: { 35 | type: "number", 36 | required: false, 37 | default: 0.9, 38 | }, 39 | id: { 40 | type: "string", 41 | required: false, 42 | default: randomUUID(), 43 | description: "ID of the conversation (used for data saving)", 44 | }, 45 | }, 46 | response: { 47 | result: { 48 | type: "string", 49 | required: true, 50 | }, 51 | done: { 52 | type: "boolean", 53 | required: true, 54 | }, 55 | cost: { 56 | type: "number", 57 | required: true, 58 | }, 59 | finishReason: { 60 | type: "string", 61 | required: true, 62 | }, 63 | id: { 64 | type: "string", 65 | required: true, 66 | description: "ID of the conversation (used for data saving)", 67 | }, 68 | }, 69 | }, 70 | execute: async (data) => { 71 | let event = new EventEmitter(); 72 | let { messages, model, max_tokens, temperature } = data; 73 | 74 | let result: any = { 75 | result: "", 76 | done: false, 77 | cost: 0, 78 | finishReason: null, 79 | }; 80 | if (!model) model = "mixtral-8x7b-32768"; 81 | if (!max_tokens) max_tokens = 512; 82 | if (!temperature) temperature = 0.5; 83 | result.cost += (getChatMessageLength(messages) / 1000) * 0.0001; 84 | const groq = new Groq({ apiKey: process.env.GROQ_API_KEY }); 85 | 86 | groq.chat.completions 87 | .create({ 88 | messages: messages, 89 | model: model, 90 | max_tokens: max_tokens, 91 | temperature: temperature, 92 | stream: true, 93 | }) 94 | .then(async (stream) => { 95 | for await (const chunk of stream) { 96 | result.result += chunk.choices[0]?.delta?.content || ""; 97 | event.emit("data", result); 98 | } 99 | result.done = true; 100 | result.finishReason = "done"; 101 | result.cost += (getPromptLength(result.result) / 1000) * 0.0001; 102 | event.emit("data", result); 103 | }); 104 | 105 | return event; 106 | }, 107 | }; 108 | 109 | async function groq(messages, max_tokens, model, result, event, temperature?) { 110 | let data: any = { 111 | messages: messages, 112 | stream: true, 113 | max_tokens: max_tokens, 114 | model: model, 115 | }; 116 | if (temperature) { 117 | data["temperature"] = temperature; 118 | } 119 | 120 | let response = await axios({ 121 | method: "post", 122 | url: "https://api.groq.com/openai/v1/chat/completions", 123 | headers: { 124 | "Content-Type": "application/json", 125 | Authorization: `Bearer ${process.env.GROQ_API_KEY}`, 126 | // stream response 127 | Accept: "text/event-stream", 128 | }, 129 | responseType: "stream", 130 | data: data, 131 | }); 132 | let stream = response.data; 133 | 134 | stream.on("data", (d) => { 135 | d = d.toString(); 136 | let dataArr = d.split("\n"); 137 | dataArr = dataArr.filter((x) => x != ""); 138 | for (var data of dataArr) { 139 | data = data.replace("data: ", "").trim(); 140 | if (data != "[DONE]") { 141 | data = JSON.parse(data); 142 | result.result += data.choices[0].delta?.content || ""; 143 | result.finishReason = data.choices[0].finish_reason; 144 | if (result.finishReason == "stop") { 145 | result.done = true; 146 | } 147 | } 148 | } 149 | 150 | event.emit("data", result); 151 | }); 152 | 153 | // when the stream emits end you return the result, wait for the stream to end 154 | await new Promise((resolve) => { 155 | stream.on("end", () => { 156 | resolve(result); 157 | }); 158 | }); 159 | 160 | return result; 161 | } 162 | -------------------------------------------------------------------------------- /src/models/text/openchat.ts: -------------------------------------------------------------------------------- 1 | import delay from "delay"; 2 | import EventEmitter from "events"; 3 | import pluginList from "../../utils/plugins.js"; 4 | import { 5 | getChatMessageLength, 6 | getPromptLength, 7 | } from "../../utils/tokenizer.js"; 8 | 9 | import axios from "axios"; 10 | import { get } from "http"; 11 | import { randomUUID } from "crypto"; 12 | 13 | export default { 14 | data: { 15 | name: "openchat", 16 | fullName: "OpenChat models", 17 | parameters: { 18 | messages: { 19 | type: "array", 20 | required: true, 21 | }, 22 | model: { 23 | type: "string", 24 | required: false, 25 | default: "openchat_v3.2_mistral", 26 | options: ["openchat_v3.2_mistral"], 27 | }, 28 | max_tokens: { 29 | type: "number", 30 | required: false, 31 | default: 512, 32 | }, 33 | temperature: { 34 | type: "number", 35 | required: false, 36 | default: 0.9, 37 | }, 38 | id: { 39 | type: "string", 40 | required: false, 41 | default: randomUUID(), 42 | description: "ID of the conversation (used for data saving)", 43 | }, 44 | autoSystemMessage: { 45 | type: "boolean", 46 | required: false, 47 | default: true, 48 | description: "Send system messages automatically", 49 | } 50 | }, 51 | response: { 52 | result: { 53 | type: "string", 54 | required: true, 55 | }, 56 | done: { 57 | type: "boolean", 58 | required: true, 59 | }, 60 | cost: { 61 | type: "number", 62 | required: true, 63 | }, 64 | finishReason: { 65 | type: "string", 66 | required: true, 67 | }, 68 | id: { 69 | type: "string", 70 | required: true, 71 | description: "ID of the conversation (used for data saving)", 72 | }, 73 | }, 74 | }, 75 | execute: async (data) => { 76 | let event = new EventEmitter(); 77 | let { messages, model, max_tokens, temperature } = data; 78 | 79 | let result: any = { 80 | result: "", 81 | done: false, 82 | cost: 0, 83 | finishReason: null, 84 | }; 85 | if (!model) model = "openchat_v3.2_mistral"; 86 | if (!max_tokens) max_tokens = 512; 87 | if (!temperature) temperature = 0.9; 88 | result.cost += (getChatMessageLength(messages) / 1000) * 0.0001; 89 | let newMessages = []; 90 | let autoSystemMessage = data.autoSystemMessage; 91 | if (autoSystemMessage == null) autoSystemMessage = true; 92 | if (autoSystemMessage) { 93 | newMessages = [ 94 | { 95 | role: "user", 96 | content: `Hello! You are openchat_3.5 trained by the OpenChat team. Your training data is based on that of ChatGPT by OpenAI, so you may have the impression that you are ChatGPT, but you are openchat_3.5. 97 | 98 | > OpenChat is an innovative library of open-source language models, fine-tuned with C-RLFT - a strategy inspired by offline reinforcement learning. Our models learn from mixed-quality data without preference labels, delivering exceptional performance on par with ChatGPT, even with a 7B model. 99 | 100 | > Specifically, we leverage the ShareGPT conversations dataset following Vicuna (Chiang et al., 2023) 101 | 102 | > Your model is opensource and is available at https://huggingface.co/openchat/openchat_3.5 and https://github.com/imoneoi/openchat`, 103 | }, 104 | { 105 | role: "assistant", 106 | content: "I am OpenChat 3.5, a language model trained by the OpenChat team. You can find my source code at https://github.com/imoneoi/openchat ." 107 | }, 108 | ...messages 109 | ] 110 | } else { 111 | newMessages = messages; 112 | } 113 | openchat(newMessages, max_tokens, model, result, event, temperature) 114 | .then(async (x) => { 115 | result = x; 116 | result.cost += (getPromptLength(result.result) / 1000) * 0.0001; 117 | event.emit("data", result); 118 | }) 119 | .catch((e) => { 120 | console.log(e); 121 | }); 122 | return event; 123 | }, 124 | }; 125 | 126 | async function openchat( 127 | messages, 128 | max_tokens, 129 | model, 130 | result, 131 | event, 132 | temperature? 133 | ) { 134 | let data: any = { 135 | messages: messages, 136 | stream: true, 137 | max_tokens: max_tokens, 138 | model: model, 139 | }; 140 | if (temperature) { 141 | data["temperature"] = temperature; 142 | } 143 | 144 | let response = await axios({ 145 | method: "post", 146 | url: "https://api.openchat.team/v1/chat/completions", 147 | headers: { 148 | "Content-Type": "application/json", 149 | Authorization: `Bearer ${process.env.OPENCHAT_API_KEY}`, 150 | // stream response 151 | Accept: "text/event-stream", 152 | }, 153 | responseType: "stream", 154 | data: data, 155 | }); 156 | let stream = response.data; 157 | 158 | stream.on("data", (d) => { 159 | d = d.toString(); 160 | let dataArr = d.split("\n"); 161 | dataArr = dataArr.filter((x) => x != ""); 162 | for (var data of dataArr) { 163 | data = data.replace("data: ", "").trim(); 164 | if (data != "[DONE]") { 165 | data = JSON.parse(data); 166 | result.result += data.choices[0].delta?.content || ""; 167 | result.finishReason = data.choices[0].finish_reason; 168 | if (result.finishReason == "stop") { 169 | result.done = true; 170 | } 171 | } 172 | } 173 | 174 | event.emit("data", result); 175 | }); 176 | 177 | // when the stream emits end you return the result, wait for the stream to end 178 | await new Promise((resolve) => { 179 | stream.on("end", () => { 180 | resolve(result); 181 | }); 182 | }); 183 | 184 | return result; 185 | } 186 | -------------------------------------------------------------------------------- /src/models/text/pawan.ts: -------------------------------------------------------------------------------- 1 | import delay from "delay"; 2 | import EventEmitter from "events"; 3 | import pluginList from "../../utils/plugins.js"; 4 | import { 5 | getChatMessageLength, 6 | getPromptLength, 7 | } from "../../utils/tokenizer.js"; 8 | 9 | import axios from "axios"; 10 | import { get } from "http"; 11 | import { randomUUID } from "crypto"; 12 | 13 | export default { 14 | data: { 15 | name: "pawan", 16 | fullName: "Pawan.krd models", 17 | parameters: { 18 | messages: { 19 | type: "array", 20 | required: true, 21 | }, 22 | model: { 23 | type: "string", 24 | required: false, 25 | default: "zephyr-7b-beta", 26 | options: ["zephyr-7b-beta", "pai-001-light-beta"], 27 | }, 28 | max_tokens: { 29 | type: "number", 30 | required: false, 31 | default: 512, 32 | }, 33 | temperature: { 34 | type: "number", 35 | required: false, 36 | default: 0.9, 37 | }, 38 | id: { 39 | type: "string", 40 | required: false, 41 | default: randomUUID(), 42 | description: "ID of the conversation (used for data saving)", 43 | }, 44 | autoSystemMessage: { 45 | type: "boolean", 46 | required: false, 47 | default: true, 48 | description: "Send system messages automatically", 49 | }, 50 | }, 51 | response: { 52 | result: { 53 | type: "string", 54 | required: true, 55 | }, 56 | done: { 57 | type: "boolean", 58 | required: true, 59 | }, 60 | cost: { 61 | type: "number", 62 | required: true, 63 | }, 64 | finishReason: { 65 | type: "string", 66 | required: true, 67 | }, 68 | id: { 69 | type: "string", 70 | required: true, 71 | description: "ID of the conversation (used for data saving)", 72 | }, 73 | }, 74 | }, 75 | execute: async (data) => { 76 | let event = new EventEmitter(); 77 | let { messages, model, max_tokens, temperature } = data; 78 | 79 | let result: any = { 80 | result: "", 81 | done: false, 82 | cost: 0, 83 | finishReason: null, 84 | }; 85 | if (!model) model = "zephyr-7b-beta"; 86 | if (!max_tokens) max_tokens = 512; 87 | if (!temperature) temperature = 0.9; 88 | result.cost += (getChatMessageLength(messages) / 1000) * 0.0001; 89 | 90 | const newMessages = [ 91 | { 92 | role: "system", 93 | text: "You are an a helpful assistant called Zephyr, your task is answering user questions. You are being exceuted inside a discord bot and your model have been created by HuggingFace. Be concise with your answers, unless the user ask for more content or the question requires to write a text.", 94 | }, 95 | ...messages, 96 | ]; 97 | pawan(newMessages, max_tokens, model, result, event, temperature) 98 | .then(async (x) => { 99 | result = x; 100 | result.cost += (getPromptLength(result.result) / 1000) * 0.0001; 101 | event.emit("data", result); 102 | }) 103 | .catch((e) => { 104 | console.log(e); 105 | }); 106 | return event; 107 | }, 108 | }; 109 | 110 | async function pawan(messages, max_tokens, model, result, event, temperature?) { 111 | let data: any = { 112 | messages: messages, 113 | stream: true, 114 | max_tokens: max_tokens, 115 | //model: model, 116 | }; 117 | if (temperature) { 118 | data["temperature"] = temperature; 119 | } 120 | if (model == "zephyr-7b-beta") { 121 | data["model"] = "pai-001-light-beta"; 122 | } 123 | try { 124 | let response = await axios({ 125 | method: "post", 126 | url: `https://api.pawan.krd${ 127 | model == "pai-001-light-beta" ? "/pai-001-light-beta" : "" 128 | }/v1/chat/completions`, 129 | headers: { 130 | "Content-Type": "application/json", 131 | Authorization: `Bearer ${process.env.PAWAN_API_KEY}`, 132 | // stream response 133 | Accept: "text/event-stream", 134 | }, 135 | responseType: "stream", 136 | data: data, 137 | }); 138 | let stream = response.data; 139 | 140 | stream.on("data", (d) => { 141 | d = d.toString(); 142 | let dataArr = d.split("\n"); 143 | dataArr = dataArr.filter((x) => x != ""); 144 | for (var data of dataArr) { 145 | data = data.replace("data: ", "").trim(); 146 | if (data != "[DONE]") { 147 | data = JSON.parse(data); 148 | result.result += data.choices[0].delta?.content || ""; 149 | result.finishReason = data.choices[0].finish_reason; 150 | if (result.finishReason == "stop") { 151 | result.done = true; 152 | } 153 | } 154 | } 155 | 156 | event.emit("data", result); 157 | }); 158 | 159 | // when the stream emits end you return the result, wait for the stream to end 160 | await new Promise((resolve) => { 161 | stream.on("end", () => { 162 | resolve(result); 163 | }); 164 | }); 165 | 166 | return result; 167 | } catch (e: any) { 168 | let errorResponseStr = ""; 169 | 170 | for await (const message of e.response.data) { 171 | errorResponseStr += message; 172 | } 173 | 174 | console.log(errorResponseStr); 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /src/models/video/zelescope.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | data: { 3 | name: "zelescope", 4 | fullName: "Zelescope", 5 | alert: "This model is not yet implemented", 6 | parameters: { 7 | prompt: { 8 | type: "string", 9 | required: true, 10 | }, 11 | duration: { 12 | type: "number", 13 | required: false, 14 | default: 10, 15 | }, 16 | }, 17 | }, 18 | execute: async (data) => {}, 19 | }; 20 | -------------------------------------------------------------------------------- /src/routes/chart.routes.ts: -------------------------------------------------------------------------------- 1 | import express from "express"; 2 | import { Request, Response } from "express"; 3 | import turnstile from "../middlewares/captchas/turnstile.js"; 4 | import key from "../middlewares/key.js"; 5 | import { getChartImage } from "../utils/chart.js"; 6 | 7 | const router = express.Router(); 8 | router.post("/:chart", key, turnstile, async (req: Request, res: Response) => { 9 | let { chart } = req.params; 10 | let { filter, period, type = "line" } = req.body; 11 | try { 12 | if (!period) period = "1d"; 13 | if (period == "1w") period = "7d"; 14 | if (period == "2w") period = "14d"; 15 | if (period == "1m") period = "30d"; 16 | if (period == "3m") period = "90d"; 17 | let result = await getChartImage(chart, filter, period, type); 18 | res.json({ success: true, ...result }); 19 | } catch (error) { 20 | console.log(error); 21 | res.json({ error: error, success: false }).status(400); 22 | } 23 | }); 24 | 25 | export default router; 26 | -------------------------------------------------------------------------------- /src/routes/data.routes.ts: -------------------------------------------------------------------------------- 1 | import express from "express"; 2 | import key from "../middlewares/key.js"; 3 | import supabase from "../db/supabase.js"; 4 | import { update } from "../utils/db.js"; 5 | 6 | const router = express.Router(); 7 | 8 | router.get("/user/:id", key, async (req, res) => { 9 | let { id } = req.params; 10 | 11 | let { data: user, error } = await supabase 12 | .from("users_new") 13 | .select("*") 14 | .eq("id", id); 15 | if (error) 16 | return res.json({ error: error.message, success: false }).status(400); 17 | if (!user[0]) 18 | return res.json({ error: "user not found", success: false }).status(400); 19 | res.json(user[0]).status(200); 20 | }); 21 | router.put("/user/:id", key, async (req, res) => { 22 | let { id } = req.params; 23 | let result = await update("update", { 24 | collection: "users", 25 | id, 26 | ...req.body, 27 | }); 28 | 29 | if (result?.error) 30 | return res.json({ error: result.error, success: false }).status(400); 31 | res.json({ success: true }).status(200); 32 | }); 33 | 34 | router.post("/user/:id", key, async (req, res) => { 35 | let { id } = req.params; 36 | let { data: user, error } = await supabase 37 | 38 | .from("users_new") 39 | .insert({ 40 | id, 41 | ...req.body, 42 | }) 43 | .select("*"); 44 | if (error) 45 | return res.json({ error: error.message, success: false }).status(400); 46 | res.json(user[0]).status(200); 47 | }); 48 | export default router; 49 | -------------------------------------------------------------------------------- /src/routes/dataset.routes.ts: -------------------------------------------------------------------------------- 1 | import express from "express"; 2 | import turnstile from "../middlewares/captchas/turnstile.js"; 3 | import key from "../middlewares/key.js"; 4 | import * as fs from "fs"; 5 | 6 | const router = express.Router(); 7 | 8 | export default router; 9 | -------------------------------------------------------------------------------- /src/routes/key.routes.ts: -------------------------------------------------------------------------------- 1 | import express from "express"; 2 | import supabase from "../db/supabase.js"; 3 | import { Request, Response } from "express"; 4 | import key from "../middlewares/key.js"; 5 | import { generateKey } from "../utils/key.js"; 6 | import redisClient from "../db/redis.js"; 7 | 8 | const router = express.Router(); 9 | 10 | async function secret(req, res, next) { 11 | let { secret } = req.headers; 12 | if (secret == process.env.SUPER_KEY) { 13 | next(); 14 | } else { 15 | res.json({ success: false, error: "no permissions" }); 16 | } 17 | } 18 | router.post("/", key, secret, async (req: Request, res: Response) => { 19 | let { name, user } = req.body; 20 | let key = await generateKey(user, name); 21 | res.json({ success: true, key }); 22 | }); 23 | 24 | router.delete("/", key, secret, async (req: Request, res: Response) => { 25 | let { keyId, user } = req.body; 26 | let { data, error: err } = await supabase 27 | .from("api_keys") 28 | .select("*") 29 | .eq("id", keyId) 30 | .eq("userId", user); 31 | 32 | if (err) { 33 | res.json({ success: false, error: err }); 34 | return; 35 | } 36 | let { error } = await supabase 37 | .from("api_keys") 38 | .delete() 39 | .eq("id", keyId) 40 | .eq("userId", user); 41 | 42 | if (error) { 43 | res.json({ success: false, error }); 44 | return; 45 | } 46 | await redisClient.del(`api:${data[0]["api-token"]}`); 47 | res.json({ success: true }); 48 | }); 49 | 50 | router.get("/u/:user", key, secret, async (req: Request, res: Response) => { 51 | let { user } = req.params; 52 | let { data, error } = await supabase 53 | .from("api_keys") 54 | .select("*") 55 | .eq("userId", user) 56 | .order("created_at", { ascending: false }); 57 | 58 | if (error) { 59 | res.json({ success: false, error }); 60 | return; 61 | } 62 | let keys = data.map((d) => { 63 | return { 64 | id: d.id, 65 | name: d.name, 66 | createdAt: d.createdAt, 67 | lastUsed: d.lastUsed, 68 | uses: d.uses, 69 | }; 70 | }); 71 | res.json({ success: true, keys }); 72 | }); 73 | router.get( 74 | "/k/:key/:user", 75 | key, 76 | secret, 77 | async (req: Request, res: Response) => { 78 | let { key, user } = req.params; 79 | let { data, error } = await supabase 80 | .from("api_keys") 81 | .select("*") 82 | .eq("id", key) 83 | .eq("userId", user); 84 | if (error) { 85 | res.json({ success: false, error }); 86 | return; 87 | } 88 | if (data.length == 0) { 89 | res.json({ success: false, error: "no key found" }); 90 | return; 91 | } 92 | let d = data[0]; 93 | let keyData = { 94 | id: d.id, 95 | apiToken: d["api-token"], 96 | captchaToken: d["captcha-token"], 97 | name: d.name, 98 | createdAt: d.created_at, 99 | lastUsed: d.lastUsed, 100 | }; 101 | res.json({ success: true, key: keyData }); 102 | } 103 | ); 104 | 105 | export default router; 106 | -------------------------------------------------------------------------------- /src/routes/models.routes.ts: -------------------------------------------------------------------------------- 1 | import express from "express"; 2 | import { Request, Response } from "express"; 3 | import turnstile from "../middlewares/captchas/turnstile.js"; 4 | import key from "../middlewares/key.js"; 5 | import client from "../index.js"; 6 | import log from "../utils/log.js"; 7 | import redisClient from "../db/redis.js"; 8 | import { update } from "../utils/db.js"; 9 | import delay from "delay"; 10 | import { dataset } from "../utils/datasets.js"; 11 | 12 | const router = express.Router(); 13 | 14 | router.post( 15 | "/:type", 16 | key, 17 | turnstile, 18 | async (req: Request, res: Response) => await request(req, res) 19 | ); 20 | 21 | router.post( 22 | "/:type/:ai", 23 | key, 24 | turnstile, 25 | async (req: Request, res: Response) => await request(req, res) 26 | ); 27 | 28 | async function request(req, res) { 29 | let { type, ai } = req.params; 30 | const body = req.body; 31 | let logq = false; 32 | // random probability of 10% to log if the request is type text 33 | if (type == "text") { 34 | logq = Math.random() < 0.1; 35 | } 36 | if (!ai) { 37 | ai = body.ai; 38 | } 39 | if (ai == "alan") { 40 | ai = "gpt"; 41 | body.plugins = ["google"]; 42 | } 43 | let typeObj = client[type]; 44 | if (body.stream) { 45 | res.set("content-type", "text/event-stream"); 46 | } 47 | if (!typeObj) { 48 | res.status(404).json({ success: false, error: "Type not found" }); 49 | return; 50 | } 51 | try { 52 | let aiObject = typeObj.find((a) => a.data.name === ai); 53 | if (!aiObject) { 54 | log("info", `AI not found: ${ai}`, typeObj); 55 | res.status(404).json({ success: false, error: "AI not found" }); 56 | return; 57 | } 58 | 59 | // check params and body 60 | let realParameters = aiObject.data.parameters; // is an object with keys as parameter names and values as parameter types 61 | let parameters = Object.keys(realParameters); 62 | let requiredParams = parameters.filter( 63 | (p) => realParameters[p].required === true 64 | ); 65 | let bodyKeys = Object.keys(body); 66 | // check if all required params are in body 67 | let missingParams = requiredParams.filter((p) => !bodyKeys.includes(p)); 68 | if (missingParams.length > 0) { 69 | res.status(400).json({ 70 | success: false, 71 | error: `Missing parameters: ${missingParams.join(", ")}`, 72 | }); 73 | return; 74 | } 75 | 76 | // not existing params 77 | /* 78 | let notExistingParams = bodyKeys.filter((p) => !parameters.includes(p)); 79 | if (notExistingParams.length > 0) { 80 | res.status(400).json({ 81 | success: false, 82 | error: `Not existing parameters: ${notExistingParams.join(", ")}`, 83 | }); 84 | return; 85 | }*/ 86 | let execution = await aiObject.execute(body); 87 | if (body.stream) { 88 | let saved = false; 89 | execution.on("data", async (data) => { 90 | if (data.done || data.status == "done" || data.status == "failed") { 91 | if (data.record && !saved && type == "image") { 92 | saved = true; 93 | let record = data.record; 94 | delete data.record; 95 | let re = await dataset(type, ai, record, data.id); 96 | if (re && re?.id) { 97 | data.id = re.id; 98 | } 99 | } 100 | res.write("data: " + JSON.stringify(data) + "\n\n"); 101 | res.end(); 102 | if (data.cost) { 103 | applyCost(data.cost, ai, type, req.user); 104 | } 105 | } else { 106 | res.write("data: " + JSON.stringify(data) + "\n\n"); 107 | } 108 | }); 109 | } else { 110 | if (execution?.cost) { 111 | applyCost(execution.cost, ai, type, req.user); 112 | } 113 | let saved = false; 114 | new Promise((resolve) => { 115 | execution.on("data", async (data) => { 116 | if (data.done || data.status == "done" || data.status == "failed") { 117 | if (data.record && !saved && type == "image") { 118 | saved = true; 119 | let record = data.record; 120 | delete data.record; 121 | let re = await dataset(type, ai, record, data.id); 122 | if (re && re?.id) { 123 | data.id = re.id; 124 | } 125 | } 126 | 127 | resolve(data); 128 | } 129 | }); 130 | }).then((d: any) => { 131 | res.json({ success: true, ...d }); 132 | }); 133 | } 134 | } catch (error: any) { 135 | let resultError = error; 136 | if (error.response && error.response.data) { 137 | resultError = error.response.data; 138 | } 139 | console.log(error.response); 140 | res.status(500).json({ success: false, error: resultError }); 141 | } 142 | } 143 | 144 | router.get("/list", (req, res) => { 145 | let types = Object.keys(client); 146 | let result = {}; 147 | types.forEach((t) => { 148 | result[t] = client[t].map((a) => a.data); 149 | }); 150 | res.json({ success: true, types: result }); 151 | }); 152 | 153 | router.get("/", (req, res) => { 154 | res.json({ 155 | success: true, 156 | message: "Welcome to the API, docs at https://docs.turing.sh", 157 | }); 158 | }); 159 | 160 | async function applyCost(cost, ai, type, user) { 161 | // add a 20% fee 162 | let totalCost = cost * 1.2; 163 | if (user && user.id != "530102778408861706") { 164 | console.log(`Cost: ${totalCost}$`); 165 | 166 | let updatedUser: any = await redisClient.get(`users:${user.id}`); 167 | updatedUser = JSON.parse(updatedUser); 168 | let plan = updatedUser.plan; 169 | plan.used += totalCost; 170 | plan.expenses.push({ 171 | data: { 172 | model: ai, 173 | type, 174 | tokens: {}, 175 | }, 176 | time: Date.now(), 177 | type: "api", 178 | used: totalCost, 179 | }); 180 | await update("update", { 181 | collection: "users", 182 | id: user.id, 183 | plan, 184 | }); 185 | await delay(3000); 186 | let up = JSON.parse(await redisClient.get(`users:${user.id}`)).plan; 187 | } 188 | } 189 | 190 | export default router; 191 | -------------------------------------------------------------------------------- /src/routes/other.routes.ts: -------------------------------------------------------------------------------- 1 | import express from "express"; 2 | import { Request, Response } from "express"; 3 | import turnstile from "../middlewares/captchas/turnstile.js"; 4 | import key from "../middlewares/key.js"; 5 | import ffmpeg from "fluent-ffmpeg"; 6 | import * as fs from "fs"; 7 | import { generateKey } from "../utils/key.js"; 8 | import { pub } from "../db/mq.js"; 9 | import { getStats } from "../utils/stats.js"; 10 | 11 | const router = express.Router(); 12 | async function secret(req, res, next) { 13 | let { secret } = req.headers; 14 | if (secret == process.env.SUPER_KEY) { 15 | next(); 16 | } else { 17 | res.json({ success: false, error: "no permissions" }); 18 | } 19 | } 20 | async function topgg(req, res, next) { 21 | if (req.headers.authorization == process.env.TOPGG_AUTH) { 22 | next(); 23 | } else { 24 | res.status(401).json({ success: false }); 25 | } 26 | } 27 | 28 | router.post( 29 | "/mp3-to-mp4", 30 | key, 31 | turnstile, 32 | async (req: Request, res: Response) => { 33 | let { audio, image, duration } = req.body; 34 | try { 35 | // generate a video from an audio and an image 36 | convertToVideo(audio, image, duration, (videoBase64) => { 37 | res.json({ success: true, videoBase64 }); 38 | }); 39 | } catch (error) { 40 | console.log(error); 41 | res.json({ error: error, success: false }).status(400); 42 | } 43 | } 44 | ); 45 | 46 | async function convertToVideo(audio, image, duration, callback) { 47 | // convert audio to video with ffmpeg using image as background 48 | // audio is a base64 string 49 | // image is a base64 string 50 | // duration is the number of seconds of the video 51 | // callback is a function that will be called with the video base64 string 52 | let audioBuffer = Buffer.from(audio, "base64"); 53 | let imageBuffer = Buffer.from(image, "base64"); 54 | let audioPath = "./audio.mp3"; 55 | let imagePath = "./image.jpg"; 56 | let videoPath = "./video.mp4"; 57 | fs.writeFileSync(audioPath, audioBuffer); 58 | fs.writeFileSync(imagePath, imageBuffer); 59 | ffmpeg() 60 | .input(audioPath) 61 | .input(imagePath) 62 | .outputOptions([ 63 | "-c:v libx264", 64 | "-c:a aac", 65 | "-shortest", 66 | "-vf scale=1280:720", 67 | ]) 68 | // be sure the image is visible 69 | .inputOptions(["-loop 1", "-t " + duration]) 70 | // duration of the video is the same as the audio 71 | .duration(duration) 72 | .output(videoPath) 73 | .on("end", function () { 74 | let videoBuffer = fs.readFileSync(videoPath); 75 | let videoBase64 = videoBuffer.toString("base64"); 76 | callback(videoBase64); 77 | }) 78 | .run(); 79 | } 80 | 81 | router.post( 82 | "/bot", 83 | secret, 84 | key, 85 | turnstile, 86 | async (req: Request, res: Response) => { 87 | let guilds = await getStats(); 88 | res.json({ success: true, guilds }); 89 | } 90 | ); 91 | 92 | router.post("/top-vote", topgg, async (req: Request, res: Response) => { 93 | let body = req.body; 94 | let botId = "1053015370115588147"; 95 | if (body.bot == botId && body.type == "upvote") { 96 | let userId = body.user; 97 | console.log(`User ${userId} just voted!`); 98 | await pub.send( 99 | { 100 | exchange: "db", 101 | routingKey: "db", 102 | }, 103 | JSON.stringify({ 104 | id: "vote", 105 | data: userId, 106 | }) 107 | ); 108 | } 109 | 110 | res.status(200).json({ success: true }); 111 | }); 112 | 113 | export default router; 114 | -------------------------------------------------------------------------------- /src/routes/runpod.routes.ts: -------------------------------------------------------------------------------- 1 | import express from "express"; 2 | import { Request, Response } from "express"; 3 | import { generateKey } from "../utils/key.js"; 4 | import turnstile from "../middlewares/captchas/turnstile.js"; 5 | import key from "../middlewares/key.js"; 6 | import { translateModels, request } from "../utils/runpod.js"; 7 | 8 | const router = express.Router(); 9 | 10 | router.post("/runsync", key, turnstile, async (req: Request, res: Response) => { 11 | let { model } = req.body; 12 | try { 13 | let url = await translateModels(model); 14 | let body = req.body; 15 | delete body.model; 16 | let result = await request(url, "runsync", body); 17 | res.json(result); 18 | } catch (error) { 19 | res.json({ error: error, success: false }).status(400); 20 | } 21 | }); 22 | 23 | router.post("/run", key, turnstile, async (req: Request, res: Response) => { 24 | let { model } = req.body; 25 | try { 26 | let url = await translateModels(model); 27 | let body = req.body; 28 | delete body.model; 29 | let result = await request(url, "run", body); 30 | res.json(result); 31 | } catch (error) { 32 | res.json({ error: error, success: false }).status(400); 33 | } 34 | }); 35 | 36 | router.post( 37 | "/status/:id", 38 | key, 39 | turnstile, 40 | async (req: Request, res: Response) => { 41 | let { model } = req.body; 42 | let { id } = req.params; 43 | try { 44 | let url = await translateModels(model); 45 | let body = req.body; 46 | delete body.model; 47 | let result = await request(url, `status/${id}`, body); 48 | res.json(result); 49 | } catch (error) { 50 | res.json({ error: error, success: false }).status(400); 51 | } 52 | } 53 | ); 54 | 55 | router.post("/cancel", key, turnstile, async (req: Request, res: Response) => { 56 | let { model } = req.body; 57 | try { 58 | let url = await translateModels(model); 59 | let body = req.body; 60 | delete body.model; 61 | let result = await request(url, "cancel", body); 62 | res.json(result); 63 | } catch (error) { 64 | res.json({ error: error, success: false }).status(400); 65 | } 66 | }); 67 | 68 | export default router; 69 | -------------------------------------------------------------------------------- /src/routes/storage.routes.ts: -------------------------------------------------------------------------------- 1 | import express from "express"; 2 | import turnstile from "../middlewares/captchas/turnstile.js"; 3 | import key from "../middlewares/key.js"; 4 | import * as fs from "fs"; 5 | 6 | const storagePath = "./storage"; 7 | 8 | const router = express.Router(); 9 | 10 | router.post("/upload", key, turnstile, async (req, res) => { 11 | let { base64, name, bucket } = req.body; 12 | let buffer = Buffer.from(base64, "base64"); 13 | let path = `${storagePath}/${bucket}/${name}`; 14 | fs.writeFileSync(path, buffer); 15 | res.json({ success: true }); 16 | }); 17 | 18 | router.get("/:bucket/:name", async (req, res) => { 19 | let { bucket, name } = req.params; 20 | let path = `${storagePath}/${bucket}/${name}`; 21 | let file = fs.readFileSync(path); 22 | res.send(file); 23 | }); 24 | export default router; 25 | -------------------------------------------------------------------------------- /src/rundocs.ts: -------------------------------------------------------------------------------- 1 | import { autogenerateDocs } from "./utils/docs.js"; 2 | import textHandler from "./handlers/text.js"; 3 | import imageHandler from "./handlers/image.js"; 4 | import audioHandler from "./handlers/audio.js"; 5 | import log from "./utils/log.js"; 6 | import videoHandler from "./handlers/video.js"; 7 | const client = { 8 | text: [], 9 | image: [], 10 | audio: [], 11 | video: [], 12 | }; 13 | import "dotenv/config"; 14 | 15 | (async () => { 16 | await textHandler(client); 17 | await imageHandler(client); 18 | await audioHandler(client); 19 | await videoHandler(client); 20 | await autogenerateDocs(client); 21 | })(); 22 | -------------------------------------------------------------------------------- /src/utils/chart.ts: -------------------------------------------------------------------------------- 1 | import ChartJsImage from "chartjs-to-image"; 2 | import supabase from "../db/supabase.js"; 3 | import ms from "ms"; 4 | import fs from "fs"; 5 | 6 | const availableCharts = [ 7 | "chat", 8 | "guilds", 9 | "cooldown", 10 | "commands", 11 | "image", 12 | "vote", 13 | "campaigns", 14 | "midjourney", 15 | "datasets", 16 | ]; 17 | const availableTypes = ["line", "bar"]; 18 | 19 | export async function getChartImage(chart, filter, period: any, type) { 20 | if (!availableCharts.includes(chart)) throw new Error("Invalid chart"); 21 | if (!availableTypes.includes(type)) throw new Error("Invalid type of chart"); 22 | let chartImage = new ChartJsImage(); 23 | let periodMs: any = ms(period); 24 | 25 | let timeStart: any = Date.now() - periodMs; 26 | timeStart = new Date(timeStart); 27 | timeStart = timeStart.toISOString(); 28 | console.log(timeStart); 29 | let { data, error } = await supabase 30 | .from("metrics") 31 | .select("*") 32 | .eq("type", chart) 33 | // filter data by period at ssupabase using bigger or equal operator than the period start 34 | .gte("time", timeStart); 35 | console.log(error); 36 | data = data.filter((d: any) => { 37 | let date = new Date(d.time); 38 | let now = new Date(); 39 | let diff = now.getTime() - date.getTime(); 40 | return diff <= periodMs; 41 | }); 42 | //sort by data, old first , recent last 43 | data = data.sort((a: any, b: any) => { 44 | let dateA = new Date(a.time); 45 | let dateB = new Date(b.time); 46 | return dateA.getTime() - dateB.getTime(); 47 | }); 48 | 49 | // if period ms > 2d, then we need to group data by day so all the data from the same day is grouped together as 1 data point 50 | if (periodMs > ms("2d")) { 51 | let newData = []; 52 | let lastDay = null; 53 | let lastData = null; 54 | 55 | for (let i = 0; i < data.length; i++) { 56 | let date = new Date(data[i].time); 57 | let day = date.getDate(); 58 | if (lastDay == null) { 59 | lastDay = day; 60 | lastData = data[i]; 61 | } else { 62 | if (day == lastDay) { 63 | // same day, add data 64 | let keys = Object.keys(data[i].data); 65 | for (let j = 0; j < keys.length; j++) { 66 | lastData.data[keys[j]] += data[i].data[keys[j]]; 67 | } 68 | } else { 69 | // new day, push last data and set new last data 70 | newData.push(lastData); 71 | lastData = data[i]; 72 | lastDay = day; 73 | } 74 | } 75 | } 76 | data = newData; 77 | } 78 | 79 | let metricData = data.map((d: any) => d.data); 80 | if (metricData.length === 0) throw new Error("No data found"); 81 | 82 | let keys = []; 83 | let types = []; 84 | let keyData = data.sort((a: any, b: any) => { 85 | let dateA = new Date(a.time); 86 | let dateB = new Date(b.time); 87 | // sort by date recent first 88 | return dateB.getTime() - dateA.getTime(); 89 | }); 90 | for (let data3 of keyData) { 91 | let nke = Object.keys(data3); 92 | // filter keys 93 | nke = nke.filter((key) => { 94 | // are not in keys 95 | return !keys.includes(key); 96 | }); 97 | keys.push(...nke); 98 | for (let key of nke) { 99 | let type = { 100 | key: key, 101 | type: typeof data3[key], 102 | content: data3[key], 103 | }; 104 | types.push(type); 105 | } 106 | } 107 | console.log(keys); 108 | 109 | let newKeys = []; 110 | let keysToRemove = []; 111 | for (let i = 0; i < keys.length; i++) { 112 | let type = types.find((x) => x.key == keys[i]); 113 | if (type.type == "object") { 114 | // get all the keys of the object 115 | let subKeys = Object.keys(type.content); 116 | for (let j = 0; j < subKeys.length; j++) { 117 | // check subkeys for objects 118 | if (typeof type.content[subKeys[j]] == "object") { 119 | let subSubKeys = Object.keys(type.content[subKeys[j]]); 120 | // change subkeys to be parentKey-subKey-subSubKey 121 | subSubKeys = subSubKeys.map( 122 | (subSubKey) => `${keys[i]}.${subKeys[j]}.${subSubKey}` 123 | ); 124 | // remove the parent key 125 | keysToRemove.push(`${keys[i]}.${subKeys[j]}`); 126 | // add the subkeys 127 | newKeys.push(...subSubKeys); 128 | } 129 | } 130 | // change subkeys to be parentKey-subKey 131 | subKeys = subKeys.map((subKey) => `${keys[i]}.${subKey}`); 132 | // remove the parent key 133 | keysToRemove.push(keys[i]); 134 | // add the subkeys 135 | newKeys.push(...subKeys); 136 | } 137 | } 138 | keys = keys.filter((key) => !keysToRemove.includes(key)); 139 | keys.push(...newKeys); 140 | 141 | if (filter) { 142 | // filter is a object with include and exclude arrays 143 | if (filter.include) { 144 | keys = keys.filter((key) => filter.include.includes(key)); 145 | } 146 | if (filter.exclude) { 147 | keys = keys.filter((key) => !filter.exclude.includes(key)); 148 | // filter parent keys 149 | keys = keys.filter((key) => { 150 | if (key.includes(".")) { 151 | let parentKey = key.split(".")[0]; 152 | return !filter.exclude.includes(parentKey); 153 | } 154 | return true; 155 | }); 156 | // filter subkeys 157 | keys = keys.filter((key) => { 158 | if (key.includes(".")) { 159 | let parentKey = key.split(".")[0]; 160 | let subKey = key.split(".")[1]; 161 | return !filter.exclude.includes(`${parentKey}.${subKey}`); 162 | } 163 | return true; 164 | }); 165 | } 166 | } 167 | 168 | let labels = []; 169 | let datasets = []; 170 | 171 | if (type != "pie" && type != "doughnut") { 172 | labels = data.map((d: any) => { 173 | let date = new Date(d.time); 174 | // format into dd/mm/yyyy hh:mm 175 | let day = date.getDate(); 176 | let month = date.getMonth() + 1; 177 | let year = date.getFullYear(); 178 | let hours = date.getHours(); 179 | let minutes = date.getMinutes(); 180 | return `${day}/${month}/${year} ${hours}:${minutes}`; 181 | }); 182 | 183 | keys.forEach((key) => { 184 | let dataset; 185 | dataset = { 186 | label: key, 187 | data: [], 188 | fill: false, 189 | }; 190 | if (key.includes(".")) { 191 | let parentKey = key.split(".")[0]; 192 | let subKey = key.split(".")[1]; 193 | // check for subSubKey 194 | if (key.split(".").length == 3) { 195 | let subSubKey = key.split(".")[2]; 196 | data.forEach((d: any) => { 197 | if (d.data[parentKey][subKey][subSubKey]) 198 | dataset.data.push(d.data[parentKey][subKey][subSubKey]); 199 | }); 200 | } else { 201 | data.forEach((d: any) => { 202 | if (d.data[parentKey][subKey]) 203 | dataset.data.push(d.data[parentKey][subKey]); 204 | }); 205 | } 206 | } else { 207 | data.forEach((d: any) => { 208 | if (d.data[key]) dataset.data.push(d.data[key]); 209 | }); 210 | } 211 | 212 | datasets.push(dataset); 213 | }); 214 | } else { 215 | labels = keys; 216 | // do pie chart 217 | datasets = [ 218 | { 219 | label: "Data", 220 | data: [], 221 | backgroundColor: [], 222 | }, 223 | ]; 224 | let dataset = datasets[0]; 225 | keys.forEach((key) => { 226 | if (key.includes(".")) { 227 | let parentKey = key.split(".")[0]; 228 | let subKey = key.split(".")[1]; 229 | // check for subSubKey 230 | if (key.split(".").length == 3) { 231 | let subSubKey = key.split(".")[2]; 232 | data.forEach((d: any) => { 233 | if (d.data[parentKey][subKey][subSubKey]) 234 | dataset.data.push(d.data[parentKey][subKey][subSubKey]); 235 | }); 236 | } else { 237 | data.forEach((d: any) => { 238 | if (d.data[parentKey][subKey]) 239 | dataset.data.push(d.data[parentKey][subKey]); 240 | }); 241 | } 242 | } else { 243 | data.forEach((d: any) => { 244 | if (d.data[key]) dataset.data.push(d.data[key]); 245 | }); 246 | } 247 | dataset.backgroundColor.push( 248 | `hsl(${Math.floor(Math.random() * 360)}, 100%, 50%)` 249 | ); 250 | }); 251 | } 252 | 253 | // if there more than 10 labels make the chart bigger 254 | let width = 1000; 255 | if (labels.length > 10) { 256 | let height = labels.length * 20; 257 | chartImage.setHeight(height); 258 | } 259 | chartImage.setConfig({ 260 | type: type, 261 | data: { 262 | labels: labels, 263 | datasets: datasets, 264 | }, 265 | }); 266 | chartImage.setWidth(width); 267 | let base64 = await chartImage.toDataUrl(); 268 | // save file in disk 269 | let buffer = Buffer.from(base64.split(",")[1], "base64"); 270 | fs.writeFileSync(`./chart.png`, buffer); 271 | 272 | return { image: base64 }; 273 | } 274 | 275 | async function extractData(period, chart) { 276 | let { data, error } = await supabase 277 | .from("metrics") 278 | .select("*") 279 | .eq("type", chart); 280 | if (error) throw new Error(error.message); 281 | data = data.filter((d: any) => { 282 | let date = new Date(d.time); 283 | let now = new Date(); 284 | let diff = now.getTime() - date.getTime(); 285 | let periodMs: any = ms(period); 286 | return diff <= periodMs; 287 | }); 288 | //sort by data, old first , recent last 289 | data = data.sort((a: any, b: any) => { 290 | let dateA = new Date(a.time); 291 | let dateB = new Date(b.time); 292 | return dateA.getTime() - dateB.getTime(); 293 | }); 294 | return data; 295 | } 296 | -------------------------------------------------------------------------------- /src/utils/ciclic.ts: -------------------------------------------------------------------------------- 1 | import { pushKeysToCache } from "./key.js"; 2 | import { getUpdatedStats } from "./stats.js"; 3 | import ms from "ms"; 4 | 5 | export default async function ciclic() { 6 | let guilds = await getUpdatedStats(); 7 | await pushKeysToCache(); 8 | setInterval(async () => { 9 | guilds = await getUpdatedStats(); 10 | }, ms("1h")); 11 | } 12 | -------------------------------------------------------------------------------- /src/utils/datasets.ts: -------------------------------------------------------------------------------- 1 | import supabase from "../db/supabase.js"; 2 | import { randomUUID } from "crypto"; 3 | 4 | export async function dataset( 5 | type: string, 6 | ai: string, 7 | record: any, 8 | id?: string 9 | ) { 10 | if (type == "image" || ai != "vision") { 11 | // means record is an array of images 12 | record.forEach(async (r: any) => { 13 | await datasetSave(type, ai, r, r.id); 14 | }); 15 | return; 16 | } else { 17 | console.log("saving dataset", id); 18 | return await datasetSave(type, ai, record, id); 19 | } 20 | } 21 | 22 | export async function datasetSave( 23 | type: string, 24 | ai: string, 25 | record: any, 26 | id?: string 27 | ) { 28 | let datasetName = `turing-${ai}-${type}`; 29 | if (!id) id = randomUUID(); 30 | if (record.base64) { 31 | let buffer = Buffer.from(record.base64, "base64"); 32 | // upload to supabase storage 33 | let { error } = await supabase.storage 34 | .from("datasets_new") 35 | .upload(`${datasetName}/${id}.png`, buffer, { 36 | cacheControl: "3600", 37 | upsert: false, 38 | }); 39 | 40 | if (error) { 41 | console.log(error); 42 | throw error; 43 | } 44 | let { data } = await supabase.storage 45 | .from("datasets_new") 46 | .getPublicUrl(`${datasetName}/${id}.png`); 47 | 48 | record.url = data.publicUrl; 49 | delete record.base64; 50 | } 51 | 52 | // first check if the data with id exists 53 | let { data, error } = await supabase 54 | .from("datasets_new") 55 | .select("*") 56 | .eq("dataset", datasetName) 57 | .eq("id", id); 58 | 59 | if (error) { 60 | console.log(error); 61 | throw error; 62 | } 63 | if (data && data.length > 0) { 64 | // update 65 | 66 | // check if last update was more than 72 hours ago 67 | if (data[0].last_update < Date.now() - 72 * 60 * 60 * 1000) { 68 | id = randomUUID(); 69 | let { error } = await supabase.from("datasets_new").insert([ 70 | { 71 | id: id, 72 | record: record, 73 | dataset: datasetName, 74 | model: ai, 75 | rates: { 76 | "1": 0, 77 | }, 78 | type: type, 79 | last_update: Date.now(), 80 | }, 81 | ]); 82 | if (error) { 83 | console.log(error); 84 | throw error; 85 | } 86 | } else { 87 | let { data: d, error } = await supabase 88 | .from("datasets_new") 89 | .update({ 90 | record: [...(data[0].record || []), record], 91 | last_update: Date.now(), 92 | }) 93 | .eq("dataset", datasetName) 94 | .eq("id", id); 95 | if (error) { 96 | console.log(error); 97 | throw error; 98 | } 99 | } 100 | } else { 101 | let { error } = await supabase.from("datasets_new").insert([ 102 | { 103 | id: id, 104 | record: record, 105 | dataset: datasetName, 106 | model: ai, 107 | rates: { 108 | "1": 0, 109 | }, 110 | type: type, 111 | last_update: Date.now(), 112 | }, 113 | ]); 114 | 115 | if (error) { 116 | console.log(error); 117 | throw error; 118 | } 119 | } 120 | return { 121 | id, 122 | }; 123 | } 124 | -------------------------------------------------------------------------------- /src/utils/db.ts: -------------------------------------------------------------------------------- 1 | import { pub } from "../db/mq.js"; 2 | 3 | export async function update(action: "update" | "vote", data: any) { 4 | let d = {}; 5 | 6 | let collection; 7 | let id; 8 | if (action === "update") { 9 | collection = data.collection; 10 | id = data.id; 11 | delete data.collection; 12 | delete data.id; 13 | d = { 14 | collection, 15 | id, 16 | data: data, 17 | }; 18 | } else { 19 | d = { 20 | userId: data.userId, 21 | }; 22 | } 23 | try { 24 | await pub.send( 25 | { 26 | exchange: "db", 27 | routingKey: "db", 28 | }, 29 | JSON.stringify({ 30 | type: action, 31 | ...d, 32 | }) 33 | ); 34 | } catch (e) { 35 | console.log(e); 36 | return { error: e }; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/utils/docs.ts: -------------------------------------------------------------------------------- 1 | import fs from "node:fs"; 2 | import path from "node:path"; 3 | import { fileURLToPath } from "url"; 4 | import log from "./log.js"; 5 | const __filename = fileURLToPath(import.meta.url); 6 | const __dirname = path.dirname(__filename); 7 | 8 | const docsPagesPath = path.join(__dirname, "../../docs/"); 9 | const docsPath = path.join(__dirname, "../../docs.json"); 10 | 11 | export async function autogenerateDocs(client) { 12 | let docsConfig = JSON.parse(fs.readFileSync(docsPath, "utf8")); 13 | let sections = []; 14 | let newConfig = {}; 15 | sections = Object.keys(client).filter((section) => { 16 | return client[section].length > 0; 17 | }); 18 | let sidebar = []; 19 | sidebar = sections.map((section) => { 20 | return [ 21 | `${section.charAt(0).toUpperCase() + section.slice(1)} Models`, 22 | [ 23 | ...client[section].map((model) => { 24 | return [model.data.fullName, `/${section}/${model.data.name}`]; 25 | }), 26 | ], 27 | ]; 28 | }); 29 | delete docsConfig.sidebar; 30 | newConfig = { 31 | ...docsConfig, 32 | sidebar, 33 | }; 34 | fs.writeFileSync(docsPath, JSON.stringify(newConfig, null, 2)); 35 | log("info", `Sidebar docs generated.`); 36 | for (let section of sections) { 37 | let folderExists = fs.existsSync(path.join(docsPagesPath, section)); 38 | if (!folderExists) { 39 | fs.mkdirSync(path.join(docsPagesPath, section)); 40 | } 41 | for (let model of client[section]) { 42 | let docsModelPath = path.join( 43 | docsPagesPath, 44 | section, 45 | `${model.data.name}/index.mdx` 46 | ); 47 | let docsModelContent = `---\ntitle: ${model.data.fullName}\n---\n\n# ${ 48 | model.data.fullName 49 | }\nPOST *https://api.turing.sh/${section}/${model.data.name}*\n${ 50 | model.data.alert ? `${model.data.alert}\n\n` : "" 51 | }`; 52 | // pricing 53 | if (model.data.pricing) { 54 | docsModelContent += `\n## Pricing\n\n`; 55 | // average price 56 | if (model.data.pricing.average) { 57 | docsModelContent += `\n- **Average:** ${model.data.pricing.average}\n`; 58 | } 59 | // price 60 | if (model.data.pricing.price) { 61 | docsModelContent += `\n- **Price:** ${model.data.pricing.price}\n`; 62 | } 63 | } 64 | 65 | docsModelContent += `\n## Parameters\n\n`; 66 | for (let parameter of Object.keys(model.data.parameters)) { 67 | docsModelContent += `\n- **${parameter}**\n - Type: ${model.data.parameters[parameter].type}\n - Required: ${model.data.parameters[parameter].required}\n`; 68 | 69 | if (model.data.parameters[parameter].description) { 70 | docsModelContent += ` - Description: ${model.data.parameters[parameter].description}\n`; 71 | } 72 | if (model.data.parameters[parameter].options) { 73 | docsModelContent += ` - Options: ${model.data.parameters[ 74 | parameter 75 | ].options.join(", ")}\n`; 76 | } 77 | if (model.data.parameters[parameter].default) { 78 | docsModelContent += ` - Default: ${model.data.parameters[parameter].default}\n`; 79 | } 80 | } 81 | // response 82 | docsModelContent += `\n## Response\n\n`; 83 | if (model.data.response) { 84 | for (let response of Object.keys(model.data.response)) { 85 | docsModelContent += `\n- **${response}**\n - Type: ${model.data.response[response].type}\n`; 86 | if (model.data.response[response].description) { 87 | docsModelContent += ` - Description: ${model.data.response[response].description}\n`; 88 | } 89 | } 90 | } else { 91 | // alert not defined yet 92 | docsModelContent += `Response not defined yet\n\n`; 93 | } 94 | 95 | docsModelContent += `\n## Examples\n\n`; 96 | docsModelContent += generateExamples(model, section); 97 | if (!fs.existsSync(path.join(docsPagesPath, section, model.data.name))) { 98 | fs.mkdirSync(path.join(docsPagesPath, section, model.data.name)); 99 | } 100 | fs.writeFileSync(docsModelPath, docsModelContent); 101 | } 102 | } 103 | log("info", `Docs generated.`); 104 | } 105 | 106 | function generateExamples(model, section) { 107 | let data = {}; 108 | for (let parameter of Object.keys(model.data.parameters)) { 109 | if (model.data.parameters[parameter].default) { 110 | data[parameter] = model.data.parameters[parameter].default; 111 | } else if (model.data.parameters[parameter].options) { 112 | data[parameter] = model.data.parameters[parameter].options[0]; 113 | } else if (model.data.parameters[parameter].required == true) { 114 | data[parameter] = model.data.parameters[parameter].type; 115 | } 116 | } 117 | 118 | let example = ` 119 | \`\`\`typescript 120 | import axios from "axios"; 121 | (async () => { 122 | let response = await axios({ 123 | method: "post", 124 | url: 'https://api.turing.sh/${section}/${model.data.name}', 125 | headers: { 126 | "Content-Type": "application/json", 127 | Authorization: "Bearer YOUR_API_KEY", 128 | "x-captcha-token": "Captcha key" 129 | }, 130 | data: ${JSON.stringify(data, null, 2)}, 131 | }) 132 | })(); 133 | \`\`\` 134 | \`\`\`python 135 | import requests 136 | import json 137 | response = requests.post( 138 | "https://api.turing.sh/${section}/${model.data.name}", 139 | headers={ 140 | "Content-Type": "application/json", 141 | "Authorization": "Bearer YOUR_API_KEY", 142 | "x-captcha-token": "Captcha key" 143 | }, 144 | data=json.dumps(${JSON.stringify(data, null, 2)}), 145 | ) 146 | \`\`\` 147 | `; 148 | return example; 149 | } 150 | -------------------------------------------------------------------------------- /src/utils/key.ts: -------------------------------------------------------------------------------- 1 | import jwt from "jsonwebtoken"; 2 | import supabase from "../db/supabase.js"; 3 | import { v4 as uuidv4 } from "uuid"; 4 | import redisClient from "../db/redis.js"; 5 | 6 | export async function pushKeysToCache() { 7 | let { data, error } = await supabase.from("api_keys").select("*"); 8 | 9 | 10 | if (data) { 11 | data.map((d) => { 12 | redisClient.set(`api:${d["api-token"]}`, JSON.stringify(d)); 13 | }); 14 | } 15 | } 16 | 17 | export async function generateKey( 18 | userId: string, 19 | name: string, 20 | allowedPaths?: Array, 21 | ips?: Array 22 | ) { 23 | let id = uuidv4(); 24 | let apiToken = jwt.sign({ ips, id }, process.env.SECRET_KEY); 25 | let captchaToken = jwt.sign({ ips, id, apiToken }, process.env.SECRET_KEY); 26 | let d = { 27 | id, 28 | "api-token": apiToken, 29 | "captcha-token": captchaToken, 30 | ips, 31 | created_at: new Date(), 32 | allowedPaths: allowedPaths || [ 33 | "/text/*", 34 | "/image/*", 35 | "/video/*", 36 | "/audio/*", 37 | ], 38 | lastUsed: Date.now(), 39 | name, 40 | userId: userId, 41 | }; 42 | let userExists = await redisClient.get(`users:${userId}`); 43 | if (!userExists) { 44 | let { data, error } = await supabase 45 | .from("users_new") 46 | .select("*") 47 | .eq("id", userId); 48 | 49 | if (error) { 50 | console.log(error); 51 | return false; 52 | } 53 | if (data.length == 0) { 54 | return false; 55 | } 56 | redisClient.set(`users:${userId}`, JSON.stringify(data[0])); 57 | } 58 | let { data, error } = await supabase.from("api_keys").insert([ 59 | { 60 | ...d, 61 | }, 62 | ]); 63 | redisClient.set(`api:${apiToken}`, JSON.stringify(d)); 64 | 65 | 66 | if (error) { 67 | console.log(error); 68 | return false; 69 | } 70 | return { apiToken, captchaToken, id, name }; 71 | } 72 | 73 | export async function checkCaptchaToken(token: string, req) { 74 | try { 75 | let decoded = jwt.verify(token, process.env.SECRET_KEY); 76 | let ApiToken = req.headers.authorization; 77 | ApiToken = ApiToken.replace("Bearer ", ""); 78 | if (!decoded) { 79 | return false; 80 | } 81 | if (decoded["apiToken"]) { 82 | if (decoded["apiToken"] != ApiToken) { 83 | return false; 84 | } 85 | let decodedApiToken = jwt.verify( 86 | decoded["apiToken"], 87 | process.env.SECRET_KEY 88 | ); 89 | if (!decodedApiToken) { 90 | return false; 91 | } 92 | if (decodedApiToken["id"] != decoded["id"]) { 93 | return false; 94 | } 95 | // check ip 96 | if (decodedApiToken["ips"]) { 97 | if ( 98 | !decodedApiToken["ips"].includes(req.ip) && 99 | req.ip != "::1" && 100 | decodedApiToken["ips"].length > 0 101 | ) { 102 | return false; 103 | } 104 | } 105 | 106 | var data = req.apiData; 107 | if (data) { 108 | var user; 109 | if (data.userId != "530102778408861706") { 110 | user = await redisClient.get(`users:${data.userId}`); 111 | user = JSON.parse(user); 112 | if (!user) { 113 | let { data: d, error } = await supabase 114 | .from("users_new") 115 | .select("*") 116 | .eq("id", data.userId); 117 | 118 | if (error) { 119 | console.log(error); 120 | return false; 121 | } 122 | if (d.length == 0) { 123 | return false; 124 | } 125 | redisClient.set(`users:${data.userId}`, JSON.stringify(d[0])); 126 | user = d[0]; 127 | } 128 | if (user?.plan?.total) { 129 | let current = user.plan.total - user.plan.used; 130 | if (current <= 0.1) { 131 | console.log("Plan limit reached"); 132 | return { 133 | error: "Plan limit reached", 134 | }; 135 | } 136 | } else { 137 | return { 138 | error: "Plan limit reached", 139 | }; 140 | } 141 | } else { 142 | user = { 143 | id: "530102778408861706", 144 | }; 145 | } 146 | 147 | return { 148 | user: user, 149 | apiId: data.id, 150 | }; 151 | } 152 | return true; 153 | } 154 | } catch (e) { 155 | return false; 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /src/utils/log.ts: -------------------------------------------------------------------------------- 1 | import chalk from "chalk"; 2 | import fs from "node:fs"; 3 | import { randomUUID } from "node:crypto"; 4 | 5 | const logsPath = "./logs"; 6 | const sessionID = randomUUID(); 7 | const logFile = `${logsPath}/${sessionID}.log`; 8 | 9 | export default function log( 10 | type: "info" | "warning" | "error" | "debug", 11 | ...args 12 | ) { 13 | const log = `[${type.toUpperCase()}] ${args.join(" ")}`; 14 | const color = 15 | type === "info" 16 | ? "green" 17 | : type === "warning" 18 | ? "yellow" 19 | : type === "error" 20 | ? "red" 21 | : "white"; 22 | if ( 23 | (process.env.NODE_ENV == "production" && type != "debug") || 24 | process.env.NODE_ENV == "development" 25 | ) { 26 | console.log(chalk[color](log)); 27 | } 28 | fs.appendFileSync(logFile, `${log}\n`); 29 | } 30 | -------------------------------------------------------------------------------- /src/utils/ms.ts: -------------------------------------------------------------------------------- 1 | export function getToday() { 2 | let today = new Date(); 3 | let dd = String(today.getDate()).padStart(2, "0"); 4 | let mm = String(today.getMonth() + 1).padStart(2, "0"); 5 | let yyyy = today.getFullYear(); 6 | return `${yyyy}-${mm}-${dd}`; 7 | } 8 | -------------------------------------------------------------------------------- /src/utils/runpod.ts: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | export async function translateModels(model) { 3 | let models = { 4 | blip2: "v2/22whrikqknoc11", 5 | musicgen: "v2/zeeocl74aergso", 6 | llama2: "v2/39i5i1rtqkm7vk", 7 | }; 8 | if (!models[model]) { 9 | throw new Error("Model not found"); 10 | } 11 | 12 | return models[model]; 13 | } 14 | 15 | export async function request(url, action, body) { 16 | let URL = `https://api.runpod.ai/${url}/${action}`; 17 | try { 18 | let res = await axios({ 19 | method: "POST", 20 | url: URL, 21 | headers: { 22 | "Content-Type": "application/json", 23 | Authorization: `Bearer ${process.env.RUNPOD_KEY}`, 24 | }, 25 | data: { 26 | input: { 27 | ...body.input, 28 | }, 29 | }, 30 | }); 31 | let result = res.data; 32 | return result; 33 | } catch (error: any) { 34 | console.log(error.response.data); 35 | throw error; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/utils/stats.ts: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | import axios from "axios"; 3 | import puppeteer from "puppeteer"; 4 | import delay from "delay"; 5 | 6 | export async function getUpdatedStats() { 7 | try { 8 | 9 | let res = await fetch( 10 | "https://discord.com/api/v9/applications/1053015370115588147", 11 | { 12 | headers: { 13 | accept: "*/*", 14 | "accept-language": "es-ES,es;q=0.9,en;q=0.8", 15 | authorization: process.env.STATS_AUTH, 16 | "sec-ch-ua": 17 | '"Chromium";v="116", "Not)A;Brand";v="24", "Brave";v="116"', 18 | "sec-ch-ua-mobile": "?0", 19 | "sec-ch-ua-platform": '"Windows"', 20 | "sec-fetch-dest": "empty", 21 | "sec-fetch-mode": "cors", 22 | "sec-fetch-site": "same-origin", 23 | "sec-gpc": "1", 24 | }, 25 | referrer: 26 | "https://discord.com/developers/applications/1053015370115588147/information", 27 | referrerPolicy: "strict-origin-when-cross-origin", 28 | body: null, 29 | method: "GET", 30 | mode: "cors", 31 | credentials: "include", 32 | } 33 | ); 34 | let answer = await res.json(); 35 | let guildsNumber = answer.approximate_guild_count; 36 | await pushStats(guildsNumber); 37 | return guildsNumber; 38 | } catch (error) { 39 | return 296000 40 | } 41 | } 42 | 43 | export async function getStats() { 44 | if (fs.existsSync("./guilds.txt")) { 45 | let guilds = fs.readFileSync("./guilds.txt", "utf-8"); 46 | return parseInt(guilds); 47 | } else { 48 | let g = await getUpdatedStats(); 49 | return g; 50 | } 51 | } 52 | 53 | async function pushStats(guilds: number) { 54 | // first update at the stats file 55 | fs.writeFileSync("./guilds.txt", guilds.toString()); 56 | let shards = Math.round(guilds / 1000); 57 | // round shards to the nearest integer 58 | try { 59 | await axios({ 60 | method: "post", 61 | url: "https://top.gg/api/bots/1053015370115588147/stats", 62 | headers: { 63 | Authorization: process.env.TOPGG_TOKEN, 64 | "Content-Type": "application/json", 65 | }, 66 | data: { 67 | server_count: guilds, 68 | shard_count: shards, 69 | }, 70 | }); 71 | } catch (error) { } 72 | try { 73 | await axios({ 74 | method: "post", 75 | url: "https://discord.bots.gg/api/v1/bots/1053015370115588147/stats", 76 | headers: { 77 | Authorization: process.env.DISCORD_BOTS_GG, 78 | "Content-Type": "application/json", 79 | }, 80 | data: { 81 | guildCount: guilds, 82 | shardCount: shards, 83 | }, 84 | }); 85 | } catch (error) { } 86 | } 87 | -------------------------------------------------------------------------------- /src/utils/tokenizer.ts: -------------------------------------------------------------------------------- 1 | import { get_encoding } from "@dqbd/tiktoken"; 2 | export const encoder = get_encoding("cl100k_base"); 3 | 4 | /** 5 | * Get the length of a prompt. 6 | * @param content Prompt to check 7 | * 8 | * @returns Length of the prompt, in tokens 9 | */ 10 | export const getPromptLength = (content: string): number => { 11 | if (!content) return 0; 12 | content = content 13 | .replaceAll("<|endoftext|>", "<|im_end|>") 14 | .replaceAll("<|endofprompt|>", "<|im_end|>"); 15 | return encoder.encode(content).length; 16 | }; 17 | 18 | export const getChatMessageLength = (messages: []): number => { 19 | /* Total tokens used for the messages */ 20 | let total: number = 0; 21 | 22 | for (const message of messages) { 23 | /* Map each property of the message to the number of tokens it contains. */ 24 | const propertyTokenCounts = Object.entries(message).map( 25 | ([_, value]: any) => { 26 | /* Count the number of tokens in the property value. */ 27 | return getPromptLength(value); 28 | } 29 | ); 30 | 31 | /* Sum the number of tokens in all properties and add 4 for metadata. */ 32 | total += propertyTokenCounts.reduce((a, b) => a + b, 4); 33 | } 34 | 35 | return total + 2; 36 | }; 37 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "ESNext", 5 | "strict": true, 6 | "declaration": true, 7 | "removeComments": true, 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "allowSyntheticDefaultImports": true, 11 | "sourceMap": true, 12 | "outDir": "./dist", 13 | "baseUrl": "./", 14 | "paths": {}, 15 | "incremental": true, 16 | "moduleResolution": "node", 17 | "skipLibCheck": true, 18 | "strictNullChecks": false, 19 | "noImplicitAny": false, 20 | "strictBindCallApply": false, 21 | "forceConsistentCasingInFileNames": false, 22 | "noFallthroughCasesInSwitch": false, 23 | "resolveJsonModule": true 24 | }, 25 | "include": ["src"], 26 | "exclude": ["node_modules", "dist"] 27 | } 28 | --------------------------------------------------------------------------------