feat: 限制用户单日提问次数
This commit is contained in:
+66
-40
@@ -1,4 +1,5 @@
|
||||
// pages/wiki/chat/index.js
|
||||
import request from '../../../utils/request';
|
||||
|
||||
Page({
|
||||
data: {
|
||||
@@ -7,6 +8,8 @@ Page({
|
||||
isTyping: false,
|
||||
scrollAnchor: '',
|
||||
_counter: 0,
|
||||
quotaRemaining: -1,
|
||||
quotaLimit: 0,
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
@@ -25,6 +28,19 @@ Page({
|
||||
}
|
||||
},
|
||||
|
||||
onShow() {
|
||||
this._fetchQuota();
|
||||
},
|
||||
|
||||
_fetchQuota() {
|
||||
request.get('/plant/chat/quota').then(res => {
|
||||
this.setData({
|
||||
quotaRemaining: res.remaining,
|
||||
quotaLimit: res.limit,
|
||||
});
|
||||
}).catch(() => {});
|
||||
},
|
||||
|
||||
goToHistory() {
|
||||
wx.navigateTo({ url: '/pages/wiki/chat/history/index' });
|
||||
},
|
||||
@@ -42,11 +58,16 @@ Page({
|
||||
const query = this.data.inputValue.trim();
|
||||
if (!query || this.data.isTyping) return;
|
||||
|
||||
// 额度检查
|
||||
if (this.data.quotaRemaining === 0) {
|
||||
wx.showToast({ title: '今日问答次数已用完,明天再来吧', icon: 'none', duration: 2500 });
|
||||
return;
|
||||
}
|
||||
|
||||
const uid = 'u' + (++this.data._counter);
|
||||
const aid = 'a' + (++this.data._counter);
|
||||
const len = this.data.messages.length;
|
||||
|
||||
// Push user msg + empty AI msg at once
|
||||
this.setData({
|
||||
[`messages[${len}]`]: { id: uid, role: 'user', content: query },
|
||||
[`messages[${len + 1}]`]: { id: aid, role: 'ai', content: '' },
|
||||
@@ -59,53 +80,58 @@ Page({
|
||||
},
|
||||
|
||||
_streamRequest(query, aiMsgId) {
|
||||
const token = wx.getStorageSync('token');
|
||||
const baseUrl = 'http://192.168.0.184:8889';
|
||||
const url = `${baseUrl}/plant/chat/stream?query=${encodeURIComponent(query)}`;
|
||||
let fullText = '';
|
||||
|
||||
const task = wx.request({
|
||||
url,
|
||||
method: 'GET',
|
||||
enableChunked: true,
|
||||
header: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Accept': 'text/event-stream',
|
||||
},
|
||||
success: () => {
|
||||
this.setData({ isTyping: false });
|
||||
request.stream('/plant/chat/stream', { query }, {
|
||||
onChunk: (res) => {
|
||||
const text = this._decode(res.data);
|
||||
|
||||
// Detect non-SSE JSON error (e.g. quota exceeded returns {code:7, msg:"..."})
|
||||
if (!text.startsWith('data: ')) {
|
||||
try {
|
||||
const json = JSON.parse(text);
|
||||
if (json.code && json.code !== 200 && json.msg) {
|
||||
this._updateAiMsg(aiMsgId, '⚠️ ' + json.msg);
|
||||
this.setData({ isTyping: false });
|
||||
this._fetchQuota();
|
||||
return;
|
||||
}
|
||||
} catch (_) { /* not JSON, continue SSE parsing */ }
|
||||
}
|
||||
|
||||
const lines = text.split('\n');
|
||||
|
||||
for (const line of lines) {
|
||||
if (!line.startsWith('data: ')) continue;
|
||||
const chunk = line.substring(6);
|
||||
|
||||
if (chunk === '[DONE]') {
|
||||
this.setData({ isTyping: false });
|
||||
return;
|
||||
}
|
||||
if (chunk.startsWith('[ERROR]')) {
|
||||
fullText += '\n⚠️ ' + (chunk.substring(7) || '服务异常');
|
||||
this._updateAiMsg(aiMsgId, fullText);
|
||||
this.setData({ isTyping: false });
|
||||
return;
|
||||
}
|
||||
|
||||
fullText += chunk;
|
||||
this._updateAiMsg(aiMsgId, fullText);
|
||||
}
|
||||
this.scrollToBottom();
|
||||
},
|
||||
fail: () => {
|
||||
onDone: () => {
|
||||
this.setData({ isTyping: false });
|
||||
this.scrollToBottom();
|
||||
// Delay: backend saves history async (go func) after stream ends
|
||||
setTimeout(() => this._fetchQuota(), 800);
|
||||
},
|
||||
onError: () => {
|
||||
this._updateAiMsg(aiMsgId, '网络连接失败,请稍后重试');
|
||||
this.setData({ isTyping: false });
|
||||
},
|
||||
});
|
||||
|
||||
task.onChunkReceived((res) => {
|
||||
const text = this._decode(res.data);
|
||||
const lines = text.split('\n');
|
||||
|
||||
for (const line of lines) {
|
||||
if (!line.startsWith('data: ')) continue;
|
||||
const chunk = line.substring(6);
|
||||
|
||||
if (chunk === '[DONE]') {
|
||||
this.setData({ isTyping: false });
|
||||
return;
|
||||
}
|
||||
if (chunk.startsWith('[ERROR]')) {
|
||||
fullText += '\n⚠️ ' + (chunk.substring(7) || '服务异常');
|
||||
this._updateAiMsg(aiMsgId, fullText);
|
||||
this.setData({ isTyping: false });
|
||||
return;
|
||||
}
|
||||
|
||||
fullText += chunk;
|
||||
this._updateAiMsg(aiMsgId, fullText);
|
||||
}
|
||||
this.scrollToBottom();
|
||||
});
|
||||
},
|
||||
|
||||
_updateAiMsg(id, content) {
|
||||
|
||||
Reference in New Issue
Block a user