处理AI回复问题

This commit is contained in:
2025-12-05 21:54:10 +08:00
parent ca3ea0630e
commit 0a1c30f669
3 changed files with 102 additions and 24 deletions

View File

@@ -288,6 +288,13 @@ static NSUInteger kb_validUTF8PrefixLen(NSData *data) {
- (void)emitChunk:(NSString *)rawText {
if (rawText.length == 0) return;
// 便
if (self.loggingEnabled) {
NSLog(@"[KBStream] RAW chunk#%ld len=%lu text=\"%@\"",
(long)(self.emittedChunkCount + 1),
(unsigned long)rawText.length,
KBPrintableSnippet(rawText, 160));
}
NSString *text = rawText;
// 0) \r/\n "\n\t""\r\n\t""\r\t" "\t"
text = [text stringByReplacingOccurrencesOfString:@"\r\n\t" withString:@"\t"];

View File

@@ -51,7 +51,7 @@
del.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.35];
del.layer.cornerRadius = 14; del.layer.masksToBounds = YES;
del.titleLabel.font = [UIFont systemFontOfSize:13 weight:UIFontWeightSemibold];
[del setTitle:KBLocalized(@"Delete") forState:UIControlStateNormal];
[del setTitle:KBLocalized(@"common_back") forState:UIControlStateNormal];
[del setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[del addTarget:self action:@selector(onTapClose) forControlEvents:UIControlEventTouchUpInside];
_closeButton = del;

View File

@@ -16,6 +16,8 @@
@property (nonatomic, strong) UIScrollView *scrollView;
//
@property (nonatomic, strong) NSMutableArray<UILabel *> *labels;
// labels
@property (nonatomic, strong) NSMutableArray<NSString *> *segmentTexts;
//
@property (nonatomic, copy) NSString *buffer;
@@ -40,14 +42,12 @@
- (void)commonInit {
_delimiter = @"\t";
_labelFont = [UIFont systemFontOfSize:16.0];
if (@available(iOS 13.0, *)) {
_labelTextColor = [UIColor labelColor];
} else {
_labelTextColor = [UIColor blackColor];
}
// 使 #02BEAC
_labelTextColor = [UIColor colorWithRed:2.0/255.0 green:190.0/255.0 blue:172.0/255.0 alpha:1.0];
_contentHorizontalPadding = 12.0;
_interItemSpacing = 5.0; // 5pt
_labels = [NSMutableArray array];
_segmentTexts = [NSMutableArray array];
_buffer = @"";
_shouldTrimSegments = YES;
@@ -95,7 +95,9 @@ static inline NSString *KBTrimRight(NSString *s) {
if (self.delimiter.length == 0) {
[self ensureCurrentLabelExists];
self.buffer = [self.buffer stringByAppendingString:text];
self.labels.lastObject.text = self.buffer;
//
NSUInteger idx = (self.labels.count > 0) ? (self.labels.count - 1) : 0;
[self setContent:self.buffer forSegmentAtIndex:idx];
[self layoutLabelsForCurrentWidth];
[self scrollToBottomIfNeeded];
return;
@@ -109,23 +111,31 @@ static inline NSString *KBTrimRight(NSString *s) {
// 1)
self.buffer = [self.buffer stringByAppendingString:parts.firstObject ?: @""];
self.labels.lastObject.text = self.buffer; //
//
NSUInteger currentIndex = (self.labels.count > 0) ? (self.labels.count - 1) : 0;
[self setContent:self.buffer forSegmentAtIndex:currentIndex];
[self layoutLabelsForCurrentWidth];
// 2)
for (NSUInteger i = 1; i < parts.count; i++) {
// a)
UILabel *current = self.labels.lastObject;
if (self.shouldTrimSegments) { current.text = KBTrimRight(current.text ?: @""); }
NSString *currentText = (self.segmentTexts.count > currentIndex)
? (self.segmentTexts[currentIndex] ?: @"")
: (self.buffer ?: @"");
if (self.shouldTrimSegments) {
currentText = KBTrimRight(currentText ?: @"");
}
[self setContent:currentText forSegmentAtIndex:currentIndex];
[self layoutLabelsForCurrentWidth];
// b)
[self createEmptyLabelAsNewSegment];
currentIndex = (self.labels.count > 0) ? (self.labels.count - 1) : 0;
// c)
NSString *piece = parts[i];
self.buffer = piece ?: @"";
self.labels.lastObject.text = self.buffer;
NSString *piece = parts[i] ?: @"";
self.buffer = piece;
[self setContent:self.buffer forSegmentAtIndex:currentIndex];
[self layoutLabelsForCurrentWidth];
}
@@ -137,6 +147,7 @@ static inline NSString *KBTrimRight(NSString *s) {
[lbl removeFromSuperview];
}
[self.labels removeAllObjects];
[self.segmentTexts removeAllObjects];
self.buffer = @"";
self.scrollView.contentSize = CGSizeMake(self.bounds.size.width, 0);
}
@@ -151,7 +162,9 @@ static inline NSString *KBTrimRight(NSString *s) {
label.font = self.labelFont;
label.textColor = self.labelTextColor;
label.userInteractionEnabled = YES; //
label.text = text;
NSUInteger idx = self.labels.count;
NSString *content = text ?: @"";
label.text = [self displayTextForSegmentIndex:idx content:content];
//
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleLabelTap:)];
@@ -159,6 +172,13 @@ static inline NSString *KBTrimRight(NSString *s) {
[self.scrollView addSubview:label];
[self.labels addObject:label];
// labels
if (self.segmentTexts.count <= idx) {
while (self.segmentTexts.count < idx) { [self.segmentTexts addObject:@""]; }
[self.segmentTexts addObject:content];
} else {
self.segmentTexts[idx] = content;
}
//
[self layoutLabelsForCurrentWidth];
@@ -182,12 +202,21 @@ static inline NSString *KBTrimRight(NSString *s) {
label.font = self.labelFont;
label.textColor = self.labelTextColor;
label.userInteractionEnabled = YES;
label.text = @"";
NSUInteger idx = self.labels.count;
// 1:
label.text = [self displayTextForSegmentIndex:idx content:@""];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleLabelTap:)];
[label addGestureRecognizer:tap];
[self.scrollView addSubview:label];
[self.labels addObject:label];
// segmentTexts labels
if (self.segmentTexts.count <= idx) {
while (self.segmentTexts.count < idx) { [self.segmentTexts addObject:@""]; }
[self.segmentTexts addObject:@""];
} else {
self.segmentTexts[idx] = @"";
}
self.buffer = @"";
[self layoutLabelsForCurrentWidth];
@@ -201,13 +230,16 @@ static inline NSString *KBTrimRight(NSString *s) {
});
return;
}
UILabel *current = self.labels.lastObject;
if (!current) { return; }
if (self.labels.count == 0) { return; }
NSUInteger idx = self.labels.count - 1;
NSString *content = (self.segmentTexts.count > idx)
? (self.segmentTexts[idx] ?: @"")
: (self.buffer ?: @"");
if (self.shouldTrimSegments) {
NSString *trimmed = KBTrimRight(current.text ?: @"");
current.text = trimmed;
self.buffer = trimmed;
content = KBTrimRight(content ?: @"");
}
[self setContent:content forSegmentAtIndex:idx];
self.buffer = content;
//
[self layoutLabelsForCurrentWidth];
[self scrollToBottomIfNeeded];
@@ -271,9 +303,12 @@ static inline NSString *KBTrimRight(NSString *s) {
UILabel *label = (UILabel *)tap.view;
if (![label isKindOfClass:[UILabel class]]) { return; }
NSInteger index = [self.labels indexOfObject:label];
NSString *text = label.text ?: @"";
// 宿使
NSString *rawText = (index != NSNotFound && index < (NSInteger)self.segmentTexts.count)
? (self.segmentTexts[(NSUInteger)index] ?: @"")
: (label.text ?: @"");
if (index != NSNotFound && self.onLabelTap) {
self.onLabelTap(index, text);
self.onLabelTap(index, rawText);
}
// 宿/TextView
@@ -281,10 +316,46 @@ static inline NSString *KBTrimRight(NSString *s) {
UIInputViewController *ivc = KBFindInputViewController(self);
if (ivc) {
id<UITextDocumentProxy> proxy = ivc.textDocumentProxy;
if (text.length > 0 && [proxy conformsToProtocol:@protocol(UITextDocumentProxy)]) {
[proxy insertText:text];
if (rawText.length > 0 && [proxy conformsToProtocol:@protocol(UITextDocumentProxy)]) {
[proxy insertText:rawText];
}
}
}
#pragma mark - Segment Helpers
// 1
- (NSString *)displayTextForSegmentIndex:(NSUInteger)index content:(NSString *)content {
NSInteger displayIndex = (NSInteger)index + 1;
//
NSString *body = content ?: @"";
body = [body stringByReplacingOccurrencesOfString:@"\r\n" withString:@"\n"];
//
while ([body containsString:@"\n\n"]) {
body = [body stringByReplacingOccurrencesOfString:@"\n\n" withString:@"\n"];
}
//
body = [body stringByReplacingOccurrencesOfString:@"\n" withString:@" "];
if (body.length > 0) {
return [NSString stringWithFormat:@"%ld: %@", (long)displayIndex, body];
} else {
return [NSString stringWithFormat:@"%ld: ", (long)displayIndex];
}
}
// label
- (void)setContent:(NSString *)content forSegmentAtIndex:(NSUInteger)idx {
if (idx >= self.labels.count) { return; }
NSString *body = content ?: @"";
if (self.segmentTexts.count <= idx) {
while (self.segmentTexts.count < idx) { [self.segmentTexts addObject:@""]; }
[self.segmentTexts addObject:body];
} else {
self.segmentTexts[idx] = body;
}
UILabel *label = self.labels[idx];
label.text = [self displayTextForSegmentIndex:idx content:body];
}
@end