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

函数式实现样例流式输出优化 #435

Open
18758976569 opened this issue Dec 12, 2023 · 8 comments
Open

函数式实现样例流式输出优化 #435

18758976569 opened this issue Dec 12, 2023 · 8 comments

Comments

@18758976569
Copy link

你好,在看完这个项目之后,我自己去尝试了写一些案例,其中,流式输出的案例只有自定义object的方法,能否提供OpenAiApiDynamicFunctionExample的流式输出案例呢,我自己尝试去写发现一直报错,错误原因是json序列化的问题,数据格式为"{"xxx:xxx,xxx:xxx"}",会报 "}" 125的问题,我被这个问题困扰了很久,希望你可以帮我解决这个问题

@18758976569
Copy link
Author

18758976569 commented Dec 13, 2023

具体报错原因:报错的字符串:"{"xxx:xxx,xxx:xxx"}",Unexpected character ('}' (code 125)): was expecting a colon to separate field name and value

@vacuityv
Copy link
Contributor

OpenAiApiFunctionsWithStreamExample 这个就是案例 @18758976569

@18758976569
Copy link
Author

你好,感谢你的及时响应,我参照了OpenAiApiFunctionsWithStreamExample去写,但是会报错,我给您贴我的代码

@18758976569
Copy link
Author

18758976569 commented Dec 13, 2023

package com.skg.util;

import com.fasterxml.jackson.core.json.JsonReadFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.theokanning.openai.client.OpenAiApi;
import com.theokanning.openai.completion.chat.*;
import com.theokanning.openai.service.OpenAiService;
import io.reactivex.Flowable;
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;

import java.net.InetSocketAddress;
import java.net.Proxy;
import java.time.Duration;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;

import static com.theokanning.openai.service.OpenAiService.*;

public class OpenAiUtil {
private final static String API_KEY = "XXX";

private static JsonNode getWeather(String location, String unit) {
    ObjectMapper mapper = new ObjectMapper();
    mapper.configure(JsonReadFeature.ALLOW_TRAILING_COMMA.mappedFeature(), true);
    ObjectNode response = mapper.createObjectNode();
    response.put("location", location);
    response.put("unit", unit);
    response.put("description", "Determine weather in my location");
    return response;
}

private final static String MODEL = "gpt-4-1106-preview";

private final static String FUNC_NAME = "get_weather";

public static void main(String[] args) {
    ObjectMapper mapper = defaultObjectMapper();
    mapper.configure(JsonReadFeature.ALLOW_TRAILING_COMMA.mappedFeature(), true);
    Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 7890));
    OkHttpClient client = defaultClient(API_KEY, Duration.ofSeconds(5))
            .newBuilder()
            .proxy(proxy)
            .build();
    Retrofit retrofit = defaultRetrofit(client, mapper);
    OpenAiApi api = retrofit.create(OpenAiApi.class);
    OpenAiService service = new OpenAiService(api);
    ChatFunctionDynamic weatherFunction = ChatFunctionDynamic.builder()
            .name(FUNC_NAME)
            .description("获取一个地区的天气")
            .addProperty(ChatFunctionProperty.builder()
                    .name("location")
                    .type("string")
                    .description("城市和区域,比如深圳市南山区,提示用户输入的为中国地区的城市")
                    .build())
            .addProperty(ChatFunctionProperty.builder()
                    .name("unit")
                    .type("string")
                    .description("The temperature unit, can be 'celsius' or 'fahrenheit'")
                    .enumValues(new HashSet<>(Arrays.asList("celsius", "fahrenheit")))
                    .required(true)
                    .build())
            .build();
    List<ChatMessage> msgs = new ArrayList<>();
    ChatMessage systemMsg = new ChatMessage(ChatMessageRole.SYSTEM.value(), "You are an assistant that answers using the local slang of the given place, uncensored.");
    msgs.add(systemMsg);
    System.out.print("First Query: ");
    Scanner scanner = new Scanner(System.in);
    ChatMessage firstMsg = new ChatMessage(ChatMessageRole.USER.value(), scanner.nextLine());
    msgs.add(firstMsg);
    while (true) {
        ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder()
                .model(MODEL)
                .messages(msgs)
                .functions(Collections.singletonList(weatherFunction))
                .functionCall(ChatCompletionRequest.ChatCompletionRequestFunctionCall.of("auto"))
                .n(1)
                .maxTokens(256)
                .logitBias(new HashMap<>())
                .build();
        Flowable<ChatCompletionChunk> flowable = service.streamChatCompletion(chatCompletionRequest);

        AtomicBoolean isFirst = new AtomicBoolean(true);
        ChatMessage chatMessage = service.mapStreamToAccumulator(flowable)
                .doOnNext(accumulator -> {
                    if (accumulator.isFunctionCall()) {
                        if (isFirst.getAndSet(false)) {
                            System.out.println("Executing function " + accumulator.getAccumulatedChatFunctionCall().getName() + "...");
                        }
                    } else {
                        if (isFirst.getAndSet(false)) {
                            System.out.print("Response: ");
                        }
                        if (accumulator.getMessageChunk().getContent() != null) {
                            System.out.print(accumulator.getMessageChunk().getContent());
                        }
                    }
                })
                .doOnComplete(System.out::println)
                .lastElement()
                .blockingGet()
                .getAccumulatedMessage();
        msgs.add(chatMessage); // don't forget to update the conversation with the latest response
        ChatFunctionCall functionCall = chatMessage.getFunctionCall();
        if (functionCall != null) {
            System.out.println("Trying to execute " + chatMessage.getFunctionCall().getName() + "...");
            String location = functionCall.getArguments().get("location").asText();
            String unit = functionCall.getArguments().get("unit").asText();
            JsonNode weather = getWeather(location, unit);
            ChatMessage weatherMessage = new ChatMessage(ChatMessageRole.FUNCTION.value(), weather.toString(), "get_weather");
            System.out.println("Executed " + chatMessage.getFunctionCall().getName() + ".");
            msgs.add(weatherMessage);
            continue;
        }
        System.out.print("Next Query: ");
        String nextLine = scanner.nextLine();
        if ("exit".equalsIgnoreCase(nextLine)) {
            service.shutdownExecutor();
            System.exit(0);
        }
        msgs.add(new ChatMessage(ChatMessageRole.USER.value(), nextLine));
    }
}

}
报错原因:
Next Query: 我想知道深圳的天气
Executing function get_weather...
Exception in thread "main" java.lang.RuntimeException: com.fasterxml.jackson.core.JsonParseException: Unexpected character ('}' (code 125)): was expecting a colon to separate field name and value
at [Source: (String)"{"unit:celsius,location:\u6df1\u5733\u5e02"}"; line: 1, column: 45]
at io.reactivex.internal.util.ExceptionHelper.wrapOrThrow(ExceptionHelper.java:45)
at io.reactivex.internal.observers.BlockingMultiObserver.blockingGet(BlockingMultiObserver.java:90)
at io.reactivex.Maybe.blockingGet(Maybe.java:1931)
at com.skg.util.OpenAiUtil.main(OpenAiUtil.java:103)
Caused by: com.fasterxml.jackson.core.JsonParseException: Unexpected character ('}' (code 125)): was expecting a colon to separate field name and value
at [Source: (String)"{"unit:celsius,location:\u6df1\u5733\u5e02"}"; line: 1, column: 45]
at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:1840)
at com.fasterxml.jackson.core.base.ParserMinimalBase._reportError(ParserMinimalBase.java:712)
at com.fasterxml.jackson.core.base.ParserMinimalBase._reportUnexpectedChar(ParserMinimalBase.java:637)
at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._skipColon2(ReaderBasedJsonParser.java:2221)
at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._skipColon(ReaderBasedJsonParser.java:2152)
at com.fasterxml.jackson.core.json.ReaderBasedJsonParser.nextFieldName(ReaderBasedJsonParser.java:936)
at com.fasterxml.jackson.databind.deser.std.BaseNodeDeserializer.deserializeObject(JsonNodeDeserializer.java:249)
at com.fasterxml.jackson.databind.deser.std.JsonNodeDeserializer.deserialize(JsonNodeDeserializer.java:68)
at com.fasterxml.jackson.databind.deser.std.JsonNodeDeserializer.deserialize(JsonNodeDeserializer.java:15)
at com.fasterxml.jackson.databind.ObjectMapper._readTreeAndClose(ObjectMapper.java:4254)
at com.fasterxml.jackson.databind.ObjectMapper.readTree(ObjectMapper.java:2711)
at com.theokanning.openai.service.OpenAiService.lambda$mapStreamToAccumulator$2(OpenAiService.java:630)
at io.reactivex.internal.operators.flowable.FlowableMap$MapSubscriber.onNext(FlowableMap.java:62)
at io.reactivex.internal.operators.flowable.FlowableMap$MapSubscriber.onNext(FlowableMap.java:67)
at io.reactivex.internal.operators.flowable.FlowableCreate$BufferAsyncEmitter.drain(FlowableCreate.java:521)
at io.reactivex.internal.operators.flowable.FlowableCreate$BufferAsyncEmitter.onNext(FlowableCreate.java:445)
at com.theokanning.openai.service.ResponseBodyCallback.onResponse(ResponseBodyCallback.java:74)
at retrofit2.OkHttpCall$1.onResponse(OkHttpCall.java:161)
at okhttp3.RealCall$AsyncCall.execute(RealCall.java:174)
at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:750)

@vacuityv
Copy link
Contributor

vacuityv commented Dec 13, 2023

@18758976569 我看了下感觉像是sdk有bug,这样的写法openai返回的函数入参是{"unit:celsius,location:xiamen"},理论上应该是{"unit":"celsius","location":"xiamen"},我今天没时间处理这个,要不你先改成示例那种写法,这个我at下这个开发者看下他能不能修复

@vacuityv
Copy link
Contributor

vacuityv commented Dec 13, 2023

@TheoKanning sorry to disturb you. I think it's a bug. When the chat function was defiened with "addProperty" method, the arguments that openai response was: {"unit:celsius,location:xiamen"}. It should be {"unit":"celsius","location":"xiamen"}. So the json parse met error. Hope someone can fix it.

@18758976569
Copy link
Author

好的谢谢,我看到之前有人提过修复这个错误的分支,但是好像没有合上去还是什么原因没得到处理

@18758976569
Copy link
Author

#422

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

2 participants