| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206 |
- // Copyright 2023 Google LLC
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- import FirebaseVertexAI
- import MarkdownUI
- import SwiftUI
- extension SafetySetting.HarmCategory: CustomStringConvertible {
- public var description: String {
- switch self {
- case .dangerousContent: "Dangerous content"
- case .harassment: "Harassment"
- case .hateSpeech: "Hate speech"
- case .sexuallyExplicit: "Sexually explicit"
- case .unknown: "Unknown"
- case .unspecified: "Unspecified"
- }
- }
- }
- extension SafetyRating.HarmProbability: CustomStringConvertible {
- public var description: String {
- switch self {
- case .high: "High"
- case .low: "Low"
- case .medium: "Medium"
- case .negligible: "Negligible"
- case .unknown: "Unknown"
- case .unspecified: "Unspecified"
- }
- }
- }
- private struct SubtitleFormRow: View {
- var title: String
- var value: String
- var body: some View {
- VStack(alignment: .leading) {
- Text(title)
- .font(.subheadline)
- Text(value)
- }
- }
- }
- private struct SubtitleMarkdownFormRow: View {
- var title: String
- var value: String
- var body: some View {
- VStack(alignment: .leading) {
- Text(title)
- .font(.subheadline)
- Markdown(value)
- }
- }
- }
- private struct SafetyRatingsSection: View {
- var ratings: [SafetyRating]
- var body: some View {
- Section("Safety ratings") {
- List(ratings, id: \.self) { rating in
- HStack {
- Text("\(String(describing: rating.category))")
- .font(.subheadline)
- Spacer()
- Text("\(String(describing: rating.probability))")
- }
- }
- }
- }
- }
- struct ErrorDetailsView: View {
- var error: Error
- var body: some View {
- NavigationView {
- Form {
- switch error {
- case let GenerateContentError.internalError(underlying: underlyingError):
- Section("Error Type") {
- Text("Internal error")
- }
- Section("Details") {
- SubtitleFormRow(title: "Error description",
- value: underlyingError.localizedDescription)
- }
- case let GenerateContentError.promptBlocked(response: generateContentResponse):
- Section("Error Type") {
- Text("Your prompt was blocked")
- }
- Section("Details") {
- if let reason = generateContentResponse.promptFeedback?.blockReason {
- SubtitleFormRow(title: "Reason for blocking", value: reason.rawValue)
- }
- if let text = generateContentResponse.text {
- SubtitleMarkdownFormRow(title: "Last chunk for the response", value: text)
- }
- }
- if let ratings = generateContentResponse.candidates.first?.safetyRatings {
- SafetyRatingsSection(ratings: ratings)
- }
- case let GenerateContentError.responseStoppedEarly(
- reason: finishReason,
- response: generateContentResponse
- ):
- Section("Error Type") {
- Text("Response stopped early")
- }
- Section("Details") {
- SubtitleFormRow(title: "Reason for finishing early", value: finishReason.rawValue)
- if let text = generateContentResponse.text {
- SubtitleMarkdownFormRow(title: "Last chunk for the response", value: text)
- }
- }
- if let ratings = generateContentResponse.candidates.first?.safetyRatings {
- SafetyRatingsSection(ratings: ratings)
- }
- default:
- Section("Error Type") {
- Text("Some other error")
- }
- Section("Details") {
- SubtitleFormRow(title: "Error description", value: error.localizedDescription)
- }
- }
- }
- .navigationTitle("Error details")
- .navigationBarTitleDisplayMode(.inline)
- }
- }
- }
- #Preview("Response Stopped Early") {
- let error = GenerateContentError.responseStoppedEarly(
- reason: .maxTokens,
- response: GenerateContentResponse(candidates: [
- CandidateResponse(content: ModelContent(role: "model", [
- """
- A _hypothetical_ model response.
- Cillum ex aliqua amet aliquip labore amet eiusmod consectetur reprehenderit sit commodo.
- """,
- ]),
- safetyRatings: [
- SafetyRating(category: .dangerousContent, probability: .high),
- SafetyRating(category: .harassment, probability: .low),
- SafetyRating(category: .hateSpeech, probability: .low),
- SafetyRating(category: .sexuallyExplicit, probability: .low),
- ],
- finishReason: FinishReason.maxTokens,
- citationMetadata: nil),
- ])
- )
- return ErrorDetailsView(error: error)
- }
- #Preview("Prompt Blocked") {
- let error = GenerateContentError.promptBlocked(
- response: GenerateContentResponse(candidates: [
- CandidateResponse(content: ModelContent(role: "model", [
- """
- A _hypothetical_ model response.
- Cillum ex aliqua amet aliquip labore amet eiusmod consectetur reprehenderit sit commodo.
- """,
- ]),
- safetyRatings: [
- SafetyRating(category: .dangerousContent, probability: .high),
- SafetyRating(category: .harassment, probability: .low),
- SafetyRating(category: .hateSpeech, probability: .low),
- SafetyRating(category: .sexuallyExplicit, probability: .low),
- ],
- finishReason: FinishReason.other,
- citationMetadata: nil),
- ])
- )
- return ErrorDetailsView(error: error)
- }
|