From 3247cced95546b1866868e9fc5abd8a9aedea50c Mon Sep 17 00:00:00 2001 From: Mykeehu Date: Sat, 3 May 2025 22:22:30 +0200 Subject: [PATCH 1/5] Fix re-translate when use Continue or Start reply with functions. Please check the changes! This will improve the re-translation of texts when using the Continue button or the Start reply with field. --- modules/chat.py | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/modules/chat.py b/modules/chat.py index 98913d5c..30b42a01 100644 --- a/modules/chat.py +++ b/modules/chat.py @@ -391,6 +391,10 @@ def chatbot_wrapper(text, state, regenerate=False, _continue=False, loading_mess # Generate reply = None for j, reply in enumerate(generate_reply(prompt, state, stopping_strings=stopping_strings, is_chat=True, for_ui=for_ui)): + # Handle start_with text (add it only once at the beginning) + if state.get('start_with', '') and j == 0 and not _continue and not regenerate: + reply = state['start_with'] + " " + reply + state['start_with'] = '' # Clear it after using # Extract the reply if state['mode'] in ['chat', 'chat-instruct']: @@ -409,20 +413,33 @@ def chatbot_wrapper(text, state, regenerate=False, _continue=False, loading_mess return if _continue: - output['internal'][-1] = [text, last_reply[0] + reply] - output['visible'][-1] = [visible_text, last_reply[1] + visible_reply] + # For continuation, we need to separate the already translated part from the new generated text + original_translated = output['visible'][-1][1] # Already translated part + new_content = reply[len(output['internal'][-1][1]):] if reply.startswith(output['internal'][-1][1]) else reply + new_content = new_content.lstrip() + + # Only send the new content for translation + translated_new_content = apply_extensions('output', new_content, state, is_chat=True) + + # Combine with the existing translation + full_translated = original_translated + " " + translated_new_content + + output['internal'][-1] = [text, reply.lstrip(' ')] + output['visible'][-1] = [visible_text, full_translated] if is_stream: yield output elif not (j == 0 and visible_reply.strip() == ''): output['internal'][-1] = [text, reply.lstrip(' ')] - output['visible'][-1] = [visible_text, visible_reply.lstrip(' ')] + output['visible'][-1] = [visible_text, apply_extensions('output', visible_reply.lstrip(' '), state, is_chat=True)] if is_stream: yield output if output['visible'][-1][1].endswith('▍'): output['visible'][-1][1] = output['visible'][-1][1][:-1] - output['visible'][-1][1] = apply_extensions('output', output['visible'][-1][1], state, is_chat=True) + # No need to apply extensions here for _continue case as we already handled it + if not _continue: + output['visible'][-1][1] = apply_extensions('output', output['visible'][-1][1], state, is_chat=True) yield output From 8e58b81f8de314e21afab50a15419e0993219e5d Mon Sep 17 00:00:00 2001 From: Mykeehu Date: Sat, 3 May 2025 22:33:54 +0200 Subject: [PATCH 2/5] Update chat.py with english save --- modules/chat.py | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/modules/chat.py b/modules/chat.py index 30b42a01..b31e8f20 100644 --- a/modules/chat.py +++ b/modules/chat.py @@ -391,9 +391,13 @@ def chatbot_wrapper(text, state, regenerate=False, _continue=False, loading_mess # Generate reply = None for j, reply in enumerate(generate_reply(prompt, state, stopping_strings=stopping_strings, is_chat=True, for_ui=for_ui)): - # Handle start_with text (add it only once at the beginning) + # Handle start_with text (add to both internal and visible) if state.get('start_with', '') and j == 0 and not _continue and not regenerate: - reply = state['start_with'] + " " + reply + start_text = state['start_with'] + # Add to internal (English) version + reply = start_text + " " + reply + # Add to visible (translated) version + translated_start = apply_extensions('output', start_text, state, is_chat=True) state['start_with'] = '' # Clear it after using # Extract the reply @@ -413,33 +417,41 @@ def chatbot_wrapper(text, state, regenerate=False, _continue=False, loading_mess return if _continue: - # For continuation, we need to separate the already translated part from the new generated text - original_translated = output['visible'][-1][1] # Already translated part - new_content = reply[len(output['internal'][-1][1]):] if reply.startswith(output['internal'][-1][1]) else reply + # Separate already existing content from new content + original_internal = output['internal'][-1][1] + original_visible = output['visible'][-1][1] + + # Get only the new generated part + new_content = reply[len(original_internal):] if reply.startswith(original_internal) else reply new_content = new_content.lstrip() - # Only send the new content for translation - translated_new_content = apply_extensions('output', new_content, state, is_chat=True) + # Translate only the new part + translated_new = apply_extensions('output', new_content, state, is_chat=True) - # Combine with the existing translation - full_translated = original_translated + " " + translated_new_content + # Update both internal and visible versions + updated_internal = original_internal + " " + new_content + updated_visible = original_visible + " " + translated_new + + output['internal'][-1] = [text, updated_internal] + output['visible'][-1] = [visible_text, updated_visible] - output['internal'][-1] = [text, reply.lstrip(' ')] - output['visible'][-1] = [visible_text, full_translated] if is_stream: yield output elif not (j == 0 and visible_reply.strip() == ''): + # For normal generation, translate the whole reply + translated_reply = apply_extensions('output', visible_reply.lstrip(' '), state, is_chat=True) output['internal'][-1] = [text, reply.lstrip(' ')] - output['visible'][-1] = [visible_text, apply_extensions('output', visible_reply.lstrip(' '), state, is_chat=True)] + output['visible'][-1] = [visible_text, translated_reply] if is_stream: yield output if output['visible'][-1][1].endswith('▍'): output['visible'][-1][1] = output['visible'][-1][1][:-1] - # No need to apply extensions here for _continue case as we already handled it + # Final translation if not in continue mode if not _continue: output['visible'][-1][1] = apply_extensions('output', output['visible'][-1][1], state, is_chat=True) + yield output From 4726516c571f789e5a5e5473e0d7231db9cc9597 Mon Sep 17 00:00:00 2001 From: Mykeehu Date: Sat, 3 May 2025 23:00:35 +0200 Subject: [PATCH 3/5] Fixed duplicated translate at end --- modules/chat.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/modules/chat.py b/modules/chat.py index b31e8f20..97ffe4a6 100644 --- a/modules/chat.py +++ b/modules/chat.py @@ -447,10 +447,6 @@ def chatbot_wrapper(text, state, regenerate=False, _continue=False, loading_mess if output['visible'][-1][1].endswith('▍'): output['visible'][-1][1] = output['visible'][-1][1][:-1] - - # Final translation if not in continue mode - if not _continue: - output['visible'][-1][1] = apply_extensions('output', output['visible'][-1][1], state, is_chat=True) yield output From 6da5612fd85149e4c32234981a36965d144f8a09 Mon Sep 17 00:00:00 2001 From: Mykeehu Date: Wed, 4 Jun 2025 08:44:45 +0200 Subject: [PATCH 4/5] Update chat.py for 3.4.0 version --- modules/chat.py | 102 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 80 insertions(+), 22 deletions(-) diff --git a/modules/chat.py b/modules/chat.py index 97ffe4a6..4becb7f5 100644 --- a/modules/chat.py +++ b/modules/chat.py @@ -337,57 +337,103 @@ def get_stopping_strings(state): def chatbot_wrapper(text, state, regenerate=False, _continue=False, loading_message=True, for_ui=False): + # Handle dict format with text and files + files = [] + if isinstance(text, dict): + files = text.get('files', []) + text = text.get('text', '') + history = state['history'] output = copy.deepcopy(history) output = apply_extensions('history', output) state = apply_extensions('state', state) + # Initialize metadata if not present + if 'metadata' not in output: + output['metadata'] = {} + visible_text = None stopping_strings = get_stopping_strings(state) is_stream = state['stream'] - # Prepare the input if not (regenerate or _continue): visible_text = html.escape(text) + # Process file attachments and store in metadata + row_idx = len(output['internal']) + + # Add attachments to metadata only, not modifying the message text + for file_path in files: + add_message_attachment(output, row_idx, file_path, is_user=True) + + # Add web search results as attachments if enabled + if state.get('enable_web_search', False): + search_query = generate_search_query(text, state) + add_web_search_attachments(output, row_idx, text, search_query, state) + # Apply extensions text, visible_text = apply_extensions('chat_input', text, visible_text, state) text = apply_extensions('input', text, state, is_chat=True) - output['internal'].append([text, '']) output['visible'].append([visible_text, '']) + # Add metadata with timestamp + update_message_metadata(output['metadata'], "user", row_idx, timestamp=get_current_timestamp()) # *Is typing...* if loading_message: yield { 'visible': output['visible'][:-1] + [[output['visible'][-1][0], shared.processing_message]], - 'internal': output['internal'] + 'internal': output['internal'], + 'metadata': output['metadata'] } else: text, visible_text = output['internal'][-1][0], output['visible'][-1][0] if regenerate: + row_idx = len(output['internal']) - 1 + + # Store the old response as a version before regenerating + if not output['metadata'].get(f"assistant_{row_idx}", {}).get('versions'): + add_message_version(output, "assistant", row_idx, is_current=False) + + # Add new empty version (will be filled during streaming) + key = f"assistant_{row_idx}" + output['metadata'][key]["versions"].append({ + "content": "", + "visible_content": "", + "timestamp": get_current_timestamp() + }) + output['metadata'][key]["current_version_index"] = len(output['metadata'][key]["versions"]) - 1 + if loading_message: yield { 'visible': output['visible'][:-1] + [[visible_text, shared.processing_message]], - 'internal': output['internal'][:-1] + [[text, '']] + 'internal': output['internal'][:-1] + [[text, '']], + 'metadata': output['metadata'] } elif _continue: last_reply = [output['internal'][-1][1], output['visible'][-1][1]] if loading_message: yield { 'visible': output['visible'][:-1] + [[visible_text, last_reply[1] + '...']], - 'internal': output['internal'] + 'internal': output['internal'], + 'metadata': output['metadata'] } - # Generate the prompt kwargs = { '_continue': _continue, - 'history': output if _continue else {k: v[:-1] for k, v in output.items()} + 'history': output if _continue else { + k: (v[:-1] if k in ['internal', 'visible'] else v) + for k, v in output.items() + } } prompt = apply_extensions('custom_generate_chat_prompt', text, state, **kwargs) if prompt is None: prompt = generate_chat_prompt(text, state, **kwargs) + # Add timestamp for assistant's response at the start of generation + row_idx = len(output['internal']) - 1 + update_message_metadata(output['metadata'], "assistant", row_idx, timestamp=get_current_timestamp()) + # Generate reply = None for j, reply in enumerate(generate_reply(prompt, state, stopping_strings=stopping_strings, is_chat=True, for_ui=for_ui)): @@ -402,16 +448,11 @@ def chatbot_wrapper(text, state, regenerate=False, _continue=False, loading_mess # Extract the reply if state['mode'] in ['chat', 'chat-instruct']: - visible_reply = re.sub("(||{{user}})", state['name1'], reply + '▍') + visible_reply = re.sub("(||{{user}})", state['name1'], reply) else: - visible_reply = reply + '▍' - + visible_reply = reply visible_reply = html.escape(visible_reply) - if shared.stop_everything: - if output['visible'][-1][1].endswith('▍'): - output['visible'][-1][1] = output['visible'][-1][1][:-1] - output['visible'][-1][1] = apply_extensions('output', output['visible'][-1][1], state, is_chat=True) yield output return @@ -420,21 +461,21 @@ def chatbot_wrapper(text, state, regenerate=False, _continue=False, loading_mess # Separate already existing content from new content original_internal = output['internal'][-1][1] original_visible = output['visible'][-1][1] - + # Get only the new generated part new_content = reply[len(original_internal):] if reply.startswith(original_internal) else reply new_content = new_content.lstrip() - + # Translate only the new part translated_new = apply_extensions('output', new_content, state, is_chat=True) - + # Update both internal and visible versions updated_internal = original_internal + " " + new_content updated_visible = original_visible + " " + translated_new - + output['internal'][-1] = [text, updated_internal] output['visible'][-1] = [visible_text, updated_visible] - + if is_stream: yield output elif not (j == 0 and visible_reply.strip() == ''): @@ -442,12 +483,29 @@ def chatbot_wrapper(text, state, regenerate=False, _continue=False, loading_mess translated_reply = apply_extensions('output', visible_reply.lstrip(' '), state, is_chat=True) output['internal'][-1] = [text, reply.lstrip(' ')] output['visible'][-1] = [visible_text, translated_reply] + + # Keep version metadata in sync during streaming (for regeneration) + if regenerate: + row_idx = len(output['internal']) - 1 + key = f"assistant_{row_idx}" + current_idx = output['metadata'][key]['current_version_index'] + output['metadata'][key]['versions'][current_idx].update({ + 'content': output['internal'][row_idx][1], + 'visible_content': output['visible'][row_idx][1] + }) if is_stream: yield output - if output['visible'][-1][1].endswith('▍'): - output['visible'][-1][1] = output['visible'][-1][1][:-1] - + # Final sync for version metadata (in case streaming was disabled) + if regenerate: + row_idx = len(output['internal']) - 1 + key = f"assistant_{row_idx}" + current_idx = output['metadata'][key]['current_version_index'] + output['metadata'][key]['versions'][current_idx].update({ + 'content': output['internal'][row_idx][1], + 'visible_content': output['visible'][row_idx][1] + }) + yield output From 72264b5bacc600d6f49a991c0a8a48271ea66c85 Mon Sep 17 00:00:00 2001 From: Mykeehu Date: Wed, 4 Jun 2025 11:56:39 +0200 Subject: [PATCH 5/5] Continue with metadata --- modules/chat.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/modules/chat.py b/modules/chat.py index 2db72f36..408555b4 100644 --- a/modules/chat.py +++ b/modules/chat.py @@ -698,6 +698,14 @@ def chatbot_wrapper(text, state, regenerate=False, _continue=False, loading_mess output['internal'][-1] = [text, updated_internal] output['visible'][-1] = [visible_text, updated_visible] + + row_idx = len(output['internal']) - 1 + key = f"assistant_{row_idx}" + current_idx = output['metadata'][key]['current_version_index'] + output['metadata'][key]['versions'][current_idx].update({ + 'content': output['internal'][row_idx][1], + 'visible_content': output['visible'][row_idx][1] + }) if is_stream: yield output