Kosten Endpunkt

This commit is contained in:
2026-06-01 14:21:42 +02:00
parent fb185c1a71
commit f3ae6859bf
21 changed files with 632 additions and 78 deletions

View File

@@ -1026,6 +1026,136 @@ BEGIN
]'
);
-- ===========================================================================
-- TEMPLATE 17: ai-costs (POST = Eintrag speichern, GET = Auswertung)
-- ===========================================================================
ORDS.DEFINE_TEMPLATE(
p_module_name => 'frigosped.dc',
p_pattern => 'ai-costs',
p_priority => 0,
p_comments => 'KI-Kostenprotokoll: POST speichert Aufruf, GET liefert Auswertung'
);
-- 17a. POST /api/dc/ai-costs
-- Body: {"provider":"mistral","model_name":"mistral-small-latest","operation":"TRANSLATE",
-- "project_id":42,"catalog_id":null,
-- "prompt_tokens":1234,"completion_tokens":567,"total_tokens":1801,"cost_eur":0.000157}
ORDS.DEFINE_HANDLER(
p_module_name => 'frigosped.dc',
p_pattern => 'ai-costs',
p_method => 'POST',
p_source_type => ORDS.SOURCE_TYPE_PLSQL,
p_comments => '201 Created mit neuer cost_log id',
p_source => q'[
DECLARE
v_body CLOB;
v_new_id NUMBER;
BEGIN
v_body := :body_text;
INSERT INTO dc_ai_cost_log (
provider, model_name, operation,
project_id, catalog_id,
prompt_tokens, completion_tokens, total_tokens,
cost_eur
) VALUES (
JSON_VALUE(v_body, '$.provider'),
JSON_VALUE(v_body, '$.model_name'),
JSON_VALUE(v_body, '$.operation'),
TO_NUMBER(JSON_VALUE(v_body, '$.project_id')),
TO_NUMBER(JSON_VALUE(v_body, '$.catalog_id')),
NVL(TO_NUMBER(JSON_VALUE(v_body, '$.prompt_tokens')), 0),
NVL(TO_NUMBER(JSON_VALUE(v_body, '$.completion_tokens')), 0),
NVL(TO_NUMBER(JSON_VALUE(v_body, '$.total_tokens')), 0),
NVL(TO_NUMBER(JSON_VALUE(v_body, '$.cost_eur')), 0)
)
RETURNING id INTO v_new_id;
:status_code := 201;
HTP.P('{"id":' || v_new_id || '}');
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
:status_code := 500;
HTP.P('{"error":"' || REPLACE(SQLERRM, '"', '''') || '"}');
END;
]'
);
-- 17b. GET /api/dc/ai-costs
-- Liefert: Gesamtkosten, laufender Monat, Monats-Aufschlüsselung (12 Monate)
ORDS.DEFINE_HANDLER(
p_module_name => 'frigosped.dc',
p_pattern => 'ai-costs',
p_method => 'GET',
p_source_type => ORDS.SOURCE_TYPE_PLSQL,
p_comments => 'Kostenauswertung: total, current_month, monatliche Aufschluesselung via DC_COSTS_PKG',
p_source => q'[
DECLARE
v_total_eur NUMBER;
v_total_tokens NUMBER;
v_total_calls NUMBER;
v_month_eur NUMBER;
v_month_tokens NUMBER;
v_month_calls NUMBER;
v_monthly_json CLOB;
BEGIN
DC_COSTS_PKG.get_summary(
v_total_eur, v_total_tokens, v_total_calls,
v_month_eur, v_month_tokens, v_month_calls
);
SELECT JSON_ARRAYAGG(
JSON_OBJECT(
'month' VALUE month,
'cost_eur' VALUE ROUND(cost_eur, 6),
'prompt_tokens' VALUE prompt_tokens,
'completion_tokens' VALUE completion_tokens,
'total_tokens' VALUE total_tokens,
'call_count' VALUE call_count
)
ORDER BY month DESC
RETURNING CLOB
)
INTO v_monthly_json
FROM (
SELECT
TO_CHAR(called_at, 'YYYY-MM') AS month,
SUM(cost_eur) AS cost_eur,
SUM(prompt_tokens) AS prompt_tokens,
SUM(completion_tokens) AS completion_tokens,
SUM(total_tokens) AS total_tokens,
COUNT(*) AS call_count
FROM dc_ai_cost_log
WHERE called_at >= ADD_MONTHS(TRUNC(SYSDATE, 'MM'), -11)
GROUP BY TO_CHAR(called_at, 'YYYY-MM')
);
:status_code := 200;
HTP.P(
'{"total":{'
|| '"cost_eur":' || ROUND(NVL(v_total_eur, 0), 6)
|| ',"total_tokens":'|| NVL(v_total_tokens, 0)
|| ',"call_count":' || NVL(v_total_calls, 0)
|| '},"current_month":{'
|| '"month":"' || TO_CHAR(SYSDATE, 'YYYY-MM') || '"'
|| ',"cost_eur":' || ROUND(NVL(v_month_eur, 0), 6)
|| ',"total_tokens":'|| NVL(v_month_tokens, 0)
|| ',"call_count":' || NVL(v_month_calls, 0)
|| '},"monthly":' || NVL(v_monthly_json, '[]')
|| '}'
);
EXCEPTION
WHEN OTHERS THEN
:status_code := 500;
HTP.P('{"error":"' || REPLACE(SQLERRM, '"', '''') || '"}');
END;
]'
);
COMMIT;
END;
/