18204BDD2C193F9D00F94E69 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 18204BDC2C193F9D00F94E69 /* Assets.xcassets */; };
18204BE02C193F9D00F94E69 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 18204BDE2C193F9D00F94E69 /* LaunchScreen.storyboard */; };
18204BEE2C19428100F94E69 /* MixSdk.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 18204BEC2C19417000F94E69 /* MixSdk.framework */; };
+ 1843A7962C4E060D00FC010F /* LogViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1843A7952C4E060D00FC010F /* LogViewController.swift */; };
184FFC492C218FC4006F664D /* PlayerManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 184FFC482C218FC4006F664D /* PlayerManager.swift */; };
184FFC4D2C2199E5006F664D /* SendToolBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 184FFC4C2C2199E5006F664D /* SendToolBar.swift */; };
184FFC512C21A4EB006F664D /* TtsLongViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 184FFC502C21A4EB006F664D /* TtsLongViewController.swift */; };
18C856202C3B81B900EAE874 /* tts.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 18C8561E2C3B81B800EAE874 /* tts.mp3 */; };
18DB20482C213D730070D571 /* AiMouseAudioRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = 18DB20462C213D730070D571 /* AiMouseAudioRecord.m */; };
18DB20492C213D730070D571 /* AiMouseRecordManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 18DB20472C213D730070D571 /* AiMouseRecordManager.m */; };
+ 18EC39D12C4F421C00964461 /* Config.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18EC39D02C4F421C00964461 /* Config.swift */; };
18EF694A2C44CB1E00AA0A36 /* BleManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18EF69492C44CB1E00AA0A36 /* BleManager.swift */; };
18FBC2BB2C38E0FC002240AF /* ChatGptViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18FBC2BA2C38E0FC002240AF /* ChatGptViewController.swift */; };
18FF930C2C39263A0006452C /* cat.png in Resources */ = {isa = PBXBuildFile; fileRef = 18FF930A2C39263A0006452C /* cat.png */; };
18204BDF2C193F9D00F94E69 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
18204BE12C193F9D00F94E69 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
18204BE72C19417000F94E69 /* MixSdk.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = MixSdk.xcodeproj; path = ../MixSdk/MixSdk.xcodeproj; sourceTree = "<group>"; };
+ 1843A7952C4E060D00FC010F /* LogViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogViewController.swift; sourceTree = "<group>"; };
184FFC482C218FC4006F664D /* PlayerManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerManager.swift; sourceTree = "<group>"; };
184FFC4C2C2199E5006F664D /* SendToolBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendToolBar.swift; sourceTree = "<group>"; };
184FFC502C21A4EB006F664D /* TtsLongViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TtsLongViewController.swift; sourceTree = "<group>"; };
18DB20452C213D730070D571 /* AiMouseAudioRecord.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AiMouseAudioRecord.h; sourceTree = "<group>"; };
18DB20462C213D730070D571 /* AiMouseAudioRecord.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AiMouseAudioRecord.m; sourceTree = "<group>"; };
18DB20472C213D730070D571 /* AiMouseRecordManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AiMouseRecordManager.m; sourceTree = "<group>"; };
+ 18EC39D02C4F421C00964461 /* Config.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Config.swift; sourceTree = "<group>"; };
18EF69492C44CB1E00AA0A36 /* BleManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BleManager.swift; sourceTree = "<group>"; };
18FBC2BA2C38E0FC002240AF /* ChatGptViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatGptViewController.swift; sourceTree = "<group>"; };
18FF930A2C39263A0006452C /* cat.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = cat.png; sourceTree = "<group>"; };
18B74A272C201F2500FABBA9 /* TranslateViewController.swift */,
18B74A292C201FF200FABBA9 /* AigcViewController.swift */,
18C42C892C24344D000D8860 /* Sbc2PcmViewController.swift */,
+ 1843A7952C4E060D00FC010F /* LogViewController.swift */,
+ 18EC39D02C4F421C00964461 /* Config.swift */,
18204BD92C193F9A00F94E69 /* Main.storyboard */,
18204BDC2C193F9D00F94E69 /* Assets.xcassets */,
18204BDE2C193F9D00F94E69 /* LaunchScreen.storyboard */,
18204BD82C193F9A00F94E69 /* ViewController.swift in Sources */,
18FBC2BB2C38E0FC002240AF /* ChatGptViewController.swift in Sources */,
18B74A242C201CE900FABBA9 /* SttViewController.swift in Sources */,
+ 1843A7962C4E060D00FC010F /* LogViewController.swift in Sources */,
18EF694A2C44CB1E00AA0A36 /* BleManager.swift in Sources */,
18204BD42C193F9A00F94E69 /* AppDelegate.swift in Sources */,
18B74A262C201EBD00FABBA9 /* ChatViewController.swift in Sources */,
18B74A2A2C201FF200FABBA9 /* AigcViewController.swift in Sources */,
184FFC512C21A4EB006F664D /* TtsLongViewController.swift in Sources */,
18C42B412C230A15000D8860 /* TtsFileViewController.swift in Sources */,
+ 18EC39D12C4F421C00964461 /* Config.swift in Sources */,
18C42C8A2C24344D000D8860 /* Sbc2PcmViewController.swift in Sources */,
18B74A282C201F2500FABBA9 /* TranslateViewController.swift in Sources */,
);
self.view.backgroundColor = .white
let toolBar = SendToolBar()
- toolBar.textField.text = "太空大æ\88\98"
+ toolBar.textField.text = "å\8a¨æ¼«"
toolBar.sendBtn.setTitle("创建任务", for: .normal)
toolBar.delegate = self
view.addSubview(toolBar)
func getStyleRequest() {
view.makeToastActivity(.center)
// 0:⽂字⽣图,1: ⽂+图⽣图 5: 图⽣图(⻛格变换)
- MixSdk.shared.aigc.getStyle(type: 0) {[weak self] list, error in
+ MixSdk.shared.aigc.getStyle(type: 1) {[weak self] list, error in
self?.view.hideToastActivity()
if let err = error{
print("\(err)")
view.makeToastActivity(.center)
let task = MSAigcTask()
task.subject = text // type=5 参数不生效
- task.type = 0 //0:⽂字⽣图,1: ⽂+图⽣图 5: 图⽣图(⻛格变换)
- task.height = 320//⽣成的图⽚⾼度,type=1时需要是32的倍数。 type=5 参数不生效
- task.width = 320//⽣成的图⽚宽度,type=1时需要是32的倍数。 type=5 参数不生效
+ task.type = 1 //0:⽂字⽣图,1: ⽂+图⽣图 5: 图⽣图(⻛格变换)
task.algorithm = style.code //算法id可⽤值⻅get-style
-// task.image_base64 = getImageBase64()//type=0 不需要提交
+ task.amount = 2//生成图片的数量
+ task.image_base64 = getImageBase64()////type=0 不需要提交image_base64 type=5 必须提交
MixSdk.shared.aigc.createTask(task){[weak self] taskId, error in
//每隔1秒去查一次结果,直到获取到结果为止
@objc func getResultRequest(_ taskId:String) {
+ let model = MSAigcSearchTask()
+ /// 任务id
+ model.task_id = taskId
+ /// 位深度 只支持 8,16,24,32
+ model.bit_depth = 32
+ /// 压缩率
+ model.compression_quality = 80
+ /// 格式 目前支持 png,jpeg,jpg
+ model.format = "jpeg"
+ /// ⽣成的图⽚⾼度
+ model.height = 128
+ /// ⽣成的图⽚宽度
+ model.width = 128
+
view.makeToastActivity(.center)
- MixSdk.shared.aigc.getResult(taskId: taskId){[weak self] image, error in
+ MixSdk.shared.aigc.getResult(task: model){[weak self] imageUrls, error in
guard let self = self else {return}
self.view.hideToastActivity()
- if let image = image {
- self.imgView.image = image
+ if let url = imageUrls?.first {
+ self.downLoadFile(url)
+ print(imageUrls)
}
else{
self.perform(#selector(getResultRequest), with: taskId, afterDelay: 1)
}
extension AigcViewController {
-// func downLoadFile(url:String){
-// var request = URLRequest(url: URL(string:url)!)
-// request.httpMethod = "Get"
-// let task = URLSession.shared.dataTask(with: request) {[weak self] (data, response, error) in
-// guard let self = self else {return}
-// DispatchQueue.main.sync {
-// if let data = data,let img = UIImage(data: data){
-// self.imgView.image = img
-// }
-// }
-// }
-// task.resume()
-// }
+ func downLoadFile(_ url:String){
+ var request = URLRequest(url: URL(string:url)!)
+ request.httpMethod = "Get"
+ let task = URLSession.shared.dataTask(with: request) {[weak self] (data, response, error) in
+ guard let self = self else {return}
+ DispatchQueue.main.sync {
+ if let data = data,let img = UIImage(data: data){
+ self.imgView.image = img
+ }
+ }
+ }
+ task.resume()
+ }
func getImageBase64()->String?{
let image = UIImage(named: "cat.png")
if let base64 = image?.pngData()?.base64EncodedString(){
- let result = "data:image/png;base64," + base64
+ let result = base64
return result
}
else{
setupViews()
//设置平台
- MixSdk.shared.setPlatform(.chatGPT, key: "sk-proj-fdifVB2nPBIVcQeegE0AT3BlbkFJsgOXO5mnrmzox8pnSxMV")
- MixSdk.shared.chatGpt.changeModel(model: "gpt-4.0-turbo")
+ setupChatGpt()
}
func setupViews(){
self.title = "ChatGpt"
self.view.backgroundColor = .white
-// self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "选择文件", style: .done, target: self, action: #selector(selectFileAction))
let toolBar = SendRecordToolBar()
toolBar.textField.text = "深圳今天天气怎么样"
make.bottom.equalTo(toolBar.snp.top)
}
}
-
-// @objc func selectFileAction() {
-// view.makeToastActivity(.center)
-// guard let path = Bundle.main.path(forResource: "tts", ofType: "mp3") else {return}
-// MixSdk.shared.chatGpt.transcription(filePath: path) {[weak self] text, error in
-// guard let self = self else {return}
-// self.view.hideToastActivity()
-// if let err = error{
-// self.view.makeToast(err.message)
-// }
-// else if let text = text{
-// textView.text += "[receive] " + text + "\n"
-// let range = NSMakeRange(textView.text.count - 1, 1)
-// textView.scrollRangeToVisible(range)
-// }
-// }
-// }
- // @objc func selectFileAction() {
- // view.makeToastActivity(.center)
- // guard let pcmPath = Bundle.main.path(forResource: "input", ofType: "msbc") else {return}
- // let mp3Path = NSHomeDirectory() + "/Documents/2.mp3"
- // print(mp3Path)
- //
- // let ressult = MSAudioConvert.sbcToMp3(sbcPath: pcmPath, mp3Path: mp3Path)
- // print(ressult)
- // view.hideToastActivity()
- // }
+
+ func setupChatGpt(){
+ view.makeToastActivity(.center)
+ MixSdk.shared.chatGpt.isValidKey(gptKey) {[weak self] isValid, error in
+ guard let self = self else {return}
+ self.view.hideToastActivity()
+ if let _ = error{
+ self.view.makeToast("请求失败")
+ }
+ else {
+ if isValid! == true {
+ MixSdk.shared.setPlatform(.chatGPT, key: gptKey)
+ MixSdk.shared.chatGpt.changeModel(model:gptModel )
+ }
+ else{
+ self.view.makeToast("无效的key")
+ }
+ }
+ }
+ }
}
extension ChatGptViewController:SendRecordToolBarDelegate{
func sendRecordToolBarStartRecord(_ toolBar: SendRecordToolBar) {
view.makeToastActivity(.center)
//1、开始
- //注意demo中的手机录音的语音编码是pcm,所以参数sbc为false,如果蓝牙设备传过来的语音数据是sbc,则参数sbc传true。
- MixSdk.shared.chatGptTrans.start(sbc:false)
+ MixSdk.shared.chatGptTrans.start()
}
func sendRecordToolBar(_ toolBar: SendRecordToolBar, record data: Data) {
//2、发送的语音流
- MixSdk.shared.chatGptTrans.sendVoice(data: data)
+ //注意demo中的手机录音的语音编码是pcm,如果蓝牙设备传过来的语音数据是sbc,则使用下面的方法
+ MixSdk.shared.chatGptTrans.sendVoice(pcmData: data)
+// MixSdk.shared.chatGptTrans.sendVoice(sbcData: data)
}
func sendRecordToolBarStopRecord(_ toolBar: SendRecordToolBar) {
}
vc.addAction(action2)
let action3 = UIAlertAction(title: "ChatGPT", style: .default) { action in
- MixSdk.shared.setPlatform(.chatGPT, key: "sk-proj-fdifVB2nPBIVcQeegE0AT3BlbkFJsgOXO5mnrmzox8pnSxMV")
- MixSdk.shared.chatGpt.changeModel(model: "gpt-4.0-turbo")
+ MixSdk.shared.setPlatform(.chatGPT, key: gptKey)
+ MixSdk.shared.chatGpt.changeModel(model: gptModel)
self.title = "chatGPT"
}
vc.addAction(action3)
--- /dev/null
+//
+// Config.swift
+// Example
+//
+// Created by incar on 2024/7/23.
+//
+
+import Foundation
+
+
+
+let gptKey = "sk-proj-04ogvrZQqyaiv1OWw8OZT3BlbkFJG9Gyr8oFvRdmr3oXQNbX"
+let gptModel = "gpt-4-turbo"
--- /dev/null
+//
+// LogViewController.swift
+// Example
+//
+// Created by incar on 2024/7/22.
+//
+
+import UIKit
+import MixSdk
+
+class LogViewController: UIViewController {
+
+ var textView = UITextView()
+
+ override func viewDidLoad() {
+ title = "log"
+
+ view.addSubview(textView)
+ textView.snp.makeConstraints { make in
+ make.top.equalToSuperview()
+ make.left.right.bottom.equalToSuperview()
+ }
+ }
+
+ override func viewDidAppear(_ animated: Bool) {
+ super.viewDidAppear(animated)
+
+ textView.text = MixSdk.shared.logs.joined(separator: "\n")
+ let range = NSMakeRange(textView.text.count - 1, 1)
+ textView.scrollRangeToVisible(range)
+ }
+}
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
guard let _ = (scene as? UIWindowScene) else { return }
+
+
+ let btn = UIButton(type: .custom)
+ btn.frame = CGRect(x: UIScreen.main.bounds.size.width - 80, y: 100, width:60, height: 60)
+ btn.backgroundColor = .blue
+ btn.layer.cornerRadius = 30
+ btn.layer.masksToBounds = true
+ btn.setTitle("log", for: .normal)
+ btn.addTarget(self, action: #selector(logAction), for: .touchUpInside)
+ window?.rootViewController?.view.addSubview(btn)
+ }
+
+ @objc func logAction(){
+ guard let nc = window?.rootViewController as? UINavigationController else {return}
+ let vc = LogViewController()
+ nc.pushViewController(vc, animated: true)
}
func sceneDidDisconnect(_ scene: UIScene) {
tableView.dataSource = self
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
view.addSubview(tableView)
+
}
}
/// 格式转换回调
public typealias MSAudioConvertCallBack = (_ data:Data) -> Void
+/// 语音格式转换
public class MSAudioConvert{
/// sbc转pcm,一次性返回
/// - Parameter data: sbc数据
/// aigc任务回调
public typealias MSAigcTaskCallBack = (_ taskId: String?,_ error:MSError?) -> Void
/// aigc查询任务回调
-public typealias MSAigcQueryCallBack = (_ image: UIImage?,_ error:MSError?) -> Void
+public typealias MSAigcQueryCallBack = (_ imageUrls: [String]?,_ error:MSError?) -> Void
/// aigc类
public class MSAigc{
func getUrl(_ api:String)->String{
- return httpBaseURL + api
+ return MSConfig.httpBaseURL + api + MSConfig.headQuery()
}
/// 获取算法类型
/// 查询任务状态
/// - Parameters:
- /// - taskId: 任务id
+ /// - task: 查询的任务模型
/// - completeHandler: 结果回调
- public func getResult(taskId:String,completeHandler: @escaping MSAigcQueryCallBack){
+ public func getResult(task:MSAigcSearchTask,completeHandler: @escaping MSAigcQueryCallBack){
if !MixSdk.shared.auth.authorized {
completeHandler(nil,.unauthorised)
return
}
let url = getUrl("aigc/get-result")
- let params = [
- "task_id":taskId,
+ let params:[String:Any] = [
+ "task_id":task.task_id,
+ "bit_depth":task.bit_depth,
+ "compression_quality":task.compression_quality,
+ "format":task.format,
+ "height":task.height,
+ "width":task.width,
]
Logger.log(params)
completeHandler(nil,MSError.parsingError)
return
}
- if let result = model.data.result,let base64 = result.components(separatedBy: "data:image/png;base64,").last,let image = MSTool.base64ToImage(String(base64)){
- completeHandler(image,nil)
+ if let result = model.data.result{
+// completeHandler(image,nil)
+ completeHandler(result,nil)
}
else{
completeHandler(nil,.reponseError(model.status, model.data.status))
class MSAigcResultDataModel:Codable{
var status:String = ""
var task_id:String = ""
- var result:String?
+ var result:[String]?
}
public var type:Int = 0
/// 主题,type=5 参数不生效
public var subject:String?
- /// ⽣成的图⽚⾼度,type=1时需要是32的倍数。 type=5 参数不生效
- public var height:Int = 320
- /// ⽣成的图⽚宽度,type=1时需要是32的倍数。 type=5 参数不生效
- public var width:Int = 320
+// /// ⽣成的图⽚⾼度,type=1时需要是32的倍数。 type=5 参数不生效
+// public var height:Int = 320
+// /// ⽣成的图⽚宽度,type=1时需要是32的倍数。 type=5 参数不生效
+// public var width:Int = 320
/// 算法id可⽤值⻅get-style
public var algorithm:String = "auto"
/// type=0 不需要提交, type=5 必须提交。data:image/png;base64,{image_base64} 只要图片内容
public var image_base64:String?
+ /// 生成图片的数量,1~4张
+ public var amount:Int = 4
+
+ public init() { }
+}
+/// aigc任务查询模型
+public class MSAigcSearchTask:Codable{
+ /// 任务id
+ public var task_id:String = ""
+ /// 位深度 只支持 8,16,24,32
+ public var bit_depth:Int = 32
+ /// 压缩率
+ public var compression_quality = 80
+ /// 格式 目前支持 png,jpeg,jpg
+ public var format:String = "jpeg"
+ /// ⽣成的图⽚⾼度
+ public var height:Int = 128
+ /// ⽣成的图⽚宽度
+ public var width:Int = 128
public init() { }
}
/// 是否已经鉴权
public private(set) var authorized = false
- /// 随机数
-// var nonce = "WFY51NbA4lUff3Jd"
+ var deviceToken = ""
func getUrl(_ api:String)->String{
return "http://180.184.206.142/bz-api/" + api
if let result = dict["success"] as? Bool,result == true,let dataDict = dict["data"] as? [String:Any]{
self.authorized = true
- let token = dataDict["token"] as? String
- completeHandler(token,nil)
+ self.deviceToken = dataDict["token"] as? String ?? ""
+ completeHandler(self.deviceToken,nil)
}
else{
completeHandler(nil,MSError.reponseError(dict["code"] as? Int ?? 0,dict["msg"] as? String ?? ""))
}
}
}
+
+extension MSAuth{
+ func addHead(_ params:inout [String:Any]) -> [String:Any] {
+ params["ut"] = ""
+ params["is_auth"] = "1"
+ return params
+ }
+}
}
func openWebSocket(){
- let url = wsBaseURL + "chat/ws/watches"
- // let url = "wss://ichat.raisound.com/chat-ws/chat/ws"
+ let url = MSConfig.wsBaseURL + "chat/ws/watches" + MSConfig.headQuery()
socket = WebSocket(url)
socket.delegate = self
}
func setupHeartBeat(){
- let timer = Timer.scheduledTimer(withTimeInterval: wsHeartBeatTime, repeats: true) { [weak self] _ in
+ let timer = Timer.scheduledTimer(withTimeInterval: MSConfig.wsHeartBeatTime, repeats: true) { [weak self] _ in
guard let self = self else {return}
if socket.readyState == .open{
self.socket.ping()
Logger.log("还未鉴权")
return
}
- let params = [
+ let params:[String:Any] = [
"platform":MixSdk.shared.aiPlatform.value,
"type":"chat",
"content":content,
]
+// params = MixSdk.shared.auth.addHead(¶ms)
let cmd = params.jsonString() ?? ""
Logger.log("send" ,cmd)
socket.send(text: cmd)
}
func webSocketMessageData(_ data: Data){
- Logger.log("MSChat receive",data.joined(""))
+// Logger.log("MSChat receive",data.joined(""))
if let model = MSChatModel.decode(data){
callBack?(model)
/// ChatGpt验证key是否有效回调
public typealias MSChatGptCheckKeyCallBack = (_ isValid: Bool?,_ error:MSChatGptError?) -> Void
-/// 鉴权管理类
+/// chatGpt管理类
public class MSChatGpt {
private var transcription = MSTranscription()
- /// gpt3.5-turbo、gpt-4.0-turbo、gpt-4o
- private var gptModel = "gpt-4.0-turbo"
+ /// gpt3.5-turbo、gpt-4-turbo、gpt-4o
+ private var gptModel = "gpt-4-turbo"
func getUrl(_ api:String)->String{
return "https://api.openai.com/" + api
/// 切换chatGpt model
- /// - Parameter model: gpt3.5-turbo、gpt-4.0-turbo、gpt-4o
+ /// - Parameter model: gpt3.5-turbo、gpt-4-turbo、gpt-4o
public func changeModel(model:String){
gptModel = model
}
/// - key: chatGpt Key
/// - completeHandler: 结果回调
public func isValidKey(_ key:String ,completeHandler: @escaping MSChatGptCheckKeyCallBack){
+ let params:[String : Any] = [
+ "model": gptModel,
+ "messages": [
+ [
+ "role": "user",
+ "content": "hello"
+ ]
+ ]
+ ]
+
+ let url = getUrl("v1/chat/completions")
+ let head:[String:String] = ["Authorization":"Bearer \(key)"]
+ Logger.log(params)
+ Logger.log(head)
- completeHandler(true,nil)
+ HTTP.POST(url,parameters: params,headers: head,requestSerializer: JSONParameterSerializer()){ response in
+ DispatchQueue.main.sync {
+ Logger.log(response.data.string ?? "")
+ guard let dict = response.data.jsonObject() as? NSDictionary else{
+ completeHandler ( nil,MSChatGptError())
+ return
+ }
+ if let code = dict.value(forKeyPath: "error.code") as? String,code == "invalid_api_key"{
+ completeHandler(false,nil)
+ }
+ else{
+ completeHandler(true,nil)
+ }
+ }
+ }
}
/// 对话
}
}
+
+/// ChatGpt语音识别
public class MSChatGptTranscription {
var voiceData = Data()
var isSbc = true
/// 开始
- public func start(sbc:Bool = true){
+ public func start(){
voiceData = Data()
- isSbc = sbc
}
/// 停止
}
}
+ /// 发送语音数据,format pcm,采样率 16000
+ /// - Parameter data: 语音数据
+ public func sendVoice(pcmData: Data){
+ isSbc = false
+ voiceData.append(pcmData)
+ }
+
/// 发送语音数据,format sbc,采样率 16000
/// - Parameter data: 语音数据
- public func sendVoice(data:Data){
- voiceData.append(data)
+ public func sendVoice(sbcData: Data){
+ isSbc = true
+ voiceData.append(sbcData)
}
}
import Foundation
+
+/// ChatGpt错误类型
public class MSChatGptError:Codable{
- ///
+ /// 提示语
public var message:String = "response error"
- ///
-// public var type:String = ""
- ///
+ /// 状态码
public var code:String = "invalid_request"
}
/// 连接类型
public enum MSConnectState: Int {
+ /// 已连接
case connected
+ /// 未连接
case disConnected
}
}
func openWebSocket(){
- socket = WebSocket(wsBaseURL + "asr/ws")
+ socket = WebSocket(MSConfig.wsBaseURL + "asr/ws" + MSConfig.headQuery())
socket.delegate = self
}
func setupHeartBeat(){
- let timer = Timer.scheduledTimer(withTimeInterval: wsHeartBeatTime, repeats: true) { [weak self] _ in
+ let timer = Timer.scheduledTimer(withTimeInterval: MSConfig.wsHeartBeatTime, repeats: true) { [weak self] _ in
guard let self = self else {return}
if socket.readyState == .open{
self.socket.ping()
return
}
- var url = httpBaseURL + "asr/sentence-recognize?"
+ var url = MSConfig.httpBaseURL + "asr/sentence-recognize?" + MSConfig.headQuery()
if let value = format{
url += "format=\(value)&"
}
Logger.log(cmd)
socket.send(text: cmd )
}
- //结束转换
+
+ /// 结束转换
func stopTranscription(){
if !MixSdk.shared.auth.authorized {
Logger.log("还未鉴权")
/// 翻译类
public class MSTranslate {
private func getUrl(_ api:String)->String{
- return httpBaseURL + api
+ return MSConfig.httpBaseURL + api + MSConfig.headQuery()
}
}
}
func openWebSocket(){
- socket = WebSocket(wsBaseURL + "tts/stream")
+ socket = WebSocket(MSConfig.wsBaseURL + "tts/stream" + MSConfig.headQuery())
socket.delegate = self
}
func setupHeartBeat(){
- let timer = Timer.scheduledTimer(withTimeInterval: wsHeartBeatTime, repeats: true) { [weak self] _ in
+ let timer = Timer.scheduledTimer(withTimeInterval: MSConfig.wsHeartBeatTime, repeats: true) { [weak self] _ in
guard let self = self else {return}
if socket.readyState == .open{
self.socket.ping()
//根据需求, AISDK 还需提供以下三个方法:
//1.国内模型切换的调用方法(国内模型需求定为文心一言、KIMI、豆包)
//2.ChatGPT Key 的合规可用的校验方法,返回校验结果
-//3.ChatGPT 模型单独切换的调用方法(gpt3.5-turbo、gpt-4.0-turbo、gpt-4o)
+//3.ChatGPT 模型单独切换的调用方法(gpt3.5-turbo、gpt-4-turbo、gpt-4o)
import Foundation
//let wsBaseURL = "ws://118.145.158.207:80/"
//let httpBaseURL = "http://118.145.158.207:80/"
-let wsBaseURL = "ws://amp.raisound.com/"
-let httpBaseURL = "https://amp.raisound.com/"
-let wsHeartBeatTime = 2.0
+
+
+class MSConfig{
+ static let wsBaseURL = "ws://amp.raisound.com/"
+ static let httpBaseURL = "https://amp.raisound.com/"
+ static let wsHeartBeatTime = 2.0
+
+ static func headQuery()->String{
+// return "?platform=aliyun&is_auth=false"
+// return "?platform=aliyun&is_auth=1&tu=\(MixSdk.shared.auth.deviceToken)"
+ return ""
+ }
+}
+
/// Ai平台类型
/// SDK 管理类
public class MixSdk:NSObject {
+
public static let shared = MixSdk()
private override init() {
public var logs: [String] { Logger.logs }
/// SDK 版本号
- public let version: String = "1.0.9"
+ public let version: String = "1.0.10"
/// 默认为 false
public var isDebug: Bool = false {
didSet { Logger.isDebug = isDebug }
//let encryptData = AESEncode_C.aes_encrypt(deviceSecret, aes_key: secretKey, iv: iv)
/// 加密工具类
-public class AESEncyptUtil: NSObject {
+ class AESEncyptUtil: NSObject {
/// AES-ECB 在进行 AES 加密时,CryptoSwift 会根据密钥的长度自动选择对应的加密算法(AES128, AES192, AES256)
/// - Parameters:
/// - encryptText: 需要加密的数据
/// - key: 密钥 AES-128 = 16 bytes, AES-192 = 24 bytes, AES-256 = 32 bytes,不够位数,则自动尾部补0,直到自动补齐至加密位数
/// - Returns: 加密后的数据
- public static func encrypt_AES_ECB(encryptText: String, key: String) throws -> String {
+ static func encrypt_AES_ECB(encryptText: String, key: String) throws -> String {
/// 使用AES_ECB模式
let aes = try AES(key: Padding.zeroPadding.add(to: key.bytes, blockSize: AES.blockSize),
blockMode: ECB())
/// - encryptData: 需要加密的数据
/// - key: 密钥 AES-128 = 16 bytes, AES-192 = 24 bytes, AES-256 = 32 bytes,不够位数,则自动尾部补0,直到自动补齐至加密位数
/// - Returns: 加密后的数据
- public static func encryptData_AES_ECB(encryptData: Data, key: String) throws -> Data {
+ static func encryptData_AES_ECB(encryptData: Data, key: String) throws -> Data {
/// 使用AES_ECB模式
let aes = try AES(key: Padding.zeroPadding.add(to: key.bytes, blockSize: AES.blockSize),
blockMode: ECB())
/// - decryptText: 需要解密的数据
/// - key: 密钥
/// - Returns: 解密后的内容
- public static func decrypt_AES_ECB(decryptText: String, key: String) throws -> String {
+ static func decrypt_AES_ECB(decryptText: String, key: String) throws -> String {
/// 使用AES_ECB模式
let aes = try AES(key: Padding.zeroPadding.add(to: key.bytes, blockSize: AES.blockSize),
blockMode: ECB())
/// - decryptData: 需要解密的数据
/// - key: 密钥
/// - Returns: 解密后的内容
- public static func decryptData_AES_ECB(decryptData: Data, key: String) throws -> Data {
+ static func decryptData_AES_ECB(decryptData: Data, key: String) throws -> Data {
/// 使用AES_ECB模式
let aes = try AES(key: Padding.zeroPadding.add(to: key.bytes, blockSize: AES.blockSize),
blockMode: ECB())
/// - key: 密钥
/// - ivs: 密钥偏移量
/// - Returns: 加密后的数据
- public static func encrypt_AES_CBC(encryptText: String, key: String, ivs: String) throws -> String {
+ static func encrypt_AES_CBC(encryptText: String, key: String, ivs: String) throws -> String {
/// 使用AES_CBC模式
let aes = try AES(key: key.bytes, blockMode: CBC(iv: ivs.bytes))
/// - key: 秘钥
/// - ivs: 密钥偏移量
/// - Returns: 解密后的数据
- public static func decrypt_AES_CBC(decryptText: String, key: String, ivs: String) throws -> String {
+ static func decrypt_AES_CBC(decryptText: String, key: String, ivs: String) throws -> String {
/// 使用AES_CBC模式
let aes = try AES(key: key.bytes, blockMode: CBC(iv: ivs.bytes))
/// 开始解密 从加密后的base64字符串解密
/// - key: 密钥
/// - ivs: 密钥偏移量
/// - Returns: 加密后的数据
- public static func encrypt_AES_GCM(encryptText: Array<UInt8>, key: Array<UInt8>, ivs: Array<UInt8>) throws -> Array<UInt8> {
+ static func encrypt_AES_GCM(encryptText: Array<UInt8>, key: Array<UInt8>, ivs: Array<UInt8>) throws -> Array<UInt8> {
let gcm = GCM(iv: ivs, mode: .combined)
let aes = try AES(key: key, blockMode: gcm, padding: .noPadding)
let encrypted = try aes.encrypt(encryptText)
/// - key: 秘钥
/// - ivs: 密钥偏移量
/// - Returns: 解密后的数据
- public static func decrypt_AES_GCM(decryptText: Array<UInt8>, key: Array<UInt8>, ivs: Array<UInt8>) throws -> Array<UInt8> {
+ static func decrypt_AES_GCM(decryptText: Array<UInt8>, key: Array<UInt8>, ivs: Array<UInt8>) throws -> Array<UInt8> {
let gcm = GCM(iv: ivs, mode: .combined)
let aes = try AES(key: key, blockMode: gcm, padding: .noPadding)
return try aes.decrypt(decryptText)
## 介绍
-- 当前版本:v1.0.9
+- 当前版本:v1.0.10
-- 更新内容20240715:
- 1. 登录注册接口修改
+- 更新内容20240722:
+ 1. aigc创建任务、查询任务接口修改,支持生成4张图片,返回urls
- 1. 新增chatGpt支持语音转写
+ 1. 新增模型切换接口(文心一言、KIMI、豆包、chatGpt)
+
+ 1. 新增验证chatGpt key是否有效接口
MixSdk.shared.isDebug = true
```
-###
+
## 鉴权
/// 注册
/// - Parameters:
- /// - productKey: 产品Key
- /// - secretKey: 产品秘钥
+ /// - productId: 产品id
+ /// - productKey: 产品秘钥
/// - deviceId: 设备ID
- /// - sn: SN号
/// - completeHandler: 结果回调
- public func register(productKey: String, secretKey: String, deviceId: String, completeHandler: @escaping MixSdk.MSRegisterCallBack)
+ public func register(productId: String, productKey: String, deviceId: String, completeHandler: @escaping MixSdk.MSRegisterCallBack)
/// 登录
/// - Parameters:
/// - productKey:产品Key
- /// - secretKey: 产品秘钥
/// - deviceId: 设备ID
/// - deviceSecrect: 注册返回的密码
/// - completeHandler: 结果回调
- public func login(deviceId: String, password: String, nonce: String, completeHandler: @escaping MixSdk.MSLoginCallBack)
+ public func login(productKey: String, deviceId: String, password: String, completeHandler: @escaping MixSdk.MSLoginCallBack)
}
-
```
## 翻译
```swift
+/// 翻译类
public class MSTranslate {
-
/// 通用翻译
/// - Parameters:
/// - lang: 语言
/// - Parameter completeHandler: 结果回调
public func getSupportLanguages(completeHandler: @escaping MixSdk.MSLanuageCallBack)
}
-
```
## Aigc
```swift
+/// aigc管理类
public class MSAigc {
-
/// 获取算法类型
/// - Parameters:
/// - type: 0:⽂字⽣图,1: ⽂+图⽣图 5:图⽣图(⻛格变换)
/// 查询任务状态
/// - Parameters:
- /// - taskId: 任务id
+ /// - task: 查询的任务模型
/// - completeHandler: 结果回调
- public func getResult(taskId: String, completeHandler: @escaping MixSdk.MSAigcQueryCallBack)
+ public func getResult(task: MixSdk.MSAigcSearchTask, completeHandler: @escaping MixSdk.MSAigcQueryCallBack)
/// 创建任务
/// - Parameters:
/// - key: key值
public func setPlatform(_ platform: MixSdk.MSPlatform, key: String? = nil)
}
-```
-
-
-```swift
/// 大模型对话管理类
public class MSChat {
/// 连接状态回调
## ChatGpt
```swift
-/// 鉴权管理类
+/// ChatGpt管理类
public class MSChatGpt {
- /// 发送对话内容
+ /// 语音识别
+ /// - Parameters:
+ /// - filePath: 音频文件,支持格式flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, webm
+ /// - completeHandler: 结果回调
+ public func transcription(filePath: String, completeHandler: @escaping MixSdk.MSChatGptTranscriptionCallBack)
+
+ /// 切换chatGpt model
+ /// - Parameter model: gpt3.5-turbo、gpt-4.0-turbo、gpt-4o
+ public func changeModel(model: String)
+
+ /// 验证key是否有效
+ /// - Parameters:
+ /// - key: chatGpt Key
+ /// - completeHandler: 结果回调
+ public func isValidKey(_ key: String, completeHandler: @escaping MixSdk.MSChatGptCheckKeyCallBack)
+
+ /// 对话
/// - Parameters:
/// - content: 内容
- /// - completeHandler: 结果会调皮
+ /// - completeHandler: 结果回调
public func send(content: String, completeHandler: @escaping MixSdk.MSChatGptCallBack)
}
```
```swift
public class MSChatGptTranscription {
/// 开始
- public func start(sbc: Bool = true)
+ public func start()
/// 停止
public func stop(completeHandler: @escaping MixSdk.MSChatGptTranscriptionCallBack)
+ /// 发送语音数据,format pcm,采样率 16000
+ /// - Parameter data: 语音数据
+ public func sendVoice(pcmData: Data)
+
/// 发送语音数据,format sbc,采样率 16000
/// - Parameter data: 语音数据
- public func sendVoice(data: Data)
+ public func sendVoice(sbcData: Data)
}
```
### MSAudioConvert
```swift
+/// 音频格式转换
public class MSAudioConvert {
/// sbc转pcm,一次性返回
/// - Returns: 转换结果
public static func pcmToMp3(_ pcmPath: String, _ mp3Path: String) -> Bool
- /// sbc转mp3
+ /// sbc转pcm
/// - Parameters:
/// - sbcPath: sbc文件路径
- /// - mp3Path: mp3文件路径
+ /// - pcmPath: pcm文件路径
/// - Returns: 转换结果
- public static func sbcToMp3(sbcPath: String, mp3Path: String) -> Bool
+ public static func sbcToPcm(sbcPath: String, pcmPath: String) -> Bool
- /// sbc转mp3
+ /// sbc转mp3
/// - Parameters:
- /// - sbcData: sbc 语音数据
+ /// - pcmPath: sbc文件路径
/// - mp3Path: mp3文件路径
/// - Returns: 转换结果
- public static func sbcToMp3(sbcData: Data, mp3Path: String) -> Bool
+ public static func sbcToMp3(sbcPath: String, mp3Path: String) -> Bool
}
-
```
### MixSdk
```swift
+
/// SDK 管理类
public class MixSdk : NSObject {
-
+ /// 单利
public static let shared: MixSdk.MixSdk
/// 初始化工作
/// aikey
public var aiKey: String?
}
-
```
-### MSRegisterModel
+### MSPlatform
```swift
-/// 注册返回模型
-public class MSRegisterModel {
+/// Ai平台类型
+public enum MSPlatform {
+
+ /// 文心一言
+ case yiyan
+
+ /// 豆包
+ case doubao
+
+ /// Kimi
+ case kimi
- /// 设备ID
- public var deviceId: String
+ /// chatGPT
+ case chatGPT
+}
+```
+
+### MSConnectState
+
+```swift
+/// 连接类型
+public enum MSConnectState : Int {
- /// 设备密码
- public var password: String
+ case connected
- /// 16个字符的随机字符串
- public var nonce: String
+ case disConnected
}
```
### MSError
```swift
+/// 错误类型
public enum MSError : Error {
/// 无效的请求
/// 主题,type=5 参数不生效
public var subject: String?
- /// type=0 不需要提交,url type=5 必须提交
- public var url: String?
+ /// 算法id可⽤值⻅get-style
+ public var algorithm: String
+
+ /// type=0 不需要提交, type=5 必须提交。data:image/png;base64,{image_base64} 只要图片内容
+ public var image_base64: String?
- /// ⽣成的图⽚数量, type=5 参数不生效
+ /// 生成图片的数量,1~4张
public var amount: Int
- /// ⽣成的图⽚⾼度,type=1时需要是32的倍数。 type=5 参数不生效
+ public init()
+}
+```
+
+### MSAigcSearchTask
+
+```swift
+/// aigc任务查询模型
+public class MSAigcSearchTask : Codable {
+
+ /// 任务id
+ public var task_id: String
+
+ /// 位深度 只支持 8,16,24,32
+ public var bit_depth: Int
+
+ /// 压缩率
+ public var compression_quality: Int
+
+ /// 格式 目前支持 png,jpeg,jpg
+ public var format: String
+
+ /// ⽣成的图⽚⾼度
public var height: Int
- /// ⽣成的图⽚宽度,type=1时需要是32的倍数。 type=5 参数不生效
+ /// ⽣成的图⽚宽度
public var width: Int
- /// 算法id可⽤值⻅get-style
- public var algorithm: String
-
public init()
}
```
+
+
### MSChat
```swift
}
```
+### 其他回调
+
+```swift
+/// 注册回调
+public typealias MSRegisterCallBack = (_ password: String?, _ error: MixSdk.MSError?) -> Void
+
+/// 登录回调
+public typealias MSLoginCallBack = (_ token: String?, _ error: MixSdk.MSError?) -> Void
+
+/// 获取支持语言回调
+public typealias MSLanuageCallBack = (_ list: [MixSdk.MSTranslateLanguage]?, _ error: MixSdk.MSError?) -> Void
+
+/// 翻译回调
+public typealias MSTranslateCallBack = (_ text: String?, _ error: MixSdk.MSError?) -> Void
+
+/// aigc获取算法类型回调
+public typealias MSAigcStyleCallBack = (_ list: [MixSdk.MSAigcStyle]?, _ error: MixSdk.MSError?) -> Void
+
+/// aigc任务回调
+public typealias MSAigcTaskCallBack = (_ taskId: String?, _ error: MixSdk.MSError?) -> Void
+
+/// aigc查询任务回调
+public typealias MSAigcQueryCallBack = (_ imageUrls: [String]?, _ error: MixSdk.MSError?) -> Void
+
+/// 对话回调
+public typealias MSChatCallBack = (_ model: MixSdk.MSChatModel) -> Void
+
+/// ChatGpt对话回调
+public typealias MSChatGptCallBack = (_ response: MixSdk.MSChatGptModel?, _ error: MixSdk.MSChatGptError?) -> Void
+
+/// ChatGpt验证key是否有效回调
+public typealias MSChatGptCheckKeyCallBack = (_ isValid: Bool?, _ error: MixSdk.MSChatGptError?) -> Void
+
+/// ChatGpt语音识别回调
+public typealias MSChatGptTranscriptionCallBack = (_ text: String?, _ error: MixSdk.MSChatGptError?) -> Void
+
+/// 连接状态回调
+public typealias MSConnectStateCallBack = (_ state: MixSdk.MSConnectState) -> Void
+
+/// 语音文件识别回调
+public typealias MSSttCallBack = (_ text: String?, _ error: MixSdk.MSError?) -> Void
+
+/// Stt事件回调
+public typealias MSSttEventCallBack = (_ model: MixSdk.MSSttEvent) -> Void
+
+/// Tts合成事件回调
+public typealias MSTtsEventCallBack = (_ model: MixSdk.MSTtsEvent) -> Void
+
+/// Tts语音合成数据回调
+public typealias MSTtsVoiceCallBack = (_ data: Data) -> Void
+
+/// 格式转换回调
+public typealias MSAudioConvertCallBack = (_ data: Data) -> Void
+```
+