Skip to main content

AI import

An AI chatbot can read a photo of a song and write it out for Achordeon. You send it the photo, it gives you a file, you import the file. No typing.

There are two ways to get a chatbot to do it. You can teach it once, with the ready-made skill, and then every song after that is just a photo. Or you can paste the whole prompt into the chat each time, which needs nothing set up. The skill is the better of the two, and the prompt is at the bottom of this page for when you cannot use one.

1. Take a photo

  • one song per photo, the whole sheet in the frame
  • two photos if the song runs over two pages, sent together
  • the chords must be readable when you zoom in

2. Teach the chatbot once

There is one file per chatbot, with the same instructions inside all three. Take the one for the chatbot you use. This is a one-off, not something you do per song.

ChatbotWhereFilePlan
Claudeclaude.aiachordeon-song.zipfree is enough
ChatGPTchatgpt.comachordeon-song-gpt.zipa paid plan, Go or Plus or above
Geminigemini.google.comachordeon-song-gem.mdfree is enough

Claude

  1. In Settings > Capabilities, switch on Code execution and file creation. A skill cannot be uploaded or run without it.
  2. Go to Customize > Skills, press +, choose Create skill and then Upload a skill, and pick the zip.

This is the fullest of the three, because Claude can run the scripts the zip carries. It checks its own markup with Achordeon's own parser before it hands anything over, and for a short song it can give you a link instead of a file.

ChatGPT

  1. Unpack the zip. There are three files inside.
  2. Open the GPT builder, Explore GPTs > Create, and on the Configure tab paste the whole of instructions.md into Instructions.
  3. Upload GRAMMAR.md and achordeon.schema.json under Knowledge.

A free account can use a GPT somebody else made, but it cannot make one. If you are on the free plan, use the prompt at the bottom of this page instead.

Gemini

Open Gem manager in the sidebar, make a new Gem, and paste the whole of the downloaded file into the instructions box. It is one file rather than three because a Gem has only the one box, so the markup rules are written inside it.

Why a skill and not a prompt

The three files are generated from the app itself, so none of them can teach you markup the app no longer reads: the list of settings comes from the app's own list, and every example in them is run through the real parser when the files are built. A prompt written out by hand goes out of date quietly. And whatever wrote the file, the import preview tells you before anything is written how many songs have markup Achordeon could not make sense of.

3. Send the photo

Open a chat with the skill, the GPT or the Gem, attach the photo, and ask for the song. 'Write this song for Achordeon' is enough - the instructions are already there, so there is nothing to paste.

Send the next photo the same way. One song at a time, because ten songs in one answer is where mistakes multiply.

4. Import the file

What comes back is the import file, with the song and its settings both inside it.

  • save it with a name ending in .json or .achordeon - take the download if the chatbot offers one, otherwise copy the JSON code block into a plain text file
  • in Songs press Import and pick the file
  • a link, if you were given one instead, opens the same preview when you tap it, with nothing to save first
  • the rules of importing are the same as for any other import

The other way round, without importing: the song text is inside the file, on the content line. Open the file in any text editor, copy that text into a new song in the editor, turn every \n back into a line break, and set the settings by hand.

Check the chords

The chatbot reads what it sees and it can be wrong - a chord one letter off, a word misread from bad handwriting. Compare the render with your photo before you play from it. Everything is editable afterwards.

File can't be read

The JSON was cut off. Ask for it again in one code block and save it without editing it.

Without setting anything up

If you cannot install a skill, or you would rather not, the whole thing fits in one message. Any of these will do. All of them read photos on the free plan, and all you need is an account:

ChatbotWhereMade by
Geminigemini.google.comGoogle
Claudeclaude.aiAnthropic
ChatGPTchatgpt.comOpenAI

Open a new chat, attach the photo, and paste the whole prompt below into the same message. Use the copy button in the corner of the block. For the next song, send the photo in the same chat with 'same again for this photo', the instructions are still there.

This prompt is written out by hand and kept short enough to paste, so it is the smaller half of what the skill knows. Use the skill if you can.

The prompt
I'm attaching a photo of a song's chord sheet. Transcribe it into Achordeon
markup and give me the three things asked for at the end.

# The markup

- `* Title` is the song's title, `** Author` is the subtitle. The marker sits at
the very start of the line, followed by a space. If several appear, the last
one counts.
- A blank line starts a new block (verse, chorus, bridge...), and it is the only
thing that does.
- A block may start with a label: text ending in a colon followed by a space or
the end of the line: `1.: `, `R:: `, `Solo:`. The last colon is swallowed, so
`R::` prints as `R:`.
- A label written on a later line of the same block is a sub-label, naming that
one line, the annotation on a row of chords. `Intro:` then
`Kl. + Bas: [Am F G]` then `Housle: [Am F G]` is one block with two named rows.
- A colon that is not followed by a space is ordinary text (`12:30` is fine). If
a lyric would become a label by accident, escape it: `Narrator\: hello`.
- Chords go inside the lyric line, in square brackets, immediately before the
character they sit above: `tr[C]ade` prints C above the `a`.
- Several chords in one bracket sit in the same spot: `[Em G A]`. A line with
chords and no words prints them in the line itself, at the size of the lyrics,
the usual intro/solo/bridge look.
- Doubled brackets put a chord in the line rather than above it: `[[C]]`. Only
needed on a line that also has words. On a line of chords alone, `[Em G A]`
already prints in the line.
- Bracket text that is not a real chord, such as `[Solo]`, `[2x]`, `[N.C.]` or
`[||: :||]`, is printed above the line exactly as written. Keep it, don't
"fix" it.
- Use English note names. Convert other systems: German `H` becomes `B`, German
`B` becomes `Bb`.
- A backslash makes the next character literal: `\:`, `\*`, `\[`.
- There are no commands for transposing, capo, key, columns or colours. A capo or
key note from the sheet stays a plain line of text or a bracket annotation.

# How to read the sheet

- Transcribe everything: lyrics, chords, section labels, repeat counts, and notes
in the margin ("slowly", "solo = verse", capo, key, tuning). Leave out only
what is about the paper itself, like a page number.
- Chord placement matters most. On the sheet the chords sit on a line above the
words, so put each `[chord]` right before the character it stands over.
- Fix obvious typos, missing accents and broken words, but keep the songwriter's
own words and dialect. Never invent anything you cannot read, say so instead.
- Keep a short list of every correction and every chord you were unsure about.

# The settings

Settings are not part of the text, they travel beside it. Set only what the sheet
plainly shows, usually that is just `columns`, and leave the rest out, so the app's
own defaults apply.

Do not set `aspectRatio`, it is not in the table on purpose. The shape you can read
off my photo is the paper's, and I will be reading the song off a screen. It is the
one setting a song can override outright, so a scan of a portrait page would pin the
song to a portrait page for good and pad the rest of my screen with white. Leave it
out and the song takes the shape I chose in my own settings.

| Setting | Values | Default | Set it when |
| --------------- | -------------------------------------------- | ----------- | -------------------------------------------------------------------- |
| `columns` | `1`, `2`, `3` | `1` | the lyrics are printed in more than one column |
| `titlePosition` | `"top"`, `"left"` | `"top"` | `"left"` only if the title runs sideways up the edge of the page |
| `titleLayout` | `"stacked"`, `"inline"` | `"stacked"` | the author sits beside the title instead of under it |
| `titleFont` | `"body"`, `"serif"`, `"display"`, `"script"` | `"body"` | the title is clearly in a different style of lettering |
| `padding` | a number, in em | `1.25` | the margin around the words is unusually wide or tight |
| `contentX` | `"left"`, `"center"`, `"right"` | `"center"` | leave it out |
| `contentY` | `"top"`, `"middle"`, `"bottom"` | `"middle"` | leave it out |
| `scale` | `"auto"` or a number | `"auto"` | leave it out |
| `chordSize` | a number, `1` is normal | `1` | the chords are clearly bigger or smaller than the words |
| `chordColor` | `"#rrggbb"` | app default | only if I ask for a colour, ink colour on a scan means nothing |
| `notation` | `"english"`, `"german"` | `"english"` | only if I ask for German (H/B) spelling |

# What to give me

1. **Settings**: a table of the settings you chose, with one line of reasoning
each, then your list of corrections and uncertain chords.
2. **Import file**: the JSON below, filled in. Offer it as a `.json` file to
download if you are able to make files, otherwise print it in one code block
and I will save it myself.

Do not write the song out on its own, outside the import file. I have the photo,
so the words are the one thing I do not need twice, and printing them is where an
answer gets stopped part of the way through - which loses me the import file too.

```json
{
"schemaVersion": 1,
"deviceId": "ai-import",
"updatedAt": 1753660800000,
"data": {
"user": [],
"songbooks": [],
"songs": [
{
"id": "6f9619ff-8b86-d011-b42d-00c04fc964ff",
"createdAt": 1753660800000,
"updatedAt": 1753660800000,
"deletedAt": null,
"name": "Wish You Were Here",
"content": "* Wish You Were Here\n** Pink Floyd\n\n[Em G Em G Em A Em A G]\n",
"favorite": false,
"settings": { "columns": 1 },
"cache": { "title": "Wish You Were Here", "subtitle": "Pink Floyd" }
}
]
}
}
```

- `content` is the markup, as a single JSON string: `\n` for line breaks, `\"`
for quotes.
- `id` is any random UUID. The three time fields are the current time in
milliseconds since 1970 (a 13-digit number).
- `name` is my label for the song in the library, so use the title.
- `cache` holds exactly the text of the effective `*` and `**` lines, or `""`
when the song has none.
- `settings` holds only keys from the table above, `{}` if none. Never invent a
key that is not listed.
- Leave `schemaVersion`, `deviceId`, `user`, `songbooks`, `favorite` and
`deletedAt` exactly as they are.
- The JSON must be valid and complete: no comments, no trailing commas, nothing
left out.