TSNetWork+Business.swift 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. //
  2. // TSNetWork+Business.swift
  3. // AIEmoji
  4. //
  5. // Created by 100Years on 2025/1/16.
  6. //
  7. /// 基础 URL(根据需求修改)
  8. private let baseURL = "http://ai.100yearslater.com"
  9. private let baseChinaURL = "http://ai.100yearslater100.com"
  10. import Alamofire
  11. enum TSNeURLType:String {
  12. case imageEmoji = "/api/image/emoji" //文生emoji
  13. case actionInfo = "/api/action/info" //查询生成过程接口
  14. case chat = "/api/text/chat" //AI 对话接口
  15. case textPicCreate = "/api/image/create" //文生图
  16. case upload = "/api/upload" //上传图片
  17. case imageRewrite = "/api/image/rewrite" //图生图
  18. case imageToImageStyle = "/api/ops/aichat-img2img-config" //图生图 风格列表
  19. case chatV2 = "/api/text/chat/v2" //AI 对话接口V2,扩展了 DeepSeek 深度思考
  20. case config = "/api/ops/aichat-config" //App配置
  21. case changeAge = "/api/image/change-age" //换年龄
  22. case subscriptionApple = "/api/subscription/apple" //苹果订阅
  23. case changeEmotion = "/api/image/change-emotion" //更换表情
  24. case changeHair = "/api/image/change-hair" //更换头发
  25. case imageRestore = "/api/image/restore" //老照片修复
  26. case eyeOpen = "/api/image/eye-open" //睁眼
  27. case pretty = "/api/image/pretty" //美容
  28. case photoAnimation = "/api/image/animation" //照片变活
  29. case photoExpand = "/api/image/outpaint" //照片扩展
  30. case overResolution = "/api/image/over-resolution" //图片超分辨率
  31. case changeClothes = "/api/image/change-clothes" //换衣服
  32. func getUrlString() -> String {
  33. if Locale.current.identifier.contains("_CN") {//中国区
  34. return baseChinaURL + self.rawValue
  35. }else{
  36. return baseURL + self.rawValue
  37. }
  38. }
  39. }
  40. //let kGenerateFailed:String = "Failed to generate, please try later".localized
  41. let kGenerateFailed:String = "Sorry there was a slight problem with the image processing, please try again later.".localized
  42. enum TSNetWorkCode : Int {
  43. case success = 200
  44. case fail = 0 //通用错误
  45. case textSensitive = -10003 //文生图敏感错误
  46. case imageSensitive = -10004 //图生图敏感错误
  47. case networkError = -1005 //网络错误
  48. var errorMsg:String {
  49. switch self {
  50. case .textSensitive,.imageSensitive:
  51. return "Your photo may contain nudity, gore or violence that does not comply with the health policy, please replace the photo and try again.".localized
  52. case .networkError:
  53. return "No network, please check your network and try again.".localized
  54. default:
  55. return "Sorry there was a slight problem with the image processing, please try again later.".localized
  56. }
  57. }
  58. //获取生成错误 code 对应的文案
  59. static func errorMsg(code:Int)->String{
  60. let netCode = TSNetWorkCode(rawValue: code) ?? .fail
  61. return netCode.errorMsg
  62. }
  63. //敏感错误
  64. static func sensitiveError(code:Int)->Bool{
  65. let netCode = TSNetWorkCode(rawValue: code)
  66. switch netCode {
  67. case .textSensitive,.imageSensitive:
  68. return true
  69. default:
  70. return false
  71. }
  72. }
  73. //网络错误错误
  74. static func networkError(code:Int)->Bool{
  75. let netCode = TSNetWorkCode(rawValue: code)
  76. switch netCode {
  77. case .networkError:
  78. return true
  79. default:
  80. return false
  81. }
  82. }
  83. //网络错误错误
  84. static func getErrorCode(_ error: Error) -> Int {
  85. if let urlError = error as? URLError {
  86. switch urlError.code {
  87. case .notConnectedToInternet, .networkConnectionLost:
  88. return TSNetWorkCode.networkError.rawValue
  89. default:
  90. return urlError.code.rawValue
  91. }
  92. }
  93. return 0
  94. }
  95. //获取生成错误 code 对应的文案
  96. static func getGeneratorStyle(code:Int)->TSGeneratorView.Style{
  97. let netCode = TSNetWorkCode(rawValue: code)
  98. switch netCode {
  99. case .textSensitive,.imageSensitive:
  100. return TSGeneratorView.Style.sensitiveError
  101. case .networkError:
  102. return TSGeneratorView.Style.netWorkError
  103. default:
  104. return TSGeneratorView.Style.generalError
  105. }
  106. }
  107. }
  108. extension Error {
  109. var tsCode:Int {
  110. if let error = self as? AFError, let underlyingError = error.underlyingError as? URLError {
  111. switch underlyingError.code {
  112. case .notConnectedToInternet, .networkConnectionLost,.timedOut:
  113. return TSNetWorkCode.networkError.rawValue
  114. default:
  115. return underlyingError.code.rawValue
  116. }
  117. }else
  118. if let urlError = self as? URLError {
  119. switch urlError.code {
  120. case .notConnectedToInternet, .networkConnectionLost,.timedOut:
  121. return TSNetWorkCode.networkError.rawValue
  122. default:
  123. return urlError.code.rawValue
  124. }
  125. }
  126. return 0
  127. }
  128. var tsDesc:String {
  129. return TSNetWorkCode.errorMsg(code: tsCode)
  130. }
  131. }
  132. func getUserInfoJsonString()->[String:Any] {
  133. let uuid: String
  134. let uuidUdKey = "my_UUID"
  135. if let saved = UserDefaults.standard.string(forKey: uuidUdKey),
  136. !saved.isEmpty {
  137. uuid = saved
  138. } else {
  139. let newUuid = UUID().uuidString
  140. UserDefaults.standard.set(newUuid, forKey: uuidUdKey)
  141. UserDefaults.standard.synchronize()
  142. uuid = newUuid
  143. }
  144. let dic:[String:Any] = [
  145. "device":UIDevice.current.modelName,
  146. "deviceId":uuid,
  147. "iosVersion":UIDevice.current.systemVersion,
  148. "appVersion":appShortVersion(),
  149. "subscriptionStatus":kPurchaseDefault.isVip ? "active" : "fallow",
  150. ]
  151. return dic
  152. }
  153. func getLanguageCode()->String{
  154. if Locale.current.identifier.contains("zh-Hant"){
  155. return "zh-Hant"
  156. }
  157. if let languageCode = Locale.current.languageCode {
  158. // print("当前设备语言简写: \(languageCode)") // 输出如 "en", "ja", "zh" 等
  159. return languageCode
  160. }
  161. return "en"
  162. }
  163. extension TSNetworkManager {
  164. /// 通用 get 请求
  165. func get<T: TSBaseModel>(
  166. urlType: TSNeURLType,
  167. parameters: [String: Any]? = nil,
  168. responseType: T.Type? = nil,
  169. completion: @escaping (Result<Any, Error>) -> Void
  170. ) -> Request {
  171. let urlString = urlType.getUrlString()
  172. return request(method: .get, urlString: urlString, parameters:parameters) { result in
  173. completion(result)
  174. }
  175. }
  176. /// 通用 POST 请求
  177. /// - Parameters:
  178. /// - endpoint: 接口路径
  179. /// - parameters: 请求参数
  180. /// - responseType: 响应数据模型(可选)
  181. /// - completion: 请求完成的回调
  182. func post<T: TSBaseModel>(
  183. urlType: TSNeURLType,
  184. parameters: [String: Any]? = nil,
  185. responseType: T.Type? = nil,
  186. completion: @escaping (Result<Any, Error>) -> Void
  187. ) -> Request {
  188. let urlString = urlType.getUrlString()
  189. return request(method: .post, urlString: urlString, parameters:parameters) { result in
  190. completion(result)
  191. }
  192. }
  193. /// 通用 POST Stream 请求
  194. /// - Parameters:
  195. /// - endpoint: 接口路径
  196. /// - parameters: 请求参数
  197. /// - responseType: 响应数据模型(可选)
  198. /// - completion: 请求完成的回调
  199. func postStream<T: TSBaseModel>(
  200. urlType: TSNeURLType,
  201. parameters: [String: Any]? = nil,
  202. responseType: T.Type? = nil,
  203. streamHandler:@escaping (String) -> Void,
  204. completion: @escaping (Result<Any, Error>) -> Void
  205. ) -> Request?{
  206. let urlString = urlType.getUrlString()
  207. let streamRequest = postStreamRequest(urlString: urlString, parameters: parameters, streamHandler: streamHandler, completion: completion)
  208. return streamRequest
  209. }
  210. /// 上传多个 Data 数据
  211. /// - Parameters:
  212. /// - urlType: TSNeURLType
  213. /// - dataArray: Data 数组,每个元素是一个字典,包含 Data 和字段名
  214. /// - parameters: 其他参数(可选)
  215. /// - headers: 自定义请求头(可选)
  216. /// - completion: 完成回调,返回结果或错误
  217. func uploadData<T: TSBaseModel>(
  218. urlType: TSNeURLType,
  219. dataArray: [[String: Any]], // Data 数组,每个元素包含 Data 和字段名
  220. parameters: [String: Any]? = nil,
  221. responseType: T.Type? = nil,
  222. progressHandler: @escaping (Float) -> Void, // 上传进度回调
  223. completion: @escaping (Result<Any, Error>) -> Void
  224. ) -> Request?{
  225. let urlString = urlType.getUrlString()
  226. let request = uploadData(urlString: urlString,dataArray:dataArray, parameters: parameters, progressHandler: { progress in
  227. progressHandler(Float(progress.fractionCompleted))
  228. },completion: completion)
  229. return request
  230. }
  231. func downloadFile(
  232. urlString: String,
  233. to destination: URL,
  234. progressHandler: ((Double) -> Void)? = nil,
  235. completion: @escaping (URL?, Error?) -> Void
  236. ) -> DownloadRequest? {
  237. let request = self.downloadFile(
  238. urlString: urlString,
  239. to: destination,
  240. progressHandler: { progress in
  241. print("下载进度: \(progress * 100)%")
  242. progressHandler?(progress)
  243. },
  244. completion: { result in
  245. switch result {
  246. case .success(let fileURL):
  247. dePrint("下载完成,文件保存在: \(fileURL.path)")
  248. completion(fileURL,nil)
  249. case .failure(let error):
  250. dePrint("下载失败: \(error.localizedDescription)")
  251. completion(nil,error)
  252. }
  253. }
  254. )
  255. return request
  256. }
  257. }
  258. extension TSNetworkManager {
  259. func uploadImage(
  260. upLoadImage:UIImage,
  261. maxKb:Int,
  262. progressHandler: @escaping (Float) -> Void, // 上传进度回调
  263. completion: @escaping (Any?, Error?) -> Void)
  264. -> Request?{
  265. guard let imageData = TSImageCompress.compressImageToTargetSize(upLoadImage, targetSizeKB: maxKb, preserveTransparency: false) else {
  266. completion(nil,NSError(domain: "image nil", code: 0))
  267. return nil
  268. }
  269. var dataArray:[[String:Any]] = []
  270. if upLoadImage.hasAlphaChannel(){
  271. dataArray = [
  272. ["data": imageData,
  273. "fieldName": "file", // 字段名
  274. "fileName": "image.png", // 文件名
  275. "mimeType": "image/png" // MIME 类型
  276. ]
  277. ]
  278. }else {
  279. dataArray = [
  280. ["data": imageData,
  281. "fieldName": "file", // 字段名
  282. "fileName": "image.jpeg", // 文件名
  283. "mimeType": "image/jpeg" // MIME 类型
  284. ]
  285. ]
  286. }
  287. return TSNetworkShared.uploadData(
  288. urlType: .upload,
  289. dataArray: dataArray,
  290. progressHandler: { progress in
  291. progressHandler(progress)
  292. },completion: { [weak self] result in
  293. guard let self = self else { return }
  294. switch result {
  295. case .success(let data):
  296. if let dataDict = kNetWorkCodeSuccess(data: data),
  297. let picUrl = dataDict["result"] as? String{
  298. completion(picUrl,nil)
  299. }else{
  300. let error = NSError(domain: "Service exception", code: 0)
  301. completion(nil,error)
  302. }
  303. case .failure(let error):
  304. completion(nil,error)
  305. }
  306. })
  307. }
  308. }