hyf

Context-aware query service for Radroots
git clone https://radroots.dev/git/hyf.git
Log | Files | Refs | README | LICENSE

jev_answers.mojo (5906B)


      1 from std.collections import List
      2 
      3 from json import Value
      4 
      5 from hyf_assist.evaluator import (
      6     TypedAnswer,
      7     typed_choice,
      8     typed_noul,
      9     typed_score,
     10 )
     11 
     12 
     13 def _has_key(value: Value, key: String) -> Bool:
     14     for candidate in value.object_keys():
     15         if candidate == key:
     16             return True
     17     return False
     18 
     19 
     20 def parse_noul_answer(question_id: String, value: Value) raises -> TypedAnswer:
     21     if not value.is_object() or not _has_key(value, "type"):
     22         raise Error("provider_answer_invalid")
     23     if value["type"].string_value() != "noul":
     24         raise Error("provider_answer_wrong_type")
     25     if not _has_key(value, "noul") or not value["noul"].is_float():
     26         raise Error("provider_answer_invalid")
     27     var probability = value["noul"].float_value()
     28     if probability < 0.0 or probability > 1.0:
     29         raise Error("provider_answer_noul_out_of_range")
     30     return typed_noul(question_id, probability)
     31 
     32 
     33 def parse_choice_answer(
     34     question_id: String, value: Value, choices: List[String]
     35 ) raises -> TypedAnswer:
     36     if not value.is_object() or not _has_key(value, "type"):
     37         raise Error("provider_answer_invalid")
     38     if value["type"].string_value() != "choice":
     39         raise Error("provider_answer_wrong_type")
     40     if not _has_key(value, "choice"):
     41         raise Error("provider_answer_invalid")
     42     var selected = value["choice"].string_value()
     43     var known = False
     44     for choice in choices:
     45         if choice == selected:
     46             known = True
     47     if not known:
     48         raise Error("provider_answer_unknown_choice")
     49     if not _has_key(value, "confidence") or not value["confidence"].is_float():
     50         raise Error("provider_answer_invalid")
     51     var confidence = value["confidence"].float_value()
     52     if confidence < 0.0 or confidence > 1.0:
     53         raise Error("provider_answer_confidence_out_of_range")
     54     if _has_key(value, "probabilities"):
     55         var probabilities = value["probabilities"]
     56         if not probabilities.is_object():
     57             raise Error("provider_answer_invalid")
     58         var total = 0.0
     59         for choice in choices:
     60             if not _has_key(probabilities, choice):
     61                 raise Error("provider_answer_missing_probability")
     62             total += probabilities[choice].float_value()
     63         if total < 0.999 or total > 1.001:
     64             raise Error("provider_answer_bad_distribution_sum")
     65     return typed_choice(question_id, selected, confidence)
     66 
     67 
     68 def parse_score_answer(
     69     question_id: String, value: Value, rubric: List[String]
     70 ) raises -> TypedAnswer:
     71     if not value.is_object() or not _has_key(value, "type"):
     72         raise Error("provider_answer_invalid")
     73     if value["type"].string_value() != "score":
     74         raise Error("provider_answer_wrong_type")
     75     if not _has_key(value, "score"):
     76         raise Error("provider_answer_invalid")
     77     var score_value = value["score"]
     78     var raw_score = 0.0
     79     if score_value.is_int():
     80         raw_score = Float64(score_value.int_value())
     81     elif score_value.is_float():
     82         raw_score = score_value.float_value()
     83     else:
     84         raise Error("provider_answer_invalid")
     85     var score = Int(raw_score)
     86     if Float64(score) != raw_score:
     87         raise Error("provider_answer_invalid")
     88     if score < 0 or score >= len(rubric):
     89         raise Error("provider_answer_score_out_of_range")
     90     if not _has_key(value, "confidence") or not value["confidence"].is_float():
     91         raise Error("provider_answer_invalid")
     92     var confidence = value["confidence"].float_value()
     93     if confidence < 0.0 or confidence > 1.0:
     94         raise Error("provider_answer_confidence_out_of_range")
     95     if _has_key(value, "legend"):
     96         var legend = value["legend"]
     97         if not legend.is_object() or len(legend.object_keys()) != len(rubric):
     98             raise Error("provider_answer_wrong_legend")
     99     if _has_key(value, "probabilities"):
    100         var probabilities = value["probabilities"]
    101         if not probabilities.is_object() or len(
    102             probabilities.object_keys()
    103         ) != len(rubric):
    104             raise Error("provider_answer_missing_level")
    105         var total = 0.0
    106         for level in range(len(rubric)):
    107             var key = String(level)
    108             if not _has_key(probabilities, key):
    109                 raise Error("provider_answer_missing_level")
    110             total += probabilities[key].float_value()
    111         if total < 0.999 or total > 1.001:
    112             raise Error("provider_answer_bad_distribution_sum")
    113     return typed_score(question_id, score, len(rubric), confidence)
    114 
    115 
    116 from hyf_assist.questions import QuestionBundle
    117 
    118 
    119 def parse_jev_response(
    120     body: Value, bundle: QuestionBundle
    121 ) raises -> List[TypedAnswer]:
    122     if not body.is_object():
    123         raise Error("provider_response_invalid")
    124     if not _has_key(body, "model") or not _has_key(body, "answers"):
    125         raise Error("provider_response_invalid")
    126     if body["model"].string_value() != bundle.model:
    127         raise Error("provider_model_mismatch")
    128     var answers = body["answers"]
    129     if not answers.is_object():
    130         raise Error("provider_response_invalid")
    131 
    132     var result = List[TypedAnswer]()
    133     for question in bundle.questions:
    134         if not _has_key(answers, question.id):
    135             raise Error("provider_answer_missing")
    136         var answer = answers[question.id]
    137         if question.kind == "choice":
    138             result.append(
    139                 parse_choice_answer(question.id, answer, question.choices)
    140             )
    141         elif question.kind == "noul":
    142             result.append(parse_noul_answer(question.id, answer))
    143         elif question.kind == "score":
    144             result.append(
    145                 parse_score_answer(question.id, answer, question.rubric)
    146             )
    147         else:
    148             raise Error("provider_answer_wrong_type")
    149 
    150     if len(answers.object_keys()) != len(bundle.questions):
    151         raise Error("provider_answer_extra")
    152     return result^