Reading Results¶
ask, query and evaluate return a JevResult: one typed answer per question, plus details about the call.
By handle¶
With a typed query, index the result with the question's handle:
val result = jev.ask(Triage, state = ticket)
result[Triage.urgent].noul // Double
result[Triage.team].choice // Team
result[Triage.frustration].score // Double
By id¶
With the inline DSL, read answers by the ids you gave them:
result.noul("urgent").noul
result.choice("team").choice // String: the option key
result.enumChoice<Team>("team").choice // Team
result.score("frustration").score
Answer helpers¶
val urgent = result[Triage.urgent]
urgent.isTrue() // noul > 0.5
urgent.isTrue(threshold = 0.8) // noul > 0.8
urgent.band() // NoulBand.NO (< 0.30), UNCERTAIN, or YES (> 0.70)
val team = result[Triage.team]
team.topProbability // the largest option probability
team.probability(Team.SALES) // any option's probability, 0.0 if absent
team.ranked() // [(TECHNICAL, 0.85), (BILLING, 0.08), (SALES, 0.07)]
val frustration = result[Triage.frustration]
frustration.normalized // score / (levels - 1): 0..1 whatever the level count
frustration.nearestLevel // score rounded to a level
frustration.mostLikelyLevel // the level with the highest probability
frustration.legendText(2) // the description of level 2
| Answer | Fields | Helpers |
|---|---|---|
NoulAnswer |
noul |
isTrue(threshold = 0.5), band(no = 0.30, yes = 0.70) |
ChoiceAnswer<K> |
choice, probabilities, confidence |
topProbability, probability(option), ranked() |
ScoreAnswer |
score, probabilities, legend, confidence, levelCount |
normalized, nearestLevel, mostLikelyLevel, legendText(level) |
- Choice probabilities are in the order the options were declared.
- Score probabilities and legend are keyed by level number, and the legend holds the level entries that were sent.
All answers¶
result.nouls.forEach { (id, answer) -> println("$id: ${answer.noul}") }
result.choices.forEach { (id, answer) -> println("$id: ${answer.choice} (${answer.confidence})") }
result.scores.forEach { (id, answer) -> println("$id: ${answer.score}") }
result.answers // every answer by id, in the order the questions were asked
result.questions.ids // the ids that were asked
Call details¶
println("model=${result.model}") // the version that answered, as reported by the API
println("requested=${result.requestedModel}") // what was sent, e.g. "jev-latest"
println("tokens in=${result.usage.inputTokens} out=${result.usage.outputTokens}")
println("request id=${result.requestId}") // quote this when contacting TypeSafe support
| Property | Meaning |
|---|---|
model |
The model that answered, as reported by the API; falls back to requestedModel |
requestedModel |
The name that was sent, possibly an alias such as jev-latest |
usage |
inputTokens / outputTokens; either may be null |
requestId |
The x-typesafe-request-id response header; quote it in support requests |
raw |
The response body exactly as received |
questions |
The QuestionSet that was asked |
Log model alongside results: an alias such as jev-latest can move to a newer model.
The raw response¶
// The response body exactly as received, e.g. for logging or fields jev4k doesn't model yet.
val rawAnswers = result.raw["answers"]?.jsonObject
When an answer is missing¶
A malformed answer to a known question fails while the response is being read. A missing answer fails
lazily, when you read it. Either way you get a JevResponseValidationException whose fieldPath points at
the problem, such as answers.team.choice:
try {
result[Triage.team]
} catch (e: JevResponseValidationException) {
// The server didn't return a usable answer for this question.
println("bad answer at ${e.fieldPath}, request ${e.requestId}")
}
An answer of a type jev4k doesn't recognize is kept as an UnknownAnswer in answers, rather than failing the
whole response.