You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中构建GPT-4-Vision预览版POST请求JSON请求体问题

Swift Codable 适配多类型请求体内容

针对你需要构建包含文本和图片URL的GPT-4V请求体需求,以下两种方案可以解决现有Codable结构体的缺失问题:

方案一:枚举关联值(类型安全)

通过枚举关联值严格区分两种内容类型,避免无效的属性组合,同时实现Codable协议完成编码解码:

struct ImageInputRequestBody: Codable {
    let model: String = "gpt-4-vision-preview"
    let messages: [Message]
    let maxTokens: Int = 300
    
    enum CodingKeys: String, CodingKey {
        case model, messages
        case maxTokens = "max_tokens"
    }
    
    struct Message: Codable {
        let role: String
        let content: [Content]
    }
    
    enum Content: Codable {
        case text(String)
        case imageURL(String)
        
        func encode(to encoder: Encoder) throws {
            var container = encoder.container(keyedBy: CodingKeys.self)
            switch self {
            case .text(let text):
                try container.encode("text", forKey: .type)
                try container.encode(text, forKey: .text)
            case .imageURL(let url):
                try container.encode("image_url", forKey: .type)
                try container.encode(ImageURLWrapper(url: url), forKey: .imageURL)
            }
        }
        
        init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            let type = try container.decode(String.self, forKey: .type)
            switch type {
            case "text":
                self = .text(try container.decode(String.self, forKey: .text))
            case "image_url":
                let wrapper = try container.decode(ImageURLWrapper.self, forKey: .imageURL)
                self = .imageURL(wrapper.url)
            default:
                throw DecodingError.dataCorruptedError(forKey: .type, in: container, debugDescription: "未知内容类型:\(type)")
            }
        }
        
        enum CodingKeys: String, CodingKey {
            case type, text, imageURL = "image_url"
        }
        
        private struct ImageURLWrapper: Codable {
            let url: String
        }
    }
}

使用示例

// 构建文本和图片内容
let textContent = ImageInputRequestBody.Content.text("动态传入的文本内容")
let imageContent = ImageInputRequestBody.Content.imageURL("https://example.com/your-image.jpg")

// 组装请求体
let message = ImageInputRequestBody.Message(role: "user", content: [textContent, imageContent])
let requestBody = ImageInputRequestBody(messages: [message])

// 编码为JSON Data用于POST请求
do {
    let jsonData = try JSONEncoder().encode(requestBody)
    // 将jsonData传入URLRequest的httpBody即可
} catch {
    print("编码失败:\(error)")
}

方案二:结构体可选属性(简洁实现)

通过给Content结构体添加可选属性,配合便捷初始化方法快速构建不同类型的内容,实现成本更低:

struct ImageInputRequestBody: Codable {
    let model: String = "gpt-4-vision-preview"
    let messages: [Message]
    let maxTokens: Int = 300
    
    enum CodingKeys: String, CodingKey {
        case model, messages
        case maxTokens = "max_tokens"
    }
    
    struct Message: Codable {
        let role: String
        let content: [Content]
    }
    
    struct Content: Codable {
        let type: String
        let text: String?
        let imageURL: ImageURL?
        
        enum CodingKeys: String, CodingKey {
            case type, text
            case imageURL = "image_url"
        }
        
        struct ImageURL: Codable {
            let url: String
        }
        
        // 便捷初始化方法,快速创建文本内容
        static func text(_ text: String) -> Content {
            Content(type: "text", text: text, imageURL: nil)
        }
        
        // 便捷初始化方法,快速创建图片URL内容
        static func imageURL(_ url: String) -> Content {
            Content(type: "image_url", text: nil, imageURL: ImageURL(url: url))
        }
    }
}

使用示例

let textContent = ImageInputRequestBody.Content.text("动态文本")
let imageContent = ImageInputRequestBody.Content.imageURL("https://example.com/another-image.png")

let message = ImageInputRequestBody.Message(role: "user", content: [textContent, imageContent])
let requestBody = ImageInputRequestBody(messages: [message])

do {
    let jsonData = try JSONEncoder().encode(requestBody)
} catch {
    print("编码错误:\(error)")
}

方案对比

  • 枚举方案:类型安全,确保每个Content实例只能是一种类型,不会出现无效组合,适合需要严格校验的场景。
  • 结构体方案:代码更简洁,实现速度快,适合快速开发,但需要注意不要错误地同时设置text和imageURL属性。

内容的提问来源于stack exchange,提问作者Vader20FF

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 20:07:49