Sfoglia il codice sorgente

wip:消息返回修改

wangkaiyue 2 anni fa
parent
commit
f5265cebeb
6 ha cambiato i file con 138 aggiunte e 84 eliminazioni
  1. 5 3
      go.mod
  2. 0 24
      go.sum
  3. 34 12
      internal/model/chatApi.go
  4. 11 11
      internal/model/question.go
  5. 87 33
      internal/model/ws.go
  6. 1 1
      manifest/config/config.yaml

+ 5 - 3
go.mod

@@ -5,11 +5,13 @@ go 1.15
 require (
 	app.yhyue.com/moapp/jybase v0.0.0-20230405040249-a36a23595798
 	app.yhyue.com/moapp/jypkg v0.0.0-20230330033424-b61bb6a4ad7e
-	bp.jydev.jianyu360.cn/BaseService/resourceCenter v0.0.7
 	github.com/gogf/gf/contrib/drivers/mysql/v2 v2.3.3
 	github.com/gogf/gf/contrib/nosql/redis/v2 v2.3.3
 	github.com/gogf/gf/v2 v2.3.1
 	github.com/juju/ratelimit v1.0.2
-	github.com/ulule/limiter/v3 v3.11.1
-	github.com/zeromicro/go-zero v1.4.4
+	github.com/klauspost/compress v1.15.9 // indirect
+	github.com/kr/pretty v0.3.0 // indirect
+	github.com/mattn/go-isatty v0.0.16 // indirect
+	github.com/rogpeppe/go-internal v1.8.0 // indirect
+	golang.org/x/crypto v0.7.0 // indirect
 )

+ 0 - 24
go.sum

@@ -477,7 +477,6 @@ github.com/alicebob/miniredis/v2 v2.23.1/go.mod h1:84TWKZlxYkfgMucPBf5SOQBYJceZe
 github.com/alicebob/miniredis/v2 v2.30.0 h1:uA3uhDbCxfO9+DI/DuGeAMr9qI+noVWwGPNTFuKID5M=
 github.com/alicebob/miniredis/v2 v2.30.0/go.mod h1:84TWKZlxYkfgMucPBf5SOQBYJceZeQRFIaQgNMiCX6Q=
 github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
-github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
 github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
 github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q=
 github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
@@ -501,8 +500,6 @@ github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff/go.mod h1:+RTT1BOk5P
 github.com/bos-hieu/mongostore v0.0.2/go.mod h1:8AbbVmDEb0yqJsBrWxZIAZOxIfv/tsP8CDtdHduZHGg=
 github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
 github.com/bradleypeabody/gorilla-sessions-memcache v0.0.0-20181103040241-659414f458e1/go.mod h1:dkChI7Tbtx7H1Tj7TqGSZMOeGpMP5gLHtjroHd4agiI=
-github.com/bsm/ginkgo/v2 v2.5.0/go.mod h1:AiKlXPm7ItEHNc/2+OkrNG4E0ITzojb9/xWzvQ9XZ9w=
-github.com/bsm/gomega v1.20.0/go.mod h1:JifAceMQ4crZIWYUKrlGcmbN3bqHogVTADMD2ATsbwk=
 github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4=
 github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
@@ -613,7 +610,6 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME
 github.com/gin-contrib/sessions v0.0.5/go.mod h1:vYAuaUPqie3WUSsft6HUlCjlwwoJQs97miaG2+7neKY=
 github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
 github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
-github.com/gin-gonic/gin v1.8.2/go.mod h1:qw5AYuDrzRTnhvusDsrov+fDIxp9Dleuu12h8nfB398=
 github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
 github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@@ -648,11 +644,8 @@ github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh
 github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
 github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
 github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
-github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
 github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
-github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
 github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
-github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
 github.com/go-redis/redis v6.15.7+incompatible h1:3skhDh95XQMpnqeqNftPkQD9jL9e5e36z/1SUm6dy1U=
 github.com/go-redis/redis v6.15.7+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
 github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w=
@@ -694,7 +687,6 @@ github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWe
 github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ=
 github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0=
 github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw=
-github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
 github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
 github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
 github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
@@ -982,7 +974,6 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
 github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
-github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
 github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
 github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
 github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
@@ -1157,7 +1148,6 @@ github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b/go.mod h1:wTPjTep
 github.com/rabbitmq/amqp091-go v1.1.0/go.mod h1:ogQDLSOACsLPsIq0NpbtiifNZi2YOz0VTJ0kHRghqbM=
 github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
 github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
-github.com/redis/go-redis/v9 v9.0.2/go.mod h1:/xDTe9EF1LM61hek62Poq2nzQSGj0xSrEtEHbBQevps=
 github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
 github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
 github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
@@ -1235,17 +1225,10 @@ github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hM
 github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
 github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
-github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
 github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
-github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
-github.com/ulule/limiter/v3 v3.11.1 h1:wm6YaA2JwIXc0S+z8TK8/neWMOTf4m20I5jL1dwLRcw=
-github.com/ulule/limiter/v3 v3.11.1/go.mod h1:4nk/9RHEJthkjD+mmkqYxaPfD4pkB91PTH7k8ozB80g=
 github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
 github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
 github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
-github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
-github.com/valyala/fasthttp v1.44.0/go.mod h1:f6VbjjoI3z1NDOZOv17o6RvtRSWxC77seBFc2uWtgiY=
-github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
 github.com/wader/gormstore/v2 v2.0.0/go.mod h1:3BgNKFxRdVo2E4pq3e/eiim8qRDZzaveaIcIvu2T8r0=
 github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
 github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
@@ -1415,8 +1398,6 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm
 golang.org/x/crypto v0.0.0-20210920023735-84f357641f63/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
 golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
@@ -1524,12 +1505,10 @@ golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug
 golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
 golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
 golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
-golang.org/x/net v0.0.0-20220906165146-f3363e06e74c/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
 golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
 golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
 golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
 golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
-golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
 golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
 golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
 golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
@@ -1682,7 +1661,6 @@ golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
@@ -1692,7 +1670,6 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn
 golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
-golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
 golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
 golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
 golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw=
@@ -1709,7 +1686,6 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0=
 golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
 golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
-golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=

+ 34 - 12
internal/model/chatApi.go

@@ -2,10 +2,13 @@ package model
 
 import (
 	"aiChat/internal/consts"
+	"bufio"
 	"context"
 	"github.com/gogf/gf/v2/frame/g"
 	"github.com/gogf/gf/v2/net/gclient"
 	"github.com/gogf/gf/v2/util/gconv"
+	"net/http"
+	"strings"
 )
 
 type GPTReq struct {
@@ -56,22 +59,41 @@ func (c *cChatGpt) SimpleDo(ctx context.Context, qReq *QuestionReq) (res *Simple
 	return
 }
 
-func (c *cChatGpt) GPTDo(ctx context.Context, qReq *QuestionReq) (res *GPTRes, err error) {
+func (c *cChatGpt) GPTDo(ctx context.Context, qReq *QuestionReq) (res *bufio.Reader, err error) {
 	gReq := GPTReq{
 		BaseQuestion: qReq.BaseQuestion,
 		Identity:     g.Config().MustGet(ctx, "chat.api.identity", "剑鱼chat").String(),
 	}
-
-	var gRes *gclient.Response
-	gRes, err = g.Client().Header(consts.RequestJsonHeader).Post(ctx, g.Config().MustGet(ctx, "chat.api.addr_answer", "").String(), gReq)
-	if err != nil {
-		return nil, err
+	if gReq.History == nil {
+		gReq.History = [][]string{}
 	}
-	res = &GPTRes{}
-	err = gconv.Struct(gRes.ReadAll(), res)
-	//g.Dump("GPTDo", gReq, res)
-	if err != nil {
-		return nil, err
+	req, err := http.NewRequest("POST", g.Config().MustGet(ctx, "chat.api.addr_answer", "").String(), strings.NewReader(gconv.String(gReq)))
+	client := &http.Client{}
+	req.Header.Set("Accept", "text/event-stream")
+	resp, err := client.Do(req)
+	return bufio.NewReader(resp.Body), nil
+}
+
+type BufRes struct {
+	Delta    string `json:"delta"`
+	Response string `json:"response"`
+	Finished bool   `json:"finished"`
+}
+
+func readEvent(res *bufio.Reader) (string, error) {
+	event := ""
+	buf := make([]byte, 1024)
+	for {
+		n, err := res.Read(buf)
+		if err != nil {
+			return "", err
+		}
+		// 解析Event-Stream消息
+		for _, b := range buf[:n] {
+			if b == '\n' {
+				return event, nil
+			}
+			event += string(b)
+		}
 	}
-	return
 }

+ 11 - 11
internal/model/question.go

@@ -3,6 +3,7 @@ package model
 import (
 	"aiChat/utility"
 	"aiChat/utility/fsw"
+	"bufio"
 	"context"
 	"encoding/json"
 	"fmt"
@@ -140,25 +141,24 @@ func (q *cQuestion) getIsbusinessData(ctx context.Context, code string) (bRes *B
 }
 
 // DetailQuestion 问题处理
-func (q *cQuestion) DetailQuestion(ctx context.Context, qRes *QuestionReq) (reply string, from int, err error) {
+func (q *cQuestion) DetailQuestion(ctx context.Context, qRes *QuestionReq) (reply string, res *bufio.Reader, from int, err error) {
 	qRes.ParseHistoryFsw()
 	// 语义服务
 	sRes, err := ChatGpt.SimpleDo(ctx, qRes)
 	if err != nil {
-		return "", 0, err
+		return "", nil, 0, err
 	}
 	if sRes.Result.Answer == "" {
 		cRes, err := ChatGpt.GPTDo(ctx, qRes)
 		if err != nil {
-			return "", 0, err
+			return "", nil, 0, err
 		}
-		return fsw.Repl(cRes.Response), Answer_ChatGPT, nil
+		return "", cRes, Answer_ChatGPT, nil
 	}
-
 	// 校验是否有业务逻辑
 	matchArr := regExpSmart.FindStringSubmatch(sRes.Result.Answer)
 	if len(matchArr) == 0 {
-		return sRes.Result.Answer, Answer_UsuallyProblem, nil
+		return sRes.Result.Answer, nil, Answer_UsuallyProblem, nil
 	}
 	// 查询业务逻辑
 	var bRes = &BusinessRes{}
@@ -190,11 +190,11 @@ func (q *cQuestion) DetailQuestion(ctx context.Context, qRes *QuestionReq) (repl
 		return true
 	}()
 	if !powerPass {
-		return bRes.Noperm, Answer_Isbusiness, nil
+		return bRes.Noperm, nil, Answer_Isbusiness, nil
 	}
 	_, infoId := GetScenarioAndInfoId(qRes.Href)
 	if bRes.Source == scenarioName[DetailPage] && infoId == "" {
-		return bRes.AutoUrl, Answer_Isbusiness, nil
+		return bRes.AutoUrl, nil, Answer_Isbusiness, nil
 	}
 	businessRes, err := utility.DoBusiness(ctx, bRes.Joggle, &utility.RpcParams{
 		UserId:     jSession.UserId,
@@ -203,10 +203,10 @@ func (q *cQuestion) DetailQuestion(ctx context.Context, qRes *QuestionReq) (repl
 		BaseUserId: jSession.NewUid,
 	})
 	if err != nil {
-		return "", Answer_Isbusiness, nil
+		return "", nil, Answer_Isbusiness, nil
 	}
 	if businessRes.ErrMsg != "" {
-		return "", Answer_Isbusiness, fmt.Errorf(businessRes.ErrMsg)
+		return "", nil, Answer_Isbusiness, fmt.Errorf(businessRes.ErrMsg)
 	}
-	return businessRes.ReplyMsg, Answer_Isbusiness, nil
+	return businessRes.ReplyMsg, nil, Answer_Isbusiness, nil
 }

+ 87 - 33
internal/model/ws.go

@@ -5,13 +5,16 @@ import (
 	. "app.yhyue.com/moapp/jybase/common"
 	"app.yhyue.com/moapp/jybase/date"
 	"app.yhyue.com/moapp/jybase/encrypt"
+	"bufio"
 	"context"
+	"encoding/json"
 	"fmt"
 	"github.com/gogf/gf/v2/encoding/gjson"
 	"github.com/gogf/gf/v2/frame/g"
 	"github.com/gogf/gf/v2/net/ghttp"
 	"github.com/gogf/gf/v2/os/glog"
 	"github.com/gogf/gf/v2/util/gconv"
+	"io"
 	"time"
 )
 
@@ -29,23 +32,31 @@ func NewMessage(ctx context.Context) *WsChat {
 func (m *WsChat) Handle(ws *ghttp.WebSocket, msg []byte) {
 	defer Catch()
 	jSession := SessionCtx.Get(m.Ctx).JSession
-
-	req := &QuestionReq{}
+	if jSession.PositionId == 0 {
+		_ = ws.WriteJSON(g.Map{
+			"error_code": -1,
+			"error_msg":  "请登录",
+		})
+		return
+	}
+	req, from := &QuestionReq{}, 0
 	if err := gjson.Unmarshal(msg, req); err != nil {
 		glog.Errorf(m.Ctx, "%d 接收消息Unmarshal出错:%v", jSession.PositionId, err)
 		return
 	}
-	reply, replyId, errMsg := func() (string, int64, error) {
-		questionId := ChatHistory.Save(m.Ctx, &ChatRecord{
-			Content:    req.Prompt,
-			Type:       1,
-			Refer:      req.Href,
-			PersonId:   jSession.PositionId,
-			CreateTime: time.Now().Format(date.Date_Full_Layout),
-		})
-
-		var err error
-		reply, from := "", 0
+	questionId := ChatHistory.Save(m.Ctx, &ChatRecord{
+		Content:    req.Prompt,
+		Type:       1,
+		Refer:      req.Href,
+		PersonId:   jSession.PositionId,
+		CreateTime: time.Now().Format(date.Date_Full_Layout),
+	})
+	content, buf, replyId, errMsg := func() (string, *bufio.Reader, int64, error) {
+		var (
+			err   error
+			buf   *bufio.Reader
+			reply string
+		)
 		errReply := func() string {
 			// 校验是否在黑名单,黑名单不返回内容
 			if UserBlackList.CheckBlackList(m.Ctx, jSession.PositionId) {
@@ -64,35 +75,78 @@ func (m *WsChat) Handle(ws *ghttp.WebSocket, msg []byte) {
 		if errReply != "" {
 			reply, from = errReply, -1
 		} else {
-			reply, from, err = Question.DetailQuestion(m.Ctx, req)
+			reply, buf, from, err = Question.DetailQuestion(m.Ctx, req)
 			if err != nil {
 				g.Log().Error(m.Ctx, "问答异常", err)
 				reply, from = g.Cfg().MustGet(m.Ctx, "limit.errMsg").String(), -1
 			}
+		}
+
+		if from != Answer_ChatGPT {
 			if reply == "" {
 				reply, from = g.Cfg().MustGet(m.Ctx, "limit.emptyMsg").String(), -1
 			}
+			replyId := ChatHistory.Save(m.Ctx, &ChatRecord{
+				Content:    reply,
+				Type:       2,
+				Actions:    gconv.Int(If(errReply == "", 1, 0)),
+				QuestionId: questionId,
+				PersonId:   jSession.PositionId,
+				Item:       gconv.Int(If(errReply == "", from, -1)),
+				CreateTime: time.Now().Format(date.Date_Full_Layout),
+			})
+			if replyId <= 0 {
+				g.Log().Error(m.Ctx, "问答存储存储异常")
+			}
+			return reply, nil, replyId, nil
 		}
-
-		// 记录问答
-		replyId := ChatHistory.Save(m.Ctx, &ChatRecord{
-			Content:    reply,
-			Type:       2,
-			Actions:    gconv.Int(If(errReply == "", 1, 0)),
-			QuestionId: questionId,
-			PersonId:   jSession.PositionId,
-			Item:       gconv.Int(If(errReply == "", from, -1)),
-			CreateTime: time.Now().Format(date.Date_Full_Layout),
-		})
-		if replyId <= 0 {
-			g.Log().Error(m.Ctx, "问答存储存储异常")
-		}
-		return reply, replyId, nil
+		return reply, buf, 0, nil
 	}()
+	if from != Answer_ChatGPT {
+		if errMsg != nil {
+			_ = ws.WriteJSON(g.Map{"error_code": -1, "error_msg": errMsg.Error(), "data": nil})
+		} else {
+			_ = ws.WriteJSON(g.Map{"error_code": 0, "error_msg": "", "data": g.Map{"id": encrypt.SE.Encode2Hex(fmt.Sprintf("%d", replyId)), "reply": content, "isEnd": true}})
+		}
+	} else if buf != nil {
+		for {
+			line, _, err := buf.ReadLine()
+			if err == io.EOF {
+				break
+			}
+			if _, data := parseEventStream(line); data != nil {
+				if data.Finished {
+					replyId := ChatHistory.Save(m.Ctx, &ChatRecord{
+						Content:    data.Response,
+						Type:       2,
+						Actions:    1,
+						QuestionId: questionId,
+						PersonId:   jSession.PositionId,
+						Item:       Answer_ChatGPT,
+						CreateTime: time.Now().Format(date.Date_Full_Layout),
+					})
+					_ = ws.WriteJSON(g.Map{"error_code": 0, "error_msg": "", "data": g.Map{"id": encrypt.SE.Encode2Hex(fmt.Sprintf("%d", replyId)), "reply": data.Response, "replyByte": data.Delta, "isEnd": data.Finished}})
+				} else {
+					_ = ws.WriteJSON(g.Map{"error_code": 0, "error_msg": "", "data": g.Map{"reply": data.Response, "replyByte": data.Delta, "isEnd": data.Finished}})
+				}
+			}
+		}
+	}
+}
 
-	if errMsg != nil {
-		_ = ws.WriteJSON(g.Map{"error_code": -1, "error_msg": errMsg.Error(), "data": nil})
-	} else {
-		_ = ws.WriteJSON(g.Map{"error_code": 0, "error_msg": "", "data": g.Map{"id": encrypt.SE.Encode2Hex(fmt.Sprintf("%d", replyId)), "reply": reply}})
+func parseEventStream(line []byte) (event string, date *BufRes) {
+	// 如果行以 "event:" 开头,表示这是一个事件的标识符
+	if len(line) > 6 && string(line[:6]) == "event:" {
+		event = string(line[6 : len(line)-1])
+		return event, nil
+	}
+	// 如果行以 "data:" 开头,表示这是事件的数据部分
+	if len(line) > 5 && string(line[:5]) == "data:" {
+		date = &BufRes{}
+		if err := json.Unmarshal(line[5:len(line)], date); err == nil {
+			return
+		}
+		return event, nil
 	}
+	return "", nil
 }

+ 1 - 1
manifest/config/config.yaml

@@ -18,7 +18,7 @@ chat:
   resourceCode: "ai_helper" # 资源扣减
   api: #ChatGpt 配置
     addr_simple: "http://192.168.3.109:8880/search" # 语义服务
-    addr_answer: "http://192.168.3.109:12001" # ai回答接口
+    addr_answer: "http://192.168.3.109:12001/stream" # ai回答接口
     identity: "剑鱼chat"
   businessRpc: "192.168.3.149:5051" #业务逻辑rpc地址