Repository navigation
Expand file tree
/
Copy pathhistory.py
More file actions
132 lines (102 loc) · 3.95 KB
/
Copy pathhistory.py
File metadata and controls
132 lines (102 loc) · 3.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import argparse
from aider import models, prompts
from aider.dump import dump # noqa: F401
from aider.sendchat import simple_send_with_retries
class ChatSummary:
def __init__(self, model=None, max_tokens=1024):
self.token_count = model.token_count
self.max_tokens = max_tokens
self.model = model
def too_big(self, messages):
sized = self.tokenize(messages)
total = sum(tokens for tokens, _msg in sized)
return total > self.max_tokens
def tokenize(self, messages):
sized = []
for msg in messages:
tokens = self.token_count(msg)
sized.append((tokens, msg))
return sized
def summarize(self, messages, depth=0):
sized = self.tokenize(messages)
total = sum(tokens for tokens, _msg in sized)
if total <= self.max_tokens and depth == 0:
return messages
min_split = 4
if len(messages) <= min_split or depth > 3:
return self.summarize_all(messages)
tail_tokens = 0
split_index = len(messages)
half_max_tokens = self.max_tokens // 2
# Iterate over the messages in reverse order
for i in range(len(sized) - 1, -1, -1):
tokens, _msg = sized[i]
if tail_tokens + tokens < half_max_tokens:
tail_tokens += tokens
split_index = i
else:
break
# Ensure the head ends with an assistant message
while messages[split_index - 1]["role"] != "assistant" and split_index > 1:
split_index -= 1
if split_index <= min_split:
return self.summarize_all(messages)
head = messages[:split_index]
tail = messages[split_index:]
summary = self.summarize_all(head)
tail_tokens = sum(tokens for tokens, msg in sized[split_index:])
summary_tokens = self.token_count(summary)
result = summary + tail
if summary_tokens + tail_tokens < self.max_tokens:
return result
return self.summarize(result, depth + 1)
def summarize_all(self, messages):
content = ""
for msg in messages:
role = msg["role"].upper()
if role not in ("USER", "ASSISTANT"):
continue
content += f"# {role}\n"
content += msg["content"]
if not content.endswith("\n"):
content += "\n"
messages = [
dict(role="system", content=prompts.summarize),
dict(role=&quo
5EA2
t;user", content=content),
]
summary = simple_send_with_retries(self.model.name, messages)
if summary is None:
raise ValueError(f"summarizer unexpectedly failed for {self.model.name}")
summary = prompts.summary_prefix + summary
return [dict(role="user", content=summary)]
def main():
parser = argparse.ArgumentParser()
parser.add_argument("filename", help="Markdown file to parse")
args = parser.parse_args()
with open(args.filename, "r") as f:
text = f.read()
messages = []
assistant = []
for line in text.splitlines(keepends=True):
if line.startswith("# "):
continue
if line.startswith(">"):
continue
if line.startswith("#### /"):
continue
if line.startswith("#### "):
if assistant:
assistant = "".join(assistant)
if assistant.strip():
messages.append(dict(role="assistant", content=assistant))
assistant = []
content = line[5:]
if content.strip() and content.strip() != "<blank>":
messages.append(dict(role="user", content=line[5:]))
continue
assistant.append(line)
summarizer = ChatSummary(models.Model(models.DEFAULT_WEAK_MODEL_NAME, weak_model=False))
summary = summarizer.summarize(messages[-40:])
dump(summary)
if __name__ == "__main__":
main()