-
-
Save galopyz/758d52efbb3f8f80a56abf0a1d188c32 to your computer and use it in GitHub Desktop.
My Dialog
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "cells": [ | |
| { | |
| "cell_type": "markdown", | |
| "id": "c635be77", | |
| "metadata": { | |
| "input_tokens": 9 | |
| }, | |
| "source": [ | |
| "# TODO app in Solveit" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "id": "2c1758a0", | |
| "metadata": { | |
| "input_tokens": 72 | |
| }, | |
| "source": [ | |
| "We will build a simple todo app in solveit. The example we will use is [todo4.py](https://github.com/AnswerDotAI/fasthtml/blob/main/examples/todos4.py) from fasthtml examples.\n", | |
| "\n", | |
| "\n" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "id": "fdf35de0", | |
| "metadata": { | |
| "input_tokens": 85 | |
| }, | |
| "source": [ | |
| "To run a FastHTML example code in solveit, we have to make some adjustments.\n", | |
| "\n", | |
| "- Change routes from `/` to something else because solveit uses `/`. We will use `/hp`.\n", | |
| "- Only GET and POST methods work. To DELETE or PUT, we will use POST." | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "id": "75a31f93", | |
| "metadata": { | |
| "input_tokens": 34 | |
| }, | |
| "source": [ | |
| "We first import fasthtml and monsterui. Then we also import dialoghelper because we are in solveit.\n" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "id": "4b63932f", | |
| "metadata": { | |
| "input_tokens": 51, | |
| "time_run": "4:26:14p" | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "from fasthtml.common import *\n", | |
| "from fasthtml.jupyter import *\n", | |
| "from monsterui.all import *\n", | |
| "\n", | |
| "from dialoghelper import *\n", | |
| "from contextkit import read_gh_file" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "id": "a2bce162", | |
| "metadata": { | |
| "input_tokens": 31 | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "# Run once to create a note cell containing all the tools available in dialoghelper\r\n", | |
| "# tool_info()" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "id": "8428c717", | |
| "metadata": { | |
| "input_tokens": 270 | |
| }, | |
| "source": [ | |
| "Tools available from `dialoghelper`:\n", | |
| "\n", | |
| "- &`curr_dialog`: Get the current dialog info.\n", | |
| "- &`msg_idx`: Get absolute index of message in dialog.\n", | |
| "- &`add_html`: Send HTML to the browser to be swapped into the DOM using hx-swap-oob.\n", | |
| "- &`find_msg_id`: Get the current message id.\n", | |
| "- &`find_msgs`: Find messages in current specific dialog that contain the given information.\n", | |
| " - (solveit can often get this id directly from its context, and will not need to use this if the required information is already available to it.)\n", | |
| "- &`read_msg`: Get the message indexed in the current dialog.\n", | |
| "- &`del_msg`: Delete a message from the dialog.\n", | |
| "- &`add_msg`: Add/update a message to the queue to show after code execution completes.\n", | |
| "- &`update_msg`: Update an existing message." | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "id": "b6a2abc2", | |
| "metadata": { | |
| "input_tokens": 13 | |
| }, | |
| "source": [ | |
| "Let's grab an example we want to use." | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "id": "e3bc79cd", | |
| "metadata": { | |
| "input_tokens": 49, | |
| "output_tokens": 84, | |
| "time_run": "4:26:18p" | |
| }, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "\"from fasthtml.common import *\\n\\ndb = database('data/todos.db')\\ntodos = db.t.todos\\nif todos not in db.\"" | |
| ] | |
| }, | |
| "execution_count": 4, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "gh_file = read_gh_file('https://github.com/AnswerDotAI/fasthtml/blob/main/examples/todos4.py')\r\n", | |
| "gh_file[:100]" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "id": "4dc42598", | |
| "metadata": { | |
| "input_tokens": 138 | |
| }, | |
| "source": [ | |
| "Using a prompt like `Can you split the code in $gh_file into smaller chunks with one function definition in each code cell? Also separate variable declrations or library imports. Use the tools from dialoghelper.`, we can use dialoghelper to cut the python script into smaller pieces. It may add the code cells in reverse order. There is also a limit on how many loops we can use in a tool loop, so it may not finish splitting." | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "id": "8adc4503", | |
| "metadata": { | |
| "input_tokens": 66, | |
| "time_run": "4:26:20p" | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "db = database('data/todos.db')\n", | |
| "todos = db.t.todos\n", | |
| "if todos not in db.t: todos.create(id=int, title=str, done=bool, pk='id')\n", | |
| "Todo = todos.dataclass()" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "id": "ec747851", | |
| "metadata": { | |
| "input_tokens": 6, | |
| "output_tokens": 19, | |
| "time_run": "4:30:02p" | |
| }, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "[]" | |
| ] | |
| }, | |
| "execution_count": 20, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "db.t.todos()" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "id": "1f151b48", | |
| "metadata": { | |
| "input_tokens": 28, | |
| "time_run": "4:26:27p" | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "id_curr = 'current-todo'\n", | |
| "def tid(id): return f'todo-{id}'" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "id": "3f85c149", | |
| "metadata": { | |
| "input_tokens": 51 | |
| }, | |
| "source": [ | |
| "To serve a FastHTML app in solveit, we need to use `nb_serve`. And we use `render_ft` to render fast tags in solveit." | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "id": "0b2d118f", | |
| "metadata": { | |
| "input_tokens": 120, | |
| "time_run": "4:26:29p" | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "if 'srv' not in globals() or not srv: # Checking it doesn't already exists for if we 'run all' - not always needed\n", | |
| " css = Style(':root { --pico-font-size: 100%; }')\n", | |
| " app = FastHTML(hdrs=(picolink, css))\n", | |
| " rt = app.route\n", | |
| " srv = nb_serve(app)\n", | |
| "\n", | |
| "render_ft()" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "id": "bf06e09b", | |
| "metadata": { | |
| "input_tokens": 100 | |
| }, | |
| "source": [ | |
| "Here are some things we have to do to run the app in solveit:\n", | |
| "\n", | |
| "- Change routes from `/` to something else because solveit uses `/`. We will use `/hp`.\n", | |
| "- Only GET and POST methods work. To DELETE or PUT, we will use POST.\n", | |
| "\n", | |
| "We can use dialoghelper to find and replace those routes." | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "id": "49dadcec", | |
| "metadata": { | |
| "input_tokens": 40, | |
| "time_run": "4:26:34p" | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "@rt(\"/{fname:path}.{ext:static}\")\n", | |
| "def get(fname:str, ext:str): return FileResponse(f'{fname}.{ext}')" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "id": "54457332", | |
| "metadata": { | |
| "input_tokens": 117, | |
| "time_run": "4:26:38p" | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "@patch\r\n", | |
| "def __ft__(self:Todo):\r\n", | |
| " show = AX(self.title, f'/todos/{self.id}', id_curr)\r\n", | |
| " edit = AX('edit', f'/edit/{self.id}' , id_curr)\r\n", | |
| " dt = ' (done)' if self.done else ''\r\n", | |
| " return Li(show, dt, ' | ', edit, id=tid(self.id))\r" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "id": "69a97297", | |
| "metadata": { | |
| "input_tokens": 22, | |
| "output_tokens": 57, | |
| "time_run": "4:26:39p" | |
| }, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/markdown": [ | |
| "<div>\n", | |
| "<a href=\"#\" hx-get=\"https://www.google.com/\">click bait</a><script>if (window.htmx) htmx.process(document.body)</script></div>\n" | |
| ], | |
| "text/plain": [ | |
| "a(('click bait',),{'href': '#', 'hx-get': 'https://www.google.com/'})" | |
| ] | |
| }, | |
| "execution_count": 11, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "AX('click bait', 'https://www.google.com/', 0)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "id": "1975ac07", | |
| "metadata": { | |
| "input_tokens": 42, | |
| "output_tokens": 64, | |
| "time_run": "4:26:42p" | |
| }, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/markdown": [ | |
| "<div>\n", | |
| " <input name=\"title\" placeholder=\"New Todo\" id=\"new-title\" class=\"uk-input \">\n", | |
| "<script>if (window.htmx) htmx.process(document.body)</script></div>\n" | |
| ], | |
| "text/plain": [ | |
| "input((),{'name': 'title', 'placeholder': 'New Todo', 'id': 'new-title', 'class': 'uk-input '})" | |
| ] | |
| }, | |
| "execution_count": 12, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "def mk_input(**kw): return Input(id=\"new-title\", name=\"title\", placeholder=\"New Todo\", **kw)\n", | |
| "mk_input()" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "id": "2845f02f", | |
| "metadata": { | |
| "input_tokens": 28, | |
| "time_run": "4:26:44p" | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "def clr_details(): return Div(hx_swap_oob='innerHTML', id=id_curr)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "id": "272887fd", | |
| "metadata": { | |
| "input_tokens": 114, | |
| "time_run": "4:26:45p" | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "@rt(\"/hp\")\n", | |
| "def get(request):\n", | |
| " add = Form(Group(mk_input(), Button(\"Add\")),\n", | |
| " hx_post=\"/hp\", target_id='todo-list', hx_swap=\"afterbegin\")\n", | |
| " card = Card(Ul(*todos(), id='todo-list'),\n", | |
| " header=add, footer=Div(id=id_curr)),\n", | |
| " return Titled('Todo list', card)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "id": "d1e0e55e", | |
| "metadata": { | |
| "input_tokens": 69 | |
| }, | |
| "source": [ | |
| "After we setup `get` into `/hp` route, we can check our web app running in a new tab. Go to `https://whatever_secret_stuff.solveit.fast.ai/hp` and check the todo app." | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "id": "4b6cd296", | |
| "metadata": { | |
| "input_tokens": 39, | |
| "time_run": "4:27:23p" | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "@rt(\"/hp\")\n", | |
| "def post(todo:Todo): return todos.insert(todo), mk_input(hx_swap_oob='true')" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "id": "00225d90", | |
| "metadata": { | |
| "input_tokens": 24 | |
| }, | |
| "source": [ | |
| "After seting the `post` to `/hp`, try adding a todo." | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "id": "901f1543", | |
| "metadata": { | |
| "input_tokens": 103, | |
| "time_run": "4:28:18p" | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "@rt(\"/edit/{id}\")\n", | |
| "def get(id:int):\n", | |
| " res = Form(Group(Input(id=\"title\"), Button(\"Save\")),\n", | |
| " Hidden(id=\"id\"), CheckboxX(id=\"done\", label='Done'),\n", | |
| " hx_post=\"/edit/todos\", target_id=tid(id), id=\"edit\")\n", | |
| " return fill_form(res, todos[id])" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "id": "e858ee7f", | |
| "metadata": { | |
| "input_tokens": 31, | |
| "time_run": "4:28:20p" | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "@rt(\"/edit/todos\")\n", | |
| "def post(todo: Todo): return todos.update(todo), clr_details()" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "id": "db9b40d2", | |
| "metadata": { | |
| "input_tokens": 15 | |
| }, | |
| "source": [ | |
| "Now we can click the edit button and edit." | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "id": "a2196650", | |
| "metadata": { | |
| "input_tokens": 36, | |
| "time_run": "4:29:02p" | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "@rt(\"/delete/todos/{id}\")\n", | |
| "def post(id:int):\n", | |
| " todos.delete(id)\n", | |
| " return clr_details()" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "id": "e2300f91", | |
| "metadata": { | |
| "input_tokens": 90, | |
| "time_run": "4:29:04p" | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "@rt(\"/todos/{id}\")\n", | |
| "def get(id:int):\n", | |
| " todo = todos[id]\n", | |
| " btn = Button('delete', hx_post=f'/delete/todos/{todo.id}',\n", | |
| " target_id=tid(todo.id), hx_swap=\"outerHTML\")\n", | |
| " return Div(Div(todo.title), btn)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "id": "a4c752b7", | |
| "metadata": { | |
| "input_tokens": 21 | |
| }, | |
| "source": [ | |
| "We can delete todos by clicking the todo and clicking the delete button." | |
| ] | |
| } | |
| ], | |
| "metadata": { | |
| "solveit_dialog_mode": "learning", | |
| "solveit_ver": 2 | |
| }, | |
| "nbformat": 4, | |
| "nbformat_minor": 5 | |
| } |
Author
Thanks for reading and giving me a heads up. I am using the version automatically deployed in solveit. I did not pip install dialoguehelper. I encourage you to try it out. It is a very fun tool set.
ah sorry about that! understood and will definitely try it out! :)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks for sharing this example, super helpful! As a heads-up, I just saw in a discord post from Jeremy on July 15th that we shouldn't pip install dialogue helper into solveit, so it seems like it would be good to remove this from the example:
https://discord.com/channels/1303610061167263814/1310989166875508849/1394757116891238511