b30ce86fa9
Revert of A9 address change. The .108 value was inferred from the container VMID (108), not from its actual network config: net0 is ip=dhcp and the container currently holds 192.168.0.99. Requests to .108 fail with "No route to host", making the UI look down while all four compose services are healthy. A9 section in vector_tasks.md is kept as history and flagged stale so the .99 -> .108 replacement is not repeated. Note: the address is DHCP-assigned and may change again; a static IP would be needed to make these docs durable. Hardcoded .99 URLs remain in MobileForm.jsx:49 and HeatmapView.jsx:73 (tracked in vector_tasks.md, untouched here). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
184 lines
5.6 KiB
Markdown
184 lines
5.6 KiB
Markdown
# Сервисы анализа SAR-MCHS
|
||
|
||
## Обзор
|
||
|
||
Созданы два основных сервиса для анализа поисково-спасательных операций:
|
||
|
||
### 1. Claude Service (`backend/services/claude_service.py`)
|
||
|
||
**Функция:** `analyze_case(case_data: dict) -> AnalysisResult`
|
||
|
||
Использует Claude API (модель `claude-sonnet-4-20250514`) для интеллектуального анализа случаев пропажи людей.
|
||
|
||
**Входные данные (case_data):**
|
||
- `age` - возраст пропавшего
|
||
- `gender` - пол
|
||
- `terrain` - тип местности
|
||
- `weather` - погодные условия
|
||
- `time_missing` - время пропажи
|
||
- `last_location` - последнее известное местоположение
|
||
- `circumstances` - особые обстоятельства
|
||
- `physical_condition` - физическое состояние
|
||
- `experience` - опыт нахождения на природе
|
||
|
||
**Возвращаемые данные (AnalysisResult):**
|
||
```python
|
||
{
|
||
"urgency": "критическая|высокая|средняя|низкая",
|
||
"primary_zones": [
|
||
{
|
||
"priority": 1,
|
||
"name": "Зона А",
|
||
"direction": "север",
|
||
"distance": 2.5,
|
||
"reason": "Обоснование выбора"
|
||
}
|
||
],
|
||
"search_radius_km": 5.0,
|
||
"key_locations": ["водоемы", "дороги", "постройки"],
|
||
"team_assignments": {
|
||
"команда_1": "зона А",
|
||
"команда_2": "зона Б"
|
||
},
|
||
"behavioral_prediction": "Прогноз поведения",
|
||
"immediate_actions": ["Действие 1", "Действие 2"],
|
||
"summary": "Краткое резюме"
|
||
}
|
||
```
|
||
|
||
### 2. Stats Service (`backend/services/stats_service.py`)
|
||
|
||
**Функция:** `get_statistical_recommendation(case_data: dict, db_session: AsyncSession) -> StatsResult`
|
||
|
||
Анализирует исторические данные из базы для получения статистических рекомендаций.
|
||
|
||
**Входные данные:**
|
||
- `age` - возраст (±2 года для фильтрации)
|
||
- `season` - сезон (winter, spring, summer, autumn)
|
||
- `terrain_primary` - основной тип местности
|
||
|
||
**Логика фильтрации:**
|
||
1. Первая попытка: возраст ±2 года + сезон + terrain
|
||
2. Если sample_size < 5: возраст ±2 года + сезон (без terrain)
|
||
3. Если данных нет: возвращает дефолтные значения
|
||
|
||
**Возвращаемые данные (StatsResult):**
|
||
```python
|
||
{
|
||
"median_distance_km": 2.5,
|
||
"top_directions": [
|
||
{
|
||
"direction": "север",
|
||
"count": 15,
|
||
"percentage": 35.0
|
||
}
|
||
],
|
||
"top_location_types": ["водоемы", "дороги", "лесные тропы"],
|
||
"survival_rate": 87.5,
|
||
"sample_size": 43
|
||
}
|
||
```
|
||
|
||
## API Endpoints
|
||
|
||
### POST `/api/v1/analyze/text`
|
||
|
||
Анализ случая с помощью Claude AI.
|
||
|
||
**Request:**
|
||
```json
|
||
{
|
||
"age": 65,
|
||
"gender": "мужской",
|
||
"terrain": "лес",
|
||
"weather": "дождь",
|
||
"time_missing": "6 часов",
|
||
"last_location": "лесная тропа у озера",
|
||
"circumstances": "вышел за грибами",
|
||
"physical_condition": "хорошее",
|
||
"experience": "опытный грибник"
|
||
}
|
||
```
|
||
|
||
**Response:** `AnalysisResult`
|
||
|
||
### POST `/api/v1/analyze/combined`
|
||
|
||
Комбинированный анализ: Claude AI + статистические данные.
|
||
|
||
**Request:** Тот же формат, что и `/text`
|
||
|
||
**Response:**
|
||
```json
|
||
{
|
||
"claude_analysis": { /* AnalysisResult */ },
|
||
"statistical_data": { /* StatsResult */ }
|
||
}
|
||
```
|
||
|
||
### POST `/api/v1/analyze/document`
|
||
|
||
Анализ загруженного документа (пока поддерживается только .txt).
|
||
|
||
**Request:** multipart/form-data с файлом
|
||
|
||
**Response:** `AnalysisResult`
|
||
|
||
## Настройка
|
||
|
||
### Переменные окружения
|
||
|
||
В файле `.env` должен быть установлен:
|
||
```
|
||
ANTHROPIC_API_KEY=your_api_key_here
|
||
```
|
||
|
||
### База данных
|
||
|
||
Для работы `stats_service` требуется таблица `cases` со следующими полями:
|
||
- `age` (integer)
|
||
- `season` (string)
|
||
- `terrain_primary` (string)
|
||
- `found_distance_km` (float)
|
||
- `found_direction` (string)
|
||
- `found_location_type` (string)
|
||
- `outcome` (string: 'alive', 'found_alive', etc.)
|
||
|
||
## Тестирование
|
||
|
||
### Тест Claude Service
|
||
|
||
```bash
|
||
curl -X POST http://192.168.0.99:8000/api/v1/analyze/text \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"age": 65,
|
||
"gender": "мужской",
|
||
"terrain": "лес",
|
||
"weather": "дождь",
|
||
"time_missing": "6 часов",
|
||
"last_location": "лесная тропа у озера"
|
||
}'
|
||
```
|
||
|
||
### Тест Combined Analysis
|
||
|
||
```bash
|
||
curl -X POST http://192.168.0.99:8000/api/v1/analyze/combined \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"age": 65,
|
||
"season": "autumn",
|
||
"terrain_primary": "forest"
|
||
}'
|
||
```
|
||
|
||
## TODO
|
||
|
||
- [ ] Настроить подключение к базе данных
|
||
- [ ] Добавить миграции Alembic для таблицы cases
|
||
- [ ] Реализовать извлечение текста из .docx и .pdf
|
||
- [ ] Добавить кэширование результатов анализа
|
||
- [ ] Добавить rate limiting для API запросов
|
||
- [ ] Добавить логирование запросов и ответов
|