{"slug": "test-a-custom-prompt-against-an-already-trained-already-flashed-esp32-s3-model", "title": "Test a custom prompt against an already-trained, already-flashed ESP32-S3 model", "summary": "A developer released a shell script that lets users test custom prompts against an already-trained ESP32-S3 model without retraining or rewriting the 15MB model partition. The script tokenizes the prompt, patches the firmware sketch, and recompiles and flashes only the app, leaving the model untouched.", "body_md": "| #!/usr/bin/env bash | |\n| # esp32-ai: test a custom prompt against an already-trained, already-flashed model. | |\n| # Does NOT retrain and does NOT rewrite the 15MB model partition. | |\n| # | |\n| # Usage: | |\n| # ./run_custom_prompt.sh \"Once there was a robot\" | |\n| set -euo pipefail | |\n| if [ \"$#\" -lt 1 ]; then | |\n| echo \"Usage: $0 \\\"Your custom prompt\\\"\" | |\n| exit 1 | |\n| fi | |\n| PROMPT=\"$1\" | |\n| REPO_DIR=\"esp32-ai\" | |\n| if [ -f \"$REPO_DIR/pyproject.toml\" ]; then | |\n| cd \"$REPO_DIR\" | |\n| elif [ ! -f \"pyproject.toml\" ]; then | |\n| echo \"Can't find the esp32-ai repo. Run this from the same folder as build_and_flash.sh, after it has cloned esp32-ai.\" | |\n| exit 1 | |\n| fi | |\n| if [ ! -f \"data/bpe32768.json\" ]; then | |\n| echo \"data/bpe32768.json not found. Run build_and_flash.sh at least once first (it trains the tokenizer).\" | |\n| exit 1 | |\n| fi | |\n| # ---- Detect port ---- | |\n| CANDIDATE_PORTS=(/dev/cu.usbmodem*) | |\n| if [ ! -e \"${CANDIDATE_PORTS[0]}\" ]; then | |\n| echo \"No /dev/cu.usbmodem* device found. Is the board plugged in?\" | |\n| exit 1 | |\n| elif [ \"${#CANDIDATE_PORTS[@]}\" -eq 1 ]; then | |\n| ESP32_PORT=\"${CANDIDATE_PORTS[0]}\" | |\n| else | |\n| select choice in \"${CANDIDATE_PORTS[@]}\"; do | |\n| [ -n \"$choice\" ] && ESP32_PORT=\"$choice\" && break | |\n| done | |\n| fi | |\n| echo \">> Using port: $ESP32_PORT\" | |\n| # ---- Tokenize the custom prompt with the same tokenizer gen_assets.py uses ---- | |\n| echo \">> Tokenizing prompt: \\\"$PROMPT\\\"\" | |\n| TOKENIZE_SCRIPT=\"$(mktemp /tmp/tokenize_prompt_XXXX.py)\" | |\n| cat > \"$TOKENIZE_SCRIPT\" << 'PYEOF' | |\n| import sys | |\n| from tokenizers import Tokenizer | |\n| tok = Tokenizer.from_file(\"data/bpe32768.json\") | |\n| prompt = sys.argv[1] | |\n| ids = tok.encode(prompt).ids | |\n| print(f'prompt \"{prompt}\" -> {len(ids)} ids: {ids}') | |\n| print(f\"round-trip: {tok.decode(ids)!r}\") | |\n| print(\"static const int PROMPT_IDS[] = {\" + \", \".join(map(str, ids)) + \"};\") | |\n| PYEOF | |\n| GEN_OUTPUT=\"$(uv run python \"$TOKENIZE_SCRIPT\" \"$PROMPT\")\" | |\n| rm -f \"$TOKENIZE_SCRIPT\" | |\n| echo \"$GEN_OUTPUT\" | |\n| PROMPT_IDS_LINE=\"$(echo \"$GEN_OUTPUT\" | grep -o 'static const int PROMPT_IDS\\[\\] = {[^}]*};')\" | |\n| if [ -z \"$PROMPT_IDS_LINE\" ]; then | |\n| echo \"!! Couldn't parse a PROMPT_IDS line out of the tokenizer output. Aborting.\" | |\n| exit 1 | |\n| fi | |\n| echo \">> New prompt line: $PROMPT_IDS_LINE\" | |\n| # ---- Paste it into the sketch ---- | |\n| SKETCH_FILE=\"firmware/esp32_llm/esp32_llm.ino\" | |\n| sed -i.bak -E \"s/static const int PROMPT_IDS\\[\\] = \\{[^}]*\\};/${PROMPT_IDS_LINE//\\//\\\\/}/\" \"$SKETCH_FILE\" | |\n| # ---- Rebuild and reflash just the app (model partition untouched) ---- | |\n| FQBN='esp32:esp32:esp32s3:UploadSpeed=921600,USBMode=hwcdc,CDCOnBoot=default,UploadMode=default,CPUFreq=240,FlashMode=qio,FlashSize=16M,PartitionScheme=custom,PSRAM=opi,DebugLevel=info' | |\n| echo \">> Recompiling firmware with new prompt...\" | |\n| arduino-cli compile \\ | |\n| --fqbn \"$FQBN\" \\ | |\n| --build-property compiler.optimization_flags=-O3 \\ | |\n| --build-path /tmp/esp32-llm-uart \\ | |\n| firmware/esp32_llm | |\n| echo \">> Flashing app (model partition is untouched)...\" | |\n| arduino-cli upload -p \"$ESP32_PORT\" \\ | |\n| --fqbn \"$FQBN\" \\ | |\n| --input-dir /tmp/esp32-llm-uart firmware/esp32_llm | |\n| echo \">> Opening serial monitor. Press the board's RESET button now.\" | |\n| arduino-cli monitor -p \"$ESP32_PORT\" --config baudrate=115200 |", "url": "https://wpnews.pro/news/test-a-custom-prompt-against-an-already-trained-already-flashed-esp32-s3-model", "canonical_source": "https://gist.github.com/andrisgauracs/e84b842d0f5e301485ecbf6654b0838e", "published_at": "2026-07-31 02:57:35+00:00", "updated_at": "2026-08-01 13:58:34.603139+00:00", "lang": "en", "topics": ["developer-tools", "machine-learning", "artificial-intelligence"], "entities": ["ESP32-S3", "esp32-ai", "Arduino CLI", "Hugging Face Tokenizers"], "alternates": {"html": "https://wpnews.pro/news/test-a-custom-prompt-against-an-already-trained-already-flashed-esp32-s3-model", "markdown": "https://wpnews.pro/news/test-a-custom-prompt-against-an-already-trained-already-flashed-esp32-s3-model.md", "text": "https://wpnews.pro/news/test-a-custom-prompt-against-an-already-trained-already-flashed-esp32-s3-model.txt", "jsonld": "https://wpnews.pro/news/test-a-custom-prompt-against-an-already-trained-already-flashed-esp32-s3-model.jsonld"}}