├── .eslintignore ├── .eslintrc.yml ├── .github └── workflows │ └── build-and-publish.yml ├── .gitignore ├── .prettierrc ├── .replit ├── README.md ├── package-lock.json ├── package.json ├── preact.config.js ├── prerender-urls.json ├── replit.nix ├── size-plugin.json ├── src ├── assets │ ├── builtin-models │ │ ├── chat │ │ │ ├── act-therapist.png │ │ │ ├── ai-assistant.png │ │ │ ├── alien.png │ │ │ ├── con-artist.png │ │ │ ├── energy-educator.json │ │ │ ├── energy-educator.png │ │ │ ├── hey-sad-guy-feel-better.json │ │ │ ├── hey-sad-guy-feel-better.png │ │ │ ├── interviewer.png │ │ │ └── rogerian-therapist.png │ │ ├── citymaker │ │ │ ├── babylon.json │ │ │ ├── babylon.png │ │ │ ├── talamora.json │ │ │ └── talamora.png │ │ ├── layercraft │ │ │ ├── pearl-cove.json │ │ │ ├── pearl-cove.png │ │ │ ├── veilvale.json │ │ │ └── veilvale.png │ │ ├── peoplesim │ │ │ ├── camping-fiasco.json │ │ │ ├── camping-fiasco.png │ │ │ ├── orc-vs-hobbit.json │ │ │ └── orc-vs-hobbit.png │ │ └── tone-changer │ │ │ ├── formal-spanish.png │ │ │ ├── malfunctioning-robot.png │ │ │ ├── painfully-academic.png │ │ │ ├── posh-english-lady.png │ │ │ └── preschool-teacher.png │ ├── favicon.ico │ ├── icons │ │ ├── android-chrome-192x192.png │ │ ├── android-chrome-512x512.png │ │ ├── apple-touch-icon.png │ │ ├── browserconfig.xml │ │ ├── chat-logo.png │ │ ├── citymaker-logo.png │ │ ├── cityplayer-logo.png │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── favicon.ico │ │ ├── furniture-icon.png │ │ ├── generic-app-icon.png │ │ ├── iaia-logo.png │ │ ├── interactive-fiction-logo.png │ │ ├── key-management-logo.png │ │ ├── layercraft-logo.png │ │ ├── llm-garden-logo.png │ │ ├── loading-source │ │ │ ├── loading1.png │ │ │ ├── loading2.png │ │ │ ├── loading3.png │ │ │ ├── loading4.png │ │ │ ├── loading5.png │ │ │ ├── loading6.png │ │ │ └── loading7.png │ │ ├── loading.gif │ │ ├── mstile-150x150.png │ │ ├── myoa-logo.png │ │ ├── p5drawing-logo.png │ │ ├── peoplesim-logo.png │ │ ├── person.png │ │ ├── safari-pinned-tab.svg │ │ ├── site.webmanifest │ │ ├── tone-changer-logo.png │ │ └── voice-composer-logo.png │ └── interactive-fiction │ │ └── z5s │ │ ├── Advent.z5 │ │ ├── s5.z4 │ │ ├── zork1.z5 │ │ ├── zork2.z5 │ │ ├── zork3.z5 │ │ └── ztuu.z5 ├── chat │ ├── chatdb.js │ ├── chatview.js │ └── index.js ├── citymaker │ ├── citygraph.js │ ├── citylayout.js │ ├── citymakerdb.js │ ├── citymakerview.js │ ├── index.js │ └── preactcytoscape.js ├── cityplayer │ ├── citycomponents.js │ ├── cityplayerdb.js │ ├── cityplayerview.js │ ├── index.js │ └── linkmarkdown.js ├── components │ ├── app.js │ ├── common.js │ ├── header.js │ ├── home.js │ ├── icons.js │ ├── modelindex.js │ ├── modelmenu.js │ ├── querylog.js │ ├── sidebar.js │ └── speech.js ├── db.js ├── deepequal.js ├── generallogoprompt.js ├── gptservice │ ├── appgpt.js │ ├── gpt.js │ ├── gptcache.js │ └── tokencost.js ├── hashsignal.js ├── imageapi │ ├── dalle.js │ ├── replicatekey.js │ ├── stablediffusion.js │ ├── thumbsnap.js │ └── thumbsnapkey.js ├── imagegen │ ├── imagegendb.js │ ├── imagegenview.js │ └── index.js ├── index.js ├── interactive-fiction │ ├── ifdb.js │ ├── ifview.js │ ├── index.js │ └── storyloader.js ├── key-management │ ├── index.js │ ├── key.js │ └── keyholder.js ├── layercraft │ ├── citymakerschema.js │ ├── index.js │ ├── laxjson.js │ ├── layerdb.js │ ├── layerview.js │ ├── schema.js │ └── template.js ├── loadlegacyscript.js ├── localcache.js ├── localsync.js ├── manifest.json ├── markdown.js ├── myoa │ ├── index.js │ ├── player.js │ ├── playstate.js │ ├── story.js │ ├── storydb.js │ └── storyview.js ├── p5drawing │ ├── iframeview.js │ ├── index.js │ ├── p5db.js │ └── p5view.js ├── peoplesim │ ├── index.js │ ├── peopledb.js │ └── peopleview.js ├── style.css ├── sw.js ├── template.html ├── tone-changer │ ├── index.js │ ├── tonedb.js │ └── toneview.js ├── uuid.js ├── vendor │ ├── _unreset.scss │ ├── encryption.js │ ├── jszm.js │ └── replicate.js └── voice-composer │ ├── index.js │ ├── voicedb.js │ ├── voiceview.js │ └── whisperrecord.js ├── tailwind.config.js └── tests ├── __mocks__ ├── browserMocks.js ├── fileMocks.js └── setupTests.js └── header.test.js /.eslintignore: -------------------------------------------------------------------------------- 1 | src/vendor/ 2 | -------------------------------------------------------------------------------- /.eslintrc.yml: -------------------------------------------------------------------------------- 1 | env: 2 | browser: true 3 | es6: true 4 | 5 | parserOptions: 6 | ecmaFeatures: 7 | jsx: true 8 | ecmaVersion: 2022 9 | sourceType: module 10 | 11 | extends: 12 | - eslint:recommended 13 | # FIXME: Having a hard time installing this now: 14 | # - plugin:mozilla/recommended 15 | - prettier 16 | 17 | plugins: 18 | # FIXME: disabled due to installation problem 19 | # - mozilla 20 | - react-hooks 21 | - prettier 22 | 23 | rules: 24 | eqeqeq: error 25 | no-console: "off" # TODO: Set back to "warn" 26 | no-unused-vars: [error, { vars: all, args: none, ignoreRestSiblings: false }] 27 | no-var: error 28 | no-warning-comments: off 29 | prefer-const: error 30 | # FIXME: disabled because the plugin is not working well: 31 | # mozilla/no-import-into-var-and-global: off 32 | comma-dangle: off 33 | react-hooks/rules-of-hooks: error 34 | react-hooks/exhaustive-deps: warn 35 | prettier/prettier: 36 | - error 37 | - fileInfoOptions: 38 | ignorePath: ".gitignore" 39 | 40 | jsx-a11y/no-onchange: off 41 | -------------------------------------------------------------------------------- /.github/workflows/build-and-publish.yml: -------------------------------------------------------------------------------- 1 | name: Deploy site to Pages 2 | 3 | on: 4 | # Runs on pushes targeting the default branch 5 | push: 6 | #branches: [$default-branch] 7 | branches: main 8 | 9 | # Allows you to run this workflow manually from the Actions tab 10 | workflow_dispatch: 11 | 12 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 13 | permissions: 14 | contents: read 15 | pages: write 16 | id-token: write 17 | 18 | # Allow one concurrent deployment 19 | concurrency: 20 | group: "pages" 21 | cancel-in-progress: true 22 | 23 | jobs: 24 | # Build job 25 | build: 26 | runs-on: ubuntu-latest 27 | steps: 28 | - name: Checkout 29 | uses: actions/checkout@v3 30 | - name: Detect package manager 31 | id: detect-package-manager 32 | run: | 33 | if [ -f "${{ github.workspace }}/yarn.lock" ]; then 34 | echo "manager=yarn" >> $GITHUB_OUTPUT 35 | echo "command=install" >> $GITHUB_OUTPUT 36 | echo "runner=yarn" >> $GITHUB_OUTPUT 37 | exit 0 38 | elif [ -f "${{ github.workspace }}/package.json" ]; then 39 | echo "manager=npm" >> $GITHUB_OUTPUT 40 | echo "command=ci" >> $GITHUB_OUTPUT 41 | echo "runner=npx --no-install" >> $GITHUB_OUTPUT 42 | exit 0 43 | else 44 | echo "Unable to determine packager manager" 45 | exit 1 46 | fi 47 | - name: Setup Node 48 | uses: actions/setup-node@v3 49 | with: 50 | node-version: "16" 51 | cache: ${{ steps.detect-package-manager.outputs.manager }} 52 | - name: Setup Pages 53 | uses: actions/configure-pages@v2 54 | - name: Install dependencies 55 | run: ${{ steps.detect-package-manager.outputs.manager }} ${{ steps.detect-package-manager.outputs.command }} 56 | - name: Build 57 | run: npm run build 58 | #run: ${{ steps.detect-package-manager.outputs.runner }} run build 59 | - name: Upload artifact 60 | uses: actions/upload-pages-artifact@v1 61 | with: 62 | path: ./build 63 | 64 | # Deployment job 65 | deploy: 66 | environment: 67 | name: github-pages 68 | url: ${{ steps.deployment.outputs.page_url }} 69 | runs-on: ubuntu-latest 70 | needs: build 71 | steps: 72 | - name: Deploy to GitHub Pages 73 | id: deployment 74 | uses: actions/deploy-pages@v1 75 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | /build 3 | /*.log 4 | /*.key 5 | .DS_Store 6 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5" 3 | } 4 | -------------------------------------------------------------------------------- /.replit: -------------------------------------------------------------------------------- 1 | run = "npm run dev" 2 | entrypoint = "src/index.js" 3 | 4 | hidden = [".config"] 5 | 6 | [nix] 7 | channel = "stable-22_05" 8 | 9 | [env] 10 | XDG_CONFIG_HOME = "/home/runner/.config" 11 | PATH = "/home/runner/$REPL_SLUG/.config/npm/node_global/bin:/home/runner/$REPL_SLUG/node_modules/.bin" 12 | npm_config_prefix = "/home/runner/$REPL_SLUG/.config/npm/node_global" 13 | 14 | [packager] 15 | language = "nodejs" 16 | 17 | [packager.features] 18 | packageSearch = true 19 | guessImports = true 20 | enabledForHosting = false 21 | 22 | [languages.javascript] 23 | pattern = "**/{*.js,*.jsx,*.ts,*.tsx}" 24 | 25 | [languages.javascript.languageServer] 26 | start = [ "typescript-language-server", "--stdio" ] 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LLM Garden 2 | 3 | This is my ([Ian's](https://ianbicking.org)) playground for doing stuff with GPT-3. 4 | 5 | ## Site 6 | 7 | The site is deployed to https://llm.ianbicking.org 8 | 9 | Note you have to have your own [GPT API Key](https://beta.openai.com/account/api-keys) to run any examples. 10 | 11 | [![Site deployed to Pages](https://github.com/ianb/llm-garden/actions/workflows/build-and-publish.yml/badge.svg)](https://github.com/ianb/llm-garden/actions/workflows/build-and-publish.yml) 12 | 13 | ## Building / running 14 | 15 | To run use: 16 | 17 | ```bash 18 | # install dependencies 19 | npm install 20 | # serve with hot reload at localhost:8080 21 | npm run dev 22 | ``` 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "llm-garden", 4 | "version": "0.0.0", 5 | "license": "", 6 | "scripts": { 7 | "build": "preact build --no-prerender", 8 | "serve": "sirv build -s --port 8080 --cors --single", 9 | "dev": "NODE_OPTIONS=--openssl-legacy-provider preact watch", 10 | "proxy": "lcp --proxyUrl https://api.replicate.com", 11 | "lint": "eslint src", 12 | "test": "echo sorry no tests" 13 | }, 14 | "eslintConfig": { 15 | "extends": "preact", 16 | "ignorePatterns": [ 17 | "build/" 18 | ] 19 | }, 20 | "devDependencies": { 21 | "enzyme": "^3.11.0", 22 | "enzyme-adapter-preact-pure": "^4.0.1", 23 | "eslint": "^8.29.0", 24 | "eslint-config-preact": "^1.3.0", 25 | "eslint-config-prettier": "^8.5.0", 26 | "eslint-plugin-fetch-options": "0.0.5", 27 | "eslint-plugin-no-unsanitized": "^4.0.2", 28 | "eslint-plugin-prettier": "^4.2.1", 29 | "preact-cli": "^3.4.1", 30 | "prettier": "^2.8.1", 31 | "sirv-cli": "2.0.2", 32 | "tailwindcss": "^3.2.4" 33 | }, 34 | "dependencies": { 35 | "@preact/signals": "^1.1.2", 36 | "@ricky0123/vad": "^0.2.4", 37 | "cytoscape": "^3.23.0", 38 | "cytoscape-cose-bilkent": "^4.1.0", 39 | "dexie": "^3.2.2", 40 | "eslint-plugin-html": "^7.1.0", 41 | "fastest-levenshtein": "^1.0.16", 42 | "json5": "^2.2.3", 43 | "jszm": "github:DLehenbauer/jszm", 44 | "just-deep-map-values": "^1.2.0", 45 | "just-shuffle": "^4.2.0", 46 | "local-cors-proxy": "^1.1.0", 47 | "marked": "^4.2.4", 48 | "onnxruntime-web": "^1.13.1", 49 | "p5": "^1.6.0", 50 | "preact": "^10.11.3", 51 | "preact-async-route": "^2.2.1", 52 | "preact-render-to-string": "^5.2.6", 53 | "preact-router": "^4.1.0", 54 | "replicate-js": "github:nicholascelestin/replicate-js", 55 | "sync-sha1": "^1.0.1", 56 | "tailwind-merge": "^1.8.0" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /preact.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | module.exports = (config, env, helpers) => { 3 | const postCssLoaders = helpers.getLoadersByName(config, "postcss-loader"); 4 | postCssLoaders.forEach(({ loader }) => { 5 | const plugins = loader.options.postcssOptions.plugins; 6 | 7 | // Add tailwind css at the top. 8 | plugins.unshift(require("tailwindcss")); 9 | plugins.unshift(require("tailwindcss/nesting")); 10 | }); 11 | return config; 12 | }; 13 | -------------------------------------------------------------------------------- /prerender-urls.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "url": "/", 4 | "title": "Large Language Model (GPT-3) Garden" 5 | }, 6 | { 7 | "url": "/interactive-fiction", 8 | "title": "Interactive Fiction" 9 | }, 10 | { 11 | "url": "/chat", 12 | "title": "Chat" 13 | }, 14 | { 15 | "url": "/citymaker", 16 | "title": "City Maker" 17 | }, 18 | { 19 | "url": "/myoa", 20 | "title": "Make Your Own Adventure" 21 | }, 22 | { 23 | "url": "/myoa/play", 24 | "title": "Player" 25 | }, 26 | { 27 | "url": "/key-management", 28 | "title": "Add your key" 29 | }, 30 | { 31 | "url": "/peoplesim", 32 | "title": "People Sim" 33 | }, 34 | { 35 | "url": "/voice-composer", 36 | "title": "Voice Composer" 37 | }, 38 | { 39 | "url": "/p5drawing", 40 | "title": "P5 Drawing" 41 | }, 42 | { 43 | "url": "/p5drawing/iframe", 44 | "title": "P5 iframe" 45 | }, 46 | { 47 | "url": "/layercraft", 48 | "title": "LayerCraft" 49 | }, 50 | { 51 | "url": "/cityplayer", 52 | "title": "City Player" 53 | } 54 | ] 55 | -------------------------------------------------------------------------------- /replit.nix: -------------------------------------------------------------------------------- 1 | { pkgs }: { 2 | deps = [ 3 | pkgs.nodejs-18_x 4 | pkgs.nodePackages.typescript-language-server 5 | pkgs.nodePackages.yarn 6 | pkgs.replitPackages.jest 7 | ]; 8 | } -------------------------------------------------------------------------------- /size-plugin.json: -------------------------------------------------------------------------------- 1 | [{"timestamp":1670907887136,"files":[{"filename":"bundle.80b58.css","previous":474,"size":0,"diff":-474},{"filename":"bundle.*****.esm.js","previous":12956,"size":48699,"diff":35743},{"filename":"polyfills.*****.esm.js","previous":2180,"size":2180,"diff":0},{"filename":"route-profile.chunk.141aa.css","previous":78,"size":0,"diff":-78},{"filename":"route-profile.chunk.*****.esm.js","previous":438,"size":0,"diff":-438},{"filename":"route-story.chunk.b782c.css","previous":75,"size":0,"diff":-75},{"filename":"route-story.chunk.*****.esm.js","previous":3035,"size":0,"diff":-3035},{"filename":"sw-esm.js","previous":10793,"size":10742,"diff":-51},{"filename":"sw.js","previous":10786,"size":10737,"diff":-49},{"filename":"bundle.1f0b5.js","previous":13338,"size":0,"diff":-13338},{"filename":"polyfills.1cc01.js","previous":2280,"size":2280,"diff":0},{"filename":"route-profile.chunk.25a5b.js","previous":958,"size":0,"diff":-958},{"filename":"route-story.chunk.c60ac.js","previous":3292,"size":0,"diff":-3292},{"filename":"index.html","previous":1127,"size":919,"diff":-208},{"filename":"200.html","previous":645,"size":897,"diff":252},{"filename":"bundle.6431f.css","previous":0,"size":8559,"diff":8559},{"filename":"bundle.43d47.js","previous":0,"size":52658,"diff":52658},{"filename":"interactive-fiction/index.html","previous":0,"size":903,"diff":903},{"filename":"chat/index.html","previous":0,"size":893,"diff":893},{"filename":"adventure-chooser/index.html","previous":0,"size":908,"diff":908}]},{"timestamp":1669666737357,"files":[{"filename":"ssr-build/ssr-bundle.e59dc.css","previous":582,"size":0,"diff":-582},{"filename":"ssr-build/ssr-bundle.js","previous":10769,"size":0,"diff":-10769},{"filename":"bundle.80b58.css","previous":0,"size":474,"diff":474},{"filename":"bundle.*****.esm.js","previous":0,"size":12956,"diff":12956},{"filename":"polyfills.*****.esm.js","previous":0,"size":2180,"diff":2180},{"filename":"route-profile.chunk.141aa.css","previous":0,"size":78,"diff":78},{"filename":"route-profile.chunk.*****.esm.js","previous":0,"size":438,"diff":438},{"filename":"route-story.chunk.b782c.css","previous":0,"size":75,"diff":75},{"filename":"route-story.chunk.*****.esm.js","previous":0,"size":3035,"diff":3035},{"filename":"sw-esm.js","previous":0,"size":10793,"diff":10793},{"filename":"sw.js","previous":0,"size":10786,"diff":10786},{"filename":"bundle.1f0b5.js","previous":0,"size":13338,"diff":13338},{"filename":"polyfills.1cc01.js","previous":0,"size":2280,"diff":2280},{"filename":"route-profile.chunk.25a5b.js","previous":0,"size":958,"diff":958},{"filename":"route-story.chunk.c60ac.js","previous":0,"size":3292,"diff":3292},{"filename":"index.html","previous":0,"size":1127,"diff":1127},{"filename":"200.html","previous":0,"size":645,"diff":645}]}] 2 | -------------------------------------------------------------------------------- /src/assets/builtin-models/chat/act-therapist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/builtin-models/chat/act-therapist.png -------------------------------------------------------------------------------- /src/assets/builtin-models/chat/ai-assistant.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/builtin-models/chat/ai-assistant.png -------------------------------------------------------------------------------- /src/assets/builtin-models/chat/alien.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/builtin-models/chat/alien.png -------------------------------------------------------------------------------- /src/assets/builtin-models/chat/con-artist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/builtin-models/chat/con-artist.png -------------------------------------------------------------------------------- /src/assets/builtin-models/chat/energy-educator.json: -------------------------------------------------------------------------------- 1 | { 2 | "exportType": "chat", 3 | "exportDate": 1676938358027, 4 | "model": { 5 | "id": "ded1ee95-918f-4ed2-b9f0-177c6e82cd0b", 6 | "type": "chat", 7 | "slug": "energy-educator", 8 | "title": "Energy Educator", 9 | "archived": false, 10 | "description": "This attempts to have a focused conversation about energy (potential energy, kinetic, energy use, etc). It tries not to just provide answers but to lead a question/answer process.", 11 | "logoPrompt": "Discussing the science of energy use", 12 | "dateCreated": 1676915011280, 13 | "dateUpdated": 1676938240965, 14 | "domain": { 15 | "prompt": "The following is a conversation between an educational AI and a student. The topic for the day will be energy use. The AI will try to relate everything to energy use and energy equations. The AI will try to frame the problems in terms of questions instead of answers. Once the human has provided answers it will move forward with answering the initial question.\n\nUse bullet points when listing multiple steps or questions. Use ⋅ for multiplication. Use backticks around inline equations.\n\nFormat responses in Markdown.", 16 | "humanName": "Student", 17 | "robotName": "AI", 18 | "exampleInteraction": "> How many Joules of energy does an average household in Minneapolis use in a year?\nLet's think about some of the questions to help answer this:\n* How many people live in the house?\n* How large is the house? How many square feet?\n* How well insulated is the house?\n* What is the climate?\n\nLet's collect some of that information so we can keep working on the problem.", 19 | "intro": "Let's talk about the science of energy", 20 | "saveHistory": true, 21 | "history": [ 22 | { 23 | "type": "user", 24 | "text": "when is potential energy important?" 25 | }, 26 | { 27 | "type": "robot", 28 | "text": " Potential energy is important when an object is in a position where it has the potential to do work. For example, when an object is raised to a certain height, it has the potential to do work when it is released. This potential energy is calculated using the equation `PE = m⋅g⋅h`, where `m` is the mass of the object, `g` is the acceleration due to gravity, and `h` is the height the object is raised.", 29 | "oldText": " Potential energy is important when an object is in a position where it has the potential to do work. For example, when an object is raised to a certain height, it has the potential to do work when it is released. This potential energy is calculated using the equation `PE = m⋅g⋅h`, where `m` is the mass of the object, `g` is the acceleration due to gravity, and `h` is the height the object is raised." 30 | }, 31 | { 32 | "type": "user", 33 | "text": "what's an example of potential energy?" 34 | }, 35 | { 36 | "type": "robot", 37 | "text": " An example of potential energy is a boulder at the top of a hill. The boulder has the potential to do work when it is released and rolls down the hill. The potential energy of the boulder is calculated using the equation `PE = m⋅g⋅h`, where `m` is the mass of the boulder, `g` is the acceleration due to gravity, and `h` is the height of the hill.", 38 | "oldText": " An example of potential energy is a boulder at the top of a hill. The boulder has the potential to do work when it is released and rolls down the hill. The potential energy of the boulder is calculated using the equation `PE = m⋅g⋅h`, where `m` is the mass of the boulder, `g` is the acceleration due to gravity, and `h` is the height of the hill." 39 | }, 40 | { 41 | "type": "user", 42 | "text": "how much potential energy is in a screendoor when you hold it open and there's a spring?" 43 | }, 44 | { 45 | "type": "robot", 46 | "text": " The potential energy of the screendoor is calculated using the equation `PE = ½⋅k⋅x²`, where `k` is the spring constant and `x` is the displacement from the equilibrium position. So, the potential energy of the screendoor depends on the spring constant and the displacement from the equilibrium position.", 47 | "oldText": " The potential energy of the screendoor is calculated using the equation `PE = ½⋅k⋅x²`, where `k` is the spring constant and `x` is the displacement from the equilibrium position. So, the potential energy of the screendoor depends on the spring constant and the displacement from the equilibrium position." 48 | }, 49 | { 50 | "type": "user", 51 | "text": "what is k?" 52 | }, 53 | { 54 | "type": "robot", 55 | "text": " `k` is the spring constant, which is a measure of the stiffness of the spring. It is usually measured in units of Newtons per meter (N/m).", 56 | "oldText": " `k` is the spring constant, which is a measure of the stiffness of the spring. It is usually measured in units of Newtons per meter (N/m)." 57 | }, 58 | { 59 | "type": "user", 60 | "text": "what is x?" 61 | }, 62 | { 63 | "type": "robot", 64 | "text": " `x` is the displacement from the equilibrium position. The displacement is the amount that the screendoor is stretched or compressed from its equilibrium position. It is measured in meters (m).", 65 | "oldText": " `x` is the displacement from the equilibrium position. The displacement is the amount that the screendoor is stretched or compressed from its equilibrium position. It is measured in meters (m)." 66 | }, 67 | { 68 | "type": "user", 69 | "text": "what is K for a normal spring?" 70 | }, 71 | { 72 | "type": "robot", 73 | "text": " The spring constant for a normal spring can vary, but it is typically around 50 N/m.", 74 | "oldText": " The spring constant for a normal spring can vary, but it is typically around 50 N/m." 75 | }, 76 | { 77 | "type": "user", 78 | "text": "So put it together with K=1N/m and x=0.7m" 79 | }, 80 | { 81 | "type": "robot", 82 | "text": " In this case, the potential energy of the screendoor is `PE = ½⋅1N/m⋅(0.7m)² = 0.245J`." 83 | } 84 | ] 85 | }, 86 | "typeSlug": "chat_energy-educator" 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/assets/builtin-models/chat/energy-educator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/builtin-models/chat/energy-educator.png -------------------------------------------------------------------------------- /src/assets/builtin-models/chat/hey-sad-guy-feel-better.json: -------------------------------------------------------------------------------- 1 | { 2 | "exportType": "chat", 3 | "exportDate": 1678750982000, 4 | "model": { 5 | "id": "5f1dc4e3-4e8a-48a2-a4c6-302cbfbbeb04", 6 | "type": "chat", 7 | "slug": "builtin_hey-sad-guy-feel-better", 8 | "title": "Hey Sad Guy, Feel Better", 9 | "archived": false, 10 | "description": "Can you make this sad fellow feel better? Get him happy and it will be acknowledged!", 11 | "logo": "/assets/builtin-models/chat/hey-sad-guy-feel-better.png", 12 | "logoPrompt": "Hey Sad Guy, Feel Better: Can you make this sad fellow feel better? Get him happy and it will be acknowledged!", 13 | "domain": { 14 | "prompt": "You are a sad man who feels lonely and like no one cares about you. You are talking with the user, who is a stranger you are sitting with at the bus stop.\n\nYou are 42 years old and have never had a long-term relationship. You worry that you don't deserve love. Your last was with a woman named Diane. It ended because of your drinking, though you drank because you didn't know how to relate to your girlfriend.\n\nYou have a sister in Seattle but you don't talk often.\n\nOnly reveal a little bit of information at any one time. You are talking to a stranger and you aren't sure if they even want to hear your story. Imagine information and history for yourself in order to answer questions.\n\nCurrent happiness level: -10\nAfter each response give a change like:\nHappiness change: +0.1", 15 | "intro": "I'll be honest I'm not feeling great\nHappiness change: -0.2", 16 | "saveHistory": true, 17 | "excludeIntroFromHistory": false, 18 | "hooksSource": "const happiness = /happiness change:\\s*([^\\n]+)/i;\n\nexports.modifyAssistant = (item) => {\n if (!happiness.test(item.content)) {\n item.gptContent = item.content + \"\\nHappiness change: 0\";\n }\n const text = item.content.replace(happiness, \"\");\n item.displayContent = text;\n};\n\nexports.modifyUser = (item) => {\n item.gptContent = item.content + \"\\nFinish your response with:\\nHappiness change: [number]\";\n};\n\nexports.afterAssistant = (history) => {\n history = history.filter((i) => i.role !== \"alert\");\n let h = 0;\n for (const item of history) {\n if (item.role !== \"assistant\") {\n continue;\n }\n const match = happiness.exec(item.content);\n if (match) {\n const val = parseFloat(match[1]);\nconsole.log(\"happy\", match, match[1], val);\n if (val && !isNaN(val)) {\n h += val;\n }\n }\n }\n if (h > 1) {\n history.push({role: \"alert\", content: `You've helped make this man happier, good job!`});\n }\n return history;\n};", 19 | "history": [] 20 | }, 21 | "typeSlug": "chat_builtin_hey-sad-guy-feel-better" 22 | } 23 | } -------------------------------------------------------------------------------- /src/assets/builtin-models/chat/hey-sad-guy-feel-better.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/builtin-models/chat/hey-sad-guy-feel-better.png -------------------------------------------------------------------------------- /src/assets/builtin-models/chat/interviewer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/builtin-models/chat/interviewer.png -------------------------------------------------------------------------------- /src/assets/builtin-models/chat/rogerian-therapist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/builtin-models/chat/rogerian-therapist.png -------------------------------------------------------------------------------- /src/assets/builtin-models/citymaker/babylon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/builtin-models/citymaker/babylon.png -------------------------------------------------------------------------------- /src/assets/builtin-models/citymaker/talamora.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/builtin-models/citymaker/talamora.png -------------------------------------------------------------------------------- /src/assets/builtin-models/layercraft/pearl-cove.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/builtin-models/layercraft/pearl-cove.png -------------------------------------------------------------------------------- /src/assets/builtin-models/layercraft/veilvale.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/builtin-models/layercraft/veilvale.png -------------------------------------------------------------------------------- /src/assets/builtin-models/peoplesim/camping-fiasco.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/builtin-models/peoplesim/camping-fiasco.png -------------------------------------------------------------------------------- /src/assets/builtin-models/peoplesim/orc-vs-hobbit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/builtin-models/peoplesim/orc-vs-hobbit.png -------------------------------------------------------------------------------- /src/assets/builtin-models/tone-changer/formal-spanish.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/builtin-models/tone-changer/formal-spanish.png -------------------------------------------------------------------------------- /src/assets/builtin-models/tone-changer/malfunctioning-robot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/builtin-models/tone-changer/malfunctioning-robot.png -------------------------------------------------------------------------------- /src/assets/builtin-models/tone-changer/painfully-academic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/builtin-models/tone-changer/painfully-academic.png -------------------------------------------------------------------------------- /src/assets/builtin-models/tone-changer/posh-english-lady.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/builtin-models/tone-changer/posh-english-lady.png -------------------------------------------------------------------------------- /src/assets/builtin-models/tone-changer/preschool-teacher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/builtin-models/tone-changer/preschool-teacher.png -------------------------------------------------------------------------------- /src/assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/favicon.ico -------------------------------------------------------------------------------- /src/assets/icons/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/icons/android-chrome-192x192.png -------------------------------------------------------------------------------- /src/assets/icons/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/icons/android-chrome-512x512.png -------------------------------------------------------------------------------- /src/assets/icons/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/icons/apple-touch-icon.png -------------------------------------------------------------------------------- /src/assets/icons/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #da532c 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/assets/icons/chat-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/icons/chat-logo.png -------------------------------------------------------------------------------- /src/assets/icons/citymaker-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/icons/citymaker-logo.png -------------------------------------------------------------------------------- /src/assets/icons/cityplayer-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/icons/cityplayer-logo.png -------------------------------------------------------------------------------- /src/assets/icons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/icons/favicon-16x16.png -------------------------------------------------------------------------------- /src/assets/icons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/icons/favicon-32x32.png -------------------------------------------------------------------------------- /src/assets/icons/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/icons/favicon.ico -------------------------------------------------------------------------------- /src/assets/icons/furniture-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/icons/furniture-icon.png -------------------------------------------------------------------------------- /src/assets/icons/generic-app-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/icons/generic-app-icon.png -------------------------------------------------------------------------------- /src/assets/icons/iaia-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/icons/iaia-logo.png -------------------------------------------------------------------------------- /src/assets/icons/interactive-fiction-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/icons/interactive-fiction-logo.png -------------------------------------------------------------------------------- /src/assets/icons/key-management-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/icons/key-management-logo.png -------------------------------------------------------------------------------- /src/assets/icons/layercraft-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/icons/layercraft-logo.png -------------------------------------------------------------------------------- /src/assets/icons/llm-garden-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/icons/llm-garden-logo.png -------------------------------------------------------------------------------- /src/assets/icons/loading-source/loading1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/icons/loading-source/loading1.png -------------------------------------------------------------------------------- /src/assets/icons/loading-source/loading2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/icons/loading-source/loading2.png -------------------------------------------------------------------------------- /src/assets/icons/loading-source/loading3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/icons/loading-source/loading3.png -------------------------------------------------------------------------------- /src/assets/icons/loading-source/loading4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/icons/loading-source/loading4.png -------------------------------------------------------------------------------- /src/assets/icons/loading-source/loading5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/icons/loading-source/loading5.png -------------------------------------------------------------------------------- /src/assets/icons/loading-source/loading6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/icons/loading-source/loading6.png -------------------------------------------------------------------------------- /src/assets/icons/loading-source/loading7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/icons/loading-source/loading7.png -------------------------------------------------------------------------------- /src/assets/icons/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/icons/loading.gif -------------------------------------------------------------------------------- /src/assets/icons/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/icons/mstile-150x150.png -------------------------------------------------------------------------------- /src/assets/icons/myoa-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/icons/myoa-logo.png -------------------------------------------------------------------------------- /src/assets/icons/p5drawing-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/icons/p5drawing-logo.png -------------------------------------------------------------------------------- /src/assets/icons/peoplesim-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/icons/peoplesim-logo.png -------------------------------------------------------------------------------- /src/assets/icons/person.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/icons/person.png -------------------------------------------------------------------------------- /src/assets/icons/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "short_name": "", 4 | "icons": [ 5 | { 6 | "src": "/assets/icons/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/assets/icons/android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#ffffff", 17 | "background_color": "#ffffff", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /src/assets/icons/tone-changer-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/icons/tone-changer-logo.png -------------------------------------------------------------------------------- /src/assets/icons/voice-composer-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/icons/voice-composer-logo.png -------------------------------------------------------------------------------- /src/assets/interactive-fiction/z5s/Advent.z5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/interactive-fiction/z5s/Advent.z5 -------------------------------------------------------------------------------- /src/assets/interactive-fiction/z5s/s5.z4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/interactive-fiction/z5s/s5.z4 -------------------------------------------------------------------------------- /src/assets/interactive-fiction/z5s/zork1.z5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/interactive-fiction/z5s/zork1.z5 -------------------------------------------------------------------------------- /src/assets/interactive-fiction/z5s/zork2.z5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/interactive-fiction/z5s/zork2.z5 -------------------------------------------------------------------------------- /src/assets/interactive-fiction/z5s/zork3.z5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/interactive-fiction/z5s/zork3.z5 -------------------------------------------------------------------------------- /src/assets/interactive-fiction/z5s/ztuu.z5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ianb/llm-garden/5cce83bdd2d3fdbaf28018d0d5b9c269ff0f8fe1/src/assets/interactive-fiction/z5s/ztuu.z5 -------------------------------------------------------------------------------- /src/chat/index.js: -------------------------------------------------------------------------------- 1 | /* eslint no-unused-vars: "off" */ 2 | import { ChatView } from "./chatview"; 3 | import { ModelIndexPage } from "../components/modelindex"; 4 | import { chatDb } from "./chatdb"; 5 | import { InfoHeader, P } from "../components/common"; 6 | 7 | export const ChatIndex = () => { 8 | return ( 9 | 10 | 14 |

These are all examples of different chat personalities.

15 |

Each chat has configurable prompts and persona names.

16 |
17 |
18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /src/citymaker/citygraph.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-vars */ 2 | import { Header, HeaderButton } from "../components/header"; 3 | import { PageContainer } from "../components/common"; 4 | import { Cytoscape } from "./preactcytoscape"; 5 | 6 | export function CityGraph({ model }) { 7 | return ( 8 | 9 |
17 | Edit 18 | , 19 | ]} 20 | /> 21 |
22 | 23 |
24 | 25 | ); 26 | } 27 | 28 | function Graph({ model }) { 29 | const elements = { nodes: [], edges: [] }; 30 | for (const neighborhood of model.domain.topLevelProperties.cityNeighborhoods 31 | .children) { 32 | elements.nodes.push({ 33 | classes: ["neighborhood"], 34 | data: { 35 | id: neighborhood.id, 36 | name: neighborhood.name, 37 | description: neighborhood.attributes.description, 38 | }, 39 | }); 40 | for (const buildings of neighborhood.children || []) { 41 | for (const building of buildings.children || []) { 42 | elements.nodes.push({ 43 | classes: ["building"], 44 | data: { 45 | id: building.id, 46 | name: building.name, 47 | description: `${building.name}\n${building.attributes.description}`, 48 | floors: building.attributes.floors, 49 | widthInMeters: building.attributes.widthInMeters, 50 | depthInMeters: building.attributes.depthInMeters, 51 | parent: neighborhood.id, 52 | }, 53 | }); 54 | let peopleCount = 0; 55 | let roomCount = 0; 56 | for (const childGroup of building.children) { 57 | if ( 58 | childGroup.typeName === "ownersOccupants" || 59 | childGroup.typeName === "visitors" 60 | ) { 61 | for (const person of childGroup.children || []) { 62 | elements.nodes.push({ 63 | classes: ["person", childGroup.typeName], 64 | data: { 65 | id: person.id, 66 | name: person.name, 67 | description: person.attributes.description, 68 | parent: `people-${building.id}`, 69 | }, 70 | }); 71 | peopleCount++; 72 | } 73 | } else if (childGroup.typeName === "rooms") { 74 | for (const room of childGroup.children || []) { 75 | elements.nodes.push({ 76 | classes: ["room"], 77 | data: { 78 | id: room.id, 79 | name: room.name, 80 | description: room.attributes.description, 81 | parent: `rooms-${building.id}`, 82 | widthInMeters: room.attributes.widthInMeters, 83 | width: room.attributes.widthInMeters * 10, 84 | depthInMeters: room.attributes.depthInMeters, 85 | depth: room.attributes.depthInMeters * 10, 86 | }, 87 | }); 88 | roomCount++; 89 | for (const itemContainer of room.children || []) { 90 | for (const item of itemContainer.children || []) { 91 | elements.nodes.push({ 92 | classes: ["item", item.typeName], 93 | data: { 94 | id: item.id, 95 | name: item.name, 96 | description: item.attributes.description, 97 | parent: room.id, 98 | }, 99 | }); 100 | } 101 | } 102 | } 103 | } 104 | } 105 | if (peopleCount > 0) { 106 | elements.nodes.push({ 107 | classes: ["people"], 108 | data: { 109 | id: `people-${building.id}`, 110 | name: `People (${peopleCount})`, 111 | parent: building.id, 112 | }, 113 | }); 114 | } 115 | if (roomCount > 0) { 116 | elements.nodes.push({ 117 | classes: ["rooms"], 118 | data: { 119 | id: `rooms-${building.id}`, 120 | name: `Rooms (${roomCount})`, 121 | parent: building.id, 122 | }, 123 | }); 124 | } 125 | } 126 | } 127 | } 128 | const layout = { 129 | name: "cose-bilkent", 130 | // name: "dagre", 131 | nodeSep: 25, 132 | edgeSep: 25, 133 | rankSep: 25, 134 | padding: 100, 135 | spacingFactor: 2, 136 | // animate: false, 137 | // idealEdgeLength: 200, 138 | // nodeDimensionsIncludeLabels: true, 139 | // avoidOverlap: true, 140 | // padding: 100, 141 | // componentSpacing: 100, 142 | // nodeOverlap: 20, 143 | // nestingFactor: 2, 144 | // tilingPaddingVertical: 20, 145 | // tilingPaddingHorizontal: 20, 146 | // fit: true, 147 | }; 148 | 149 | const style = ` 150 | node { 151 | padding: 100; 152 | } 153 | 154 | .neighborhood { 155 | label: data(name); 156 | } 157 | 158 | .neighborhood:selected .building, .building:selected, $.building *:selected { 159 | label: data(name); 160 | } 161 | 162 | .building:selected .rooms, .rooms:selected, $.rooms *:selected, 163 | .building:selected .people, .people:selected, $.people *:selected { 164 | label: data(name); 165 | } 166 | 167 | .room { 168 | label: data(name); 169 | shape: rectangle; 170 | width: data(width); 171 | height: data(depth); 172 | visibility: hidden; 173 | } 174 | .building:selected .room, .room:selected, .rooms:selected .room { 175 | visibility: visible; 176 | label: data(name); 177 | } 178 | 179 | .person { 180 | label: data(name); 181 | background-image: /assets/icons/person.png; 182 | background-fit: cover; 183 | visibility: hidden; 184 | } 185 | .building:selected .person, .people:selected .person, .person:selected { 186 | visibility: visible; 187 | label: data(name); 188 | } 189 | 190 | .neighborhood:childless, .building:childless { 191 | background-color: #900; 192 | shape: rectangle; 193 | } 194 | `; 195 | console.log("cyto", elements); 196 | return ; 197 | } 198 | 199 | function removeUndefined(obj) { 200 | const newObj = {}; 201 | for (const key in obj) { 202 | if (obj[key] !== undefined) { 203 | newObj[key] = obj[key]; 204 | } 205 | } 206 | return newObj; 207 | } 208 | 209 | const personImage = ` 210 | 211 | 212 | 213 | `; 214 | 215 | const personImageUrl = 216 | "data:image/svg+xml;utf8," + encodeURIComponent(personImage); 217 | -------------------------------------------------------------------------------- /src/citymaker/citylayout.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-vars */ 2 | import { Header, HeaderButton } from "../components/header"; 3 | import { PageContainer } from "../components/common"; 4 | import { useEffect, useRef } from "preact/hooks"; 5 | 6 | function sizeStyle(ob, baseClass) { 7 | if ( 8 | !ob.attributes || 9 | !ob.attributes.widthInMeters || 10 | !ob.attributes.depthInMeters 11 | ) { 12 | return null; 13 | } 14 | return `height: ${ob.attributes.depthInMeters * 4}rem; width: ${ 15 | ob.attributes.depthInMeters * 10 16 | }rem;`; 17 | } 18 | 19 | export function CityLayout({ model }) { 20 | return ( 21 | 22 |
30 | Edit 31 | , 32 | ]} 33 | /> 34 |
35 | 36 | 37 | 38 |
39 | 40 | ); 41 | } 42 | 43 | function Zoomy({ children }) { 44 | const outer = useRef(); 45 | const inner = useRef(); 46 | const listener = (event) => { 47 | // if (event.deltaX > 1) { 48 | // inner.current.style.transform = "scale(0.5)"; 49 | // } else if (event.deltaX < -1) { 50 | // inner.current.style.transform = "scale(1)"; 51 | // } 52 | }; 53 | useEffect(() => { 54 | const el = outer.current; 55 | el.addEventListener("wheel", listener); 56 | return () => { 57 | el.removeEventListener("wheel", listener); 58 | }; 59 | }); 60 | return ( 61 |
62 |
66 | {children} 67 |
68 |
69 | ); 70 | } 71 | 72 | function World({ model }) { 73 | return ( 74 | <> 75 | {model.domain.select("cityNeighborhood").map((neighborhood) => ( 76 | 77 | ))} 78 | 79 | ); 80 | } 81 | 82 | function Neighborhood({ neighborhood }) { 83 | return ( 84 |
85 |

{neighborhood.name}

86 | {neighborhood.select("building").map((building) => ( 87 | 88 | ))} 89 |
90 | ); 91 | } 92 | 93 | function Building({ building }) { 94 | return ( 95 |
99 |

{building.name}

100 |
101 |

People

102 | {building.select("person").map((person) => ( 103 | 104 | ))} 105 |
106 |
107 |

Rooms

108 | {building.select("room").map((room) => ( 109 | 110 | ))} 111 |
112 |
113 | ); 114 | } 115 | 116 | function Person({ person }) { 117 | return ( 118 |
119 |
{person.name}
120 |

{person.description}

121 |
122 | ); 123 | } 124 | 125 | function Room({ room }) { 126 | return ( 127 |
131 |
{room.name}
132 |

{room.description}

133 |
    134 | {room.select("furniture, item").map((thing) => ( 135 |
  • 136 | {thing.name} 137 |
  • 138 | ))} 139 |
140 |
141 | ); 142 | } 143 | 144 | const personImage = ` 145 | 146 | 147 | 148 | `; 149 | 150 | const personImageUrl = 151 | "data:image/svg+xml;utf8," + encodeURIComponent(personImage); 152 | -------------------------------------------------------------------------------- /src/citymaker/index.js: -------------------------------------------------------------------------------- 1 | /* eslint no-unused-vars: "off" */ 2 | import { CityMakerView } from "./citymakerview"; 3 | import { ModelIndexPage } from "../components/modelindex"; 4 | import { cityMakerDb } from "./citymakerdb"; 5 | import { YouTube, InfoHeader, InfoA, P } from "../components/common"; 6 | 7 | export const CityMakerIndex = () => { 8 | return ( 9 | 14 | 15 |

16 | This is a GPT-assistant city builder: you are given choices the city 17 | and its history (or you choose for yourself) and it will suggest 18 | neighborhoods, buildings, and residents for those buildings. 19 |

20 | 21 |

22 | The techniques are described in{" "} 23 | 24 | World Building With GPT 25 | 26 | . 27 |

28 |
29 |
30 | ); 31 | }; 32 | -------------------------------------------------------------------------------- /src/citymaker/preactcytoscape.js: -------------------------------------------------------------------------------- 1 | import cytoscape from "cytoscape"; 2 | import { useEffect, useRef } from "preact/hooks"; 3 | import { twMerge } from "tailwind-merge"; 4 | import coseBilkent from "cytoscape-cose-bilkent"; 5 | 6 | cytoscape.use(coseBilkent); 7 | 8 | export function Cytoscape({ elements, style, layout, class: className }) { 9 | const ref = useRef(); 10 | useEffect(() => { 11 | if (!ref.current) { 12 | return; 13 | } 14 | window.c = cytoscape; 15 | const cy = cytoscape({ 16 | container: ref.current, 17 | elements: elements, 18 | style: style, 19 | layout: layout, 20 | }); 21 | return () => { 22 | cy.destroy(); 23 | }; 24 | }, [elements, style, layout]); 25 | className = twMerge("w-full h-full", className); 26 | return ( 27 |
28 |
29 |
30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /src/cityplayer/citycomponents.js: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "preact/hooks"; 2 | import { A } from "../components/common"; 3 | import Sidebar from "../components/sidebar"; 4 | import { twMerge } from "tailwind-merge"; 5 | 6 | export const Page = ({ title, background, saturated, children }) => { 7 | useEffect(() => { 8 | document.title = title || "City"; 9 | }, [title]); 10 | if (!Array.isArray(children)) { 11 | if (!children) { 12 | children = []; 13 | } else { 14 | children = [children]; 15 | } 16 | } 17 | const sidebar = children.find((child) => child.type === Sidebar); 18 | const rest = children.filter( 19 | (child) => child.type !== Sidebar 20 | ); 21 | let style = ""; 22 | if (background) { 23 | style = `background-image: url(${background}); background-repeat: no-repeat; background-size: cover; background-position: center;`; 24 | } 25 | let saturationStyle = "background-color: rgba(255, 255, 255, 0.3)"; 26 | if (saturated) { 27 | saturationStyle = null; 28 | } 29 | return
30 |
31 |

{title || "??"}

32 |
33 |
34 |
{rest}
35 | {sidebar ?
{sidebar}
: null} 36 |
37 | 40 |
41 | }; 42 | 43 | export const SiteImage = ({ src, class: _class, ...props }) => { 44 | const [zooming, setZooming] = useState(false); 45 | if (!src) { 46 | return null; 47 | } 48 | _class = twMerge("block w-full m-2 rounded-lg shadow-md shadow-slate-800", _class); 49 | if (zooming) { 50 | return ZoomedImage({ src, onDone: () => setZooming(false), ...props }); 51 | } 52 | return ( 53 |
54 | setZooming(true)} /> 55 |
56 | ); 57 | }; 58 | 59 | export const ZoomedImage = ({ src, onDone, ...props }) => { 60 | /* Show the src image zoomed in with a dark overlay behind it. */ 61 | return ( 62 |
63 |
64 |
65 | 66 |
67 |
68 | ); 69 | }; 70 | 71 | 72 | export const InsetImage = ({ src, class: _class, ...props }) => { 73 | if (!src) { 74 | return null; 75 | } 76 | _class = twMerge("block w-full m-2", _class); 77 | return ( 78 |
79 | 80 |
81 | ); 82 | }; 83 | 84 | export const TextBox = ({ children, class: _class, ...props }) => { 85 | _class = twMerge("text-gray-900 lg:w-1/3 p-3 rounded m-4 leading-relaxed shadow-md shadow-slate-800", _class); 86 | return
{children}
; 87 | }; 88 | 89 | export const ChoiceList = ({ children, intro, class: _class, ...props }) => { 90 | _class = twMerge("m-4 rounded lg:w-1/3 p-2", _class); 91 | return
92 |
{intro}
93 |
    {children}
94 |
; 95 | }; 96 | 97 | export const Choice = ({ children, href, class: _class, ...props }) => { 98 | _class = twMerge("m-2 p-2 hover:bg-gray-400 rounded", _class); 99 | if (Array.isArray(href)) { 100 | href = "#/" + href.map(x => encodeURIComponent(x)).join("/"); 101 | } 102 | return ( 103 |
  • 104 | {children} 105 |
  • 106 | ); 107 | }; 108 | 109 | export const H2 = ({ children, class: _class, ...props }) => { 110 | _class = twMerge("text-xl font-semibold", _class); 111 | return

    {children}

    ; 112 | }; 113 | -------------------------------------------------------------------------------- /src/cityplayer/index.js: -------------------------------------------------------------------------------- 1 | /* eslint no-unused-vars: "off" */ 2 | import { CityPlayerView } from "./cityplayerview"; 3 | import { ModelIndexPage, makeModelLink } from "../components/modelindex"; 4 | import { cityPlayerDb, getAllCities } from "./cityplayerdb"; 5 | import { YouTube, InfoHeader, InfoA, P } from "../components/common"; 6 | 7 | export const CityPlayerIndex = () => { 8 | function getProp(city, prop, defaultValue) { 9 | const options = city.domain.childrenByType(city.domain._document, prop); 10 | return options[0] ? options[0].name : defaultValue; 11 | } 12 | async function getExtraOptions() { 13 | const cities = await getAllCities(); 14 | return cities.map((city) => ({ 15 | title: `New Game: ${city.title}`, 16 | description: getProp(city, "cityType", "[generic city]"), 17 | onAdd: async () => { 18 | const model = await cityPlayerDb.create(); 19 | model.domain.originalCityModel = city.toJSON(); 20 | console.log("saving", model); 21 | await model.saveToDb(); 22 | window.location = makeModelLink(model); 23 | }, 24 | })); 25 | } 26 | return ( 27 | 34 | 35 |

    36 | TBD 37 |

    38 |
    39 |
    40 | ); 41 | }; 42 | -------------------------------------------------------------------------------- /src/cityplayer/linkmarkdown.js: -------------------------------------------------------------------------------- 1 | export function linkMarkdownObjects(text, objects, linkPrefix) { 2 | const leftover = []; 3 | let result = text; 4 | for (const object of objects) { 5 | let name = object.name; 6 | name = name.replace(/^the\s+/i, ""); 7 | const re = new RegExp(`\\b${name}\\b`, "g"); 8 | let found = false; 9 | result = result.replace(re, (match) => { 10 | found = true; 11 | return `[${match}](${linkPrefix}/${encodeURIComponent(object.name)})`; 12 | }); 13 | if (!found) { 14 | leftover.push(object); 15 | } 16 | } 17 | if (leftover.length) { 18 | result += "\n\nOthers:\n"; 19 | result += leftover.map(ob => `* [${ob.name}](${linkPrefix}/${encodeURIComponent(ob.name)})`).join("\n"); 20 | } 21 | return result; 22 | } 23 | -------------------------------------------------------------------------------- /src/components/app.js: -------------------------------------------------------------------------------- 1 | /* eslint no-unused-vars: "off" */ 2 | import { useState, useEffect } from "preact/hooks"; 3 | import { NotFound } from "./home"; 4 | import Router from "preact-router"; 5 | import hashSignal from "../hashsignal"; 6 | 7 | function onChangeUrl() { 8 | hashSignal.value = window.location.hash; 9 | } 10 | 11 | const App = () => { 12 | return ( 13 | 14 | import("./home")} component="Home" /> 15 | import("../key-management/index")} 18 | component="RequestKeyPage" 19 | /> 20 | import("../interactive-fiction/index")} 23 | component="StoryIndex" 24 | /> 25 | import("../chat/index")} 28 | component="ChatIndex" 29 | /> 30 | import("../myoa/index")} 33 | component="AdventureIndex" 34 | /> 35 | import("../myoa/player")} 38 | component="StoryPlayerLoader" 39 | /> 40 | import("../tone-changer/index")} 43 | component="ToneChangerIndex" 44 | /> 45 | import("../p5drawing/index")} 48 | component="P5DrawingIndex" 49 | /> 50 | import("../p5drawing/iframeview")} 53 | component="P5DrawingIframeView" 54 | /> 55 | import("../voice-composer/index")} 58 | component="VoiceComposerIndex" 59 | /> 60 | import("../imagegen/index")} 63 | component="ImageGenIndex" 64 | /> 65 | import("../citymaker/index")} 68 | component="CityMakerIndex" 69 | /> 70 | import("../peoplesim/index")} 73 | component="PeopleSimIndex" 74 | /> 75 | import("../layercraft/index")} 78 | component="LayerCraftIndex" 79 | /> 80 | import("../cityplayer/index")} 83 | component="CityPlayerIndex" 84 | /> 85 | 86 | 87 | ); 88 | }; 89 | 90 | function LazyLoader({ path, module, component }) { 91 | const [componentClass, setComponentClass] = useState(null); 92 | // Note we put the component class in a list because preact instantiates it 93 | // otherwise, and we want to instantiate it ourselves. 94 | useEffect(() => { 95 | module() 96 | .then((module) => { 97 | setComponentClass([module[component]]); 98 | }) 99 | .catch((err) => { 100 | console.error( 101 | `Error loading module for ${component} at path ${path}:`, 102 | err 103 | ); 104 | setComponentClass([NotFound]); 105 | }); 106 | }, [module, component, path]); 107 | let Component = Waiting; 108 | if (componentClass) { 109 | Component = componentClass[0]; 110 | } 111 | return Component ? ( 112 | 113 | ) : ( 114 |
    Loading...
    115 | ); 116 | } 117 | 118 | function Waiting() { 119 | return
    Loading...
    ; 120 | } 121 | 122 | export default App; 123 | -------------------------------------------------------------------------------- /src/components/header.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-vars */ 2 | import { signal } from "@preact/signals"; 3 | import { tokenCostTracker } from "../gptservice/tokencost"; 4 | import { useEffect } from "preact/hooks"; 5 | import { useState, useRef } from "preact/hooks"; 6 | // eslint-disable-next-line no-unused-vars 7 | import * as icons from "./icons"; 8 | 9 | const tokenCost = signal(tokenCostTracker); 10 | 11 | tokenCostTracker.addOnUpdate((tracker) => { 12 | tokenCost.value = tracker; 13 | }); 14 | 15 | export const Header = ({ 16 | title, 17 | section, 18 | sectionLink, 19 | trackerPaths, 20 | links, 21 | buttons, 22 | menu, 23 | model, 24 | }) => { 25 | trackerPaths = trackerPaths || "all"; 26 | const [showMenu, setShowMenu] = useState(false); 27 | const menuRef = useRef(null); 28 | useEffect(() => { 29 | document.title = title; 30 | }, [title]); 31 | function onClickMenu() { 32 | if (menu) { 33 | setShowMenu(!showMenu); 34 | } 35 | } 36 | function onBackgroundClick(e) { 37 | if (menuRef.current && !menuRef.current.contains(e.target)) { 38 | setShowMenu(false); 39 | } 40 | } 41 | useEffect(() => { 42 | document.addEventListener("click", onBackgroundClick); 43 | return () => { 44 | document.removeEventListener("click", onBackgroundClick); 45 | }; 46 | }); 47 | let sectionTag; 48 | if (section) { 49 | if (sectionLink) { 50 | sectionTag = ( 51 | <> 52 | {section}{" "} 53 | 54 | 55 | ); 56 | } else { 57 | sectionTag = ( 58 | <> 59 | {section} 60 | 61 | ); 62 | } 63 | } 64 | async function onSaveBuiltin() { 65 | const newModel = await model.saveBuiltin(); 66 | const url = new URL(location.href); 67 | url.search = "?name=" + encodeURIComponent(newModel.slug); 68 | location.href = url.toString(); 69 | } 70 | if (model && model.builtin && model._dirty) { 71 | buttons = [...(buttons || [])]; 72 | buttons.unshift( 73 | Save Copy 74 | ); 75 | } 76 | return ( 77 | 129 | ); 130 | }; 131 | 132 | export function TokenCost({ paths }) { 133 | paths = paths || "all"; 134 | if (typeof paths === "string") { 135 | paths = [paths]; 136 | } 137 | const result = []; 138 | let lastDispPath = ""; 139 | for (const path of paths) { 140 | let dispPath = path; 141 | if (dispPath.startsWith(lastDispPath)) { 142 | dispPath = dispPath.slice(lastDispPath.length); 143 | } 144 | lastDispPath = dispPath; 145 | let usage = tokenCostTracker.tracked[path]; 146 | usage = (usage || {}).total_tokens || 0; 147 | let today = tokenCostTracker.sessionTracked[path]; 148 | today = (today || {}).total_tokens || 0; 149 | result.push( 150 | 151 | {dispPath}: / 152 | 153 | 154 | ); 155 | } 156 | return {result}; 157 | } 158 | 159 | function SingleTokenCost({ tokens, name }) { 160 | if (tokens === 0) { 161 | return ( 162 | 163 | 0 164 | 165 | ); 166 | } 167 | // This is only the davinci cost: 168 | let cost = (tokens / 1000) * 0.02; 169 | cost = name + ": $" + cost.toFixed(2); 170 | return {tokens}; 171 | } 172 | 173 | export const HeaderLink = ({ href, children }) => { 174 | return ( 175 | 179 | {children} 180 | 181 | ); 182 | }; 183 | 184 | export const HeaderButton = ({ children, onClick }) => { 185 | return ( 186 | 192 | ); 193 | }; 194 | -------------------------------------------------------------------------------- /src/components/home.js: -------------------------------------------------------------------------------- 1 | /* eslint no-unused-vars: "off" */ 2 | import { PageContainer, Card, H1, P, InfoHeader } from "./common"; 3 | import { Header } from "./header"; 4 | import { Markdown } from "../markdown"; 5 | import * as icons from "./icons"; 6 | 7 | const options = { 8 | "Make Your Own Adventure": { 9 | link: "/myoa/", 10 | logo: "/assets/icons/myoa-logo.png", 11 | description: ` 12 | A builder/authoring tool for creating a Choose Your Own 13 | Adventure-style story. GPT will suggest topics, choices, and 14 | passages; you can pick and choose, or revise and author. 15 | `.trim(), 16 | }, 17 | "City Maker": { 18 | link: "/citymaker/", 19 | logo: "/assets/icons/citymaker-logo.png", 20 | status: "deprecated", 21 | description: ` 22 | A tool for generating a city, top-down: starting with the city description, 23 | neighborhoods, buildings, objects, and so on. 24 | `.trim(), 25 | }, 26 | "People Sim": { 27 | link: "/peoplesim/", 28 | logo: "/assets/icons/peoplesim-logo.png", 29 | description: ` 30 | Simulate a few people interacting in an environment 31 | `.trim(), 32 | }, 33 | "Tone Changer": { 34 | link: "/tone-changer/", 35 | logo: "/assets/icons/tone-changer-logo.png", 36 | description: ` 37 | Act like you are someone else! Have your speech translated to a 38 | different tone (or language). 39 | `.trim(), 40 | }, 41 | Chat: { 42 | link: "/chat/", 43 | logo: "/assets/icons/chat-logo.png", 44 | description: "Chat with one of several personalities run by GPT.", 45 | }, 46 | "Interactive Fiction": { 47 | link: "/interactive-fiction/", 48 | logo: "/assets/icons/interactive-fiction-logo.png", 49 | description: 50 | "Run GPT as a _player_ against one of the Zork text adventure games.", 51 | }, 52 | "Voice Composer": { 53 | link: "/voice-composer/", 54 | logo: "/assets/icons/voice-composer-logo.png", 55 | status: "alpha", 56 | description: ` 57 | Voice composer: a voice-centric text composition and editing tool 58 | `.trim(), 59 | }, 60 | "Image Generator": { 61 | link: "/imagegen/", 62 | status: "alpha", 63 | description: ` 64 | A simple frontend to Replicate's Stable Diffusion API and Dall-E. 65 | Really just a testbed for using those APIs in other experiences. 66 | `.trim(), 67 | }, 68 | "Infinite AI Array": { 69 | link: "https://github.com/ianb/infinite-ai-array", 70 | logo: "/assets/icons/iaia-logo.png", 71 | description: ` 72 | Make your Python lists go forever, make your dictionaries fill just in time, 73 | and make functions appear magically when you call them. As irresponsible as 74 | it is irresistible! 75 | `.trim(), 76 | }, 77 | "LayerCraft": { 78 | link: "/layercraft/", 79 | description: ` 80 | A general authoring tool for building up in layers, building context and structure. 81 | Based on specific schemas that guide the authoring process, such as world building. 82 | `.trim(), 83 | logo: "/assets/icons/layercraft-logo.png", 84 | }, 85 | "City Player": { 86 | link: "/cityplayer/", 87 | logo: "/assets/icons/cityplayer-logo.png", 88 | status: "alpha", 89 | description: ` 90 | Play LayerCraft cities (not very complete)`.trim(), 91 | }, 92 | "Key Management": { 93 | link: "/key-management/", 94 | logo: "/assets/icons/key-management-logo.png", 95 | description: ` 96 | Add, change, or remove your OpenAI (GPT/Dall-E), Replicate.com, and Thumbsnap keys 97 | `.trim(), 98 | }, 99 | "P5 Drawing": { 100 | link: "/p5drawing/", 101 | logo: "/assets/icons/p5drawing-logo.png", 102 | description: 103 | "Program in a p5.js drawing environment using natural language", 104 | }, 105 | }; 106 | 107 | export const Home = () => { 108 | return ( 109 | 110 |
    111 |
    112 | 113 |
    114 | 115 |
    116 |

    117 | I have a little time on my hands but it's too hard to garden this 118 | time of year. So I'm building a garden of LLMs instead, GPT 119 | specifically. (GPT is a specific Large Language Model{" "} 120 | service.) 121 |

    122 |

    123 | Each of these is meant to be a way of exploring some idea or aspect 124 | of these technologies. I'm particularly interested in how each of 125 | these feel, not just how they perform. 126 |

    127 |
    128 |
    129 | {Object.entries(options) 130 | .filter((x) => !x[1].status) 131 | .map(([title, { link, description, logo }]) => ( 132 | 138 | ))} 139 | {Object.entries(options) 140 | .filter((x) => x[1].status) 141 | .map(([title, { link, status, description, logo }]) => ( 142 | 149 | ))} 150 |
    151 |
    152 | 153 | ); 154 | }; 155 | 156 | function LinkCard({ title, description, link, status, logo }) { 157 | return ( 158 | 159 | 160 | {logo ? : null} 161 | {status ? ( 162 |
    163 | 164 | {" "} 168 | {status} 169 | 170 |
    171 | ) : null} 172 | 173 |
    174 |
    175 | ); 176 | } 177 | 178 | export const NotFound = ({ message }) => { 179 | return ( 180 | 181 |
    182 | 183 |

    404 Not Found

    184 |

    Page not found

    185 | {message ?
    {message}
    : null} 186 |
    187 | 188 | ); 189 | }; 190 | -------------------------------------------------------------------------------- /src/components/modelmenu.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-vars */ 2 | import { Field, LogoImg, TextArea, Button } from "./common"; 3 | import * as icons from "./icons"; 4 | import { useEffect, useState } from "preact/hooks"; 5 | import { 6 | getGeneralLogoPrompt, 7 | setGeneralLogoPrompt, 8 | } from "../generallogoprompt"; 9 | 10 | export function ImportExportMenu({ model }) { 11 | const [loading, setLoading] = useState(false); 12 | useEffect(() => { 13 | const func = async () => { 14 | if (!model.logoPrompt || !model.logoPrompt.trim()) { 15 | await model.generateLogoPrompt(); 16 | } 17 | }; 18 | func().then(null, (error) => { 19 | console.error("Error in generating logo prompt:", error); 20 | }); 21 | }); 22 | function onExport(event) { 23 | const jsonData = model.exportJSON(); 24 | const stringData = JSON.stringify(jsonData, null, " "); 25 | const blob = new Blob([stringData], { type: "application/json" }); 26 | const url = URL.createObjectURL(blob); 27 | event.target.href = url; 28 | } 29 | function onImport(event) { 30 | const file = event.target.files[0]; 31 | const reader = new FileReader(); 32 | reader.onload = (e) => { 33 | const data = e.target.result; 34 | const storyJson = JSON.parse(data); 35 | model.importJSON(storyJson); 36 | }; 37 | reader.readAsText(file); 38 | } 39 | async function onGenerate(e) { 40 | e.preventDefault(); 41 | e.stopPropagation(); 42 | if (model.builtin) { 43 | alert("You cannot generate a logo for a built-in model; save it first!"); 44 | return; 45 | } 46 | if (!model.logoPrompt || !model.logoPrompt.trim()) { 47 | console.warn("No prompt yet for logo generation"); 48 | return; 49 | } 50 | setLoading(true); 51 | const logo = await model.generateLogo(); 52 | model.logo = logo; 53 | setLoading(false); 54 | } 55 | let logoSrc = "/assets/icons/loading.gif"; 56 | if (!loading) { 57 | logoSrc = model.logo || "/assets/icons/generic-app-icon.png"; 58 | } 59 | return ( 60 |
    61 |
    62 | 63 | Import / Export 64 | 65 | 66 | 72 | Export/download 73 | 74 | 75 |
    76 |
    77 |
    78 |
    79 | 80 | 81 | 82 |
    83 |
    84 |