forked from intitni/CopilotForXcode
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathEmbeddingService.swift
More file actions
118 lines (100 loc) · 3.94 KB
/
EmbeddingService.swift
File metadata and controls
118 lines (100 loc) · 3.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import Foundation
public struct EmbeddingResponse: Decodable {
public struct Object: Decodable {
public var embedding: [Float]
public var index: Int
public var object: String
}
public var data: [Object]
public var model: String
public struct Usage: Decodable {
public var prompt_tokens: Int
public var total_tokens: Int
}
public var usage: Usage
}
struct EmbeddingRequestBody: Encodable {
var input: [String]
var model: String
}
struct EmbeddingFromTokensRequestBody: Encodable {
var input: [[Int]]
var model: String
}
public struct EmbeddingService {
public let configuration: EmbeddingConfiguration
public init(configuration: EmbeddingConfiguration) {
self.configuration = configuration
}
public func embed(text: String) async throws -> EmbeddingResponse {
return try await embed(text: [text])
}
public func embed(text: [String]) async throws -> EmbeddingResponse {
guard let url = URL(string: configuration.endpoint) else {
throw ChatGPTServiceError.endpointIncorrect
}
var request = URLRequest(url: url)
request.httpMethod = "POST"
let encoder = JSONEncoder()
request.httpBody = try encoder.encode(EmbeddingRequestBody(
input: text,
model: configuration.model
))
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
if !configuration.apiKey.isEmpty {
switch configuration.featureProvider {
case .openAI:
request.setValue(
"Bearer \(configuration.apiKey)",
forHTTPHeaderField: "Authorization"
)
case .azureOpenAI:
request.setValue(configuration.apiKey, forHTTPHeaderField: "api-key")
}
}
let (result, response) = try await URLSession.shared.data(for: request)
guard let response = response as? HTTPURLResponse else {
throw ChatGPTServiceError.responseInvalid
}
guard response.statusCode == 200 else {
let error = try? JSONDecoder().decode(CompletionAPIError.self, from: result)
throw error ?? ChatGPTServiceError
.otherError(String(data: result, encoding: .utf8) ?? "Unknown Error")
}
return try JSONDecoder().decode(EmbeddingResponse.self, from: result)
}
public func embed(tokens: [[Int]]) async throws -> EmbeddingResponse {
guard let url = URL(string: configuration.endpoint) else {
throw ChatGPTServiceError.endpointIncorrect
}
var request = URLRequest(url: url)
request.httpMethod = "POST"
let encoder = JSONEncoder()
request.httpBody = try encoder.encode(EmbeddingFromTokensRequestBody(
input: tokens,
model: configuration.model
))
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
if !configuration.apiKey.isEmpty {
switch configuration.featureProvider {
case .openAI:
request.setValue(
"Bearer \(configuration.apiKey)",
forHTTPHeaderField: "Authorization"
)
case .azureOpenAI:
request.setValue(configuration.apiKey, forHTTPHeaderField: "api-key")
}
}
let (result, response) = try await URLSession.shared.data(for: request)
guard let response = response as? HTTPURLResponse else {
throw ChatGPTServiceError.responseInvalid
}
guard response.statusCode == 200 else {
let error = try? JSONDecoder().decode(CompletionAPIError.self, from: result)
throw error ?? ChatGPTServiceError
.otherError(String(data: result, encoding: .utf8) ?? "Unknown Error")
}
return try JSONDecoder().decode(EmbeddingResponse.self, from: result)
}
}