Skip to main content

src/langfuse_client@score.erl

-module(langfuse_client@score).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/langfuse_client/score.gleam").
-export(['query'/0, with_page/2, with_limit/2, with_name/2, with_trace_id/2, with_session_id/2, with_dataset_run_id/2, with_user_id/2, with_data_type/2, with_from_timestamp/2, with_to_timestamp/2, decode/1, list/2]).
-export_type([score/0, page/0, scores/0, 'query'/0]).

-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.

?MODULEDOC(
    " `GET /api/public/v2/scores` — paginated fetch of eval scores from a\n"
    " Langfuse project. Build a `Query` with `query()` and the `with_*` helpers,\n"
    " then pass it to `list(client, query)`.\n"
).

-type score() :: {score,
        binary(),
        gleam@option:option(binary()),
        gleam@option:option(binary()),
        gleam@option:option(binary()),
        binary(),
        binary(),
        binary(),
        gleam@option:option(float()),
        gleam@option:option(binary()),
        gleam@option:option(binary()),
        binary(),
        gleam@option:option(binary())}.

-type page() :: {page, integer(), integer(), integer(), integer()}.

-type scores() :: {scores, list(score()), page()}.

-type 'query'() :: {'query',
        gleam@option:option(integer()),
        gleam@option:option(integer()),
        gleam@option:option(binary()),
        gleam@option:option(binary()),
        gleam@option:option(binary()),
        gleam@option:option(binary()),
        gleam@option:option(binary()),
        gleam@option:option(binary()),
        gleam@option:option(binary()),
        gleam@option:option(binary()),
        gleam@option:option(binary())}.

-file("src/langfuse_client/score.gleam", 67).
?DOC(
    " Empty query — pass to `list` to retrieve the first page with the server\n"
    " defaults (page 1, limit 50).\n"
).
-spec 'query'() -> 'query'().
'query'() ->
    {'query', none, none, none, none, none, none, none, none, none, none, none}.

-file("src/langfuse_client/score.gleam", 84).
?DOC(" Set the page number (1-indexed).\n").
-spec with_page('query'(), integer()) -> 'query'().
with_page(Q, Page) ->
    {'query',
        {some, Page},
        erlang:element(3, Q),
        erlang:element(4, Q),
        erlang:element(5, Q),
        erlang:element(6, Q),
        erlang:element(7, Q),
        erlang:element(8, Q),
        erlang:element(9, Q),
        erlang:element(10, Q),
        erlang:element(11, Q),
        erlang:element(12, Q)}.

-file("src/langfuse_client/score.gleam", 89).
?DOC(" Set the page size (Langfuse defaults to 50).\n").
-spec with_limit('query'(), integer()) -> 'query'().
with_limit(Q, Limit) ->
    {'query',
        erlang:element(2, Q),
        {some, Limit},
        erlang:element(4, Q),
        erlang:element(5, Q),
        erlang:element(6, Q),
        erlang:element(7, Q),
        erlang:element(8, Q),
        erlang:element(9, Q),
        erlang:element(10, Q),
        erlang:element(11, Q),
        erlang:element(12, Q)}.

-file("src/langfuse_client/score.gleam", 94).
?DOC(" Filter to scores with this exact name.\n").
-spec with_name('query'(), binary()) -> 'query'().
with_name(Q, Name) ->
    {'query',
        erlang:element(2, Q),
        erlang:element(3, Q),
        erlang:element(4, Q),
        {some, Name},
        erlang:element(6, Q),
        erlang:element(7, Q),
        erlang:element(8, Q),
        erlang:element(9, Q),
        erlang:element(10, Q),
        erlang:element(11, Q),
        erlang:element(12, Q)}.

-file("src/langfuse_client/score.gleam", 99).
?DOC(" Filter to scores attached to this trace.\n").
-spec with_trace_id('query'(), binary()) -> 'query'().
with_trace_id(Q, Trace_id) ->
    {'query',
        erlang:element(2, Q),
        erlang:element(3, Q),
        erlang:element(4, Q),
        erlang:element(5, Q),
        erlang:element(6, Q),
        erlang:element(7, Q),
        erlang:element(8, Q),
        {some, Trace_id},
        erlang:element(10, Q),
        erlang:element(11, Q),
        erlang:element(12, Q)}.

-file("src/langfuse_client/score.gleam", 104).
?DOC(" Filter to scores attached to this session.\n").
-spec with_session_id('query'(), binary()) -> 'query'().
with_session_id(Q, Session_id) ->
    {'query',
        erlang:element(2, Q),
        erlang:element(3, Q),
        erlang:element(4, Q),
        erlang:element(5, Q),
        erlang:element(6, Q),
        erlang:element(7, Q),
        erlang:element(8, Q),
        erlang:element(9, Q),
        {some, Session_id},
        erlang:element(11, Q),
        erlang:element(12, Q)}.

-file("src/langfuse_client/score.gleam", 109).
?DOC(" Filter to scores tied to this dataset run.\n").
-spec with_dataset_run_id('query'(), binary()) -> 'query'().
with_dataset_run_id(Q, Dataset_run_id) ->
    {'query',
        erlang:element(2, Q),
        erlang:element(3, Q),
        erlang:element(4, Q),
        erlang:element(5, Q),
        erlang:element(6, Q),
        erlang:element(7, Q),
        erlang:element(8, Q),
        erlang:element(9, Q),
        erlang:element(10, Q),
        {some, Dataset_run_id},
        erlang:element(12, Q)}.

-file("src/langfuse_client/score.gleam", 114).
?DOC(" Filter to scores whose trace has this user id.\n").
-spec with_user_id('query'(), binary()) -> 'query'().
with_user_id(Q, User_id) ->
    {'query',
        erlang:element(2, Q),
        erlang:element(3, Q),
        {some, User_id},
        erlang:element(5, Q),
        erlang:element(6, Q),
        erlang:element(7, Q),
        erlang:element(8, Q),
        erlang:element(9, Q),
        erlang:element(10, Q),
        erlang:element(11, Q),
        erlang:element(12, Q)}.

-file("src/langfuse_client/score.gleam", 119).
?DOC(" Filter to scores of a given data type (`NUMERIC`, `BOOLEAN`, `CATEGORICAL`).\n").
-spec with_data_type('query'(), binary()) -> 'query'().
with_data_type(Q, Data_type) ->
    {'query',
        erlang:element(2, Q),
        erlang:element(3, Q),
        erlang:element(4, Q),
        erlang:element(5, Q),
        erlang:element(6, Q),
        erlang:element(7, Q),
        erlang:element(8, Q),
        erlang:element(9, Q),
        erlang:element(10, Q),
        erlang:element(11, Q),
        {some, Data_type}}.

-file("src/langfuse_client/score.gleam", 124).
?DOC(" Lower bound on `timestamp` (ISO 8601, inclusive).\n").
-spec with_from_timestamp('query'(), binary()) -> 'query'().
with_from_timestamp(Q, From) ->
    {'query',
        erlang:element(2, Q),
        erlang:element(3, Q),
        erlang:element(4, Q),
        erlang:element(5, Q),
        {some, From},
        erlang:element(7, Q),
        erlang:element(8, Q),
        erlang:element(9, Q),
        erlang:element(10, Q),
        erlang:element(11, Q),
        erlang:element(12, Q)}.

-file("src/langfuse_client/score.gleam", 129).
?DOC(" Upper bound on `timestamp` (ISO 8601, exclusive).\n").
-spec with_to_timestamp('query'(), binary()) -> 'query'().
with_to_timestamp(Q, To) ->
    {'query',
        erlang:element(2, Q),
        erlang:element(3, Q),
        erlang:element(4, Q),
        erlang:element(5, Q),
        erlang:element(6, Q),
        {some, To},
        erlang:element(8, Q),
        erlang:element(9, Q),
        erlang:element(10, Q),
        erlang:element(11, Q),
        erlang:element(12, Q)}.

-file("src/langfuse_client/score.gleam", 142).
?DOC(
    " Parse a `GET /api/public/v2/scores` response body. Useful if you already\n"
    " have the raw body in hand (e.g. from a cached/recorded response).\n"
).
-spec decode(binary()) -> {ok, scores()} | {error, gleam@json:decode_error()}.
decode(Body) ->
    gleam@json:parse(Body, scores_decoder()).

-file("src/langfuse_client/score.gleam", 182).
-spec meta_decoder() -> gleam@dynamic@decode:decoder(page()).
meta_decoder() ->
    gleam@dynamic@decode:field(
        <<"page"/utf8>>,
        {decoder, fun gleam@dynamic@decode:decode_int/1},
        fun(Page) ->
            gleam@dynamic@decode:field(
                <<"limit"/utf8>>,
                {decoder, fun gleam@dynamic@decode:decode_int/1},
                fun(Limit) ->
                    gleam@dynamic@decode:field(
                        <<"totalItems"/utf8>>,
                        {decoder, fun gleam@dynamic@decode:decode_int/1},
                        fun(Total_items) ->
                            gleam@dynamic@decode:field(
                                <<"totalPages"/utf8>>,
                                {decoder, fun gleam@dynamic@decode:decode_int/1},
                                fun(Total_pages) ->
                                    gleam@dynamic@decode:success(
                                        {page,
                                            Page,
                                            Limit,
                                            Total_items,
                                            Total_pages}
                                    )
                                end
                            )
                        end
                    )
                end
            )
        end
    ).

-file("src/langfuse_client/score.gleam", 178).
-spec lenient_float() -> gleam@dynamic@decode:decoder(float()).
lenient_float() ->
    gleam@dynamic@decode:one_of(
        {decoder, fun gleam@dynamic@decode:decode_float/1},
        [begin
                _pipe = {decoder, fun gleam@dynamic@decode:decode_int/1},
                gleam@dynamic@decode:map(_pipe, fun erlang:float/1)
            end]
    ).

-file("src/langfuse_client/score.gleam", 190).
-spec score_decoder() -> gleam@dynamic@decode:decoder(score()).
score_decoder() ->
    gleam@dynamic@decode:field(
        <<"id"/utf8>>,
        {decoder, fun gleam@dynamic@decode:decode_string/1},
        fun(Id) ->
            gleam@dynamic@decode:optional_field(
                <<"traceId"/utf8>>,
                none,
                gleam@dynamic@decode:optional(
                    {decoder, fun gleam@dynamic@decode:decode_string/1}
                ),
                fun(Trace_id) ->
                    gleam@dynamic@decode:optional_field(
                        <<"sessionId"/utf8>>,
                        none,
                        gleam@dynamic@decode:optional(
                            {decoder, fun gleam@dynamic@decode:decode_string/1}
                        ),
                        fun(Session_id) ->
                            gleam@dynamic@decode:optional_field(
                                <<"observationId"/utf8>>,
                                none,
                                gleam@dynamic@decode:optional(
                                    {decoder,
                                        fun gleam@dynamic@decode:decode_string/1}
                                ),
                                fun(Observation_id) ->
                                    gleam@dynamic@decode:field(
                                        <<"name"/utf8>>,
                                        {decoder,
                                            fun gleam@dynamic@decode:decode_string/1},
                                        fun(Name) ->
                                            gleam@dynamic@decode:field(
                                                <<"dataType"/utf8>>,
                                                {decoder,
                                                    fun gleam@dynamic@decode:decode_string/1},
                                                fun(Data_type) ->
                                                    gleam@dynamic@decode:field(
                                                        <<"source"/utf8>>,
                                                        {decoder,
                                                            fun gleam@dynamic@decode:decode_string/1},
                                                        fun(Source) ->
                                                            gleam@dynamic@decode:optional_field(
                                                                <<"value"/utf8>>,
                                                                none,
                                                                gleam@dynamic@decode:optional(
                                                                    lenient_float(
                                                                        
                                                                    )
                                                                ),
                                                                fun(Value) ->
                                                                    gleam@dynamic@decode:optional_field(
                                                                        <<"stringValue"/utf8>>,
                                                                        none,
                                                                        gleam@dynamic@decode:optional(
                                                                            {decoder,
                                                                                fun gleam@dynamic@decode:decode_string/1}
                                                                        ),
                                                                        fun(
                                                                            String_value
                                                                        ) ->
                                                                            gleam@dynamic@decode:optional_field(
                                                                                <<"comment"/utf8>>,
                                                                                none,
                                                                                gleam@dynamic@decode:optional(
                                                                                    {decoder,
                                                                                        fun gleam@dynamic@decode:decode_string/1}
                                                                                ),
                                                                                fun(
                                                                                    Comment
                                                                                ) ->
                                                                                    gleam@dynamic@decode:field(
                                                                                        <<"timestamp"/utf8>>,
                                                                                        {decoder,
                                                                                            fun gleam@dynamic@decode:decode_string/1},
                                                                                        fun(
                                                                                            Timestamp
                                                                                        ) ->
                                                                                            gleam@dynamic@decode:optional_field(
                                                                                                <<"environment"/utf8>>,
                                                                                                none,
                                                                                                gleam@dynamic@decode:optional(
                                                                                                    {decoder,
                                                                                                        fun gleam@dynamic@decode:decode_string/1}
                                                                                                ),
                                                                                                fun(
                                                                                                    Environment
                                                                                                ) ->
                                                                                                    gleam@dynamic@decode:success(
                                                                                                        {score,
                                                                                                            Id,
                                                                                                            Trace_id,
                                                                                                            Session_id,
                                                                                                            Observation_id,
                                                                                                            Name,
                                                                                                            Data_type,
                                                                                                            Source,
                                                                                                            Value,
                                                                                                            String_value,
                                                                                                            Comment,
                                                                                                            Timestamp,
                                                                                                            Environment}
                                                                                                    )
                                                                                                end
                                                                                            )
                                                                                        end
                                                                                    )
                                                                                end
                                                                            )
                                                                        end
                                                                    )
                                                                end
                                                            )
                                                        end
                                                    )
                                                end
                                            )
                                        end
                                    )
                                end
                            )
                        end
                    )
                end
            )
        end
    ).

-file("src/langfuse_client/score.gleam", 170).
-spec scores_decoder() -> gleam@dynamic@decode:decoder(scores()).
scores_decoder() ->
    gleam@dynamic@decode:field(
        <<"data"/utf8>>,
        gleam@dynamic@decode:list(score_decoder()),
        fun(Data) ->
            gleam@dynamic@decode:field(
                <<"meta"/utf8>>,
                meta_decoder(),
                fun(Meta) ->
                    gleam@dynamic@decode:success({scores, Data, Meta})
                end
            )
        end
    ).

-file("src/langfuse_client/score.gleam", 147).
-spec query_pairs('query'()) -> list({binary(), binary()}).
query_pairs(Q) ->
    _pipe = [{<<"page"/utf8>>,
            gleam@option:map(
                erlang:element(2, Q),
                fun erlang:integer_to_binary/1
            )},
        {<<"limit"/utf8>>,
            gleam@option:map(
                erlang:element(3, Q),
                fun erlang:integer_to_binary/1
            )},
        {<<"userId"/utf8>>, erlang:element(4, Q)},
        {<<"name"/utf8>>, erlang:element(5, Q)},
        {<<"fromTimestamp"/utf8>>, erlang:element(6, Q)},
        {<<"toTimestamp"/utf8>>, erlang:element(7, Q)},
        {<<"source"/utf8>>, erlang:element(8, Q)},
        {<<"traceId"/utf8>>, erlang:element(9, Q)},
        {<<"sessionId"/utf8>>, erlang:element(10, Q)},
        {<<"datasetRunId"/utf8>>, erlang:element(11, Q)},
        {<<"dataType"/utf8>>, erlang:element(12, Q)}],
    gleam@list:filter_map(
        _pipe,
        fun(Pair) ->
            {K, V} = Pair,
            case V of
                {some, Value} ->
                    {ok, {K, Value}};

                none ->
                    {error, nil}
            end
        end
    ).

-file("src/langfuse_client/score.gleam", 136).
?DOC(
    " Fetch one page of scores from `GET /api/public/v2/scores`. Erlang-only —\n"
    " the JavaScript target lacks an HTTP transport in this library.\n"
).
-spec list(langfuse_client@client:client(), 'query'()) -> {ok, scores()} |
    {error, langfuse_client@client:error()}.
list(C, Q) ->
    langfuse_client@client:send_get(
        C,
        <<"/api/public/v2/scores"/utf8>>,
        query_pairs(Q),
        scores_decoder()
    ).