Skip to main content

OVOS pipeline plugin that orchestrates 'read me something' across content provider skills (fairy tales, articles, news, documents and more), similar in spirit to OCP for media skills

Project description

Common Reading

An OVOS pipeline plugin that reads things aloud - fairy tales, articles, news, documents, reports, and whatever else a provider skill wants to offer - by orchestrating "read me something" across those provider skills, the same way OCP (ovos-common-play) orchestrates "play X" across media skills.

"If you want your children to be intelligent, read them fairy tales. If you want them to be more intelligent, read them more fairy tales." — Albert Einstein

Tests PyPI version

What this is: a pipeline plugin for narrating text-based content via TTS - providers deliver plain text, and this plugin reads it aloud, sentence by sentence, with bookmarking and "continue" support.

What this is not: an audiobook or audio-file player. If you're looking for pre-recorded audiobooks, radio dramas, or narrated readings as audio files, that's already well covered by existing OCP media skills (e.g. ovos-skill-librivox, or JarbasSkills' skill-golden-audiobooks / skill-hppodcraft / skill-epic-horror-theatre). This plugin solves a different problem: letting several text content providers coexist and be searched together, without any of them registering competing voice intents.

Install

pip install ovos-common-reading-pipeline-plugin

Add it to your pipeline in mycroft.conf:

{
  "intents": {
    "pipeline": [
      "stop_high",
      "ovos-common-reading-pipeline-plugin",
      "converse",
      "ocp_high",
      "padatious_high",
      "adapt_high",
      "..."
    ]
  }
}

You'll also want at least one provider skill installed, otherwise there's nothing to read:

Building your own provider

See ovos-skill-common-reading-example - a template walking through two working patterns (RSS feeds and static-page scraping), the bus protocol, caching, and the judgment calls every provider has to make for itself (translate or not, what a human calls the source, what's worth reading aloud).

The ovos.common_reading.* bus protocol

Provider skills implement this to be usable by this plugin. It's a plain messagebus convention (like ovos.common_play.*) - no shared package dependency needed.

1. Search

Broadcast on a matched utterance:

ovos.common_reading.search
{
  "phrase": "<what the user asked for, or null for 'surprise me'>",
  "collection_hint": "<raw text like 'grimm' or 'h c andersen', or null>",
  "content_type": "<raw hint like 'story', 'book', 'article', 'poem', or null>",
  "requester": "<this plugin's id>"
}

collection_hint is set when the user names a specific source/collection ("read me a story from Grimm", "find Cinderella by Andersen"). It's raw, unvalidated text - each provider fuzzy-matches it against its own known friendly names and should only respond if it's a match, or if collection_hint is null (in which case every provider competes as usual).

content_type is a similarly raw, optional hint. A provider that only offers one kind of content can use it to stay silent when it clearly doesn't apply, but should treat a null/missing content_type as "anyone can compete".

phrase can also be null on its own - "read me a story from Grimm" with no specific title named is a valid request for the hinted provider to offer something of its own choosing.

Every provider that thinks it can help replies (within ~2s):

ovos.common_reading.search.response
{
  "skill_id": "<provider skill id>",
  "content_id": "<opaque id the provider will recognize later>",
  "title": "<human-readable title>",
  "author": "<author, optional>",
  "collection": "<book/collection name, optional>",
  "source": "<where the text comes from, e.g. 'grimmstories.com'>",
  "confidence": 0.0-1.0,
  "machine_translated": true/false (optional, defaults falsy)
}

The highest-confidence response wins (and, if it's below 0.8, this plugin confirms with the user before continuing). If a provider sets "machine_translated": true, that's disclosed as part of the announcement right before reading starts.

2. Fetch

Once something is chosen (or resumed via "continue"), a targeted request goes to just that provider:

ovos.common_reading.fetch_content.<provider_skill_id>
{"content_id": "<from the search response>", "requester": "<this plugin's id>"}

The provider replies once with the full text, split into paragraphs:

ovos.common_reading.fetch_content.response
{"paragraphs": ["First paragraph...", "Second paragraph...", ...]}

Reading pacing, sentence splitting, and bookmark tracking all happen here - providers just deliver text.

3. Ping (only used when a search comes up empty)

If a search returns zero candidates, this plugin needs to say something honest - but "I couldn't find that" and "you don't have any reading skills installed" are very different situations, and guessing which one applies (or worse, silently falling back to some other language, see #2) is worse than just asking. So it asks:

ovos.common_reading.ping
{"requester": "<this plugin's id>"}

Every provider that's loaded and listening should reply, cheaply, with no index lookup:

ovos.common_reading.pong
{"skill_id": "<provider skill id>", "collection": "<same collection name it uses in search responses>"}

This is only broadcast on the rare 0-candidates path, never on every search - a normal search/fetch round trip never triggers a ping. Based on the pongs:

  • Zero pongs -> "you don't have any reading skills installed" (the most useful thing to tell the user, since it's actionable)
  • At least one pong, but nothing matched a collection_hint -> "I don't know a source called X"
  • At least one pong, but no phrase matched at all -> a generic "I couldn't find anything matching that"

This needs no language-awareness on the plugin's part: a provider that refused to load for the device's language (the SUPPORTED_LANGUAGES gate described below) never registers a ping handler either, so it correctly stays silent here too - the same mechanism that keeps it out of search results keeps it out of ping results, for free.

If you're building a provider, implementing this is required, not optional - a provider that never pongs looks, from the pipeline's perspective, exactly like a provider that isn't installed at all, which produces a misleading "nothing installed" message even when your skill is present and just didn't have a match. See ovos-skill-common-reading-example for the reference implementation.

Friendly names

Each provider should keep a small list of names it's willing to answer to as collection_hint - not just its skill_id, but the natural things a person might call it: ovos-skill-grimm-tales might match "grimm", "the brothers grimm"; ovos-skill-andersen-tales matches "andersen", "hans christian andersen", "h c andersen". Matching should be fuzzy (e.g. via ovos_utils.parse.match_one against the provider's own alias list) rather than exact string equality, since STT transcription is never perfectly consistent.

If collection_hint doesn't clearly match a provider's own aliases, that provider should simply not respond to the search at all - only providers that actually answered are considered.

Tune your match threshold carefully. A threshold around 0.6 can produce false positives on short strings (e.g. "andrew lang" scoring 0.63 against "andersen" on plain character overlap, nothing to do with meaning) - 0.85 is a safer default. Verify empirically for your own alias list.

Language handling

Every provider in this family handles the device's language one of two ways:

  • Fixed set of supported languages, no translation (ovos-skill-andersen-tales, ovos-skill-grimm-tales, ovos-skill-andrew-lang-tales): checks a SUPPORTED_LANGUAGES set at the top of initialize(), before building any index or registering any bus events. On an unsupported device language, the provider logs why and stays completely inert - never loads an index, never listens for ovos.common_reading.search - rather than loading fully and silently declining every search.
  • Machine translation (ovos-skill-ovosblog, ovos-skill-arxiv-papers): always loads (it can't know in advance whether a translation plugin will be configured), matches search phrases against translated titles, and declines per-search rather than per-load if no translator is available.

Neither pattern ever silently serves the wrong language - the difference is only when the provider decides it can't help (once, at load time, if it has no way to translate; or per-search, if it might). See ovos-skill-common-reading-example's module docstring (decision points #1 and #4) for the full reasoning behind picking one over the other for your own provider.

Category

Entertainment

Tags

#reading #stories #articles #news #orchestrator #pipeline

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ovos_common_reading_pipeline_plugin-0.1.1.tar.gz (41.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

File details

Details for the file ovos_common_reading_pipeline_plugin-0.1.1.tar.gz.

File metadata

File hashes

Hashes for ovos_common_reading_pipeline_plugin-0.1.1.tar.gz
Algorithm Hash digest
SHA256 9377f2f0f58df5029b51442974c6266314330e656dcd2d3303f85647ae545be9
MD5 70752e86b4658e436dea32b0f3969f7b
BLAKE2b-256 763714a49c4c01d2a61c756fedfd597cb744806ce405583bacdf9a27381fbbe7

See more details on using hashes here.

Provenance

The following attestation bundles were made for ovos_common_reading_pipeline_plugin-0.1.1.tar.gz:

Publisher: publish.yml on andlo/ovos-common-reading-pipeline-plugin

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ovos_common_reading_pipeline_plugin-0.1.1-py3-none-any.whl.

File metadata

File hashes

Hashes for ovos_common_reading_pipeline_plugin-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 582b5bd9fb19e044dc0cbb55a43b7690ea02880daf2f3ea32d352b40270e658a
MD5 6771d27858df9f072b05518d85b1a3fe
BLAKE2b-256 852d6013e8bf47dabd702062914bb40b07e18498a94324e7f140229b5bc55792

See more details on using hashes here.

Provenance

The following attestation bundles were made for ovos_common_reading_pipeline_plugin-0.1.1-py3-none-any.whl:

Publisher: publish.yml on andlo/ovos-common-reading-pipeline-plugin

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page