(斯威夫特 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
请求函数代码(获取selectImage/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 命令,它也可以很好地处理本地图像(我需要的)。
我在这个问题上浪费了大约一个星期,但没有找到任何有效的解决方案。我确定错误一定是在查询语法(swift/curl)中,但我不知道如何找到它。
Swift 代码中的问题是:
curl
命令中用于图像的键名是file
,而不是takenPhoto
。options_json
里面的curl
根本就没有供应你可能会做类似的事情
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
而不是 error
。 localizedDescription
用于 UI 的友好字符串,但出于诊断目的,error
对开发人员更具启发性;和
responseJSON
已弃用,您可能希望在不久的将来切换到 responseDecodable
;和
我会警惕对 mime 类型和文件扩展名进行硬编码。我通常会根据原始资产的 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 版本的支持,你可以简化它。但它说明了用于确定 mime 类型的 API。选择图像时,可能会有各种不同的 mimetypes。