// Copyright © 2024 Ryan Booker. All rights reserved.
import ArgumentParser
import Domain
import Foundation
public struct FastGPT: AsyncParsableCommand {
public static let configuration = CommandConfiguration(
commandName: "fastgpt",
abstract: "Ask FastGPT something.",
usage: "kg fastgpt \"What is the answer to life, the universe, and everything?\""
)
@Argument(help: "A query for FastGPT")
public var query: String
var client = Client.liveValue
enum CodingKeys: CodingKey {
case query
}
public init() {
// Intentionally left empty
}
public mutating func run() async throws {
do {
let response = try await client.run(query: query)
print(response)
} catch {
throw ValidationError(error.localizedDescription)
}
}
}
// MARK: - Processing
extension FastGPT {
struct Client {
var run: @Sendable (
_ query: String
) async throws -> Response<Answer>
@inlinable
func run(
query: String
) async throws -> Response<Answer> {
try await run(query)
}
}
}
extension FastGPT.Client {
static let liveValue = Self(
run: { query in
var request = try Endpoint.fastGPT.authorizedRequest
request.httpBody = try JSONSerialization.data(withJSONObject: ["query": query])
let (data, response) = try await URLSession.shared.data(for: request)
do {
return try JSONDecoder().decode(Response.self, from: data)
} catch {
#if DEBUG
print(response)
print(error)
print("-----")
#endif
throw error
}
}
)
}
// MARK: - Response
extension FastGPT {
public struct Answer: CustomStringConvertible, Decodable {
public struct Reference: CustomStringConvertible, Decodable {
public var title: String
public var snippet: String
public var url: URL
public var description: String {
"""
- \(title)
\(url)
\(snippet.trimmingCharacters(in: .whitespaces))
"""
}
}
public var output: String
public var tokens: Int
public var references: [Reference]
public var description: String {
"""
\(output)
References:
\(references.map(\.description).joined(separator: "\n\n"))
"""
}
}
}