Add iOS Langfuse analytics via backend events endpoint
Some checks failed
CI / build-and-deploy (push) Failing after 8s
Some checks failed
CI / build-and-deploy (push) Failing after 8s
AnalyticsService.track() is fire-and-forget — posts to POST /v1/marks/events which records a Langfuse trace. No external SDK, no Sentry on iOS side. Events tracked: - podcast.started (url, cached) - podcast.completed (url, durationSec) — fires at 97% playback - podcast.failed (url, error) - search.semantic (query, resultCount) - enrich.completed (count) - collections.generated (collectionCount) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -59,10 +59,12 @@ final class PodcastPlayerViewModel {
|
||||
|
||||
let cached = ClaudeService.cachedPodcastURL(for: articleUrl)
|
||||
if FileManager.default.fileExists(atPath: cached.path) {
|
||||
Analytics.track("podcast.started", ["url": articleUrl, "cached": true])
|
||||
setupPlayer(url: cached, title: "Podcast")
|
||||
return
|
||||
}
|
||||
|
||||
Analytics.track("podcast.started", ["url": articleUrl, "cached": false])
|
||||
phase = .generating(progress: 0, label: "Starting…")
|
||||
|
||||
pollingTask = Task {
|
||||
@@ -81,13 +83,16 @@ final class PodcastPlayerViewModel {
|
||||
return
|
||||
}
|
||||
if job.isFailed {
|
||||
phase = .failed(job.error ?? "Generation failed")
|
||||
let errMsg = job.error ?? "Generation failed"
|
||||
Analytics.track("podcast.failed", ["url": articleUrl, "error": errMsg])
|
||||
phase = .failed(errMsg)
|
||||
return
|
||||
}
|
||||
try await Task.sleep(for: .seconds(3))
|
||||
}
|
||||
} catch is CancellationError {
|
||||
} catch {
|
||||
Analytics.track("podcast.failed", ["url": articleUrl, "error": error.localizedDescription])
|
||||
phase = .failed(error.localizedDescription)
|
||||
}
|
||||
}
|
||||
@@ -155,8 +160,14 @@ final class PodcastPlayerViewModel {
|
||||
|
||||
let interval = CMTime(seconds: 0.5, preferredTimescale: 600)
|
||||
timeObserver = p.addPeriodicTimeObserver(forInterval: interval, queue: .main) { [weak self] t in
|
||||
self?.currentTime = t.seconds
|
||||
self?.updateNowPlaying()
|
||||
guard let self else { return }
|
||||
let prev = self.currentTime
|
||||
self.currentTime = t.seconds
|
||||
self.updateNowPlaying()
|
||||
// Track completion when crossing 97%
|
||||
if self.duration > 1 && prev / self.duration < 0.97 && t.seconds / self.duration >= 0.97 {
|
||||
Analytics.track("podcast.completed", ["url": self.currentArticleUrl, "durationSec": Int(self.duration)])
|
||||
}
|
||||
}
|
||||
|
||||
setupRemoteCommands()
|
||||
|
||||
Reference in New Issue
Block a user