feat(llm): 启用AI点评功能并新增AI聊天API接口,自动创建相关数据库表
This commit is contained in:
@@ -215,40 +215,104 @@
|
||||
$('#llm-review-error').hide();
|
||||
$('#llm-review-result').hide();
|
||||
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: 'llm-review.php?sid=<?php echo intval($id); ?>',
|
||||
dataType: 'json',
|
||||
timeout: 60000,
|
||||
success: function(data){
|
||||
btn.removeClass('loading');
|
||||
$('#llm-review-loading').hide();
|
||||
if(data.error){
|
||||
$('#llm-review-error-msg').text(data.error);
|
||||
$('#llm-review-error').show();
|
||||
btn.prop('disabled', false);
|
||||
} else if(data.review){
|
||||
$('#llm-review-result').show();
|
||||
var container = document.getElementById('llm-review-content');
|
||||
// 先以纯文本放入,再用 Vditor 渲染为 Markdown HTML
|
||||
container.textContent = data.review;
|
||||
if(typeof HustOJVditor !== 'undefined' && HustOJVditor.renderMarkdownBlocks){
|
||||
HustOJVditor.renderMarkdownBlocks('#llm-review-content', {
|
||||
useTextContent: true
|
||||
});
|
||||
}
|
||||
btn.hide();
|
||||
var fullText = "";
|
||||
var container = document.getElementById('llm-review-content');
|
||||
var resultDiv = document.getElementById('llm-review-result');
|
||||
var reader = null;
|
||||
var decoder = new TextDecoder();
|
||||
|
||||
// 解析 SSE 事件
|
||||
var sseBuffer = "";
|
||||
function processSSE(text) {
|
||||
sseBuffer += text;
|
||||
var lines = sseBuffer.split('\n');
|
||||
sseBuffer = lines.pop(); // 保留未完成的行
|
||||
|
||||
var currentEvent = "";
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
var line = lines[i];
|
||||
if (line.indexOf('event: ') === 0) {
|
||||
currentEvent = line.substring(7);
|
||||
} else if (line.indexOf('data: ') === 0) {
|
||||
var dataStr = line.substring(6);
|
||||
try {
|
||||
var data = JSON.parse(dataStr);
|
||||
if (currentEvent === 'chunk') {
|
||||
fullText += data.text;
|
||||
container.textContent = fullText;
|
||||
resultDiv.style.display = 'block';
|
||||
} else if (currentEvent === 'cached') {
|
||||
fullText = data.text;
|
||||
container.textContent = fullText;
|
||||
resultDiv.style.display = 'block';
|
||||
} else if (currentEvent === 'done') {
|
||||
finishReview();
|
||||
} else if (currentEvent === 'error') {
|
||||
showError(data.message || '未知错误');
|
||||
}
|
||||
} catch(e) {}
|
||||
currentEvent = "";
|
||||
}
|
||||
},
|
||||
error: function(xhr, status){
|
||||
btn.removeClass('loading').prop('disabled', false);
|
||||
$('#llm-review-loading').hide();
|
||||
var msg = '请求失败';
|
||||
if(status === 'timeout') msg = '请求超时,请稍后重试';
|
||||
$('#llm-review-error-msg').text(msg);
|
||||
$('#llm-review-error').show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function finishReview() {
|
||||
btn.removeClass('loading').hide();
|
||||
document.getElementById('llm-review-loading').style.display = 'none';
|
||||
resultDiv.style.display = 'block';
|
||||
// 渲染 Markdown
|
||||
if (fullText && typeof HustOJVditor !== 'undefined' && HustOJVditor.renderMarkdownBlocks) {
|
||||
HustOJVditor.renderMarkdownBlocks('#llm-review-content', { useTextContent: true });
|
||||
}
|
||||
}
|
||||
|
||||
function showError(msg) {
|
||||
btn.removeClass('loading').prop('disabled', false);
|
||||
document.getElementById('llm-review-loading').style.display = 'none';
|
||||
document.getElementById('llm-review-error-msg').textContent = msg;
|
||||
document.getElementById('llm-review-error').style.display = 'block';
|
||||
}
|
||||
|
||||
if (typeof fetch === 'undefined') {
|
||||
showError('浏览器不支持,请升级浏览器');
|
||||
return;
|
||||
}
|
||||
|
||||
fetch('llm-review.php?sid=<?php echo intval($id); ?>')
|
||||
.then(function(response) {
|
||||
if (!response.ok) {
|
||||
return response.text().then(function(text) {
|
||||
try {
|
||||
var d = JSON.parse(text);
|
||||
showError(d.error || '请求失败 (HTTP ' + response.status + ')');
|
||||
} catch(e) {
|
||||
showError('请求失败 (HTTP ' + response.status + ')');
|
||||
}
|
||||
});
|
||||
}
|
||||
reader = response.body.getReader();
|
||||
function read() {
|
||||
reader.read().then(function(result) {
|
||||
if (result.done) {
|
||||
if (fullText) finishReview();
|
||||
return;
|
||||
}
|
||||
var text = decoder.decode(result.value, { stream: true });
|
||||
processSSE(text);
|
||||
read();
|
||||
}).catch(function(err) {
|
||||
if (fullText) {
|
||||
finishReview();
|
||||
} else {
|
||||
showError('读取响应失败: ' + err.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
read();
|
||||
})
|
||||
.catch(function(err) {
|
||||
showError('网络请求失败: ' + err.message);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<?php } ?>
|
||||
|
||||
Reference in New Issue
Block a user