JAVA 监听 text/event-stream ,事件流 SSE

chatGPT 最近很火,有意做个套壳小程序玩玩跟跟风

第三方依赖 async-http-client
        <!-- https://mvnrepository.com/artifact/org.asynchttpclient/async-http-client -->
        <dependency>
            <groupId>org.asynchttpclient</groupId>
            <artifactId>async-http-client</artifactId>
            <version>2.12.3</version>
        </dependency>

上代码
import io.netty.handler.codec.http.HttpHeaders;
import lombok.extern.slf4j.Slf4j;
import org.asynchttpclient.HttpResponseBodyPart;
import org.asynchttpclient.HttpResponseStatus;
import org.asynchttpclient.handler.StreamedAsyncHandler;
import org.reactivestreams.Publisher;

/**
 * 事件流处理器
 *
 * @Description 事件流处理器
 * @Author Mr.dan
 * @Date 2023-05-04 10:15
 */
@Slf4j
public class ChatGptStreamedHandler implements StreamedAsyncHandler {
    @Override
    public State onStream(Publisher publisher) {
        publisher.subscribe(new ChatGptSubscriber());
        log.info("》》》》》 onStream");
        return State.CONTINUE;
    }

    @Override
    public State onStatusReceived(HttpResponseStatus responseStatus) throws Exception {
        log.info("》》》》》onStatusReceived");
        return responseStatus.getStatusCode() == 200 ? State.CONTINUE : State.ABORT;
    }

    @Override
    public State onHeadersReceived(HttpHeaders headers) throws Exception {
        log.info("》》》》》 头信息处理");
        return State.CONTINUE;
    }

    @Override
    public State onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception {
        log.info("》》》》》 onBodyPartReceived");
        return State.CONTINUE;
    }

    @Override
    public void onThrowable(Throwable t) {
        log.error("发生异常", t);
    }

    @Override
    public Object onCompleted() throws Exception {
        log.info("》》》》》 完成");
        return State.ABORT;
    }
}

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;

/**
 * 订阅者
 *
 * @Description 订阅者
 * @Author Mr.dan
 * @Date 2023-05-04 13:18
 */
@Slf4j
public class ChatGptSubscriber implements Subscriber {
    @Override
    public void onSubscribe(Subscription s) {
        s.request(Long.MAX_VALUE);
    }

    @Override
    public void onNext(Object o) {
        //这里就是监听到的响应
        log.info(">>>>> onNext  {}", JSON.toJSONString(o));
    }

    @Override
    public void onError(Throwable t) {
    }

    @Override
    public void onComplete() {
    }
}

    public static void main(String[] args) throws Exception {
    //原始地址
//      String apiUrl = "https://api.openai.com/v1/chat/completions";
       //需要买个国外跳板机,装Nginx 转发请求
        String apiUrl = "http://xxx.xxx.xxx/v1/chat/completions";
        //去某宝买个成品号更简单(注册难搞的话)
        String apiKey = "sk-xxxxxxxxxxxxxxxxxxxxxx";
        List<JSONObject> msgData = new ArrayList<>();
        msgData.add(
                new JSONObject()
                        .fluentPut("role", "user")
                        .fluentPut("content", "夸奖我一下")
        );
        JSONObject req = new JSONObject()
                // 完成时要生成的最大token数量。
                // 提示的token计数加上max_tokens不能超过模型的上下文长度。大多数模型的上下文长度为2048个token(最新模型除外,支持4096个)。
                .fluentPut("max_tokens", 512)
                .fluentPut("model", "gpt-3.5-turbo")
                // 可选 默认值1
                // 使用什么样的采样温度,介于0和2之间。较高的值(如0.8)将使输出更加随机,而较低的值(例如0.2)将使其更加集中和确定。
                // 通常建议更改它或top_p,但不能同时更改两者。
                .fluentPut("temperature", 0.6)
                //告诉ChatGpt 使用流式返回,传FALSE 则返回完整的JSON(有点慢)
                .fluentPut("stream", Boolean.TRUE)
                .fluentPut("messages", msgData);

        log.info("》》 {}", JSON.toJSONString(req));
        AsyncHttpClient asyncHttpClient = new DefaultAsyncHttpClient();
        asyncHttpClient.preparePost(apiUrl)
                .addHeader("Content-Type", "application/json")
                .addHeader("Authorization", "Bearer " + apiKey)
                .addHeader("Accept", "text/event-stream")
                .setBody(JSON.toJSONString(req))
                .execute(new ChatGptStreamedHandler())
                .get();
        asyncHttpClient.close();
    }
    }
补充一下nginx配置
#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    #tcp_nopush     on;
    #keepalive_timeout  0;
    keepalive_timeout  65;
    #gzip  on;
    # 监听80端口 将所有请求 转发到 https://api.openai.com/
    server {
        listen      80;
        server_name  api.openai.com;
        charset utf-8;
        # 聊天
       location / {
          proxy_pass https://api.openai.com/;
          proxy_set_header Host api.openai.com;
		  # 使用调用方的IP地址请求
          proxy_set_header X-Real-IP $remote_addr;
		  # 使用Nginx所在服务器的外网IP
		  # proxy_set_header X-Real-IP $proxy_protocol_addr;
          
		  # 将代理服务器所在的IP放到集合中
		  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		  # 仅将自己的IP放到集合中
		  # proxy_set_header X-Forwarded-For $proxy_protocol_addr;
		  
          proxy_ssl_server_name on;
          proxy_ssl_session_reuse off;
       }
       
        error_page  404              /404.html;
        # redirect server error pages to the static page /50x.html
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
       }
    }
    
# 这组配置还没测好
   server {
      listen 9898;
      server_name proxy;
      charset utf-8;
        # 代理节点
       location / {
          # DNS 解析域名
          resolver 8.8.8.8;
        # 获取当前请求的 类型,域名, 路径 并原样转发
          proxy_pass $scheme://$host$request_uri;
       #   proxy_set_header Host $host;
       #   proxy_set_header X-Real-IP $remote_addr;
       #   proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
       #   proxy_set_header X-Forwarded-Proto $scheme;
       #   proxy_ssl_server_name on;
       #   proxy_ssl_session_reuse off;
       }
        error_page  404              /404.html;
        # redirect server error pages to the static page /50x.html
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
       }
   }
   
}
  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值