Skip to content

Commit 9ac3b2e

Browse files
andrewheardG.Dev.Ssomsak
authored and
G.Dev.Ssomsak
committed
Update Citation decoding to handle optional values (google-gemini#135)
1 parent c70f616 commit 9ac3b2e

File tree

2 files changed

+56
-9
lines changed

2 files changed

+56
-9
lines changed

Sources/GoogleAI/GenerateContentResponse.swift

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ public struct CitationMetadata: Decodable {
174174

175175
/// A struct describing a source attribution.
176176
@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, *)
177-
public struct Citation: Decodable {
177+
public struct Citation {
178178
/// The inclusive beginning of a sequence in a model response that derives from a cited source.
179179
public let startIndex: Int
180180

@@ -297,3 +297,23 @@ extension PromptFeedback: Decodable {
297297
}
298298
}
299299
}
300+
301+
// MARK: - Codable Conformances
302+
303+
@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, *)
304+
extension Citation: Decodable {
305+
enum CodingKeys: CodingKey {
306+
case startIndex
307+
case endIndex
308+
case uri
309+
case license
310+
}
311+
312+
public init(from decoder: any Decoder) throws {
313+
let container = try decoder.container(keyedBy: CodingKeys.self)
314+
startIndex = try container.decodeIfPresent(Int.self, forKey: .startIndex) ?? 0
315+
endIndex = try container.decode(Int.self, forKey: .endIndex)
316+
uri = try container.decode(String.self, forKey: .uri)
317+
license = try container.decodeIfPresent(String.self, forKey: .license) ?? ""
318+
}
319+
}

Tests/GoogleAITests/GenerativeModelTests.swift

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -104,12 +104,27 @@ final class GenerativeModelTests: XCTestCase {
104104
XCTAssertEqual(candidate.content.parts.count, 1)
105105
XCTAssertEqual(response.text, "Some information cited from an external source")
106106
let citationMetadata = try XCTUnwrap(candidate.citationMetadata)
107-
XCTAssertEqual(citationMetadata.citationSources.count, 1)
108-
let citationSource = try XCTUnwrap(citationMetadata.citationSources.first)
109-
XCTAssertEqual(citationSource.uri, "https://www.example.com/some-citation")
110-
XCTAssertEqual(citationSource.startIndex, 574)
111-
XCTAssertEqual(citationSource.endIndex, 705)
112-
XCTAssertEqual(citationSource.license, "")
107+
XCTAssertEqual(citationMetadata.citationSources.count, 4)
108+
let citationSource1 = try XCTUnwrap(citationMetadata.citationSources[0])
109+
XCTAssertEqual(citationSource1.uri, "https://www.example.com/some-citation-1")
110+
XCTAssertEqual(citationSource1.startIndex, 0)
111+
XCTAssertEqual(citationSource1.endIndex, 128)
112+
XCTAssertEqual(citationSource1.license, "")
113+
let citationSource2 = try XCTUnwrap(citationMetadata.citationSources[1])
114+
XCTAssertEqual(citationSource2.uri, "https://www.example.com/some-citation-2")
115+
XCTAssertEqual(citationSource2.startIndex, 130)
116+
XCTAssertEqual(citationSource2.endIndex, 265)
117+
XCTAssertEqual(citationSource2.license, "")
118+
let citationSource3 = try XCTUnwrap(citationMetadata.citationSources[2])
119+
XCTAssertEqual(citationSource3.uri, "https://www.example.com/some-citation-3")
120+
XCTAssertEqual(citationSource3.startIndex, 272)
121+
XCTAssertEqual(citationSource3.endIndex, 431)
122+
XCTAssertEqual(citationSource3.license, "")
123+
let citationSource4 = try XCTUnwrap(citationMetadata.citationSources[3])
124+
XCTAssertEqual(citationSource4.uri, "https://www.example.com/some-citation-4")
125+
XCTAssertEqual(citationSource4.startIndex, 444)
126+
XCTAssertEqual(citationSource4.endIndex, 630)
127+
XCTAssertEqual(citationSource4.license, "mit")
113128
}
114129

115130
func testGenerateContent_success_quoteReply() async throws {
@@ -724,9 +739,21 @@ final class GenerativeModelTests: XCTestCase {
724739

725740
XCTAssertEqual(citations.count, 8)
726741
XCTAssertTrue(citations
727-
.contains(where: { $0.startIndex == 574 && $0.endIndex == 705 && !$0.uri.isEmpty }))
742+
.contains(where: {
743+
$0.startIndex == 0 && $0.endIndex == 128 && !$0.uri.isEmpty && $0.license.isEmpty
744+
}))
728745
XCTAssertTrue(citations
729-
.contains(where: { $0.startIndex == 899 && $0.endIndex == 1026 && !$0.uri.isEmpty }))
746+
.contains(where: {
747+
$0.startIndex == 130 && $0.endIndex == 265 && !$0.uri.isEmpty && $0.license.isEmpty
748+
}))
749+
XCTAssertTrue(citations
750+
.contains(where: {
751+
$0.startIndex == 272 && $0.endIndex == 431 && !$0.uri.isEmpty && $0.license.isEmpty
752+
}))
753+
XCTAssertTrue(citations
754+
.contains(where: {
755+
$0.startIndex == 444 && $0.endIndex == 630 && !$0.uri.isEmpty && $0.license == "mit"
756+
}))
730757
}
731758

732759
func testGenerateContentStream_errorMidStream() async throws {

0 commit comments

Comments
 (0)