Kaynağa Gözat

深度思考和文生图增加风格开发完毕

100Years 1 ay önce
ebeveyn
işleme
fe347603c4
31 değiştirilmiş dosya ile 770 ekleme ve 123 silme
  1. 34 14
      AIEmoji.xcodeproj/project.pbxproj
  2. 22 0
      AIEmoji/Assets.xcassets/AIChat/chat_down_arrow.imageset/Contents.json
  3. BIN
      AIEmoji/Assets.xcassets/AIChat/chat_down_arrow.imageset/chat_down_arrow@2x.png
  4. BIN
      AIEmoji/Assets.xcassets/AIChat/chat_down_arrow.imageset/chat_down_arrow@3x.png
  5. 22 0
      AIEmoji/Assets.xcassets/AIChat/chat_up_arrow.imageset/Contents.json
  6. BIN
      AIEmoji/Assets.xcassets/AIChat/chat_up_arrow.imageset/chat_up_arrow@2x.png
  7. BIN
      AIEmoji/Assets.xcassets/AIChat/chat_up_arrow.imageset/chat_up_arrow@3x.png
  8. 22 0
      AIEmoji/Assets.xcassets/AIChat/deepseek_icon.imageset/Contents.json
  9. BIN
      AIEmoji/Assets.xcassets/AIChat/deepseek_icon.imageset/deepseek_icon@2x.png
  10. BIN
      AIEmoji/Assets.xcassets/AIChat/deepseek_icon.imageset/deepseek_icon@3x.png
  11. 21 16
      AIEmoji/Business/AIChat/TSChatViewController/Models/CHatMessageModel/TSChatMessage.swift
  12. 33 0
      AIEmoji/Business/AIChat/TSChatViewController/Models/CHatMessageModel/TSChatThinkingModel.swift
  13. 0 0
      AIEmoji/Business/AIChat/TSChatViewController/Models/CHatMessageModel/TSChatUser.swift
  14. 0 15
      AIEmoji/Business/AIChat/TSChatViewController/Models/TSChatMessageUIModel.swift
  15. 119 0
      AIEmoji/Business/AIChat/TSChatViewController/Models/TSChatMessageUIModel/TSChatMessageUIModel.swift
  16. 54 0
      AIEmoji/Business/AIChat/TSChatViewController/Models/TSDBAIChatList.swift
  17. 11 3
      AIEmoji/Business/AIChat/TSChatViewController/Models/TSLayoutSizeCalculator.swift
  18. 10 2
      AIEmoji/Business/AIChat/TSChatViewController/TSChatViewController/TSChatViewController+ChatDelegate.swift
  19. 3 3
      AIEmoji/Business/AIChat/TSChatViewController/TSChatViewController/TSChatViewController+Keyboard.swift
  20. 95 11
      AIEmoji/Business/AIChat/TSChatViewController/TSChatViewController/TSChatViewController+SendMsg.swift
  21. 5 0
      AIEmoji/Business/AIChat/TSChatViewController/TSChatViewController/TSChatViewController.swift
  22. 75 10
      AIEmoji/Business/AIChat/TSChatViewController/ViewModel/TSAIChatVM.swift
  23. 0 7
      AIEmoji/Business/AIChat/TSChatViewController/Views/TSCellView/Untitled.swift
  24. 175 0
      AIEmoji/Business/AIChat/TSChatViewController/Views/TSChatMsgBaseView/TSAIThinkingView.swift
  25. 29 14
      AIEmoji/Business/AIChat/TSChatViewController/Views/TSChatMsgBaseView/TSChatMsgBaseView.swift
  26. 1 0
      AIEmoji/Business/AIChat/TSChatViewController/Views/TSChatMsgBaseView/TSChatMsgToolView.swift
  27. 10 9
      AIEmoji/Business/AIChat/TSChatViewController/Views/TSChatMsgBaseView/TSMSGAIDefaultHeaderView.swift
  28. 18 15
      AIEmoji/Business/AIChat/TSChatViewController/Views/TSMessageContentCell.swift
  29. 7 1
      AIEmoji/Business/General/TSBigIconBrowseVC/TSBigIconBrowseVC.swift
  30. 1 0
      AIEmoji/Business/TSTextGeneralPictureVC/TSTTPInputVC/TSTTPInputVC.swift
  31. 3 3
      AIEmoji/Common/TSRealmManager/TSRealmManager.swift

+ 34 - 14
AIEmoji.xcodeproj/project.pbxproj

@@ -78,7 +78,6 @@
 		A80EDD642D6C3F82003CD332 /* MarkdownStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = A80EDD322D6C3F82003CD332 /* MarkdownStyle.swift */; };
 		A80EDD682D6C5098003CD332 /* TSChatMsgBaseView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A80EDD672D6C507D003CD332 /* TSChatMsgBaseView.swift */; };
 		A80EDD6A2D6C518E003CD332 /* TSChatMsgToolView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A80EDD692D6C5176003CD332 /* TSChatMsgToolView.swift */; };
-		A80EDDDB2D6EB0D0003CD332 /* Untitled.swift in Sources */ = {isa = PBXBuildFile; fileRef = A80EDDDA2D6EB0BB003CD332 /* Untitled.swift */; };
 		A80EDDE02D6EB1B9003CD332 /* TSPTPGeneratorCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A80EDDDF2D6EB1B8003CD332 /* TSPTPGeneratorCell.swift */; };
 		A80EDDE22D6EB8D8003CD332 /* TSPTPUploadCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A80EDDE12D6EB8C7003CD332 /* TSPTPUploadCell.swift */; };
 		A80EDDE42D6EB8FA003CD332 /* TSPTPSelectStyleCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A80EDDE32D6EB8DC003CD332 /* TSPTPSelectStyleCell.swift */; };
@@ -105,6 +104,8 @@
 		A875870F2D81689A00286A66 /* TSPTPEnterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A875870E2D81689600286A66 /* TSPTPEnterView.swift */; };
 		A87587122D81702700286A66 /* TSUserDefaultData.swift in Sources */ = {isa = PBXBuildFile; fileRef = A87587102D81702700286A66 /* TSUserDefaultData.swift */; };
 		A87587162D81734300286A66 /* text_to_photo_style.json in Resources */ = {isa = PBXBuildFile; fileRef = A87587152D81733C00286A66 /* text_to_photo_style.json */; };
+		A87587182D81814500286A66 /* TSAIThinkingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A87587172D81812C00286A66 /* TSAIThinkingView.swift */; };
+		A899D34A2D827A0E00AB9C1C /* TSChatThinkingModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A899D3492D8279FB00AB9C1C /* TSChatThinkingModel.swift */; };
 		A89EA64B2D59A588000EB181 /* MessageKit in Frameworks */ = {isa = PBXBuildFile; productRef = A89EA64A2D59A588000EB181 /* MessageKit */; };
 		A89EA6542D59A9F4000EB181 /* TSTextLayoutSizeCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A89EA64F2D59A9F4000EB181 /* TSTextLayoutSizeCalculator.swift */; };
 		A89EA6552D59A9F4000EB181 /* TSChatMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = A89EA6502D59A9F4000EB181 /* TSChatMessage.swift */; };
@@ -268,7 +269,6 @@
 		A80EDD402D6C3F82003CD332 /* MarkdownParser+UIKit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MarkdownParser+UIKit.swift"; sourceTree = "<group>"; };
 		A80EDD672D6C507D003CD332 /* TSChatMsgBaseView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSChatMsgBaseView.swift; sourceTree = "<group>"; };
 		A80EDD692D6C5176003CD332 /* TSChatMsgToolView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSChatMsgToolView.swift; sourceTree = "<group>"; };
-		A80EDDDA2D6EB0BB003CD332 /* Untitled.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Untitled.swift; sourceTree = "<group>"; };
 		A80EDDDF2D6EB1B8003CD332 /* TSPTPGeneratorCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSPTPGeneratorCell.swift; sourceTree = "<group>"; };
 		A80EDDE12D6EB8C7003CD332 /* TSPTPUploadCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSPTPUploadCell.swift; sourceTree = "<group>"; };
 		A80EDDE32D6EB8DC003CD332 /* TSPTPSelectStyleCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSPTPSelectStyleCell.swift; sourceTree = "<group>"; };
@@ -294,6 +294,8 @@
 		A875870E2D81689600286A66 /* TSPTPEnterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSPTPEnterView.swift; sourceTree = "<group>"; };
 		A87587102D81702700286A66 /* TSUserDefaultData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSUserDefaultData.swift; sourceTree = "<group>"; };
 		A87587152D81733C00286A66 /* text_to_photo_style.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = text_to_photo_style.json; sourceTree = "<group>"; };
+		A87587172D81812C00286A66 /* TSAIThinkingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAIThinkingView.swift; sourceTree = "<group>"; };
+		A899D3492D8279FB00AB9C1C /* TSChatThinkingModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSChatThinkingModel.swift; sourceTree = "<group>"; };
 		A89EA64C2D59A9F4000EB181 /* CustomMessageFlowLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomMessageFlowLayout.swift; sourceTree = "<group>"; };
 		A89EA64E2D59A9F4000EB181 /* TSLayoutSizeCalculator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSLayoutSizeCalculator.swift; sourceTree = "<group>"; };
 		A89EA64F2D59A9F4000EB181 /* TSTextLayoutSizeCalculator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSTextLayoutSizeCalculator.swift; sourceTree = "<group>"; };
@@ -1010,15 +1012,15 @@
 			path = TSBigIconBrowseVC;
 			sourceTree = "<group>";
 		};
-		A85E47C12D6964500018D62D /* TSCellView */ = {
+		A85E47C12D6964500018D62D /* TSChatMsgBaseView */ = {
 			isa = PBXGroup;
 			children = (
-				A80EDDDA2D6EB0BB003CD332 /* Untitled.swift */,
 				A80EDD672D6C507D003CD332 /* TSChatMsgBaseView.swift */,
 				A85E47C22D69646D0018D62D /* TSMSGAIDefaultHeaderView.swift */,
 				A80EDD692D6C5176003CD332 /* TSChatMsgToolView.swift */,
+				A87587172D81812C00286A66 /* TSAIThinkingView.swift */,
 			);
-			path = TSCellView;
+			path = TSChatMsgBaseView;
 			sourceTree = "<group>";
 		};
 		A87587112D81702700286A66 /* Data */ = {
@@ -1029,6 +1031,24 @@
 			path = Data;
 			sourceTree = "<group>";
 		};
+		A87587192D819F7000286A66 /* TSChatMessageUIModel */ = {
+			isa = PBXGroup;
+			children = (
+				A85E47BF2D6961B90018D62D /* TSChatMessageUIModel.swift */,
+			);
+			path = TSChatMessageUIModel;
+			sourceTree = "<group>";
+		};
+		A899D3482D8279E500AB9C1C /* CHatMessageModel */ = {
+			isa = PBXGroup;
+			children = (
+				A899D3492D8279FB00AB9C1C /* TSChatThinkingModel.swift */,
+				A89EA6502D59A9F4000EB181 /* TSChatMessage.swift */,
+				A89EA6522D59A9F4000EB181 /* TSChatUser.swift */,
+			);
+			path = CHatMessageModel;
+			sourceTree = "<group>";
+		};
 		A89EA64D2D59A9F4000EB181 /* Layout */ = {
 			isa = PBXGroup;
 			children = (
@@ -1040,13 +1060,12 @@
 		A89EA6532D59A9F4000EB181 /* Models */ = {
 			isa = PBXGroup;
 			children = (
+				A899D3482D8279E500AB9C1C /* CHatMessageModel */,
+				A87587192D819F7000286A66 /* TSChatMessageUIModel */,
 				A89EA6A22D5B26E3000EB181 /* TSDBAIChatList.swift */,
 				A89EA6C02D5ED278000EB181 /* TSChatCellConfig.swift */,
 				A89EA64E2D59A9F4000EB181 /* TSLayoutSizeCalculator.swift */,
 				A89EA64F2D59A9F4000EB181 /* TSTextLayoutSizeCalculator.swift */,
-				A89EA6502D59A9F4000EB181 /* TSChatMessage.swift */,
-				A85E47BF2D6961B90018D62D /* TSChatMessageUIModel.swift */,
-				A89EA6522D59A9F4000EB181 /* TSChatUser.swift */,
 			);
 			path = Models;
 			sourceTree = "<group>";
@@ -1054,7 +1073,7 @@
 		A89EA6682D59AA31000EB181 /* Views */ = {
 			isa = PBXGroup;
 			children = (
-				A85E47C12D6964500018D62D /* TSCellView */,
+				A85E47C12D6964500018D62D /* TSChatMsgBaseView */,
 				A89EA6632D59AA31000EB181 /* CameraInputBarAccessoryView.swift */,
 				A89EA6662D59AA31000EB181 /* TSTextMessageContentCell.swift */,
 				A89EA6652D59AA31000EB181 /* TSMessageContentCell.swift */,
@@ -1784,7 +1803,6 @@
 				A8F775172D38EB7400AA6E93 /* TSTabBarController.swift in Sources */,
 				A80E73E12D533E5800C64288 /* TSPurchaseVC.swift in Sources */,
 				A80EDDE02D6EB1B9003CD332 /* TSPTPGeneratorCell.swift in Sources */,
-				A80EDDDB2D6EB0D0003CD332 /* Untitled.swift in Sources */,
 				A8F776352D3A7C2B00AA6E93 /* TSGenmojiColSectionView.swift in Sources */,
 				A80327B32D813D4900AF7878 /* TSTTPInputVC.swift in Sources */,
 				A80E724F2D3F6D7F00C64288 /* DiyFixedTextElement.swift in Sources */,
@@ -1807,6 +1825,7 @@
 				A80E72262D3F3A9A00C64288 /* HYHAddImageView.m in Sources */,
 				A80E72272D3F3A9A00C64288 /* DiyTextElement.swift in Sources */,
 				A8FB02BA2D3E3BB20031A396 /* TSEmojisCoLItemCell.swift in Sources */,
+				A87587182D81814500286A66 /* TSAIThinkingView.swift in Sources */,
 				A85E47962D672ADA0018D62D /* TSTextPicGennerateVC.swift in Sources */,
 				A80E72562D3F98D700C64288 /* TSDiyKeyboardViewVC.swift in Sources */,
 				A8F775032D38EA8C00AA6E93 /* GlobalImports.swift in Sources */,
@@ -1831,6 +1850,7 @@
 				A8F7753F2D39340E00AA6E93 /* TSSetingVC.swift in Sources */,
 				A8F7762B2D3A70B200AA6E93 /* PaddedLabel.swift in Sources */,
 				A80E73E62D5348D000C64288 /* SettingPurchaseTopView.swift in Sources */,
+				A899D34A2D827A0E00AB9C1C /* TSChatThinkingModel.swift in Sources */,
 				A80EDDE22D6EB8D8003CD332 /* TSPTPUploadCell.swift in Sources */,
 				A80EDDF62D6EC1ED003CD332 /* TSPhotoToPhotoVM.swift in Sources */,
 				A80E72382D3F473B00C64288 /* DiyPaperProtocol.swift in Sources */,
@@ -1872,7 +1892,7 @@
 				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
 				CLANG_ENABLE_MODULES = YES;
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 3;
+				CURRENT_PROJECT_VERSION = 1;
 				DEVELOPMENT_TEAM = 65UD255J84;
 				ENABLE_USER_SCRIPT_SANDBOXING = NO;
 				GENERATE_INFOPLIST_FILE = YES;
@@ -1888,7 +1908,7 @@
 					"$(inherited)",
 					"@executable_path/Frameworks",
 				);
-				MARKETING_VERSION = 2.0;
+				MARKETING_VERSION = 2.1;
 				PRODUCT_BUNDLE_IDENTIFIER = com.girl.music.wallpaper;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
@@ -1911,7 +1931,7 @@
 				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
 				CLANG_ENABLE_MODULES = YES;
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 3;
+				CURRENT_PROJECT_VERSION = 1;
 				DEVELOPMENT_TEAM = 65UD255J84;
 				ENABLE_USER_SCRIPT_SANDBOXING = NO;
 				GENERATE_INFOPLIST_FILE = YES;
@@ -1927,7 +1947,7 @@
 					"$(inherited)",
 					"@executable_path/Frameworks",
 				);
-				MARKETING_VERSION = 2.0;
+				MARKETING_VERSION = 2.1;
 				PRODUCT_BUNDLE_IDENTIFIER = com.girl.music.wallpaper;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";

+ 22 - 0
AIEmoji/Assets.xcassets/AIChat/chat_down_arrow.imageset/Contents.json

@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "chat_down_arrow@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "chat_down_arrow@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
AIEmoji/Assets.xcassets/AIChat/chat_down_arrow.imageset/chat_down_arrow@2x.png


BIN
AIEmoji/Assets.xcassets/AIChat/chat_down_arrow.imageset/chat_down_arrow@3x.png


+ 22 - 0
AIEmoji/Assets.xcassets/AIChat/chat_up_arrow.imageset/Contents.json

@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "chat_up_arrow@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "chat_up_arrow@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
AIEmoji/Assets.xcassets/AIChat/chat_up_arrow.imageset/chat_up_arrow@2x.png


BIN
AIEmoji/Assets.xcassets/AIChat/chat_up_arrow.imageset/chat_up_arrow@3x.png


+ 22 - 0
AIEmoji/Assets.xcassets/AIChat/deepseek_icon.imageset/Contents.json

@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "deepseek_icon@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "deepseek_icon@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
AIEmoji/Assets.xcassets/AIChat/deepseek_icon.imageset/deepseek_icon@2x.png


BIN
AIEmoji/Assets.xcassets/AIChat/deepseek_icon.imageset/deepseek_icon@3x.png


+ 21 - 16
AIEmoji/Business/AIChat/TSChatViewController/Models/TSChatMessage.swift → AIEmoji/Business/AIChat/TSChatViewController/Models/CHatMessageModel/TSChatMessage.swift

@@ -23,6 +23,24 @@
 import Foundation
 import MessageKit
 import UIKit
+
+
+// 定义一个枚举作为字典的键
+enum TSChatMessageAppendDictKey: String ,Equatable{
+    case topView
+    case centerView
+    case bottomView
+    case centerBottomView
+}
+
+// 定义一个枚举作为消息体
+enum TSChatMessageMsgType: String ,Equatable{
+    case aiRobotWelcome     = "aiRobotWelcome"
+    case userQuestion       = "userQuestion"
+    case aiRobotResponse    = "aiRobotResponse"
+}
+
+
 // MARK: - TSChatMessage
 internal class TSChatMessage: MessageType{
   // MARK: Lifecycle
@@ -59,24 +77,11 @@ internal class TSChatMessage: MessageType{
         user
     }
     var sendState: TSProgressState = .none
-    var appendDict:[TSChatMessageAppendDictKey:Any] = [:]
+    var appendUIDict:[TSChatMessageAppendDictKey:TSChatMessageUIBaseModel] = [:]
     
     var messageType:TSChatMessageMsgType = .aiRobotResponse
     var markDownText:String = ""
-}
-
-// 定义一个枚举作为字典的键
-enum TSChatMessageAppendDictKey: String ,Equatable{
-    case topView
-    case centerView
-    case bottomView
     
-    case centerBottomView
-}
-
-// 定义一个枚举作为消息体
-enum TSChatMessageMsgType: String ,Equatable{
-    case aiRobotWelcome     = "aiRobotWelcome"
-    case userQuestion       = "userQuestion"
-    case aiRobotResponse    = "aiRobotResponse"
+    
+    var thinkingModel:TSChatThinkingModel?
 }

+ 33 - 0
AIEmoji/Business/AIChat/TSChatViewController/Models/CHatMessageModel/TSChatThinkingModel.swift

@@ -0,0 +1,33 @@
+//
+//  TSChatThinkingModel.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/3/12.
+//
+
+import ObjectMapper
+
+class TSChatThinkingModel:TSBaseModel{
+    var thinkingIcon:String = "deepseek_icon"//图标
+    var thinkingName:String = "DeepSeek-R1"
+    var thinkingState:String = ""
+    
+    var thinkingString: String = ""//ai思考内容
+    var thinkingFold: Bool = false//ai 思考UI是否折叠
+    
+    var startStamp: Int = 0//开始思考时间戳
+    var endStamp: Int = 0//结束思考时间戳
+    
+    
+    override func mapping(map: Map) {
+        thinkingIcon            <- map["thinkingIcon"]
+        thinkingName            <- map["thinkingName"]
+        thinkingState            <- map["thinkingState"]
+        
+        thinkingString                  <- map["thinkingString"]
+        thinkingFold            <- map["thinkingFold"]
+        
+        startStamp                <- map["startStamp"]
+        endStamp            <- map["endStamp"]
+    }
+}

+ 0 - 0
AIEmoji/Business/AIChat/TSChatViewController/Models/TSChatUser.swift → AIEmoji/Business/AIChat/TSChatViewController/Models/CHatMessageModel/TSChatUser.swift


+ 0 - 15
AIEmoji/Business/AIChat/TSChatViewController/Models/TSChatMessageUIModel.swift

@@ -1,15 +0,0 @@
-//
-//  TSChatMessageUIModel.swift
-//  AIEmoji
-//
-//  Created by 100Years on 2025/2/21.
-//
-
-class TSChatMessageUIBaseModel: TSBaseModel {
-    var text:String = ""
-    
-    var view:TSChatMsgBaseView = TSChatMsgBaseView()
-    var height:CGFloat = 0.0
-    
-}
-

+ 119 - 0
AIEmoji/Business/AIChat/TSChatViewController/Models/TSChatMessageUIModel/TSChatMessageUIModel.swift

@@ -0,0 +1,119 @@
+//
+//  TSChatMessageUIModel.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/2/21.
+//
+
+import ObjectMapper
+
+enum TSChatMessageUIBaseModelStyle:String {
+    case base
+    case image
+    case video
+
+    func getModelClass() -> TSChatMessageUIBaseModel.Type {
+        switch self {
+        case .base:
+            return TSChatMessageUIBaseModel.self
+        case .image:
+            return TSChatMessageUIImageModel.self // 假设有一个 TSChatMessageUIImageModel 类
+        case .video:
+            return TSChatMessageVideoModel.self // 假设有一个 TSChatMessageVideoModel 类
+        }
+    }
+}
+
+
+class TSChatMessageUIBaseModel: TSBaseModel {
+    
+    weak var msgModel:TSChatMessage?
+    
+    var selfClass:String = "TSChatMessageUIBaseModel"
+    var viewClass:String = "TSChatMsgBaseView"
+    
+    
+    
+    lazy var view: TSChatMsgBaseView? = {
+        if let view = kGetTSChatMsgBaseView(uiBaseModel: self){
+//            view.updataView(uiBaseModel: self)
+            return view
+        }
+        return nil
+    }()
+    
+//    var view:TSChatMsgBaseView?{
+//        if let view = kGetTSChatMsgBaseView(uiBaseModel: self){
+//            view.updataView(uiBaseModel: self)
+//            return view
+//        }
+//        return nil
+//    }
+    
+    func getRecentDataView() -> TSChatMsgBaseView?{
+        updataView()
+        return view
+    }
+    
+    func updataView() {
+        view?.updataView(uiBaseModel: self)
+    }
+    
+    override func mapping(map: Map) {
+        selfClass       <- map["selfClass"]
+        viewClass       <- map["viewClass"]
+    }
+    
+}
+
+extension TSChatMessageUIBaseModel {
+    
+    static func creat(viewClass:String,msgModel:TSChatMessage)->TSChatMessageUIBaseModel{
+        let model = TSChatMessageUIBaseModel()
+        model.viewClass = viewClass
+        model.msgModel = msgModel
+        return model
+    }
+    
+    func creat(viewClass:String,msgModel:TSChatMessage)->TSChatMessageUIBaseModel{
+        let model = TSChatMessageUIBaseModel()
+        model.viewClass = viewClass
+        model.msgModel = msgModel
+        return model
+    }
+    
+}
+func kGetTSChatMessageUIBaseModel(jsonString:String,msgModel:TSChatMessage) -> TSChatMessageUIBaseModel? {
+    
+    if let jsonDict = jsonString.jsonDict(),
+        let selfClass = jsonDict["selfClass"] as? String,
+       let baseClass = selfClass.toClass() as? TSBaseModel.Type,
+       let baseObj = baseClass.init(json: jsonDict),
+       let uiModel = baseObj as? TSChatMessageUIBaseModel
+    {
+        uiModel.msgModel = msgModel
+        return uiModel
+    }
+    return nil
+}
+
+func kGetTSChatMsgBaseView(uiBaseModel:TSChatMessageUIBaseModel) -> TSChatMsgBaseView? {
+    
+    if let baseClass = uiBaseModel.viewClass.toClass() as? TSChatMsgBaseView.Type
+    {
+        let baseObj = baseClass.init()
+        baseObj.updataView(uiBaseModel: uiBaseModel)
+        return baseObj
+    }
+    return nil
+}
+
+
+class TSChatMessageUIImageModel: TSChatMessageUIBaseModel {
+    
+    
+}
+class TSChatMessageVideoModel: TSChatMessageUIBaseModel {
+    
+    
+}

+ 54 - 0
AIEmoji/Business/AIChat/TSChatViewController/Models/TSDBAIChatList.swift

@@ -132,6 +132,30 @@ extension TSDBAIChatList {
         
         dbModel.messageType = chatMsg.messageType.rawValue
         dbModel.markDownText = chatMsg.markDownText
+        
+        if let thinkingModel = chatMsg.thinkingModel,
+           let jsonStr = thinkingModel.toJSONString(){
+            dbModel.thinkingJson = jsonStr
+        }
+        
+        
+        if chatMsg.appendUIDict.count > 0 {
+            var appendUIDict:[String:String] = [:]
+            chatMsg.appendUIDict.forEach { key, value in
+                print("Key: \(key), Value: \(value)")
+                if let json = value.toJSONString(){
+                    appendUIDict[key.rawValue] = json
+                }
+            }
+            
+            if appendUIDict.count > 0 {
+                if let appendUIJson = appendUIDict.toJSONString() {
+                    dbModel.appendUIJson = appendUIJson
+                }
+            }
+        }
+
+
         return dbModel
     }
     
@@ -185,6 +209,8 @@ class TSDBChatMessage: Object {
     @objc dynamic var sendStateValue: String = ""
 
     @objc dynamic var markDownText: String = ""
+    @objc dynamic var thinkingJson: String = ""
+    @objc dynamic var appendUIJson: String = ""
     
     override static func primaryKey() -> String? {
         return "messageId"
@@ -202,6 +228,34 @@ class TSDBChatMessage: Object {
         model.messageType = TSChatMessageMsgType(rawValue: messageType) ?? .aiRobotResponse
         model.sendState = .fromKeyValue(key: sendStateKey, value: sendStateValue)
         model.markDownText = markDownText
+
+        if thinkingJson.count > 0 {
+            model.thinkingModel = TSChatThinkingModel(JSONString: thinkingJson)
+        }
+        
+        if appendUIJson.count > 0 {
+            if let jsonDict = appendUIJson.jsonDict(),
+               jsonDict.count > 0
+            {
+                var appendUIDict:[TSChatMessageAppendDictKey:TSChatMessageUIBaseModel] = [:]
+                jsonDict.forEach { key, value in
+                    if let dictKey = TSChatMessageAppendDictKey(rawValue: key),
+                       let modelJson = value as? String,
+                       let model = kGetTSChatMessageUIBaseModel(jsonString: modelJson, msgModel: model)
+                    {
+                        appendUIDict[dictKey] = model
+                    } else {
+                        print("Invalid raw value")
+                    }
+                }
+                
+                if appendUIDict.count > 0 {
+                    model.appendUIDict = appendUIDict
+                }
+            }
+        }
+        
+
         return model
     }
     

+ 11 - 3
AIEmoji/Business/AIChat/TSChatViewController/Models/TSLayoutSizeCalculator.swift

@@ -83,10 +83,18 @@ class TSLayoutSizeCalculator: MessageSizeCalculator {//CellSizeCalculator {
         
         if let msgModel = message as? TSChatMessage {
             //有ai机器人头部imageview
-            if let uiBaseModel = msgModel.appendDict[.topView] as? TSChatMessageUIBaseModel {
-                height+=uiBaseModel.height
+//            if let uiBaseModelJson = msgModel.appendUIDict[.topView],
+//               let uiBaseModel = kGetTSChatMessageUIBaseModel(jsonString: uiBaseModelJson,msgModel: msgModel),
+//               let view = uiBaseModel.view
+//            {
+//                height+=view.viewH
+//            }
+            if let uiBaseModel = msgModel.appendUIDict[.topView],
+               let modelView = uiBaseModel.getRecentDataView()
+            {
+                //dePrint("modelView.viewH Height =\(modelView.viewH)")
+                height+=modelView.viewH
             }
-
             
             
             let isLast = TSMessageContentCell.kIsChatLast(message: message, dataSource: messagesDataSource)

+ 10 - 2
AIEmoji/Business/AIChat/TSChatViewController/TSChatViewController/TSChatViewController+ChatDelegate.swift

@@ -237,10 +237,18 @@ extension TSChatViewController: MessageCellDelegate {
                 }
                 
                 if questionString.count > 0 {
-                    generativeAIChat(questionString: questionString,indexPath:indexPath)
+//                    generativeAIChat(questionString: questionString,indexPath:indexPath)
+                    generativeThinkingAIChat(questionString: questionString,indexPath:indexPath)
                 }
             }
-        
+        case .refreshCell:
+            UIView.performWithoutAnimation {
+                messagesCollectionView.reloadItems(at: [indexPath])
+            }
+        case .refreshColView:
+            messagesCollectionView.reloadData()
+        default:
+            break
         }
     }
 }

+ 3 - 3
AIEmoji/Business/AIChat/TSChatViewController/TSChatViewController/TSChatViewController+Keyboard.swift

@@ -45,14 +45,14 @@ extension TSChatViewController{
         let frameHeight = scrollView.frame.size.height
         // 判断是否需要显示滚动到底部的按钮
         let h = contentHeight - frameHeight + inputContainerView.frame.size.height - 60
-        debugPrint("scrollViewDidScroll offsetY=\(offsetY),contentHeight=\(contentHeight),frameHeight=\(frameHeight),h=\(h)")
+//        debugPrint("scrollViewDidScroll offsetY=\(offsetY),contentHeight=\(contentHeight),frameHeight=\(frameHeight),h=\(h)")
         
         if offsetY > h {
             scrollToBottomButton.isHidden = true
-            debugPrint("scrollViewDidScroll true")
+//            debugPrint("scrollViewDidScroll true")
         } else {
             scrollToBottomButton.isHidden = false
-            debugPrint("scrollViewDidScroll false")
+//            debugPrint("scrollViewDidScroll false")
         }
         
       

+ 95 - 11
AIEmoji/Business/AIChat/TSChatViewController/TSChatViewController/TSChatViewController+SendMsg.swift

@@ -53,7 +53,8 @@ extension TSChatViewController {
             return
         }
         
-        generativeAIChat(questionString: messageString, indexPath: indexPath)
+//        generativeAIChat(questionString: messageString, indexPath: indexPath)
+        generativeThinkingAIChat(questionString: messageString, indexPath: indexPath)
     }
     
     func generativeAIChat(questionString:String,indexPath:IndexPath? = nil) {
@@ -150,6 +151,99 @@ extension TSChatViewController {
 }
 
 
+
+let kIsAIAnswering = "isAIAnswering"
+let kIsStopAIRespond = "isStopAIRespond"
+public extension Notification.Name {
+    //AI 回答中通知
+    static let kAIAnsweringNotification = Self.init("kAIAnsweringNotification")
+    static let kAIStopRespondNotification = Self.init("kAIStopRespondNotification")
+}
+
+
+
+extension TSChatViewController{
+
+    func generativeThinkingAIChat(questionString:String,indexPath:IndexPath? = nil) {
+        
+        //先插入回答的消息,转圈加载
+        let message = TSChatMessage(attributedText: kMDAttributedString(text: ""), user: viewModel.kAIUser, messageId: UUID().uuidString, date: Date())
+        message.sendState = .start
+        message.messageType = .aiRobotResponse
+    
+        let thinkingModel = TSChatThinkingModel()
+        thinkingModel.startStamp = Int.timestampInt()
+        thinkingModel.thinkingName = "DeepSeek-R1"
+        thinkingModel.thinkingState = "Thinking..."
+        message.thinkingModel = thinkingModel
+        
+        let model = TSChatMessageUIBaseModel.creat(viewClass: "TSAIThinkingView", msgModel: message)
+        message.appendUIDict = [.topView:model]
+        
+        insertMessage(message,indexPath: indexPath)
+        
+        kDelayMainShort {
+    //            self.scrollToBottom()
+            self.scrollViewDidScroll(self.messagesCollectionView)
+        }
+        
+        
+        NotificationCenter.default.post(name: .kAIAnsweringNotification, object: nil, userInfo: [kIsAIAnswering: true])
+
+        viewModel.sendChatThinkingMessage(message: questionString) { [weak self] thinkingString,mdString in
+            guard let self = self else { return }
+            message.kind = .attributedText(kMDAttributedString(text: viewModel.AiMDString))
+            message.markDownText = viewModel.AiMDString
+            
+            
+            thinkingModel.thinkingString = viewModel.AiThinkingString
+            if viewModel.AiMDString.count > 0{
+                message.sendState = .progress(0.5)
+                if  thinkingModel.endStamp == 0{
+                    thinkingModel.endStamp = Int.timestampInt()
+                    let time = thinkingModel.endStamp - thinkingModel.startStamp
+                    thinkingModel.thinkingState = "Thought for \(time)s"
+                }
+            }
+            
+            if self.scrollToBottomButton.isHidden == true {
+                updataAIChatCellUI()
+                self.messagesCollectionView.scrollToLastItem(animated: false)
+            }
+        }completion: {[weak self] data, error in
+            guard let self = self else { return }
+            if let _ = data {
+                message.sendState = .success("netData")
+            }else {
+                message.sendState = .failed(kAIErrorString)
+                if viewModel.AiMDString.count == 0 {
+                    viewModel.AiMDString = kAIErrorString
+                    message.kind = .attributedText(kMDAttributedString(text: viewModel.AiMDString))
+                }
+            }
+            message.markDownText = viewModel.AiMDString
+            updataAIChatCellUI()
+            
+            kExecuteOnMainThread {
+                NotificationCenter.default.post(name: .kAIAnsweringNotification, object: nil, userInfo: [kIsAIAnswering: false])
+                if self.scrollToBottomButton.isHidden == true {
+                    self.scrollToBottom()
+                }
+            }
+        }
+    }
+
+
+}
+
+
+
+
+
+
+
+
+
 extension  TSChatViewController{
     
     func delayedOutputAnimation(message:TSChatMessage,previousStr:String,newAddStr:String, delay: TimeInterval = 0.07)  {
@@ -202,13 +296,3 @@ extension  TSChatViewController{
         typeCharacter(at: originalText.count)
     }
 }
-
-let kIsAIAnswering = "isAIAnswering"
-let kIsStopAIRespond = "isStopAIRespond"
-public extension Notification.Name {
-    //AI 回答中通知
-    static let kAIAnsweringNotification = Self.init("kAIAnsweringNotification")
-    static let kAIStopRespondNotification = Self.init("kAIStopRespondNotification")
-}
-
-

+ 5 - 0
AIEmoji/Business/AIChat/TSChatViewController/TSChatViewController/TSChatViewController.swift

@@ -96,6 +96,10 @@ class TSChatViewController: MessagesViewController, MessagesDataSource {
         }
     }
     
+    
+//    override func viewDidDisappear(_ animated: Bool) {
+//        saveChatList()
+//    }
     func loadFirstMessages() {
         self.messageList = viewModel.getHistoryChatMessage()
         self.messagesCollectionView.reloadData()
@@ -108,6 +112,7 @@ class TSChatViewController: MessagesViewController, MessagesDataSource {
         //设置自定义FlowLayout,itemsize等,都在这里控制
         let flowLayout = CustomMessagesFlowLayout()
         flowLayout.sectionInset = UIEdgeInsets(top: 4, left: 0, bottom: 4, right: 0)
+        flowLayout.minimumLineSpacing = 16
         messagesCollectionView.collectionViewLayout = flowLayout
         messagesCollectionView.backgroundColor = .clear
         messagesCollectionView.register(TSTextMessageContentCell.self)

+ 75 - 10
AIEmoji/Business/AIChat/TSChatViewController/ViewModel/TSAIChatVM.swift

@@ -29,7 +29,8 @@ class TSAIChatVM {
     
     //ai markDown 回答的string
     var AiMDString:String = ""
-    
+    // ai 思考的内容
+    var AiThinkingString:String = ""
     
     
     init() {
@@ -62,7 +63,7 @@ extension TSAIChatVM {
         ]
 
         AiMDString = ""
-        streamRequest = TSNetworkShared.postStream(urlType: .chatV2,parameters: parameters) {[weak self] string in
+        streamRequest = TSNetworkShared.postStream(urlType: .chat,parameters: parameters) {[weak self] string in
             guard let self = self else { return }
             
             if AiMDString.count == 0 {
@@ -89,12 +90,82 @@ extension TSAIChatVM {
             }
         }
     }
-    
     func stopAiGenerate () {
         streamRequest?.cancel()
     }
 }
 
+extension TSAIChatVM {
+    
+    func sendChatThinkingMessage(
+        message:String,
+        streamHandler:@escaping (String,String) -> Void,
+        completion: @escaping (Any?, Error?) -> Void
+    ) {
+        let parameters: [String: String] = [
+            "sessionId": dbAIChatList.sessionId,
+            "message": message
+        ]
+
+        AiMDString = ""
+        AiThinkingString = ""
+        streamRequest = TSNetworkShared.postStream(urlType: .chatV2,parameters: parameters) {[weak self] string in
+            guard let self = self else { return }
+
+//            if AiMDString.count == 0 {
+//                //{"code":500,"message":"Server Error"}
+//                //如果错误,基本都是第一条就返回结果了,这里需要做下 code 判断,来确定接口
+//                if let dataDict = string.jsonDict() , let code = dataDict["code"] {
+//                    completion(nil,NSError(domain: dataDict.safeString(forKey: "message"), code: 0))
+//                    return
+//                }
+//            }
+            
+            //{"type": "reason", "content": "思考"}\n{"type": "content", "content": "内容"}
+            let jsonLines = string.components(separatedBy: "\n")
+            for line in jsonLines {
+                if !line.isEmpty, let jsonData = line.data(using: .utf8) {
+                    do {
+                        let json = try JSONSerialization.jsonObject(with: jsonData, options: [])
+                        dePrint("Stream Received JSON:\(json)")
+                        
+                        guard let jsonDict = json as? [String:String] else {
+                            return
+                        }
+
+                        let type = jsonDict.safeString(forKey: "type")
+                        let content = jsonDict.safeString(forKey: "content")
+                        if type == "reason"{
+                            AiThinkingString = AiThinkingString + content
+                        }else if type == "content"{
+                            AiMDString = AiMDString + content
+                        }
+                        dePrint("streamHandler viewModel.AiThinkingString=\(AiThinkingString)")
+                        dePrint("streamHandler viewModel.AiMDString=\(AiMDString)")
+                        streamHandler(AiThinkingString,AiMDString)
+
+                    } catch {
+                        print("Stream Received JSON parsing error:", error)
+                    }
+                }
+            }
+
+        } completion: { result in
+            switch result {
+            case .success(let data):
+                completion(data,nil)
+            case .failure(let error):
+                if case Alamofire.AFError.explicitlyCancelled = error {//主动取消的
+                    completion("",nil)
+                } else {
+                    completion(nil,error)
+                }
+            }
+        }
+    }
+    
+}
+
 //MARK: 数据存储
 extension TSAIChatVM {
     
@@ -102,16 +173,10 @@ extension TSAIChatVM {
         if uiStyle == .history {
             return self.dbAIChatList.getMessageList()
         }else {
-//            let aiString = "I can tackle your questions, my skillset includes, but is not limited to:\n**📧 Composing high-quality emails**\n**🇺🇸 Facilitating language learning**\n**📑 Assisting in your studies**\n**💡Brainstorming ideas**\n**and much more!**"
             let aiString = "I can tackle your questions, my skillset includes, but is not limited to:\n`📧 Composing high-quality emails`\n`🇺🇸 Facilitating language learning`\n`📑 Assisting in your studies`\n`💡Brainstorming ideas`\n`and much more!`"
             let msg = TSChatMessage(kind: .attributedText(kMDAttributedString(text: aiString)), user: kAIUser, messageId: "", date: Date())
-
-            let model = TSChatMessageUIBaseModel()
-            model.height = 52.0
-            model.view = TSMSGAIDefaultHeaderView(text: "Greetings! Curious about\nwhat I can do?".localized)
-            msg.appendDict = [.topView:model]
             msg.messageType = .aiRobotWelcome
-            
+            msg.appendUIDict = [.topView:TSChatMessageUIBaseModel.creat(viewClass: "TSMSGAIDefaultHeaderView", msgModel: msg)]
             return [msg]
         }
     }

+ 0 - 7
AIEmoji/Business/AIChat/TSChatViewController/Views/TSCellView/Untitled.swift

@@ -1,7 +0,0 @@
-//
-//  Untitled.swift
-//  AIEmoji
-//
-//  Created by 100Years on 2025/2/25.
-//
-

+ 175 - 0
AIEmoji/Business/AIChat/TSChatViewController/Views/TSChatMsgBaseView/TSAIThinkingView.swift

@@ -0,0 +1,175 @@
+//
+//  TSAIThinkingView.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/3/12.
+//
+
+class TSAIThinkingView: TSChatMsgBaseView {
+ 
+    var isFold:Bool = false {
+        didSet{
+            self.textBgView.isHidden = isFold
+            arrowImageView.image = UIImage(named: isFold ? "chat_down_arrow" : "chat_up_arrow")
+            if isFold{
+                textBgView.snp.removeConstraints()
+            }else{
+                textBgView.snp.remakeConstraints { make in
+        //            make.top.equalTo(topView.snp.bottom).offset(12)
+                    make.top.equalTo(40)
+                    make.leading.equalTo(16)
+                    make.trailing.equalTo(-32)
+                    make.bottom.equalTo(-12)
+                }
+            }
+         
+            updateViewH()
+        }
+    }
+    lazy var aiIconImageView: UIImageView = {
+        let iconImageView = UIImageView.createImageView(imageName: "deepseek_icon")
+        return iconImageView
+    }()
+    
+    lazy var aiInfoLabel: UILabel = {
+        let aiInfoLabel = UILabel.createLabel(font: .font(size: 14), textColor: "#4D6BFE".uiColor, textAlignment: .left, numberOfLines: 1)
+        return aiInfoLabel
+    }()
+    
+    lazy var arrowImageView: UIImageView = {
+        let arrowImageView = UIImageView.createImageView(imageName: "chat_up_arrow")
+        return arrowImageView
+    }()
+    lazy var topView: UIView = {
+        let topView = UIView()
+        topView.backgroundColor = "#4D6BFE".uiColor.withAlphaComponent(0.1)
+        topView.cornerRadius = 14
+        topView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(clickTopView)))
+        topView.addSubview(aiIconImageView)
+        aiIconImageView.snp.makeConstraints { make in
+            make.leading.equalTo(12)
+            make.centerY.equalToSuperview()
+            make.width.height.equalTo(20)
+        }
+        
+        topView.addSubview(aiInfoLabel)
+        aiInfoLabel.snp.makeConstraints { make in
+            make.leading.equalTo(aiIconImageView.snp.trailing).offset(4)
+            make.centerY.equalToSuperview()
+        }
+
+        topView.addSubview(arrowImageView)
+        arrowImageView.snp.makeConstraints { make in
+            make.leading.equalTo(aiInfoLabel.snp.trailing).offset(8)
+            make.trailing.equalTo(-12)
+            make.centerY.equalToSuperview()
+            make.width.height.equalTo(16)
+        }
+        
+        return topView
+    }()
+    
+    
+    
+    lazy var textLabel: UILabel = {
+        let textLabel = UILabel()
+        textLabel.numberOfLines = 0
+        textLabel.font = .font(size: 14)
+        textLabel.textColor = .white.withAlphaComponent(0.5)
+        return textLabel
+    }()
+    
+    lazy var textBgView: UIView = {
+        let textBgView = UIView()
+        
+        let lineView = UIView()
+        lineView.backgroundColor = "#D8D8D8".uiColor.withAlphaComponent(0.2)
+        textBgView.addSubview(lineView)
+        lineView.snp.makeConstraints { make in
+            make.leading.equalTo(0)
+            make.bottom.equalTo(4)
+            make.top.equalTo(-4)
+            make.width.equalTo(1)
+        }
+        
+        textBgView.addSubview(textLabel)
+        textLabel.snp.makeConstraints { make in
+            make.trailing.top.equalTo(0)
+            make.leading.equalTo(12)
+        }
+        
+        return textBgView
+    }()
+    
+    override func creatUI() {
+        
+        contentView.addSubview(topView)
+        contentView.addSubview(textBgView)
+        
+        topView.snp.makeConstraints { make in
+            make.leading.equalTo(16)
+            make.top.equalTo(0)
+            make.height.equalTo(28)
+        }
+        
+        textBgView.snp.makeConstraints { make in
+//            make.top.equalTo(topView.snp.bottom).offset(12)
+            make.top.equalTo(40)
+            make.leading.equalTo(16)
+            make.trailing.equalTo(-32)
+            make.bottom.equalTo(-12)
+        }
+    }
+    
+    
+    @objc func clickTopView(){
+//        isFold = !isFold
+//        self.uiBaseModel?.msgModel?.thinkingFold = isFold
+        
+        if let isFold = self.uiBaseModel?.msgModel?.thinkingModel?.thinkingFold {
+            self.uiBaseModel?.msgModel?.thinkingModel?.thinkingFold = !isFold
+            self.isFold = !isFold
+            self.didTapCustomViewBlock?(.refreshCell)
+        }
+        
+        
+    }
+    
+    func setText(text:String){
+        textLabel.text = text
+        updateViewH()
+    }
+    
+    
+    func updateViewH(){
+        let topH:CGFloat = 28.0 + 12.0
+        if isFold {
+            viewH = topH
+            //dePrint("modelView.viewH text =\(textLabel.text)")
+            //dePrint("modelView.viewH viewH =\(viewH)")
+        }else {
+            let size = textLabel.sizeThatFits(CGSize(width: k_ScreenWidth - 60, height: .greatestFiniteMagnitude))
+            viewH = topH + size.height + 12.0
+            //dePrint("modelView.viewH text1 =\(textLabel.text)")
+            //dePrint("modelView.viewH viewH1 =\(viewH)")
+        }
+        
+//        self.frame = CGRect(x: 0, y: 0, width: k_ScreenWidth - 48, height: viewH)
+    }
+
+    
+    override func updataView(uiBaseModel: TSChatMessageUIBaseModel) {
+        self.uiBaseModel = uiBaseModel
+        guard let thinkingModel = uiBaseModel.msgModel?.thinkingModel else { return  }
+        
+       
+        aiIconImageView.image = UIImage(named: thinkingModel.thinkingIcon)
+        textLabel.text = thinkingModel.thinkingString
+        aiInfoLabel.text = "\(thinkingModel.thinkingName) \(thinkingModel.thinkingState) "
+        self.isFold = thinkingModel.thinkingFold
+        //dePrint("modelView.viewH text =\(textLabel.text)")
+    
+        
+     
+    }
+}

+ 29 - 14
AIEmoji/Business/AIChat/TSChatViewController/Views/TSCellView/TSChatMsgBaseView.swift → AIEmoji/Business/AIChat/TSChatViewController/Views/TSChatMsgBaseView/TSChatMsgBaseView.swift

@@ -5,25 +5,48 @@
 //  Created by 100Years on 2025/2/23.
 //
 
+import MessageKit
 
 
 
-import MessageKit
+
+enum TSChatMsgBaseViewStyle:String {
+    case base
+
+    func getModelClass() -> TSChatMsgBaseView.Type {
+        switch self {
+        case .base:
+            return TSChatMsgBaseView.self
+        }
+    }
+}
+
 class TSChatMsgBaseView: TSBaseView {
-//    open weak var messageCellDelegate: MessageCellDelegate?
-//    open weak var messageCollectionViewCell:MessageCollectionViewCell?
     var didTapCustomViewBlock:((TSChatMsgViewTapType)->Void)?
     open var indexPath:IndexPath?
-
+    open var viewH:CGFloat = 0.0
+    
+    
+    weak var uiBaseModel:TSChatMessageUIBaseModel?
+    
     override func creatUI() {
         
         
+    }
+    
+
+    func updataView(uiBaseModel:TSChatMessageUIBaseModel){
+  
     }
 }
+
+
 // 定义一个枚举作为字典的键
 public enum TSChatMsgViewTapType {
-    case copyMsg
-    case refreshMsg
+    case copyMsg    //复制ai 的消息
+    case refreshMsg //让ai重新回答
+    case refreshCell //刷新 cell
+    case refreshColView //刷新 collectview
 }
 public extension MessageCellDelegate {
 
@@ -31,11 +54,3 @@ public extension MessageCellDelegate {
         debugPrint("MessageCellDelegate extension didTapCustomView")
     }
 }
-
-
-//public protocol MessageCellDelegate: MessageLabelDelegate {
-//    
-//    
-//    
-//}
-

+ 1 - 0
AIEmoji/Business/AIChat/TSChatViewController/Views/TSCellView/TSChatMsgToolView.swift → AIEmoji/Business/AIChat/TSChatViewController/Views/TSChatMsgBaseView/TSChatMsgToolView.swift

@@ -53,6 +53,7 @@ class TSChatMsgToolView: TSChatMsgBaseView {
         contentView.addSubview(stackView)
         stackView.snp.makeConstraints { make in
             make.leading.equalTo(12)
+            make.trailing.equalTo(-12)
             make.top.equalTo(0)
             make.height.equalTo(20)
         }

+ 10 - 9
AIEmoji/Business/AIChat/TSChatViewController/Views/TSCellView/TSMSGAIDefaultHeaderView.swift → AIEmoji/Business/AIChat/TSChatViewController/Views/TSChatMsgBaseView/TSMSGAIDefaultHeaderView.swift

@@ -7,18 +7,19 @@
 
 class TSMSGAIDefaultHeaderView: TSChatMsgBaseView {
     
-    var text:String
-    init(text:String) {
-        self.text = text
-        super.init(frame: .zero)
-    }
+//    var text:String
+//    init(text:String) {
+//        self.text = text
+//        super.init(frame: .zero)
+//    }
     
-    @MainActor required init?(coder: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
-    }
+//    @MainActor required init?(coder: NSCoder) {
+//        fatalError("init(coder:) has not been implemented")
+//    }
 
     override func creatUI() {
-        let view = creatAIDefaultHeaderView(text: text)
+        viewH = 52.0
+        let view = creatAIDefaultHeaderView(text: "Greetings! Curious about\nwhat I can do?".localized)
         addSubview(view)
         view.snp.makeConstraints { make in
             make.edges.equalToSuperview()

+ 18 - 15
AIEmoji/Business/AIChat/TSChatViewController/Views/TSMessageContentCell.swift

@@ -29,14 +29,14 @@ class TSMessageContentCell: MessageCollectionViewCell {
     var topContainerView: UIView = {
         let containerView = UIView()
         containerView.clipsToBounds = true
-//        containerView.backgroundColor = .red
+//        containerView.backgroundColor = .red.withAlphaComponent(0.3)
         return containerView
     }()
     
     /// 中部内容
     var centerContainerView: UIView = {
         let containerView = UIView()
-//        containerView.backgroundColor = .yellow
+//        containerView.backgroundColor = .yellow.withAlphaComponent(0.3)
         return containerView
     }()
 
@@ -44,7 +44,7 @@ class TSMessageContentCell: MessageCollectionViewCell {
     /// 底部内容
     var bottomContainerView: UIView = {
         let containerView = UIView()
-//        containerView.backgroundColor = .blue
+//        containerView.backgroundColor = .blue.withAlphaComponent(0.3)
         return containerView
     }()
     
@@ -270,24 +270,27 @@ class TSMessageContentCell: MessageCollectionViewCell {
         delegate = messagesCollectionView.messageCellDelegate
         
         if let msgModel = message as? TSChatMessage {
-            if let uiBaseModel = msgModel.appendDict[.topView] as? TSChatMessageUIBaseModel {
-                let modelView = uiBaseModel.view
+            if let uiBaseModel = msgModel.appendUIDict[.topView],
+              let modelView = uiBaseModel.getRecentDataView(){
+                modelView.didTapCustomViewBlock = {[weak self] tapType in
+                    guard let self = self else { return }
+                    if let delegate = delegate{
+                        cellTapType = tapType
+                        delegate.didTapBackground(in: self)
+                    }
+                }
+                //dePrint("modelView.viewH cell =\(modelView.viewH)")
                 topContainerView.addSubview(modelView)
-                modelView.snp.makeConstraints { make in
-                    make.leading.trailing.top.bottom.equalTo(0)
-                    make.height.equalTo(uiBaseModel.height)
+                modelView.snp.remakeConstraints { make in
+                    make.leading.trailing.top.bottom.equalToSuperview()
+                    make.height.equalTo(modelView.viewH)
                 }
             }
         }
-        
-        
+
         handelMsgToolView(message: message, dataSource: dataSource)
     }
-    
-    
-    
-    
-    
+
     func handelMsgToolView(message: MessageType,dataSource: MessagesDataSource){
         if let msgModel = message as? TSChatMessage,let chatVC = dataSource as? TSChatViewController{
     

+ 7 - 1
AIEmoji/Business/General/TSBigIconBrowseVC/TSBigIconBrowseVC.swift

@@ -199,7 +199,13 @@ extension TSBigIconBrowseVC:UICollectionViewDataSource,UICollectionViewDelegate
         if let model = dataModelArray.safeObj(At: indexPath.item){
             cell.netWorkImageView.setAsyncImage(urlString: model.response.resultUrl,placeholder: kPlaceholderImage,contentMode: .scaleAspectFill)
             cell.vipImageView.isHidden = !model.response.vip
-            cell.textLabel.text = model.request.prompt
+            
+            if model.request.promptSort.count > 0 {
+                cell.textLabel.text = model.request.promptSort
+            }else{
+                cell.textLabel.text = model.request.prompt
+            }
+
         }
         return cell
     }

+ 1 - 0
AIEmoji/Business/TSTextGeneralPictureVC/TSTTPInputVC/TSTTPInputVC.swift

@@ -135,6 +135,7 @@ extension TSTTPInputVC {
         
         let gennerateVC = TSTextPicGennerateVC(aiText: viewModel.prompt) {[weak self] model in
             guard let self = self else { return }
+            model.request.promptSort = viewModel.promptText
             viewModel.saveModel(model: model)
             reloadUIBlock?()
         }

+ 3 - 3
AIEmoji/Common/TSRealmManager/TSRealmManager.swift

@@ -19,11 +19,11 @@ class TSRealmManager {
     private init() {
         /*设置新的版本号
          1.0 ->1
-         1.9 ->2
-         
+         1.9 ->2    //新增
+         2.1 ->3    //新增ai思考
          **/
    
-        let newSchemaVersion: UInt64 = 2
+        let newSchemaVersion: UInt64 = 3
         // 获取默认配置
         var config = Realm.Configuration.defaultConfiguration
         // 设置新版本号