Skip to content

Commit 4aede7e

Browse files
authored
Merge pull request #1571 from WebFuzzing/llm-dictionary-creation
building dictionary
2 parents ebce47d + 057a9b3 commit 4aede7e

4 files changed

Lines changed: 66792 additions & 28 deletions

File tree

core/src/main/kotlin/org/evomaster/core/llm/DictionaryCreator.kt

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import org.evomaster.core.utils.TimeUtils
1212
import java.io.File
1313
import java.util.Collections
1414
import java.util.concurrent.Executors
15+
import java.util.concurrent.TimeUnit
1516
import kotlin.io.path.Path
1617

1718

@@ -20,9 +21,21 @@ object DictionaryCreator {
2021
@JvmStatic
2122
fun main(args: Array<String>) {
2223

24+
/*
25+
June 2026
26+
111M tokens
27+
deepseek-v4-flash
28+
cost: ~$19
29+
size: 25.3Mb
30+
*/
31+
32+
// TODO need to add manually
33+
// WARNING: make sure you do NOT commit it
2334
val API_KEY = ""
2435

2536
val file = File("src/main/resources/llm_dictionary.jsonl")
37+
val errors = 0
38+
val alreadyHandled = errors + file.bufferedReader().use { it.lineSequence().count() }
2639

2740
// val modelName = "deepseek-v4-pro"
2841
val modelName = "deepseek-v4-flash"
@@ -33,17 +46,24 @@ object DictionaryCreator {
3346
TimeUtils.measureTimeMillis(
3447
{ms, res -> println("Took ${ms/1000}s")},
3548
{
36-
val executor = Executors.newFixedThreadPool(10)
49+
val parallelism = 20
50+
val executor = Executors.newFixedThreadPool(parallelism)
3751
val list = Collections.synchronizedList(mutableListOf<String>())
3852

3953
val futures = data.entries
4054
.sortedBy { it.key }
41-
//.drop(1) //TODO for debugging
42-
.take(10) //TODO for debugging
55+
.drop(alreadyHandled)
56+
.take(2000) //TODO use for incremental job
4357
.map { entry ->
4458
executor.submit { handleEntry(entry, model, list) }
4559
}
46-
futures.forEach { it.get() }
60+
futures.forEach {
61+
try {
62+
it.get(120, TimeUnit.SECONDS)
63+
}catch (e: Exception) {
64+
println("ERROR. Failed to wait for job: ${e.message}")
65+
}
66+
}
4767
executor.shutdown()
4868

4969
list.sorted().forEach {
@@ -62,18 +82,22 @@ object DictionaryCreator {
6282
val description = entry.value.maxByOrNull { it.length }
6383
val prompt = Prompts.getPromptForNameDescription(name, description)
6484
var result = LlmSupport.chat(model, prompt.first, prompt.second)
65-
val list = try {
85+
try {
6686
mapper.readValue(result, object : TypeReference<List<String>>() {})
6787
} catch (e: Exception) {
68-
val failed = Prompts.getPromptForFailedName(e.toString())
69-
result = LlmSupport.chat(model, failed.first, failed.second)
70-
mapper.readValue(result, object : TypeReference<List<String>>() {})
71-
} catch (e: Exception) {
72-
print("Failed handling response: $result")
73-
throw e
88+
print("ERROR. Failed handling response: $result")
89+
try {
90+
val failed = Prompts.getPromptForFailedName(e.toString())
91+
result = LlmSupport.chat(model, failed.first, failed.second)
92+
mapper.readValue(result, object : TypeReference<List<String>>() {})
93+
} catch (e: Exception) {
94+
print("ERROR. Failed again handling response: $result")
95+
throw e
96+
}
7497
}
7598

76-
val row = "{ \"$name\": $result }"
99+
//must be a single row, and we have it in the prompt, but sometimes it is ignored
100+
val row = "{ \"$name\": $result }".replace('\n',' ')
77101
println(row)
78102
buffer.add(row)
79103
}
@@ -83,8 +107,7 @@ object DictionaryCreator {
83107
val data = mutableMapOf<String, MutableSet<String>>()
84108

85109
val locations = scanForSchemas("./src/test/resources/swagger")
86-
//TODO put back once rest finished
87-
//.plus(scanForSchemas("../core-tests/integration-tests/core-it/src/test/resources/APIs_guru"))
110+
.plus(scanForSchemas("../core-tests/integration-tests/core-it/src/test/resources/APIs_guru"))
88111

89112
for(l in locations){
90113
println("Analyzing: $l")

core/src/main/kotlin/org/evomaster/core/llm/service/DictionaryService.kt

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ class DictionaryService {
5656

5757
val toFind = names.toList().sorted()
5858
var index = 0
59+
var previous = ""
5960

6061
reader.lineSequence()
6162
.takeWhile { index < toFind.size }
@@ -66,6 +67,11 @@ class DictionaryService {
6667
val endQuote = line.indexOf('"', startQuote+1)
6768
val x = line.substring(startQuote+1, endQuote)
6869

70+
if(x != "" && x <= previous) {
71+
throw IllegalStateException("Not sorted: $x should be before $previous")
72+
}
73+
previous = x
74+
6975
var handled = false
7076

7177
while(!handled && index < toFind.size) {
@@ -104,12 +110,15 @@ class DictionaryService {
104110
) {
105111
val node = mapper.readTree(line)
106112
if (!node.isObject) {
107-
log.warn("Not an object: $line")
113+
throw IllegalStateException("Not an object: $line")
108114
} else {
109115
node.fields().forEach { field ->
110116
if (!field.value.isArray) {
111-
log.warn("Not containing an array: $line")
117+
throw IllegalStateException("Not containing an array: $line")
112118
} else {
119+
if(found.containsKey(field.key)) {
120+
throw IllegalStateException("Already handled: ${field.key}")
121+
}
113122
found[field.key] = mapper.convertValue(field.value, object : TypeReference<Set<String>>() {})
114123
}
115124
}

0 commit comments

Comments
 (0)