Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,39 @@ for mention in client.mentions.list(entity_id=ramp.id, after="2026-09-01", befor

A name where an id belongs raises `BadRequestError` with the code `id_required`. Its message names the parameter and the resolve call.

## Compare a speaker's comments over time

Compare what Jensen Huang said about TSMC in August and September 2026. Resolve his name, filter by who is speaking, and retrieve dated passages to review side by side.

```python
from urllib.parse import urljoin
from arcmira import Arcmira

client = Arcmira()
match = client.entities.resolve(
q="Jensen Huang",
type="person",
context="NVIDIA CEO discussing chip suppliers",
)
if match.best is None:
raise LookupError(match.ask or match.suggested or match.note)

for after, before in [("2026-08-01", "2026-09-01"), ("2026-09-01", "2026-10-01")]:
hits = client.transcripts.search(q="TSMC", by=match.best.id, after=after, before=before, limit=5)
print(hits.window, hits.search_index, hits.note)
for hit in hits.chunks:
print(hit.published_at, hit.text)
print(urljoin("https://arcmira.com", hit.watch_url))
```

If the resolver returns a suggested match or several options, confirm the intended person before continuing.

The `by` filter selects passages in which the resolved person speaks. Passages can include other speakers, so keep the speaker labels and read the surrounding exchange. Dates filter publication time, which may differ from when a recording was made.

In a search on October 15, 2026, these windows returned comments about [wafer demand in August](https://arcmira.com/watch?v=JAg8MM5onsE&t=511) and [US manufacturing commitments in September](https://arcmira.com/watch?v=HjurAWAr_nY&t=5274). They also returned a shorter upload of the same August exchange. Treat repeated clips as one source when comparing statements.

Use the reported `window`, `search_index`, and `note` to describe coverage. Speaker labels cover only part of the index, and results depend on your plan's date window. Review the passages before concluding that a stance changed. Replace the dates and topic to investigate another period or supplier.

## Dates

Every dated read takes `after` and `before`. The window is half-open, `[after, before)`. Each accepts an ISO date (`2026-09-01`) or a datetime with an offset (`2026-09-01T00:00:00Z`), read in UTC. Each dated read echoes the window it applied in `window`.
Expand Down
26 changes: 16 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,27 +12,31 @@ uv add arcmira

`pip install arcmira` works too. Set `ARCMIRA_API_KEY` to your API key. Save an example as `example.py` and run `python example.py` in your environment.

## Find quotes with source links
## Search clips and quotes in YouTube videos

Search YouTube and podcast transcripts by topic. Keep the source link beside each quote so readers can check the original.
Find spoken passages in YouTube videos and podcasts, then jump to the matching moment. Search a topic, company, or phrase.

```python
from urllib.parse import urljoin
from arcmira import Arcmira

client = Arcmira()
hits = client.transcripts.search(q="agent payments", limit=5)
hits = client.transcripts.search(q="TSMC", limit=5)
for hit in hits.chunks:
print(hit.text)
print(urljoin("https://arcmira.com", hit.watch_url))
print(hits.note)
```

Search covers indexed transcripts within your plan's date window. Check `window`, `search_index`, and `note` before treating an empty result as evidence that nobody said it.
For a research workflow, [compare what Jensen Huang said about TSMC across two months](https://github.com/arcmira/python/blob/master/GUIDE.md#compare-a-speakers-comments-over-time). Filter by speaker and date, then inspect the quoted passages in context.

## Pull a YouTube transcript
Search covers indexed transcripts within your plan's date window. Check `window`, `search_index`, and `note` before drawing conclusions from missing results.

Read available captions with timestamps. Replace the video id with the video you need.
## Transcribe a YouTube video

Start free with 1,000 credits a month, enough for up to 250 caption transcripts of videos up to 15 minutes each. Captions use 4 credits per started 15 minutes from the same balance as search and alerts. [Plans and usage](https://arcmira.com/pricing).

Pull an available YouTube caption track with timestamps. Replace the video id below with yours. For a new transcription of the audio with speaker labels, use Premium on a paid plan.

```python
from arcmira import Arcmira
Expand All @@ -44,11 +48,13 @@ if transcript.state == "ready":
print(line.start, line.text)
```

For a Premium transcript with speaker labels, first call `client.transcripts.quote(video_id)` for a free quote, then read with `quality="premium"`. A Premium read uses credits from your plan, then your on-demand budget. It may return `pending`; poll after `job.next_poll_seconds`. A `failed` result needs an explicit retry. [Premium states and polling](https://github.com/arcmira/python/blob/master/GUIDE.md#premium-transcripts).
Get a free cost estimate with `client.transcripts.quote(video_id)`, then read with `quality="premium"`. Premium uses credits from your plan, then your on-demand budget. If `pending`, poll after `job.next_poll_seconds`. [Premium states, polling, and retries](https://github.com/arcmira/python/blob/master/GUIDE.md#premium-transcripts).

## Set up YouTube monitoring for your company

## Monitor company mentions
Follow 2 names and get up to 40 alert deliveries a month on a free account, if you use all 1,000 monthly credits for alerts. Each delivery uses 25 credits. Get alerts by email or [Slack](https://arcmira.com/docs/monitors#delivery), or use a [webhook](https://arcmira.com/docs/monitors#verify-webhooks) on a paid plan.

Follow an exact name in newly analyzed media, even before it is indexed. Replace `you@example.com` with your alert address. External recipients must confirm before delivery.
Follow your company or a competitor in newly analyzed YouTube videos and podcasts. Replace `Ramp` and `you@example.com` below. External email recipients must confirm before delivery.

```python
from arcmira import Arcmira
Expand All @@ -68,7 +74,7 @@ for result in added.results:
print(result.tracker_id if result.attached else result.reason)
```

This creates a monitor and tracker in your account. Creation is free; delivered alerts use credits from your plan, then your on-demand budget. Check each `attached` result because a name may already belong to another monitor. For retries of writes, reuse the same `idempotency_key`.
This creates a monitor and tracker in your account. Check each `attached` result. Alerts cover newly analyzed episodes published within the last 14 days. Multiple recipients or channels can use multiple deliveries per mention. For retries of writes, reuse the same `idempotency_key`.

## Choose the next task

Expand Down
2 changes: 1 addition & 1 deletion llms.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ This repo is the `arcmira` Python SDK for the Arcmira API: synchronous and async

## Tasks

Use Arcmira to pull YouTube transcripts, find quotes with timestamps, research podcast sponsors, and monitor company mentions. Start with the README examples. Keep source links beside quotes, preserve the reported coverage window, and distinguish captions from Premium transcripts. For agent tasks, connect the MCP server; for an application, use this SDK.
Use Arcmira to pull YouTube transcripts, search clips and quotes in YouTube videos, compare a speaker's comments over time, research podcast sponsors, and set up YouTube monitoring for a company. Search returns passages with links to the matching moment. It does not export video clips. Start with the README examples. Keep source links beside quotes, preserve the reported coverage window, and distinguish captions from Premium transcripts. For agent tasks, connect the MCP server; for an application, use this SDK.

## Install

Expand Down
32 changes: 31 additions & 1 deletion tests/fixtures/readme-responses.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
"channel_id": "x",
"source": "x",
"published_at": "x",
"text": "agent payments on air",
"text": "TSMC on air",
"start_seconds": 1,
"watch_url": "https://arcmira.com/watch?v=dQw4w9WgXcQ&t=1",
"score": 1
Expand Down Expand Up @@ -116,5 +116,35 @@
"attached": true
}
]
},
"resolve_entity": {
"query": "x",
"context": "x",
"confidence": "exact",
"best": {
"id": "ent_14",
"name": "Jensen Huang",
"slug": "x",
"type": "person",
"youtube_channel_id": "x",
"description": "x",
"page": "x",
"match": "exact"
},
"suggested": null,
"ask": null,
"candidates": [
{
"id": "x",
"name": "x",
"slug": "x",
"type": "x",
"youtube_channel_id": "x",
"description": "x",
"page": "x",
"match": "exact"
}
],
"note": "x"
}
}
30 changes: 28 additions & 2 deletions tests/test_readme.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,38 @@ def respond(request):
for code in examples:
exec(compile(code, 'README.md', 'exec'), {})
printed = output.getvalue().splitlines()
self.assertIn('agent payments on air', printed)
self.assertIn('TSMC on air', printed)
self.assertIn('https://arcmira.com/watch?v=dQw4w9WgXcQ&t=1', printed)
self.assertIn('0.0 Welcome back to the show.', printed)
self.assertIn('trk_200', printed)
self.assertEqual([(r.method, r.url.path) for r in requests], list(routes))
self.assertEqual(dict(requests[0].url.params), dict(q='agent payments', limit='5'))
self.assertEqual(dict(requests[0].url.params), dict(q='TSMC', limit='5'))
self.assertEqual(json.loads(requests[2].content), dict(name='Company watch', notify_frequency='daily', notify_emails=['you@example.com']))
self.assertEqual(json.loads(requests[3].content), dict(names=[dict(name='Ramp', type='organization')]))
self.assertTrue(all(r.headers['Authorization'] == 'Bearer fixture-key' for r in requests))

def test_supplier_comparison_resolves_speaker_and_searches_both_windows(self):
requests = []
def respond(request):
requests.append(request)
name = 'resolve_entity' if request.url.path == '/v1/entities/resolve' else 'search'
return httpx.Response(200, json=RESPONSES[name])
section = (ROOT / 'GUIDE.md').read_text().split("## Compare a speaker's comments over time\n")[1].split('\n## ')[0]
code = re.search(r'```python\n(.*?)```', section, re.S).group(1)
output = io.StringIO()
with httpx.Client(transport=httpx.MockTransport(respond)) as http:
client = Arcmira(api_key='fixture-key', httpx_client=http, max_retries=0)
with patch('arcmira.Arcmira', return_value=client), contextlib.redirect_stdout(output):
exec(compile(code, 'GUIDE.md', 'exec'), {})
self.assertEqual([(r.method, r.url.path) for r in requests], [
('GET', '/v1/entities/resolve'), ('GET', '/v1/search'), ('GET', '/v1/search'),
])
self.assertEqual(dict(requests[0].url.params), dict(
q='Jensen Huang', type='person', context='NVIDIA CEO discussing chip suppliers',
))
self.assertEqual([dict(r.url.params) for r in requests[1:]], [
dict(q='TSMC', by='ent_14', after='2026-08-01', before='2026-09-01', limit='5'),
dict(q='TSMC', by='ent_14', after='2026-09-01', before='2026-10-01', limit='5'),
])
self.assertEqual(output.getvalue().count('TSMC on air'), 2)
self.assertEqual(output.getvalue().count('https://arcmira.com/watch?v=dQw4w9WgXcQ&t=1'), 2)
Loading