Skip to content

[RSM] Smart bookmarks API layer#5283

Open
sztomek wants to merge 2 commits into
feat/smart-bookmarks-modelfrom
feat/smart-bookmarks-api
Open

[RSM] Smart bookmarks API layer#5283
sztomek wants to merge 2 commits into
feat/smart-bookmarks-modelfrom
feat/smart-bookmarks-api

Conversation

@sztomek
Copy link
Copy Markdown
Contributor

@sztomek sztomek commented May 8, 2026

Description

This adds the core wiring for Smart Bookmarks — AI-generated titles and summaries for bookmarks based on what was being said at the bookmarked moment.
When a bookmark is created, the app extracts a ~60-second transcript window around the timestamp directly from the episode's cached VTT transcript on-device, then sends that text snippet to the server for AI processing. The server returns a short title and one-line summary, which are saved to the bookmark.
A new SMART_BOOKMARKS feature flag (Plus tier) gates the entire flow. This branch introduces the TranscriptWindowExtractor for local VTT parsing, the enrichment API models and Retrofit endpoint, and the BookmarkManager.enrichBookmark() method that orchestrates the full flow. Unit tests cover the VTT window extraction logic.

Testing Instructions

Just review the code, please

Checklist

  • If this is a user-facing change, I have added an entry in CHANGELOG.md
  • Ensure the linter passes (./gradlew spotlessApply to automatically apply formatting/linting)
  • I have considered whether it makes sense to add tests for my changes
  • All strings that need to be localized are in modules/services/localization/src/main/res/values/strings.xml
  • Any jetpack compose components I added or changed are covered by compose previews
  • I have updated (or requested that someone edit) the spreadsheet to reflect any new or changed analytics.

@sztomek sztomek added this to the 8.12 milestone May 8, 2026
Copilot AI review requested due to automatic review settings May 8, 2026 11:58
@sztomek sztomek requested a review from a team as a code owner May 8, 2026 11:58
@sztomek sztomek requested review from geekygecko and removed request for a team May 8, 2026 11:58
@sztomek sztomek added [Type] Feature Adding a new feature. [Area] Bookmarks labels May 8, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds the client-side plumbing for “Smart Bookmarks” enrichment by extracting a transcript snippet around a bookmark timestamp and calling a new sync API to get an AI-generated title/summary.

Changes:

  • Added SMART_BOOKMARKS feature flag (Plus tier) and new sync endpoint/model types for bookmark enrichment.
  • Introduced TranscriptWindowExtractor (+ unit tests) to extract a window of text from cached WebVTT transcript content.
  • Added SyncManager.enrichBookmark(...) and BookmarkManager.enrichBookmark(...) wiring to call the new endpoint and persist AI title/summary onto the bookmark.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
modules/services/utils/src/main/java/au/com/shiftyjelly/pocketcasts/utils/featureflag/Feature.kt Adds SMART_BOOKMARKS feature flag definition.
modules/services/servers/src/main/java/au/com/shiftyjelly/pocketcasts/servers/sync/SyncServiceManager.kt Adds enrichBookmark(...) wrapper calling the sync service.
modules/services/servers/src/main/java/au/com/shiftyjelly/pocketcasts/servers/sync/SyncService.kt Adds Retrofit POST /user/bookmark/enrich endpoint definition.
modules/services/servers/src/main/java/au/com/shiftyjelly/pocketcasts/servers/sync/bookmark/BookmarkEnrichModels.kt Introduces Moshi request/response models for enrichment.
modules/services/repositories/src/test/java/au/com/shiftyjelly/pocketcasts/repositories/transcript/TranscriptWindowExtractorTest.kt Adds unit tests for VTT window extraction behavior.
modules/services/repositories/src/main/java/au/com/shiftyjelly/pocketcasts/repositories/transcript/TranscriptWindowExtractor.kt Implements transcript window extraction and simple VTT parsing.
modules/services/repositories/src/main/java/au/com/shiftyjelly/pocketcasts/repositories/sync/SyncManagerImpl.kt Implements SyncManager.enrichBookmark(...).
modules/services/repositories/src/main/java/au/com/shiftyjelly/pocketcasts/repositories/sync/SyncManager.kt Adds enrichBookmark(...) to the sync abstraction.
modules/services/repositories/src/main/java/au/com/shiftyjelly/pocketcasts/repositories/bookmark/BookmarkManagerImpl.kt Adds enrichment orchestration and persists AI fields onto bookmarks.
modules/services/repositories/src/main/java/au/com/shiftyjelly/pocketcasts/repositories/bookmark/BookmarkManager.kt Exposes enrichBookmark(bookmark) on the bookmark manager interface.

@wpmobilebot wpmobilebot modified the milestones: 8.12, 8.13 May 11, 2026
@wpmobilebot
Copy link
Copy Markdown
Collaborator

Version 8.12 has now entered code-freeze, so the milestone of this PR has been updated to 8.13.

Copilot AI review requested due to automatic review settings May 11, 2026 19:43
@sztomek sztomek force-pushed the feat/smart-bookmarks-api branch from 3f769c9 to 9e9da4a Compare May 11, 2026 19:43
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 4 comments.

Comment on lines +19 to +35
suspend fun extractWindow(episodeUuid: String, timeSecs: Int, windowSecs: Int = 30): String? {
return try {
val transcripts = withTimeoutOrNull(1.minutes) {
transcriptDao.observeTranscripts(episodeUuid)
.filter { it.isNotEmpty() }
.firstOrNull()
}
val generated = transcripts?.firstOrNull { it.isGenerated } ?: return null

val body = runCatching { transcriptService.getTranscriptOrThrow(generated.url, CacheControl.FORCE_CACHE) }
.getOrNull() ?: return null

val vttContent = body.use { it.string() }
parseVttWindow(vttContent, timeSecs, windowSecs)
} catch (e: Exception) {
Timber.e(e, "Failed to extract transcript window for episode $episodeUuid")
null
Comment on lines +64 to +67
val cueLines = mutableListOf<String>()
while (i < lines.size && lines[i].isNotBlank()) {
cueLines.add(lines[i].replace(Regex("<[^>]+>"), "").trim())
i++
Comment on lines +235 to +258
override suspend fun enrichBookmark(bookmark: Bookmark) {
try {
val snippet = transcriptWindowExtractor.extractWindow(
episodeUuid = bookmark.episodeUuid,
timeSecs = bookmark.timeSecs,
) ?: return

val response = syncManager.enrichBookmark(transcriptSnippet = snippet)
val title = response.title
val summary = response.summary
if (title != null && summary != null) {
val now = System.currentTimeMillis()
bookmarkDao.updateAiData(
bookmarkUuid = bookmark.uuid,
aiTitle = title,
aiSummary = summary,
aiTitleModified = now,
aiSummaryModified = now,
syncStatus = SyncStatus.NOT_SYNCED,
)
}
} catch (e: Exception) {
Timber.e(e, "Smart bookmark enrichment failed for ${bookmark.uuid}")
}
aiTitleModified = now,
aiSummaryModified = now,
syncStatus = SyncStatus.NOT_SYNCED,
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants