[RSM] Smart bookmarks API layer#5283
Open
sztomek wants to merge 2 commits into
Open
Conversation
Contributor
There was a problem hiding this comment.
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_BOOKMARKSfeature 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(...)andBookmarkManager.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. |
Collaborator
|
Version |
3f769c9 to
9e9da4a
Compare
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, | ||
| ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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_BOOKMARKSfeature flag (Plus tier) gates the entire flow. This branch introduces theTranscriptWindowExtractorfor local VTT parsing, the enrichment API models and Retrofit endpoint, and theBookmarkManager.enrichBookmark()method that orchestrates the full flow. Unit tests cover the VTT window extraction logic.Testing Instructions
Just review the code, please
Checklist
./gradlew spotlessApplyto automatically apply formatting/linting)modules/services/localization/src/main/res/values/strings.xml