处理流逝返回

处理粘贴
This commit is contained in:
2025-12-09 16:12:54 +08:00
parent 7b86b739eb
commit e39104c431
4 changed files with 106 additions and 17 deletions

View File

@@ -9,6 +9,13 @@
@interface KBStreamOverlayView ()
@property (nonatomic, strong) KBStreamTextView *textViewInternal;
@property (nonatomic, strong) UIButton *closeButton;
// &
@property (nonatomic, strong) NSMutableString *pendingText;
@property (nonatomic, strong) NSTimer *streamTimer;
@property (nonatomic, assign) NSInteger charsPerTick; //
// SSE done
@property (nonatomic, assign) BOOL streamDidReceiveDone;
@end
@implementation KBStreamOverlayView
@@ -34,6 +41,10 @@
make.height.mas_equalTo(28);
make.width.mas_greaterThanOrEqualTo(56);
}];
_pendingText = [NSMutableString string];
_charsPerTick = 2; // 1~2
_streamDidReceiveDone = NO;
}
return self;
}
@@ -67,13 +78,73 @@
- (void)appendChunk:(NSString *)text {
if (text.length == 0) return;
[self.textViewInternal appendStreamText:text];
if (![NSThread isMainThread]) {
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf appendChunk:text];
});
return;
}
[self.pendingText appendString:text];
[self startStreamTimerIfNeeded];
}
- (void)finish {
[self.textViewInternal finishStreaming];
- (void)startStreamTimerIfNeeded {
if (self.streamTimer) return;
self.streamTimer = [NSTimer scheduledTimerWithTimeInterval:0.02
target:self
selector:@selector(handleStreamTick)
userInfo:nil
repeats:YES];
}
- (void)stopStreamTimer {
[self.streamTimer invalidate];
self.streamTimer = nil;
}
- (void)handleStreamTick {
if (self.pendingText.length == 0) {
// done finish
if (self.streamDidReceiveDone) {
[self.textViewInternal finishStreaming];
}
[self stopStreamTimer];
return;
}
NSInteger len = MIN(self.charsPerTick, self.pendingText.length);
NSString *slice = [self.pendingText substringToIndex:len];
[self.pendingText deleteCharactersInRange:NSMakeRange(0, len)];
[self.textViewInternal appendStreamText:slice];
}
- (void)finish {
if (![NSThread isMainThread]) {
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf finish];
});
return;
}
//
self.streamDidReceiveDone = YES;
//
if (self.pendingText.length == 0) {
[self stopStreamTimer];
[self.textViewInternal finishStreaming];
}
// handleStreamTick pendingText
// pendingText == 0 streamDidReceiveDone == YES finishStreaming
}
- (KBStreamTextView *)textView { return self.textViewInternal; }
@end

View File

@@ -290,9 +290,10 @@
}
NSInteger resolvedCharacterId = (characterId > 0) ? characterId : 75;
NSString *message = seedTitle.length > 0 ? seedTitle : @"aliqua non cupidatat";
// message = [NSString stringWithFormat:@"%@%d",message,arc4random() % 10000];
NSDictionary *payload = @{
@"characterId": @(resolvedCharacterId),
@"message": @"dolore ea cillum"
@"message": message
};
NSLog(@"[KBFunction] request payload: %@", payload);
NSError *bodyError = nil;
@@ -399,13 +400,15 @@
- (NSString *)kb_normalizedLLMChunkString:(id)dataValue {
if (![dataValue isKindOfClass:[NSString class]]) { return @""; }
NSString *text = (NSString *)dataValue;
// 1. <SPLIT> "<SP" + "LIT>"
if (self.eventSourceSplitPrefix.length > 0) {
text = [self.eventSourceSplitPrefix stringByAppendingString:text ?: @""];
self.eventSourceSplitPrefix = nil;
}
text = [text stringByReplacingOccurrencesOfString:@"\r\n\t" withString:@"\t"];
text = [text stringByReplacingOccurrencesOfString:@"\n\t" withString:@"\t"];
text = [text stringByReplacingOccurrencesOfString:@"\r\t" withString:@"\t"];
if (text.length == 0) { return @""; }
// 2.
while (text.length > 0) {
unichar c0 = [text characterAtIndex:0];
if (c0 == '\n' || c0 == '\r') {
@@ -414,17 +417,24 @@
}
break;
}
text = [text stringByReplacingOccurrencesOfString:@"/t" withString:@"\t"];
text = [text stringByReplacingOccurrencesOfString:@"<SPLIT>" withString:@"\t"];
if (text.length == 0) { return @""; }
// 3. "<SPLIT"
NSString *suffix = [self kb_pendingSplitSuffixForString:text];
if (suffix.length > 0) {
self.eventSourceSplitPrefix = suffix;
text = [text substringToIndex:text.length - suffix.length];
}
text = [text stringByReplacingOccurrencesOfString:@"\t " withString:@"\t"];
if (text.length == 0) { return @""; }
// 4. <SPLIT> \t
text = [text stringByReplacingOccurrencesOfString:@"<SPLIT>" withString:@"\t"];
// /t UI
return text;
}
- (NSString *)kb_formattedSearchResultString:(id)dataValue {
// data
if (![dataValue isKindOfClass:[NSArray class]]) { return @""; }
@@ -570,12 +580,18 @@
// });
// return;
}
BOOL hasPasteText = ![self.pasteView.pasBtn.currentTitle isEqualToString:KBLocalized(@" Paste Ta's Words")];
// BOOL hasPasteText = (self.pasteView.pasBtn.imageView.image == nil);
if (!hasPasteText) {
[KBHUD showInfo:KBLocalized(@"Please copy the text first")];
return;
}
NSString *copyTitle = self.pasteView.pasBtn.currentTitle;
// 3)
[self.tagListView setLoading:YES atIndex:index];
self.loadingTagIndex = @(index);
self.loadingTagTitle = title ?: @"";
[self kb_startNetworkStreamingWithSeed:self.loadingTagTitle];
[self kb_startNetworkStreamingWithSeed:copyTitle];
return;
}
@@ -652,11 +668,11 @@ static void KBULDarwinCallback(CFNotificationCenterRef center, void *observer, C
}
// 1
UIInputViewController *ivc = KBFindInputViewController(self);
if (ivc) {
id<UITextDocumentProxy> proxy = ivc.textDocumentProxy;
[proxy insertText:text];
}
// UIInputViewController *ivc = KBFindInputViewController(self);
// if (ivc) {
// id<UITextDocumentProxy> proxy = ivc.textDocumentProxy;
// [proxy insertText:text];
// }
// 2便便
[self kb_updatePasteButtonWithDisplayText:text];

View File

@@ -262,3 +262,4 @@
"Change The Nickname" = "Change Nickname";
"Please Enter The Modified Nickname" = "Please enter the new nickname";
"Save" = "Save";
"Please copy the text first" = "Please copy the text first";

View File

@@ -259,3 +259,4 @@
"Change The Nickname" = "修改名称";
"Please Enter The Modified Nickname" = "请输入修改后的昵称";
"Save" = "保存";
"Please copy the text first" = "请先复制文本";