mirror of
https://github.com/yangjian102621/geekai.git
synced 2025-09-17 16:56:38 +08:00
完成聊天 websocket API 对接
This commit is contained in:
parent
c25cc97450
commit
9477b96629
@ -1,11 +1,34 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gorilla/websocket"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func (s *Server) Chat(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"code": 0, "message": fmt.Sprintf("HELLO, ChatGPT !!!")})
|
||||
ws, err := (&websocket.Upgrader{CheckOrigin: func(r *http.Request) bool { return true }}).Upgrade(c.Writer, c.Request, nil)
|
||||
if err != nil {
|
||||
logger.Fatal(err)
|
||||
return
|
||||
}
|
||||
logger.Infof("New websocket connected, IP: %s", c.Request.RemoteAddr)
|
||||
client := NewWsClient(ws)
|
||||
go func() {
|
||||
for {
|
||||
_, message, err := client.Receive()
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
client.Close()
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: 接受消息,调用 ChatGPT 返回消息
|
||||
logger.Info(string(message))
|
||||
err = client.Send(message)
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
@ -14,18 +14,14 @@ type Client interface {
|
||||
|
||||
// WsClient websocket client
|
||||
type WsClient struct {
|
||||
NodeId string
|
||||
SessionId string
|
||||
Conn *websocket.Conn
|
||||
lock sync.Mutex
|
||||
mt int
|
||||
closed bool
|
||||
}
|
||||
|
||||
func NewWsClient(nodeId string, sessionId string, conn *websocket.Conn) *WsClient {
|
||||
func NewWsClient(conn *websocket.Conn) *WsClient {
|
||||
return &WsClient{
|
||||
NodeId: nodeId,
|
||||
SessionId: sessionId,
|
||||
Conn: conn,
|
||||
lock: sync.Mutex{},
|
||||
mt: 2, // fixed bug for 'Invalid UTF-8 in text frame'
|
||||
|
7
web/src/assets/css/bootstrap.min.css
vendored
Normal file
7
web/src/assets/css/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -6,6 +6,7 @@ import App from './App.vue'
|
||||
import Home from './views/Chat.vue'
|
||||
import NotFound from './views/404.vue'
|
||||
import './utils/prototype'
|
||||
import "./assets/css/bootstrap.min.css"
|
||||
|
||||
|
||||
const routes = [
|
||||
|
@ -1,77 +0,0 @@
|
||||
import axios from 'axios'
|
||||
import JSONBigInt from 'json-bigint'
|
||||
import qs from 'qs'
|
||||
|
||||
import { ElMessageBox } from 'element-plus'
|
||||
|
||||
axios.defaults.timeout = 5000
|
||||
axios.defaults.baseURL = process.env.VUE_APP_API_SECURE === true ? 'https://' + process.env.VUE_APP_API_HOST : 'http://' + process.env.VUE_APP_API_HOST
|
||||
axios.defaults.withCredentials = true
|
||||
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'
|
||||
axios.defaults.transformResponse = [(data, headers) => {
|
||||
if (headers['content-type'].indexOf('application/json') !== -1) {
|
||||
try {
|
||||
data = JSONBigInt.parse(data)
|
||||
} catch (e) { /* Ignore */ }
|
||||
}
|
||||
return data
|
||||
}]
|
||||
|
||||
|
||||
// HTTP拦截器
|
||||
axios.interceptors.request.use(
|
||||
config => {
|
||||
// set session-name
|
||||
config.headers['Session-Name'] = "xwebssh-sess-token"
|
||||
return config
|
||||
}, error => {
|
||||
return Promise.reject(error)
|
||||
})
|
||||
axios.interceptors.response.use(
|
||||
response => {
|
||||
if (response.data.code == 0) {
|
||||
return response
|
||||
} else {
|
||||
return Promise.reject(response.data)
|
||||
}
|
||||
}, error => {
|
||||
if (error.response.status === 401) {
|
||||
ElMessageBox.alert('您未登录或者登录已退出,请先登录再操作。', '登录提醒', {
|
||||
confirmButtonText: '确定',
|
||||
callback: () => {
|
||||
// TODO: goto login page
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
if (error.response.status === 400) {
|
||||
return Promise.reject(error.response.data)
|
||||
}
|
||||
return Promise.reject(error)
|
||||
})
|
||||
|
||||
|
||||
// send a http get request
|
||||
export function httpGet (url, params = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios.get(url, {
|
||||
params: params
|
||||
}).then(response => {
|
||||
resolve(response.data)
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// send a http post request
|
||||
export function httpPost (url, data = {}, options = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios.post(url, qs.stringify(data), options).then(response => {
|
||||
resolve(response.data)
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
/* eslint-disable no-constant-condition */
|
||||
/**
|
||||
* storage handler
|
||||
*/
|
||||
// import Storage from 'good-storage'
|
||||
|
||||
|
@ -16,13 +16,17 @@
|
||||
<div class="input-box" :style="{width: inputBoxWidth+'px'}" id="input-box">
|
||||
<div class="input-container">
|
||||
<textarea class="input-text" id="input-text" rows="1" :style="{minHeight:'24px', height: textHeight+'px'}"
|
||||
v-on:keyup="inputKeyUp"
|
||||
v-on:keydown="inputKeyDown"
|
||||
v-model="inputValue"
|
||||
placeholder="Input any thing here..."
|
||||
autofocus></textarea>
|
||||
</div>
|
||||
<div class="btn-container">
|
||||
<button type="button">发送</button>
|
||||
<button type="button"
|
||||
class="btn btn-success"
|
||||
:disabled="sending"
|
||||
v-on:click="sendMessage">发送
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -60,7 +64,10 @@ export default defineComponent({
|
||||
textHeight: 24,
|
||||
textWidth: 0,
|
||||
chatBoxHeight: 0,
|
||||
isMobile: false
|
||||
isMobile: false,
|
||||
|
||||
socket: null,
|
||||
sending: false
|
||||
}
|
||||
},
|
||||
|
||||
@ -81,6 +88,37 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
window.addEventListener('resize', this.windowResize);
|
||||
|
||||
// 初始化 WebSocket 对象
|
||||
const socket = new WebSocket('ws://172.22.11.200:5678/api/chat');
|
||||
socket.addEventListener('open', () => {
|
||||
console.log('WebSocket 连接已打开');
|
||||
});
|
||||
socket.addEventListener('message', event => {
|
||||
if (event.data instanceof Blob) {
|
||||
const reader = new FileReader();
|
||||
reader.readAsText(event.data, "UTF-8");
|
||||
reader.onload = () => {
|
||||
this.chatData.push({
|
||||
type: "reply",
|
||||
id: randString(32),
|
||||
icon: 'images/gpt-icon.png',
|
||||
content: reader.result
|
||||
});
|
||||
this.sending = false;
|
||||
};
|
||||
}
|
||||
|
||||
});
|
||||
socket.addEventListener('close', event => {
|
||||
console.log('WebSocket 连接已关闭', event.reason);
|
||||
});
|
||||
socket.addEventListener('error', event => {
|
||||
console.error('WebSocket 连接发生错误', event);
|
||||
});
|
||||
|
||||
this.socket = socket;
|
||||
|
||||
},
|
||||
|
||||
beforeUnmount() {
|
||||
@ -88,20 +126,36 @@ export default defineComponent({
|
||||
},
|
||||
|
||||
methods: {
|
||||
inputKeyUp: function (e) {
|
||||
inputKeyDown: function (e) {
|
||||
// PC 端按回车键直接提交数据
|
||||
if (e.keyCode === 13 && !this.isMobile) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
return this.sendMessage();
|
||||
}
|
||||
|
||||
this.inputResize();
|
||||
},
|
||||
|
||||
// 发送消息
|
||||
sendMessage: function () {
|
||||
if (this.sending) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 追加消息
|
||||
this.chatData.push({
|
||||
type: "prompt",
|
||||
id: randString(32),
|
||||
icon: 'images/user-icon.png',
|
||||
content: this.inputValue
|
||||
});
|
||||
this.inputValue = '';
|
||||
console.log("提交数据")
|
||||
}
|
||||
|
||||
this.inputResize();
|
||||
// TODO: 使用 websocket 提交数据到后端
|
||||
this.sending = true;
|
||||
this.socket.send(this.inputValue);
|
||||
this.inputValue = '';
|
||||
return true;
|
||||
},
|
||||
|
||||
// 初始化
|
||||
@ -205,21 +259,6 @@ export default defineComponent({
|
||||
|
||||
button {
|
||||
width 70px;
|
||||
outline none
|
||||
border none
|
||||
cursor pointer
|
||||
background-color: #07c160
|
||||
position: relative;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
font-size 16px
|
||||
box-sizing: border-box;
|
||||
font-weight: 700;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
color: #fff;
|
||||
line-height: 2.25;
|
||||
border-radius: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user