feat(api): My Wave sessions with a Go fallback and wave metrics (M4)
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 40s
ci / mobile / mobile (Metro-бандл Android) (push) Failing after 9s
ci / api / api (push) Successful in 35s
ci / ts / ts (packages + web) (push) Successful in 51s

- /wave/options, POST /wave/sessions (activity, mood, seed),
  /next with reactions, PATCH to switch the context on the fly, DELETE
- the recommender is called with an 800 ms budget; on failure the api
  serves a fallback wave of likes, favourite artists and random
  available tracks with the same dislike / recent / served filters
- every served track is an impression with its source and model; wave
  events (context_type wave) set its outcome, reactions win
- library status shows the analysis queue and 7-day wave metrics:
  listen-through, early skip and like rate

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mrleo1nidandClaude Opus 5.5 committed 2026-10-20 12:23:17 +03:00
1 parent ef29b85320
commit 3908814cda
13 files changed
+1811 -162

No files matched your search

+254
View File
@@ -809,6 +809,79 @@ export interface paths {
patch?: never;
trace?: never;
};
"/api/v1/wave/options": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/** Занятия и настроения (ключи для i18n и иконки) */
get: operations["getWaveOptions"];
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/api/v1/wave/sessions": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get?: never;
put?: never;
/** Начать «Мою волну» */
post: operations["startWave"];
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/api/v1/wave/sessions/{id}": {
parameters: {
query?: never;
header?: never;
path: {
id: components["parameters"]["EntityId"];
};
cookie?: never;
};
get?: never;
put?: never;
post?: never;
/** Завершить сессию волны */
delete: operations["endWave"];
options?: never;
head?: never;
/** Сменить занятие / настроение на лету — пачка пересобирается */
patch: operations["updateWave"];
trace?: never;
};
"/api/v1/wave/sessions/{id}/next": {
parameters: {
query?: never;
header?: never;
path: {
id: components["parameters"]["EntityId"];
};
cookie?: never;
};
get?: never;
put?: never;
/** Следующая пачка с учётом реакций на выданные треки */
post: operations["nextWave"];
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
}
export type webhooks = Record<string, never>;
export interface components {
@@ -1098,6 +1171,8 @@ export interface components {
error: string | null;
};
LibraryStatus: {
analysis: components["schemas"]["AnalysisStatus"];
wave: components["schemas"]["WaveMetrics"];
artists: number;
albums: number;
tracks: number;
@@ -1306,6 +1381,64 @@ export interface components {
ReactionInput: {
reaction: components["schemas"]["Reaction"];
};
WaveOption: {
/** @example running */
key: string;
/** @description Имя иконки Material Symbols */
icon: string;
};
WaveOptions: {
activities: components["schemas"]["WaveOption"][];
moods: components["schemas"]["WaveOption"][];
};
WaveContext: {
activity?: string | null;
mood?: string | null;
};
WaveStart: {
activity?: string | null;
mood?: string | null;
seed?: {
/** @enum {string} */
type: "track" | "album" | "artist";
/** Format: uuid */
id: string;
};
};
WaveFeedback: {
/** Format: uuid */
track_id: string;
/** @enum {string} */
outcome: "complete" | "skip" | "skip_early" | "like" | "dislike";
};
WaveNext: {
feedback?: components["schemas"]["WaveFeedback"][];
};
WaveBatch: {
/** Format: uuid */
session_id: string;
activity: string | null;
mood: string | null;
tracks: components["schemas"]["Track"][];
/** @description Рекомендатель недоступен — пачка собрана упрощённо (лайки, любимые исполнители) */
fallback: boolean;
};
AnalysisStatus: {
queued: number;
running: number;
done: number;
failed: number;
analyzer_ver: string | null;
};
/** @description Метрики волны за 7 дней */
WaveMetrics: {
served: number;
listen_through_rate: number | null;
early_skip_rate: number | null;
/** @description Лайков на 100 треков */
like_rate: number | null;
sessions: number;
};
Session: {
/** Format: uuid */
id: string;
@@ -2580,4 +2713,125 @@ export interface operations {
default: components["responses"]["Problem"];
};
};
getWaveOptions: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description Варианты */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["WaveOptions"];
};
};
default: components["responses"]["Problem"];
};
};
startWave: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody?: {
content: {
"application/json": components["schemas"]["WaveStart"];
};
};
responses: {
/** @description Сессия и первая пачка */
201: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["WaveBatch"];
};
};
default: components["responses"]["Problem"];
};
};
endWave: {
parameters: {
query?: never;
header?: never;
path: {
id: components["parameters"]["EntityId"];
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description Завершена */
204: {
headers: {
[name: string]: unknown;
};
content?: never;
};
default: components["responses"]["Problem"];
};
};
updateWave: {
parameters: {
query?: never;
header?: never;
path: {
id: components["parameters"]["EntityId"];
};
cookie?: never;
};
requestBody: {
content: {
"application/json": components["schemas"]["WaveContext"];
};
};
responses: {
/** @description Новая пачка */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["WaveBatch"];
};
};
default: components["responses"]["Problem"];
};
};
nextWave: {
parameters: {
query?: never;
header?: never;
path: {
id: components["parameters"]["EntityId"];
};
cookie?: never;
};
requestBody?: {
content: {
"application/json": components["schemas"]["WaveNext"];
};
};
responses: {
/** @description Пачка */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["WaveBatch"];
};
};
default: components["responses"]["Problem"];
};
};
}