{"id":20482909,"url":"https://github.com/lzhpo/chatgpt-spring-boot-starter","last_synced_at":"2025-07-16T12:07:50.131Z","repository":{"id":150650890,"uuid":"622629279","full_name":"lzhpo/chatgpt-spring-boot-starter","owner":"lzhpo","description":"支持OpenAi所有可用的接口，包括但不限于流式输出和Token计算等，可配置多个API-Key、权重、代理、自定义API等诸多功能...","archived":false,"fork":false,"pushed_at":"2024-11-29T16:21:21.000Z","size":917,"stargazers_count":163,"open_issues_count":3,"forks_count":31,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-07-12T21:38:46.145Z","etag":null,"topics":["chatgpt","chatgpt-api","chatgpt-app","chatgpt-bot","spring-boot"],"latest_commit_sha":null,"homepage":"http://www.lzhpo.com","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lzhpo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-04-02T17:09:24.000Z","updated_at":"2025-06-02T13:41:50.000Z","dependencies_parsed_at":"2024-06-22T18:56:05.509Z","dependency_job_id":"82d9efc1-9294-433b-930a-834dce83cf5a","html_url":"https://github.com/lzhpo/chatgpt-spring-boot-starter","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/lzhpo/chatgpt-spring-boot-starter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lzhpo%2Fchatgpt-spring-boot-starter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lzhpo%2Fchatgpt-spring-boot-starter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lzhpo%2Fchatgpt-spring-boot-starter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lzhpo%2Fchatgpt-spring-boot-starter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lzhpo","download_url":"https://codeload.github.com/lzhpo/chatgpt-spring-boot-starter/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lzhpo%2Fchatgpt-spring-boot-starter/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265083776,"owners_count":23708790,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["chatgpt","chatgpt-api","chatgpt-app","chatgpt-bot","spring-boot"],"created_at":"2024-11-15T16:15:07.584Z","updated_at":"2025-07-16T12:07:50.100Z","avatar_url":"https://github.com/lzhpo.png","language":"Java","funding_links":[],"categories":["人工智能"],"sub_categories":["Spring Cloud框架"],"readme":"![](https://img.shields.io/badge/JDK-1.8+-success.svg)\n![](https://maven-badges.herokuapp.com/maven-central/com.lzhpo/chatgpt-spring-boot-starter/badge.svg?color=blueviolet)\n![](https://img.shields.io/:license-Apache2-orange.svg)\n[![Style check](https://github.com/lzhpo/chatgpt-spring-boot-starter/actions/workflows/style-check.yml/badge.svg)](https://github.com/lzhpo/chatgpt-spring-boot-starter/actions/workflows/style-check.yml)\n\n## 概览\n\n1. 支持设置多个 API Key，并且支持对其设置权重以及是否启用，支持自动禁用失效的 API Key 以及自动轮转\n2. 支持设置请求代理\n3. 支持自定义请求 API（如果对 OpenAi 的 API 做了中转/代理）\n4. 支持 OpenAi 所有可以使用 API Key 访问的 API\n5. 支持流式响应，即所谓的\"打字机\"模式\n6. 请求参数自动校验\n7. 支持 token 计算\n8. 支持 function calling\n\n## 支持的功能\n\n✅ 模型查询（Model）\u003cbr\u003e\n✅ 流式、非流式对话聊天（Stream Chat/completion）\u003cbr\u003e\n✅ 根据提示生成文本（Edit）\u003cbr\u003e\n✅ 自然语言转换为向量表示\u003cbr\u003e\n✅ 音频、视频语音转文本（Create transcription）\u003cbr\u003e\n✅ 文本翻译（Create translation）\u003cbr\u003e\n✅ 文件的查询、上传、删除（File - List/Upload/Delete/Retrieve）\u003cbr\u003e\n✅ 预训练模型的微调、查询、放弃、过程(事件)（Fine-tunes - Create/List/Retrieve/Cancel/Events）\u003cbr\u003e\n✅ 内容审核（Moderation）\u003cbr\u003e\n✅ 用户余额、使用量查询（Billing/Usage）\u003cbr\u003e\n✅ 用户信息查询（User）\u003cbr\u003e\n✅ 根据提示创建、编辑图像、根据图像生成多版本图像（Image - Create/Create edit/Create variation）\n\n## 项目地址\n\n- Github: https://github.com/lzhpo/chatgpt-spring-boot-starter\n- Gitee: https://gitee.com/lzhpo/chatgpt-spring-boot-starter\n\n## 导入依赖\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.lzhpo\u003c/groupId\u003e\n    \u003cartifactId\u003echatgpt-spring-boot-starter\u003c/artifactId\u003e\n    \u003cversion\u003e${version}\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n## 配置示例\n\n### 1. 支持配置多个 API Key（权重、是否启用）\n\n\u003e 可以对当前 api key 设置权重，以及是否需要启用此 api key，提供了两种方式配置。\n\n#### 1.1 方式1-常规yaml配置方式\n\n```yaml\nopenai:\n  keys:\n    - key: \"sk-xxx1\"\n      weight: 1.0\n      enabled: true\n    - key: \"sk-xxx2\"\n      weight: 2.0\n      enabled: false\n    - key: \"sk-xxx3\"\n      weight: 3.0\n      enabled: false\n```\n\n_支持自动禁用失效的 API Key 以及自动轮转，参考：`InvalidedKeyEvent`、`NoAvailableKeyEvent`、`OpenAiEventListener`_\n\n#### 1.2 方式2-自定义获取 API Key 逻辑\n\n如果你的 API Key 是存在数据库或者其它地方的，那么可以选择使用这种方式配置。\n\n实现`OpenAiKeyProvider`接口即可，例如：\n```java\n@Component\npublic class XxxOpenAiKeyProvider implements OpenAiKeyProvider {\n\n    @Override\n    public List\u003cOpenAiKey\u003e get() {\n        List\u003cOpenAiKey\u003e openAiKeys = new ArrayList\u003c\u003e();\n        openAiKeys.add(OpenAiKey.builder().key(\"sk-xxx1\").weight(1.0).enabled(true).build());\n        openAiKeys.add(OpenAiKey.builder().key(\"sk-xxx2\").weight(2.0).enabled(false).build());\n        openAiKeys.add(OpenAiKey.builder().key(\"sk-xxx2\").weight(3.0).enabled(true).build());\n        return openAiKeys;\n    }\n}\n```\n\n**注意：每次请求都会调用此方法，有需要的话可以在此加一个缓存。**\n\n### 2. 支持配置代理\n\n```yaml\nopenai:\n  proxy:\n    host: \"127.0.0.1\"\n    port: 7890\n    type: http\n    header-name: \"Proxy-Authorization\"\n    username: admin\n    password: 123456\n```\n\n### 3. 支持配置超时时间\n\n```yaml\nopenai:\n  connect-timeout: 1m\n  read-timeout: 1m\n  write-timeout: 1m\n```\n\n### 4. 支持自定义请求API\n\n\u003e 如果没有配置代理，也没有定制完整请求地址的需求，那么无需配置`openai.domain`以及`openai.urls`，会自动使用默认的。\n\n#### 4.1 方式1 - 只配置了代理\n\n如果只是配置了国内中转代理，那么只需要配置`openai.domain`为代理地址即可，默认值为https://api.openai.com\n\n```yaml\nopenai:\n  domain: \"https://api.openai.com\"\n```\n\n#### 4.2 方式2 - 定制完整的请求地址\n\n如果有定制完整请求地址的需求，可以按照如下配置，优先级比`openai.domain`更高，但需要的是**完整的请求地址**。\n\n```yaml\nopenai:\n  urls:\n    moderations: \"https://api.openai.com/v1/moderations\"\n    completions: \"https://api.openai.com/v1/completions\"\n    edits: \"https://api.openai.com/v1/edits\"\n    chat-completions: \"https://api.openai.com/v1/chat/completions\"\n    list-models: \"https://api.openai.com/v1/models\"\n    retrieve-model: \"https://api.openai.com/v1/models/{model}\"\n    embeddings: \"https://api.openai.com/v1/embeddings\"\n    list-files: \"https://api.openai.com/v1/files\"\n    upload-file: \"https://api.openai.com/v1/files\"\n    delete-file: \"https://api.openai.com/v1/files/{file_id}\"\n    retrieve-file: \"https://api.openai.com/v1/files/{file_id}\"\n    retrieve-file-content: \"https://api.openai.com/v1/files/{file_id}/content\"\n    create_fine_tune: \"https://api.openai.com/v1/fine-tunes\"\n    list_fine_tune: \"https://api.openai.com/v1/fine-tunes\"\n    retrieve_fine_tune: \"https://api.openai.com/v1/fine-tunes/{fine_tune_id}\"\n    cancel_fine_tune: \"https://api.openai.com/v1/fine-tunes/{fine_tune_id}/cancel\"\n    list_fine_tune_events: \"https://api.openai.com/v1/fine-tunes/{fine_tune_id}/events\"\n    delete_fine_tune_events: \"https://api.openai.com/v1/models/{model}\"\n    create-transcription: \"https://api.openai.com/v1/audio/transcriptions\"\n    create-translation: \"https://api.openai.com/v1/audio/translations\"\n    create_image: \"https://api.openai.com/v1/images/generations\"\n    create_image_edit: \"https://api.openai.com/v1/images/edits\"\n    create_image_variation: \"https://api.openai.com/v1/images/variations\"\n    billing-credit-grants: \"https://api.openai.com/dashboard/billing/credit_grants\"\n    users: \"https://api.openai.com/v1/organizations/{organizationId}/users\"\n    billing-subscription: \"https://api.openai.com/v1/dashboard/billing/subscription\"\n    billing-usage: \"https://api.openai.com/v1/dashboard/billing/usage?start_date={start_date}\u0026end_date={end_date}\"\n```\n\n### 5. 支持token计算\n\n示例1：\n```java\nLong tokens = TokenUtils.tokens(model, content);\n```\n\n示例2：`CompletionRequest`\n```java\nCompletionRequest request = new CompletionRequest();\n// request.setXXX 略...\nLong tokens = TokenUtils.tokens(request.getModel(), request.getPrompt());\n```\n\n示例3：`ChatCompletionRequest`\n```java\nChatCompletionRequest request = new ChatCompletionRequest();\n// request.setXXX 略...\nLong tokens = TokenUtils.tokens(request.getModel(), request.getMessages());\n```\n\nOpenAi返回的token计算结果可在response返回体中获取：\n- `prompt_tokens`：OpenAi计算的输入消耗的token\n- `completion_tokens`：OpenAi计算的输出消耗的token\n- `total_tokens`：`prompt_tokens` + `completion_tokens`\n\n具体可参考测试用例`OpenAiCountTokensTest`以及`TokenUtils`\n\n### 6. 支持 function calling\n\n关于 function calling 的介绍：https://platform.openai.com/docs/guides/gpt/function-calling\n\n参考示例见测试目录：`com.lzhpo.chatgpt.OpenAiClientTest#functions`\n\n### 7. 关于异常处理\n\n1. 常规、SSE以及WebSocket请求失败均会抛出`OpenAiException`异常，可自定义全局异常，取出OpenAi的响应结果转换为`OpenAiError`(如果转换结果`OpenAiError`不为空)，继而自行处理。\n2. 自定义流式处理的`EventSourceListener`，推荐继承`AbstractEventSourceListener`，如果没有特殊需求，直接重写`onEvent`方法即可，如果重写了`onFailure`方法，抛出何种异常取决于重写的`onFailure`方法。\n3. 提供了失效的Api-Key事件、当前无可用的Api-Key事件，可自行监听处理，例如：\n    ```java\n    @Slf4j\n    @Component\n    public class OpenAiEventListener {\n    \n       @EventListener\n       public void processInvalidedKey(InvalidedKeyEvent event) {\n           String invalidedApiKey = event.getInvalidedApiKey();\n           String errorResponse = event.getErrorResponse();\n           log.error(\"Processing invalidedApiKey={} event, errorResponse: {}\", invalidedApiKey, errorResponse);\n       }\n    \n       @EventListener\n       public void processNoAvailableKey(NoAvailableKeyEvent event) {\n           List\u003cString\u003e invalidedKeys = event.getInvalidedKeys();\n           log.error(\"Processing noAvailableKey event, invalidedKeys={}\", invalidedKeys);\n       }\n    }\n    ```\n4. 也可以实现OKHttp的`Interceptor`接口，并声明为Bean，也可在里面自行处理异常，参考：`OpenAiErrorInterceptor`\n\n## 代码示例\n\n### 1. 流式输出（“打字机”）\n\n#### 1.1 SSE方式示例\n\n**这里快速了解一下SSE（Server-Sent Events）**\n\nSSE和WebSocket都是用于实现服务器和浏览器之间实时通信的技术。\nWebSocket是全双工通信协议，适用于双向通信的实时场景，而SSE是单向通信协议，适用于服务器向客户端推送消息的实时场景。\n\n简单网页效果示例（“打字机”效果）：\n![](./docs/images/SSE-Stream-Chat.png)\n\n后端代码简单示例：\n```java\n@RestController\n@RequestMapping(\"/\")\n@RequiredArgsConstructor\npublic class ChatController {\n\n    private final OpenAiClient openAiClient;\n\n    @GetMapping(\"/chat/sse\")\n    public SseEmitter sseStreamChat(@RequestParam String message) {\n        SseEmitter sseEmitter = new SseEmitter();\n        ChatCompletionRequest request = ChatCompletionRequest.create(message);\n        openAiClient.streamChatCompletions(request, new SseEventSourceListener(sseEmitter));\n        return sseEmitter;\n    }\n}\n```\n`SseEventSourceListener`是基于`okhttp3.sse.EventSourceListener`实现的，可以接收`text/event-stream`类型的流式数据。\n\n前端代码简单示例：\n```javascript\n// message为需要发送的消息\nconst eventSource = new EventSource(`http://127.0.0.1:6060/chat/sse?message=${message}`);\n// 收到消息处理\neventSource.onmessage = function(event) {\n    // 略...\n}\n```\n\n由于SSE协议只支持GET方法，不支持POST方法。\u003cbr/\u003e\n如果要支持POST方法可以参考：https://github.com/Azure/fetch-event-source\n\n详细代码见仓库目录下：\n- `templates/chat.html`\n- `templates/sse-stream-chat.html`\n- `com.lzhpo.chatgpt.OpenAiTestController`\n\n#### 1.2 WebSocket方式示例\n\n效果和SSE方式一样，即“打字机”效果。\n\n声明WebSocket端点：\n```java\n@Slf4j\n@Component\n@ServerEndpoint(\"/chat/websocket\")\npublic class OpenAiWebSocketTest {\n\n    @OnOpen\n    public void onOpen(Session session) {\n        log.info(\"sessionId={} joined.\", session.getId());\n    }\n\n    @OnMessage\n    public void onMessage(Session session, String message) {\n        log.info(\"Received sessionId={} message={}\", session.getId(), message);\n        ChatCompletionRequest request = ChatCompletionRequest.create(message);\n        WebSocketEventSourceListener listener = new WebSocketEventSourceListener(session);\n        SpringUtil.getBean(OpenAiClient.class).streamChatCompletions(request, listener);\n    }\n\n    @OnClose\n    public void onClose(Session session) {\n        log.info(\"Closed sessionId={} connection.\", session.getId());\n    }\n\n    @OnError\n    public void onError(Session session, Throwable e) {\n        log.error(\"sessionId={} error: {}\", session.getId(), e.getMessage(), e);\n    }\n}\n```\n开启WebSocket端点：\n```java\n@Bean\npublic ServerEndpointExporter serverEndpointExporter() {\n    return new ServerEndpointExporter();\n}\n```\n\n前端代码主要逻辑如下：\n```javascript\nconst websocket = new WebSocket(\"ws://127.0.0.1:6060/chat/websocket\");\n// 发送消息（message为需要发送的消息）\nwebsocket.send(message);\n// 收到消息\nwebsocket.onmessage = function(event) {\n    // 略...\n}\n```\n详细代码见仓库目录下的`templates/websocket-stream-chat.html`\n\n### 2. 自定义请求拦截器\n\n实现`okhttp3.Interceptor`接口，并将其声明为bean即可。\n\n例如：\n```java\n@Slf4j\npublic class OpenAiLoggingInterceptor implements Interceptor {\n\n    @Override\n    public Response intercept(Chain chain) throws IOException {\n        Request request = chain.request();\n        log.info(\"Request url: {} {}\", request.method(), request.url());\n        log.info(\"Request header: {}\", request.headers());\n\n        Response response = chain.proceed(request);\n        log.info(\"Response code: {}\", response.code());\n        log.info(\"Response body: {}\", response.body().string());\n        return response;\n    }\n}\n```\n\n### 3. 全部API测试示例\n\n见：`com.lzhpo.chatgpt.OpenAiClientTest`\n\n## 问题锦集\n\n### 1. okhttp 报错 NoSuchMethodError\n\n参考 issue：https://gitee.com/lzhpo/chatgpt-spring-boot-starter/issues/I7KHQG\n\n## 鸣谢\n\n感谢Jetbrains提供的License！\n\n\u003cimg width=\"150\" height=\"150\" src=\"https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.png\" alt=\"JetBrains Logo (Main) logo.\"\u003e\n\n## 微信公众号\n\n\u003cimg src=\"./docs/images/WeChat-MP.png\" width=\"453\" height=\"150\" alt=\"会打篮球的程序猿\"\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flzhpo%2Fchatgpt-spring-boot-starter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flzhpo%2Fchatgpt-spring-boot-starter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flzhpo%2Fchatgpt-spring-boot-starter/lists"}