Skip to content

Commit

Permalink
feat: 封装chat部分代码&在题目页面添加AI
Browse files Browse the repository at this point in the history
  • Loading branch information
daizeyao committed Dec 15, 2024
1 parent 551b969 commit 0079e9a
Show file tree
Hide file tree
Showing 17 changed files with 551 additions and 424 deletions.
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v2.7.5
v2.8.0
15 changes: 15 additions & 0 deletions docs/init-dev-mac.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,18 @@ docker run \
--character-set-server=utf8mb4 \
--collation-server=utf8mb4_unicode_ci
```

hznuoj docker php7.0配置curl
```
apt-get install curl libcurl4 libcurl4-openssl-dev php7.0-curl
```

ollama局域网配置

```
sudo vim /etc/systemd/system/ollama.service
Environment="OLLAMA_HOST=0.0.0.0:11434"
sudo ufw allow 11434/tcp
systemctl daemon-reload
systemctl restart ollama
```
68 changes: 45 additions & 23 deletions web/OJ/chat.php
Original file line number Diff line number Diff line change
@@ -1,37 +1,52 @@
<?php

// 设置时区为东八区
date_default_timezone_set('PRC');
require_once('./include/cache_start.php');

// 这行代码用于关闭输出缓冲。关闭后,脚本的输出将立即发送到浏览器,而不是等待缓冲区填满或脚本执行完毕。
date_default_timezone_set('PRC');
ini_set('output_buffering', 'off');

// 这行代码禁用了 zlib 压缩。通常情况下,启用 zlib 压缩可以减小发送到浏览器的数据量,但对于服务器发送事件来说,实时性更重要,因此需要禁用压缩。
ini_set('zlib.output_compression', false);

// 这行代码使用循环来清空所有当前激活的输出缓冲区。ob_end_flush() 函数会刷新并关闭最内层的输出缓冲区,@ 符号用于抑制可能出现的错误或警告。
while (@ob_end_flush()) {
}

// 这行代码设置 HTTP 响应的 Content-Type 为 text/event-stream,这是服务器发送事件(SSE)的 MIME 类型。
header('Content-Type: text/event-stream');

// 这行代码设置 HTTP 响应的 Cache-Control 为 no-cache,告诉浏览器不要缓存此响应。
header('Cache-Control: no-cache');

// 这行代码设置 HTTP 响应的自定义头部 X-Accel-Buffering 为 no,用于禁用某些代理或 Web 服务器(如 Nginx)的缓冲。
header('X-Accel-Buffering: no');

require_once './include/static.php';
// 未登录禁止使用
if (isset($_SESSION['user_id'])) {
$uid = $mysqli->real_escape_string($_SESSION['user_id']);
} else {
echo "data: " . json_encode(["code" => "499", "error" => "No user"]) . "\n\n";
flush();
exit();
}

// 引入敏感词检测类
require './class/Class.DFA.php';
// 检查请求头,确保是通过 EventSource 发起的请求
if ($_SERVER['HTTP_ACCEPT'] !== 'text/event-stream') {
header('HTTP/1.1 403 Forbidden');
echo "This endpoint can only be accessed via EventSource.";
exit();
}

// TODO:查询是否禁用AI功能

// 查询当前用户是否正处于AI对话中

$currentTime = time();
if (isset($_SESSION['last_chat_time'])) {
$lastChatTime = $_SESSION['last_chat_time'];
if (($currentTime - $lastChatTime) < 5) {
echo "data: " . json_encode(["code" => "498", "error" => "In Conversation now"]) . "\n\n";
flush();
exit();
}
}
$_SESSION['last_chat_time'] = $currentTime;

// 引入流处理类
require './class/Class.StreamHandler.php';

// 引入调用 OpenAI 接口类
require './class/Class.ChatGPT.php';
require_once './include/static.php';
require './class/Class.DFA.php';
require './class/Class.StreamHandler.php';
require './class/Class.OllamaChat.php';

echo 'data: ' . json_encode(['time' => date('Y-m-d H:i:s'), 'content' => '']) . PHP_EOL . PHP_EOL;
flush();
Expand All @@ -47,19 +62,26 @@

// api 和 模型选择
$chat = new OllamaChat(
"http://$DB_HOST:11434/api/generate",
"http://$AI_HOST:11434/api/generate",
"$AI_MODEL"
);

$DOCUMENT_ROOT = $_SERVER['DOCUMENT_ROOT'];
$dfa = new DFA([
'words_file' => "$DOCUMENT_ROOT/OJ/plugins/code-helper/dict.txt",
'words_file' => "$DOCUMENT_ROOT/OJ/plugins/hznuojai/dict.txt",
]);
$chat->set_dfa($dfa);


// 开始提问
$chat->qa([
'system' => '你是HznuOnlineJudge的智能代码助手,只负责和代码相关的问题',
'system' => '你是杭州师范大学在线测评系统的智能代码助手,你负责且只负责回答代码相关的问题,并且使用中文回答,代码部分使用```包围,下面是问题:',
'question' => $question,
]);


// echo "*************************************" . PHP_EOL;
unset($_SESSION['last_chat_time']);

if(file_exists('./include/cache_end.php'))
require_once('./include/cache_end.php');
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public function set_dfa(&$dfa)
public function qa($params)
{

$this->question = $params['question'];
$this->question = $params['system'] . $params['question'];
$this->streamHandler = new StreamHandler([
'qmd5' => md5($this->question . '' . time())
]);
Expand All @@ -53,30 +53,9 @@ public function qa($params)
$this->ollamaApiCall($json, $headers);
}

private function buildCurlCommand($json, $headers)
{
$command = "curl";

// 添加 URL
$command .= " '" . $this->api_url . "'";

// 添加请求头
foreach ($headers as $header) {
$command .= " -H '" . str_replace("'", "\'", $header) . "'";
}

// 添加 POST 数据
if ($json) {
$command .= " -d '" . str_replace("'", "\'", $json) . "'";
}

// 你可以继续添加其他 cURL 选项,如需要

return $command;
}

private function ollamaApiCall($json, $headers)
{ // 修改后的方法名
{
// 注意 curl 需要开启 php 拓展
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->api_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
Expand All @@ -90,9 +69,6 @@ private function ollamaApiCall($json, $headers)

curl_setopt($ch, CURLOPT_WRITEFUNCTION, [$this->streamHandler, 'callback']);

// $curlCommand = $this->buildCurlCommand($json, $headers);
// echo $curlCommand . PHP_EOL;

$response = curl_exec($ch);

if (curl_errno($ch)) {
Expand Down
5 changes: 2 additions & 3 deletions web/OJ/class/Class.StreamHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

class StreamHandler
{

private $data_buffer; //缓存,有可能一条data被切分成两部分了,无法解析json,所以需要把上一半缓存起来
private $counter; //数据接收计数器
private $qmd5; //问题md5
Expand Down Expand Up @@ -33,9 +32,9 @@ public function callback($ch, $data)
$this->counter += 1;
file_put_contents('./log/data.' . $this->qmd5 . '.log', $this->counter . '==' . $data . PHP_EOL . '--------------------' . PHP_EOL, FILE_APPEND);

echo $data;
// echo $data;

$result = json_decode($data, TRUE);
// $result = json_decode($data, TRUE);

// if (is_array($result)) {
// $this->end('openai 请求错误:' . json_encode($result));
Expand Down
Loading

0 comments on commit 0079e9a

Please sign in to comment.