Skip to content

Commit

Permalink
Merge branch 'release/3.0.0-alpha.2'
Browse files Browse the repository at this point in the history
  • Loading branch information
antonio-war committed Apr 27, 2024
2 parents d1a88d6 + 059c848 commit f1e7ef0
Show file tree
Hide file tree
Showing 10 changed files with 233 additions and 4 deletions.
12 changes: 12 additions & 0 deletions .swiftpm/xcode/xcshareddata/xcschemes/SwiftyGPT.xcscheme
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,18 @@
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<EnvironmentVariables>
<EnvironmentVariable
key = "OPEN_AI_API_KEY"
value = "ADD_YOUR_OPEN_AI_API_KEY_HERE"
isEnabled = "YES">
</EnvironmentVariable>
<EnvironmentVariable
key = "OPEN_AI_INVALID_API_KEY"
value = "ADD_YOUR_OPEN_AI_INVALID_API_KEY_HERE"
isEnabled = "YES">
</EnvironmentVariable>
</EnvironmentVariables>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,5 @@ public struct SwiftyGPTChatResponseSuccessBody: SwiftyGPTChatResponseBody, Ident
}

public struct SwiftyGPTChatResponseFailureBody: SwiftyGPTChatResponseBody, Decodable {
let error: SwiftyGPTChatResponseError
}
19 changes: 19 additions & 0 deletions Sources/SwiftyGPTChat/Models/SwiftyGPTChatResponseChoice.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,23 @@ public struct SwiftyGPTChatResponseChoice: Decodable, Equatable {
return message
}
}

init(index: Int, codableMessage: SwiftyGPTChatCodableMessage, finishReason: SwiftyGPTChatResponseFinishReason) {
self.index = index
self.codableMessage = codableMessage
self.finishReason = finishReason
}

public init(from decoder: any Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.index = try container.decode(Int.self, forKey: .index)
self.codableMessage = try container.decode(SwiftyGPTChatCodableMessage.self, forKey: .message)
self.finishReason = try container.decode(SwiftyGPTChatResponseFinishReason.self, forKey: .finishReason)
}

enum CodingKeys: String, CodingKey {
case index
case message
case finishReason = "finish_reason"
}
}
13 changes: 13 additions & 0 deletions Sources/SwiftyGPTChat/Models/SwiftyGPTChatResponseError.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// SwiftyGPTChatResponseError.swift
//
//
// Created by Antonio Guerra on 27/04/24.
//

import Foundation

struct SwiftyGPTChatResponseError: Decodable, Equatable {
let type: String
let message: String
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import Foundation

enum SwiftyGPTChatResponseFinishReason: String, Decodable {
public enum SwiftyGPTChatResponseFinishReason: String, Decodable {
case stop
case lenght
case contentFilter = "content_filter"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import XCTest
final class SwiftyGPTChatManagerTests: XCTestCase {

func testRequestWhenResponseIsSuccessful() async throws {
let mockedResponseBody = SwiftyGPTChatResponseSuccessBody(id: "Test", created: 0.0, model: .gpt3_5_turbo, fingerprint: "Test", object: "Test")
let mockedResponseBody = SwiftyGPTChatResponseSuccessBody(id: "Test", choices: [], created: 0.0, model: .gpt3_5_turbo, fingerprint: "Test", object: .completion, usage: SwiftyGPTChatResponseTokenUsage(completion: 0, prompt: 0, total: 0))
let service = SwiftyGPTChatMockService(responseBody: mockedResponseBody)
let manager = SwiftyGPTChatManager(service: service)
let response = try await manager.send(messages: [], model: .gpt3_5_turbo)
Expand Down
146 changes: 146 additions & 0 deletions Tests/SwiftyGPTChatTests/Models/SwiftyGPTChatResponseChoiceTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
//
// SwiftyGPTChatResponseChoiceTests.swift
//
//
// Created by Antonio Guerra on 27/04/24.
//

import XCTest
@testable import SwiftyGPTChat

final class SwiftyGPTChatResponseChoiceTests: XCTestCase {

var decoder: JSONDecoder!

override func setUpWithError() throws {
self.decoder = JSONDecoder()
}

override func tearDownWithError() throws {
self.decoder = nil
}

func testInitWhenMessageIsSystem() throws {
let message = SwiftyGPTChatSystemMessage(content: "test")
let choice = SwiftyGPTChatResponseChoice(index: 0, codableMessage: .system(message), finishReason: .stop)
let systemMessage = try XCTUnwrap(choice.message as? SwiftyGPTChatSystemMessage)
XCTAssertEqual(choice.index, 0)
XCTAssertEqual(choice.codableMessage, .system(message))
XCTAssertEqual(systemMessage, message)
XCTAssertEqual(choice.finishReason, .stop)
}

func testDecodeWhenMessageIsSystem() throws {
let json = """
{
"index": 0,
"message": {
"role": "system",
"content": "test"
},
"finish_reason": "stop"
}
"""
let data = try XCTUnwrap(json.data(using: .utf8))
let choice = try decoder.decode(SwiftyGPTChatResponseChoice.self, from: data)
let message = SwiftyGPTChatSystemMessage(content: "test")
XCTAssertEqual(choice.index, 0)
XCTAssertEqual(choice.codableMessage, .system(message))
let systemMessage = try XCTUnwrap(choice.message as? SwiftyGPTChatSystemMessage)
XCTAssertEqual(systemMessage, message)
XCTAssertEqual(choice.finishReason, .stop)
}

func testInitWhenMessageIsAssistant() throws {
let message = SwiftyGPTChatAssistantMessage(content: "test")
let choice = SwiftyGPTChatResponseChoice(index: 0, codableMessage: .assistant(message), finishReason: .stop)
let assistantMessage = try XCTUnwrap(choice.message as? SwiftyGPTChatAssistantMessage)
XCTAssertEqual(choice.index, 0)
XCTAssertEqual(choice.codableMessage, .assistant(message))
XCTAssertEqual(assistantMessage, message)
XCTAssertEqual(choice.finishReason, .stop)
}

func testDecodeWhenMessageIsAssistant() throws {
let json = """
{
"index": 0,
"message": {
"role": "assistant",
"content": "test"
},
"finish_reason": "stop"
}
"""
let data = try XCTUnwrap(json.data(using: .utf8))
let choice = try decoder.decode(SwiftyGPTChatResponseChoice.self, from: data)
let message = SwiftyGPTChatAssistantMessage(content: "test")
XCTAssertEqual(choice.index, 0)
XCTAssertEqual(choice.codableMessage, .assistant(message))
let assistantMessage = try XCTUnwrap(choice.message as? SwiftyGPTChatAssistantMessage)
XCTAssertEqual(assistantMessage, message)
XCTAssertEqual(choice.finishReason, .stop)
}

func testInitWhenMessageIsUser() throws {
let message = SwiftyGPTChatUserMessage(content: "test")
let choice = SwiftyGPTChatResponseChoice(index: 0, codableMessage: .user(message), finishReason: .stop)
let userMessage = try XCTUnwrap(choice.message as? SwiftyGPTChatUserMessage)
XCTAssertEqual(choice.index, 0)
XCTAssertEqual(choice.codableMessage, .user(message))
XCTAssertEqual(userMessage, message)
XCTAssertEqual(choice.finishReason, .stop)
}

func testDecodeWhenMessageIsUser() throws {
let json = """
{
"index": 0,
"message": {
"role": "user",
"content": "test"
},
"finish_reason": "stop"
}
"""
let data = try XCTUnwrap(json.data(using: .utf8))
let choice = try decoder.decode(SwiftyGPTChatResponseChoice.self, from: data)
let message = SwiftyGPTChatUserMessage(content: "test")
XCTAssertEqual(choice.index, 0)
XCTAssertEqual(choice.codableMessage, .user(message))
let userMessage = try XCTUnwrap(choice.message as? SwiftyGPTChatUserMessage)
XCTAssertEqual(userMessage, message)
XCTAssertEqual(choice.finishReason, .stop)
}

func testInitWhenMessageIsTool() throws {
let message = SwiftyGPTChatToolMessage(content: "test")
let choice = SwiftyGPTChatResponseChoice(index: 0, codableMessage: .tool(message), finishReason: .stop)
let toolMessage = try XCTUnwrap(choice.message as? SwiftyGPTChatToolMessage)
XCTAssertEqual(choice.index, 0)
XCTAssertEqual(choice.codableMessage, .tool(message))
XCTAssertEqual(toolMessage, message)
XCTAssertEqual(choice.finishReason, .stop)
}

func testDecodeWhenMessageIsTool() throws {
let json = """
{
"index": 0,
"message": {
"role": "tool",
"content": "test"
},
"finish_reason": "stop"
}
"""
let data = try XCTUnwrap(json.data(using: .utf8))
let choice = try decoder.decode(SwiftyGPTChatResponseChoice.self, from: data)
let message = SwiftyGPTChatToolMessage(content: "test")
XCTAssertEqual(choice.index, 0)
XCTAssertEqual(choice.codableMessage, .tool(message))
let toolMessage = try XCTUnwrap(choice.message as? SwiftyGPTChatToolMessage)
XCTAssertEqual(toolMessage, message)
XCTAssertEqual(choice.finishReason, .stop)
}
}
19 changes: 19 additions & 0 deletions Tests/SwiftyGPTChatTests/Models/SwiftyGPTChatResponseTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,24 @@
import XCTest

final class SwiftyGPTChatResponseTests: XCTestCase {

func testInitWhenBodyIsSuccess() throws {
let body = SwiftyGPTChatResponseSuccessBody(id: "Test", choices: [], created: 0.0, model: .gpt3_5_turbo, fingerprint: "Test", object: .completion, usage: SwiftyGPTChatResponseTokenUsage(completion: 0, prompt: 0, total: 0))
let response = try SwiftyGPTChatResponse(body: body)
XCTAssertEqual(response, .success(body: body))
}

func testInitWhenBodyIsFailure() throws {
let body = SwiftyGPTChatResponseFailureBody(error: SwiftyGPTChatResponseError(type: "Test", message: "Test"))
let response = try SwiftyGPTChatResponse(body: body)
XCTAssertEqual(response, .failure(body: body))
}

func testInitWhenBodyIsUnknown() throws {
let body = SwiftyGPTChatResponseUnknownBody()
XCTAssertThrowsError(try SwiftyGPTChatResponse(body: body))
}

struct SwiftyGPTChatResponseUnknownBody: SwiftyGPTChatResponseBody {}
}

Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import XCTest
final class SwiftyGPTChatMockServiceTests: XCTestCase {

func testRequestWhenResponseIsSuccessful() async throws {
let mockedResponseBody = SwiftyGPTChatResponseSuccessBody(id: "Test", created: 0.0, model: .gpt3_5_turbo, fingerprint: "Test", object: "Test")
let mockedResponseBody = SwiftyGPTChatResponseSuccessBody(id: "Test", choices: [], created: 0.0, model: .gpt3_5_turbo, fingerprint: "Test", object: .completion, usage: SwiftyGPTChatResponseTokenUsage(completion: 0, prompt: 0, total: 0))
let service = SwiftyGPTChatMockService(responseBody: mockedResponseBody)
let requestBody = SwiftyGPTChatRequestBody(messages: [], model: .gpt3_5_turbo)
let genericResponseBody = try await service.request(body: requestBody)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import XCTest
@testable import SwiftyGPTNetworking

final class SwiftyGPTChatNetworkingServiceTests: XCTestCase {

func testInit() {
let client = SwiftyGPTNetworkingClient()
let apiKey = "testApiKey"
Expand All @@ -20,4 +20,23 @@ final class SwiftyGPTChatNetworkingServiceTests: XCTestCase {
XCTAssertEqual(service.apiKey, apiKey)
XCTAssertEqual(service.organization, organization)
}

func testRequestWhenApiKeyIsValid() async throws {
let apiKey = try XCTUnwrap(ProcessInfo.processInfo.environment["OPEN_AI_API_KEY"])
let service = SwiftyGPTChatNetworkingService(apiKey: apiKey)
let requestBody = SwiftyGPTChatRequestBody(messages: [SwiftyGPTChatUserMessage(content: "Hello world!")], model: .gpt3_5_turbo, n: 1)
let responseBody = try await service.request(body: requestBody)
let successBody = try XCTUnwrap(responseBody as? SwiftyGPTChatResponseSuccessBody)
XCTAssertEqual(successBody.choices.count, 1)
XCTAssertEqual(successBody.object, .completion)
}

func testRequestWhenApiKeyIsNotValid() async throws {
let apiKey = try XCTUnwrap(ProcessInfo.processInfo.environment["OPEN_AI_INVALID_API_KEY"])
let service = SwiftyGPTChatNetworkingService(apiKey: apiKey)
let requestBody = SwiftyGPTChatRequestBody(messages: [SwiftyGPTChatUserMessage(content: "Hello world!")], model: .gpt3_5_turbo, n: 1)
let responseBody = try await service.request(body: requestBody)
let failureBody = try XCTUnwrap(responseBody as? SwiftyGPTChatResponseFailureBody)
XCTAssertEqual(failureBody.error.type, "invalid_request_error")
}
}

0 comments on commit f1e7ef0

Please sign in to comment.