更新阅读器功能与示例
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
import Foundation
|
||||
import FoundationModels
|
||||
|
||||
@available(iOS 26.0, *)
|
||||
@Generable(description: "A factual statement grounded in one or more supplied passage identifiers.")
|
||||
private struct RDAIModelStatement {
|
||||
var text: String
|
||||
var passageIDs: [String]
|
||||
}
|
||||
|
||||
@available(iOS 26.0, *)
|
||||
@Generable(description: "A citation-grounded book summary.")
|
||||
private struct RDAIModelSummary {
|
||||
var overview: String
|
||||
var statements: [RDAIModelStatement]
|
||||
}
|
||||
|
||||
@available(iOS 26.0, *)
|
||||
@Generable(description: "A citation-grounded answer to a question about supplied passages.")
|
||||
private struct RDAIModelAnswer {
|
||||
var answer: String
|
||||
var statements: [RDAIModelStatement]
|
||||
}
|
||||
|
||||
/// Optional on-device provider. The Core service remains fully functional on
|
||||
/// older systems by falling back to evidence-only retrieval.
|
||||
@available(iOS 26.0, *)
|
||||
public actor RDAIAppleFoundationModelsProvider: RDAIGenerativeProvider {
|
||||
public let identifier = "apple.foundation-models"
|
||||
|
||||
public init() {}
|
||||
|
||||
public func availability(for capability: RDAICapability, locale: Locale?) async -> RDAICapabilityAvailability {
|
||||
switch SystemLanguageModel.default.availability {
|
||||
case .available: return .available
|
||||
case .unavailable(.deviceNotEligible): return .unavailable(reason: .deviceNotEligible)
|
||||
case .unavailable(.appleIntelligenceNotEnabled): return .unavailable(reason: .appleIntelligenceNotEnabled)
|
||||
case .unavailable(.modelNotReady): return .unavailable(reason: .modelNotReady)
|
||||
@unknown default: return .unavailable(reason: .unknown("system-model-unavailable"))
|
||||
}
|
||||
}
|
||||
|
||||
public func generate(_ request: RDAIGenerationRequest) async throws -> RDAIGeneratedArtifact {
|
||||
guard case .available = await availability(for: capability(for: request.task), locale: request.locale) else {
|
||||
throw RDAIError.modelUnavailable(.modelNotReady)
|
||||
}
|
||||
let context = request.passages.enumerated().map { "[\($0.element.id)] \($0.element.text)" }.joined(separator: "\n\n")
|
||||
let task: String
|
||||
switch request.task {
|
||||
case .summary: task = "Summarize the passages in the user's language. Do not add facts."
|
||||
case .answer: task = "Answer the question using only the passages. If evidence is insufficient, say so. Question: \(request.userText ?? "")"
|
||||
case .characters, .relationships: throw RDAIError.insufficientEvidence
|
||||
}
|
||||
let session = LanguageModelSession(instructions: "You are a book reading assistant. Use only supplied passages and never reveal unread content.")
|
||||
switch request.task {
|
||||
case .summary:
|
||||
let response = try await session.respond(to: "\(task) Each statement must include its supplied passage IDs.\n\nPassages:\n\(context)", generating: RDAIModelSummary.self)
|
||||
return .summary(overview: response.content.overview, statements: response.content.statements.map(statement))
|
||||
case .answer:
|
||||
let response = try await session.respond(to: "\(task) Each statement must include its supplied passage IDs.\n\nPassages:\n\(context)", generating: RDAIModelAnswer.self)
|
||||
return .answer(text: response.content.answer, statements: response.content.statements.map(statement))
|
||||
case .characters, .relationships: throw RDAIError.insufficientEvidence
|
||||
}
|
||||
}
|
||||
|
||||
private func capability(for task: RDAIGenerationTask) -> RDAICapability {
|
||||
switch task {
|
||||
case .summary: return .summarization
|
||||
case .answer: return .questionAnswering
|
||||
case .characters, .relationships: return .characterRelationships
|
||||
}
|
||||
}
|
||||
|
||||
private func statement(_ value: RDAIModelStatement) -> RDAISourcedStatement {
|
||||
RDAISourcedStatement(text: value.text, citationIdentifiers: value.passageIDs)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user