196 lines
10 KiB
Markdown
196 lines
10 KiB
Markdown
---
|
|
name: fireflies-relanguage
|
|
description: Fix a wrong-language Fireflies transcript on a meeting you don't own (can't hit Reprocess yourself) by re-uploading its audio under the correct language via the Fireflies API, recovering real speaker names into the result with transcript-speaker-fill, then deleting the duplicate meeting. Use when the user has a link to a Fireflies recording they aren't the host/owner of, the transcript is in the wrong language, and they want a corrected transcript without waiting for the owner to act or leaving a duplicate meeting behind. Trigger phrases: "I'm not the owner of this meeting", "can't reprocess this transcript", "fix this Fireflies transcript without the owner", "re-transcribe a shared meeting".
|
|
---
|
|
|
|
# Fireflies relanguage skill
|
|
|
|
## Purpose
|
|
|
|
Fireflies' own "Update Language + Reprocess" fix only works for the meeting's
|
|
host/owner (see `guide.fireflies.ai` docs). If you were just sent a link to
|
|
someone else's recording and it came out in the wrong language, you have no
|
|
UI path to fix it and can't wait for the owner. This skill routes around
|
|
that: pull the meeting's audio via the API, re-upload it as a **new** meeting
|
|
under your own account with the correct language forced, recover the
|
|
original's real speaker names into the new, correctly-transcribed text using
|
|
the [[transcript-speaker-fill]](../transcript-speaker-fill/SKILL.md) skill,
|
|
then delete the duplicate meeting the re-upload created.
|
|
|
|
## Before you start: real constraints, not hypothetical ones
|
|
|
|
**This may simply not be possible on your account.** `audio_url`/`video_url`
|
|
on a Fireflies transcript require a Pro+ plan, and it is undocumented whether
|
|
they populate at all for a meeting merely *shared* with you rather than
|
|
owned by you. [Michał's own wiki notes](/wiki/entities/fireflies-transcript-handling.md)
|
|
record hitting exactly this wall before (no Pro seat → transcript download
|
|
tooling broke). Step 1 below (`fetch`) is also the diagnostic: if it prints
|
|
the "audio_url is null" warning, stop here — this workflow cannot proceed
|
|
without one of the workarounds it suggests (a Pro+ seat's API key, the actual
|
|
owner reprocessing it, or you manually downloading the audio via the web UI
|
|
and hosting it at some public HTTPS URL yourself).
|
|
|
|
**Every re-upload consumes real transcription quota/minutes** on the account
|
|
whose API key you use, same as any other Fireflies upload — this isn't free
|
|
just because it's automated. **Deleting a transcript is irreversible.** Don't
|
|
run this on a meeting you actually might need to keep two copies of, and
|
|
don't skip the confirmation gates below.
|
|
|
|
Also worth knowing up front: the Fireflies API has thin rate limits (Free:
|
|
50 requests/day, Pro: 500/day, Business/Enterprise: 60/min) and
|
|
`deleteTranscript` specifically is capped at 10/min. This workflow only
|
|
needs a handful of calls plus some polling, but don't loop the `wait` step
|
|
aggressively.
|
|
|
|
## Requirements
|
|
|
|
- `FIREFLIES_API_KEY` set in the environment. Get one from the Fireflies web
|
|
app under **Settings > API**. The script exits with this exact instruction
|
|
if it's missing — don't hardcode the key anywhere.
|
|
- The `transcript-speaker-fill` skill installed alongside this one (it is,
|
|
in this repo) — this skill hands off the actual name-recovery merge to it
|
|
rather than duplicating that logic.
|
|
|
|
## Workflow
|
|
|
|
Resolve `<skill-dir>` to this skill's own directory throughout.
|
|
|
|
### 1. Fetch the original (broken-language) transcript
|
|
|
|
```bash
|
|
python3 "<skill-dir>/scripts/fireflies_client.py" fetch --ref "<link-or-id-the-user-gave-you>" --out original.md
|
|
```
|
|
|
|
Accepts a bare transcript id or a full share link like
|
|
`https://app.fireflies.ai/view/Some-Title::abcDEF123`. Writes `original.md`
|
|
(real speaker names, garbled text — the shape `transcript-speaker-fill`
|
|
expects for its "broken" input) and `original.md.meta.json` (id, title,
|
|
`audio_url`, etc., needed by later steps).
|
|
|
|
**Check the printed output for the audio_url warning before continuing.** If
|
|
it's null, stop and follow the guidance it prints instead of proceeding to
|
|
step 2 — do not attempt step 2 anyway "just to see."
|
|
|
|
### 2. Confirm the target language with the user
|
|
|
|
Don't guess the correct language from context alone unless it's unambiguous
|
|
(e.g. the user already told you). Ask if unclear. Use the language code
|
|
Fireflies expects — check
|
|
[Learn about Fireflies supported languages](https://guide.fireflies.ai/articles/2973706448-learn-about-fireflies-supported-languages)
|
|
for the exact code if you're not sure it matches (e.g. `en`, `pl`, `es`).
|
|
|
|
### 3. Re-upload the audio under the correct language
|
|
|
|
```bash
|
|
python3 "<skill-dir>/scripts/fireflies_client.py" upload --meta original.md.meta.json --language <code>
|
|
```
|
|
|
|
This calls `uploadAudio` with `custom_language` set, tagging the new
|
|
meeting's title with `[relang:<original-id>]` so it can be found
|
|
unambiguously afterward (override with `--title` if you want a cleaner
|
|
name, but then pass that exact same string to step 4). Note the exact title
|
|
printed — you need it verbatim for the next step.
|
|
|
|
### 4. Wait for the re-upload to finish processing
|
|
|
|
```bash
|
|
python3 "<skill-dir>/scripts/fireflies_client.py" wait --title "<exact title from step 3>"
|
|
```
|
|
|
|
Polls every 30s (default) up to 15 minutes (default) for a transcript with
|
|
that exact title to appear with content. Long recordings can take longer —
|
|
if it times out, just re-run `wait` again rather than assuming failure.
|
|
Prints the new transcript's `id` once ready.
|
|
|
|
### 5. Fetch the new (correct-language) transcript
|
|
|
|
```bash
|
|
python3 "<skill-dir>/scripts/fireflies_client.py" fetch --ref "<id from step 4>" --out new.md
|
|
```
|
|
|
|
This one should come back with correct text but generic `Speaker 1`,
|
|
`Speaker 2`, ... labels (no calendar/roster context on a bare re-upload) —
|
|
exactly the gap `transcript-speaker-fill` closes.
|
|
|
|
### 6. Recover real speaker names
|
|
|
|
Hand off to the `transcript-speaker-fill` skill exactly per its own
|
|
SKILL.md, using `original.md` and `new.md` as the two inputs — dry run
|
|
first, present the resolution report, get the user's confirmation/manual
|
|
overrides, then `--apply`. Do not skip its confirmation gate just because
|
|
you're mid-pipeline; it's exactly as load-bearing here as when invoked
|
|
standalone.
|
|
|
|
Also pass `--recording-url "https://app.fireflies.ai/view/<id from step 4>"`
|
|
on every `fill_speakers.py` call in this handoff (both the dry-run and the
|
|
`--apply` run) — the bare-id form of the URL works without needing to
|
|
slug-encode the title, and gives the user a direct link to a recording they
|
|
definitely have full access to (they own the re-uploaded meeting) right
|
|
next to every label's example lines, for the spot-check
|
|
`transcript-speaker-fill` asks them to do before confirming. Use the new
|
|
transcript's id, not the original's — do this *before* step 8's cleanup,
|
|
while that meeting (and its recording) still exists.
|
|
|
|
### 7. Ask where to save the corrected transcript
|
|
|
|
Before touching the duplicate meeting, ask the user where the final
|
|
`--apply`'d output (from step 6) should end up — don't default to leaving
|
|
it in a scratch/temp location without asking. Common answers: a specific
|
|
path they name, this project's own `tmp/` (if this skill is being run from
|
|
inside a Cascade Knowledge Base repo like this one — gitignored, agent-
|
|
managed), or `raw/inbox/` if they want it ingested into a wiki afterward.
|
|
Move (don't copy) the file there once they've told you.
|
|
|
|
### 8. Delete the duplicate meeting — only after explicit confirmation
|
|
|
|
Once the user has confirmed the merged transcript (from step 6) looks right
|
|
and it's been saved wherever they wanted (step 7), delete the meeting the
|
|
re-upload created (**not** the original — you don't own that one anyway,
|
|
and couldn't delete it if you tried):
|
|
|
|
```bash
|
|
python3 "<skill-dir>/scripts/fireflies_client.py" delete --id <id from step 4> --yes
|
|
```
|
|
|
|
The script refuses to run without `--yes`. Never pass `--yes` without the
|
|
user having explicitly confirmed they're ready — this is irreversible and
|
|
removes a real meeting from their Fireflies account. Show them the printed
|
|
`{id, title, date, duration}` of what was deleted as final confirmation.
|
|
|
|
## Failure modes and what they mean
|
|
|
|
- **`fetch` on the original prints the audio_url warning** — see "Before you
|
|
start" above. This is the expected failure mode when the API key's
|
|
account isn't Pro+, or when a merely-shared meeting doesn't expose audio
|
|
via the API. Not a bug to work around silently.
|
|
- **`upload` mutation succeeds (`success: true`) but `wait` never finds it**
|
|
— the title match is exact-string, so a `--title` override that doesn't
|
|
exactly match what you pass to `wait` will never resolve; double check
|
|
you used the identical string in both commands.
|
|
- **`wait` times out** — normal for long recordings. Re-run it; don't
|
|
assume the upload failed.
|
|
- **Rate limit errors (`too_many_requests`)** — the error message includes
|
|
`retryAfter`; wait that long before retrying, especially on a Free-tier
|
|
key (50 requests/day total).
|
|
- **`delete` fails with `require_elevated_privilege`** — you're trying to
|
|
delete a transcript you don't own (e.g. you accidentally passed the
|
|
*original* id instead of the new one from step 4). Only the re-uploaded
|
|
meeting is yours to delete.
|
|
|
|
## Edge cases
|
|
|
|
- **Multiple speakers with a name-recovery gap** (new transcript has more
|
|
distinct `Speaker N` labels than the original has real names) — this is
|
|
`transcript-speaker-fill`'s "roster gap" warning, not something this
|
|
skill's own steps can fix; it means someone's voice wasn't distinctly
|
|
captured with a real name in the original either.
|
|
- **Original meeting has `video_url` but not `audio_url`** — `upload` only
|
|
accepts `--audio-url`; there's no video re-upload path here. If you truly
|
|
only have video access, extract audio from it yourself first and host
|
|
that as a public URL, then pass it via `--audio-url`.
|
|
- **The user wants the corrected transcript ingested into this repo's
|
|
wiki**, not just saved as a file — step 7 already asks where to save it;
|
|
if the answer is "ingest it," save it to `raw/inbox/` there, then run the
|
|
normal "Ingest" workflow from the root `CLAUDE.md` on it after step 8's
|
|
cleanup (the duplicate meeting is Fireflies-side bookkeeping, unrelated
|
|
to whether the wiki ingest has happened yet).
|