├── .gitignore ├── README.md ├── server ├── .env.example ├── package.json ├── pnpm-lock.yaml ├── server.js ├── serverGPT3API.js ├── whitelist.js └── whitelist.js.Example └── ui ├── .eslintignore ├── .eslintrc.cjs ├── .gitignore ├── .npmrc ├── .prettierignore ├── .prettierrc ├── README.md ├── package.json ├── playwright.config.ts ├── pnpm-lock.yaml ├── postcss.config.cjs ├── src ├── DeclarationFile.d.ts ├── app.d.ts ├── app.html ├── app.postcss ├── index.test.ts ├── lib │ ├── images │ │ ├── banner1.jpg │ │ ├── favicon.png │ │ ├── github.svg │ │ ├── svelte-logo.svg │ │ ├── svelte-welcome.png │ │ └── svelte-welcome.webp │ └── styles │ │ ├── chat.css │ │ ├── prism-okaidia.css │ │ └── prism-okaidiaOLD.css └── routes │ ├── +layout.svelte │ ├── +page.svelte │ ├── Header.svelte │ ├── pageCopy1.svelte │ ├── pageCopy2.svelte │ ├── pageCopy3.svelte │ ├── pageCopy4.svelte │ ├── pageCopy5.svelte │ └── pageCopy6.svelte ├── static └── favicon.png ├── svelte.config.js ├── tailwind.config.cjs ├── tests └── test.ts ├── tsconfig.json └── vite.config.ts /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | 26 | # env 27 | .env 28 | 29 | # build 30 | build 31 | 32 | # test 33 | test 34 | 35 | # others: 36 | # whitelist.js 37 | servertest 38 | uitest -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # ✨ Build and Deploy Your Own ChatGPT AI Application That Will Help You 5 | 6 | ![Open AI CodeGPT](https://i.ibb.co/LS4DRhb/image-257.png) 7 | 8 | ## 📚 SETUP 9 | 10 | To Use this ChatGPT Clone AI Chatbot app built with SvelteKit (Frontend), Express.js (Backend) and Openai GPT-3 AI API, do the following: 11 | 12 | - `Star` this repo, 13 | 14 | - Then `Clone` this repo, 15 | 16 | - Finally, see the `Demo` to test the amazing `features` of the `ai chatbot app` and go through the `documentation` by enrolling for the `full course` to guide on how to set it up quickly, easily and successfully, which is `totally FREE` with support at: 17 | 18 | - [Build and Deploy AI chatbot Website Like chatGPT With Sveltekit, ExpressJs and Openai GPT-3 AI API](https://aihipuniversity.com/Svelte-SvelteKit-303-Advanced-Build-And-Deploy-Ai-Chatbot-Website?ref=AiHiPUniversity.com "FREE Full Course To get Started With AI Chatbot Development") 19 | 20 | ## 🎉 Launch your Full Stack and Web3 development career with Ai enhanced project-based courses and support 21 | 22 | [AiHiPUniversity.com](https://AiHiPUniversity.com?ref=AiHiPUniversity.com "Visit AiHiPUniversity Website") 23 | 24 | ## 📚 Star this Repository 25 | 26 | If you find this helpful, 27 | 28 | please remember to `star` the repo at the top and also share it on social media platforms. 29 | -------------------------------------------------------------------------------- /server/.env.example: -------------------------------------------------------------------------------- 1 | # COPY AND PAST YOUR OPENAI's API KEY BELOW WITHIN THE QOUTAION MARKS. 2 | # WARNING: Your API Key is confidencial and must not be exposed on frontend or commited to public places like Github: 3 | # To avoid exposing your API key, kindly rename this file from .evn.example to .env to avoid any errors accessing it by the server, 4 | # and it will also ensure that .gitinore rules help prevent exposing your API KEY by removing it from your commit files to send to github. 5 | OPENAI_API_KEY= "COPY AND PASTE TO REPLACE THIS TEXT WITH YOUR OPENAI's API KEY" -------------------------------------------------------------------------------- /server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "foskaay-ai-server", 3 | "private": true, 4 | "version": "1.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "server": "nodemon server" 8 | }, 9 | "dependencies": { 10 | "cors": "^2.8.5", 11 | "dotenv": "^16.0.3", 12 | "express": "^4.18.2", 13 | "nodemon": "^2.0.20", 14 | "openai": "^3.1.0" 15 | } 16 | } -------------------------------------------------------------------------------- /server/pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: 5.4 2 | 3 | specifiers: 4 | cors: ^2.8.5 5 | dotenv: ^16.0.3 6 | express: ^4.18.2 7 | nodemon: ^2.0.20 8 | openai: ^3.1.0 9 | 10 | dependencies: 11 | cors: 2.8.5 12 | dotenv: 16.0.3 13 | express: 4.18.2 14 | nodemon: 2.0.20 15 | openai: 3.1.0 16 | 17 | packages: 18 | 19 | /abbrev/1.1.1: 20 | resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} 21 | dev: false 22 | 23 | /accepts/1.3.8: 24 | resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} 25 | engines: {node: '>= 0.6'} 26 | dependencies: 27 | mime-types: 2.1.35 28 | negotiator: 0.6.3 29 | dev: false 30 | 31 | /anymatch/3.1.3: 32 | resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} 33 | engines: {node: '>= 8'} 34 | dependencies: 35 | normalize-path: 3.0.0 36 | picomatch: 2.3.1 37 | dev: false 38 | 39 | /array-flatten/1.1.1: 40 | resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} 41 | dev: false 42 | 43 | /asynckit/0.4.0: 44 | resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} 45 | dev: false 46 | 47 | /axios/0.26.1: 48 | resolution: {integrity: sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==} 49 | dependencies: 50 | follow-redirects: 1.15.2 51 | transitivePeerDependencies: 52 | - debug 53 | dev: false 54 | 55 | /balanced-match/1.0.2: 56 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 57 | dev: false 58 | 59 | /binary-extensions/2.2.0: 60 | resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} 61 | engines: {node: '>=8'} 62 | dev: false 63 | 64 | /body-parser/1.20.1: 65 | resolution: {integrity: sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==} 66 | engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} 67 | dependencies: 68 | bytes: 3.1.2 69 | content-type: 1.0.4 70 | debug: 2.6.9 71 | depd: 2.0.0 72 | destroy: 1.2.0 73 | http-errors: 2.0.0 74 | iconv-lite: 0.4.24 75 | on-finished: 2.4.1 76 | qs: 6.11.0 77 | raw-body: 2.5.1 78 | type-is: 1.6.18 79 | unpipe: 1.0.0 80 | transitivePeerDependencies: 81 | - supports-color 82 | dev: false 83 | 84 | /brace-expansion/1.1.11: 85 | resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} 86 | dependencies: 87 | balanced-match: 1.0.2 88 | concat-map: 0.0.1 89 | dev: false 90 | 91 | /braces/3.0.2: 92 | resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} 93 | engines: {node: '>=8'} 94 | dependencies: 95 | fill-range: 7.0.1 96 | dev: false 97 | 98 | /bytes/3.1.2: 99 | resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} 100 | engines: {node: '>= 0.8'} 101 | dev: false 102 | 103 | /call-bind/1.0.2: 104 | resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} 105 | dependencies: 106 | function-bind: 1.1.1 107 | get-intrinsic: 1.1.3 108 | dev: false 109 | 110 | /chokidar/3.5.3: 111 | resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} 112 | engines: {node: '>= 8.10.0'} 113 | dependencies: 114 | anymatch: 3.1.3 115 | braces: 3.0.2 116 | glob-parent: 5.1.2 117 | is-binary-path: 2.1.0 118 | is-glob: 4.0.3 119 | normalize-path: 3.0.0 120 | readdirp: 3.6.0 121 | optionalDependencies: 122 | fsevents: 2.3.2 123 | dev: false 124 | 125 | /combined-stream/1.0.8: 126 | resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} 127 | engines: {node: '>= 0.8'} 128 | dependencies: 129 | delayed-stream: 1.0.0 130 | dev: false 131 | 132 | /concat-map/0.0.1: 133 | resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} 134 | dev: false 135 | 136 | /content-disposition/0.5.4: 137 | resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} 138 | engines: {node: '>= 0.6'} 139 | dependencies: 140 | safe-buffer: 5.2.1 141 | dev: false 142 | 143 | /content-type/1.0.4: 144 | resolution: {integrity: sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==} 145 | engines: {node: '>= 0.6'} 146 | dev: false 147 | 148 | /cookie-signature/1.0.6: 149 | resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} 150 | dev: false 151 | 152 | /cookie/0.5.0: 153 | resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} 154 | engines: {node: '>= 0.6'} 155 | dev: false 156 | 157 | /cors/2.8.5: 158 | resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} 159 | engines: {node: '>= 0.10'} 160 | dependencies: 161 | object-assign: 4.1.1 162 | vary: 1.1.2 163 | dev: false 164 | 165 | /debug/2.6.9: 166 | resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} 167 | peerDependencies: 168 | supports-color: '*' 169 | peerDependenciesMeta: 170 | supports-color: 171 | optional: true 172 | dependencies: 173 | ms: 2.0.0 174 | dev: false 175 | 176 | /debug/3.2.7_supports-color@5.5.0: 177 | resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} 178 | peerDependencies: 179 | supports-color: '*' 180 | peerDependenciesMeta: 181 | supports-color: 182 | optional: true 183 | dependencies: 184 | ms: 2.1.3 185 | supports-color: 5.5.0 186 | dev: false 187 | 188 | /delayed-stream/1.0.0: 189 | resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} 190 | engines: {node: '>=0.4.0'} 191 | dev: false 192 | 193 | /depd/2.0.0: 194 | resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} 195 | engines: {node: '>= 0.8'} 196 | dev: false 197 | 198 | /destroy/1.2.0: 199 | resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} 200 | engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} 201 | dev: false 202 | 203 | /dotenv/16.0.3: 204 | resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==} 205 | engines: {node: '>=12'} 206 | dev: false 207 | 208 | /ee-first/1.1.1: 209 | resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} 210 | dev: false 211 | 212 | /encodeurl/1.0.2: 213 | resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} 214 | engines: {node: '>= 0.8'} 215 | dev: false 216 | 217 | /escape-html/1.0.3: 218 | resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} 219 | dev: false 220 | 221 | /etag/1.8.1: 222 | resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} 223 | engines: {node: '>= 0.6'} 224 | dev: false 225 | 226 | /express/4.18.2: 227 | resolution: {integrity: sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==} 228 | engines: {node: '>= 0.10.0'} 229 | dependencies: 230 | accepts: 1.3.8 231 | array-flatten: 1.1.1 232 | body-parser: 1.20.1 233 | content-disposition: 0.5.4 234 | content-type: 1.0.4 235 | cookie: 0.5.0 236 | cookie-signature: 1.0.6 237 | debug: 2.6.9 238 | depd: 2.0.0 239 | encodeurl: 1.0.2 240 | escape-html: 1.0.3 241 | etag: 1.8.1 242 | finalhandler: 1.2.0 243 | fresh: 0.5.2 244 | http-errors: 2.0.0 245 | merge-descriptors: 1.0.1 246 | methods: 1.1.2 247 | on-finished: 2.4.1 248 | parseurl: 1.3.3 249 | path-to-regexp: 0.1.7 250 | proxy-addr: 2.0.7 251 | qs: 6.11.0 252 | range-parser: 1.2.1 253 | safe-buffer: 5.2.1 254 | send: 0.18.0 255 | serve-static: 1.15.0 256 | setprototypeof: 1.2.0 257 | statuses: 2.0.1 258 | type-is: 1.6.18 259 | utils-merge: 1.0.1 260 | vary: 1.1.2 261 | transitivePeerDependencies: 262 | - supports-color 263 | dev: false 264 | 265 | /fill-range/7.0.1: 266 | resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} 267 | engines: {node: '>=8'} 268 | dependencies: 269 | to-regex-range: 5.0.1 270 | dev: false 271 | 272 | /finalhandler/1.2.0: 273 | resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==} 274 | engines: {node: '>= 0.8'} 275 | dependencies: 276 | debug: 2.6.9 277 | encodeurl: 1.0.2 278 | escape-html: 1.0.3 279 | on-finished: 2.4.1 280 | parseurl: 1.3.3 281 | statuses: 2.0.1 282 | unpipe: 1.0.0 283 | transitivePeerDependencies: 284 | - supports-color 285 | dev: false 286 | 287 | /follow-redirects/1.15.2: 288 | resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==} 289 | engines: {node: '>=4.0'} 290 | peerDependencies: 291 | debug: '*' 292 | peerDependenciesMeta: 293 | debug: 294 | optional: true 295 | dev: false 296 | 297 | /form-data/4.0.0: 298 | resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} 299 | engines: {node: '>= 6'} 300 | dependencies: 301 | asynckit: 0.4.0 302 | combined-stream: 1.0.8 303 | mime-types: 2.1.35 304 | dev: false 305 | 306 | /forwarded/0.2.0: 307 | resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} 308 | engines: {node: '>= 0.6'} 309 | dev: false 310 | 311 | /fresh/0.5.2: 312 | resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} 313 | engines: {node: '>= 0.6'} 314 | dev: false 315 | 316 | /fsevents/2.3.2: 317 | resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} 318 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 319 | os: [darwin] 320 | requiresBuild: true 321 | dev: false 322 | optional: true 323 | 324 | /function-bind/1.1.1: 325 | resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} 326 | dev: false 327 | 328 | /get-intrinsic/1.1.3: 329 | resolution: {integrity: sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==} 330 | dependencies: 331 | function-bind: 1.1.1 332 | has: 1.0.3 333 | has-symbols: 1.0.3 334 | dev: false 335 | 336 | /glob-parent/5.1.2: 337 | resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} 338 | engines: {node: '>= 6'} 339 | dependencies: 340 | is-glob: 4.0.3 341 | dev: false 342 | 343 | /has-flag/3.0.0: 344 | resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} 345 | engines: {node: '>=4'} 346 | dev: false 347 | 348 | /has-symbols/1.0.3: 349 | resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} 350 | engines: {node: '>= 0.4'} 351 | dev: false 352 | 353 | /has/1.0.3: 354 | resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} 355 | engines: {node: '>= 0.4.0'} 356 | dependencies: 357 | function-bind: 1.1.1 358 | dev: false 359 | 360 | /http-errors/2.0.0: 361 | resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} 362 | engines: {node: '>= 0.8'} 363 | dependencies: 364 | depd: 2.0.0 365 | inherits: 2.0.4 366 | setprototypeof: 1.2.0 367 | statuses: 2.0.1 368 | toidentifier: 1.0.1 369 | dev: false 370 | 371 | /iconv-lite/0.4.24: 372 | resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} 373 | engines: {node: '>=0.10.0'} 374 | dependencies: 375 | safer-buffer: 2.1.2 376 | dev: false 377 | 378 | /ignore-by-default/1.0.1: 379 | resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==} 380 | dev: false 381 | 382 | /inherits/2.0.4: 383 | resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} 384 | dev: false 385 | 386 | /ipaddr.js/1.9.1: 387 | resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} 388 | engines: {node: '>= 0.10'} 389 | dev: false 390 | 391 | /is-binary-path/2.1.0: 392 | resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} 393 | engines: {node: '>=8'} 394 | dependencies: 395 | binary-extensions: 2.2.0 396 | dev: false 397 | 398 | /is-extglob/2.1.1: 399 | resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} 400 | engines: {node: '>=0.10.0'} 401 | dev: false 402 | 403 | /is-glob/4.0.3: 404 | resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} 405 | engines: {node: '>=0.10.0'} 406 | dependencies: 407 | is-extglob: 2.1.1 408 | dev: false 409 | 410 | /is-number/7.0.0: 411 | resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} 412 | engines: {node: '>=0.12.0'} 413 | dev: false 414 | 415 | /media-typer/0.3.0: 416 | resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} 417 | engines: {node: '>= 0.6'} 418 | dev: false 419 | 420 | /merge-descriptors/1.0.1: 421 | resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==} 422 | dev: false 423 | 424 | /methods/1.1.2: 425 | resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} 426 | engines: {node: '>= 0.6'} 427 | dev: false 428 | 429 | /mime-db/1.52.0: 430 | resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} 431 | engines: {node: '>= 0.6'} 432 | dev: false 433 | 434 | /mime-types/2.1.35: 435 | resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} 436 | engines: {node: '>= 0.6'} 437 | dependencies: 438 | mime-db: 1.52.0 439 | dev: false 440 | 441 | /mime/1.6.0: 442 | resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} 443 | engines: {node: '>=4'} 444 | hasBin: true 445 | dev: false 446 | 447 | /minimatch/3.1.2: 448 | resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} 449 | dependencies: 450 | brace-expansion: 1.1.11 451 | dev: false 452 | 453 | /ms/2.0.0: 454 | resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} 455 | dev: false 456 | 457 | /ms/2.1.3: 458 | resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} 459 | dev: false 460 | 461 | /negotiator/0.6.3: 462 | resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} 463 | engines: {node: '>= 0.6'} 464 | dev: false 465 | 466 | /nodemon/2.0.20: 467 | resolution: {integrity: sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw==} 468 | engines: {node: '>=8.10.0'} 469 | hasBin: true 470 | dependencies: 471 | chokidar: 3.5.3 472 | debug: 3.2.7_supports-color@5.5.0 473 | ignore-by-default: 1.0.1 474 | minimatch: 3.1.2 475 | pstree.remy: 1.1.8 476 | semver: 5.7.1 477 | simple-update-notifier: 1.1.0 478 | supports-color: 5.5.0 479 | touch: 3.1.0 480 | undefsafe: 2.0.5 481 | dev: false 482 | 483 | /nopt/1.0.10: 484 | resolution: {integrity: sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==} 485 | hasBin: true 486 | dependencies: 487 | abbrev: 1.1.1 488 | dev: false 489 | 490 | /normalize-path/3.0.0: 491 | resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} 492 | engines: {node: '>=0.10.0'} 493 | dev: false 494 | 495 | /object-assign/4.1.1: 496 | resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} 497 | engines: {node: '>=0.10.0'} 498 | dev: false 499 | 500 | /object-inspect/1.12.2: 501 | resolution: {integrity: sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==} 502 | dev: false 503 | 504 | /on-finished/2.4.1: 505 | resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} 506 | engines: {node: '>= 0.8'} 507 | dependencies: 508 | ee-first: 1.1.1 509 | dev: false 510 | 511 | /openai/3.1.0: 512 | resolution: {integrity: sha512-v5kKFH5o+8ld+t0arudj833Mgm3GcgBnbyN9946bj6u7bvel4Yg6YFz2A4HLIYDzmMjIo0s6vSG9x73kOwvdCg==} 513 | dependencies: 514 | axios: 0.26.1 515 | form-data: 4.0.0 516 | transitivePeerDependencies: 517 | - debug 518 | dev: false 519 | 520 | /parseurl/1.3.3: 521 | resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} 522 | engines: {node: '>= 0.8'} 523 | dev: false 524 | 525 | /path-to-regexp/0.1.7: 526 | resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} 527 | dev: false 528 | 529 | /picomatch/2.3.1: 530 | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} 531 | engines: {node: '>=8.6'} 532 | dev: false 533 | 534 | /proxy-addr/2.0.7: 535 | resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} 536 | engines: {node: '>= 0.10'} 537 | dependencies: 538 | forwarded: 0.2.0 539 | ipaddr.js: 1.9.1 540 | dev: false 541 | 542 | /pstree.remy/1.1.8: 543 | resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==} 544 | dev: false 545 | 546 | /qs/6.11.0: 547 | resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} 548 | engines: {node: '>=0.6'} 549 | dependencies: 550 | side-channel: 1.0.4 551 | dev: false 552 | 553 | /range-parser/1.2.1: 554 | resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} 555 | engines: {node: '>= 0.6'} 556 | dev: false 557 | 558 | /raw-body/2.5.1: 559 | resolution: {integrity: sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==} 560 | engines: {node: '>= 0.8'} 561 | dependencies: 562 | bytes: 3.1.2 563 | http-errors: 2.0.0 564 | iconv-lite: 0.4.24 565 | unpipe: 1.0.0 566 | dev: false 567 | 568 | /readdirp/3.6.0: 569 | resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} 570 | engines: {node: '>=8.10.0'} 571 | dependencies: 572 | picomatch: 2.3.1 573 | dev: false 574 | 575 | /safe-buffer/5.2.1: 576 | resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} 577 | dev: false 578 | 579 | /safer-buffer/2.1.2: 580 | resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} 581 | dev: false 582 | 583 | /semver/5.7.1: 584 | resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==} 585 | hasBin: true 586 | dev: false 587 | 588 | /semver/7.0.0: 589 | resolution: {integrity: sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==} 590 | hasBin: true 591 | dev: false 592 | 593 | /send/0.18.0: 594 | resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} 595 | engines: {node: '>= 0.8.0'} 596 | dependencies: 597 | debug: 2.6.9 598 | depd: 2.0.0 599 | destroy: 1.2.0 600 | encodeurl: 1.0.2 601 | escape-html: 1.0.3 602 | etag: 1.8.1 603 | fresh: 0.5.2 604 | http-errors: 2.0.0 605 | mime: 1.6.0 606 | ms: 2.1.3 607 | on-finished: 2.4.1 608 | range-parser: 1.2.1 609 | statuses: 2.0.1 610 | transitivePeerDependencies: 611 | - supports-color 612 | dev: false 613 | 614 | /serve-static/1.15.0: 615 | resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==} 616 | engines: {node: '>= 0.8.0'} 617 | dependencies: 618 | encodeurl: 1.0.2 619 | escape-html: 1.0.3 620 | parseurl: 1.3.3 621 | send: 0.18.0 622 | transitivePeerDependencies: 623 | - supports-color 624 | dev: false 625 | 626 | /setprototypeof/1.2.0: 627 | resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} 628 | dev: false 629 | 630 | /side-channel/1.0.4: 631 | resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} 632 | dependencies: 633 | call-bind: 1.0.2 634 | get-intrinsic: 1.1.3 635 | object-inspect: 1.12.2 636 | dev: false 637 | 638 | /simple-update-notifier/1.1.0: 639 | resolution: {integrity: sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==} 640 | engines: {node: '>=8.10.0'} 641 | dependencies: 642 | semver: 7.0.0 643 | dev: false 644 | 645 | /statuses/2.0.1: 646 | resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} 647 | engines: {node: '>= 0.8'} 648 | dev: false 649 | 650 | /supports-color/5.5.0: 651 | resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} 652 | engines: {node: '>=4'} 653 | dependencies: 654 | has-flag: 3.0.0 655 | dev: false 656 | 657 | /to-regex-range/5.0.1: 658 | resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} 659 | engines: {node: '>=8.0'} 660 | dependencies: 661 | is-number: 7.0.0 662 | dev: false 663 | 664 | /toidentifier/1.0.1: 665 | resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} 666 | engines: {node: '>=0.6'} 667 | dev: false 668 | 669 | /touch/3.1.0: 670 | resolution: {integrity: sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==} 671 | hasBin: true 672 | dependencies: 673 | nopt: 1.0.10 674 | dev: false 675 | 676 | /type-is/1.6.18: 677 | resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} 678 | engines: {node: '>= 0.6'} 679 | dependencies: 680 | media-typer: 0.3.0 681 | mime-types: 2.1.35 682 | dev: false 683 | 684 | /undefsafe/2.0.5: 685 | resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==} 686 | dev: false 687 | 688 | /unpipe/1.0.0: 689 | resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} 690 | engines: {node: '>= 0.8'} 691 | dev: false 692 | 693 | /utils-merge/1.0.1: 694 | resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} 695 | engines: {node: '>= 0.4.0'} 696 | dev: false 697 | 698 | /vary/1.1.2: 699 | resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} 700 | engines: {node: '>= 0.8'} 701 | dev: false 702 | -------------------------------------------------------------------------------- /server/server.js: -------------------------------------------------------------------------------- 1 | import express from 'express' //backend server framework 2 | import * as dotenv from 'dotenv' // access and use API KEY stored in .env file 3 | import cors from 'cors' //allow make cross origin API request to server from frontend 4 | import allowedOrigins from './whitelist.js'; //allowed domains only 5 | import { Configuration, OpenAIApi } from 'openai' //Openai API wrapper 6 | import { toChatML, get_message } from "gpt-to-chatgpt"; //using this as wrapper to make chatgpt api call work till official openai package is upgraded 7 | 8 | 9 | //call config function to give access to .env API KEY variable 10 | dotenv.config() 11 | 12 | 13 | //Openai API wrapper function which accepts API KEY as object parameter 14 | const configuration = new Configuration({ 15 | apiKey: process.env.OPENAI_API_KEY, 16 | }); 17 | 18 | 19 | // create instance of Openai and pass in the configuration object created above 20 | const openai = new OpenAIApi(configuration); 21 | 22 | 23 | // initialize expressjs server 24 | const app = express() 25 | 26 | 27 | // configure the cors middleware to allow accepting and processing request from allowed domains 28 | app.use(cors({ 29 | origin: (origin, callback) => { 30 | // check if the origin is in the allowed origins array 31 | if (allowedOrigins.indexOf(origin) !== -1) { 32 | callback(null, true); 33 | } else { 34 | callback(new Error('Not allowed by CORS')); 35 | } 36 | } 37 | })); 38 | 39 | 40 | //middleware: allows the backend to recieve and acces request from frontend as a json object 41 | // rather than just a string. 42 | // This is necessary in the following POST request route code: 43 | // app.post('/', async (req, res) => { 44 | // try {const prompt = req.body.prompt; 45 | // where it uses req.body to get the prompt data/question sent in the post request 46 | // from our chatGPT Ai chatBot SvelteKit powered frontend 47 | app.use(express.json()) 48 | 49 | 50 | // routes/endpoint to expose expressjs backend to frontend "GET" request 51 | // with a return statement of info to show user visiting the route 52 | // "started on http://localhost:5001" makes the port link clickable from terminal 53 | app.get('/', async (req, res) => { 54 | res.status(200).send({ 55 | message: 'Hello Web3 AI World from Foskaay AI', 56 | }) 57 | }) 58 | 59 | 60 | //route/endpoint which allows Expressjs backend to recieve and process 61 | // the request sent from users of our chatGPT Ai chatBot SvelteKit powered frontend 62 | app.post('/', async (req, res) => { 63 | 64 | // check if the origin is in the allowed origins array/whitelist domains 65 | // before processing request 66 | if (!allowedOrigins.includes(req.headers.origin)) { 67 | return res.status(401).send({ message: 'Unauthorized: Origin not allowed' }); 68 | } 69 | 70 | try { 71 | const prompt = req.body.prompt; //access user question submited as prompt 72 | 73 | //Initiate an API call to Openai's API to recieve response for user questions 74 | //from Openai's AI 75 | // But while making the call we bundle the user question/prompt and other 76 | // instructions to ensure we get the best response from the AI back to user 77 | openai.createChatCompletion({ 78 | model: "gpt-3.5-turbo", 79 | messages: toChatML((prompt)) 80 | }).then((data) => { 81 | const aiResponse = get_message(data.data); 82 | // console.log(aiResponse); // Log the response to the console for confirmation 83 | // console.log((get_message(data.data))); 84 | 85 | // Send the response back to the frontend 86 | res.status(200).send({ 87 | ai: aiResponse, 88 | }); 89 | }); 90 | 91 | 92 | // logs error to the console and sends it back our chatGPT Ai chatBot SvelteKit powered frontend 93 | //with a status of 500 if there is any error caught in try block. 94 | } catch (error) { 95 | console.log(error); 96 | res.status(400).send({ 97 | message: error.message, 98 | }); 99 | } 100 | }) 101 | 102 | 103 | // start the server on specified port on localhost 104 | // this get overriden when deployed to web server by the server url 105 | app.listen(5000, () => console.log('Foskaay Ai server started on http://localhost:5000')) -------------------------------------------------------------------------------- /server/serverGPT3API.js: -------------------------------------------------------------------------------- 1 | import express from 'express' //backend server framework 2 | import * as dotenv from 'dotenv' // access and use API KEY stored in .env file 3 | import cors from 'cors' //allow make cross origin API request to server from frontend 4 | import allowedOrigins from './whitelist.js'; //allowed domains only 5 | import { Configuration, OpenAIApi } from 'openai' //Openai API wrapper 6 | 7 | 8 | //call config function to give access to .env API KEY variable 9 | dotenv.config() 10 | 11 | 12 | //Openai API wrapper function which accepts API KEY as object parameter 13 | const configuration = new Configuration({ 14 | apiKey: process.env.OPENAI_API_KEY, 15 | }); 16 | 17 | 18 | // create instance of Openai and pass in the configuration object created above 19 | const openai = new OpenAIApi(configuration); 20 | 21 | 22 | // initialize expressjs server 23 | const app = express() 24 | 25 | 26 | // configure the cors middleware to allow accepting and processing request from allowed domains 27 | app.use(cors({ 28 | origin: (origin, callback) => { 29 | // check if the origin is in the allowed origins array 30 | if (allowedOrigins.indexOf(origin) !== -1) { 31 | callback(null, true); 32 | } else { 33 | callback(new Error('Not allowed by CORS')); 34 | } 35 | } 36 | })); 37 | 38 | 39 | //middleware: allows the backend to recieve and acces request from frontend as a json object 40 | // rather than just a string. 41 | // This is necessary in the following POST request route code: 42 | // app.post('/', async (req, res) => { 43 | // try {const prompt = req.body.prompt; 44 | // where it uses req.body to get the prompt data/question sent in the post request 45 | // from our chatGPT Ai chatBot SvelteKit powered frontend 46 | app.use(express.json()) 47 | 48 | 49 | // routes/endpoint to expose expressjs backend to frontend "GET" request 50 | // with a return statement of info to show user visiting the route 51 | // "started on http://localhost:5001" makes the port link clickable from terminal 52 | app.get('/', async (req, res) => { 53 | res.status(200).send({ 54 | message: 'Hello Web3 AI World from Foskaay AI', 55 | }) 56 | }) 57 | 58 | 59 | //route/endpoint which allows Expressjs backend to recieve and process 60 | // the request sent from users of our chatGPT Ai chatBot SvelteKit powered frontend 61 | app.post('/', async (req, res) => { 62 | 63 | // check if the origin is in the allowed origins array/whitelist domains 64 | // before processing request 65 | if (!allowedOrigins.includes(req.headers.origin)) { 66 | return res.status(401).send({ message: 'Unauthorized: Origin not allowed' }); 67 | } 68 | 69 | try { 70 | const prompt = req.body.prompt; //access user question submited as prompt 71 | 72 | //Initiate an API call to Openai's API to recieve response for user questions 73 | //from Openai's AI 74 | // But while making the call we bundle the user question/prompt and other 75 | // instructions to ensure we get the best response from the AI back to user 76 | const response = await openai.createCompletion({ 77 | model: "text-davinci-003", //most powerful openai large language Ai model for now 78 | prompt: `${prompt}`, //input text value of the form input box in sveltekit app ui 79 | temperature: 1, // Higher values means the model will take more risks and can change/modify response for same question when asked again. 80 | max_tokens: 3000, // If not specified, it auto limit reponses usually less than 50 character (thats about 50 words)The maximum number of tokens to generate in the completion. Most models have a context length of 2048 tokens (except for the newest models, which support over 8,000). 81 | top_p: 1, // alternative to sampling with temperature, called nucleus sampling 82 | frequency_penalty: 0.5, // Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim. 83 | presence_penalty: 0, // Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far, increasing the model's likelihood to talk about new topics. 84 | // user: "user123456", // optional but can be useful to detect user abusing your API request. You can use session ID or hash email/psw so each user is unique but still not individually identificable for openai 85 | }); 86 | 87 | //Send the AI response back to user of 88 | // our chatGPT Ai chatBot SvelteKit powered frontend 89 | //in json format with a success status code of 200. 90 | res.status(200).send({ 91 | ai: response.data.choices[0].text 92 | }); 93 | 94 | 95 | // logs error to the console and sends it back our chatGPT Ai chatBot SvelteKit powered frontend 96 | //with a status of 500 if there is any error caught in try block. 97 | } catch (error) { 98 | console.error(error) 99 | res.status(500).send(error || 'Something went wrong communicating with Ai Foskaay'); 100 | } 101 | }) 102 | 103 | 104 | // start the server on specified port on localhost 105 | // this get overriden when deployed to web server by the server url 106 | app.listen(5000, () => console.log('Foskaay Ai server started on http://localhost:5000')) -------------------------------------------------------------------------------- /server/whitelist.js: -------------------------------------------------------------------------------- 1 | // allowed origins is an array of allowed domains 2 | const allowedOrigins = ['https://foskaay.aihipuniversity.com']; 3 | 4 | export default allowedOrigins; -------------------------------------------------------------------------------- /server/whitelist.js.Example: -------------------------------------------------------------------------------- 1 | // Rename this file from whitelist.js.Example to whitelist.js 2 | // Never allow localhost in your production server whitelist 3 | // because anyone can connect as whitelisted domain once they runing on local host 4 | //You can add as many whitelist domains as you want 5 | 6 | // allowed origins is an array of allowed domains 7 | const allowedOrigins = ['https://example.com','http://localhost:5173']; 8 | 9 | export default allowedOrigins; 10 | -------------------------------------------------------------------------------- /ui/.eslintignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | 10 | # Ignore files for PNPM, NPM and YARN 11 | pnpm-lock.yaml 12 | package-lock.json 13 | yarn.lock 14 | -------------------------------------------------------------------------------- /ui/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: '@typescript-eslint/parser', 4 | extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'], 5 | plugins: ['svelte3', '@typescript-eslint'], 6 | ignorePatterns: ['*.cjs'], 7 | overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }], 8 | settings: { 9 | 'svelte3/typescript': () => require('typescript') 10 | }, 11 | parserOptions: { 12 | sourceType: 'module', 13 | ecmaVersion: 2020 14 | }, 15 | env: { 16 | browser: true, 17 | es2017: true, 18 | node: true 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /ui/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | vite.config.js.timestamp-* 10 | vite.config.ts.timestamp-* 11 | -------------------------------------------------------------------------------- /ui/.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /ui/.prettierignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | 10 | # Ignore files for PNPM, NPM and YARN 11 | pnpm-lock.yaml 12 | package-lock.json 13 | yarn.lock 14 | -------------------------------------------------------------------------------- /ui/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": true, 3 | "singleQuote": true, 4 | "trailingComma": "none", 5 | "printWidth": 100, 6 | "plugins": ["prettier-plugin-svelte"], 7 | "pluginSearchDirs": ["."], 8 | "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] 9 | } 10 | -------------------------------------------------------------------------------- /ui/README.md: -------------------------------------------------------------------------------- 1 | # create-svelte 2 | 3 | Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/master/packages/create-svelte). 4 | 5 | ## Creating a project 6 | 7 | If you're seeing this, you've probably already done this step. Congrats! 8 | 9 | ```bash 10 | # create a new project in the current directory 11 | npm create svelte@latest 12 | 13 | # create a new project in my-app 14 | npm create svelte@latest my-app 15 | ``` 16 | 17 | ## Developing 18 | 19 | Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server: 20 | 21 | ```bash 22 | npm run dev 23 | 24 | # or start the server and open the app in a new browser tab 25 | npm run dev -- --open 26 | ``` 27 | 28 | ## Building 29 | 30 | To create a production version of your app: 31 | 32 | ```bash 33 | npm run build 34 | ``` 35 | 36 | You can preview the production build with `npm run preview`. 37 | 38 | > To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment. 39 | -------------------------------------------------------------------------------- /ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ui", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "dev": "vite dev", 7 | "build": "vite build", 8 | "preview": "vite preview", 9 | "test": "playwright test", 10 | "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", 11 | "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", 12 | "test:unit": "vitest", 13 | "lint": "prettier --plugin-search-dir . --check . && eslint .", 14 | "format": "prettier --plugin-search-dir . --write ." 15 | }, 16 | "devDependencies": { 17 | "@playwright/test": "^1.28.1", 18 | "@sveltejs/adapter-auto": "^2.0.0", 19 | "@sveltejs/kit": "^1.5.0", 20 | "@typescript-eslint/eslint-plugin": "^5.45.0", 21 | "@typescript-eslint/parser": "^5.45.0", 22 | "eslint": "^8.28.0", 23 | "eslint-config-prettier": "^8.5.0", 24 | "eslint-plugin-svelte3": "^4.0.0", 25 | "prettier": "^2.8.0", 26 | "prettier-plugin-svelte": "^2.8.1", 27 | "svelte": "^3.54.0", 28 | "svelte-check": "^3.0.1", 29 | "svelte-prism": "^1.1.6", 30 | "tslib": "^2.4.1", 31 | "typescript": "^4.9.3", 32 | "vite": "^4.0.0", 33 | "vitest": "^0.25.3", 34 | "postcss": "^8.4.14", 35 | "postcss-load-config": "^4.0.1", 36 | "svelte-preprocess": "^4.10.7", 37 | "autoprefixer": "^10.4.7", 38 | "tailwindcss": "^3.1.5" 39 | }, 40 | "type": "module", 41 | "dependencies": { 42 | "uuid": "^9.0.0" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /ui/playwright.config.ts: -------------------------------------------------------------------------------- 1 | import type { PlaywrightTestConfig } from '@playwright/test'; 2 | 3 | const config: PlaywrightTestConfig = { 4 | webServer: { 5 | command: 'npm run build && npm run preview', 6 | port: 4173 7 | }, 8 | testDir: 'tests' 9 | }; 10 | 11 | export default config; 12 | -------------------------------------------------------------------------------- /ui/postcss.config.cjs: -------------------------------------------------------------------------------- 1 | const tailwindcss = require('tailwindcss'); 2 | const autoprefixer = require('autoprefixer'); 3 | 4 | const config = { 5 | plugins: [ 6 | //Some plugins, like tailwindcss/nesting, need to run before Tailwind, 7 | tailwindcss(), 8 | //But others, like autoprefixer, need to run after, 9 | autoprefixer 10 | ] 11 | }; 12 | 13 | module.exports = config; 14 | -------------------------------------------------------------------------------- /ui/src/DeclarationFile.d.ts: -------------------------------------------------------------------------------- 1 | //Declaration file to help resolve conflict between typescript and modules not identified after been properly installed. 2 | // this help resolve module not found error when importing packages modules 3 | 4 | //declare uuid package module 5 | declare module 'uuid'; 6 | 7 | -------------------------------------------------------------------------------- /ui/src/app.d.ts: -------------------------------------------------------------------------------- 1 | // See https://kit.svelte.dev/docs/types#app 2 | // for information about these interfaces 3 | declare global { 4 | namespace App { 5 | // interface Error {} 6 | // interface Locals {} 7 | // interface PageData {} 8 | // interface Platform {} 9 | } 10 | } 11 | 12 | export {}; 13 | -------------------------------------------------------------------------------- /ui/src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %sveltekit.head% 8 | 9 | 10 |
%sveltekit.body%
11 | 12 | 13 | -------------------------------------------------------------------------------- /ui/src/app.postcss: -------------------------------------------------------------------------------- 1 | /* Write your global styles here, in PostCSS syntax */ 2 | @tailwind base; 3 | @tailwind components; 4 | @tailwind utilities; 5 | -------------------------------------------------------------------------------- /ui/src/index.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from 'vitest'; 2 | 3 | describe('sum test', () => { 4 | it('adds 1 + 2 to equal 3', () => { 5 | expect(1 + 2).toBe(3); 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /ui/src/lib/images/banner1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AiHiPUniversity/ai-chatbot-openai-sveltekit-boilerplate-1/abde58b12363206eae0af605ba920b67adf89c38/ui/src/lib/images/banner1.jpg -------------------------------------------------------------------------------- /ui/src/lib/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AiHiPUniversity/ai-chatbot-openai-sveltekit-boilerplate-1/abde58b12363206eae0af605ba920b67adf89c38/ui/src/lib/images/favicon.png -------------------------------------------------------------------------------- /ui/src/lib/images/github.svg: -------------------------------------------------------------------------------- 1 | 2 | 9 | 16 | -------------------------------------------------------------------------------- /ui/src/lib/images/svelte-logo.svg: -------------------------------------------------------------------------------- 1 | svelte-logo -------------------------------------------------------------------------------- /ui/src/lib/images/svelte-welcome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AiHiPUniversity/ai-chatbot-openai-sveltekit-boilerplate-1/abde58b12363206eae0af605ba920b67adf89c38/ui/src/lib/images/svelte-welcome.png -------------------------------------------------------------------------------- /ui/src/lib/images/svelte-welcome.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AiHiPUniversity/ai-chatbot-openai-sveltekit-boilerplate-1/abde58b12363206eae0af605ba920b67adf89c38/ui/src/lib/images/svelte-welcome.webp -------------------------------------------------------------------------------- /ui/src/lib/styles/chat.css: -------------------------------------------------------------------------------- 1 | /* style the chat appearance */ 2 | 3 | #new-chat { 4 | width: 100%; 5 | display: block; 6 | padding: 10px; 7 | font-size: 1.2em; 8 | background-color: #333; 9 | color: white; 10 | border: none; 11 | cursor: pointer; 12 | margin-bottom: 10px; 13 | } 14 | 15 | #prompts { 16 | display: flex; 17 | flex-wrap: wrap; 18 | } 19 | 20 | .prompts-section, 21 | .features-section { 22 | width: 50%; 23 | } 24 | 25 | .prompts-section { 26 | text-align: right; 27 | } 28 | 29 | .features-section { 30 | text-align: left; 31 | } 32 | 33 | h2 { 34 | margin: 0; 35 | } 36 | 37 | .prompt { 38 | display: block; 39 | margin: 0; 40 | padding: 5px 10px; 41 | font-size: 0.9em; 42 | background-color: #eee; 43 | color: #333; 44 | cursor: pointer; 45 | } 46 | 47 | .prompt:hover { 48 | background-color: #ddd; 49 | } 50 | 51 | ul { 52 | list-style: none; 53 | margin: 0; 54 | padding: 0; 55 | } 56 | 57 | li { 58 | margin: 5px 0; 59 | } 60 | -------------------------------------------------------------------------------- /ui/src/lib/styles/prism-okaidia.css: -------------------------------------------------------------------------------- 1 | /* 2 | This is Prism theme used with svelte-prism 3 | 4 | Svelte-Prism: https://www.npmjs.com/package/svelte-prism 5 | -------------------------------- 6 | Theme Name: prism-okaidia 7 | 8 | Css Code Link: 9 | https://cdnjs.cloudflare.com/ajax/libs/prism/1.17.1/themes/prism-okaidia.min.css 10 | 11 | Css Code Link Source Map (download and copy the code to the end of this file): 12 | https://cdnjs.cloudflare.com/ajax/libs/prism/1.17.1/themes/prism-okaidia.min.css 13 | 14 | */ 15 | 16 | code[class*='language-'], 17 | pre[class*='language-'] { 18 | color: #f8f8f2; 19 | background: 0 0; 20 | text-shadow: 0 1px rgba(0, 0, 0, 0.3); 21 | font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; 22 | font-size: 1em; 23 | text-align: left; 24 | white-space: pre; 25 | word-spacing: normal; 26 | word-break: normal; 27 | word-wrap: normal; 28 | line-height: 1.5; 29 | -moz-tab-size: 4; 30 | -o-tab-size: 4; 31 | tab-size: 4; 32 | -webkit-hyphens: none; 33 | -moz-hyphens: none; 34 | -ms-hyphens: none; 35 | hyphens: none; 36 | } 37 | pre[class*='language-'] { 38 | padding: 1em; 39 | margin: 0.5em 0; 40 | overflow: auto; 41 | border-radius: 0.3em; 42 | } 43 | :not(pre) > code[class*='language-'], 44 | pre[class*='language-'] { 45 | background: #272822; 46 | } 47 | :not(pre) > code[class*='language-'] { 48 | padding: 0.1em; 49 | border-radius: 0.3em; 50 | white-space: normal; 51 | } 52 | .token.cdata, 53 | .token.comment, 54 | .token.doctype, 55 | .token.prolog { 56 | color: #708090; 57 | } 58 | .token.punctuation { 59 | color: #f8f8f2; 60 | } 61 | .namespace { 62 | opacity: 0.7; 63 | } 64 | .token.constant, 65 | .token.deleted, 66 | .token.property, 67 | .token.symbol, 68 | .token.tag { 69 | color: #f92672; 70 | } 71 | .token.boolean, 72 | .token.number { 73 | color: #ae81ff; 74 | } 75 | .token.attr-name, 76 | .token.builtin, 77 | .token.char, 78 | .token.inserted, 79 | .token.selector, 80 | .token.string { 81 | color: #a6e22e; 82 | } 83 | .language-css .token.string, 84 | .style .token.string, 85 | .token.entity, 86 | .token.operator, 87 | .token.url, 88 | .token.variable { 89 | color: #f8f8f2; 90 | } 91 | .token.atrule, 92 | .token.attr-value, 93 | .token.class-name, 94 | .token.function { 95 | color: #e6db74; 96 | } 97 | .token.keyword { 98 | color: #66d9ef; 99 | } 100 | .token.important, 101 | .token.regex { 102 | color: #fd971f; 103 | } 104 | .token.bold, 105 | .token.important { 106 | font-weight: 700; 107 | } 108 | .token.italic { 109 | font-style: italic; 110 | } 111 | .token.entity { 112 | cursor: help; 113 | } 114 | /*# sourceMappingURL=prism-okaidia.min.css.map */ 115 | { 116 | "version": 3, 117 | "sources": [ 118 | "prism-okaidia.css" 119 | ]; 120 | "names": [], 121 | "mappings": "AAMA,uBACA,sBACC,MAAO,QACP,WAAY,IACZ,YAAa,EAAE,IAAI,eACnB,YAAa,QAAQ,CAAE,MAAM,CAAE,aAAa,CAAE,aAAa,CAAE,UAC7D,UAAW,IACX,WAAY,KACZ,YAAa,IACb,aAAc,OACd,WAAY,OACZ,UAAW,OACX,YAAa,IAEb,cAAe,EACf,YAAa,EACb,SAAU,EAEV,gBAAiB,KACjB,aAAc,KACd,YAAa,KACb,QAAS,KAIV,sBACC,QAAS,IACT,OAAQ,KAAK,EACb,SAAU,KACV,cAAe,KAGhB,iCACA,sBACC,WAAY,QAIb,iCACC,QAAS,KACT,cAAe,KACf,YAAa,OAMd,aAHA,eAEA,eADA,cAGC,MAAO,QAGR,mBACC,MAAO,QAGR,WACC,QAAS,GAKV,gBAEA,eAJA,gBAGA,cAFA,WAIC,MAAO,QAGR,eACA,cACC,MAAO,QAIR,iBAGA,eADA,YAEA,gBALA,gBAEA,cAIC,MAAO,QAMR,4BACA,qBAHA,cADA,gBAEA,WAGA,gBACC,MAAO,QAGR,cACA,kBAEA,kBADA,gBAEC,MAAO,QAGR,eACC,MAAO,QAIR,iBADA,aAEC,MAAO,QAIR,YADA,iBAEC,YAAa,IAEd,cACC,WAAY,OAGb,cACC,OAAQ" 122 | } 123 | 124 | /* other custom styles not included in the default theme above */ 125 | 126 | /* .code-block { 127 | Add styles for the code block here 128 | } 129 | 130 | .scrollable-code-block { 131 | Add a scrollbar to the code block 132 | overflow-y: scroll; 133 | Set a maximum height for the code block 134 | max-height: 500px; 135 | } */ -------------------------------------------------------------------------------- /ui/src/lib/styles/prism-okaidiaOLD.css: -------------------------------------------------------------------------------- 1 | /* This is Prism theme used with svelte-prism 2 | Svelte-Prism: https://www.npmjs.com/package/svelte-prism 3 | -------------------------------- 4 | Theme Name: prism-okaidia 5 | Css Code Link: https://cdnjs.cloudflare.com/ajax/libs/prism/1.17.1/themes/prism-okaidia.min.css 6 | */ 7 | 8 | code[class*='language-'], 9 | pre[class*='language-'] { 10 | color: #f8f8f2; 11 | background: 0 0; 12 | text-shadow: 0 1px rgba(0, 0, 0, 0.3); 13 | font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; 14 | font-size: 1em; 15 | text-align: left; 16 | white-space: pre; 17 | word-spacing: normal; 18 | word-break: normal; 19 | word-wrap: normal; 20 | line-height: 1.5; 21 | -moz-tab-size: 4; 22 | -o-tab-size: 4; 23 | tab-size: 4; 24 | -webkit-hyphens: none; 25 | -moz-hyphens: none; 26 | -ms-hyphens: none; 27 | hyphens: none; 28 | /* customization added */ 29 | /* Add a scrollbar to the code block */ 30 | overflow-y: scroll; 31 | /* Set a maximum height for the code block */ 32 | max-height: 870px; 33 | } 34 | pre[class*='language-'] { 35 | padding: 1em; 36 | margin: 0.5em 0; 37 | overflow: auto; 38 | border-radius: 0.3em; 39 | } 40 | :not(pre) > code[class*='language-'], 41 | pre[class*='language-'] { 42 | background: #272822; 43 | } 44 | :not(pre) > code[class*='language-'] { 45 | padding: 0.1em; 46 | border-radius: 0.3em; 47 | white-space: normal; 48 | } 49 | .token.cdata, 50 | .token.comment, 51 | .token.doctype, 52 | .token.prolog { 53 | color: #708090; 54 | } 55 | .token.punctuation { 56 | color: #f8f8f2; 57 | } 58 | .namespace { 59 | opacity: 0.7; 60 | } 61 | .token.constant, 62 | .token.deleted, 63 | .token.property, 64 | .token.symbol, 65 | .token.tag { 66 | color: #f92672; 67 | } 68 | .token.boolean, 69 | .token.number { 70 | color: #ae81ff; 71 | } 72 | .token.attr-name, 73 | .token.builtin, 74 | .token.char, 75 | .token.inserted, 76 | .token.selector, 77 | .token.string { 78 | color: #a6e22e; 79 | } 80 | .language-css .token.string, 81 | .style .token.string, 82 | .token.entity, 83 | .token.operator, 84 | .token.url, 85 | .token.variable { 86 | color: #f8f8f2; 87 | } 88 | .token.atrule, 89 | .token.attr-value, 90 | .token.class-name, 91 | .token.function { 92 | color: #e6db74; 93 | } 94 | .token.keyword { 95 | color: #66d9ef; 96 | } 97 | .token.important, 98 | .token.regex { 99 | color: #fd971f; 100 | } 101 | .token.bold, 102 | .token.important { 103 | font-weight: 700; 104 | } 105 | .token.italic { 106 | font-style: italic; 107 | } 108 | .token.entity { 109 | cursor: help; 110 | } 111 | /*# sourceMappingURL=prism-okaidia.min.css.map */ 112 | 113 | /* other custom styles not included in the default theme above */ 114 | 115 | /* .code-block { 116 | Add styles for the code block here 117 | } 118 | 119 | .scrollable-code-block { 120 | Add a scrollbar to the code block 121 | overflow-y: scroll; 122 | Set a maximum height for the code block 123 | max-height: 500px; 124 | } */ 125 | -------------------------------------------------------------------------------- /ui/src/routes/+layout.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 |
7 |
8 | 9 |
10 | 11 |
12 | 13 |
14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /ui/src/routes/+page.svelte: -------------------------------------------------------------------------------- 1 | 2 | 3 | Home 4 | 5 | 6 | 7 | 10 | 227 | 228 | 229 | 230 | 231 |
232 | 233 |
234 | 235 | 236 |
237 |
238 | {#if messages.length === 0} 239 |
240 |
241 |

Prompts

242 |

What is your favorite color?

243 |

What is your favorite animal?

244 |

What is your favorite food?

245 |
246 |
247 |

Features

248 |
    249 |
  • Realistic conversations
  • 250 |
  • Quick responses
  • 251 |
  • Unlimited chat instances
  • 252 |
253 |
254 |
255 | {/if} 256 | 257 |

Foskaay Coding AI:

258 | 259 | 260 |
261 | 262 | {#each messages as message} 263 | {#if message.type === 'user'} 264 |

265 | 266 | {message.text} 267 |

268 | {:else} 269 |

270 | {message.text} 271 |

272 | {/if} 273 | {/each} 274 |
275 | 276 | 277 | 278 |
279 | 280 | {#if chatInstances.length > 0} 281 |
282 | 283 | 293 | 294 |
295 | {/if} 296 |
297 | 298 | 299 | 300 | 301 | 302 |
303 | 304 |
305 | {#each chatInstances as chatInstance} 306 |
307 | {#if chatInstance.isEditing} 308 | newTitle = e.target.value}> 309 |
310 | 313 | 316 | {:else} 317 | {chatInstance.title} 318 | 321 | 324 | {/if} 325 |
326 |
327 | {/each} 328 |
329 |
330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | -------------------------------------------------------------------------------- /ui/src/routes/Header.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 |
8 |
9 | 12 |
13 | 14 | 42 | 43 |
44 | 52 |
53 |
54 | 55 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /ui/src/routes/pageCopy1.svelte: -------------------------------------------------------------------------------- 1 | 2 | 3 | Home 4 | 5 | 6 | 7 | 10 | 210 | 211 | 212 | 213 | 214 |
215 | 216 |
217 | 218 | 219 |
220 |
221 | {#if messages.length === 0} 222 |
223 |
224 |

Prompts

225 |

What is your favorite color?

226 |

What is your favorite animal?

227 |

What is your favorite food?

228 |
229 |
230 |

Features

231 |
    232 |
  • Realistic conversations
  • 233 |
  • Quick responses
  • 234 |
  • Unlimited chat instances
  • 235 |
236 |
237 |
238 | {/if} 239 | 240 | {#each messages as message} 241 | {#if message.type === 'user'} 242 |
{message.text}
243 | {:else} 244 | 245 | 246 | 247 | 248 |
249 | {message.text} 250 |
251 | {/if} 252 | {/each} 253 | 254 | 255 |
256 | 257 | {#if chatInstances.length > 0} 258 |
259 | 260 | 261 |
262 | {/if} 263 |
264 | 265 | 266 | 267 | 268 | 269 |
270 | 271 |
272 | {#each chatInstances as chatInstance} 273 |
274 | {#if chatInstance.isEditing} 275 | newTitle = e.target.value}> 276 |
277 | 280 | 283 | {:else} 284 | {chatInstance.title} 285 | 288 | 291 | {/if} 292 |
293 |
294 | {/each} 295 |
296 |
297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | -------------------------------------------------------------------------------- /ui/src/routes/pageCopy2.svelte: -------------------------------------------------------------------------------- 1 | 2 | 3 | Home 4 | 5 | 6 | 7 | 10 | 210 | 211 | 212 | 213 | 214 |
215 | 216 |
217 | 218 | 219 |
220 |
221 | {#if messages.length === 0} 222 |
223 |
224 |

Prompts

225 |

What is your favorite color?

226 |

What is your favorite animal?

227 |

What is your favorite food?

228 |
229 |
230 |

Features

231 |
    232 |
  • Realistic conversations
  • 233 |
  • Quick responses
  • 234 |
  • Unlimited chat instances
  • 235 |
236 |
237 |
238 | {/if} 239 | 240 | {#each messages as message} 241 | {#if message.type === 'user'} 242 |
243 | {message.text} 244 |
245 | {:else} 246 | 247 |
248 | {message.text} 249 |
250 | {/if} 251 | {/each} 252 |
253 | 254 | {#if chatInstances.length > 0} 255 |
256 | 257 | 258 |
259 | {/if} 260 |
261 | 262 | 263 | 264 | 265 | 266 |
267 | 268 |
269 | {#each chatInstances as chatInstance} 270 |
271 | {#if chatInstance.isEditing} 272 | newTitle = e.target.value}> 273 |
274 | 277 | 280 | {:else} 281 | {chatInstance.title} 282 | 285 | 288 | {/if} 289 |
290 |
291 | {/each} 292 |
293 |
294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | -------------------------------------------------------------------------------- /ui/src/routes/pageCopy3.svelte: -------------------------------------------------------------------------------- 1 | 2 | 3 | Home 4 | 5 | 6 | 7 | 10 | 227 | 228 | 229 | 230 | 231 |
232 | 233 |
234 | 235 | 236 |
237 |
238 | {#if messages.length === 0} 239 |
240 |
241 |

Prompts

242 |

What is your favorite color?

243 |

What is your favorite animal?

244 |

What is your favorite food?

245 |
246 |
247 |

Features

248 |
    249 |
  • Realistic conversations
  • 250 |
  • Quick responses
  • 251 |
  • Unlimited chat instances
  • 252 |
253 |
254 |
255 | {/if} 256 | 257 |

NEW DISPLAY BELOW:

258 | 259 | 260 |
261 | 262 | {#each messages as message} 263 |
264 | 265 |

{message.text}

266 | 267 | 268 |
269 | {/each} 270 |
271 | 272 | 273 | 274 |
275 | 276 | {#if chatInstances.length > 0} 277 |
278 | 279 | 280 |
281 | {/if} 282 |
283 | 284 | 285 | 286 | 287 | 288 |
289 | 290 |
291 | {#each chatInstances as chatInstance} 292 |
293 | {#if chatInstance.isEditing} 294 | newTitle = e.target.value}> 295 |
296 | 299 | 302 | {:else} 303 | {chatInstance.title} 304 | 307 | 310 | {/if} 311 |
312 |
313 | {/each} 314 |
315 |
316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | -------------------------------------------------------------------------------- /ui/src/routes/pageCopy4.svelte: -------------------------------------------------------------------------------- 1 | 2 | 3 | Home 4 | 5 | 6 | 7 | 10 | 227 | 228 | 229 | 230 | 231 |
232 | 233 |
234 | 235 | 236 |
237 |
238 | {#if messages.length === 0} 239 |
240 |
241 |

Prompts

242 |

What is your favorite color?

243 |

What is your favorite animal?

244 |

What is your favorite food?

245 |
246 |
247 |

Features

248 |
    249 |
  • Realistic conversations
  • 250 |
  • Quick responses
  • 251 |
  • Unlimited chat instances
  • 252 |
253 |
254 |
255 | {/if} 256 | 257 |

NEW DISPLAY BELOW:

258 | 259 | 260 | 263 | 264 |
265 | {#each messages as message} 266 |
267 | {message.text} 268 |
269 | {/each} 270 |
271 | 272 | 273 | 274 |
275 | 276 | {#if chatInstances.length > 0} 277 |
278 | 279 | 280 |
281 | {/if} 282 |
283 | 284 | 285 | 286 | 287 | 288 |
289 | 290 |
291 | {#each chatInstances as chatInstance} 292 |
293 | {#if chatInstance.isEditing} 294 | newTitle = e.target.value}> 295 |
296 | 299 | 302 | {:else} 303 | {chatInstance.title} 304 | 307 | 310 | {/if} 311 |
312 |
313 | {/each} 314 |
315 |
316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | -------------------------------------------------------------------------------- /ui/src/routes/pageCopy5.svelte: -------------------------------------------------------------------------------- 1 | 2 | 3 | Home 4 | 5 | 6 | 7 | 10 | 240 | 241 | 242 | 243 | 244 |
245 | 246 |
247 | 248 | 249 |
250 |
251 | {#if messages.length === 0} 252 |
253 |
254 |

Prompts

255 |

What is your favorite color?

256 |

What is your favorite animal?

257 |

What is your favorite food?

258 |
259 |
260 |

Features

261 |
    262 |
  • Realistic conversations
  • 263 |
  • Quick responses
  • 264 |
  • Unlimited chat instances
  • 265 |
266 |
267 |
268 | {/if} 269 | 270 |

NEW DISPLAY BELOW:

271 | 272 | 273 | 276 | 277 |
278 | {#each messages as message} 279 |
280 | 281 | {#if message.type === 'user'} 282 |

{message.text}

283 | {:else} 284 |

285 | {message.text} 286 |

287 | {/if} 288 |
289 | {/each} 290 |
291 | 292 | 301 | 302 | 303 |
304 | 305 | {#if chatInstances.length > 0} 306 |
307 | 308 | 309 |
310 | {/if} 311 |
312 | 313 | 314 | 315 | 316 | 317 |
318 | 319 |
320 | {#each chatInstances as chatInstance} 321 |
322 | {#if chatInstance.isEditing} 323 | newTitle = e.target.value}> 324 |
325 | 328 | 331 | {:else} 332 | {chatInstance.title} 333 | 336 | 339 | {/if} 340 |
341 |
342 | {/each} 343 |
344 |
345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | -------------------------------------------------------------------------------- /ui/src/routes/pageCopy6.svelte: -------------------------------------------------------------------------------- 1 | 2 | 3 | Home 4 | 5 | 6 | 7 | 10 | 227 | 228 | 229 | 230 | 231 |
232 | 233 |
234 | 235 | 236 |
237 |
238 | {#if messages.length === 0} 239 |
240 |
241 |

Prompts

242 |

What is your favorite color?

243 |

What is your favorite animal?

244 |

What is your favorite food?

245 |
246 |
247 |

Features

248 |
    249 |
  • Realistic conversations
  • 250 |
  • Quick responses
  • 251 |
  • Unlimited chat instances
  • 252 |
253 |
254 |
255 | {/if} 256 | 257 |

Foskaay Coding AI:

258 | 259 | 260 |
261 | 262 | {#each messages as message} 263 | {#if message.type === 'user'} 264 |

{message.text}

265 | {:else} 266 |

267 | {message.text} 268 |

269 | {/if} 270 | {/each} 271 |
272 | 273 | 274 | 275 |
276 | 277 | {#if chatInstances.length > 0} 278 |
279 | 280 | 281 |
282 | {/if} 283 |
284 | 285 | 286 | 287 | 288 | 289 |
290 | 291 |
292 | {#each chatInstances as chatInstance} 293 |
294 | {#if chatInstance.isEditing} 295 | newTitle = e.target.value}> 296 |
297 | 300 | 303 | {:else} 304 | {chatInstance.title} 305 | 308 | 311 | {/if} 312 |
313 |
314 | {/each} 315 |
316 |
317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | -------------------------------------------------------------------------------- /ui/static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AiHiPUniversity/ai-chatbot-openai-sveltekit-boilerplate-1/abde58b12363206eae0af605ba920b67adf89c38/ui/static/favicon.png -------------------------------------------------------------------------------- /ui/svelte.config.js: -------------------------------------------------------------------------------- 1 | import preprocess from 'svelte-preprocess'; 2 | import adapter from '@sveltejs/adapter-auto'; 3 | import { vitePreprocess } from '@sveltejs/kit/vite'; 4 | 5 | /** @type {import('@sveltejs/kit').Config} */ 6 | const config = { 7 | // Consult https://kit.svelte.dev/docs/integrations#preprocessors 8 | // for more information about preprocessors 9 | preprocess: [ 10 | vitePreprocess(), 11 | preprocess({ 12 | postcss: true 13 | }) 14 | ], 15 | 16 | kit: { 17 | adapter: adapter() 18 | } 19 | }; 20 | 21 | export default config; 22 | -------------------------------------------------------------------------------- /ui/tailwind.config.cjs: -------------------------------------------------------------------------------- 1 | const config = { 2 | content: ['./src/**/*.{html,js,svelte,ts}'], 3 | 4 | theme: { 5 | extend: {} 6 | }, 7 | 8 | plugins: [] 9 | }; 10 | 11 | module.exports = config; 12 | -------------------------------------------------------------------------------- /ui/tests/test.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from '@playwright/test'; 2 | 3 | test('index page has expected h1', async ({ page }) => { 4 | await page.goto('/'); 5 | await expect(page.getByRole('heading', { name: 'Welcome to SvelteKit' })).toBeVisible(); 6 | }); 7 | -------------------------------------------------------------------------------- /ui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.svelte-kit/tsconfig.json", 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "checkJs": true, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "resolveJsonModule": true, 9 | "skipLibCheck": true, 10 | "sourceMap": true, 11 | "strict": true 12 | } 13 | // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias 14 | // 15 | // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes 16 | // from the referenced tsconfig.json - TypeScript does not merge them in 17 | } 18 | -------------------------------------------------------------------------------- /ui/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { sveltekit } from '@sveltejs/kit/vite'; 2 | import { defineConfig } from 'vitest/config'; 3 | 4 | export default defineConfig({ 5 | plugins: [sveltekit()], 6 | test: { 7 | include: ['src/**/*.{test,spec}.{js,ts}'] 8 | } 9 | }); 10 | --------------------------------------------------------------------------------