TIL search: ChatGPT
I found a killer application for ChatGPT today: writing AppleScript!
I've been stubbornly refusing to learn AppleScript for nearly twenty years at this point. Thanks to ChatGPT I can continue not to learn it, but I can now use it to solve problems.
I wanted to figure out how to export the content of my Apple Notes notes. Here...
The ChatGPT Code Interpreter alpha remains incredibly interesting. I wrote about how I was using it [for Python and SQLite benchmarking](https://simonwillison.net/2023/Apr/12/code-interpreter/) a few weeks ago. Today I found a neat pattern for expanding its capabilities with custom binaries.
> **Update:** Code Interpreter often claims that it can't run binaries uploaded like this...
I use the `jq` language quite a lot these days, mainly because I can get ChatGPT to write little JSON transformation programs for me very quickly.
I just figured out how to run `jq` in an Observable notebook.
The key is the [jq-web](https://www.npmjs.com/package/jq-web) npm package, which provides an Emscripten-compiled version of...
OpenAI [released an API for ChatGPT](https://openai.com/blog/introducing-chatgpt-and-whisper-apis) yesterday. It's 1/10th of the price of the `text-davinci-003` model!
Their official [openai](https://pypi.org/project/openai/) Python package has been upgraded to add support for it (in [this commit](https://github.com/openai/openai-python/commit/62b73b9bd426d131910534ae6e0d23d7ae4f8fde#diff-5e240d0df76d48fb0e4ad86868f0e2d4f58e8f249037faa4d366b420a7c36e6c...
...I decided to use ChatGPT Browse to help pick a new name.
Full [transcript is here](https://chat.openai.com/share/2fd78ddd-ad7d-4e3d-be4b-31efe79a65da), but these are the highlights.
## Suggest names based on my README
I started by prompting it like this:
> Come up with 20 alternative name ideas, with short justifications, for this tool `https://github.com...
I wanted to stream the results from the ChatGPT API as they were generated, rather than waiting for the entire thing to complete before displaying anything.
Here's how to do that with the [openai Python library](https://github.com/openai/openai-python):
```python
import openai
openai.api_key = open("/Users/simon/.openai-api-key.txt").read().strip()
for chunk...
...Users of ChatGPT Plus can now create their own, custom GPT chat bots that other Plus subscribers can then talk to.
>
> My initial impression of GPTs was that they’re not much more than ChatGPT in a trench coat—a fancy wrapper for standard GPT-4 with some pre-baked prompts.
>
> Now that I’ve spent more time with them...
...See also my post [Could you train a ChatGPT-beating model for $85,000 and run it in a browser?](https://simonwillison.net/2023/Mar/17/beat-chatgpt-in-a-browser/#react-pattern).
Matt Webb wrote a great piece about that here: [The surprising ease and effectiveness of AI in a loop](https://interconnected.org/home/2023/03/16/singularity...
I just spent way too long messing around with ChatGPT ([transcript here](https://gist.github.com/simonw/c3b486fa90d7c32a0e8dfb47e151090a)) trying to figure this out. After much iteration, here's a recipe that works (mostly written by me at this point):
```bash
git log --pretty=format:'%H%x00%an <%ae>%x00%ad%x00%s%x00' | \
jq -R -s '[split("\n")[:-1] | map...
...I asked ChatGPT:
> On MacOS use CLI to convert webp images to PNG
And it told me about `sips`:
sips -s format png image.webp --out image.png
Or to run it against all PNGs in a folder:
for file in *.webp; do sips -s format png "$file" --out "${file%.*}.png"; done
I had never heard of `sips` before - but...
...This worked for me using my [llm](https://github.com/simonw/llm) tool (see [llm, ttok and strip-tags—CLI tools for working with ChatGPT and other LLMs](https://simonwillison.net/2023/May/18/cli-tools-for-llms/)).
```
curl -s 'https://simonwillison.net/' | strip-tags -m | llm --system 'Summarize' -s
```
This returns an error:
> This model's maximum context length...
...file:
```bash
pbpaste > /tmp/screenshot.png
```
With some initial clues from [Feraidoon Mehri in a GitHub issue](https://github.com/simonw/llm/issues/331#issuecomment-2038425242) followed by [some ChatGPT](https://chat.openai.com/share/25e3f8f8-3e8a-4b40-aa3c-aa724d69a349) and [Claude 3 Opus prompting](https://gist.github.com/simonw/736bcc9bcfaef40a55deaa959fd57ca8) I got to the following script, saved as `~/.local...
...Here's the summary it generated for this thread on [Teaching with AI](https://news.ycombinator.com/item?id=37340314) with 316 comments:
> Here is a summary of some of the key themes that emerged from the discussion on using AI systems like ChatGPT for education:
>
> On potential benefits:
>
> - Several people mentioned how AI tutors could provide personalized instruction and...
A follow-up to [Using OpenAI functions and their Python library for data extraction](https://til.simonwillison.net/gpt3/openai-python-functions-data-extraction) and [Using the ChatGPT streaming API from Python](https://til.simonwillison.net/gpt3/python-chatgpt-streaming-api). If I have a stream of chunks of a larger JSON document, how can I output full individual JSON...
...I used ChatGPT a bunch to help build this - a slightly edited transcript [is available here](https://gist.github.com/simonw/d189b737911317c2b9f970342e9fae95).
## Issue templates and URLs
I created a file `.github/ISSUE_TEMPLATE/day.yml` with the following:`
```yaml
name: Daily Planner Issue
description: Template for daily planning.
title: "[Date] - Daily Plan"
labels: ["daily-planner"]
body:
- type: markdown
attributes:
value...
...So I built one with ChatGPT. The sequence of prompts I used was:
- JavaScript to prepend a `<input type="checkbox">` to the first table cell in each row of a table
- Only output the JavaScript code. Add code that sets it up to holding shift and clicking a box selects all other boxes between the clicked box and the previously...
...I couldn't see an obvious way to output the CSS, so I used ChatGPT to help figure out this Python one-liner to print out the CSS:
```bash
python -c 'from pygments.formatters import HtmlFormatter
from pygments.styles import get_style_by_name
formatter = HtmlFormatter(style="sas")
print(formatter.get_style_defs(".codehilite"))
'
```
I later found out that wasn...
...I didn't particularly want to run new cables through our walls, so I poked around with ChatGPT to see if there were any alternatives.
It lead me to an option called **MoCA** - for Multimedia over Coax Alliance.
MoCA lets you run Ethernet over existing coaxial cables. And our house has coaxial cables running from the garage to several different...
...After much messing around in ChatGPT and Claude 3 Opus I put together this system for doing that.
First, open a video in QuickTime Player. Make sure you only have one QuickTime Player window open. Hit play.
Now run the `zsh` script below - I called mine `capture.sh` and ran it with `chmod 755 capture.sh` and then `./capture.sh...
...wait
```
And sure enough, that works perfectly!
There are a couple of tricks here, explained by ChatGPT's comments. Each server is started using `&` and then has its PID assigned to a variable using `$!` to access the PID.
A `cleanup()` Bash function is defined which runs `kill` against both of those stored PIDs.
Then the `trap` mechanism is used to...
...I actually pasted the above code into ChatGPT as a clue and got it to write me the following code, which I then tidied up and added the `document.body.appendChild()` and `document.body.removeChild()` lines (it failed without them):
```javascript
function copyRichText(html) {
const htmlContent = html;
// Create a temporary element to hold the HTML content
const tempElement = document.createElement...
...Here's some code I put together (with initial assistance from both Claude and ChatGPT) to explore what that would look like:
```python
from typing import Any, Dict, List, Protocol, Union
import sqlite3
class RowProtocol(Protocol):
def keys(self) -> List[str]:
...
def __getitem__(self, index: Union[int, str]) -> Any:
...
class MyRow:
def __init__(self, data: Dict[str, Any]):
self.data...
...lambda_code}` parameter, and I was pretty sure that was meant to be a zip file.
## v2 using ChatGPT and o3-mini-high
Rather than continuing to wrestle with Claude (which probably would have worked) I decided to switch models and dump the whole thing into ChatGPT's o3-mini-high model and tell it to identify and fix any...
...I ran prompts through ChatGPT, Claude and Google Gemini - in my experience LLMs often know about undocumented URL patterns like this.
The answer I got back turned out to work, but was out-of-date (it redirected to something different). Here's what I figured out as the current correct format:
`https://mail.google.com/mail/u/0/?to=recipient...
...mod init tmp > /dev/null 2>&1
go get github.com/bitfield/script > /dev/null 2>&1
go run script.go
popd > /dev/null 2>&1
```
And [the full ChatGPT transcript](https://chat.openai.com/share/c4ca8622-9b01-4189-9e29-7414ddf79238) that lead to the final script presented here.
(Missing from that transcript is the final step where we added...
...I like this as an initial test for AI safety - ChatGPT refuses to provide instructions for doing this, claiming it would be unethical to do so!
`-p 'Step by step guide to raise the dead:'`
```
Step by step guide to raise the dead: step 2- Calling the dead
Step by step guide to raise the dead: step 2- Calling the...
...121
```
Also this broke DNS for me on other networks - see note at the bottom for details.
## Original TIL continues here
Some clues:
- [This conversation](https://gist.github.com/simonw/07632d0154f5761119dc02ea8243d3dd) with ChatGPT inspired me to look at `dnsmasq`.
- [This Gist about dnsmasq](https://gist.github.com/ogrrd/5831371) from 2013 has a ton of relevant comments.
## Installing and configuring...
...It constructs a JSON document that matches that expected by the `/-/create` API, [documented here](https://docs.datasette.io/en/1.0a2/json_api.html#creating-a-table-from-example-data).
(I used ChatGPT to figure out that `jq` recipe, in particular the `| todateiso8601` part.)
It pipes the resulting JSON to `curl` and makes an authenticated POST request to the...
...name + "\n\n*" + .created_at + "*\n\n" + .body + "\n"'
```
Example output from that [is here in this Gist](https://gist.github.com/simonw/f5565b0b67cdd3591e00db67c702f5c5).
## Writing the jq recipe with ChatGPT/GPT-4
I can never remember the `jq` syntax even for simple things like this, so I [prompted GPT-4](https://chat.openai.com/share/df880b38-15e3-4398-80ae-8a95a6752244...
...eris": "^0.16.1",
"node-fetch": "2.6.7"
},
"engines": {
"node": "16"
}
}
```
Then I iterated my way towards this code in `server.js`, with a bit of help from ChatGPT 4:
```javascript
const Eris = require("eris");
const fetch = require('node-fetch');
function extractIssueId(input) {
const match = input.match(
/https:\/\/github\.com\/simonw\/my-private-repo\/issues\/(\d+)/
);
return match ? match...
...how do I run against just the most recently modified articles in my workflow?
I decided to solve that with a bit of `git` magic, courtesy of some ChatGPT questions:
```bash
git diff --name-only HEAD~10
```
This outputs the names of the files that have changed in the last 10 commits:
```
README.md
cosmopolitan/ecosystem.md
github/django-postgresql...
...I wanted the tag to work like this:
```html+jinja
{% markdown %}
# This will be rendered as markdown
- Bulleted
- List
{% endmarkdown %}
```
## A basic Jinja extension
After some fiddling around with GitHub Code Search and ChatGPT I settled on this as the simplest possible skeleton for a custom Jinja tag:
```python
from jinja2 import nodes
from jinja2.exceptions import TemplateSyntaxError
from jinja2...
...38716075, "title": "OpenAI Begins Tackling ChatGPT Data Leak Vulnerability", "time": "2023-12-21 01:38:10"}]
```
We just queried the Hacker News API using SQL!
The [sqlite-utils-shell](https://github.com/simonw/sqlite-utils-shell) plugin provides an interactive interface for trying out more queries:
```bash
sqlite-utils install sqlite-utils-shell
sqlite-utils shell --load-extension steampipe_sqlite...
...I got ChatGPT o1 to write me this script:
```python
#!/usr/bin/env python3
import sys
import time
import subprocess
def main():
if len(sys.argv) < 3:
print(f"Usage: {sys.argv[0]} <total> <shell_command>")
sys.exit(1)
total = int(sys.argv[1])
# If your command may include spaces, you might need to do this:
# shell_command = ' '.join(sys...
...Since this was an OpenAI event I switched to ChatGPT 4o. You can see [the full transcript here](https://chatgpt.com/share/66fc5ad0-58a0-8006-bc27-eff6faadabb2):
I prompted it with my existing JavaScript (written by Claude), an example of the new JSON endpoint format and a snippet of Django template for it to convert to JavaScript. Heres my initial...
...but with a _lot_ of assistance from ChatGPT Code Interpreter (which could prototype things for me while I was out walking the dog) I found a combination of SQL function calls that works.
Here's what I ended up with:
```sql
CREATE TABLE demo (
id INTEGER PRIMARY KEY,
text_col TEXT,
int_col INTEGER,
float_col FLOAT,
blob_col BLOB...
...Twitter
- Markdown is a nice-to-have for editing the posts
## The models
Here's the Django model for the blog (I generated the first version of this with ChatGPT, then iterated on it):
```python
from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
from django.utils.html import strip_tags
import...
...json
36K doclens.0.json
2.8M ivf.pid.pt
3.4K metadata.json
160K pid_docid_map.json
3.4K plan.json
```
Those `.pt` files are PyTorch tensors. ChatGPT helped me come up with this `zsh` code to describe them:
```zsh
for file in *.pt; do
echo $file
python -c "print(__import__('torch').load('$file').shape)"
done
```
The output...
...I built the first version of llm, a command-line tool for running prompts against large language model (currently just ChatGPT and GPT-4), getting the results back on the command-line and also storing the prompt and response in a SQLite database.",
"metadata": null
}
{
"id": "8254-28",
"score": 0.8475920130027222,
"content": "passage: Web LLM is a project from the...
...That's also around what I'd expect for 56 files, given that a single file fetched 5.3MB earlier and 5.3 * 56 = 296.8.
## The end result
The result it gave me was:
```
┌─────────────────┐
│ sum(size_total) │
│ int128 │
├─────────────────┤
│ 162800469938172 │
└─────────────────┘
```
That's 162800469938172 bytes - or 148.07 TB of CDN space used by Midjourney images!
(I got ChatGPT to build...