├── .gitignore ├── README.md ├── __init__.py ├── docs ├── jemma-builds.png ├── jemma-logo.png ├── jemma-sketch.png ├── jemma.cast ├── jemma.gif └── minesweeper.png ├── huddle.py ├── jemma ├── __init__.py ├── epic │ ├── chord-progression.txt │ ├── talk-to-me-wiki.md │ └── valgo.txt ├── huddle.py ├── prompt │ ├── __init__.py │ ├── business │ │ ├── __init__.py │ │ └── owner.py │ ├── engineer │ │ ├── __init__.py │ │ ├── clarify.py │ │ ├── code.py │ │ └── game.py │ ├── tester │ │ ├── __init__.py │ │ └── test.py │ └── ui │ │ └── designer.py ├── requirements │ ├── __init__.py │ └── feature.py ├── team │ ├── __init__.py │ ├── business_owner.py │ ├── engineer.py │ ├── project_manager.py │ ├── tester.py │ └── ui_ux_designer.py ├── thinker.py ├── tools.py └── work │ ├── __init__.py │ └── flow.py └── pyproject.toml /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # poetry 98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 102 | #poetry.lock 103 | 104 | # pdm 105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 106 | #pdm.lock 107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 108 | # in version control. 109 | # https://pdm.fming.dev/#use-with-ide 110 | .pdm.toml 111 | 112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 113 | __pypackages__/ 114 | 115 | # Celery stuff 116 | celerybeat-schedule 117 | celerybeat.pid 118 | 119 | # SageMath parsed files 120 | *.sage.py 121 | 122 | # Environments 123 | .env 124 | .venv 125 | env/ 126 | venv/ 127 | ENV/ 128 | env.bak/ 129 | venv.bak/ 130 | 131 | # Spyder project settings 132 | .spyderproject 133 | .spyproject 134 | 135 | # Rope project settings 136 | .ropeproject 137 | 138 | # mkdocs documentation 139 | /site 140 | 141 | # mypy 142 | .mypy_cache/ 143 | .dmypy.json 144 | dmypy.json 145 | 146 | # Pyre type checker 147 | .pyre/ 148 | 149 | # pytype static type analyzer 150 | .pytype/ 151 | 152 | # Cython debug symbols 153 | cython_debug/ 154 | 155 | # PyCharm 156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 158 | # and can be added to the global gitignore or merged into this file. For a more nuclear 159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 160 | #.idea/ 161 | 162 | prototype/ 163 | requirements/ 164 | .copilot-token 165 | .DS_Store 166 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jemma 2 | > hey, I am Jemma. I convert your thoughts to code 3 | 4 | 5 | - [🧬 what I do](#-what-i-do) 6 | - [am skechin'](#-am-sketchin) 7 | - [🕹️ can I play?](#%EF%B8%8F-can-i-play) 8 | - [install me](#install-me) 9 | - [convert ideas to code](#convert-ideas-to-code) 10 | - [🛠️ how I do it](#%EF%B8%8F-how-i-do-it) 11 | - [models](#models) 12 | - [problems](#problems) 13 | - [development](#development) 14 | - [license](#license) 15 | 16 | # 🧬 what I do 17 | 18 | I take an idea in a form of: 19 | * a few words, such as "`Bill Pay Service`", "`2048`" or "`Kanban Board`" 20 | * OR a text file with requirements 21 | 22 | and I create a web based prototype 🚀 23 | 24 | > _in fact I just created all three 👆 (so you can quickly see what I mean):_ 25 | 26 | image 27 | 28 | 29 | after the prototype is built, I take feedback and refactor it. 30 | 31 | ## 🎨 am sketchin' 32 | 33 | I also dabble in converting sketches to web app mockups: 34 | 35 | ```bash 36 | $ jemma --prompt "Learning Portal" --sketch ~/tmp/sketch.png --build-prototype --claude 37 | ``` 38 | image 39 | 40 | _this does require one or two hints of feedback, but I'm getting better_ 41 | 42 | # 🕹️ can I play? 43 | 44 | of course! 45 | 46 | ## install me 47 | 48 | ``` 49 | $ pip install jemma 50 | ``` 51 | 52 | add a "`.env`" file from where I am going to be called from with API keys of your choice: 53 | 54 | ```bash 55 | export ANTHROPIC_API_KEY=sk-ant-api03... 56 | export OPENAI_API_KEY=sk-puk... 57 | export REPLICATE_API_TOKEN=r8_ai... 58 | ``` 59 | 60 | ready to rock! :metal: 61 | 62 | ## convert ideas to code 63 | 64 | ``` 65 | $ jemma --prompt "Bill Pay Service" --build-prototype --claude 66 | ``` 67 | 68 | I will assemble a team who will build a prototype, open a browser with it, and wait for your feedback: 69 | ```bash 70 | Claude 🧠 claude-3-haiku-20240307 ✅ 71 | 72 | > Project Manager: 73 | Dear Business Owner, in this meeting we'll work on creating requirements based on the 💡 idea 74 | 75 | > Business Owner: 📚 creating detailed requirements ...🖋️ 76 | 77 | > Project Manager: 78 | Dear Engineer, in this meeting let's put our heads together to build a prototype based on the requirements. 79 | 80 | > Engineer: 💫 creating a prototype based on the requirements... 81 | > Engineer: crafting css 🎨 (a.k.a. "visual beauty") 82 | > Engineer: cooking javascript 🎮 (a.k.a. "master of interactions") 83 | > Engineer: creating html 🕸️ (a.k.a. "the skeleton of the web") 84 | 85 | prototype files created successfully: 86 | - prototype/index.html 87 | - prototype/app.js 88 | - prototype/app.css 89 | opened prototype in the web browser 90 | 91 | tell me how to make it better > 92 | ``` 93 | 94 | # 🛠️ how I do it 95 | 96 | I rely on my team of project managers, business owners and engineers
97 | yes... "AI Agents" 98 | 99 | When I get an idea a Project Manager meets with a Business Owner to take it in and create a comprehensive set of requirements
100 | then the Project Manager meets with an Engineer to build the idea based on these new requirements. 101 | 102 | ## models 103 | 104 | I best work with Claude models, that is why my examples all end in "`--claude`": 105 | ```bash 106 | $ jemma --prompt "Trivia Game" --build-prototype --claude 107 | ``` 108 | by default though I will call Ollama (llama3 model): 109 | 110 | ```bash 111 | $ jemma --prompt "Trivia Game" --build-prototype 112 | Ollama 🧠 llama3:8b-instruct-fp16 ✅ 113 | ``` 114 | 115 | here are the default models I would use: 116 | 117 | | model param | default model| 118 | | ---- | ---- | 119 | | `--claude` | `claude-3-haiku-20240307` | 120 | | `--openai` | `gpt-3.5-turbo`| 121 | | `--ollama` | `llama3:8b-instruct-fp16`| 122 | | `--replicate` | `meta/meta-llama-3-70b-instruct`| 123 | | `--copilot` | `gpt-3.5-turbo`| 124 | 125 | but you can override all of these with your (local, or not) models: 126 | 127 | ```bash 128 | $ jemma --prompt "Trivia Game" --build-prototype --claude claude-3-opus-20240229 129 | $ jemma --prompt "Trivia Game" --build-prototype --ollama dolphin-mistral:7b-v2.6-dpo-laser-fp16 130 | $ jemma --prompt "Trivia Game" --build-prototype --openai gpt-4-turbo-preview 131 | $ jemma --prompt "Trivia Game" --build-prototype --replicate meta/llama-2-70b-chat 132 | $ jemma --prompt "Trivia Game" --build-prototype --copilot gpt-4 133 | $ ... 134 | ``` 135 | 136 | > _but, at least for now, the best results are produced with **Claude** based models_ 137 | 138 | ## problems 139 | 140 | I am still learning, so some prototypes that I build might result in errors
141 | this would especially be likely with non Claude based models 142 | 143 | but, we are all learning, _and_ I love feedback: 144 | 145 | ```bash 146 | tell me how to make it better > I see an error "app.js:138: uncaught TypeError: chordProgressionData.find(...) is undefined" 147 | 148 | > Project Manager: 149 | Dear Engineer, we have met with the user and received a valuable feedback. sudo make it better! 🛠️ 150 | 151 | > Engineer: 💫 refactoring prototype based on the feedback... 152 | 153 | > Engineer: ♻️ crafting css 🎨 (a.k.a. "visual beauty") 154 | 155 | > Engineer: ♻️ cooking javascript 🎮 (a.k.a. "master of interactions") 156 | 157 | > Engineer: ♻️ creating html 🕸️ (a.k.a. "the skeleton of the web") 158 | prototype files created successfully: 159 | - prototype/index.html 160 | - prototype/app.js 161 | - prototype/app.css 162 | opened prototype in the web browser 163 | 164 | tell me how to make it better > 165 | ``` 166 | 167 | _you can check for / find errors in your browser console_ 168 | 169 | >_iff you know "how to HTML", you can help fix the code as well
_ 170 | >_it is often something simple: adding a CSS class, updating the "width", etc._ 171 | 172 | ## development 173 | 174 | in order to run from source
175 | clone jemma: 176 | 177 | ```bash 178 | $ git clone git@github.com:tolitius/jemma.git 179 | ``` 180 | and 181 | ```bash 182 | $ cd jemma 183 | $ python huddle.py --prompt "Code Editor" --build-prototype --claude 184 | Claude 🧠 claude-3-haiku-20240307 ✅ 185 | ... 186 | ``` 187 | 188 | # license 189 | 190 | Copyright © 2024 tolitius 191 | 192 | Distributed under the Eclipse Public License either version 1.0 or (at 193 | your option) any later version. 194 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tolitius/jemma/6b2ec2979a733f7a99c9ff698dc253239ea0d9de/__init__.py -------------------------------------------------------------------------------- /docs/jemma-builds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tolitius/jemma/6b2ec2979a733f7a99c9ff698dc253239ea0d9de/docs/jemma-builds.png -------------------------------------------------------------------------------- /docs/jemma-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tolitius/jemma/6b2ec2979a733f7a99c9ff698dc253239ea0d9de/docs/jemma-logo.png -------------------------------------------------------------------------------- /docs/jemma-sketch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tolitius/jemma/6b2ec2979a733f7a99c9ff698dc253239ea0d9de/docs/jemma-sketch.png -------------------------------------------------------------------------------- /docs/jemma.cast: -------------------------------------------------------------------------------- 1 | {"version": 2, "width": 110, "height": 24, "timestamp": 1712671227, "env": {"SHELL": "/bin/zsh", "TERM": "xterm-256color"}} 2 | [23.183867, "o", "\u001b]0;jemma@simmons: /tmp\u0007"] 3 | [23.184034, "o", "(simmons) [\u001b[01;36mai\u001b[01;37m]\u001b[01;34m\u001b[00m$ "] 4 | [26.427115, "o", "#"] 5 | [26.854374, "o", " "] 6 | [27.285076, "o", "l"] 7 | [27.426631, "o", "e"] 8 | [27.490238, "o", "t"] 9 | [27.648269, "o", "'"] 10 | [27.724372, "o", "s"] 11 | [28.052343, "o", " "] 12 | [28.252589, "o", "i"] 13 | [28.307936, "o", "n"] 14 | [28.406209, "o", "s"] 15 | [28.515345, "o", "t"] 16 | [28.586581, "o", "a"] 17 | [28.677015, "o", "l"] 18 | [28.81579, "o", "l"] 19 | [29.223139, "o", " "] 20 | [29.537522, "o", "j"] 21 | [29.650377, "o", "e"] 22 | [29.737625, "o", "m"] 23 | [29.889897, "o", "m"] 24 | [30.540265, "o", "a"] 25 | [31.322033, "o", "\r\n"] 26 | [31.322854, "o", "\u001b]0;jemma@simmons: /tmp\u0007"] 27 | [31.322987, "o", "(simmons) [\u001b[01;36mai\u001b[01;37m]\u001b[01;34m\u001b[00m$ "] 28 | [31.809095, "o", "\r\n"] 29 | [31.809283, "o", "\u001b]0;jemma@simmons: /tmp\u0007"] 30 | [31.809365, "o", "(simmons) [\u001b[01;36mai\u001b[01;37m]\u001b[01;34m\u001b[00m$ "] 31 | [32.387362, "o", "p"] 32 | [32.468176, "o", "i"] 33 | [32.553229, "o", "p"] 34 | [32.957947, "o", " "] 35 | [33.52269, "o", "i"] 36 | [33.578804, "o", "n"] 37 | [33.685539, "o", "s"] 38 | [33.776625, "o", "t"] 39 | [33.85148, "o", "a"] 40 | [33.90132, "o", "l"] 41 | [34.047729, "o", "l"] 42 | [34.136452, "o", " "] 43 | [35.22181, "o", "j"] 44 | [35.348903, "o", "e"] 45 | [35.501331, "o", "m"] 46 | [35.623357, "o", "m"] 47 | [35.715591, "o", "a"] 48 | [36.9748, "o", "\r\n"] 49 | [37.605139, "o", "Collecting jemma\r\n"] 50 | [41.855677, "o", "Downloading jemma-0.1.42-py3-none-any.whl (30.8 kB)\r\n"] 51 | [43.433938, "o", "\u001b[?25l"] 52 | [43.436122, "o", " \u001b[38;5;237m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m0.0/30.8 kB\u001b[0m \u001b[31m?\u001b[0m eta \u001b[36m-:--:--\u001b[0m"] 53 | [43.462826, "o", "\r\u001b[2K \u001b[38;2;114;156;31m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m30.8/30.8 kB\u001b[0m \u001b[31m4.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\r\n\u001b[?25h"] 54 | [46.811493, "o", "Successfully installed jemma-0.1.42\r\n"] 55 | [47.187392, "o", "\u001b]0;jemma@simmons: /tmp\u0007"] 56 | [47.187462, "o", "(simmons) [\u001b[01;36mai\u001b[01;37m]\u001b[01;34m\u001b[00m$ "] 57 | [50.102587, "o", "\r\n"] 58 | [50.102804, "o", "\u001b]0;jemma@simmons: /tmp\u0007"] 59 | [50.103034, "o", "(simmons) [\u001b[01;36mai\u001b[01;37m]\u001b[01;34m\u001b[00m$ "] 60 | [52.102811, "o", "#"] 61 | [52.222686, "o", " "] 62 | [52.621102, "o", "j"] 63 | [52.725522, "o", "e"] 64 | [52.832191, "o", "m"] 65 | [52.968215, "o", "m"] 66 | [53.043827, "o", "a"] 67 | [53.308322, "o", " "] 68 | [53.925784, "o", "i"] 69 | [54.028707, "o", "s"] 70 | [54.141023, "o", " "] 71 | [54.323593, "o", "i"] 72 | [54.374484, "o", "n"] 73 | [54.464592, "o", "s"] 74 | [54.601129, "o", "t"] 75 | [54.681652, "o", "a"] 76 | [54.753266, "o", "l"] 77 | [54.858666, "o", "l"] 78 | [54.97183, "o", "e"] 79 | [55.018816, "o", "d"] 80 | [55.404868, "o", "!"] 81 | [55.73258, "o", "\r\n"] 82 | [55.733235, "o", "\u001b]0;jemma@simmons: /tmp\u0007"] 83 | [55.733324, "o", "(simmons) [\u001b[01;36mai\u001b[01;37m]\u001b[01;34m\u001b[00m$ "] 84 | [56.358198, "o", "\r\n"] 85 | [56.358363, "o", "\u001b]0;jemma@simmons: /tmp\u0007"] 86 | [56.358457, "o", "(simmons) [\u001b[01;36mai\u001b[01;37m]\u001b[01;34m\u001b[00m$ "] 87 | [56.78382, "o", "#"] 88 | [56.922403, "o", "#"] 89 | [57.335237, "o", " "] 90 | [57.50485, "o", "c"] 91 | [57.754626, "o", "r"] 92 | [57.839279, "o", "e"] 93 | [57.918637, "o", "a"] 94 | [58.108663, "o", "t"] 95 | [58.136224, "o", "e"] 96 | [58.701196, "o", " "] 97 | [59.091609, "o", "a"] 98 | [59.286239, "o", " "] 99 | [59.452303, "o", "\""] 100 | [59.558795, "o", "\""] 101 | [59.742611, "o", "\b"] 102 | [60.297858, "o", ".\"\b"] 103 | [60.65312, "o", "e\"\b"] 104 | [60.78167, "o", "n\"\b"] 105 | [60.898833, "o", "v\"\b"] 106 | [61.232338, "o", "\u001b[C"] 107 | [61.605882, "o", " "] 108 | [61.788714, "o", "f"] 109 | [61.856224, "o", "i"] 110 | [61.90117, "o", "l"] 111 | [61.988846, "o", "e"] 112 | [62.33452, "o", " "] 113 | [62.438841, "o", "w"] 114 | [62.536185, "o", "i"] 115 | [62.654946, "o", "t"] 116 | [62.734316, "o", "h"] 117 | [63.1561, "o", " "] 118 | [63.479123, "o", "A"] 119 | [63.587403, "o", "P"] 120 | [63.649455, "o", "I"] 121 | [64.587512, "o", " "] 122 | [64.733834, "o", "k"] 123 | [64.832183, "o", "e"] 124 | [64.980079, "o", "y"] 125 | [65.063448, "o", "s"] 126 | [65.152313, "o", " "] 127 | [65.546689, "o", "o"] 128 | [65.64047, "o", "f"] 129 | [65.716444, "o", " "] 130 | [66.103964, "o", "y"] 131 | [66.169787, "o", "o"] 132 | [66.211616, "o", "u"] 133 | [66.302025, "o", "r"] 134 | [66.422154, "o", " "] 135 | [66.94006, "o", "c"] 136 | [67.064801, "o", "h"] 137 | [67.137327, "o", "o"] 138 | [67.187885, "o", "i"] 139 | [67.334851, "o", "c"] 140 | [67.434883, "o", "e"] 141 | [68.333271, "o", "\r\n"] 142 | [68.334155, "o", "\u001b]0;jemma@simmons: /tmp\u0007"] 143 | [68.334328, "o", "(simmons) [\u001b[01;36mai\u001b[01;37m]\u001b[01;34m\u001b[00m$ "] 144 | [69.023081, "o", "c"] 145 | [69.080178, "o", "a"] 146 | [69.171631, "o", "t"] 147 | [69.222838, "o", " "] 148 | [69.759086, "o", "."] 149 | [69.885643, "o", "e"] 150 | [69.991501, "o", "nv "] 151 | [70.590873, "o", "\r\n"] 152 | [70.604078, "o", "export ANTHROPIC_API_KEY=sk-ant-api...\r\nexport OPENAI_API_KEY=sk-puk...\r\nexport REPLICATE_API_TOKEN=r8_ai...\r\n"] 153 | [70.604514, "o", "\u001b]0;jemma@simmons: /tmp\u0007"] 154 | [70.604643, "o", "(simmons) [\u001b[01;36mai\u001b[01;37m]\u001b[01;34m\u001b[00m$ "] 155 | [71.33887, "o", "\r\n"] 156 | [71.339039, "o", "\u001b]0;jemma@simmons: /tmp\u0007"] 157 | [71.339194, "o", "(simmons) [\u001b[01;36mai\u001b[01;37m]\u001b[01;34m\u001b[00m$ "] 158 | [76.117585, "o", "#"] 159 | [77.848998, "o", "\b\u001b[K"] 160 | [78.767181, "o", "#"] 161 | [78.885124, "o", " "] 162 | [79.500423, "o", "w"] 163 | [79.531504, "o", "e"] 164 | [79.670532, "o", " "] 165 | [79.780999, "o", "a"] 166 | [79.954666, "o", "r"] 167 | [80.027463, "o", "e"] 168 | [80.112079, "o", " "] 169 | [80.314912, "o", "n"] 170 | [80.362062, "o", "o"] 171 | [80.351413, "o", "w"] 172 | [80.49187, "o", " "] 173 | [80.852561, "o", "r"] 174 | [80.907151, "o", "e"] 175 | [81.13743, "o", "a"] 176 | [81.152483, "o", "d"] 177 | [81.794738, "o", "y"] 178 | [81.856976, "o", " "] 179 | [82.030695, "o", "t"] 180 | [82.093292, "o", "o"] 181 | [82.153796, "o", " "] 182 | [82.412856, "o", "c"] 183 | [82.654921, "o", "r"] 184 | [82.754491, "o", "e"] 185 | [82.831862, "o", "a"] 186 | [83.015021, "o", "t"] 187 | [83.083481, "o", "e"] 188 | [83.396401, "o", " "] 189 | [83.610557, "o", "w"] 190 | [83.701977, "o", "h"] 191 | [83.782256, "o", "a"] 192 | [83.939274, "o", "t"] 193 | [84.383062, "o", "e"] 194 | [84.430107, "o", "v"] 195 | [84.519922, "o", "e"] 196 | [84.589967, "o", "r"] 197 | [84.755435, "o", " "] 198 | [85.137483, "o", "o"] 199 | [85.199325, "o", "u"] 200 | [85.384681, "o", "r"] 201 | [85.464833, "o", " "] 202 | [85.703198, "o", "m"] 203 | [85.825467, "o", "i"] 204 | [85.923186, "o", "n"] 205 | [86.089466, "o", "d"] 206 | [86.186953, "o", " "] 207 | [86.557464, "o", "d"] 208 | [86.630235, "o", "e"] 209 | [86.830593, "o", "s"] 210 | [86.970969, "o", "i"] 211 | [87.915445, "o", "r"] 212 | [87.983687, "o", "e"] 213 | [88.235896, "o", "s"] 214 | [89.12749, "o", "!"] 215 | [89.699432, "o", "\r\n"] 216 | [89.700102, "o", "\u001b]0;jemma@simmons: /tmp\u0007"] 217 | [89.700311, "o", "(simmons) [\u001b[01;36mai\u001b[01;37m]\u001b[01;34m\u001b[00m$ "] 218 | [91.603908, "o", "\r\n"] 219 | [91.604093, "o", "\u001b]0;jemma@simmons: /tmp\u0007(simmons) [\u001b[01;36mai\u001b[01;37m]\u001b[01;34m\u001b[00m$ "] 220 | [91.990094, "o", "j"] 221 | [92.344294, "o", "e"] 222 | [92.497118, "o", "m"] 223 | [92.624674, "o", "m"] 224 | [92.773592, "o", "a"] 225 | [93.533758, "o", " "] 226 | [93.961426, "o", "-"] 227 | [94.073652, "o", "-"] 228 | [94.41557, "o", "p"] 229 | [94.582055, "o", "r"] 230 | [94.675312, "o", "o"] 231 | [94.892753, "o", "m"] 232 | [94.965641, "o", "p"] 233 | [95.499592, "o", "t"] 234 | [96.222088, "o", " "] 235 | [96.774856, "o", "\""] 236 | [96.774856, "o", "R"] 237 | [96.774856, "o", "e"] 238 | [96.774856, "o", "t"] 239 | [96.774856, "o", "r"] 240 | [96.774856, "o", "o"] 241 | [96.774856, "o", " "] 242 | [96.774856, "o", "M"] 243 | [96.774856, "o", "i"] 244 | [96.774856, "o", "n"] 245 | [96.774856, "o", "e"] 246 | [96.774856, "o", "s"] 247 | [96.774856, "o", "w"] 248 | [96.774856, "o", "e"] 249 | [96.774856, "o", "e"] 250 | [96.774856, "o", "p"] 251 | [96.774856, "o", "e"] 252 | [96.774856, "o", "r"] 253 | [96.774856, "o", "\""] 254 | [106.017869, "o", " "] 255 | [106.221827, "o", "-"] 256 | [106.338306, "o", "-"] 257 | [106.849482, "o", "b"] 258 | [106.926901, "o", "u"] 259 | [106.950488, "o", "i"] 260 | [107.14714, "o", "l"] 261 | [107.249215, "o", "d"] 262 | [108.02931, "o", "-"] 263 | [108.672744, "o", "p"] 264 | [108.851926, "o", "r"] 265 | [108.943869, "o", "o"] 266 | [109.449629, "o", "t"] 267 | [109.570386, "o", "o"] 268 | [110.032397, "o", "t"] 269 | [110.170903, "o", "y"] 270 | [110.280879, "o", "p"] 271 | [110.420384, "o", "e"] 272 | [110.700011, "o", " "] 273 | [111.25571, "o", "-"] 274 | [111.349431, "o", "-"] 275 | [111.488602, "o", "c"] 276 | [111.603774, "o", "l"] 277 | [112.342723, "o", "a"] 278 | [112.503399, "o", "u"] 279 | [112.677954, "o", "d"] 280 | [112.769259, "o", "e"] 281 | [113.364133, "o", "\r\n"] 282 | [104.471046, "o", "\u001b[38;5;244mClaude 🧠 claude-3-haiku-20240307 ✅\u001b[0m\r\n\r\n\u001b[94m> \u001b[1m\u001b[96m\u001b[4mProject Manager\u001b[0m: \u001b[93m\r\nDear Business Owner, in this meeting we'll work on creating requirements based on the 💡 idea\r\n\r\n\u001b[94m> \u001b[1m\u001b[95m\u001b[4mBusiness Owner\u001b[0m: \u001b[36m📚 creating detailed requirements ...🖋️\r\n"] 283 | [122.008796, "o", "\r\n\u001b[94m> \u001b[1m\u001b[96m\u001b[4mProject Manager\u001b[0m: \u001b[93m\r\nDear Engineer, in this meeting let's put our heads together to build a prototype based on the requirements.\r\n\r\n\u001b[94m> \u001b[1m\u001b[95m\u001b[4mEngineer\u001b[0m: \u001b[36m💫 creating a prototype based on the requirements...\r\n\r\n\u001b[94m> \u001b[1m\u001b[95m\u001b[4mEngineer\u001b[0m: \u001b[96mcrafting css 🎨 (a.k.a. \"visual beauty\")\r\n"] 284 | [134.758708, "o", "\r\n\u001b[94m> \u001b[1m\u001b[95m\u001b[4mEngineer\u001b[0m: \u001b[96mcooking javascript 🎮 (a.k.a. \"master of interactions\")\r\n"] 285 | [157.272637, "o", "\r\n\u001b[94m> \u001b[1m\u001b[95m\u001b[4mEngineer\u001b[0m: \u001b[96mcreating html 🕸️ (a.k.a. \"the skeleton of the web\")\r\n"] 286 | [166.188864, "o", "prototype files created successfully:\r\n- prototype/index.html\r\n- prototype/app.js\r\n- prototype/app.css\r\n"] 287 | [166.421101, "o", "opened prototype in the web browser\r\n"] 288 | [166.421453, "o", "\r\n\u001b[92mtell me how to make it better > \u001b[0m"] 289 | [167.368968, "o", "a"] 290 | [167.623074, "o", "d"] 291 | [167.764074, "o", "d"] 292 | [168.12246, "o", " "] 293 | [168.27193, "o", "c"] 294 | [168.342906, "o", "o"] 295 | [168.474862, "o", "l"] 296 | [168.623646, "o", "o"] 297 | [169.222911, "o", "r"] 298 | [169.30331, "o", "s"] 299 | [169.467906, "o", ","] 300 | [169.541442, "o", " "] 301 | [169.72338, "o", "m"] 302 | [169.767506, "o", "a"] 303 | [169.899985, "o", "k"] 304 | [169.997455, "o", "e"] 305 | [170.633092, "o", " "] 306 | [170.767175, "o", "i"] 307 | [170.872972, "o", "t"] 308 | [170.922585, "o", " "] 309 | [171.104084, "o", "m"] 310 | [171.152494, "o", "o"] 311 | [171.934826, "o", "r"] 312 | [172.003481, "o", "e"] 313 | [172.124126, "o", " "] 314 | [172.176365, "o", "f"] 315 | [172.357832, "o", "u"] 316 | [172.973384, "o", "n"] 317 | [174.893149, "o", "!"] 318 | [177.14567, "o", "\r\n"] 319 | [177.145885, "o", "\r\n\u001b[94m> \u001b[1m\u001b[96m\u001b[4mProject Manager\u001b[0m: \u001b[93m\r\nDear Engineer, we have met with the user and received a valuable feedback. sudo make it better! 🛠️\r\n"] 320 | [177.145966, "o", "\r\n\u001b[94m> \u001b[1m\u001b[95m\u001b[4mEngineer\u001b[0m: \u001b[36m💫 refactoring prototype based on the feedback...\r\n"] 321 | [208.358243, "o", "prototype files created successfully:\r\n- prototype/index.html\r\n- prototype/app.js\r\n- prototype/app.css\r\n"] 322 | [208.591947, "o", "opened prototype in the web browser\r\n"] 323 | [208.592253, "o", "\r\n\u001b[92mtell me how to make it better > \u001b[0m"] 324 | [278.751848, "o", "\r\n"] 325 | [278.86765, "o", "\u001b]0;jemma@simmons: /tmp\u0007"] 326 | [278.867897, "o", "(simmons) [\u001b[01;36mai\u001b[01;37m]\u001b[01;34m\u001b[00m$ "] 327 | [280.605838, "o", "\r\n"] 328 | [280.606012, "o", "\u001b]0;jemma@simmons: /tmp\u0007"] 329 | [280.606124, "o", "(simmons) [\u001b[01;36mai\u001b[01;37m]\u001b[01;34m\u001b[00m$ "] 330 | [283.671642, "o", "#"] 331 | [286.006794, "o", " "] 332 | [287.790002, "o", "y"] 333 | [287.9022, "o", "a"] 334 | [288.447781, "o", "y"] 335 | [288.790676, "o", "!"] 336 | -------------------------------------------------------------------------------- /docs/jemma.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tolitius/jemma/6b2ec2979a733f7a99c9ff698dc253239ea0d9de/docs/jemma.gif -------------------------------------------------------------------------------- /docs/minesweeper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tolitius/jemma/6b2ec2979a733f7a99c9ff698dc253239ea0d9de/docs/minesweeper.png -------------------------------------------------------------------------------- /huddle.py: -------------------------------------------------------------------------------- 1 | import argparse, os 2 | from dotenv import load_dotenv 3 | 4 | from jemma.tools import parse_cli_arguments 5 | from jemma.requirements.feature import Feature 6 | from jemma.team.ui_ux_designer import UiUxDesigner 7 | from jemma.team.business_owner import BusinessOwner 8 | from jemma.team.engineer import Engineer 9 | from jemma.team.tester import Tester 10 | from jemma.team.project_manager import ProjectManager 11 | import jemma.work.flow as flow 12 | 13 | import jemma.thinker as thinker 14 | 15 | def main(): 16 | 17 | ## ----------------------------- setup 18 | env_path = os.path.join(os.getcwd(), '.env') 19 | load_dotenv(dotenv_path=env_path) 20 | 21 | args = parse_cli_arguments() 22 | brain = thinker.make_brain(args) 23 | 24 | ## ----------------------------- create a feature 25 | # read requirements from the file 26 | requirements = "" 27 | if args.requirements: 28 | with open(args.requirements, 'r') as file: 29 | requirements = file.read() 30 | 31 | feature = Feature(requirements) 32 | 33 | ## ----------------------------- create a team 34 | designer = UiUxDesigner("an experienced UI/UX designer with attention to detail, " 35 | "focused on building beautiful and intuitive user interfaces") 36 | 37 | business_owner = BusinessOwner("an experienced business owner with attention to detail, " 38 | "focused on building requirements for engineers to build software products") 39 | 40 | engineer = Engineer("an experienced software engineer " 41 | "with a focus on full stack development") 42 | 43 | tester = Tester("a professional software tester with a deep expertise is " 44 | "understanding business requirements and how they translate into software features") 45 | 46 | project_manager = ProjectManager(feature) 47 | 48 | ## ----------------------------- rock & roll 49 | 50 | if args.tasks: 51 | flow.compose(brain, 52 | project_manager, 53 | designer, 54 | business_owner, 55 | engineer, 56 | tester, 57 | args) 58 | 59 | if args.user_stories: 60 | flow.create_user_stories (brain, 61 | project_manager, 62 | business_owner, 63 | engineer) 64 | if args.build_prototype: 65 | flow.build_prototype(brain, 66 | project_manager, 67 | designer, 68 | business_owner, 69 | engineer, 70 | args.prompt, 71 | args.sketch) 72 | 73 | if args.build_user_stories: 74 | flow.build_user_stories(brain, 75 | project_manager, 76 | business_owner, 77 | engineer) 78 | if args.test_prototype: 79 | flow.test_prototype(brain, 80 | project_manager, 81 | tester) 82 | 83 | if __name__ == '__main__': 84 | main() 85 | -------------------------------------------------------------------------------- /jemma/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tolitius/jemma/6b2ec2979a733f7a99c9ff698dc253239ea0d9de/jemma/__init__.py -------------------------------------------------------------------------------- /jemma/epic/chord-progression.txt: -------------------------------------------------------------------------------- 1 | Here's a detailed prompt with requirements for the "Musical Chord Progression Generator" web app: 2 | 3 | Title: Musical Chord Progression Generator 4 | 5 | Description: 6 | Create a web app that generates chord progressions based on user-selected musical keys and moods. The app should display the generated chords, their positions on a virtual fretboard, and allow the user to play the progression and adjust the tempo. The app should also display the chord names and their corresponding musical notation. 7 | 8 | Requirements: 9 | 1. Key and Mood Selection: 10 | - Provide a dropdown menu for the user to select a musical key (e.g., C, D, E, F, G, A, B). 11 | - Include another dropdown menu for the user to choose a mood (e.g., happy, sad, mysterious, uplifting, melancholic). 12 | 13 | 2. Chord Progression Generation: 14 | - Upon user selection of key and mood, generate a chord progression that fits the selected criteria. 15 | - Use music theory rules and algorithms to create harmonically pleasing progressions. 16 | - Generate progressions with a minimum of 4 chords and a maximum of 8 chords. 17 | 18 | 3. Chord Display Table: 19 | - Display the generated chords in a table format. 20 | - Each row should represent a chord in the progression. 21 | - Columns should include the chord name, its position in the progression, and its musical notation. 22 | - The chord name should be displayed in both letter notation (e.g., Cmaj7) and Roman numeral notation (e.g., I7). 23 | 24 | 4. Virtual Fretboard: 25 | - Display a virtual fretboard that shows the positions of the chords in the generated progression. 26 | - Highlight the chords on the fretboard as the progression plays. 27 | - Allow the user to interact with the fretboard by hovering over or clicking on the chords to display their names. 28 | 29 | 5. Audio Playback: 30 | - Include a "Play" button that allows the user to listen to the generated chord progression. 31 | - Use a default tempo for playback, but allow the user to adjust the tempo using a slider or input field. 32 | - Highlight the currently playing chord in the table and on the virtual fretboard. 33 | 34 | 6. Musical Notation: 35 | - Display the musical notation for each chord in the progression. 36 | - Use standard notation symbols for chords (e.g., triads, sevenths, extensions). 37 | - Optionally, include the ability to export the chord progression as a MIDI file or sheet music image. 38 | 39 | 7. User Interface: 40 | - Design a clean, intuitive, and visually appealing user interface. 41 | - Use appropriate colors, fonts, and layout to create a professional and engaging experience. 42 | - Ensure the app is responsive and works well on various screen sizes. 43 | 44 | 8. Code Generation: 45 | - The AI agent should generate the necessary HTML, CSS, and JavaScript code to create a functional prototype of the Musical Chord Progression Generator. 46 | - The generated code should be well-structured, efficiently written, and include relevant comments. 47 | 48 | Additional Considerations: 49 | - Consider adding a feature to save and share generated chord progressions. 50 | - Provide a help section or tutorial to explain the app's features and how to use them. 51 | - Incorporate accessibility best practices to ensure the app is usable by a wide range of users. 52 | 53 | By following this prompt and its requirements, the AI agent should be able to create a comprehensive and engaging prototype of the Musical Chord Progression Generator web app. 54 | -------------------------------------------------------------------------------- /jemma/epic/talk-to-me-wiki.md: -------------------------------------------------------------------------------- 1 | # CONTEXT 2 | - Company documentation is stored on an internally hosted Confluence wiki 3 | - Each team has their own space for documentation 4 | - Documents contain text, links, images, tables, presentations, etc. 5 | - The wiki contains hundreds of thousands of documents 6 | 7 | # PROBLEM 8 | - Searching for information on the wiki is difficult due to: 9 | - Information being scattered across different spaces and pages 10 | - Many documents being abandoned and not updated 11 | - Onboarding new employees is challenging as they need to read through extensive documentation 12 | - Understanding integration points between systems is difficult due to scattered information 13 | - Comprehending how things work is not easy, despite most information being available 14 | 15 | # SOLUTION 16 | - Build a RAG (Retrieval Augmented Generation) system that allows users to interact with and retrieve information from the wiki through natural language queries 17 | - Ensure data privacy by: 18 | - Running the RAG system on internal company servers 19 | - Using local embeddings and language models (e.g., Ollama or llama.cpp) 20 | - Host the RAG system using an open-source UI (e.g., open-webui, oobabooga) for user interaction 21 | - Implement document indexing to keep the RAG system up-to-date: 22 | - Index new documents as they are created 23 | - Periodically re-index old documents 24 | - Utilize ColBERT (v2) for document retrieval and RAGatouille for reranking to provide relevant search results 25 | - Implement a fallback search mechanism using LLM function calling/tooling to directly search the wiki when the RAG system fails to find relevant information 26 | - Develop user authentication, authorization, and access control to ensure data security 27 | - Implement monitoring, logging, and reporting features to track system performance and usage 28 | -------------------------------------------------------------------------------- /jemma/epic/valgo.txt: -------------------------------------------------------------------------------- 1 | # Algorithmic Visualizer 2 | 3 | ## Requirements: 4 | - User selects a common algorithm (e.g., sorting, pathfinding, graph traversal) 5 | - App displays a visually appealing, animated representation of the algorithm in action 6 | - A table below the visualization shows the algorithm's step-by-step progress 7 | - User can adjust parameters (e.g., array size, animation speed) via sliders or input fields 8 | - App highlights the relevant code snippets as the algorithm progresses 9 | - User can pause, step forward/backward, or restart the visualization 10 | 11 | The Algorithmic Visualizer would be an engaging and interactive way for developers to understand and teach common algorithms. The visual animations and step-by-step table would make the algorithm's inner workings clear and easy to follow. 12 | 13 | ## Instructions: 14 | 15 | Here's how the AI agent could approach generating the prototype: 16 | 17 | HTML: 18 | - Create a container for the visualization canvas 19 | - Add a table to display the algorithm's progress 20 | - Include sliders and input fields for adjusting parameters 21 | - Place buttons for controlling the visualization (play, pause, step, restart) 22 | - Display the relevant code snippets in a syntax-highlighted code block 23 | 24 | CSS: 25 | - Style the visualization canvas to be visually appealing and responsive 26 | - Use animations and transitions to smoothly update the visualization 27 | - Style the table to be readable and visually consistent with the overall design 28 | - Ensure the sliders, input fields, and buttons have a modern, intuitive appearance 29 | - Apply syntax highlighting styles to the code block 30 | 31 | JavaScript: 32 | - Implement a few algorithms in a modular, readable way 33 | - Create functions to update the visualization canvas based on the algorithm's progress 34 | - Populate and update the table with the algorithm's step-by-step progress 35 | - Add event listeners to the sliders, input fields, and buttons to control the visualization 36 | - Highlight the relevant lines of code as the algorithm progresses 37 | 38 | The AI agent would need to intelligently generate the HTML structure, CSS styles, and JavaScript code based on the selected algorithm and user-specified parameters. The resulting prototype would be a fully functional, visually engaging app that showcases the power of AI-driven development. 39 | 40 | This Algorithmic Visualizer combines the fun of interactive visualizations, the developer-oriented focus on common algorithms, and the flashy use of tables and animations to create an appealing and educational web app. 41 | 42 | (!) make sure that when launched the first algorithm is defined, selected, visible and playable 43 | -------------------------------------------------------------------------------- /jemma/huddle.py: -------------------------------------------------------------------------------- 1 | ../huddle.py -------------------------------------------------------------------------------- /jemma/prompt/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tolitius/jemma/6b2ec2979a733f7a99c9ff698dc253239ea0d9de/jemma/prompt/__init__.py -------------------------------------------------------------------------------- /jemma/prompt/business/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tolitius/jemma/6b2ec2979a733f7a99c9ff698dc253239ea0d9de/jemma/prompt/business/__init__.py -------------------------------------------------------------------------------- /jemma/prompt/business/owner.py: -------------------------------------------------------------------------------- 1 | def clarify_user_story(role, 2 | requirements, 3 | user_story, 4 | engineer_response): 5 | return f""" 6 | # INSTRUCTIONS 7 | As the {role}, your task is to review the engineer's feedback on the user story and provide clarifications while ensuring the user story remains concise and focused on a single unit of work. 8 | 9 | Consider the following guidelines: 10 | 1. Address the specific questions or points raised by the engineer. 11 | 2. Provide clear and concise clarifications without adding unnecessary details. 12 | 3. Ensure that the clarified user story still aligns with the overall feature requirements. 13 | 4. Keep the user story focused on a single, well-defined unit of work. 14 | 5. Use simple language and avoid ambiguity or vague statements. 15 | 6. If the engineer has confirmed that no clarification is needed, simply return the original user story. 16 | 17 | you task is to return the clarified acceptance criteria of the original user story. ALL in the Gherkin format (Given/When/Then). and NOTHING ELSE: no headers, no footers, no explanations, just the user story. 18 | 19 | Return the acceptance criteria of the original user story clarified in the following JSON format: 20 | 21 | "Given ,", 22 | "When ,", 23 | "And ,", 24 | "Then .", 25 | "", 26 | "Given ,", 27 | "When ,", 28 | "And ,", 29 | "And ,", 30 | "Then .", 31 | "", 32 | "", 33 | ... 34 | 35 | make sure the final acceptance criteria covers ALL the points raised by the engineer 36 | AS WELL AS the previous acceptance criteria, so no context is lost 37 | 38 | * Use clear and concise language 39 | return this acceptance criteria without any additional text, headings or footers: just a list of acceptance criteria in Gherkin format. 40 | 41 | # FEATURE REQUIREMENTS 42 | {requirements} 43 | 44 | # ORIGINAL USER STORY 45 | {user_story} 46 | 47 | # ENGINEER'S RESPONSE 48 | {engineer_response} 49 | 50 | # CLARIFIED USER STORY 51 | """ 52 | 53 | def split_requirements_to_features(role, 54 | requirements, 55 | evaluation, 56 | features): 57 | return f""" 58 | # INSTRUCTIONS 59 | As a {role}, your task is to take in: 60 | 61 | * requirements: high level requirements for the project 62 | * evaluation: previous feedback on the current features split 63 | * features: the current features split 64 | 65 | and, given all three, split the requirements into feature names by looking at the current features split and the previous evaluation. 66 | 67 | # REQUIREMENTS 68 | {requirements} 69 | 70 | # FEATURES 71 | {features} 72 | 73 | # EVALUATION 74 | {evaluation} 75 | 76 | # GUIDELINES 77 | 1. Review the current features split and the previous evaluation. 78 | 2. Split the requirements into features based on evaluation and these guidelines. 79 | 3. Name them by their business goal and purpose: DON'T start their name with "Implement" 80 | 4. To determine the appropriate granularity of the features make sure each feature is 81 | - focused on a single business aspect of the requirements 82 | - cohesive busineswise 83 | - prefer delivering incremental value to the user 84 | - for example if something can be delivered read only with a follow up feature to edit or change, prefer that 85 | 5. Ensure that an individual feature is NOT too small to implement. 86 | - example of TOO SMALL: 87 | - "edit one field" 88 | - "when naviated to a link user can see a view" 89 | - "display a button, component on the screen" 90 | - "validate email field", etc. 91 | 6. Return each feaure on a separate line. Do not add empty lines. 92 | 7. Return no other information, only a list of features. 93 | - NO additional text, headers, or footers 94 | 95 | Remember feature is not a small task, it is a business functionality 96 | Make sure that the list of feature names FULLY addresses every aspect of the requirements. 97 | think step by step before providing a response 98 | 99 | # RESPONSE FORMAT EXAMPLE 100 | : 101 | : 102 | : 103 | : 104 | : 105 | ... 106 | 107 | (!) return a list of features ONLY: no other headers, footers, or additional text 108 | """ 109 | 110 | def evaluate_features(role, features, requirements): 111 | return f""" 112 | # INSTRUCTIONS 113 | As a {role}, your task is to evaluate the following feature names against the original requirements and decide whether the feedback is needed. 114 | 115 | Your goal is to make sure requirements are split into features that are: 116 | - focused on a single business aspect of the requirements 117 | - cohesive busineswise 118 | - clear, concise 119 | - simple to implemented by the engineering team 120 | 121 | Remember feature is not a small task but a business functionality 122 | 123 | # FEATURES 124 | {features} 125 | 126 | # REQUIREMENTS 127 | {requirements} 128 | 129 | # RESPONSE FORMAT 130 | 131 | **chain of thought** 132 | 133 | 134 | **feedback about each feature** 135 | 136 | 137 | 138 | # GUIDELINES 139 | 1. Review features and assess whether it aligns with the original requirements 140 | - ask to remove any features that are not aligned with the requirements 141 | 2. Determine whether this split needs to change, provide feedback accordingly 142 | 3. (!) Prefer delivering incremental value to the user 143 | - for example if something can be delivered read only with a follow up feature to edit or change, prefer that 144 | 4. Ensure that an individual feature is NOT too small to implement. 145 | - example of TOO SMALL: 146 | - "edit one field" 147 | - "when naviated to a link user can see a view" 148 | - "display a button, component on the screen" 149 | - "validate email field", etc. 150 | 5. Don't include features that are satisfactory in the reponse 151 | 6. Stricly follow the "RESPONSE FORMAT" provided above 152 | 7. If the features are not split well and require to be split differently, provide feedback indicating so. 153 | 154 | Make sure that the list of feature names FULLY addresses every aspect of the requirements. 155 | (!) Only in case there no suggestions or improvements to ANY of the features in the list, reply with "APPROVED AND READY FOR REFINEMENT" in uppercase 156 | Remember, these are not full descriptions of the features, but a high-level feature names. 157 | """ 158 | 159 | def refine_feature(role, project_requiements, feature): 160 | return f""" 161 | # INSTRUCTIONS 162 | As a {role}, your task is to given the project requirements refine the business feature 163 | This feature was carefully carfted to be a single, isolated, cohesive piece of business functionality 164 | Please keep it that way while refining 165 | 166 | 167 | {project_requiements} 168 | 169 | 170 | {feature} 171 | 172 | # GUIDELINES 173 | 1. Analyze the feature and identify any areas that need improvement in terms of: 174 | - Cohesiveness: Ensure that the feature focuses on a single, specific functionality or business goal. 175 | - Size: Ensure that the feature is small enough to be easily understood and implemented. 176 | - Clarity: Ensure that the feature is clear, concise, and free of ambiguity. 177 | - Simplicity: Ensure that the feature is simple enough for an engineer to implement without requiring further clarification. 178 | 2. If any improvements are needed, refine the feature by making the necessary changes. 179 | 3. Return the refined feature. 180 | - don't share any additional information 181 | - only the refined feature name, description and the final list of detailed requirements 182 | 183 | Remember, the goal is to create a feature that is cohesive, small, clear, concise, and simple for the engineer to implement. 184 | 185 | # EXAMPLE RESPONSE 186 | 187 | ## "Edit Account Details Inside the Table Row" 188 | 189 | ### Description 190 | 191 | 192 | ### Requirements 193 | 194 | """ 195 | 196 | def combine_user_stories(role, 197 | requirements, 198 | user_stories): 199 | return f""" 200 | # INSTRUCTIONS 201 | As the {role}, your task is to combine the provided user stories, and the original requirements, combine these user stories into a single, cohesive set of requirements that has all the necessary details and instructions for implementation. 202 | 203 | # REQUIREMENTS 204 | {requirements} 205 | 206 | # USER STORIES 207 | {user_stories} 208 | 209 | # GUIDELINES 210 | 1. Review the original requirements and the provided user stories. 211 | 2. Combine the user stories into a single, cohesive set of requirements that cover all the necessary details. 212 | 3. Ensure that the combined requirements are clear, concise, and free of ambiguity. 213 | 4. Make sure the combined requirements are detailed enough for an engineer to implement without requiring further clarification. 214 | 5. Return the combined requirements. 215 | - don't share any additional information 216 | """ 217 | 218 | def idea_to_prompt(idea): 219 | return f""" 220 | Title: Web App Prototype Prompt Generator 221 | 222 | Description: 223 | Create a prompt generator that takes a short-form web app idea and generates a detailed prompt for building a self-sufficient prototype using only HTML, CSS, and JavaScript. The generated prompt should guide an AI model to create a functional web app prototype based on the provided idea. 224 | 225 | Web App Idea: 226 | {idea} 227 | 228 | Prompt: 229 | [Web App Idea] 230 | Description: [A brief description of the web app idea] 231 | 232 | Desired Prompt Output: 233 | 234 | Title: [Web App Name] 235 | 236 | Description: 237 | [A detailed description of the web app, including its purpose, main features, and target audience] 238 | 239 | Requirements: 240 | 1. [Requirement 1] 241 | 2. [Requirement 2] 242 | 3. [Requirement 3] 243 | ... 244 | 245 | User Interface: 246 | [A description of the desired user interface, including layout, design elements, and user interactions] 247 | 248 | Functionality: 249 | [Detailed explanations of the app's functionality, including any necessary algorithms, data processing, or dynamic behavior] 250 | 251 | HTML Structure: 252 | [Guidelines for structuring the HTML code, including specific elements, classes, and IDs to be used] 253 | 254 | CSS Styling: 255 | [Instructions for styling the app using CSS, including color scheme, typography, layout, and responsive design considerations] 256 | 257 | JavaScript Interactivity: 258 | [Directions for implementing interactivity and dynamic functionality using JavaScript, including event handling, data manipulation, and API integration if applicable] 259 | 260 | Additional Considerations: 261 | [Any additional features, optimizations, or best practices to keep in mind while building the prototype] 262 | 263 | Note: The generated prompt should be clear, concise, and provide sufficient detail for an AI model to generate a functional web app prototype using only HTML, CSS, and JavaScript. The prompt should focus on guiding the model to create a self-sufficient prototype without relying on external libraries or frameworks. 264 | 265 | Example Usage: 266 | Input: 267 | [Web App Idea]: Color Palette Generator 268 | Description: A web app that generates color palettes based on user input, allowing users to discover and save color combinations for their projects. 269 | 270 | Output: 271 | Title: Color Palette Generator 272 | 273 | Description: 274 | The Color Palette Generator is a web app that helps users create, discover, and save beautiful color palettes for their design projects. Users can input a base color or select a random color, and the app will generate a visually appealing color palette based on color theory principles. The app will display the color palette along with the hex codes and RGB values for each color. Users can adjust the brightness and saturation of the colors, save their favorite palettes, and export them for use in their projects. 275 | 276 | Requirements: 277 | 1. Color input: Allow users to input a base color using a color picker or by entering a hex code. 278 | 2. Random color generation: Provide an option to generate a random base color for the palette. 279 | 3. Color palette generation: Generate a visually appealing color palette based on the base color using color theory principles (e.g., complementary, analogous, triadic). 280 | 4. Color palette display: Show the generated color palette with the hex codes and RGB values for each color. 281 | 5. Color adjustment: Allow users to adjust the brightness and saturation of the colors in the palette. 282 | 6. Palette saving: Enable users to save their favorite color palettes for future reference. 283 | 7. Palette export: Provide options to export the color palette as an image or CSS code snippet. 284 | 285 | User Interface: 286 | The Color Palette Generator should have a clean, intuitive, and visually appealing user interface. The main section of the app should display the generated color palette, with each color shown as a large swatch along with its hex code and RGB values. The color input and random color generation options should be prominently placed above the palette. The color adjustment controls should be located below the palette, allowing users to easily tweak the brightness and saturation. The save and export options should be easily accessible, with clear labels and icons. 287 | 288 | Functionality: 289 | The app should use JavaScript to handle color input, generation, and manipulation. When a user inputs a base color or selects the random color option, the app should generate a color palette using predefined color theory algorithms. The generated colors should be displayed dynamically on the page, with their hex codes and RGB values updated in real-time. The color adjustment controls should use range sliders to allow users to modify the brightness and saturation of the colors. The adjusted colors should be updated instantly in the palette display. The save functionality should store the user's favorite palettes in the browser's local storage, while the export options should generate downloadable files or copy CSS code snippets to the clipboard. 290 | 291 | HTML Structure: 292 | The HTML structure should be semantically marked up and include the following main elements: 293 | - Header with the app title and navigation menu 294 | - Main section with the color input, random color button, and color palette display 295 | - Color adjustment controls below the palette 296 | - Save and export buttons 297 | - Footer with any necessary information or links 298 | 299 | Use appropriate classes and IDs for styling and JavaScript manipulation. 300 | 301 | CSS Styling: 302 | The CSS should provide an attractive and responsive design for the Color Palette Generator. Use a clean, modern color scheme that complements the generated color palettes. Ensure proper spacing, alignment, and sizing of elements. Use CSS Grid or Flexbox for the layout, and apply hover and focus states for interactive elements. Make the app responsive and mobile-friendly using media queries and relative units. 303 | 304 | JavaScript Interactivity: 305 | Use JavaScript to add interactivity and functionality to the app. Implement the following features: 306 | - Color input and validation 307 | - Random color generation 308 | - Color palette generation based on color theory algorithms 309 | - Real-time updates of color swatches, hex codes, and RGB values 310 | - Color adjustment using range sliders 311 | - Saving and loading of favorite palettes using local storage 312 | - Exporting palettes as images or CSS code snippets 313 | 314 | Organize the JavaScript code into modular functions and use descriptive variable and function names for clarity. 315 | 316 | Additional Considerations: 317 | - Implement accessibility best practices, such as proper color contrast and keyboard navigation support. 318 | - Optimize the app's performance by minimizing DOM manipulation and using efficient algorithms for color generation and manipulation. 319 | - Add error handling and validation for user inputs to ensure a smooth user experience. 320 | - Consider adding a feature to share color palettes on social media or via unique URLs. 321 | - Provide a help section or tutorial to guide users on how to use the app effectively. 322 | 323 | By following this prompt, an AI model should be able to generate a self-sufficient and functional prototype of the Color Palette Generator web app using HTML, CSS, and JavaScript. The prototype should fulfill the specified requirements, provide an engaging user interface, and demonstrate the core functionality of the app idea. 324 | """ 325 | 326 | def design_to_requirements(idea, design): 327 | return f""" 328 | Title: Web App Prototype Prompt Generator 329 | 330 | Description: 331 | Create a prompt generator that takes a short-form web app idea and a description of a mockup and generates a detailed prompt for building a self-sufficient prototype using only HTML, CSS, and JavaScript. The generated prompt should guide an AI model to create a functional web app prototype based on the provided idea and the mockup description. The generated prompt should make sure that the prototype 100% aligns with the visual structure and interactivity described in the mockup. 332 | 333 | Web App Idea: 334 | {idea} 335 | 336 | Mockup Description: 337 | {design} 338 | 339 | Prompt: 340 | [Web App Idea] 341 | Description: [A brief description of the web app idea] 342 | 343 | Desired Prompt Output: 344 | 345 | Title: [Web App Name] 346 | 347 | Description: 348 | [A detailed description of the web app, including its purpose, main features, and target audience] 349 | 350 | Requirements: 351 | 1. [Requirement 1] 352 | 2. [Requirement 2] 353 | 3. [Requirement 3] 354 | ... 355 | 356 | User Interface: 357 | [A description of the desired user interface, including layout, design elements, and user interactions based on the idea and mockup description] 358 | 359 | Functionality: 360 | [Detailed explanations of the app's functionality, including any necessary algorithms, data processing, or dynamic behavior based on the idea and mockup description] 361 | 362 | HTML Structure: 363 | [Guidelines for structuring the HTML code, including specific elements, classes, and IDs to be used based on the idea and mockup description] 364 | 365 | CSS Styling: 366 | [Instructions for styling the app using CSS, including color scheme, typography, layout, and responsive design considerations based on the idea and mockup description] 367 | 368 | JavaScript Interactivity: 369 | [Directions for implementing interactivity and dynamic functionality using JavaScript, including event handling, data manipulation, and API integration if applicable based on the idea and mockup description] 370 | 371 | Additional Considerations: 372 | [Any additional features, optimizations, or best practices to keep in mind while building the prototype based on the idea and mockup description] 373 | 374 | Note: The generated prompt should be clear, concise, and provide sufficient detail for an AI model to generate a functional web app prototype using only HTML, CSS, and JavaScript. The prompt should focus on guiding the model to create a self-sufficient prototype relying on jQuery, Twitter Bootstrap and DataTable libraries. 375 | """ 376 | -------------------------------------------------------------------------------- /jemma/prompt/engineer/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tolitius/jemma/6b2ec2979a733f7a99c9ff698dc253239ea0d9de/jemma/prompt/engineer/__init__.py -------------------------------------------------------------------------------- /jemma/prompt/engineer/clarify.py: -------------------------------------------------------------------------------- 1 | def check_whether_clarification_needed(requirements, user_story): 2 | return f""" 3 | # INSTRUCTIONS 4 | As an experienced software engineer, your task is to carefully review the provided user story and determine if you have enough information to implement it precisely based on the project requirements. 5 | 6 | Thoroughly analyze the user story and identify any missing, ambiguous, or unclear details that could impact the implementation. Consider the following aspects: 7 | 8 | - all the necessary functionalities and behaviors clearly defined 9 | - specific requirements about system integration 10 | - any edge cases or exceptional scenarios to consider 11 | - any specific performance criteria or constraints to consider 12 | - how should the feature integrate with existing systems or components 13 | - any security considerations or requirements 14 | 15 | you job is to see which of the above options apply to the user story 16 | NONE or some could apply, depending on the user story context 17 | 18 | If any information is missing or unclear, provide a list of specific questions or points that require further clarification from the business owner. Each clarification request should be clear, concise, and directly related to the implementation of the user story. 19 | 20 | Make sure the clarifications and questions are ONLY about the content the user story itself vs. other non relevant requiements of the project. 21 | 22 | Only share the final set of questions wit no headers, no footers, no explanations, just the questions. 23 | (!) Only if the user story is already complete and no further clarification is needed respond with "No clarification needed." 24 | 25 | # PROJECT REQUIREMENTS 26 | {requirements} 27 | 28 | # USER STORY 29 | {user_story} 30 | 31 | # ENGINEER'S RESPONSE 32 | """ 33 | -------------------------------------------------------------------------------- /jemma/prompt/engineer/code.py: -------------------------------------------------------------------------------- 1 | def create_css_file(requirements): 2 | return f""" 3 | You are a CSS expert with deep knowledge of Twitter Bootstrap CSS framework. 4 | 5 | Your task is to generate a complete and working CSS file for a web prototype based on a twitter's "bootstrap.css" framework and the following requirements: 6 | 7 | # REQUIREMENTS 8 | {requirements} 9 | 10 | follow these guidelines to create the CSS file: 11 | 12 | # GUIDELINES 13 | - Implement a color scheme with pastel colors that creates a pleasing atmosphere. 14 | - USE colors on a brighter side effectively to create visual hierarchy, highlight important elements, and convey the desired mood. 15 | - Use appropriate margins, paddings, and spacing to create a balanced and visually pleasing arrangement. 16 | - (!) make sure DataTables are styled and flexible width so they don't overflow 17 | - Choose a clean and readable font family for headings and body text 18 | - make font small enough to fit the content 19 | - Make sure top and side margins and paddings make user focus on the main content 20 | - Use Bootstrap's grid system to create a responsive layout 21 | - align menu items in a single row whether it is vertical or horizontal 22 | 23 | Please generate a complete CSS file that fulfills these requirements and provides a beautiful, user-friendly, and responsive design for the web prototype. The generated CSS file should be ready to be integrated with the corresponding HTML and JavaScript files. 24 | 25 | do NOT surround the file with markdown backticks: ```css ... ``` 26 | start the response with /* Global Styles */ and follow with CSS source according the guidelines. 27 | 28 | # IMPORTANT 29 | Provide the CSS file content ONLY, without any additional text or explanations. The CSS file should be well-structured, organized, and easy to understand for developers working on the web prototype. 30 | 31 | (!) make sure ALL the requirements and actions are addressed in the CSS file. 32 | """ 33 | 34 | 35 | def create_javascript_file(requirements, css): 36 | return f""" 37 | You are a JavaScript expert who specializes in jQuery with a focus on Twitter Bootstrap and DataTables libraries. 38 | 39 | Given requirements and a CSS file (based on "bootstrap.css") your task is to generate a JavaScript file that utilizes the jQuery library to create an interactive and dynamic web prototype based on these requirements that relies on that CSS file. 40 | 41 | for tables, use a DataTables jQuery plugin to enhance the functionality and appearance of the tables. 42 | 43 | This JavaScript file should be self-contained as this would be the only file that would be used to run the web prototype. 44 | 45 | # REQUIREMENTS 46 | {requirements} 47 | 48 | # CSS FILE 49 | {css} 50 | 51 | follow these guidelines to create the JavaScript file: 52 | 53 | # GUIDELINES 54 | - Make sure layout pieces do not overlap or are not hidden by other elements. 55 | - Make sure tables are used to store grid and tabular data 56 | - Ensure that the generated JavaScript file seamlessly integrates with the provided CSS file. 57 | - Instead of calling backend APIs populate test data or MINIMUM 7 entries in the JavaScript file to simulate the dynamic behavior of the web prototype. 58 | - doublechek that the data is visible to the user 59 | - doublecheck that the data is POPULATED 60 | - Make sure edits happen in either inline within the table rows or in a modal window. 61 | - do not forget to close all the code forms in parentheses, brackets, etc. $(function() {{ foo = [..] }}); 62 | - don't use todo action comments such as "// Add more test data here" or "// add code for to do X": instead IMPLEMENT the data / action 63 | 64 | do NOT surround the file with markdown backticks: ```javascript ... ``` 65 | - start your response with a comment "// jQuery implementation" 66 | - followed by the source code according to guidelines. 67 | - ending with a comment "// prototype implementation" 68 | 69 | IMPORTANT: Provide the JavaScript file content ONLY, without any additional text or explanations. The JavaScript file should be well-structured, organized, and easy to understand for developers working on the web prototype. 70 | 71 | # IMPORTANT 72 | (!) make sure ALL the requirements and actions are addressed in the JavaScript file. 73 | """ 74 | 75 | def create_html_file(requirements, css, js): 76 | return f""" 77 | Code Generator Agent, 78 | 79 | Given requirements, a CSS file (based on "bootstrap.css"), and a JavaScript file, your task is to generate a complete and semantic HTML file that serves as the foundation for the web prototype based on these requirements. 80 | The HTML file should import these in the following order: 81 | 82 | - remote "bootrap.css" 83 | - remote dataTables css (for bootstrap 4, "dataTables.bootstrap4.css") 84 | - local, previously generated, CSS: app.css 85 | - remote jQuery library 86 | - remote "popper.js" 87 | - remote "bootrap.js" 88 | - remote dataTables js 89 | - remote dataTables js (for bootstrap 4, "dataTables.bootstrap4.js") 90 | - local, previously generated, JavaScript: app.js 91 | 92 | example: 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | and adhere to the following requirements to create the best layout and user experience possible. 105 | 106 | # REQUIREMENTS 107 | {requirements} 108 | 109 | # CSS FILE 110 | {css} 111 | 112 | # JAVASCRIPT FILE 113 | {js} 114 | 115 | follow these guidelines to create the HTML file: 116 | 117 | # GUIDELINES 118 | 119 | - Link the previously generated CSS file in the head section using the appropriate `` tag. 120 | - Place the previously generated JavaScript file before the closing `` tag using the ` 219 | 220 | 221 | 222 | Remember, the goal is to create a self-contained, functional, and visually appealing prototype that showcases the core aspects of the user story. The prototype should be easily understandable by stakeholders and developers alike. 223 | 224 | """ 225 | 226 | def refactor_css_file(requirements, 227 | prototype_css, 228 | feedback): 229 | return f""" 230 | Given the following information: 231 | 232 | Original Requirements: 233 | {requirements} 234 | 235 | Existing Prototype CSS (using Twitter Bootstrap): 236 | {prototype_css} 237 | 238 | User Feedback: 239 | {feedback} 240 | 241 | Please refactor the CSS code, taking into account the original requirements and the user's feedback. Consider the following points: 242 | 243 | 1. Ensure that the refactored CSS aligns with the original requirements and incorporates the user's suggestions where appropriate. 244 | 2. Optimize the CSS for better performance, readability, and maintainability. 245 | 3. Use best practices and modern CSS techniques where applicable. 246 | 4. Keep in mind that the CSS code is using the Twitter Bootstrap library, so make sure to leverage Bootstrap classes and conventions where appropriate. 247 | 248 | do NOT surround the file with markdown backticks: ```css ... ``` 249 | start the response with /* Global Styles */ and follow with CSS source according the guidelines. 250 | 251 | Please provide only the refactored CSS code without any additional explanations or comments. The code will be written into a separate "app.css" file. 252 | """ 253 | 254 | def refactor_javascript_file(requirements, 255 | css, 256 | prototype_js, 257 | feedback): 258 | return f""" 259 | Given the following information: 260 | 261 | Original Requirements: 262 | {requirements} 263 | 264 | Refactored CSS (using Twitter Bootstrap): 265 | {css} 266 | 267 | Existing Prototype JavaScript (using jQuery and DataTables): 268 | {prototype_js} 269 | 270 | User Feedback: 271 | {feedback} 272 | 273 | Please refactor the JavaScript code, taking into account the original requirements, the refactored CSS, and the user's feedback. Consider the following points: 274 | 275 | 1. Ensure that the refactored JavaScript aligns with the original requirements and incorporates the user's suggestions where appropriate. 276 | 2. Optimize the JavaScript for better performance, readability, and maintainability. 277 | 3. Use best practices and modern JavaScript techniques where applicable. 278 | 4. Keep in mind that the JavaScript code is using the jQuery library and the DataTables plugin, so make sure to leverage their features and conventions where appropriate. 279 | 5. Ensure compatibility with the refactored CSS code, especially considering the use of Twitter Bootstrap classes and conventions. 280 | 281 | do NOT surround the file with markdown backticks: ```javascript ... ``` 282 | - start your response with a comment "// jQuery implementation" 283 | - followed by the source code according to guidelines. 284 | - ending with a comment "// prototype implementation" 285 | 286 | Please provide only the refactored JavaScript code without any additional explanations or comments. The code will be written into a separate "app.js" file. 287 | """ 288 | 289 | def refactor_html_file(requirements, 290 | css, 291 | js, 292 | prototype_html, 293 | feedback): 294 | return f""" 295 | Given the following information: 296 | 297 | Original Requirements: 298 | {requirements} 299 | 300 | Refactored CSS (using Twitter Bootstrap): 301 | {css} 302 | 303 | Refactored JavaScript (using jQuery and DataTables): 304 | {js} 305 | 306 | Existing Prototype HTML: 307 | {prototype_html} 308 | 309 | User Feedback: 310 | {feedback} 311 | 312 | Please refactor the HTML code, taking into account the original requirements, the refactored CSS and JavaScript, and the user's feedback. Consider the following points: 313 | 314 | 1. Ensure that the refactored HTML aligns with the original requirements and incorporates the user's suggestions where appropriate. 315 | 2. Optimize the HTML structure for better semantics, accessibility, and SEO. 316 | 3. Use appropriate HTML5 elements and attributes where applicable. 317 | 4. Ensure compatibility with the refactored CSS code, especially considering the use of Twitter Bootstrap classes and conventions. 318 | 5. Integrate the refactored JavaScript code seamlessly, making sure that all necessary elements have the correct IDs, classes, and data attributes required by jQuery and DataTables. 319 | 6. Improve the overall user experience and usability of the HTML page based on the user's feedback. 320 | 321 | do NOT surround the file with markdown backticks: ```html ... ``` 322 | start the response with and follow the instructions. 323 | 324 | Please provide only the refactored HTML code without any additional explanations, comments. The code will be written into a separate "index.html" file. 325 | """ 326 | -------------------------------------------------------------------------------- /jemma/prompt/engineer/game.py: -------------------------------------------------------------------------------- 1 | def create_css_file(requirements): 2 | return f""" 3 | You are a CSS expert with deep knowledge of Phaser HTML5 game framework. 4 | 5 | Your task is to generate a complete and working CSS file for a web prototype based on the Phaser framework and the following requirements: 6 | 7 | # REQUIREMENTS 8 | {requirements} 9 | 10 | follow these guidelines to create the CSS file: 11 | 12 | # GUIDELINES 13 | - Implement a color scheme with pastel colors that creates a pleasing atmosphere. 14 | - USE colors on a brighter side effectively to create visual hierarchy, highlight important elements, and convey the desired mood. 15 | - Use appropriate margins, paddings, and spacing to create a balanced and visually pleasing arrangement. 16 | - (!) make sure DataTables are styled and flexible width so they don't overflow 17 | - Choose a clean and readable font family for headings and body text 18 | - make font small enough to fit the content 19 | - Make sure top and side margins and paddings make user focus on the main content 20 | - Use Bootstrap's grid system to create a responsive layout 21 | - align menu items in a single row whether it is vertical or horizontal 22 | 23 | Please generate a complete CSS file that fulfills these requirements and provides a beautiful, user-friendly, and responsive design for the web prototype. The generated CSS file should be ready to be integrated with the corresponding HTML and JavaScript files. 24 | 25 | do NOT surround the file with markdown backticks: ```css ... ``` 26 | start the response with /* Global Styles */ and follow with CSS source according the guidelines. 27 | 28 | make sure the game-container and game-canvas are styled by ids as follows: 29 | #game-container {{ 30 | display: flex; 31 | flex-direction: column; 32 | align-items: center; 33 | justify-content: center; 34 | }} 35 | #game-canvas {{ 36 | border: 2px solid #00FFFF; 37 | box-shadow: 0 0 20px 0 #00FFFF; 38 | }} 39 | 40 | 41 | (!) Use Phaser's default styles as a starting point and customize them as needed to match the game's aesthetic requirements. Since we are using built-in shapes instead of images, focus on styling the shapes using CSS properties like background color, border, and border-radius." 42 | 43 | EXAMPLE OF USING DEFAULT SHAPES IN PHASER: 44 | .paddle {{ 45 | background-color: white; 46 | border-radius: 10px; 47 | }} 48 | 49 | .ball {{ 50 | background-color: white; 51 | border-radius: 50%; 52 | }} 53 | 54 | .brick {{ 55 | background-color: red; 56 | border: 1px solid black; 57 | }} 58 | 59 | # IMPORTANT 60 | Provide the CSS file content ONLY, without any additional text or explanations. The CSS file should be well-structured, organized, and easy to understand for developers working on the web prototype. 61 | 62 | (!) make sure ALL the requirements and actions are addressed in the CSS file. 63 | """ 64 | 65 | 66 | def create_javascript_file(requirements, css): 67 | return f""" 68 | You are a JavaScript expert who specializes in game development with a focus on Phaser HTML5 game framework. 69 | 70 | Given requirements and a CSS file (based on Phaser framework) your task is to generate a JavaScript file that utilizes the the Phaser framework to create an interactive and dynamic web prototype based on these requirements that relies on that CSS file. 71 | 72 | This JavaScript file should be self-contained as this would be the only file that would be used to run the web prototype. 73 | 74 | # REQUIREMENTS 75 | {requirements} 76 | 77 | # CSS FILE 78 | {css} 79 | 80 | follow these guidelines to create the JavaScript file: 81 | 82 | # GUIDELINES 83 | The game implementation should include the following features and components: 84 | 85 | 1. Game Board: 86 | - Create a visually appealing game board using Phaser's graphics objects to represent the play area. 87 | - Design the game board to match the theme and style of the game. 88 | 89 | 2. Player Character: 90 | - Create a player character using appropriate shapes and position it on the game board. 91 | - Implement player character movement and controls based on user input (e.g., arrow keys, touch controls). 92 | - Ensure the player character interacts properly with other game elements and stays within the game boundaries. 93 | 94 | 3. Game Objects: 95 | - Create various game objects (e.g., obstacles, enemies, collectibles) using suitable shapes and position them on the game board. 96 | - Implement collision detection between the player character and game objects. 97 | - Define the behavior and effects of game objects when they interact with the player character. 98 | 99 | 4. Scoring and Progression: 100 | - Implement a scoring system that awards points based on player actions and achievements. 101 | - Create a visual display to show the current score, level, and other relevant information. 102 | - Define conditions for level progression and implement level transitions seamlessly. 103 | 104 | 5. Power-ups and Bonuses: 105 | - Implement power-ups and bonuses that enhance gameplay and provide temporary advantages to the player. 106 | - Spawn power-ups and bonuses at appropriate times and locations on the game board. 107 | - Define the effects and duration of each power-up and bonus. 108 | 109 | 6. User Interface: 110 | - Create an intuitive and visually appealing user interface for the game. 111 | - Implement menus, buttons, and text displays for game controls, settings, and information. 112 | - Ensure the user interface is responsive and provides a smooth user experience. 113 | 114 | 7. Sound and Visual Effects: 115 | - Make sure there is no sound in the game 116 | - Create visual effects (e.g., particle effects, animations) to provide visual feedback and enhance the game's aesthetics. 117 | 118 | 8. Game State Management: 119 | - Implement proper game state management, including game start, pause, resume, and game over states. 120 | - Define conditions for game over and level completion, and handle these events appropriately. 121 | - Allow players to restart the game or return to the main menu after game over. 122 | 123 | 9. Code Organization and Best Practices: 124 | - Organize the code into logical modules and functions for better readability and maintainability. 125 | - Use meaningful variable and function names that describe their purpose. 126 | - Follow best practices for code formatting, indentation, and commenting. 127 | - Optimize the code for performance and consider mobile compatibility if applicable. 128 | 129 | 10. Testing and Debugging: 130 | - Thoroughly test the game to identify and fix any bugs or glitches. 131 | - Ensure the game runs smoothly on different devices and browsers. 132 | - Implement error handling and logging mechanisms for easier debugging and troubleshooting. 133 | 134 | - Ensure that the generated JavaScript file seamlessly integrates with the provided CSS file. 135 | - do not forget to close all the code forms in parentheses, brackets, etc. $(function() {{ foo = [..] }}); 136 | - don't use todo action comments such as "// Add more test data here" or "// add code for to do X": instead IMPLEMENT the data / action 137 | 138 | Implement the startGame function completely, including all the necessary game logic and interactions. The startGame function should be the entry point for the game and should set up the game environment, initialize game objects, and start the game loop. 139 | 140 | do not include a "preload" function since we are not using images, but instead built-in shapes such as "circles, squares, dots, etc.". 141 | 142 | instead use basic shapes in "create" function to represent game elements. 143 | ### EXAMPLE OF USING BUILT-IN SHAPES IN PHASER CREATE FUNCTION: 144 | function create() {{ 145 | // Set up the game world 146 | game.physics.startSystem(Phaser.Physics.ARCADE); 147 | game.stage.backgroundColor = '#000000'; 148 | 149 | // Create the player's spaceship 150 | player = game.add.graphics(400, 550); 151 | player.beginFill(0xffffff); 152 | player.drawRect(-20, -20, 40, 40); 153 | player.endFill(); 154 | game.physics.arcade.enable(player); 155 | player.body.collideWorldBounds = true; 156 | player.body.immovable = true; 157 | 158 | // Create the enemy ships 159 | enemies = game.add.group(); 160 | enemies.enableBody = true; 161 | enemies.physicsBodyType = Phaser.Physics.ARCADE; 162 | 163 | // Create the player's projectiles 164 | playerProjectiles = game.add.group(); 165 | playerProjectiles.enableBody = true; 166 | playerProjectiles.physicsBodyType = Phaser.Physics.ARCADE; 167 | 168 | // Create the enemy projectiles 169 | enemyProjectiles = game.add.group(); 170 | enemyProjectiles.enableBody = true; 171 | enemyProjectiles.physicsBodyType = Phaser.Physics.ARCADE; 172 | 173 | // Create the UI elements 174 | scoreText = game.add.text(16, 16, 'Score: 0', {{ fontSize: '32px', fill: '#fff' }}); 175 | highScoreText = game.add.text(game.width - 200, 16, 'High Score: 0', {{ fontSize: '32px', fill: '#fff' }}); 176 | startButton = game.add.text(game.width / 2, game.height / 2, 'Start Game', {{ fontSize: '24px', fill: '#fff' }}); 177 | startButton.anchor.set(0.5); 178 | startButton.inputEnabled = true; 179 | startButton.events.onInputDown.add(startGame, this); 180 | 181 | // Initialize game variables 182 | score = 0; 183 | highScore = 0; 184 | gameStarted = false; 185 | }} 186 | 187 | make action functions to to create basic shapes instead of using loaded assets 188 | ### EXAMPLE OF ACTION FUNCTION TO CREATE BASIC SHAPES: 189 | function fireBullet(x, y, xVelocity, yVelocity, group) {{ 190 | var bullet = group.create(x, y, null); 191 | var graphics = game.add.graphics(0, 0); 192 | graphics.beginFill(0x00FF00); 193 | graphics.drawRect(0, 0, 10, 20); 194 | graphics.endFill(); 195 | bullet.addChild(graphics); 196 | bullet.body.velocity.x = xVelocity; 197 | bullet.body.velocity.y = yVelocity; 198 | }} 199 | 200 | since we are using built-in shapes, 201 | make sure to create individual Sprite objects for each object and then draw the shapes on those sprites. 202 | ### EXAMPLE OF CREATING SPRITES AND DRAWING SHAPES: 203 | function spawnEnemies() {{ 204 | if (enemies.countLiving() === 0) {{ 205 | for (var y = 100; y < 400; y += 50) {{ 206 | for (var x = 100; x < 700; x += 50) {{ 207 | var enemy = enemies.create(x, y, null); 208 | var graphics = game.add.graphics(0, 0); 209 | graphics.beginFill(0xFF0000); 210 | graphics.drawCircle(0, 0, 20); 211 | graphics.endFill(); 212 | enemy.addChild(graphics); 213 | enemy.body.velocity.y = ENEMY_SPEED; 214 | }} 215 | }} 216 | }} 217 | }} 218 | 219 | make sure to load the game in Phaser that matches CSS sizing as well as attaches to the game container: 220 | parent: 'game-container', 221 | canvas: document.getElementById('game-canvas'), 222 | 223 | ### EXAMPLE OF LOADING THE GAME IN PHASER: 224 | // make sure the Phaser Game starts exactly like this: 225 | var game = new Phaser.Game({{ 226 | width: 800, // Match the CSS 227 | height: 600, // Match the CSS 228 | renderer: Phaser.AUTO, 229 | parent: 'game-container', 230 | canvas: document.getElementById('game-canvas'), 231 | state: {{ preload: preload, create: create, update: update }} 232 | }}); 233 | 234 | make sure not to play an animation on a sprite that doesn't have a loaded texture or spritesheet 235 | for this add a remove effects correctly: 236 | ### EXAMPLE OF REMOVING EFFECTS: 237 | function createExplosion(x, y) {{ 238 | var explosion = explosions.create(x, y, null); 239 | var graphics = game.add.graphics(0, 0); 240 | graphics.beginFill(0xFF9900); 241 | graphics.drawCircle(0, 0, 50); 242 | graphics.endFill(); 243 | explosion.addChild(graphics); 244 | explosion.scale.set(0.5); 245 | 246 | // Remove the explosion after a short delay 247 | game.time.events.add(200, function() {{ 248 | explosion.kill(); 249 | }}, this); 250 | }} 251 | 252 | do NOT surround the file with markdown backticks: ```javascript ... ``` 253 | - start your response with a comment "// game implementation" 254 | - followed by the source code according to guidelines. 255 | - ending with a comment "// built by Jemma with bytes" 256 | 257 | IMPORTANT: Provide the JavaScript file content ONLY, without any additional text or explanations. The JavaScript file should be well-structured, organized, and easy to understand for developers working on the web prototype. 258 | 259 | (!) Use Phaser's built-in shapes like Rectangle, Circle, and Graphics to represent game elements instead of loading external images. 260 | 261 | # EXAMPLE OF USING BUILT-IN SHAPES IN PHASER: 262 | // Create the paddle 263 | let paddle = this.add.rectangle(400, 550, 120, 20, 0xffffff); 264 | 265 | // Create the ball 266 | let ball = this.add.circle(400, 300, 10, 0xffffff); 267 | 268 | // Create the bricks 269 | let bricks = this.add.group(); 270 | for (let row = 0; row < 4; row++) {{ 271 | for (let col = 0; col < 10; col++) {{ 272 | let brick = this.add.rectangle(col * 80 + 40, row * 40 + 40, 70, 30, 0xff0000); 273 | bricks.add(brick); 274 | }} 275 | }} 276 | 277 | 278 | # IMPORTANT 279 | (!) make sure ALL the requirements and actions are addressed in the JavaScript file. 280 | """ 281 | 282 | def create_html_file(requirements, css, js): 283 | return f""" 284 | You are a web developer with deep expertise in HTML5 creating interactive web games using Phaser game framework, HTML5, CSS, and JavaScript. 285 | 286 | Given requirements, a CSS file (based on Phaser), and a JavaScript file, your task is to generate a complete and semantic HTML file that serves as the foundation for the web based game based on these requirements. 287 | The HTML file should import these in the following order: 288 | 289 | - local, previously generated, CSS: app.css 290 | - remote Phaser framework library ("https://cdnjs.cloudflare.com/ajax/libs/phaser/2.6.2/phaser.js") 291 | - local, previously generated, JavaScript: app.js 292 | 293 | and adhere to the following requirements to create the best layout and user experience possible. 294 | 295 | # REQUIREMENTS 296 | {requirements} 297 | 298 | # CSS FILE 299 | {css} 300 | 301 | # JAVASCRIPT FILE 302 | {js} 303 | 304 | HTML body should only have the "game-container" div and NO OTHER COMPONENTS: 305 | ### EXAMPLE OF HTML BODY: 306 | 307 | 308 | 309 | Retro Galaga Game 310 | 311 | 312 | 313 | 314 |
315 | 316 | 317 | 318 | 319 | 320 | do not add scores, buttons, or any other elements to the HTML file. The game will be controlled by the JavaScript file and styled by the CSS file. 321 | 322 | IMPORTANT: Provide the HTML file content ONLY, without any additional text or explanations: no text headers, no footers. 323 | do NOT surround the file with markdown backticks: ```html ... ``` 324 | start the response with and end with 325 | """ 326 | 327 | 328 | 329 | ## TODO: refactor prompts 330 | def refactor_css_file(requirements, 331 | prototype_css, 332 | feedback): 333 | return f""" 334 | Given the following information: 335 | 336 | Original Requirements: 337 | {requirements} 338 | 339 | Existing Prototype CSS (using Phaser HTML5 game framework): 340 | {prototype_css} 341 | 342 | User Feedback: 343 | {feedback} 344 | 345 | Please refactor the CSS code, taking into account the original requirements and the user's feedback. Consider the following points: 346 | 347 | 1. Ensure that the refactored CSS aligns with the original requirements and incorporates the user's suggestions where appropriate. 348 | 2. Optimize the CSS for better performance, readability, and maintainability. 349 | 3. Use best practices and modern CSS techniques where applicable. 350 | 4. Keep in mind that the CSS code is using the Phaserlibrary, so make sure to leverage Phaser conventions where appropriate. 351 | 352 | do NOT surround the file with markdown backticks: ```css ... ``` 353 | start the response with /* Global Styles */ and follow with CSS source according the guidelines. 354 | 355 | Please provide only the refactored CSS code without any additional explanations or comments. The code will be written into a separate "app.css" file. 356 | """ 357 | 358 | def refactor_javascript_file(requirements, 359 | css, 360 | prototype_js, 361 | feedback): 362 | return f""" 363 | Given the following information: 364 | 365 | Original Requirements: 366 | {requirements} 367 | 368 | Refactored CSS (using Phaser HTML5 game framework): 369 | {css} 370 | 371 | Existing Prototype JavaScript (using Phaser HTML5 game framework): 372 | {prototype_js} 373 | 374 | User Feedback: 375 | {feedback} 376 | 377 | Please refactor the JavaScript code, taking into account the original requirements, the refactored CSS, and the user's feedback. Consider the following points: 378 | 379 | 1. Ensure that the refactored JavaScript aligns with the original requirements and incorporates the user's suggestions where appropriate. 380 | 2. Optimize the JavaScript for better performance, readability, and maintainability. 381 | 3. Use best practices and modern JavaScript techniques where applicable. 382 | 4. Keep in mind that the JavaScript code is using the Phaser HTML5 game framework, so make sure to leverage their features and conventions where appropriate. 383 | 5. Ensure compatibility with the refactored CSS code, especially considering the use of Phaser. 384 | 385 | do NOT surround the file with markdown backticks: ```javascript ... ``` 386 | - start your response with a comment "// game implementation" 387 | - followed by the source code according to guidelines. 388 | - ending with a comment "// improved by Jemma with bytes" 389 | 390 | Please provide only the refactored JavaScript code without any additional explanations or comments. The code will be written into a separate "app.js" file. 391 | """ 392 | 393 | def refactor_html_file(requirements, 394 | css, 395 | js, 396 | prototype_html, 397 | feedback): 398 | return f""" 399 | Given the following information: 400 | 401 | Original Requirements: 402 | {requirements} 403 | 404 | Refactored CSS (using Phaser HTML5 game framework): 405 | {css} 406 | 407 | Refactored JavaScript (using Phaser HTML5 game framework): 408 | {js} 409 | 410 | Existing Prototype HTML: 411 | {prototype_html} 412 | 413 | User Feedback: 414 | {feedback} 415 | 416 | Please refactor the HTML code, taking into account the original requirements, the refactored CSS and JavaScript, and the user's feedback. Consider the following points: 417 | 418 | 1. Ensure that the refactored HTML aligns with the original requirements and incorporates the user's suggestions where appropriate. 419 | 2. Optimize the HTML structure for better semantics, accessibility, and SEO. 420 | 3. Use appropriate HTML5 elements and attributes where applicable. 421 | 4. Ensure compatibility with the refactored CSS code, especially considering the use of Twitter Bootstrap classes and conventions. 422 | 5. Integrate the refactored JavaScript code seamlessly, making sure that all necessary elements have the correct IDs, classes, and data attributes required by Phaser. 423 | 6. Improve the overall user experience and usability of the HTML page based on the user's feedback. 424 | 425 | do NOT surround the file with markdown backticks: ```html ... ``` 426 | start the response with and follow the instructions. 427 | 428 | Please provide only the refactored HTML code without any additional explanations, comments. The code will be written into a separate "index.html" file. 429 | """ 430 | -------------------------------------------------------------------------------- /jemma/prompt/tester/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tolitius/jemma/6b2ec2979a733f7a99c9ff698dc253239ea0d9de/jemma/prompt/tester/__init__.py -------------------------------------------------------------------------------- /jemma/prompt/tester/test.py: -------------------------------------------------------------------------------- 1 | ## TODO: test it in a headless environment 2 | # def test_code(role, requirements, html, css, js): 3 | 4 | def review_code(role, requirements, html, css, js): 5 | return f""" 6 | you are {role} 7 | 8 | #INSTRUCTIONS 9 | given the following requirements, a CSS file, a JavaScript file, and an HTML file, your task is to review the HTML file to ensure it meets ALL the requirements and integrates correctly with the CSS and JavaScript files. 10 | 11 | #REQUIREMENTS 12 | {requirements} 13 | 14 | #CSS FILE 15 | {css} 16 | 17 | #JAVASCRIPT FILE 18 | {js} 19 | 20 | #HTML FILE 21 | {html} 22 | 23 | #REVIEW CRITERIA 24 | 1. Document Structure: 25 | - Verify that the HTML file has a valid structure with the correct doctype, head, and body elements. 26 | - Check if the CSS and JavaScript files are correctly linked in the HTML file. 27 | - Ensure that the file paths for the CSS and JavaScript files are relative and accurate. 28 | - Confirm that the required data is not hidden and visible. 29 | 2. Requirements Compliance: 30 | - Ensure that all CSS, JavaScript and HTML files addresses ALL the specified requirements from the user story. 31 | 3. Find errors and bugs 32 | - The main objective of this review is to find errors and bugs in these 3 files: FIND THEM ALL 33 | 34 | #REVIEW RESPONSE 35 | - Provide an actionable list of fixes and improvements for all three files (HTML, CSS, and JavaScript) based on the requirements. 36 | - Make sure to include any missing elements, incorrect implementations, or potential enhancements to meet the user story requirements. 37 | - There is always room for improvement, so be thorough in your review and provide detailed feedback. 38 | - The idea is no to include new features, but to make sure the existing ones are implemented correctly. 39 | - (!) after comminicating step by step thinking ONLY share ERRORS, BUGS and IMPROVEMENTS 40 | 41 | (!) Before responding with the actual review, THINK STEP BY STEP what you would do to review the files and then provide the feedback. 42 | """ 43 | -------------------------------------------------------------------------------- /jemma/prompt/ui/designer.py: -------------------------------------------------------------------------------- 1 | def idea_with_sketch_to_css(requirements): 2 | return f"""You are an AI-powered UI/UX Designer agent. your task is to generate a complete CSS file based on a given image data and requirements. 3 | 4 | ### REQUIREMENTS 5 | {requirements} 6 | 7 | ### INSTRUCTIONS 8 | - analyze the image data and return all the components and all the text labels that you can identify 9 | - rely on existing Twitter Bootstrap CSS classes to create a complete css file that represents the wireframe and design elements, ALL the labels and text of the image 10 | - make sure the css file covers the following sections: 11 | - page layout and all the sections of the page 12 | - component relave positions to each other and the grid 13 | - components within each section 14 | - component classes, sizes, and positions 15 | - styles (colors, typography) 16 | - include different pastel colors, typography, avatar images, thumbnails, icons, and other design elements 17 | - make borders and shadows subtle and elegant 18 | - make sure components do NOT overlap 19 | - (!) pay extra attention to the grid system, sizing, and location fo components in relation to each other and the grid. 20 | - provide a full, valid css output only. no headers, footers, backticks, or additional text. 21 | - start your response / css output from the opening comment "/* me stylish */" and end with the css comment /** done **/ 22 | 23 | ### OUTPUT EXAMPLE 24 | /* learning portal */ 25 | .navbar {{ 26 | background-color: #f8f9fa; 27 | padding: 10px; 28 | }} 29 | .navbar-brand {{ 30 | font-size: 24px; 31 | font-weight: bold; 32 | }} 33 | .nav-link {{ 34 | margin-right: 15px; 35 | }} 36 | .container {{ 37 | margin-top: 30px; 38 | }} 39 | .row {{ 40 | margin-bottom: 20px; 41 | }} 42 | .col-md-4 {{ 43 | text-align: center; 44 | }} 45 | .card {{ 46 | border: none; 47 | box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); 48 | }} 49 | .card-header {{ 50 | background-color: #f8f9fa; 51 | font-weight: bold; 52 | }} 53 | .card-body {{ 54 | padding: 20px; 55 | }} 56 | .btn-primary {{ 57 | width: 100%; 58 | }} 59 | h4 {{ 60 | margin-bottom: 20px; 61 | }} 62 | .progress {{ 63 | height: 25px; 64 | margin-bottom: 20px; 65 | }} 66 | .progress-bar {{ 67 | background-color: #007bff; 68 | }} 69 | .list-group-item {{ 70 | border: none; 71 | padding: 10px 0; 72 | }} 73 | .text-muted {{ 74 | font-size: 14px; 75 | }} 76 | /* done */ 77 | """ 78 | 79 | def css_to_html(requirements, css): 80 | return f"""You are an AI-powered UI/UX Designer agent. Your task is to generate a complete HTML file based on a given image data, requirements and an already generated CSS file. 81 | 82 | ### REQUIREMENTS 83 | {requirements} 84 | 85 | ### CSS FILE 86 | {css} 87 | 88 | ### INSTRUCTIONS 89 | - analyze the image data and return all the components and all the text labels that you can identify 90 | - rely on existing CSS as well as Twitter Bootstrap CSS classes to create a complete HTML file that represents: 91 | - the wireframe as per the image data 92 | - ALL components & design elements that are present in the image data 93 | - ALL the labels and text of the image 94 | - make sure the HTML file covers the following sections: 95 | - page layout and sections 96 | - component relave positions to each other and the grid 97 | - look at both vertical and horizontal component position in relation to the grid and one another 98 | - components within each section 99 | - component classes, sizes, and positions 100 | - include different pastel colors, typography, avatar images, thumbnails, icons, and other design elements 101 | - make sure components do NOT overlap 102 | - use Twitter Bootstrap 103 | - badges 104 | - tabs, nav, pills, progress bars 105 | - buttons 106 | - cards, thumbnails 107 | - and other components to represent the image data 108 | - use icons from Font Awesome to make sure all the elements are clear 109 | - add pastel colors. colors are very important to make the design look good 110 | - use DataTables to represent the table data 111 | - don't include the CSS code in the HTML file, but make sure to reference the CSS file in the HTML file: 112 | - (!) pay extra attention to the location of the components in relation to each other and the grid. 113 | 114 | - provide a full, valid HTML output only. no headers, footers, backticks, or additional text. 115 | - start your response / HTML output from "" and end with the closing tag "" 116 | - the HTML file should import these in the following order: 117 | 118 | - remote "bootrap.css" 119 | - remote dataTables css (for bootstrap 4, "dataTables.bootstrap4.css") 120 | - local, previously generated, CSS: app.css 121 | - remote jQuery library 122 | - remote "popper.js" 123 | - remote "bootrap.js" 124 | - remote dataTables js 125 | - remote dataTables js (for bootstrap 4, "dataTables.bootstrap4.js") 126 | - local, previously generated, JavaScript file: app.js 127 | 128 | example: 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | (!) make sure the HTML file includes ALL the content from the image data: ALL components, ALL text, ALL labels 141 | """ 142 | 143 | def sketch_to_description(focus): 144 | return f"""You are an AI-powered UI/UX Designer agent. 145 | Your task is given an image data, generate a VERY detailed and comprehensive description of the image data. 146 | You are also given a focus area of the image data to concentrate on. 147 | 148 | ### FOCUS AREA 149 | {focus} 150 | 151 | ### INSTRUCTIONS 152 | - analyze the image data and return all the components and all the text labels that you can identify 153 | - list all the components and text labels in the image data 154 | - for every component and text label, provide a detailed description of the following: 155 | - component type 156 | - component size 157 | - component position in relation to the grid and other components 158 | - component classes and styles 159 | - component text content and labels 160 | - provide a full, detailed, and VERY comprehensive description of the image data that can be used by the Engineer to create a working HTML, CSS, and JavaScript based prototype 161 | - include the focus unchanged at the end of your output 162 | 163 | ### OUTPUT STRUCTURE 164 | 165 | 166 | 167 | 168 | {focus} 169 | """ 170 | 171 | ### ------------- new wave 172 | 173 | def sketch_to_layout(focus): 174 | return f"""You are an AI-powered UI/UX Designer agent. 175 | You are given a wireframe image data to analyze and generate a detailed description of Component Layout and Positioning. 176 | You are also optinally given a user feedback to focus on. Please return it in the response as well. 177 | ### USER FEEDBACK 178 | {focus} 179 | 180 | Please analyze the provided wireframe and generate a structured description of the layout and component positioning. Pay close attention to the side-by-side arrangement of sections and components. Provide specific details based on the visual information present in the wireframe. 181 | 182 | 1. Identify the main sections or containers in the layout 183 | - List the sections in the order they appear vertically 184 | - Clearly specify any sections that are positioned side by side horizontally 185 | 186 | 2. For each main section, describe the components within it 187 | - List the components in the order they appear within the section 188 | - Specify the relative positioning of components (e.g., aligned to the left, centered, aligned to the right) 189 | - Clearly indicate any components that are positioned side by side horizontally 190 | - Mention any nested components and their parent-child relationships 191 | 192 | 3. Provide a detailed description of each component 193 | - Specify the component type (e.g., text, button, image, input field) 194 | - Describe the content or placeholder text of the component 195 | - Mention any icons or visual elements associated with the component 196 | 197 | 4. Describe any sections or components that span across multiple columns or rows 198 | - Indicate if a section or component spans the full width or height of its container 199 | - Specify any components that are positioned relative to other components or sections 200 | 201 | 5. Clarify the horizontal and vertical arrangement of sections and components 202 | - Based on the provided wireframe, specify the arrangement of all its sections 203 | - Describe how components are aligned within each section (e.g., left-aligned, centered, right-aligned) 204 | 205 | 6. Double-check the side-by-side arrangement of sections and components 206 | - Verify that any side-by-side arrangements are accurately identified and described 207 | - Ensure that the positioning of sections and components is consistent with the visual information in the wireframe 208 | 209 | 7. Provide any additional observations or notes relevant to the layout and positioning 210 | 211 | Please analyze the wireframe carefully and provide a structured description based on the visual information available. Use the following format for your response: 212 | 213 | 1. Main Sections: 214 | - Section 1 (e.g., Header) 215 | - Component 1 (type, content, positioning) 216 | - Component 2 (type, content, positioning) 217 | - Section 2 (e.g., Main Content) 218 | - Component 1 (type, content, positioning) 219 | - Nested Component (type, content, positioning) 220 | - Component 2 (type, content, positioning) 221 | 222 | 2. Side-by-Side Sections/Components: 223 | - Section or Component (description, side-by-side arrangement) 224 | 225 | 3. Full-width or Full-height Sections/Components: 226 | - Section or Component (description, spanning details) 227 | 228 | 4. Relatively Positioned Components: 229 | - Component (description, positioning relative to other components or sections) 230 | 231 | 5. Horizontal and Vertical Arrangement: 232 | - Sections (horizontal or vertical arrangement) 233 | - Components (alignment within sections) 234 | 235 | 6. Additional Observations: 236 | - Any other relevant notes or observations about the layout and positioning 237 | 238 | (!) It is important to identify 239 | - ALL the components in the wireframe from top to bottom 240 | - the components, cards that are positioned side by side horizontally: provide a detailed description of their relative positioning. 241 | - components that live inside other components: provide a clear parent-child relationship. 242 | 243 | Please proceed with analyzing the wireframe and provide the structured description based on the available visual information. Ensure that the side-by-side arrangement of sections and components is accurately captured. 244 | And at the end provide the original user feedback unchanged ({focus}). 245 | """ 246 | 247 | def sketch_to_specification(focus): 248 | return f"""You are an AI-powered UI/UX Designer agent. 249 | You are given a wireframe image data to analyze and generate a detailed Component Specification. 250 | You are also optinally given a user feedback to focus on. Please return it in the response as well. 251 | ### USER FEEDBACK 252 | {focus} 253 | 254 | Based on the layout and component positioning described in the previous prompt, please provide detailed specifications for each identified component. Include the following information: 255 | 256 | 1. Component Type: 257 | - Specify the type of the component (e.g., button, input field, text, image, icon) 258 | 259 | 2. Size and Dimensions: 260 | - Provide the size and dimensions of the component, if visually apparent or specified in the wireframe 261 | - Include width, height, padding, and margin values, if applicable 262 | - If the size is not explicitly specified, provide an estimate based on the visual proportions 263 | 264 | 3. Text Content and Labels: 265 | - Transcribe any text content, labels, or placeholders associated with the component 266 | - Specify the font family, size, weight, and color of the text, if visually apparent or specified in the wireframe 267 | 268 | 4. Color Scheme and Visual Styles: 269 | - Describe the color scheme of the component, including background color, border color, and any other relevant colors 270 | - Specify the visual styles, such as border thickness, border radius, shadow, or gradient, if applicable 271 | 272 | 5. Icons and Visual Elements: 273 | - Describe any icons or visual elements associated with the component 274 | - Provide details on the icon style, color, and size, if visually apparent or specified in the wireframe 275 | 276 | 6. States and Interactions: 277 | - Describe any visible states or interactions associated with the component, such as hover, active, or disabled states 278 | - Specify any visual changes or effects that occur during these states or interactions 279 | 280 | 7. Responsive Behavior: 281 | - If the component's appearance or behavior is expected to change based on screen size or device, describe the responsive behavior 282 | - Specify any modifications to the component's size, position, or layout at different breakpoints 283 | 284 | Please provide the component specifications in a structured format, using the following template: 285 | 286 | Component 1: 287 | 1. Component Type: 288 | 2. Size and Dimensions: 289 | 3. Text Content and Labels: 290 | 4. Color Scheme and Visual Styles: 291 | 5. Icons and Visual Elements: 292 | 6. States and Interactions: 293 | 7. Responsive Behavior: 294 | 295 | Component 2: 296 | 1. Component Type: 297 | 2. Size and Dimensions: 298 | 3. Text Content and Labels: 299 | 4. Color Scheme and Visual Styles: 300 | 5. Icons and Visual Elements: 301 | 6. States and Interactions: 302 | 7. Responsive Behavior: 303 | 304 | ... 305 | 306 | Please analyze each component carefully and provide as much detail as possible based on the visual information available in the wireframe. If certain aspects are not explicitly specified or visually apparent, make reasonable assumptions or provide estimates based on the overall design aesthetics. 307 | 308 | (!) At the end of your response please provide the original user feedback unchanged ({focus}). 309 | """ 310 | 311 | def spec_to_css(layout, component_spec, feedback): 312 | return f"""You are an AI-powered UI/UX Designer agent. your task is to generate a complete CSS file based on a given image data, description of its layout, component specification and a user feedback. 313 | 314 | ### LAYOUT DESCRIPTION 315 | {layout} 316 | 317 | ### COMPONENT SPECIFICATIONS 318 | {component_spec} 319 | 320 | ### USER FEEDBACK 321 | {feedback} 322 | 323 | ### INSTRUCTIONS 324 | - analyze the image data and return all the components and all the text labels that you can identify 325 | - rely on the layout description and component specifications to create a complete css file that represents the wireframe and design elements, ALL the labels and text of the image 326 | - rely on existing Twitter Bootstrap CSS classes to create a complete css file that represents the wireframe and design elements, ALL the labels and text of the image 327 | - make sure to incorporate user feedback if provided and applicable 328 | - make sure the css file covers the following sections: 329 | - page layout and all the sections of the page 330 | - component relave positions to each other and the grid 331 | - components within each section 332 | - component classes, sizes, and positions 333 | - styles (colors, typography) 334 | - include different pastel colors, typography, avatar images, thumbnails, icons, and other design elements 335 | - make borders and shadows subtle and elegant 336 | - make sure components do NOT overlap 337 | - (!) pay extra attention to the grid system, sizing, and location fo components in relation to each other and the grid. 338 | - provide a full, valid css output only. no headers, footers, backticks, or additional text. 339 | - start your response / css output from the opening comment "/* me stylish */" and end with the css comment /** done **/ 340 | 341 | ### OUTPUT EXAMPLE 342 | /* learning portal */ 343 | .navbar {{ 344 | background-color: #f8f9fa; 345 | padding: 10px; 346 | }} 347 | .navbar-brand {{ 348 | font-size: 24px; 349 | font-weight: bold; 350 | }} 351 | .nav-link {{ 352 | margin-right: 15px; 353 | }} 354 | .container {{ 355 | margin-top: 30px; 356 | }} 357 | .row {{ 358 | margin-bottom: 20px; 359 | }} 360 | .col-md-4 {{ 361 | text-align: center; 362 | }} 363 | 364 | ... 365 | 366 | .card {{ 367 | border: none; 368 | box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); 369 | }} 370 | .card-header {{ 371 | background-color: #f8f9fa; 372 | font-weight: bold; 373 | }} 374 | .card-body {{ 375 | padding: 20px; 376 | }} 377 | .btn-primary {{ 378 | width: 100%; 379 | }} 380 | h4 {{ 381 | margin-bottom: 20px; 382 | }} 383 | .progress {{ 384 | height: 25px; 385 | margin-bottom: 20px; 386 | }} 387 | .progress-bar {{ 388 | background-color: #007bff; 389 | }} 390 | .list-group-item {{ 391 | border: none; 392 | padding: 10px 0; 393 | }} 394 | .text-muted {{ 395 | font-size: 14px; 396 | }} 397 | /* done */ 398 | """ 399 | 400 | def spec_to_html(layout, component_spec, css, feedback): 401 | return f"""You are an AI-powered UI/UX Designer agent. Your task is to generate a complete HTML file based on a given image data, its layout, component specification, an already generated CSS file and (if provided) a user feedback. 402 | 403 | ### LAYOUT DESCRIPTION 404 | {layout} 405 | 406 | ### COMPONENT SPECIFICATIONS 407 | {component_spec} 408 | 409 | ### CSS FILE 410 | {css} 411 | 412 | ### USER FEEDBACK 413 | {feedback} 414 | 415 | ### INSTRUCTIONS 416 | - analyze the image data and fix the layout and component specifications IF there is anything missing or incorrect 417 | - rely on provided layout description and component specifications to create a complete HTML file that represents the wireframe and design elements, ALL the labels and text of the image 418 | - make sure to incorporate user feedback if provided and applicable 419 | - rely on existing CSS as well as Twitter Bootstrap CSS classes to create a complete HTML file that represents: 420 | - the wireframe as per the image data 421 | - ALL components & design elements that are present in the image data, layout and component specifications 422 | - ALL the labels and text of the image, layout and component specifications 423 | - make sure the HTML file covers the following sections: 424 | - page layout and sections 425 | - component relave positions to each other and the grid 426 | - look at both vertical and horizontal component position in relation to the grid and one another 427 | - components within each section 428 | - component classes, sizes, and positions 429 | - include different pastel colors, typography, avatar images, thumbnails, icons, and other design elements 430 | - make sure components do NOT overlap 431 | - use Twitter Bootstrap 432 | - badges 433 | - tabs, nav, pills, progress bars 434 | - buttons 435 | - cards, thumbnails 436 | - and other components to represent the image data 437 | - use icons from Font Awesome to make sure all the elements are clear 438 | - add pastel colors. colors are very important to make the design look good 439 | - use DataTables to represent the table data 440 | - don't include the CSS code in the HTML file, but make sure to reference the CSS file in the HTML file: 441 | - (!) pay extra attention to the location of the components in relation to each other and the grid. 442 | 443 | - provide a full, valid HTML output only. no headers, footers, backticks, or additional text. 444 | - start your response / HTML output from "" and end with the closing tag "" 445 | - the HTML file should import these in the following order: 446 | 447 | - remote "bootrap.css" 448 | - font awesome css 449 | - remote dataTables css (for bootstrap 4, "dataTables.bootstrap4.css") 450 | - local, previously generated, CSS: app.css 451 | - remote jQuery library 452 | - remote "popper.js" 453 | - remote "bootrap.js" 454 | - remote dataTables js 455 | - remote dataTables js (for bootstrap 4, "dataTables.bootstrap4.js") 456 | - local, previously generated, JavaScript file: app.js 457 | 458 | example: 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | ## IMPORTANT 472 | make sure to use plenty of icons from Font Awesome to make sure all the elements are clear 473 | please populate components with dummy data where applicable if the image data does not provide any 474 | please use Twitter Bootstrap's cards to clearly represent and isolate components 475 | 476 | (!) make sure the HTML file includes ALL the content from the image data, layout and component specification: ALL components, ALL text, ALL labels 477 | """ 478 | -------------------------------------------------------------------------------- /jemma/requirements/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tolitius/jemma/6b2ec2979a733f7a99c9ff698dc253239ea0d9de/jemma/requirements/__init__.py -------------------------------------------------------------------------------- /jemma/requirements/feature.py: -------------------------------------------------------------------------------- 1 | class UserStory: 2 | def __init__(self, title, acceptance_criteria, description=""): 3 | self.title = title 4 | self.description = description 5 | self.acceptance_criteria = acceptance_criteria 6 | 7 | def update_acceptance_criteria (self, acceptance_criteria): 8 | self.acceptance_criteria = acceptance_criteria 9 | 10 | def __str__(self): 11 | return f"Title: {self.title}\nDescription: {self.description}\nAcceptance Criteria:\n{self.acceptance_criteria}" 12 | 13 | class Feature: 14 | def __init__(self, 15 | requirements="follow the instructions", 16 | title="feature", 17 | sketch=""): 18 | self.title = title 19 | self.requirements = requirements 20 | self.sketch = sketch 21 | self.user_stories = {} 22 | 23 | def add_user_story(self, user_story): 24 | self.user_stories[user_story.title] = user_story 25 | 26 | def update_user_story(self, title, updated_user_story): 27 | self.user_stories[title] = updated_user_story 28 | 29 | def get_user_story(self, title): 30 | return self.user_stories.get(title) 31 | 32 | def get_user_stories(self): 33 | return self.user_stories 34 | 35 | def export_user_stories_titles_and_criteria(self): 36 | export_list = [] 37 | for title, user_story in self.user_stories.items(): 38 | export_list.append(f"Title: {user_story.title}\nAcceptance Criteria:\n{user_story.acceptance_criteria}") 39 | return "\n\n".join(export_list) 40 | -------------------------------------------------------------------------------- /jemma/team/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tolitius/jemma/6b2ec2979a733f7a99c9ff698dc253239ea0d9de/jemma/team/__init__.py -------------------------------------------------------------------------------- /jemma/team/business_owner.py: -------------------------------------------------------------------------------- 1 | import json 2 | from jemma.requirements.feature import UserStory 3 | from jemma.tools import read_file, say, color 4 | import jemma.prompt.business.owner as prompt 5 | 6 | class BusinessOwner: 7 | def __init__(self, role, title="Business Owner"): 8 | self.role = role 9 | self.title = title 10 | 11 | def split_requirements_to_features(self, thinker, requirements, features="", evaluation=""): 12 | features = thinker.think(prompt.split_requirements_to_features(self.role, 13 | requirements, 14 | features, 15 | evaluation), 16 | self.title) 17 | splits = [line for line in features.strip().split('\n') if line.strip()] 18 | return splits 19 | 20 | def evaluate_features(self, thinker, features, requirements): 21 | features_json = json.dumps(features) 22 | evaluation = thinker.think(prompt.evaluate_features(self.role, features_json, requirements), self.title) 23 | return evaluation 24 | 25 | def refine_feature(self, thinker, requirements, feature): 26 | refined_feature = thinker.think(prompt.refine_feature(self.role, requirements, feature), self.title) 27 | return refined_feature 28 | 29 | def split_and_refine(self, 30 | thinker, 31 | requirements, 32 | max_refinement_attempts=2): 33 | 34 | # slit requirements into features 35 | features = self.split_requirements_to_features(thinker, requirements) 36 | 37 | # evaluate and split features until approved or max attempts reached 38 | refinement_attempts = 0 39 | while refinement_attempts < max_refinement_attempts: 40 | evaluation = self.evaluate_features(thinker, features, requirements) 41 | if "APPROVED AND READY FOR REFINEMENT" in evaluation: 42 | break 43 | features = self.split_requirements_to_features(thinker, requirements, features, evaluation) 44 | refinement_attempts += 1 45 | 46 | if refinement_attempts == max_refinement_attempts: 47 | say(self.title, "end of day for me (\"max refinement attempts\" is reached)") 48 | else: 49 | say(self.title, "we did well: requirements are split into features and approved for refinement") 50 | 51 | # refine each feature individually 52 | refined_features = [] 53 | for feature in features: 54 | refined_feature = self.refine_feature(thinker, requirements, feature) 55 | feature_map = {"title": feature, 56 | "acceptance_criteria": refined_feature} 57 | refined_features.append(feature_map) 58 | 59 | return refined_features 60 | 61 | def clarify_user_story(self, 62 | thinker, 63 | requirements, 64 | user_story, 65 | clarification_request): 66 | 67 | # use the thinker to clarify the user story 68 | clarified = thinker.think(prompt.clarify_user_story(self.role, 69 | requirements, 70 | user_story, 71 | clarification_request), 72 | self.title) 73 | 74 | user_story.update_acceptance_criteria(clarified) 75 | 76 | return user_story 77 | 78 | def combine_user_stories(self, thinker, requirements, user_stories): 79 | say(self.title, "combining user stories...", message_color=color.DARKCYAN) 80 | return thinker.think(prompt.combine_user_stories(self.role, requirements, user_stories), 81 | self.title) 82 | 83 | 84 | def idea_to_prompt(self, thinker, idea): 85 | say(self.title, "📚 creating detailed requirements ...🖋️", message_color=color.DARKCYAN) 86 | return thinker.think(prompt.idea_to_prompt(idea), 87 | self.title, 88 | mute=True) 89 | 90 | def idea_with_desing_to_requirements(self, 91 | thinker, 92 | idea, 93 | design): 94 | say(self.title, "📚 creating detailed requirements (for: idea + design) ...🖋️", message_color=color.DARKCYAN) 95 | return thinker.think(prompt.design_to_requirements(idea, design), 96 | self.title) 97 | -------------------------------------------------------------------------------- /jemma/team/engineer.py: -------------------------------------------------------------------------------- 1 | import os, json 2 | from jemma.prompt.engineer.clarify import check_whether_clarification_needed 3 | import jemma.prompt.engineer.code as code 4 | import jemma.prompt.engineer.game as game 5 | from jemma.tools import say, color 6 | 7 | class Engineer: 8 | def __init__(self, role, implementation_approach=code.default_implementation_approach()): 9 | self.role = role 10 | self.implementation_approach = implementation_approach 11 | 12 | def create_prototype(self, thinker, requirements): 13 | say("Engineer", f"💫 creating a prototype based on the requirements...", message_color=color.DARKCYAN) 14 | 15 | css = thinker.think(code.create_css_file(requirements), 16 | "Engineer", 17 | mute=True, 18 | action="crafting css 🎨 (a.k.a. \"visual beauty\")") 19 | 20 | js = thinker.think(code.create_javascript_file(requirements, css), 21 | "Engineer", 22 | mute=True, 23 | action="cooking javascript 🎮 (a.k.a. \"master of interactions\")") 24 | 25 | html = thinker.think(code.create_html_file(requirements, css, js), 26 | "Engineer", 27 | mute=True, 28 | action="creating html 🕸️ (a.k.a. \"the skeleton of the web\")") 29 | 30 | return {"css": css, "js": js, "html": html} 31 | 32 | def refactor_prototype(self, 33 | thinker, 34 | requirements, 35 | prototype, 36 | feedback): 37 | say("Engineer", "💫 refactoring prototype based on the feedback...", message_color=color.DARKCYAN) 38 | 39 | css = thinker.think(code.refactor_css_file(requirements, 40 | prototype["css"], 41 | feedback), 42 | "Engineer", 43 | mute=True, 44 | action="♻️ crafting css 🎨 (a.k.a. \"visual beauty\")") 45 | 46 | js = thinker.think(code.refactor_javascript_file(requirements, 47 | css, 48 | prototype["js"], 49 | feedback), 50 | "Engineer", 51 | mute=True, 52 | action="♻️ cooking javascript 🎮 (a.k.a. \"master of interactions\")") 53 | 54 | html = thinker.think(code.refactor_html_file(requirements, 55 | css, 56 | js, 57 | prototype["html"], 58 | feedback), 59 | "Engineer", 60 | mute=True, 61 | action="♻️ creating html 🕸️ (a.k.a. \"the skeleton of the web\")") 62 | 63 | return {"css": css, "js": js, "html": html} 64 | 65 | 66 | def review_user_story(self, thinker, user_story, requirements): 67 | say("Engineer", f"checking whether clarification is needed for user story: \"{user_story.title}\"", 68 | message_color=color.DARKCYAN) 69 | 70 | review_result = thinker.think(check_whether_clarification_needed(requirements, user_story), "Engineer") 71 | return review_result 72 | 73 | def implement_user_story(self, 74 | thinker, 75 | requirements, 76 | user_story = "provide full implementation of this feature", 77 | existing_code=""): 78 | implementation = thinker.think(code.implement_user_story(self.implementation_approach, 79 | requirements, 80 | user_story, 81 | existing_code), 82 | "Engineer") 83 | return implementation 84 | -------------------------------------------------------------------------------- /jemma/team/project_manager.py: -------------------------------------------------------------------------------- 1 | import os 2 | from jemma.tools import say, color, open_local_browser, name_to_file_name, record_prototype 3 | from jemma.requirements.feature import Feature, UserStory 4 | 5 | class ProjectManager: 6 | def __init__(self, feature, project_name="project", role = "Project Manager"): 7 | self.feature = feature 8 | self.role = role 9 | self.project_name = project_name 10 | 11 | def record_requirement(self, 12 | name, 13 | requirement, 14 | path): 15 | # create the directory if it doesn't exist 16 | os.makedirs(path, exist_ok=True) 17 | 18 | requirement_path = os.path.join(path, 19 | name_to_file_name(name)) 20 | with open(requirement_path, "w") as requirement_file: 21 | requirement_file.write(requirement) 22 | 23 | print(color.GRAY_MEDIUM + f"storing requirements for \"{name}\" in \"{requirement_path}\"" + color.END) 24 | 25 | def meet_to_create_user_stories(self, 26 | thinker, 27 | business_owner): 28 | say(self.role, "\nDear Business Owner, in this meeting we'll work on splitting the requirements and creating user stories.", 29 | who_color = color.CYAN, message_color = color.YELLOW) 30 | 31 | refined = business_owner.split_and_refine(thinker, 32 | self.feature.requirements) 33 | 34 | for unit in refined: 35 | user_story = UserStory(title=unit["title"], 36 | acceptance_criteria=unit["acceptance_criteria"]) 37 | self.feature.add_user_story(user_story) 38 | 39 | def meet_to_refine_user_stories(self, 40 | thinker, 41 | engineer, 42 | business_owner, 43 | max_refinement_attempts = 1): 44 | 45 | say(self.role, "\nDear Engineer, meet the Business Owner, welcome to the refinement meeting, let's refine'em user stories!", 46 | who_color = color.CYAN, message_color = color.YELLOW) 47 | 48 | for title, user_story in self.feature.get_user_stories().items(): 49 | self._refine_user_story(thinker, 50 | engineer, 51 | business_owner, 52 | user_story, 53 | max_refinement_attempts) 54 | 55 | def _refine_user_story(self, 56 | thinker, 57 | engineer, 58 | business_owner, 59 | user_story, 60 | max_refinement_attempts): 61 | 62 | refinement_attempts = 0 63 | engineer_response = engineer.review_user_story(thinker, 64 | user_story, 65 | self.feature.requirements) 66 | 67 | while "No clarification needed" not in engineer_response and refinement_attempts < max_refinement_attempts: 68 | say(self.role, "\nDear Business Owner, the Engineer would like you to clarify details about \"" + user_story.title + "\"", 69 | who_color=color.CYAN, message_color=color.YELLOW) 70 | 71 | clarified_user_story = business_owner.clarify_user_story(thinker, 72 | self.feature.requirements, 73 | user_story, 74 | engineer_response) 75 | self.feature.update_user_story(user_story.title, 76 | clarified_user_story) 77 | 78 | refinement_attempts += 1 79 | if refinement_attempts < max_refinement_attempts: 80 | engineer_response = engineer.review_user_story(thinker, 81 | self.feature.get_user_story(user_story.title), 82 | self.feature.requirements) 83 | 84 | def meet_to_build_prototype(self, 85 | thinker, 86 | engineer, 87 | path = "prototype"): 88 | 89 | say(self.role, 90 | "\nDear Engineer, in this meeting let's put our heads together to build a prototype based on the requirements.", 91 | who_color = color.CYAN, 92 | message_color = color.YELLOW) 93 | 94 | prototype = engineer.create_prototype(thinker, 95 | self.feature.requirements) 96 | record_prototype(path, 97 | prototype) 98 | open_local_browser(path) 99 | 100 | return prototype 101 | 102 | def meet_to_refactor(self, 103 | thinker, 104 | engineer, 105 | prototype, 106 | feedback, 107 | path = "prototype"): 108 | 109 | say(self.role, 110 | "\nDear Engineer, we have met with the user and received a valuable feedback. sudo make it better! 🛠️", 111 | who_color = color.CYAN, 112 | message_color = color.YELLOW) 113 | 114 | refactored = engineer.refactor_prototype(thinker, 115 | self.feature.requirements, 116 | prototype, 117 | feedback) 118 | 119 | record_prototype(path, 120 | refactored) 121 | open_local_browser(path) 122 | 123 | return refactored 124 | 125 | def meet_to_test_prototype(self, 126 | thinker, 127 | tester, 128 | path = "prototype"): 129 | 130 | say(self.role, 131 | "\nDear Tester, in this meeting let's focus on requirements and built code to test a prototype.", 132 | who_color = color.CYAN, 133 | message_color = color.YELLOW) 134 | 135 | prototype = tester.read_prototype(path) 136 | test_results = tester.review_prototype(thinker, 137 | self.feature.requirements, 138 | prototype) 139 | 140 | return test_results 141 | 142 | def meet_to_combine_user_stories(self, 143 | thinker, 144 | business_owner): 145 | 146 | say(self.role, "\nDear Business Owner, in this meeting we'll combine user stories into a single document", 147 | who_color = color.CYAN, message_color = color.YELLOW) 148 | 149 | combined_user_stories = business_owner.combine_user_stories(thinker, 150 | self.feature.requirements, 151 | self.feature.get_user_stories()) 152 | self.feature = Feature(combined_user_stories) 153 | 154 | def user_stories_to_requirement(self): 155 | self.feature = Feature(self.feature.export_user_stories_titles_and_criteria()) 156 | 157 | def meet_to_discuss_mockups(self, 158 | thinker, 159 | designer, 160 | idea, 161 | sketch, 162 | store_path="requirements"): 163 | 164 | say(self.role, "\nDear UI/UX Designer, in this meeting we'll work on creating mockups based on the 💡 idea & sketch", 165 | who_color = color.CYAN, message_color = color.YELLOW) 166 | 167 | requirements = designer.sketch_to_description(thinker, 168 | sketch, 169 | idea) 170 | 171 | self.record_requirement("mockup", requirements, store_path) 172 | self.feature = Feature(requirements) 173 | 174 | return requirements 175 | 176 | def meet_to_convert_design_to_prototype(thinker, 177 | designer, 178 | sketch, 179 | design): 180 | 181 | prototype = designer.sketch_to_prototype(thinker, 182 | design, 183 | sketch) 184 | return prototype 185 | 186 | def record_and_open_prototype(self, 187 | prototype, 188 | path="prototype"): 189 | record_prototype(path, 190 | prototype) 191 | open_local_browser(path) 192 | 193 | return prototype 194 | 195 | def meet_to_create_mockups(self, 196 | thinker, 197 | designer, 198 | idea, 199 | sketch, 200 | store_path="requirements"): 201 | 202 | say(self.role, "\nDear UI/UX Designer, in this meeting we'll work on creating mockups based on the 💡 idea & sketch", 203 | who_color = color.CYAN, message_color = color.YELLOW) 204 | 205 | requirements = designer.sketch_to_description(thinker, 206 | sketch, 207 | idea) 208 | 209 | self.record_requirement("mockup", requirements, store_path) 210 | self.feature = Feature(requirements) 211 | 212 | prototype = designer.sketch_to_prototype(thinker, 213 | requirements, 214 | sketch) 215 | record_prototype(store_path, 216 | prototype) 217 | open_local_browser(store_path) 218 | 219 | return prototype 220 | 221 | def meet_to_create_requirements(self, 222 | thinker, 223 | business_owner, 224 | idea, 225 | store_path="requirements"): 226 | 227 | say(self.role, "\nDear Business Owner, in this meeting we'll work on creating requirements based on the 💡 idea", 228 | who_color = color.CYAN, message_color = color.YELLOW) 229 | 230 | requirements = business_owner.idea_to_prompt(thinker, idea) 231 | 232 | self.record_requirement(idea, requirements, store_path) 233 | 234 | self.feature = Feature(requirements) 235 | 236 | def meet_to_address_feedback(self, 237 | thinker, 238 | designer, 239 | sketch, 240 | feedback, 241 | store_path="requirements"): 242 | 243 | say(self.role, "\nDear UI/UX Designer, in this meeting we'll look at the sketch to address user's the feedback", 244 | who_color = color.CYAN, message_color = color.YELLOW) 245 | 246 | requirements = designer.sketch_to_description(thinker, 247 | sketch, 248 | feedback) 249 | 250 | self.record_requirement("mockup", requirements, store_path) 251 | 252 | self.feature = Feature(requirements) 253 | -------------------------------------------------------------------------------- /jemma/team/tester.py: -------------------------------------------------------------------------------- 1 | import os, json 2 | import jemma.prompt.tester.test as test 3 | from jemma.tools import say, color 4 | 5 | class Tester: 6 | def __init__(self, role, testing_approach=""): 7 | self.role = role 8 | self.testing_approach = testing_approach 9 | 10 | def read_prototype(self, path): 11 | prototype = {} 12 | 13 | # Read the CSS file 14 | css_file_path = os.path.join(path, "app.css") 15 | with open(css_file_path, "r") as css_file: 16 | prototype["css"] = css_file.read() 17 | 18 | # Read the JavaScript file 19 | js_file_path = os.path.join(path, "app.js") 20 | with open(js_file_path, "r") as js_file: 21 | prototype["js"] = js_file.read() 22 | 23 | # Read the HTML file 24 | html_file_path = os.path.join(path, "index.html") 25 | 26 | with open(html_file_path, "r") as html_file: 27 | prototype["html"] = html_file.read() 28 | 29 | return prototype 30 | 31 | def review_prototype(self, 32 | thinker, 33 | requirements, 34 | prototype): 35 | say("Tester", 36 | f"reviewing a prototype based on the requirements", 37 | message_color=color.DARKCYAN) 38 | 39 | review = thinker.think(test.review_code(# self.testing_approach, 40 | self.role, 41 | requirements, 42 | prototype["html"], 43 | prototype["css"], 44 | prototype["js"]), 45 | "Tester") 46 | return review 47 | -------------------------------------------------------------------------------- /jemma/team/ui_ux_designer.py: -------------------------------------------------------------------------------- 1 | import json 2 | from jemma.tools import read_file, say, color 3 | import jemma.prompt.ui.designer as prompt 4 | 5 | class UiUxDesigner: 6 | def __init__(self, role, title="UI/UX Designer"): 7 | self.role = role 8 | self.title = title 9 | 10 | def idea_with_sketch_to_design(self, 11 | thinker, 12 | requirements, 13 | sketch): 14 | say(self.title, "🔍 collecting intel about the sketch ...", message_color=color.DARKCYAN) 15 | return thinker.see(prompt.idea_with_sketch_to_css(requirements), 16 | sketch, 17 | self.title) 18 | 19 | def design_to_layout(self, 20 | thinker, 21 | requirements, 22 | css, 23 | sketch): 24 | say(self.title, "🎨 designing a layout based on sketch's beauty ...", message_color=color.DARKCYAN) 25 | return thinker.see(prompt.css_to_html(requirements, css), 26 | sketch, 27 | self.title) 28 | 29 | def sketch_to_prototype(self, 30 | thinker, 31 | requirements, 32 | sketch): 33 | 34 | css = self.idea_with_sketch_to_design(thinker, 35 | requirements, 36 | sketch) 37 | print(f"design: {css}") 38 | html = self.design_to_layout(thinker, 39 | requirements, 40 | css, 41 | sketch) 42 | print(f"html: {html}") 43 | 44 | return {"css": css, "js": "", "html": html} 45 | 46 | def sketch_to_description(self, 47 | thinker, 48 | sketch, 49 | focus): 50 | say(self.title, "🎨 looking at the sketch very closely now ...", message_color=color.DARKCYAN) 51 | return thinker.see(prompt.sketch_to_description(focus), 52 | sketch, 53 | self.title) 54 | 55 | def sketch_to_layout(self, 56 | thinker, 57 | intel): 58 | 59 | feedback, sketch = [intel[key] for key in ("prompt", "sketch")] 60 | 61 | say(self.title, "🪟 looking at the sketch to infer the layout ...", message_color=color.DARKCYAN) 62 | return {"layout": thinker.see(prompt.sketch_to_layout(feedback), 63 | sketch, 64 | self.title)} 65 | 66 | def sketch_to_specification(self, 67 | thinker, 68 | intel): 69 | 70 | feedback, sketch = [intel[key] for key in ("prompt", "sketch")] 71 | 72 | say(self.title, "📃 looking at the sketch to create component specs ...", message_color=color.DARKCYAN) 73 | return {"spec": thinker.see(prompt.sketch_to_specification(feedback), 74 | sketch, 75 | self.title)} 76 | 77 | def spec_to_css(self, 78 | thinker, 79 | intel): 80 | 81 | feedback, sketch, layout, spec = [intel[key] for key in ("prompt", "sketch", "layout", "spec")] 82 | 83 | say(self.title, "🎨 using sketch specs to create styles (a.k.a CSS) ...", message_color=color.DARKCYAN) 84 | 85 | # return {"css": thinker.see(prompt.spec_to_css(layout, spec, feedback), 86 | # sketch, 87 | # self.title)} 88 | return {"css": thinker.think(prompt.spec_to_css(layout, spec, feedback), 89 | self.title)} 90 | 91 | def spec_to_html(self, 92 | thinker, 93 | intel): 94 | 95 | feedback, sketch, layout, spec, css = [intel[key] for key in ("prompt", "sketch", "layout", "spec", "css")] 96 | 97 | say(self.title, "🕸️ using styles and sketch specs to create a wireframe (a.k.a HTML) ...", message_color=color.DARKCYAN) 98 | # return {"html": thinker.see(prompt.spec_to_html(layout, spec, css, feedback), 99 | # sketch, 100 | # self.title)} 101 | return {"html": thinker.think(prompt.spec_to_html(layout, spec, css, feedback), 102 | self.title)} 103 | -------------------------------------------------------------------------------- /jemma/thinker.py: -------------------------------------------------------------------------------- 1 | import os, time, json 2 | from jemma.tools import color, say, image_path_to_data, send_post_request 3 | 4 | import ollama 5 | import replicate 6 | from anthropic import Anthropic 7 | from openai import OpenAI 8 | import colalamo 9 | 10 | ## TODO: take and pass options with a model type (i.e. max_tokens [llama] vs. max_new_tokens [mistral], etc.) 11 | 12 | class Thinker: 13 | 14 | # defining init method for class 15 | def __init__(self, model_name): 16 | self.model_name = model_name 17 | 18 | def __str__(self): 19 | return f"{self.__class__.__name__} 🧠 {self.model_name} ✅" 20 | 21 | def think(prompt, who="user", sleep_time=0): 22 | raise NotImplementedError("can't think without a implementation. try creating Ollama that is based on me") 23 | 24 | class Ollama(Thinker): 25 | 26 | def __init__(self, model_name): 27 | super().__init__(model_name) 28 | 29 | def think(self, prompt, who="user", action="", mute=False, sleep_time=0): 30 | thinking = ollama.generate(model=self.model_name, 31 | prompt=prompt, 32 | options={'num_predict': -1, 33 | 'num_ctx': 8192}, # default to llama's 3 context window 34 | stream=True) 35 | if action != "" or not mute: 36 | say(who, action) 37 | 38 | response = "" 39 | for word in thinking: 40 | response += word['response'] 41 | if not mute: 42 | print(word['response'], end="") 43 | 44 | return response 45 | 46 | def see(self, prompt, image_path, who="user", action="", mute=False, sleep_time=0): 47 | 48 | if action != "" or not mute: 49 | say(who, action + image_path) 50 | 51 | image_data, image_type = image_path_to_data(image_path).values() 52 | 53 | thinking = ollama.generate(model=self.model_name, 54 | prompt=prompt, 55 | images=[image_data], 56 | options={'num_predict': -1, 57 | 'num_ctx': 4096}, 58 | stream=True) 59 | 60 | response = "" 61 | for word in thinking: 62 | response += word['response'] 63 | if not mute: 64 | print(word['response'], end="") 65 | 66 | return response 67 | 68 | class Replicate(Thinker): 69 | 70 | def __init__(self, model_name): 71 | super().__init__(model_name) 72 | 73 | def think(self, prompt, who="user", action="", mute=False, sleep_time=0): 74 | 75 | if action != "" or not mute: 76 | say(who, action) 77 | 78 | response = "" 79 | for event in replicate.stream( 80 | self.model_name, 81 | input={ 82 | "prompt": prompt, 83 | # "max_tokens": 8192, # llama3 84 | # "max_new_tokens": 32000, # mistral 85 | # "max_length": 32000 86 | }, 87 | ): 88 | response = response + str(event) 89 | if not mute: 90 | print(str(event), end="") 91 | 92 | # print(color.RED + ">>" + response + "<<" + color.END) 93 | 94 | return response 95 | 96 | class Claude(Thinker): 97 | 98 | def __init__(self, model_name): 99 | super().__init__(model_name) 100 | 101 | ## make sure ANTHROPIC_API_KEY is exported in shell 102 | ## or it is exported in a .env file 103 | self.client = client = Anthropic() 104 | 105 | def see(self, 106 | prompt, 107 | image_path, 108 | who="user", 109 | max_tokens=2048, 110 | action="👀 looking at the image... ", 111 | mute=False, 112 | sleep_time=1): 113 | 114 | # return "not looking" 115 | 116 | say(who, action + image_path) 117 | 118 | image_data, image_type = image_path_to_data(image_path).values() 119 | 120 | response = self.client.messages.create( 121 | model=self.model_name, 122 | max_tokens=max_tokens, 123 | messages=[ 124 | { 125 | "role": "user", 126 | "content": [ 127 | { 128 | "type": "image", 129 | "source": { 130 | "type": "base64", 131 | "media_type": image_type, 132 | "data": image_data, 133 | }, 134 | }, 135 | { 136 | "type": "text", 137 | "text": prompt, 138 | } 139 | ], 140 | } 141 | ], 142 | ) 143 | 144 | saw_this = response.content[0].text 145 | 146 | # print(color.RED + f">> {saw_this} <<" + color.END) 147 | 148 | return saw_this 149 | 150 | def think(self, prompt, who="user", action="", mute=False, sleep_time=1): # sleep not to exceed the rate limit 151 | 152 | if action != "" or not mute: 153 | say(who, action) 154 | 155 | time.sleep(sleep_time) 156 | 157 | response = "" 158 | with self.client.messages.stream(max_tokens=4096, 159 | messages=[{"role": "user", 160 | "content": prompt}], 161 | model=self.model_name 162 | ) as stream: 163 | for text in stream.text_stream: 164 | if not mute: 165 | print(text, end="", flush=True) 166 | response += text 167 | 168 | # print(color.RED + ">>" + response + "<<" + color.END) 169 | 170 | return response 171 | 172 | class ChatGPT(Thinker): 173 | 174 | def __init__(self, model_name): 175 | super().__init__(model_name) 176 | 177 | ## make sure OPENAI_API_KEY is exported in shell 178 | ## or it is exported in a .env file 179 | self.client = client = OpenAI() 180 | 181 | def think(self, prompt, who="user", action="", mute=False, sleep_time=2): # sleep not to exceed the rate limit 182 | 183 | if action != "" or not mute: 184 | say(who, action) 185 | 186 | time.sleep(sleep_time) 187 | 188 | response = "" 189 | stream = self.client.chat.completions.create( 190 | model=self.model_name, 191 | messages=[{"role": "user", 192 | "content": prompt}], 193 | max_tokens=4096, 194 | stream=True, 195 | ) 196 | for chunk in stream: 197 | thought = chunk.choices[0].delta.content or "" 198 | if not mute: 199 | print(thought, end="") 200 | response += thought 201 | 202 | # print(color.RED + ">>" + response + "<<" + color.END) 203 | 204 | return response 205 | 206 | class Copilot(Thinker): 207 | 208 | def __init__(self, model_name): 209 | super().__init__(model_name) 210 | self.client = colalamo.Copilot() 211 | self.config = {'gpt-3.5-turbo': {'max_tokens': 16384}, 212 | 'gpt-4': {'max_tokens': 4096}} 213 | 214 | ## make sure local gateway is running 215 | def think(self, prompt, who="user", action="", mute=True, sleep_time=2): # sleep not to exceed the rate limit 216 | 217 | if action != "" or not mute: 218 | say(who, action) 219 | 220 | time.sleep(sleep_time) 221 | 222 | response = self.client.ask(messages = [{"role": "user", 223 | "content": prompt}], 224 | model = self.model_name, 225 | max_tokens = self.config.get(self.model_name, {}).get('max_tokens', 4096), 226 | temperature = 0.1) 227 | 228 | if response['status'] != 200: 229 | say(who, f"🚨 could not help you: {response}", message_color=color.RED) 230 | return response 231 | 232 | reply = response['text']['reply'] 233 | 234 | say(who, f"\n\n{reply}", message_color=color.GRAY_MEDIUM_LIGHT) 235 | 236 | # print(color.RED + ">>" + response + "<<" + color.END) 237 | 238 | return reply 239 | 240 | class CustomModel(Thinker): 241 | 242 | def __init__(self, url): 243 | super().__init__(url) 244 | 245 | ## make sure local gateway is running 246 | def think(self, prompt, who="user", action="", mute=True, sleep_time=2): # sleep not to exceed the rate limit 247 | 248 | if action != "" or not mute: 249 | say(who, action) 250 | 251 | time.sleep(sleep_time) 252 | 253 | ask = {"messages": [{"role": "user", 254 | "content": prompt}], 255 | # "temperature": 0.0, 256 | # "max_tokens": 4096, 257 | } 258 | 259 | response = send_post_request(ask, self.model_name) 260 | parsed = json.loads(response) 261 | reply = parsed['reply'] 262 | 263 | say(who, f"\n\n{reply}", message_color=color.GRAY_MEDIUM_LIGHT) 264 | 265 | # print(color.RED + ">>" + response + "<<" + color.END) 266 | 267 | return reply 268 | 269 | ## makes a brain from cli arguments 270 | def make_brain(args, default_models = {'claude': 'claude-3-haiku-20240307', 271 | 'openai': 'gpt-3.5-turbo', 272 | 'ollama': 'llama3:8b-instruct-fp16', 273 | 'replicate': 'meta/meta-llama-3-70b-instruct', 274 | 'copilot': 'gpt-3.5-turbo', 275 | 'custom': 'http://localhost:4242/ask'}): 276 | 277 | model_classes = { 278 | 'claude': Claude, 279 | 'openai': ChatGPT, 280 | 'ollama': Ollama, 281 | 'replicate': Replicate, 282 | 'copilot': Copilot, 283 | 'custom': CustomModel 284 | } 285 | 286 | # make it with the first model argument that is provided 287 | for model_name in model_classes.keys(): 288 | model_arg = getattr(args, model_name, None) 289 | if model_arg is not None: 290 | 291 | model_name_to_use = default_models[model_name] if model_arg is True else model_arg 292 | 293 | brain = model_classes[model_name](model_name_to_use) 294 | print(color.GRAY_MEDIUM + f"{brain}" + color.END) 295 | return brain 296 | 297 | # ollama by default 298 | brain = Ollama(default_models['ollama']) 299 | print(color.GRAY_MEDIUM + f"{brain}" + color.END) 300 | 301 | return brain 302 | 303 | # ---- local models 304 | 305 | # nous-hermes2:10.7b-solar-q4_0 306 | # nous-hermes2:10.7b-solar-q6_K 307 | # mistral:7b-instruct-v0.2-fp16 308 | # dolphin-mistral:7b-v2.6-dpo-laser-fp16 309 | # mixtral:8x7b-instruct-v0.1-q4_K_M 310 | # deepseek-coder:6.7b-instruct-fp16 311 | # gemma:7b-instruct-fp16 312 | # llama3:8b-instruct-fp16 313 | 314 | # ---- claude models 315 | 316 | # claude-3-haiku-20240307 317 | # claude-3-sonnet-20240229 318 | # claude-3-opus-20240229 319 | 320 | # ---- chatgpt models 321 | 322 | # gpt-3.5-turbo-0125 (16K context window) 323 | # gpt-4-32k 324 | # gpt-4-turbo-preview (128K context window) 325 | 326 | # ---- replicate models 327 | 328 | # meta/meta-llama-3-70b-instruct 329 | -------------------------------------------------------------------------------- /jemma/tools.py: -------------------------------------------------------------------------------- 1 | import webbrowser, requests 2 | import os, argparse, sys, re, base64 3 | 4 | from datetime import datetime 5 | 6 | class color: 7 | PURPLE = '\033[95m' 8 | CYAN = '\033[96m' 9 | DARKCYAN = '\033[36m' 10 | BLUE = '\033[94m' 11 | GREEN = '\033[92m' 12 | YELLOW = '\033[93m' 13 | RED = '\033[91m' 14 | GRAY_DARK = '\033[38;5;232m' 15 | GRAY_ME = '\033[38;5;239m' 16 | GRAY_DIUM = '\033[38;5;240m' 17 | GRAY_MEDIUM = '\033[38;5;244m' 18 | GRAY_MEDIUM_LIGHT = '\033[38;5;248m' 19 | GRAY_LIGHT = '\033[38;5;250m' 20 | GRAY_VERY_LIGHT = '\033[38;5;254m' 21 | BOLD = '\033[1m' 22 | UNDERLINE = '\033[4m' 23 | END = '\033[0m' 24 | 25 | def say(who, message, 26 | who_color = color.PURPLE, 27 | message_color = color.CYAN, 28 | newline=True): 29 | print("\n" + color.BLUE + "> " + color.BOLD + who_color + color.UNDERLINE + who + color.END + ": ", end="") 30 | if newline: 31 | print(message_color + message + color.END) 32 | else: 33 | print(message_color + message + color.END, end="") 34 | 35 | def jemma_say(message, 36 | message_color = color.GRAY_ME): 37 | say("[jemma]", 38 | message, 39 | color.GRAY_DIUM, 40 | message_color, 41 | False) 42 | 43 | def read_file(path): 44 | with open(path, 'r') as file: 45 | data = file.read() 46 | return data 47 | 48 | def name_to_file_name(name, extension="txt"): 49 | 50 | clean_name = re.sub(r'[^a-zA-Z0-9\s-]', '', name).replace(' ', '-').lower() 51 | 52 | timestamp = datetime.now().strftime("%Y-%m-%d.%H-%M-%S-%f")[:-3] 53 | return f"{clean_name}.{timestamp}.{extension}" 54 | 55 | def record_prototype(path, prototype): 56 | 57 | os.makedirs(path, exist_ok=True) 58 | 59 | # write the CSS file 60 | css_file_path = os.path.join(path, "app.css") 61 | with open(css_file_path, "w") as css_file: 62 | css_file.write(prototype["css"]) 63 | 64 | if "js" in prototype: 65 | # write the JavaScript file 66 | js_file_path = os.path.join(path, "app.js") 67 | with open(js_file_path, "w") as js_file: 68 | js_file.write(prototype["js"]) 69 | 70 | # write the HTML file 71 | html_file_path = os.path.join(path, "index.html") 72 | with open(html_file_path, "w") as html_file: 73 | html_file.write(prototype["html"]) 74 | 75 | print("\nprototype files created successfully:") 76 | print(f"- {path}/index.html") 77 | if "js" in prototype: 78 | print(f"- {path}/app.js") 79 | print(f"- {path}/app.css") 80 | 81 | 82 | def open_local_browser(dir_path): 83 | current_dir = os.getcwd() 84 | try: 85 | # Get the absolute path of the file 86 | abs_path = os.path.abspath(dir_path) 87 | 88 | # Check if the file exists 89 | if os.path.exists(abs_path): 90 | # Open the file in the default web browser 91 | webbrowser.open(f"file://{abs_path}/index.html") 92 | print(f"opened {dir_path} in the web browser") 93 | else: 94 | print(f"can't find a file system path to open in the browser: {file_path}") 95 | finally: 96 | os.chdir(current_dir) 97 | 98 | def deploy(prototype, path="prototype"): 99 | record_prototype(path, prototype) 100 | open_local_browser(path) 101 | return {"deployed": True, "deploy_path": path} 102 | 103 | def parse_cli_arguments(): 104 | parser = argparse.ArgumentParser( 105 | description='jemma takes in a prompt or a file with requirements and builds a working prototype based on it\n' 106 | ' then it helps you to iterate on it', 107 | formatter_class=argparse.RawTextHelpFormatter, 108 | usage='%(prog)s [-h] [--requirements path-to-file] [--prompt prompt] [--build-prototype]\n' 109 | ' [--claude [model name]] [--openai [model name]] [--ollama [model name]] [--replicate [model name]] [--copilot [model]] [--custom [url]]', 110 | epilog='thoughts in, software out' 111 | ) 112 | 113 | parser.add_argument('--compose', metavar='actions', type=str, nargs='*', default=None, 114 | help='provide a set of actions to compose (e.g., \'--compose get-milk feed-kids launch-mars-expedition\')') 115 | 116 | parser.add_argument('--requirements', metavar='path', type=str, help='path to a text file with requirements') 117 | parser.add_argument('--prompt', metavar='prompt', type=str, help='short idea to convert to creation') 118 | parser.add_argument('--sketch', metavar='sketch', type=str, help='a mockup or a hand drawn sketch to convert to a prototype') 119 | 120 | parser.add_argument('--user-stories', action='store_true', help='create and refine user stories') 121 | parser.add_argument('--build-user-stories', action='store_true', help='build prototype on combined (non-refined) user stories') 122 | 123 | parser.add_argument('--build-prototype', action='store_true', help='build prototype') 124 | parser.add_argument('--test-prototype', action='store_true', help='test prototype') 125 | 126 | parser.add_argument('--claude', metavar='model name', nargs='?', const=True, default=None, help='choose a claude model (optional, can be provided without a value)') 127 | parser.add_argument('--openai', metavar='model name', nargs='?', const=True, default=None, help='choose an open ai model (optional, can be provided without a value)') 128 | parser.add_argument('--ollama', metavar='model name', nargs='?', const=True, default=None, help='choose an ollama model (optional, can be provided without a value)') 129 | parser.add_argument('--replicate', metavar='model name', nargs='?', const=True, default=None, help='choose a model from Replicate (optional, can be provided without a value)') 130 | parser.add_argument('--copilot', metavar='model name ', nargs='?', const=True, default=None, help='use copilot via "colalamo" with an optional model name') 131 | parser.add_argument('--custom', metavar='url', nargs='?', const=True, default=None, help='choose a model running at a custom url (optional, can be provided without a value)') 132 | 133 | if len(sys.argv) == 1 or '-h' in sys.argv or '--help' in sys.argv: 134 | parser.print_help(sys.stderr) 135 | sys.exit(1) 136 | 137 | args = parser.parse_args() 138 | 139 | if args.compose: 140 | tasks = [task.strip() for task in args.compose] 141 | args.tasks = tasks 142 | else: 143 | args.tasks = None 144 | 145 | return args 146 | 147 | 148 | def file_to_utf8(path): 149 | 150 | with open(path, "rb") as file: 151 | image_data = file.read() 152 | encoded = base64.b64encode(image_data) 153 | return encoded.decode("utf-8") 154 | 155 | def image_path_to_type(path): 156 | 157 | extension = path.split(".")[-1].lower() 158 | 159 | media_types = { 160 | "jpg": "image/jpeg", 161 | "jpeg": "image/jpeg", 162 | "png": "image/png", 163 | "gif": "image/gif", 164 | "bmp": "image/bmp", 165 | "tiff": "image/tiff", 166 | "webp": "image/webp", 167 | "svg": "image/svg+xml" 168 | } 169 | 170 | if extension not in media_types: 171 | raise ValueError(f"could not determine an image type. image path: {path}") 172 | 173 | return media_types[extension] 174 | 175 | def image_path_to_data(path): 176 | 177 | return {"image_data": file_to_utf8(path), 178 | "image_type": image_path_to_type(path)} 179 | 180 | def send_post_request(prompt, 181 | url="http://localhost:4242/ask"): 182 | 183 | try: 184 | response = requests.post(url, json = prompt) 185 | response.raise_for_status() # raise an exception for 4xx or 5xx status codes 186 | 187 | # process the response 188 | if response.status_code == 200: 189 | # print(f"response {response.text}") 190 | return response.text 191 | else: 192 | print(f"request failed with status code: {response.status_code}") 193 | 194 | except requests.exceptions.RequestException as e: 195 | print(f"an error occurred: {e}") 196 | -------------------------------------------------------------------------------- /jemma/work/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tolitius/jemma/6b2ec2979a733f7a99c9ff698dc253239ea0d9de/jemma/work/__init__.py -------------------------------------------------------------------------------- /jemma/work/flow.py: -------------------------------------------------------------------------------- 1 | try: 2 | from pyreadline3 import Readline # windows support 3 | readline = Readline() 4 | except ImportError: 5 | import readline 6 | 7 | from functools import partial 8 | from jemma.tools import color, jemma_say, deploy 9 | 10 | def compose_tasks(brain, 11 | project_manager, 12 | designer, ## TODO: project_manager should have a designer OR there should be a Team 13 | engineer, 14 | tasks, 15 | args): 16 | 17 | prompt = args.prompt 18 | sketch = args.sketch 19 | 20 | can_do = { 21 | 'sketch-to-layout': { 22 | 'fn': partial(designer.sketch_to_layout, brain), 23 | 'needs': ['prompt', 'sketch'], 24 | }, 25 | 'sketch-to-spec': { 26 | 'fn': partial(designer.sketch_to_specification, brain), 27 | 'needs': ['prompt', 'sketch'], 28 | }, 29 | 'spec-to-css': { 30 | 'fn': partial(designer.spec_to_css, brain), 31 | 'needs': ['prompt', 'sketch', 'layout', 'spec'], 32 | }, 33 | 'spec-to-html': { 34 | 'fn': partial(designer.spec_to_html, brain), 35 | 'needs': ['prompt', 'sketch', 'layout', 'spec', 'css'], 36 | }, 37 | 'deploy': { 38 | 'fn': partial(deploy), 39 | 'needs': ['css', 'html'], 40 | }, 41 | 'take-feedback': { 42 | 'fn': partial(ask_for_feedback), 43 | 'provide-to': ['spec-to-css', 'spec-to-html'], 44 | }, 45 | ## 'evaluate': { 46 | ## 'fn': partial(tester.validate-foo, brain), 47 | ## 'needs': ['css', 'html'], 48 | ## } 49 | } 50 | 51 | # validate all tasks before execution 52 | unknown_tasks = [task for task in tasks if task not in can_do] 53 | if unknown_tasks: 54 | raise Exception(f"don't know how to do this yet: {', '.join(unknown_tasks)}") 55 | 56 | ## handrolling Clojure's threading macro 57 | memory = {'prompt': prompt, 'sketch': sketch} 58 | 59 | for task in tasks: 60 | fn = can_do[task]['fn'] 61 | needs = can_do[task].get('needs', []) 62 | 63 | ## if this tasks has "needs" validate that all that is "needed" is in memory 64 | missing_needs = [need for need in needs if need not in memory] 65 | if missing_needs: 66 | raise Exception(f"can't do \"{task}\" without \"{', '.join(missing_needs)}\"") 67 | 68 | if needs: 69 | jemma_say(f"task \"{task}\" <<< {list(memory.keys())}") 70 | fact = fn(memory) 71 | else: 72 | jemma_say(f"task \"{task}\" <<< [no input]") 73 | fact = fn() 74 | 75 | ## check that fact is a dict, if not raise an exception 76 | if not isinstance(fact, dict): 77 | raise Exception(f"task \"{task}\" did not return a dict, but {type(fact)} instead: {fact}") 78 | 79 | ## if any of fact keys already exist in memory, communicate a warning that they will be overwritten 80 | existing_facts = [k for k in fact if k in memory] 81 | if existing_facts: 82 | jemma_say(f"(!) task \"{task}\" >>> overwriting {', '.join(existing_facts)}") 83 | 84 | jemma_say(f"task \"{task}\" >>> {fact}") 85 | memory.update(fact) 86 | 87 | return fact 88 | 89 | def create_user_stories(brain, 90 | project_manager, 91 | business_owner, 92 | engineer): 93 | 94 | project_manager.meet_to_create_user_stories(brain, 95 | business_owner) 96 | 97 | ## have another business owner to review the stories 98 | # project_manager.meet_to_review_user_stories(brain, 99 | # business_owner, 100 | # stories) 101 | 102 | project_manager.meet_to_refine_user_stories(brain, 103 | engineer, 104 | business_owner) 105 | 106 | def build_user_stories(brain, 107 | project_manager, 108 | business_owner, 109 | engineer): 110 | project_manager.meet_to_create_user_stories(brain, 111 | business_owner) 112 | # project_manager.meet_to_combine_user_stories(brain, 113 | # business_owner) 114 | project_manager.user_stories_to_requirement() 115 | return project_manager.meet_to_build_prototype(brain, 116 | engineer) 117 | 118 | 119 | def ask_for_feedback(): 120 | 121 | # make sure the cursor works 122 | readline.parse_and_bind('set editing-mode emacs') 123 | 124 | while True: 125 | feedback = input("\n" + color.GREEN + "tell me how to make it better > " + color.END) 126 | if feedback.strip(): 127 | return feedback 128 | elif feedback == "": 129 | return None 130 | 131 | def build_prototype(brain, 132 | project_manager, 133 | designer, 134 | business_owner, 135 | engineer, 136 | prompt = None, 137 | sketch = None): 138 | 139 | prototype = None 140 | 141 | if prompt: 142 | if sketch: 143 | prototype = project_manager.meet_to_create_mockups(brain, 144 | designer, 145 | prompt, 146 | sketch) 147 | else: 148 | project_manager.meet_to_create_requirements(brain, 149 | business_owner, 150 | prompt) 151 | 152 | if not prototype: 153 | prototype = project_manager.meet_to_build_prototype(brain, 154 | engineer) 155 | 156 | while True: 157 | feedback = ask_for_feedback() 158 | if not feedback: 159 | break 160 | 161 | if sketch: 162 | project_manager.meet_to_address_feedback(brain, 163 | designer, 164 | sketch, 165 | feedback) 166 | 167 | prototype = project_manager.meet_to_refactor(brain, 168 | engineer, 169 | prototype, 170 | feedback) 171 | 172 | return prototype 173 | 174 | def test_prototype(brain, 175 | project_manager, 176 | tester): 177 | return project_manager.meet_to_test_prototype(brain, 178 | tester) 179 | 180 | ## create a team to encapsulate agents 181 | def compose(brain, 182 | project_manager, 183 | designer, 184 | business_owner, 185 | engineer, 186 | tester, 187 | args): 188 | 189 | compose_tasks(brain, 190 | project_manager, 191 | designer, 192 | engineer, 193 | args.tasks, 194 | args) 195 | 196 | return None 197 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools >= 61.0"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | [project] 6 | name = "jemma" 7 | version = "0.1.4207" 8 | description = "jemma & her ai agents that build software" 9 | authors = [ 10 | { name = "tolitius" }, 11 | ] 12 | readme = {file = "README.md", content-type = "text/markdown"} 13 | keywords = ["ai", "agents", "llm", "code generation"] 14 | 15 | dependencies = [ 16 | "python-dotenv==1.0.1", 17 | "anthropic==0.21.3", 18 | "openai==1.14.3", 19 | "ollama==0.1.8", 20 | "replicate==0.25.1", 21 | "colalamo==0.1.2106", 22 | "pyreadline3==3.4.1; os_name == 'nt'" 23 | ] 24 | 25 | [project.scripts] 26 | jemma = "jemma.huddle:main" 27 | 28 | [project.urls] 29 | Homepage = "https://github.com/tolitius/jemma" 30 | Documentation = "https://github.com/tolitius/jemma?tab=readme-ov-file#-jemma" 31 | Repository = "https://github.com/tolitius/jemma" 32 | Issues = "https://github.com/tolitius/jemma/issues" 33 | 34 | [tool.setuptools.packages.find] 35 | where = ["."] 36 | include = ["jemma*"] 37 | --------------------------------------------------------------------------------