anasfik / openai

Dart/Flutter SDK for ChatGPT and all OpenAI APIs (GPT, Dall-e..)
https://pub.dev/packages/dart_openai
MIT License
539 stars 151 forks source link

“createStream” method may lead to duplicate invocations of listeners. #173

Open NingNing0111 opened 2 months ago

NingNing0111 commented 2 months ago

Test Code

  test('chat stream', () async {
    OpenAI.baseUrl = "https://api.openai.com";
    OpenAI.apiKey = "sk-**********";
    var createStream =
        OpenAI.instance.chat.createStream(model: "gpt-3.5-turbo", messages: [
      OpenAIChatCompletionChoiceMessageModel(
          role: OpenAIChatMessageRole.user,
          content: [
            OpenAIChatCompletionChoiceMessageContentItemModel.text("Hi!")
          ])
    ]);

    final completer = Completer<bool>();
    // Count the number of calls
    var count = 0;
    // Merge results
    var assistant = "";
    createStream.listen((event) {
      count++;
      final content = event.choices.first.delta.content;
      if (content != null) {
        assistant = assistant + content.first!.text!;
      }
    }, onDone: () {
      completer.complete(true);
      print(assistant);
      print(count);
    });
    await completer.future;
  });

Logs

Hello! How can I assist you today?Hello! How can I assist you today?Hello! How can I assist you today?Hello! How can I assist you today?Hello! How can I assist you today?Hello! How can I help you today?Hello! How can I assist you today?Hello! How can I assist you today?Hello! How can I assist you today?Hello! How can I assist you today?Hello! How can I help you today?
121

 If my processing method is incorrect, how can I correctly obtain unique values?

anasfik commented 1 month ago

I guess there was some external factor that made this function behavior, I just copied your code and runned it, and this was the response:

image

can you retry again, so you make sure if the issue is caused by the package or from the API itself

NingNing0111 commented 1 month ago

I'm currently learning to use OpenAI in Flutter. I recreated a simple demo to demonstrate how I use OpenAI in Flutter, but unfortunately, the issue still persists.

import 'dart:async';

import 'package:dart_openai/dart_openai.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String _result="";
  int _count = 0;
  int _countFun = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(_result),
            const SizedBox(height: 50,),
            Text("Count: $_count"),
            const SizedBox(height: 50,),
            Text("Count Function: $_countFun"),
          ],
        ),
      ),
      floatingActionButton: TextButton(
        onPressed: _chatStream,
        child: Container(
          padding: const EdgeInsets.all(5),
            child: const Text("Get Stream Response")),
      ),
    );
  }

  Future<void> _chatStream() async {

    setState(() {
      // count the number of _chatStream method
      _countFun ++;
    });

    OpenAI.baseUrl = "https://api.openai.com";
    OpenAI.apiKey = "sk-****";

    var createStream =
        OpenAI.instance.chat.createStream(model: "gpt-3.5-turbo", messages: [
      OpenAIChatCompletionChoiceMessageModel(
          role: OpenAIChatMessageRole.user,
          content: [
            OpenAIChatCompletionChoiceMessageContentItemModel.text("Hi!")
          ])
    ]);
    final completer = Completer<bool>();
    // Count the number of calls
    var count = 0;
    // Merge results
    var assistant = "";
    createStream.listen((event) {
      count++;
      final content = event.choices.first.delta.content;
      if (content != null) {
        assistant = assistant + content.first!.text!;

        setState(() {
          _result = assistant;
          _count = count;

        });
      }
    }, onDone: () {
      completer.complete(true);
    });
    await completer.future;
  }
}

 In my pubspec.yaml, I only imported the dependency dart_openai.

image

 The results are shown in the figure.I am speculating whether I am handling asynchronous streams incorrectly.

NingNing0111 commented 1 month ago
image