Created
November 20, 2025 15:59
-
-
Save fredguth/a86aff093fc1b664c253494f1ff559e0 to your computer and use it in GitHub Desktop.
solveish_v3
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": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "from fastcore.utils import *\n", | |
| "from fasthtml.common import *\n", | |
| "from fasthtml.jupyter import *\n", | |
| "import fasthtml.components as fc\n", | |
| "from toolslm.shell import get_shell\n", | |
| "from lisette import *\n", | |
| "import random" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "# Setup\n", | |
| "daisy_hdrs = (\n", | |
| " Link(href='https://cdn.jsdelivr.net/npm/daisyui@5', rel='stylesheet', type='text/css'),\n", | |
| " Script(src='https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4'),\n", | |
| " Link(href='https://cdn.jsdelivr.net/npm/daisyui@5/themes.css', rel='stylesheet', type='text/css')\n", | |
| ")\n", | |
| "app = FastHTML(hdrs=daisy_hdrs, session_cookie='mysessioncookie')\n", | |
| "rt = app.route\n", | |
| "preview = partial(HTMX, app=app, host=None, port=None)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "# Component wrappers\n", | |
| "def mk_comp(name, compcls):\n", | |
| " comp = getattr(fc, name)\n", | |
| " def wrapper(*args, cls='', **kwargs): return comp(*args, cls=f'{compcls} {cls}', **kwargs)\n", | |
| " globals()[name] = wrapper\n", | |
| "mk_comp('Button', 'btn')\n", | |
| "mk_comp('Input', 'input')" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "# Check if string is valid Python code\n", | |
| "def is_code(code):\n", | |
| " try:\n", | |
| " compile(code, '<string>', 'eval')\n", | |
| " return True\n", | |
| " except SyntaxError:\n", | |
| " try:\n", | |
| " compile(code, '<string>', 'exec')\n", | |
| " return True\n", | |
| " except SyntaxError: return False" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "# Execute code in shell\n", | |
| "def ex(s, sh):\n", | |
| " res = sh.run_cell(s)\n", | |
| " return res.result if res.result else res.stdout" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "# LLM setup\n", | |
| "sysp = \"You are a chat model, in a chat with a user that also includes code executions. Given the chat history as context, answer the user's current question concisely.\"\n", | |
| "def cts(r): return r.choices[0].message.content" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "# Store per-user chats and shells\n", | |
| "user_chats = {}" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "# Render a message as HTML\n", | |
| "def render_message(msg):\n", | |
| " color = 'info' if msg['author'] == 'user' else 'accent' if msg['author'] == 'ai' else 'primary'\n", | |
| " align = 'end' if msg['author'] == 'user' else 'start'\n", | |
| " return Div(Div(msg['content'], cls=f'chat-bubble chat-bubble-{color}'), cls=f'chat chat-{align}') if msg['content'] else \"\"" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "# Process submitted code or question\n", | |
| "@rt\n", | |
| "def proc_code(code:str, session):\n", | |
| " if 'userid' not in session: return\n", | |
| " h, sh = user_chats[session['userid']]\n", | |
| " c = is_code(code)\n", | |
| " if c: res = ex(code, sh)\n", | |
| " else:\n", | |
| " ctx = \"Past context/conversation: \" + \"\\n\".join([str(msg['content']) for msg in h])\n", | |
| " res = cts(Chat(model='claude-haiku-4-5', sp=sysp)(ctx + \"\\n\\nCurrent question: \" + code))\n", | |
| " h += {'content': code, 'author': 'user'}, {'content': res, 'author': 'ai' if not c else 'computer'}\n", | |
| " return (render_message({'content': code, 'author': 'user'}), \n", | |
| " render_message({'content': res, 'author': 'ai' if not c else 'computer'}), \n", | |
| " Input(type='text', placeholder='Enter code...', id='code', hx_swap_oob='true', cls='flex-1'))" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "# Clear chat history\n", | |
| "@rt\n", | |
| "def clear_chat(session):\n", | |
| " if 'userid' not in session: return\n", | |
| " if session['userid'] not in user_chats: return\n", | |
| " user_chats[session['userid']] = ([], get_shell())\n", | |
| " return Div(id='chat', cls='mb-4 border rounded-lg p-4 h-[400px] overflow-y-auto')" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "# Main chat page\n", | |
| "@rt\n", | |
| "def chatdemo(session):\n", | |
| " if 'userid' not in session: session['userid'] = random.randint(0, 1_000_000)\n", | |
| " if session['userid'] not in user_chats:\n", | |
| " user_chats[session['userid']] = ([], get_shell())\n", | |
| " h, _ = user_chats[session['userid']]\n", | |
| " bubs = [render_message(m) for m in h]\n", | |
| " return Div(\n", | |
| " H1('Code Chat', cls='text-3xl font-bold mb-4 text-center'),\n", | |
| " Div(*bubs, id='chat', cls='mb-4 border rounded-lg p-4 h-[400px] overflow-y-auto'),\n", | |
| " Form(hx_post=proc_code, hx_target='#chat', hx_swap='beforeend', cls='flex gap-2')(\n", | |
| " Input(type='text', placeholder='Enter code...', id='code', cls='flex-1'),\n", | |
| " Button('Run', type='submit', cls='btn-primary'), \n", | |
| " Button('Clear', type='button', cls='btn-secondary', hx_post=clear_chat, hx_target='#chat', hx_swap='outerHTML')\n", | |
| " ), cls='p-4', style='max-width:600px'\n", | |
| " )" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "# Start server\n", | |
| "srv = JupyUvi(app, port=3004)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "# Preview the app\n", | |
| "preview(chatdemo)" | |
| ] | |
| } | |
| ], | |
| "metadata": { | |
| "kernelspec": { | |
| "display_name": "Python 3", | |
| "language": "python", | |
| "name": "python3" | |
| }, | |
| "language_info": { | |
| "name": "python", | |
| "version": "3.12.0" | |
| } | |
| }, | |
| "nbformat": 4, | |
| "nbformat_minor": 2 | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment