This commit is contained in:
2026-01-26 20:36:51 +08:00
parent 3a5a6395af
commit e8b4b2c58a
7 changed files with 338 additions and 170 deletions

View File

@@ -13,7 +13,7 @@
#import <Masonry/Masonry.h>
#import <SDWebImage/SDWebImage.h>
@interface KBPersonaChatCell () <UITableViewDelegate, UITableViewDataSource>
@interface KBPersonaChatCell () <KBChatTableViewDelegate>
///
@property (nonatomic, strong) UIImageView *backgroundImageView;
@@ -28,7 +28,7 @@
@property (nonatomic, strong) UILabel *openingLabel;
///
@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, strong) KBChatTableView *chatView;
///
@property (nonatomic, strong) NSMutableArray<KBAiChatMessage *> *messages;
@@ -102,8 +102,8 @@
}];
//
[self.contentView addSubview:self.tableView];
[self.tableView mas_makeConstraints:^(MASConstraintMaker *make) {
[self.contentView addSubview:self.chatView];
[self.chatView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.openingLabel.mas_bottom).offset(30);
make.left.right.bottom.equalTo(self.contentView);
}];
@@ -130,7 +130,7 @@
self.nameLabel.text = persona.name;
self.openingLabel.text = persona.shortDesc.length > 0 ? persona.shortDesc : persona.introText;
[self.tableView reloadData];
[self.chatView clearMessages];
}
#pragma mark - 2
@@ -145,11 +145,16 @@
- (void)loadChatHistory {
if (self.isLoading || !self.hasMoreHistory) {
[self.chatView endLoadMoreWithHasMoreData:self.hasMoreHistory];
return;
}
self.isLoading = YES;
if (self.currentPage == 1) {
[self.chatView resetNoMoreData];
}
// 使 persona.personaId companionId
NSInteger companionId = self.persona.personaId;
@@ -162,6 +167,7 @@
if (error) {
NSLog(@"[KBPersonaChatCell] 加载聊天记录失败:%@", error.localizedDescription);
[weakSelf.chatView endLoadMoreWithHasMoreData:weakSelf.hasMoreHistory];
//
if (weakSelf.currentPage == 1 && weakSelf.persona.introText.length > 0) {
@@ -177,12 +183,24 @@
NSMutableArray *newMessages = [NSMutableArray array];
for (KBChatHistoryModel *item in pageModel.records) {
KBAiChatMessage *message;
if (item.isUserMessage) {
// sender
// sender = 1:
// sender = 2: AI
if (item.sender == KBChatSenderUser) {
//
message = [KBAiChatMessage userMessageWithText:item.content];
} else if (item.sender == KBChatSenderAssistant) {
// AI
message = [KBAiChatMessage assistantMessageWithText:item.content];
} else {
// AI
NSLog(@"[KBPersonaChatCell] 未知的 sender 类型:%ld", (long)item.sender);
message = [KBAiChatMessage assistantMessageWithText:item.content];
}
message.isComplete = YES;
message.needsTypewriterEffect = NO;
[newMessages addObject:message];
}
@@ -198,24 +216,12 @@
// UI
dispatch_async(dispatch_get_main_queue(), ^{
if (weakSelf.currentPage == 1) {
[weakSelf.tableView reloadData];
//
if (weakSelf.messages.count > 0) {
NSIndexPath *lastIndexPath = [NSIndexPath indexPathForRow:weakSelf.messages.count - 1 inSection:0];
[weakSelf.tableView scrollToRowAtIndexPath:lastIndexPath
atScrollPosition:UITableViewScrollPositionBottom
animated:NO];
}
} else {
//
CGFloat oldContentHeight = weakSelf.tableView.contentSize.height;
[weakSelf.tableView reloadData];
CGFloat newContentHeight = weakSelf.tableView.contentSize.height;
CGFloat offsetY = newContentHeight - oldContentHeight;
[weakSelf.tableView setContentOffset:CGPointMake(0, offsetY) animated:NO];
}
BOOL keepOffset = (weakSelf.currentPage != 1);
BOOL scrollToBottom = (weakSelf.currentPage == 1);
[weakSelf.chatView reloadWithMessages:weakSelf.messages
keepOffset:keepOffset
scrollToBottom:scrollToBottom];
[weakSelf.chatView endLoadMoreWithHasMoreData:weakSelf.hasMoreHistory];
});
NSLog(@"[KBPersonaChatCell] 加载成功:第 %ld 页,%ld 条消息,还有更多:%@",
@@ -227,6 +233,7 @@
- (void)loadMoreHistory {
if (!self.hasMoreHistory || self.isLoading) {
[self.chatView endLoadMoreWithHasMoreData:self.hasMoreHistory];
return;
}
@@ -238,41 +245,53 @@
//
KBAiChatMessage *openingMsg = [KBAiChatMessage assistantMessageWithText:self.persona.introText];
openingMsg.isComplete = YES;
openingMsg.needsTypewriterEffect = NO;
[self.messages addObject:openingMsg];
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
[self.chatView reloadWithMessages:self.messages
keepOffset:NO
scrollToBottom:YES];
});
}
#pragma mark - UITableViewDataSource
#pragma mark - 3
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.messages.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"];
cell.backgroundColor = [UIColor clearColor];
cell.textLabel.textColor = [UIColor whiteColor];
cell.textLabel.numberOfLines = 0;
- (void)appendUserMessage:(NSString *)text {
if (text.length == 0) {
return;
}
KBAiChatMessage *message = self.messages[indexPath.row];
cell.textLabel.text = message.text;
if (!self.messages) {
self.messages = [NSMutableArray array];
}
return cell;
KBAiChatMessage *message = [KBAiChatMessage userMessageWithText:text];
[self.messages addObject:message];
[self.chatView addMessage:message autoScroll:YES];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewAutomaticDimension;
- (void)appendAssistantMessage:(NSString *)text
audioId:(NSString *)audioId {
if (text.length == 0) {
return;
}
if (!self.messages) {
self.messages = [NSMutableArray array];
}
KBAiChatMessage *message = [KBAiChatMessage assistantMessageWithText:text
audioId:audioId];
message.needsTypewriterEffect = YES;
[self.messages addObject:message];
[self.chatView addMessage:message autoScroll:YES];
}
#pragma mark - UIScrollViewDelegate
#pragma mark - KBChatTableViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
- (void)chatTableViewDidScroll:(KBChatTableView *)chatView
scrollView:(UIScrollView *)scrollView {
CGFloat offsetY = scrollView.contentOffset.y;
//
@@ -281,6 +300,10 @@
}
}
- (void)chatTableViewDidTriggerLoadMore:(KBChatTableView *)chatView {
[self loadMoreHistory];
}
#pragma mark - Lazy Load
- (UIImageView *)backgroundImageView {
@@ -325,22 +348,13 @@
return _openingLabel;
}
- (UITableView *)tableView {
if (!_tableView) {
_tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
_tableView.delegate = self;
_tableView.dataSource = self;
_tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
_tableView.backgroundColor = [UIColor clearColor];
_tableView.showsVerticalScrollIndicator = NO;
_tableView.estimatedRowHeight = 60;
_tableView.rowHeight = UITableViewAutomaticDimension;
if (@available(iOS 11.0, *)) {
_tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}
- (KBChatTableView *)chatView {
if (!_chatView) {
_chatView = [[KBChatTableView alloc] init];
_chatView.backgroundColor = [UIColor clearColor];
_chatView.delegate = self;
}
return _tableView;
return _chatView;
}
@end