| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- import 'dart:convert';
- import 'package:http/http.dart' as http;
- import '../data/models/analysis_models.dart';
- class AnalysisApiService {
- AnalysisApiService({http.Client? client, String? baseUrl})
- : _client = client ?? http.Client(),
- _baseUri = _normalizeBaseUri(baseUrl ?? 'http://127.0.0.1:8000/api');
- final http.Client _client;
- final Uri _baseUri;
- Future<ObservationSummary> createObservation({
- required int durationMs,
- required int sampleRate,
- required int channels,
- List<String> tags = const [],
- Map<String, dynamic> captureMetadata = const {},
- }) async {
- final response = await _client.post(
- _endpointUri('observations'),
- headers: {'Content-Type': 'application/json'},
- body: jsonEncode({
- 'modality': 'audio',
- 'duration_ms': durationMs,
- 'sample_rate': sampleRate,
- 'channels': channels,
- 'tags': tags,
- 'capture_metadata': captureMetadata,
- }),
- );
- return ObservationSummary.fromJson(
- _decodeJson(response) as Map<String, dynamic>,
- );
- }
- Future<ObservationSummary> uploadObservation({
- required String filePath,
- required int durationMs,
- required int sampleRate,
- required int channels,
- List<String> tags = const [],
- Map<String, dynamic> captureMetadata = const {},
- }) async {
- final request = http.MultipartRequest(
- 'POST',
- _endpointUri('observations/upload'),
- );
- request.fields['duration_ms'] = '$durationMs';
- request.fields['sample_rate'] = '$sampleRate';
- request.fields['channels'] = '$channels';
- request.fields['tags_json'] = jsonEncode(tags);
- request.fields['capture_metadata_json'] = jsonEncode(captureMetadata);
- request.files.add(
- await http.MultipartFile.fromPath('audio_file', filePath),
- );
- final streamed = await request.send();
- final response = await http.Response.fromStream(streamed);
- return ObservationSummary.fromJson(
- _decodeJson(response) as Map<String, dynamic>,
- );
- }
- Future<AnalysisSessionSummary> createSession({
- required String observationId,
- String mode = 'initial_analysis',
- }) async {
- final response = await _client.post(
- _endpointUri('analysis/sessions'),
- headers: {'Content-Type': 'application/json'},
- body: jsonEncode({'observation_id': observationId, 'mode': mode}),
- );
- return AnalysisSessionSummary.fromJson(
- _decodeJson(response) as Map<String, dynamic>,
- );
- }
- Future<List<AnalysisSessionSummary>> listSessions() async {
- final response = await _client.get(_endpointUri('analysis/sessions'));
- final json = _decodeJson(response) as Map<String, dynamic>;
- final items = (json['items'] as List<dynamic>? ?? const []);
- return items
- .map(
- (item) =>
- AnalysisSessionSummary.fromJson(item as Map<String, dynamic>),
- )
- .toList();
- }
- Future<List<ObservationSummary>> listObservations() async {
- final response = await _client.get(_endpointUri('observations'));
- final json = _decodeJson(response) as Map<String, dynamic>;
- final items = (json['items'] as List<dynamic>? ?? const []);
- return items
- .map(
- (item) => ObservationSummary.fromJson(item as Map<String, dynamic>),
- )
- .toList();
- }
- Future<ObservationSummary> getObservation(String observationId) async {
- final response = await _client.get(_endpointUri('observations/$observationId'));
- return ObservationSummary.fromJson(
- _decodeJson(response) as Map<String, dynamic>,
- );
- }
- Future<AnalysisSessionSnapshot> getSession(String sessionId) async {
- final response = await _client.get(
- _endpointUri('analysis/sessions/$sessionId'),
- );
- return AnalysisSessionSnapshot.fromJson(
- _decodeJson(response) as Map<String, dynamic>,
- );
- }
- Object _decodeJson(http.Response response) {
- if (response.statusCode < 200 || response.statusCode >= 300) {
- throw AnalysisApiException(
- 'Backend request failed with status ${response.statusCode}: ${response.body}',
- );
- }
- return jsonDecode(response.body);
- }
- Uri _endpointUri(String path) => _baseUri.resolve(path);
- static Uri _normalizeBaseUri(String rawBaseUrl) {
- final normalized = rawBaseUrl.endsWith('/') ? rawBaseUrl : '$rawBaseUrl/';
- return Uri.parse(normalized);
- }
- }
- class AnalysisApiException implements Exception {
- AnalysisApiException(this.message);
- final String message;
- @override
- String toString() => message;
- }
|