What you will get
Three replace tables. One writes product names the way your company spells them. One expands a short phrase into an email sign-off. One writes units as symbols.
| You say | You get |
|---|---|
| we moved billing to northwind pay last week | we moved billing to Northwind Pay last week |
| North Wind Cloud Plus is live for every customer | Northwind Cloud+ is live for every customer |
| the run was twelve kilometers | the run was 12 km |
| it is twenty two degrees celsius in the office | it is 22 °C in the office |
| the image is two point five gigabytes | the image is 2.5 GB |
“Thanks for the update. Insert signature.” gives:
Thanks for the update.
Best regards,
Alex Martin
Each output above is the real result of --replace on that sentence. A replace table needs no model and costs nothing at run time.
How a replace table works
A transform with a replace: body is a table. Each key is the text to write. Its list holds what to look for.
- A plain phrase matches as whole words, in any case.
'Northwind Pay': ['northwind pay']also catches “Northwind pay” and “NORTHWIND PAY”. - A pattern between slashes is a regular expression. It also ignores case.
$1in the key is what the first group in brackets captured.$2is the second group. This works only when the source is a pattern. With a plain phrase, the key is written exactly as typed,$included.- An empty key deletes what matched. The shipped
fillersrule deletes “um” and “uh” this way.
A transform runs on a dictation only when transcription.pipeline has a step for it. Define the table and skip the step, and nothing happens. We checked this: with the tables below defined and no step, --replace "we moved billing to northwind pay last week" printed the sentence unchanged.
Steps
-
Open
~/.config/parrotflow/config.yaml. From the menu bar, use Settings, then Edit Config. -
Add the three tables under the
transforms:key that is already in the file. Do not add a secondtransforms:key. Put your own product names and your own name in place of ours.transforms: - name: product_names description: our product names, written the way marketing writes them replace: 'Northwind Cloud+': ['northwind cloud plus', 'north wind cloud plus'] 'Northwind Pay': ['northwind pay', 'north wind pay'] - name: signature description: my email sign-off replace: "\n\nBest regards,\nAlex Martin": ['/,?\s*\binsert (?:my )?signature\b\.?/'] - name: units description: spoken units as symbols replace: '$1 km': ['/\b(\d+(?:\.\d+)?) (?:kilometers|kilometres)\b/'] '$1 °C': ['/\b(\d+(?:\.\d+)?) degrees? (?:celsius|centigrade)\b/'] '$1 GB': ['/\b(\d+(?:\.\d+)?) gigabytes?\b/']What each one does:
product_nameslists two spellings of each name. The recogniser can write “Northwind” as one word or as “North Wind”, and a plain phrase only matches what it is given.signatureuses a pattern so it can take the comma before “insert signature” and the full stop after it. The key is in double quotes, so YAML turns each\ninto a line break.unitscaptures the number in(\d+(?:\.\d+)?)and writes it back with$1.
-
Add a step for each table to
transcription.pipeline.unitsgoes right afternumbers_en, because it needs digits andnumbers_enis the step that writes them. The other two can go at the end. This is the default pipeline with the three new steps:transcription: pipeline: - transform: fillers - transform: fillers_fr when: language == "fr" - transform: dates_en - transform: numbers_en - transform: units - transform: money_en - transform: disfluency - transform: product_names - transform: signature -
Save the file. The app reloads it at once.
Check that it worked
The commands below use the full path to the app. If you installed with Homebrew, parrotflow runs the same binary.
Ask the app what it loaded:
/Applications/ParrotFlow.app/Contents/MacOS/ParrotFlow --check-config
The pipeline line names the new steps in order:
· pipeline sentence_repair → vocabulary → transform fillers → transform fillers_fr when language == "fr" → transform dates_en → transform numbers_en → transform units → transform money_en → transform disfluency → transform product_names → transform signature
The replace section counts the rules in each table:
table product_names — 4 rule(s), our product names, written the way marketing writes them
table signature — 1 rule(s), my email sign-off
table units — 3 rule(s), spoken units as symbols
Then run sentences through your pipeline. --replace uses your config and skips the steps that call a model.
/Applications/ParrotFlow.app/Contents/MacOS/ParrotFlow --replace "the run was twelve kilometers"
the run was 12 km
Try sentences that must not change too. These came back as they went in:
| Sentence | Why it stays |
|---|---|
| upgrade to northwind cloud | No rule lists “northwind cloud” without “plus”. |
| a few kilometers away | The pattern needs a number before “kilometers”. |
| please sign the contract | The pattern needs the words “insert signature”. |
Last, dictate one of the sentences into any text field.
To see what the recogniser really wrote for a phrase, dictate it once and read the log. Each dictation adds a transcribed: line:
grep "transcribed:" ~/Library/Logs/ParrotFlow.log | tail -1
Add that spelling to the list if your rule missed it.
Order matters
Between steps
Steps run from top to bottom. Each step gets the text as the steps above it left it.
We moved units above numbers_en and ran the same sentence:
the run was 12 kilometers
units ran first and saw “twelve kilometers”, with no digits, so it did nothing. Then numbers_en wrote the digits. With units below numbers_en, the result is the run was 12 km.
Inside one table
The order of the keys inside one table is not fixed. Do not put two rules that match the same words in one table.
We tested this table on “northwind cloud plus is live” ten times:
replace:
'NW Cloud': ['northwind cloud']
'NW Cloud+': ['northwind cloud plus']
It gave NW Cloud+ is live six times and NW Cloud plus is live four times. When the shorter rule ran first, the longer one had nothing left to match.
Put the longer phrase in its own transform, and give it the earlier step:
transforms:
- name: long_names
description: product names with a suffix
replace:
'NW Cloud+': ['northwind cloud plus']
- name: short_names
description: product names without a suffix
replace:
'NW Cloud': ['northwind cloud']
transcription:
pipeline:
# the steps already in your config stay here
- transform: long_names
- transform: short_names
On “northwind cloud plus is live, northwind cloud is not” this gave NW Cloud+ is live, NW Cloud is not on all six runs.
Write patterns in single quotes
In single quotes, YAML keeps a backslash as it is. In double quotes, YAML reads \b and \d as its own escapes, and the config does not load. --check-config shows the error:
✗ 213:22: error: scanner: while parsing a quoted scalar in line 213, column 17
found unknown escape character:
'$1 mi': ["/\b(\d+) miles\b/"]
^
Use double quotes only for a key that needs a real line break, like the signature above.
Capture groups
$1 is the first group in brackets, $2 the second, and so on. A group that starts with (?: captures nothing, so it has no number.
Write $1, not ${1}. We tested '${1} km' on “ran 12 kilometers” and got ran ${1} km.
If the key names a group the pattern does not have, the rule still runs and writes nothing in that place. --check-config reports it. We changed the units key to '$1 $2 km':
✗ replacements: "/\b(\d+(?:\.\d+)?) (?:kilometers|kilometres)\b/" writes $2, but the pattern captures 1 group(s) — $2 comes out as nothing
Limits
- A table only changes what the recogniser wrote. If it writes “North Wind” one day and “Northwind” the next, list both.
- A name the recogniser gets wrong in many ways belongs in your vocabulary, not in a table. See Teach ParrotFlow a word.
- A table cannot change the case of what it captured. Use a script for that. See Post-process dictation with a Python script.
- A table runs in every app. To limit a step to some apps, add
app:to it. See Apps in pipelines.md. --replaceskips the vocabulary pass and every prompt step. A live dictation runs them too.
Related
- Write your first rule, a plain table with three phrases.
- Turn “PR 478” into a link, a pattern that writes a link.
- Programmable dictation, for rules, scripts and prompts.
- Configuration, for every setting.
- Pipelines, for step order, conditions and
app:. - Lists in configuration.md, to reuse one word list in several patterns.