-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrun.ts
More file actions
148 lines (138 loc) · 5.13 KB
/
Copy pathrun.ts
File metadata and controls
148 lines (138 loc) · 5.13 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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
import { readdirSync, readFileSync, writeFileSync } from 'fs'
import { groupHunks } from '../src/ai'
import { EmbeddingService } from '../src/embedding-service'
import { computeF1 } from './metrics'
import simpleGit from 'simple-git'
import { configureStore } from '@reduxjs/toolkit'
import { reducer, usageIncreased } from '../src/redux/slice'
import { hunksToVectorEntries } from '../src/redux/thunks/hunkThunks'
import { parseDiff } from '../src/redux/thunks/hunkThunksHelpers'
import { getSecretConfig } from '../src/config'
const SUMMARY_PATH = './benchmark_history/summary.json'
const INPUT_DIR = './benchmarks/input/'
const RUNS_DIR = './benchmark_history/runs/'
const formatDuration = (ms: number): string => {
const totalSeconds = Math.floor(ms / 1000)
const hours = Math.floor(totalSeconds / 3600)
const minutes = Math.floor((totalSeconds % 3600) / 60)
const seconds = totalSeconds % 60
const mm = minutes.toString().padStart(hours > 0 ? 2 : 1, '0')
const ss = seconds.toString().padStart(2, '0')
return hours > 0 ? `${hours}h:${mm}m:${ss}s` : `${mm}m:${ss}s`
}
const getCurrentSha = async () => {
// Ensure that there aren't any uncommitted changes using the simple git module
const git = simpleGit()
const status = await git.status()
if (!status.isClean()) {
throw new Error(
'There are uncommitted changes. Please commit or stash your changes so that the benchmark results are reproducible.',
)
}
const sha = (await git.revparse('HEAD')) as string
return sha
}
const run = async () => {
const sha = await getCurrentSha()
// read the benchmarks/input directory
const inputs = readdirSync(INPUT_DIR)
const embeddingService = new EmbeddingService()
await embeddingService.initialize()
const secretConfig = await getSecretConfig()
if (!secretConfig) {
throw new Error('Secret config not found')
}
const llmConfig = secretConfig.llmConfig
// Create a temporary store for the benchmark
const store = configureStore({ reducer })
const resultsByFile: Record<
string,
{
f1Score: number
timeMilliseconds: number
timeHumanReadable: string
numHunks: number
sha: string
groups: Array<Array<string>>
llmProvider: string
}
> = {}
for (const input of inputs) {
const start = Date.now()
const diffOutput = readFileSync(`${INPUT_DIR}${input}`, 'utf8')
const hunks = parseDiff(diffOutput)
const goldFileName = input.split('.diff')[0] + '.ts'
// Generate vector entries with embeddings
const vectorEntries = await store
.dispatch(
hunksToVectorEntries({
hunks,
embeddingService,
llmConfig,
}),
)
.unwrap()
const groups = await groupHunks({
config: llmConfig,
hunks: vectorEntries,
userInstructions: '',
embeddingService,
debug: false,
addUsage: (usage) => {
store.dispatch(usageIncreased({ usage }))
},
})
const prediction = Object.values(groups).map((g) => g.hunks.map((h) => h.hash))
// Import the gold file and access the GROUPS array
const gold = (await import(`./gold/${goldFileName}`)).default as {
groups: Array<Array<string>>
}
const f1Score = computeF1({ gold: gold.groups, prediction })
const timeMilliseconds = Date.now() - start
resultsByFile[input] = {
f1Score,
timeMilliseconds,
timeHumanReadable: formatDuration(timeMilliseconds),
numHunks: hunks.length,
sha,
groups: Object.values(groups).map((g) => g.hunks.map((h) => h.hash)),
llmProvider: llmConfig.provider,
}
}
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').replace('T', '_').split('.')[0]
writeFileSync(`${RUNS_DIR}${timestamp}.json`, JSON.stringify(resultsByFile, null, 2))
const summariesSoFar = JSON.parse(readFileSync(SUMMARY_PATH).toString())
const worstToBest = Object.keys(resultsByFile)
.map((file) => ({
filePath: file,
f1Score: resultsByFile[file].f1Score,
timeMilliseconds: resultsByFile[file].timeMilliseconds,
timeHumanReadable: resultsByFile[file].timeHumanReadable,
numHunks: resultsByFile[file].numHunks,
}))
.sort((a, b) => (a.f1Score < b.f1Score ? -1 : 1))
const f1Sum = worstToBest.map(({ f1Score }) => f1Score).reduce((sum, score) => sum + score, 0)
const averageF1Score = f1Sum / worstToBest.length
const totalHunks = worstToBest
.map(({ numHunks }) => numHunks)
.reduce((sum, numHunks) => sum + numHunks, 0)
const averageTimePerHunk =
worstToBest
.map(({ timeMilliseconds }) => timeMilliseconds)
.reduce((sum, timeMilliseconds) => sum + timeMilliseconds, 0) / totalHunks
const newSummaryEntry = {
date: new Date().toString(),
worst: worstToBest[0],
best: worstToBest[worstToBest.length - 1],
averageF1Score,
averageTimePerHunk: formatDuration(averageTimePerHunk),
sha,
llmProvider: llmConfig.provider,
}
writeFileSync(SUMMARY_PATH, JSON.stringify([...summariesSoFar, newSummaryEntry], null, 2))
// Commit all of the changes marking the time
const git = simpleGit()
await git.add('.')
await git.commit(`Benchmark results for ${llmConfig.provider}`)
}
run()