postStreamRaw method

Stream<String> postStreamRaw(
  1. String endpoint,
  2. Map<String, dynamic> body
)

Make a POST request and return SSE stream

Implementation

Stream<String> postStreamRaw(
  String endpoint,
  Map<String, dynamic> body,
) async* {
  if (config.apiKey.isEmpty) {
    throw const AuthError('Missing OpenAI API key');
  }

  // Reset SSE buffer for new stream
  resetSSEBuffer();

  try {
    if (logger.isLoggable(Level.FINE)) {
      logger.fine('OpenAI request: POST /$endpoint (stream)');
      logger.fine('OpenAI request headers: ${dio.options.headers}');
    }

    final response = await dio.post(
      endpoint,
      data: body,
      options: Options(
        responseType: ResponseType.stream,
        headers: {'Accept': 'text/event-stream'},
      ),
    );

    if (response.statusCode != 200) {
      _handleErrorResponse(response, endpoint);
    }

    // Handle ResponseBody properly for streaming
    final responseBody = response.data;
    Stream<List<int>> stream;

    if (responseBody is Stream<List<int>>) {
      stream = responseBody;
    } else if (responseBody is ResponseBody) {
      stream = responseBody.stream;
    } else {
      throw GenericError(
          'Unexpected response type: ${responseBody.runtimeType}');
    }

    // Use UTF-8 stream decoder to handle incomplete byte sequences
    final decoder = Utf8StreamDecoder();

    await for (final chunk in stream) {
      final decoded = decoder.decode(chunk);
      if (decoded.isNotEmpty) {
        yield decoded;
      }
    }

    // Flush any remaining bytes
    final remaining = decoder.flush();
    if (remaining.isNotEmpty) {
      yield remaining;
    }
  } on DioException catch (e) {
    throw handleDioError(e);
  } catch (e) {
    throw GenericError('Unexpected error: $e');
  }
}