import Foundation import RDAIReaderView /// Temporary speech content for an AI answer or summary. It deliberately uses /// an in-memory identifier and disables progress persistence by default. @MainActor public final class RDAISpeechContentProvider: RDSpeechContentProvider { private let descriptor: RDSpeechBookDescriptor private let units: [RDSpeechTextUnit] public init(title: String, text: String, language: String? = nil) { let identifier = "rdai-speech-\(UUID().uuidString)" descriptor = RDSpeechBookDescriptor(identifier: identifier, title: title) let location = RDSpeechLocation(bookIdentifier: identifier, resourceIdentifier: "ai-result") units = RDSpeechTextPreprocessor.makeUnits(text: text, location: location, language: language) } public func speechBookDescriptor() -> RDSpeechBookDescriptor { descriptor } public func speechContentBatch(startingAt location: RDSpeechLocation?, limit: Int) async throws -> RDSpeechContentBatch { let start = location.flatMap { requested in units.firstIndex { $0.location.textOffset >= requested.textOffset } } ?? 0 let batch = Array(units.dropFirst(start).prefix(max(1, limit))) let nextIndex = start + batch.count return RDSpeechContentBatch(units: batch, nextLocation: nextIndex < units.count ? units[nextIndex].location : nil) } } @MainActor public extension RDSpeechReaderController { convenience init(aiTitle: String, text: String, language: String? = nil, configuration: RDSpeechReaderConfiguration = .default) { let provider = RDAISpeechContentProvider(title: aiTitle, text: text, language: language) self.init(contentProvider: provider, configuration: configuration, progressStore: nil) } }