# Індикатори настрою

> GET /3/movie/{movie_id}/moods і GET /3/tv/{tv_id}/moods повертають source та список results. Кожен результат має назву настрою, наприклад fear чи humor, значення avg за шкалою від 0 до 10 і значення, на яких воно ґрунтується. Додайте append_to_response=moods до виклику деталей, щоб підтягнути індикатори без другого запиту.

## Ендпоінт

`GET /3/movie/{movie_id}/moods`

```bash
curl "https://api.amodb.dev/3/movie/155/moods" \
  -H "Authorization: Bearer $AMODB_KEY"
```

Відповідь:

```json
{
  "id": 155,
  "source": "measured",
  "results": [
    {
      "name": "action",
      "avg": 3.9,
      "values": [
        3.6,
        3.4,
        4.2
      ]
    },
    {
      "name": "fear",
      "avg": 5.2,
      "values": [
        3.6,
        6,
        4.8
      ]
    },
    {
      "name": "humor",
      "avg": 0.9,
      "values": [
        2.4,
        1.8,
        0.4
      ]
    }
  ]
}
```

## Отримання індикаторів настрою фільму

`GET /3/movie/{movie_id}/moods` повертає індикатори настрою одного фільму. Індикатор настрою складається з назви та середнього значення за шкалою від 0 до 10. Відповідь містить `id` фільму, `source` і масив `results`. Кожен результат має `name`, `avg` і `values`.

Приклад завантажує індикатори для The Dark Knight (id 155) і виводить їх від найсильнішого до найслабшого.

```bash
curl -sf "https://api.amodb.dev/3/movie/155/moods" \
  -H "Authorization: Bearer $AMODB_KEY"
```

```js
const res = await fetch('https://api.amodb.dev/3/movie/155/moods', {
  headers: { Authorization: `Bearer ${process.env.AMODB_KEY}` },
});
if (!res.ok) throw new Error(`amodb returned ${res.status}`);
const { source, results } = await res.json();
console.log('source:', source);
for (const m of [...results].sort((a, b) => b.avg - a.avg)) {
  console.log(m.name.padEnd(10), m.avg);
}
```

```python
import os
import requests

r = requests.get(
    "https://api.amodb.dev/3/movie/155/moods",
    headers={"Authorization": f"Bearer {os.environ['AMODB_KEY']}"},
    timeout=10,
)
r.raise_for_status()
data = r.json()
print("source:", data.get("source"))
for m in sorted(data["results"], key=lambda m: m["avg"], reverse=True):
    print(f"{m['name']:<10} {m['avg']}")
```

```php
<?php
$ch = curl_init('https://api.amodb.dev/3/movie/155/moods');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 10,
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('AMODB_KEY')],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status !== 200) {
    throw new RuntimeException("amodb returned $status");
}
$data = json_decode($body, true);
echo 'source: ', $data['source'] ?? 'none', PHP_EOL;
$results = $data['results'];
usort($results, fn ($a, $b) => $b['avg'] <=> $a['avg']);
foreach ($results as $m) {
    printf("%-10s %.1f\n", $m['name'], $m['avg']);
}
```

```go
package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"sort"
	"time"
)

type Mood struct {
	Name   string    `json:"name"`
	Avg    float64   `json:"avg"`
	Values []float64 `json:"values"`
}

func main() {
	req, _ := http.NewRequest("GET", "https://api.amodb.dev/3/movie/155/moods", nil)
	req.Header.Set("Authorization", "Bearer "+os.Getenv("AMODB_KEY"))
	client := &http.Client{Timeout: 10 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	if res.StatusCode != http.StatusOK {
		panic(res.Status)
	}
	var body struct {
		Source  string `json:"source"`
		Results []Mood `json:"results"`
	}
	if err := json.NewDecoder(res.Body).Decode(&body); err != nil {
		panic(err)
	}
	fmt.Println("source:", body.Source)
	sort.Slice(body.Results, func(i, j int) bool { return body.Results[i].Avg > body.Results[j].Avg })
	for _, m := range body.Results {
		fmt.Printf("%-10s %.1f\n", m.Name, m.Avg)
	}
}
```

### Параметри

| Параметр   | Де           | Обов'язковий | Опис                                                                 |
| ---------- | ------------ | ------------ | -------------------------------------------------------------------- |
| `movie_id` | шлях         | так          | Числовий id фільму, наприклад `155`.                                 |
| `api_key`  | рядок запиту | один із двох | Ваш ключ. Використовуйте його або заголовок `Authorization: Bearer`. |

### Поля відповіді

| Поле               | Тип            | Примітки                                                                                                   |
| ------------------ | -------------- | ---------------------------------------------------------------------------------------------------------- |
| `id`               | ціле число     | Id фільму.                                                                                                 |
| `source`           | рядок або null | `measured` для даних глядачів, `estimated`, коли виведено з жанрів, `null`, коли для фільму немає даних.   |
| `results`          | масив          | Індикатори настрою, відсортовані за `name`. Порожній, коли нічого не відомо.                               |
| `results[].name`   | рядок          | Коротке слово малими літерами, наприклад `fear`.                                                           |
| `results[].avg`    | число          | Середнє за шкалою від 0 до 10. Один десятковий знак для виміряних фільмів, ціле число для оцінених.        |
| `results[].values` | масив чисел    | До 24 показань за тією самою шкалою від 0 до 10. У наявних даних виміряні фільми мають 6, оцінені мають 5. |

Сьогодні трапляються назви `action`, `fear`, `humor`, `pace`, `profanity`, `romance`, `sadness`, `sex` і `violence`. Не кожен фільм має всі дев'ять, тому показуйте назви з даних, а не з фіксованого списку.

### Приклад відповіді

```json
{
  "id": 155,
  "source": "measured",
  "results": [
    { "name": "action", "avg": 3.9, "values": [3.6, 3.4, 4.2, 4.2, 4.8, 3] },
    { "name": "fear", "avg": 5.2, "values": [3.6, 6, 4.8, 6.4, 6.4, 3.8] },
    { "name": "humor", "avg": 0.9, "values": [2.4, 1.8, 0.4, 0.4, 0, 0.5] }
  ]
}
```

Список скорочено до 3 із 9 результатів.

### Виміряні й оцінені фільми

Fight Club (id 550) поки не має даних глядачів, тому його індикатори виведено з жанрів. Кожне `avg` є цілим числом, а `values` містить 5 елементів.

```json
{
  "id": 550,
  "source": "estimated",
  "results": [
    { "name": "action", "avg": 4, "values": [3, 4, 5, 4, 3] },
    { "name": "fear", "avg": 7, "values": [6, 7, 8, 7, 6] }
  ]
}
```

Перевіряйте `source`, якщо хочете обробляти оцінені індикатори інакше, ніж виміряні.

## Отримання індикаторів настрою серіалу

`GET /3/tv/{tv_id}/moods` має ту саму форму відповіді, з id серіалу в `id`. Для Breaking Bad використовуйте `1396`.

| Метод і шлях                  | Повертає                         | Параметри                              |
| ----------------------------- | -------------------------------- | -------------------------------------- |
| `GET /movie/{movie_id}/moods` | `id`, `source` і `results`       | `movie_id`                             |
| `GET /tv/{tv_id}/moods`       | `id`, `source` і `results`       | `tv_id`                                |
| `append_to_response=moods`    | `source` і `results` під `moods` | Додається до деталей фільму чи серіалу |

```bash
curl -sf "https://api.amodb.dev/3/tv/1396?append_to_response=moods" -H "Authorization: Bearer $AMODB_KEY"
```

Коли ви додаєте `moods` до виклику деталей, ключ `moods` стоїть на верхньому рівні запису поряд із `title` або `name`. Він містить `source` і `results` та не має власного `id`. Це коштує один запит, тоді як два окремі виклики коштують два.

## Як читати шкалу

Поле `avg` є інтенсивністю від 0 до 10. Більше число означає сильніший настрій у фільмі.

| Діапазон     | Тлумачення                     |
| ------------ | ------------------------------ |
| від 0 до 2.9 | Настрій слабкий або відсутній. |
| від 3 до 5.9 | Настрій присутній.             |
| від 6 до 7.9 | Настрій виразний.              |
| від 8 до 10  | Настрій визначає фільм.        |

Ці діапазони є порадою для вашого інтерфейсу, а не полем відповіді. Масив `values` містить показання, на яких ґрунтується середнє, за тією самою шкалою.

## Бейджі та фільтри

Настрої підходять для трьох поширених шаблонів інтерфейсу. Підберіть пороги під свій каталог і налаштуйте їх.

| Шаблон           | Правило                                                    | Примітки                                                            |
| ---------------- | ---------------------------------------------------------- | ------------------------------------------------------------------- |
| Бейдж            | Показуйте до 3 настроїв із `avg` 6 або вище                | Спершу відсортуйте за `avg`.                                        |
| Смуга індикатора | Задайте ширину смуги як `avg` помножене на 10 у відсотках  | Шкала йде від 0 до 10.                                              |
| Чип фільтра      | Підбирайте фільми, де вибраний настрій дорівнює 7 або вище | Отримайте індикатори для кожного фільму, потім фільтруйте локально. |

```js
function topMoods(results, min = 6, limit = 3) {
  return results
    .filter((m) => m.avg >= min)
    .sort((a, b) => b.avg - a.avg)
    .slice(0, limit)
    .map((m) => m.name);
}

function matchesMood(results, name, min = 7) {
  return results.some((m) => m.name === name && m.avg >= min);
}
```

Порожній масив `results` слід показувати як відсутність бейджів, а не як помилку.

## Помилки

Тіло помилки містить `success`, `status_code` і `status_message`, ті самі поля, що використовує TMDB.

| HTTP | status_code | Коли                                                                              |
| ---- | ----------- | --------------------------------------------------------------------------------- |
| 401  | 7           | Ключ відсутній або хибний.                                                        |
| 402  | 36          | Період дії тарифу закінчився.                                                     |
| 429  | 25          | Перевищено ліміт запитів на хвилину. Зачекайте кількість секунд із `Retry-After`. |

Ендпоінт moods не відповідає 404 для невідомого id. Він відповідає 200 з порожнім масивом `results`, а `source` дорівнює `null` або відсутній. Якщо додавати до деталей, невідомий id дає 404 від виклику деталей. Повний список на сторінці [помилки](https://amodb.dev/uk/errors/), а ліміти на сторінці [ліміти запитів](https://amodb.dev/uk/rate-limits/).

## Практичні поради

- Як і інші дані деталей, індикатори настрою кешуються на периферії мережі на 6 годин. Частіші запити повертають те саме тіло.
- Для списку з 20 фільмів потрібно 20 запитів настроїв. Якщо ви вже викликаєте деталі для кожного фільму, додайте `moods` і заощадьте другий виклик.
- Перевіряйте `source`, перш ніж порівнювати фільми. Виміряні й оцінені індикатори мають однакову шкалу, але не однакову точність.
- Якщо часто фільтруєте, зберігайте `name` і `avg` разом з id фільму у власній базі даних. Локальний фільтр кращий за запит на кожен фільм.
- Для оцінки дивіться [рейтинги](https://amodb.dev/uk/ratings/), для музики в тому самому фільмі [саундтреки](https://amodb.dev/uk/soundtracks/).

## Запитання й відповіді

### Що означає значення настрою?

Поле avg є інтенсивністю за шкалою від 0 до 10, з одним десятковим знаком для виміряних фільмів. Значення avg 7 для fear означає, що фільм страшний, а 0 означає відсутність настрою. Це не відсоток і не оцінка рецензії.

### Чи фіксований список назв настроїв?

Не вважайте його фіксованим. Сьогодні трапляються назви action, fear, humor, pace, profanity, romance, sadness, sex і violence, а фільм може мати менше дев'яти. Показуйте рядки назв, які отримуєте, щоб нова теж з'явилася.

### Що означають measured та estimated у source?

Measured означає, що індикатори ґрунтуються на даних глядачів і мають десяткові знаки. Estimated означає, що їх виведено з жанрів фільму, тому avg є цілим числом. Фільм без даних має порожній масив results, а source дорівнює null.

### Як відфільтрувати список фільмів за настроєм?

Отримайте індикатори для кожного фільму зі списку, через ендпоінт moods або через append_to_response у деталях, і залишіть ті фільми, де вибраний настрій проходить ваш поріг. Фільтр виконується у вашому коді.

### Чи є настрої в серіалів?

Так. Використовуйте GET /3/tv/{tv_id}/moods, наприклад з id серіалу 1396. Відповідь має ту саму форму, що й ендпоінт для фільмів.

## Пов'язані сторінки

- [API деталей фільму](https://amodb.dev/uk/movies/): API деталей фільму з тими самими шляхами та JSON, що в TMDB v3. Отримайте фільм за id, додайте акторів, рейтинги й настрої через append_to_response, 14 мовами.
- [API серіалів](https://amodb.dev/uk/tv-series/): API серіалів з тими самими шляхами та JSON, що в TMDB v3. Отримайте серіал за id із сезонами, телемережами й наступною серією, плюс вікові рейтинги.
- [Рейтинги фільмів і серіалів](https://amodb.dev/uk/ratings/): API рейтингів фільмів повертає оцінки IMDb, Kinopoisk, Metacritic, Rotten Tomatoes і TMDB для фільму чи серіалу одним викликом, з null для невідомих джерел.
- [Саундтреки](https://amodb.dev/uk/soundtracks/): API саундтреків повертає альбом саундтреку фільму чи серіалу зі списком треків. Викличте ендпоінт або додайте append_to_response=soundtracks до деталей.
- [Discover API](https://amodb.dev/uk/discover/): Discover API з тими самими фільтрами, що й у TMDB v3. Фільми та серіали за жанром, акторами, компанією, роком, рейтингом, тривалістю й провайдером.
- [Швидкий старт](https://amodb.dev/uk/quickstart/): Перший виклик amodb: отримайте ключ, запросіть деталі фільму в curl, JavaScript, Python, PHP чи Go і завантажте постер з img.amodb.dev. Менш ніж за 2 хвилини.

Оновлено: 2026-10-18. Source: https://amodb.dev/uk/moods/
