在Swift中使用URLRequest或Alamofire将图像发送到API

lsmd5eda  于 2023-04-10  发布在  Swift
关注(0)|答案(1)|浏览(126)

(Swift 5 / Alamofire 5 / Xcode / IOS)
我正在尝试将我拍摄的一张照片发送到mathpix API。这是mathpix的api文档中显示的方式:

curl -X POST https://api.mathpix.com/v3/text \
-H 'app_id: APP_ID' \
-H 'app_key: APP_KEY' \
--form 'file=@"cases_hw.jpg"' \
--form 'options_json="{\"math_inline_delimiters\": [\"$\", \"$\"], \"rm_spaces\": true}"'

或者使用python

#!/usr/bin/env python
import requests
import json

r = requests.post("https://api.mathpix.com/v3/text",
    files={"file": open("cases_hw.jpg","rb")},
    data={
      "options_json": json.dumps({
        "math_inline_delimiters": ["$", "$"],
        "rm_spaces": True
      })
    },
    headers={
        "app_id": "APP_ID",
        "app_key": "APP_KEY"
    }
)
print(json.dumps(r.json(), indent=4, sort_keys=True))

下面是我的代码:
@State private var selectedImage: UIImage? // The taken photo is stored here
@State private var imagePath = "" // Full path of image
请求函数代码(获取selectedImage/imagePath后调用的函数):

let image = selectedImage
                let imageData = image!.jpegData(compressionQuality: 1.0)!
                let imageKey = "takenPhoto"
                let urlString = "https://api.mathpix.com/v3/text"
                let headers: HTTPHeaders = [
                        "app_id": "my_working_app_id_here",
                        "app_key": "my_working_app_key_here"
                    ]
                
                AF.upload(multipartFormData: { multiPart in
                    multiPart.append(imageData, withName: imageKey, fileName: "takenPhoto.jpg", mimeType: "image/jpg")
                }, to: urlString, headers: headers).responseJSON { response in
                    switch response.result {
                    case .success(_):
                        if let dictionary = response.value as? [String:Any] {
                            print("success", dictionary)
                        } else {
                            print("error")
                        }
                    case .failure(let error):
                        print("error", error.localizedDescription)
                    }
                }

此代码给出

["error": Internal error, "error_info": {
    id = "sys_exception";
    message = "Internal error";
}]

我还尝试使用https://github.com/zonble/CurlDSL库来创建cURL请求:

try CURL("curl -X POST https://api.mathpix.com/v3/text -H \'app_id: my_app_id_here\' -H \'app_key: my_app_key_here\' -F image@=\(homeDirectoryString)"

但是,它会抛出与上面相同的错误。
我上面的代码只有在我用来自互联网的全局链接替换图像时才能工作(如https://mathpix-ocr-examples.s3.amazonaws.com/cases_hw.jpg
如果我在Mac上的终端中使用curl命令,它也可以很好地处理本Map像(我需要的)。
我在这个问题上浪费了大约一个星期的时间,还没有找到任何有效的解决方案。我确信错误一定是在查询语法(swift/curl)中,但我不知道如何找到它。

4ktjp1zp

4ktjp1zp1#

Swift代码中的问题是:

  1. curl命令中用于图像的密钥名称是file,而不是takenPhoto
  2. curl中的options_json根本没有提供。
    你可能会做一些像
let imageData = …
let imageKey = "file"
let filename = "takenPhoto.jpg"

let optionsKey = "options_json"
let options: [String: Any] = ["math_inline_delimiters": ["$", "$"], "rm_spaces": true]
let optionsData = try JSONSerialization.data(withJSONObject: options)

AF.upload(multipartFormData: { multiPart in
    multiPart.append(imageData, withName: imageKey, fileName: filename, mimeType: "image/jpg")
    multiPart.append(optionsData, withName: optionsKey)
}, to: urlString, headers: headers).responseJSON { response in
    …
}

一些小的观察:

  • 我建议不要使用try?,因为它会丢弃抛出的任何有意义的诊断信息;
  • 我通常会建议不要使用强制解包操作符(!);
  • 当出于诊断目的打印错误时,而不是error.localizedDescription,我可能建议只打印errorlocalizedDescription用于UI的友好字符串,但对于诊断目的,error对开发人员来说更有启发性;和
  • responseJSON已被弃用,您可能希望在不久的将来切换到responseDecodable;和
  • 我会谨慎地对mimetype和文件扩展名进行硬编码。我通常会从原始资源的URL确定mimetype:
extension URL {
    /// Mime type for the URL
    ///
    /// Requires `import UniformTypeIdentifiers` for iOS 14 solution.
    /// Requires `import MobileCoreServices` for pre-iOS 14 solution

    var mimeType: String {
        if #available(iOS 14.0, *) {
            return UTType(filenameExtension: pathExtension)?.preferredMIMEType ?? "application/octet-stream"
        } else {
            guard
                let identifier = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, pathExtension as CFString, nil)?.takeRetainedValue(),
                let mimeType = UTTypeCopyPreferredTagWithClass(identifier, kUTTagClassMIMEType)?.takeRetainedValue() as String?
            else {
                return "application/octet-stream"
            }

            return mimeType
        }
    }
}

不用说,如果你不需要支持早期的iOS版本,你可以简化它。但它说明了用于确定mimetype的API。当挑选图像时,可能会有各种不同的mimetype。

相关问题