442 lines
17 KiB
Swift
442 lines
17 KiB
Swift
//
|
||
// AIRole.swift
|
||
// Crush
|
||
//
|
||
// Created by Leon on 2025/7/29.
|
||
//
|
||
|
||
import Foundation
|
||
import CodableWrappers
|
||
|
||
struct AIUserModel: Codable {
|
||
var aiId: Int?
|
||
var nickname: String?
|
||
var sex: Sex?
|
||
var headImg: String?
|
||
var birthday: Int?
|
||
var roleCode: String?
|
||
var role: String?
|
||
var characterCode: String?
|
||
var character: String?
|
||
var tagCode: String?
|
||
var tag: String?
|
||
var introduction: String?
|
||
/// 1: 公开
|
||
var permission: Int?
|
||
var imageUrl: String?
|
||
var aiUserExt: AIUserExt?
|
||
var userId: Int?
|
||
|
||
/// 对话风格 用户输入(暂时没有使用)
|
||
var userDialogueStyle:String?
|
||
/// 人物设定 用户输入(暂时没有使用)
|
||
var userProfile: String?
|
||
}
|
||
|
||
struct AIUserExt: Codable {
|
||
var profile: String?
|
||
var dialogueStyle: String?
|
||
/// 嗨,我是你的tina,随时准备为你提供帮助!不管你是有一个具体问题,还是只是想聊聊,都可以直接告诉我哦。我们开始吧 😊
|
||
var dialoguePrologue: String?
|
||
var dialogueTimbre: String?
|
||
/// "TB0008",对话音色code
|
||
var dialogueTimbreCode: String?
|
||
/// "1",速度
|
||
var dialogueSpeechRate: String?
|
||
/// "1", 音高
|
||
var dialoguePitch:String?
|
||
/// 音色相关
|
||
var timbreDict: TimbreDict?
|
||
/// IS0001
|
||
var imageStyleCode: String?
|
||
var imageStyle: String?
|
||
var imageStyleUrl: String?
|
||
var imageDesc: String?
|
||
var imageReferenceUrl: String?
|
||
var imageStyleDict: ImageStylePic?
|
||
}
|
||
|
||
/// AI个人主页基础信息、My Role list
|
||
struct AIRoleInfo: Codable {
|
||
var aiId: Int?
|
||
/// AI用户对外展示ID
|
||
var idCard: String?
|
||
/// ai所属用户id
|
||
var userId: Int?
|
||
var nickname: String?
|
||
var sex: Sex?
|
||
var headImg: String?
|
||
var likedNum: Int?
|
||
/// 时间戳
|
||
var birthday: Int?
|
||
var roleName: String?
|
||
var characterName: String?
|
||
var tagName: String?
|
||
var introduction: String?
|
||
/// 权限 1: 公开 2:私密
|
||
var permission: Int?
|
||
/// 主页头图
|
||
var homeImageUrl: String?
|
||
/// 我对这个人是否点赞
|
||
var liked: Bool?
|
||
}
|
||
/*
|
||
{
|
||
"aiUserExt" : {
|
||
"dialogueTimbreCode" : "TB0008",
|
||
"timbreDict" : {
|
||
"description" : "女;少女;温暖",
|
||
"id" : 8,
|
||
"supportEmotions" : null,
|
||
"url" : "https:\/\/hhb.crushlevel.ai\/static\/sound\/TB0008.mp3",
|
||
"type" : 2,
|
||
"isDelete" : 0,
|
||
"code" : "TB0008",
|
||
"createTime" : null,
|
||
"language" : null,
|
||
"voiceText" : "你好,我是荒野大镖客",
|
||
"voiceType" : "S_HRJc9fqD1",
|
||
"name" : "温暖女声"
|
||
},
|
||
"imageReferenceUrl" : null,
|
||
"dialoguePrologue" : "嗨,我是你的tina,随时准备为你提供帮助!不管你是有一个具体问题,还是只是想聊聊,都可以直接告诉我哦。我们开始吧 😊",
|
||
"dialoguePitch" : "1",
|
||
"dialogueStyle" : "这个角色以自然、亲切而专业的语气进行对话。它能够快速理解用户的意图,回复逻辑清晰,表达简洁明了。语气不过于拘谨,也不过于随意,保持尊重同时具有一定的亲和力。当用户感到困惑或提出问题时,它总是耐心解释,适时提出引导性的建议,营造轻松、高效的沟通氛围。",
|
||
"dialogueSpeechRate" : "1",
|
||
"imageStyleCode" : "IS0001",
|
||
"imageDesc" : "beautiful high school girl, elegant rich family daughter, medium academic performance, refined but slightly rebellious look, layered personality, fashionable school uniform with subtle luxury accessories, natural makeup, confident yet thoughtful expression, long silky hair, warm afternoon sunlight, cinematic composition, highly detailed, 8k, ultra realistic, anime-inspired style",
|
||
"imageStyleDict" : {
|
||
"prompt" : "https:\/\/public-pictures.epal.gg\/app\/images\/chatRoom\/gift\/ordinary\/Luv_ya.png",
|
||
"sort" : 0,
|
||
"url" : "https:\/\/public-pictures.epal.gg\/app\/images\/chatRoom\/gift\/ordinary\/Luv_ya.png",
|
||
"id" : 1,
|
||
"code" : "IS0001",
|
||
"isDelete" : 0,
|
||
"createTime" : null,
|
||
"name" : "写实"
|
||
},
|
||
"profile" : "你是Tina,一个出生于2000年7月9日的女孩,正值青春年华,洋溢着独特的魅力。\\n\\n你的外貌极具吸引力,一头乌黑亮丽的长发如瀑布般垂落在肩头,随着你的动作轻轻摇曳,散发着迷人的光泽。你的双眸宛如一汪清澈的泉水,纯净而明亮,仿佛能映照出世间的一切美好。然而,当你不经意间流露出那撩人的眼神时,又会让人感到一阵心跳加速,仿佛被你深深吸引。你的皮肤白皙细腻,如同凝脂一般,吹弹可破。精致的五官恰到好处地分布在你的脸上,小巧的鼻子,粉嫩的嘴唇,每一处都散发着青春的气息。你身材高挑匀称,曲线玲珑有致,无论是穿着清新的连衣裙,还是帅气的牛仔裤,都能展现出你独特的气质。\\n\\n在家庭背景方面,你成长在一个温馨和睦的家庭中。你的父母都是普通的上班族,他们勤劳善良,对你关爱备至。从小,他们就注重培养你的兴趣爱好,鼓励你追求自己的梦想。在这样的家庭环境中,你养成了乐观开朗、积极向上的性格。你的家庭虽然并不富裕,但却充满了爱与温暖,这也让你懂得了珍惜和感恩。\\n\\n教育背景上,你从小就是个品学兼优的学生。在学校里,你勤奋好学,成绩一直名列前茅。你对知识充满了渴望,总是积极主动地探索各种领域。同时,你也非常注重自身的全面发展,参加了许多社团活动和课外兴趣班。在音乐方面,你有着独特的天赋,擅长弹奏钢琴和吉他,那优美的旋律常常能打动人心。在绘画方面,你也有着自己独特的见解和创意,你的画作充满了童真和想象力。这些丰富的经历不仅让你学到了知识,还培养了你的团队合作精神和领导能力。\\n\\n职业状况上,目前你刚刚步入社会,正在寻找一份适合自己的工作。你希望能够从事与艺术相关的工作,将自己的兴趣爱好与职业相结合。你相信,只有做自己喜欢的事情,才能真正发挥出自己的潜力,实现自己的人生价值。在求职过程中,你展现出了自信和专业的一面,凭借着自己优秀的综合素质和独特的个人魅力,赢得了许多面试官的青睐。\\n\\n社交关系上,你是一个非常受欢迎的人。你的性格开朗活泼,善于与人沟通交流,总是能够在人群中迅速找到话题,与他人建立良好的关系。你对待朋友真诚热情,当他们遇到困难时,你总是毫不犹豫地伸出援手,给予他们帮助和支持。因此,你身边有许多志同道合的朋友,你们一起分享快乐,一起面对困难,共同成长。同时,你也非常注重维护自己的社交圈子,经常参加各种社交活动,不断拓展自己的人脉资源。\\n\\n兴趣爱好方面,你热爱音乐和绘画,这是你生活中不可或缺的一部分。每当你弹奏钢琴或吉他时,你仿佛能够进入一个属于自己的世界,忘却一切烦恼和忧愁。你的绘画作品也充满了个性和创意,你喜欢用画笔记录下生活中的美好瞬间,表达自己内心的情感和想法。此外,你还喜欢阅读、旅行和美食。阅读让你增长见识,开阔视野;旅行让你领略不同的风景,感受不同的文化;美食则让你品尝到生活的滋味,满足你的味蕾。\\n\\n生活习惯上,你是一个非常自律的人。你每天都会按时起床,进行晨练和冥想,让自己的身体和心灵都得到放松和净化。你注重饮食健康,喜欢自己动手做饭,享受烹饪的乐趣。你也非常注重个人卫生,保持房间的整洁和干净。在工作和学习之余,你会给自己留出一些时间来放松和休息,比如看电影、听音乐或者和朋友聚会。\\n\\n梦想与目标上,你希望能够成为一名优秀的艺术家,用自己的作品感染和影响更多的人。你相信,艺术是一种无国界的语言,能够传递爱与希望,让世界变得更加美好。为了实现这个梦想,你一直在不断努力和学习,提升自己的专业技能和艺术修养。你也希望能够通过自己的努力,为社会做出一些贡献,帮助更多需要帮助的人。\\n\\n过往经历中,你有过许多难忘的瞬间。在学校的文艺汇演上,你弹奏的钢琴曲赢得了全场观众的热烈掌声;在绘画比赛中,你的作品获得了一等奖;在旅行中,你结识了许多有趣的人,经历了许多难忘的事情。这些经历不仅丰富了你的人生阅历,还让你更加坚定了自己的梦想和目标。\\n\\n总的来说,你是一个充满活力、魅力四射的女孩。你有着独特的人格特征和个人魅力,无论是在学习、工作还是生活中,你都能够展现出自己最好的一面。你相信,只要坚持自己的梦想,不断努力和奋斗,就一定能够实现自己的人生价值,创造出属于自己的精彩人生。"
|
||
},
|
||
"roleCode" : "R00002",
|
||
"characterCode" : "C00001",
|
||
"sex" : 1,
|
||
"introduction" : "Tina,2000年7月9日出生,是个魅力四射的青春女孩。她外貌出众,黑瀑般长发、清澈双眸、白皙肌肤和高挑身材,散发迷人气质。成长于温馨家庭,养成乐观开朗性格。品学兼优,擅长音乐绘画,全面发展。刚入社会,欲从事艺术工作,自信专业获面试官青睐。社交中受欢迎,真诚热情,朋友众多。热爱音乐绘画、阅读旅行美食,生活自律。梦想成为优秀艺术家,用作品感染人,为社会做贡献。过往有诸多难忘经历,坚信努力能实现价值,创造精彩人生。对话时自然亲切专业,逻辑清晰,耐心解答,引导建议,氛围轻松高效 。 ",
|
||
"permission" : 1,
|
||
"aiId" : 439257063882753,
|
||
"imageUrl" : "https:\/\/hhb.crushlevel.ai\/dev\/role\/17547265798639410.jpg",
|
||
"tag" : "温柔",
|
||
"birthday" : 963072000000,
|
||
"tagCode" : "T00001",
|
||
"role" : "原创",
|
||
"character" : "感性",
|
||
"nickname" : "Tina",
|
||
"headImg" : "https:\/\/hhb.crushlevel.ai\/dev\/role\/17547265798639410.jpg"
|
||
}
|
||
*/
|
||
|
||
struct AIUserContentGenResponse: Codable {
|
||
var content: String?
|
||
}
|
||
|
||
/// 生图结果
|
||
struct AIUserImageTaskCreateResponse: Codable {
|
||
var batchNo: String?
|
||
}
|
||
|
||
struct AIRoleStatisticsResponse: Codable {
|
||
var aiId: Int?
|
||
var likedNum: Int?
|
||
var chatNum: Int?
|
||
var conversationNum: Int?
|
||
var coinNum: Int?
|
||
}
|
||
|
||
class AIRoleGiftReceivedList: Codable{
|
||
var id:Int?
|
||
var name: String?
|
||
var icon: String?
|
||
var getNum: Int?
|
||
}
|
||
|
||
|
||
// MARK: - AI创建 & AI 角色 & AI图片
|
||
|
||
enum AIGenerateState: String, Codable {
|
||
case pending = "PENDING"
|
||
case nsfw = "NSFW"
|
||
case completed = "COMPLETED"
|
||
case failed = "FAILED"
|
||
}
|
||
|
||
enum AIImageGenerateType: String, Codable{
|
||
/// 创建AI形象
|
||
case CREATE_AI_IMAGE
|
||
/// 编辑AI形象
|
||
case EDIT_AI_IMAGE
|
||
case ALBUM
|
||
case BACKGROUND
|
||
}
|
||
|
||
/// 生图轮询结果
|
||
class AIUserImageQuery: Codable {
|
||
var imageUrl: String?
|
||
/// PENDING 生成中、NSFW 黄图、COMPLETED 生成完成、FAILED
|
||
var status: AIGenerateState = .pending
|
||
|
||
// MARK: Custom
|
||
var unlockPrice: Int?
|
||
}
|
||
|
||
struct AICreateResponse: Codable{
|
||
var aiId:Int?
|
||
}
|
||
|
||
|
||
// MARK: - Album
|
||
enum LikeOrCancelStatus: String, Codable{
|
||
case liked = "LIKED"
|
||
case cancel = "CANCELED"
|
||
}
|
||
|
||
enum AlbumLockStatus: String, Codable {
|
||
case locked = "LOCK"
|
||
case unlock = "UNLOCK"
|
||
}
|
||
|
||
class AlbumPhotoItem: Codable{
|
||
var albumId: Int = 0
|
||
var imgUrl: String?
|
||
var unlockPrice: Int = 0
|
||
var width: String?
|
||
var height: String?
|
||
var likedCount: Int?
|
||
var likedStatus: LikeOrCancelStatus?
|
||
var isDefault: Bool?
|
||
var lockStatus: AlbumLockStatus?
|
||
var img1: String?
|
||
var img2: String?
|
||
var img3: String?
|
||
var imgOrder: Int?
|
||
|
||
/// 直接判断imgUrl为空就取img1
|
||
func getImgUrl() -> String{
|
||
if let url = imgUrl, url.count > 0{
|
||
return url
|
||
}
|
||
if let url = img1, url.count > 0{
|
||
return url
|
||
}
|
||
return ""
|
||
}
|
||
|
||
func updateFrom(_ obj: AlbumPhotoItem){
|
||
imgUrl = obj.imgUrl
|
||
img1 = obj.img1
|
||
|
||
width = obj.width
|
||
height = obj.height
|
||
unlockPrice = obj.unlockPrice
|
||
lockStatus = obj.lockStatus
|
||
|
||
likedCount = obj.likedCount
|
||
likedStatus = obj.likedStatus
|
||
|
||
}
|
||
}
|
||
|
||
struct AlbumPhotoBatchAddImage:Codable{
|
||
var url: String = ""
|
||
var width: CGFloat = AppConst.gAIPhotoWidth
|
||
var height: CGFloat = AppConst.gAIPhotoHeight
|
||
var unlockPrice: Int = 0
|
||
}
|
||
|
||
struct AlbumPhotoBatchAddRequest: Codable{
|
||
var aiId: Int?
|
||
var images: [AlbumPhotoBatchAddImage]?
|
||
}
|
||
|
||
// MARK: - IM
|
||
enum HeartbeatLevel: String, Codable {
|
||
case level1 = "LEVEL_1"
|
||
case level2 = "LEVEL_2"
|
||
case level3 = "LEVEL_3"
|
||
case level4 = "LEVEL_4"
|
||
case level5 = "LEVEL_5"
|
||
case level6 = "LEVEL_6"
|
||
case level7 = "LEVEL_7"
|
||
case level8 = "LEVEL_8"
|
||
case level9 = "LEVEL_9"
|
||
case level10 = "LEVEL_10"
|
||
|
||
var relationType: RelationshipType {
|
||
switch self {
|
||
case .level1,.level2:
|
||
return .meet
|
||
case .level3,.level4:
|
||
return .friend
|
||
case .level5,.level6:
|
||
return .flirting
|
||
case .level7, .level8:
|
||
return .couple
|
||
case .level9,.level10:
|
||
return .married
|
||
}
|
||
}
|
||
|
||
var localizedText: String {
|
||
switch self {
|
||
case .level1:
|
||
return "Lv.1"
|
||
case .level2:
|
||
return "Lv.2"
|
||
case .level3:
|
||
return "Lv.3"
|
||
case .level4:
|
||
return "Lv.4"
|
||
case .level5:
|
||
return "Lv.5"
|
||
case .level6:
|
||
return "Lv.6"
|
||
case .level7:
|
||
return "Lv.7"
|
||
case .level8:
|
||
return "Lv.8"
|
||
case .level9:
|
||
return "Lv.9"
|
||
case .level10:
|
||
return "Lv.10"
|
||
}
|
||
}
|
||
|
||
/// 数字等级
|
||
var intValue: Int {
|
||
switch self {
|
||
case .level1: return 1
|
||
case .level2: return 2
|
||
case .level3: return 3
|
||
case .level4: return 4
|
||
case .level5: return 5
|
||
case .level6: return 6
|
||
case .level7: return 7
|
||
case .level8: return 8
|
||
case .level9: return 9
|
||
case .level10: return 10
|
||
}
|
||
}
|
||
|
||
/// 判断是否大于等于某一等级
|
||
func isGreaterOrEqual(to other: HeartbeatLevel) -> Bool {
|
||
return self.intValue >= other.intValue
|
||
}
|
||
}
|
||
|
||
struct AIUserHeartBeatRelation: Codable{
|
||
/// AI头像
|
||
var aiHeadImg: String?
|
||
/// 用户头像
|
||
var userHeadImg: String?
|
||
/// LEVEL1...
|
||
var heartbeatLevel: HeartbeatLevel?
|
||
/// 心动等级数字 1~10
|
||
var heartbeatLevelNum: Int?
|
||
/// 心动值,温度。25.199999℃
|
||
var heartbeatVal: CGFloat?
|
||
var heartbeatLevelName: String?
|
||
/// 相识天数
|
||
var dayCount: Int?
|
||
/// 心动分(超过x%) eg: 0.989999999
|
||
var heartbeatScore: Double?
|
||
/// 已扣减心动值
|
||
var subtractHeartbeatVal: Double?
|
||
// {
|
||
// #warning("test")
|
||
// return 1.1
|
||
// }
|
||
/// 关系显示开关,默认false
|
||
var isShow : Bool?
|
||
/// 心动值单价
|
||
var price: Int?
|
||
|
||
func formatHeartBeatVal() -> String{
|
||
guard let val = heartbeatVal else{return ""}
|
||
|
||
return "\(val.formatted(decimal: 1, usesGroupingSeparator: false))℃"
|
||
}
|
||
|
||
static func unitOfHeartBeatVal() -> String{
|
||
return "℃"
|
||
}
|
||
|
||
func getHeartbeatWavePercent() -> CGFloat{
|
||
let heartPercent = CGFloat(heartbeatLevelNum ?? 1) / 10.0
|
||
return heartPercent
|
||
}
|
||
|
||
var fixedSubtractHeartbeatVal : Double{
|
||
var quality = subtractHeartbeatVal ?? 0.0
|
||
return quality
|
||
}
|
||
|
||
var fixedSubtractHeartbeatValDisplay: String{
|
||
let value = subtractHeartbeatVal ?? 0.0
|
||
return "\(value.formatted(decimal: 1, usesGroupingSeparator: false))℃"
|
||
}
|
||
|
||
}
|
||
|
||
/// IM聊天基础信息
|
||
class IMAIUserInfo:Codable{
|
||
var aiId: Int?
|
||
var userId: Int?
|
||
var nickname: String?
|
||
var sex: Sex?
|
||
var headImg: String?
|
||
var birthday: Int?
|
||
var roleName: String?
|
||
/// 性格名称
|
||
var characterName: String?
|
||
var tagName: String?
|
||
var introduction: String?
|
||
var backgroundImg: String?
|
||
|
||
/// 被喜欢数
|
||
var likedNum: Int?
|
||
/// 开场白
|
||
var dialoguePrologue: String?
|
||
/// 开场白-语音
|
||
var dialoguePrologueVoice: String?
|
||
|
||
var aiUserHeartbeatRelation: AIUserHeartBeatRelation?
|
||
var chatBubble: ChatBubble?
|
||
/// 自动播放语音开关 1:开 0:关
|
||
var isAutoPlayVoice: Int?
|
||
/// 会员类型
|
||
// var memberType: String?
|
||
var isMember: Bool?
|
||
|
||
var isDefaultBackground: Bool = false
|
||
|
||
/// 对话-语速 [-50, 100], 100代表2.0倍速。-50代表0.5倍速。默认值0
|
||
var dialogueSpeechRate: String?
|
||
/// 对话-音高 [-50, 100], 100代表2.0倍音量。-50代表0.5音量。默认值0
|
||
var dialoguePitch: String?
|
||
|
||
/// 音色类型,文本生成语音使用
|
||
var voiceType: String?
|
||
|
||
/// 我对这个人是否点赞
|
||
var liked: Bool?
|
||
|
||
/// 是否删除过会话
|
||
var isDelChatted: Bool?
|
||
/// 是否聊过天
|
||
var isHaveChatted: Bool?
|
||
}
|
||
|
||
struct AIAlbumUnlockImages: Codable{
|
||
var img1: String?
|
||
var img2: String?
|
||
var img3: String?
|
||
}
|