馃悕馃悕馃悕
1
2export function chatEntry(role, content) {
3 return { role, content };
4}
5
6function noCollect() {
7 return {
8 name: null,
9 collect: (line) => {},
10 finalize: () => {}
11 };
12}
13
14function literalCollector(name) {
15 const lines = [];
16
17 const collect = (line) => {
18 lines.push(line);
19 };
20
21 const finalize = () => {
22 let result = "";
23 let inBlankRun = false;
24
25 for (const line of lines) {
26 if (line === "") {
27 inBlankRun = true;
28 } else {
29 if (result.length > 0) {
30 result += inBlankRun ? '\n\n' : ' ';
31 }
32 result += line;
33 inBlankRun = false;
34 }
35 }
36
37 return result;
38 };
39
40 return {
41 name,
42 collect,
43 finalize
44 };
45}
46
47function chatCollector(name) {
48 let chat = [];
49 let collector = noCollect();
50
51 const collect = (line) => {
52 if (['.user:', '.system:', '.assistant:'].includes(line)) {
53 let role = line.slice(1, -1);
54 if (collector.name !== null) {
55 chat.push(chatEntry(collector.name, collector.finalize()));
56 }
57 collector = literalCollector(role);
58 }
59 else {
60 collector.collect(line);
61 }
62 };
63
64 const finalize = () => {
65 if (collector.name !== null) {
66 chat.push(chatEntry(collector.name, collector.finalize()));
67 }
68 return chat;
69 };
70
71 return {
72 name,
73 collect,
74 finalize
75 };
76}
77
78
79
80export function readChatlog(text) {
81 const lines = text.split('\n');
82
83 if (
84 lines.length < 3 || lines[0] !== '' ||
85 !lines[1].startsWith('chatlog ') || lines[2] !== ''
86 ) {
87 throw new Error('invalid chatlog header');
88 }
89
90 // ignore version number for now
91
92 let chatlog = {};
93
94 let collector = noCollect();
95
96 for (let lineIndex = 3; lineIndex < lines.length; lineIndex += 1) {
97 const line = lines[lineIndex];
98
99 if (line.startsWith(".chat ")) {
100 let name = line.slice(6); // rest of the line
101 if (collector.name !== null) {
102 console.log(collector);
103 chatlog[collector.name] = collector.finalize();
104 }
105 collector = chatCollector(name);
106 }
107 else if (line.startsWith(".literal ")) {
108 let name = line.slice(9); // rest of the line
109 if (collector.name !== null) {
110 chatlog[collector.name] = collector.finalize();
111 }
112 collector = literalCollector(name);
113 }
114 else {
115 collector.collect(line);
116 }
117 }
118
119 if (collector.name !== null) {
120 chatlog[collector.name] = collector.finalize();
121 }
122
123 return chatlog;
124}
125
126export async function loadChatlog(uri) {
127 const response = await fetch(uri);
128
129 if (!response.ok) {
130 throw new Error(`could not load ${uri}`);
131 }
132
133 const source = await response.text();
134
135 return readChatlog(source);
136}
137