Skip to content
This repository has been archived by the owner on Jun 6, 2024. It is now read-only.

Still experiencing "Unrecognized token 'data': was expecting..." when using stream(true)...code works fine when stream(false) is set. #83

Closed
mcfasa09 opened this issue Feb 3, 2023 · 8 comments

Comments

@mcfasa09
Copy link

mcfasa09 commented Feb 3, 2023

This issue was set to "Closed" (issue #52), but I am still having the same issue despite trying the recommended fix. I've been pulling my hair out with this one for three days. Please help?

Here is my code that gives the error in the logcat, "Unrecognized token 'data': was expecting (JSON String, Number, Array, Object or token 'null', 'true' or 'false')":

From another method:
        final Duration ai_timeout = Duration.ofSeconds(75);
        service = new OpenAiService("MY_API_KEY_GOES_HERE", ai_timeout);
        String userInput = binding.fragmentMainUsersEditTextToAi.getText().toString();
        new OpenAITask().execute(userInput);


String Username;
private class OpenAITask extends AsyncTask<String, Void, String> {
    @Override
    protected String doInBackground(String... params) {

        SetThreadPolicy();

        //TODO: Set username to "Username" variable to the users username:
        Username = "Username goes here.";

        String question = params[0];
        String response = "";

        CompletionRequest request = CompletionRequest.builder()
                .prompt(question)
                .model("text-davinci-003")
                .maxTokens(220)
                .topP(0.1)
                .stream(Boolean.TRUE) //TODO: Figure out why setting .stream(true) causes the error: Unrecognized token 'data': was expecting (JSON String, Number, Array, Object or token 'null', 'true' or 'false')
                .echo(false)
                .frequencyPenalty(0.0)
                .user(Username)
                .build();

        List<String> responses = null;

        try {
            responses = service.createCompletion(request)
                    .getChoices()
                    .stream()
                    .map(CompletionChoice::getText)
                    .collect(Collectors.toList());

            System.out.println(responses);

            if (responses != null && responses.size() > 0) {
                responses.stream().forEach(System.out::println);
                response = responses.get(0);
            } else {
                System.out.println("Response is null or size=0");
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return response;
    }


    @Override
    protected void onPostExecute(String response) {
        if (response != null && !response.isEmpty()) {
            Log.d("Debug", "response: " + response);

            messagesAdapter.appendMessage(new com.wiscoapps.askai.Message(response.trim(), false)); //Note: ".trim()" will remove any leading or trailing whitespace or line breaks from the response before appending the text.

            storeMessagesAndRecyclerViewPositionToSharedPreferences();

            messagesAdapter.notifyItemInserted(messagesAdapter.getItemCount() - 1);

            // Smooth scroll to the last item in the RecyclerView:
            retrieveMessagesFromSharedPreferences();
            LinearLayoutManager layoutManager = ((LinearLayoutManager) binding.messagesRecyclerView.getLayoutManager());
            if (layoutManager != null && layoutManager.findLastCompletelyVisibleItemPosition() < messagesAdapter.getItemCount() - 1) {
                binding.messagesRecyclerView.requestLayout();
                if (binding.messagesRecyclerView.getLayoutManager() instanceof LinearLayoutManager) {
                    LinearLayoutManager linearLayoutManager = (LinearLayoutManager) binding.messagesRecyclerView.getLayoutManager();
                    linearLayoutManager.smoothScrollToPosition(binding.messagesRecyclerView, null, messagesAdapter.getItemCount() - 1);
                }
            }

            //TODO: HANDLE EXCEPTIONS/ALERT USER...like if the user hasn't input an API...an invalid API is input...no internet connection...etc.
        }
    }
@cryptoapebot
Copy link

cryptoapebot commented Feb 3, 2023

Can you print your prompt out? I want to make sure you don't have to quote it.

String question = "\" + params[0] + "\"";

@mcfasa09
Copy link
Author

mcfasa09 commented Feb 3, 2023

Thanks for the reply. That does not change the issue. I can type in a string for the prompt as well, and the same result happens.

@cryptoapebot
Copy link

Let me experiment.

This from the code:
* Whether to stream back partial progress.
* If set, tokens will be sent as data-only server-sent events as they become available,
* with the stream terminated by a data: DONE message.

I'm wondering if you need to define a get output stream? I don't know the exact syntax w/o testing it yet.

			BufferedReader bri = new BufferedReader(new InputStreamReader(service.createCompletion.getInputStream()));
			String line;
			while ((line = bri.readLine()) != null) {
				System.out.println(line);
			}
			bri.close();

Because I wonder in your .collect it's not handling the DONE correctly?

i.e.

{response : "whatever....multiple lines and stuff"}
DONE. 

@cryptoapebot
Copy link

Some previous discussion and ideas on the subject.

openai/openai-node#18

@cryptoapebot
Copy link

	public static HttpResponse<InputStream> dalle2stream(String prompt) {
		String json = json_request.replace("${PROMPT}", prompt);
		HttpRequest request = 
				HttpRequest.newBuilder()
				.uri(URI.create(openai_image))						
		        .header("Content-Type","application/json")					
		        .header("Authorization", OPENAI_API_KEY)
		        .POST(HttpRequest.BodyPublishers.ofString(json))
				.build();
		HttpResponse<InputStream> response = null;
		try {
			response = httpClient.send(request, HttpResponse.BodyHandlers.ofInputStream());
			if ((response.statusCode() / 100) != 2) {
				System.out.println("response code: " + response.statusCode());
				System.out.println("response body: " + response.body());
			} else {
				return response;
			}
		} catch (IOException | InterruptedException e) {
			System.out.println("response code: " + response.statusCode());
			e.printStackTrace();
		}

		return null;
	}

@terryyin
Copy link

The response for stream(true) utilizes the Server-Sent Events protocol, which is not currently supported by this project's retrofit2 API. Discussions on this issue can be found here square/retrofit#1029.

Unfortunately, it does not seem as though this issue can be resolved in the near future as long as retrofit is in use.

@cryptoapebot
Copy link

See #129

n3bul4 added a commit to n3bul4/openai-java that referenced this issue Mar 17, 2023
Utilize retrofit2.http.Streaming and retrofit2.Call<ResponseBody>
in additional OpenAIApi methods to enable a streamable ResponseBody.

Utilize retrofit2.Callback to get the streamable ResponseBody,
parse Server Sent Events (SSE) and emit them using
io.reactivex.FlowableEmitter.

Enable:

- Streaming of raw bytes
- Streaming of Java objects
- Shutdown of OkHttp ExecutorService

Fixes: TheoKanning#51, TheoKanning#83, TheoKanning#182, TheoKanning#184
TheoKanning pushed a commit that referenced this issue Mar 28, 2023
Utilize retrofit2.http.Streaming and retrofit2.Call<ResponseBody>
in additional OpenAIApi methods to enable a streamable ResponseBody.

Utilize retrofit2.Callback to get the streamable ResponseBody,
parse Server Sent Events (SSE) and emit them using
io.reactivex.FlowableEmitter.

Enable:

- Streaming of raw bytes
- Streaming of Java objects
- Shutdown of OkHttp ExecutorService

Fixes: #51, #83, #182, #184
@TheoKanning
Copy link
Owner

This is fixed in 0.12.0 👍

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants