feat(backend): Implement multi-take sequence differencing and text formatting utility
This commit is contained in:
@@ -2206,7 +2206,8 @@ class AppController:
|
|||||||
project_manager.branch_discussion(self.project, self.active_discussion, new_name, index)
|
project_manager.branch_discussion(self.project, self.active_discussion, new_name, index)
|
||||||
self._switch_discussion(new_name)
|
self._switch_discussion(new_name)
|
||||||
|
|
||||||
def _rename_discussion(self, old_name: str, new_name: str) -> None: disc_sec = self.project.get("discussion", {})
|
def _rename_discussion(self, old_name: str, new_name: str) -> None:
|
||||||
|
disc_sec = self.project.get("discussion", {})
|
||||||
discussions = disc_sec.get("discussions", {})
|
discussions = disc_sec.get("discussions", {})
|
||||||
if old_name not in discussions:
|
if old_name not in discussions:
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -2493,7 +2493,8 @@ def hello():
|
|||||||
break # Break from inner loop, clipper will re-step
|
break # Break from inner loop, clipper will re-step
|
||||||
imgui.same_line()
|
imgui.same_line()
|
||||||
if imgui.button("Branch"):
|
if imgui.button("Branch"):
|
||||||
self._branch_discussion(i) imgui.same_line()
|
self._branch_discussion(i)
|
||||||
|
imgui.same_line()
|
||||||
preview = entry["content"].replace("\\n", " ")[:60]
|
preview = entry["content"].replace("\\n", " ")[:60]
|
||||||
if len(entry["content"]) > 60: preview += "..."
|
if len(entry["content"]) > 60: preview += "..."
|
||||||
if not preview.strip() and entry.get("thinking_segments"):
|
if not preview.strip() and entry.get("thinking_segments"):
|
||||||
|
|||||||
42
src/synthesis_formatter.py
Normal file
42
src/synthesis_formatter.py
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
def format_takes_diff(takes: dict[str, list[dict]]) -> str:
|
||||||
|
if not takes:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
histories = list(takes.values())
|
||||||
|
if not histories:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
min_len = min(len(h) for h in histories)
|
||||||
|
common_prefix_len = 0
|
||||||
|
for i in range(min_len):
|
||||||
|
first_msg = histories[0][i]
|
||||||
|
if all(h[i] == first_msg for h in histories):
|
||||||
|
common_prefix_len += 1
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
shared_lines = []
|
||||||
|
for i in range(common_prefix_len):
|
||||||
|
msg = histories[0][i]
|
||||||
|
shared_lines.append(f"{msg.get('role', 'unknown')}: {msg.get('content', '')}")
|
||||||
|
|
||||||
|
shared_text = "=== Shared History ==="
|
||||||
|
if shared_lines:
|
||||||
|
shared_text += "\n" + "\n".join(shared_lines)
|
||||||
|
|
||||||
|
variation_lines = []
|
||||||
|
if len(takes) > 1:
|
||||||
|
for take_name, history in takes.items():
|
||||||
|
if len(history) > common_prefix_len:
|
||||||
|
variation_lines.append(f"[{take_name}]")
|
||||||
|
for i in range(common_prefix_len, len(history)):
|
||||||
|
msg = history[i]
|
||||||
|
variation_lines.append(f"{msg.get('role', 'unknown')}: {msg.get('content', '')}")
|
||||||
|
variation_lines.append("")
|
||||||
|
else:
|
||||||
|
# Single take case
|
||||||
|
pass
|
||||||
|
|
||||||
|
variations_text = "=== Variations ===\n" + "\n".join(variation_lines)
|
||||||
|
|
||||||
|
return shared_text + "\n\n" + variations_text
|
||||||
59
tests/test_synthesis_formatter.py
Normal file
59
tests/test_synthesis_formatter.py
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import pytest
|
||||||
|
from src.synthesis_formatter import format_takes_diff
|
||||||
|
|
||||||
|
def test_format_takes_diff_empty():
|
||||||
|
assert format_takes_diff({}) == ""
|
||||||
|
|
||||||
|
def test_format_takes_diff_single_take():
|
||||||
|
takes = {
|
||||||
|
"take1": [
|
||||||
|
{"role": "user", "content": "hello"},
|
||||||
|
{"role": "assistant", "content": "hi"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
expected = "=== Shared History ===\nuser: hello\nassistant: hi\n\n=== Variations ===\n"
|
||||||
|
assert format_takes_diff(takes) == expected
|
||||||
|
|
||||||
|
def test_format_takes_diff_common_prefix():
|
||||||
|
takes = {
|
||||||
|
"take1": [
|
||||||
|
{"role": "user", "content": "hello"},
|
||||||
|
{"role": "assistant", "content": "hi"},
|
||||||
|
{"role": "user", "content": "how are you?"},
|
||||||
|
{"role": "assistant", "content": "I am fine."}
|
||||||
|
],
|
||||||
|
"take2": [
|
||||||
|
{"role": "user", "content": "hello"},
|
||||||
|
{"role": "assistant", "content": "hi"},
|
||||||
|
{"role": "user", "content": "what is the time?"},
|
||||||
|
{"role": "assistant", "content": "It is noon."}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
expected = (
|
||||||
|
"=== Shared History ===\n"
|
||||||
|
"user: hello\n"
|
||||||
|
"assistant: hi\n\n"
|
||||||
|
"=== Variations ===\n"
|
||||||
|
"[take1]\n"
|
||||||
|
"user: how are you?\n"
|
||||||
|
"assistant: I am fine.\n\n"
|
||||||
|
"[take2]\n"
|
||||||
|
"user: what is the time?\n"
|
||||||
|
"assistant: It is noon.\n"
|
||||||
|
)
|
||||||
|
assert format_takes_diff(takes) == expected
|
||||||
|
|
||||||
|
def test_format_takes_diff_no_common_prefix():
|
||||||
|
takes = {
|
||||||
|
"take1": [{"role": "user", "content": "a"}],
|
||||||
|
"take2": [{"role": "user", "content": "b"}]
|
||||||
|
}
|
||||||
|
expected = (
|
||||||
|
"=== Shared History ===\n\n"
|
||||||
|
"=== Variations ===\n"
|
||||||
|
"[take1]\n"
|
||||||
|
"user: a\n\n"
|
||||||
|
"[take2]\n"
|
||||||
|
"user: b\n"
|
||||||
|
)
|
||||||
|
assert format_takes_diff(takes) == expected
|
||||||
Reference in New Issue
Block a user