-
Notifications
You must be signed in to change notification settings - Fork 0
/
app.ts
118 lines (90 loc) · 3.83 KB
/
app.ts
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
import readline from 'readline';
import * as Diff from 'diff';
import OpenAI from 'openai';
// TODO: Better markers for diff e.g. invisible unicode characters
const ADD_START='追追追';
const DEL_START='削削削';
const DIFF_END='終終終';
function question(query: string): Promise<string> {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
return new Promise(resolve => rl.question(query, answer => {
rl.close();
resolve(answer);
}));
}
function buildPrompt(partialCommand: string, requirement: string): string {
const prompt = `
Below is a partial command.
${partialCommand}
Here are the requirements.
「${requirement}」
Infer the intent behind the requirements and suggest up to 5 modifications to the command line. Separate each suggestion with a new line and format each line as follows:
command_part@@@description@@@full_command
Where:
- command_part: The part of the command line to add (if removing, use remove: followed by the part to be removed)
- description: A description of the modification
- full_command: The complete command line.
First, you think the full_command to satisfy the requirements. Then you can think command_part where highlights the most important parts of your modification. Finally, you can write a description of the modification.
Please output only command_part is relevant suggestion to the requirements.
Strictly maintain the order of the columns. Only use this format for the output. Do not enclose the output in a Markdown code block.`;
return prompt;
}
function processDiff(partialCommand: string, completeCommand: string): string {
const diffColoredStr = Diff.diffWordsWithSpace(partialCommand, completeCommand, {ignoreWhitespace: true}).map(part => {
if (part.added) {
return `${ADD_START}${part.value}${DIFF_END}`;
}
if (part.removed) {
return `${DEL_START}${part.value}${DIFF_END}`;
}
return part.value;
}).join('');
return diffColoredStr;
}
function toTsv(partialCommand: string, aiLine: string): string {
// just in case AI outputs more than four fields, we concats the rest as completeCommand
const [commandPart, description, ...rest] = aiLine.split('@@@');
const completeCommand = rest.join('');
const diffColoredStr = processDiff(partialCommand, completeCommand);
const tsv = [commandPart, description, completeCommand, diffColoredStr].join('\t');
return tsv
}
async function main() {
const partialCommand = process.argv[2];
const requirement = process.argv[3];
const ans = requirement ? requirement : await question('What do you want to do: ');
const prompt = buildPrompt(partialCommand, ans);
const openai = new OpenAI();
const stream = openai.beta.chat.completions.stream({
model: process.env.MANAI_MODEL ?? 'gpt-4o',
messages: [
{ role: 'system', content: prompt },
],
stream: true,
});
// const completion = await stream.finalContent();
// const filteredLines = completion?.split('\n').map(e => e.replaceAll('@@@', '\t')).filter((line) => line.length > 0);
// console.log(filteredLines?.join('\n'));
let buffer: string = "";
stream.on('content', (contentDelta) => {
buffer += contentDelta;
const lines = buffer.split('\n');
const completeLines = lines.slice(0, -1);
const incompleteLine = lines.slice(-1)[0];
for (const line of completeLines) {
if (line.length === 0) {
continue;
}
console.log(toTsv(partialCommand, line));
}
buffer = incompleteLine;
});
await stream.finalContent();
if (buffer.length > 0) {
console.log(toTsv(partialCommand, buffer));
}
}
main();