// 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")) """ } } }