Files
EasySoft-ZenTaoPMS/module/zai/control.php

237 lines
8.2 KiB
PHP

<?php
/**
* The control file of zai module of ZenTaoPMS.
*
* @copyright Copyright 2009-2025 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.cnezsoft.com)
* @license ZPL(http://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @author tenghuaian <tenghuaian@chandao.com>
* @link https://www.zentao.net
*/
class zai extends control
{
/**
* 配置ZAI。
* Configure ZAI.
*
* @param string $mode
* @access public
* @return void
*/
public function setting($mode = 'view')
{
if(!empty($_POST))
{
$setting = new stdClass();
$setting->appID = trim($_POST['appID']);
$setting->host = trim($_POST['host']);
$setting->port = trim($_POST['port']);
$setting->token = trim($_POST['token']);
$setting->adminToken = trim($_POST['adminToken']);
if(empty($setting->host)) $setting = null;
$this->zai->setSetting($setting);
if(dao::isError()) return $this->sendError(dao::getError());
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'load' => $this->createLink('zai', 'setting')));
}
$setting = $this->zai->getSetting(true);
if($mode == 'view')
{
if(!empty($setting->token)) $setting->token = str_repeat('*', strlen($setting->token));
if(!empty($setting->adminToken)) $setting->adminToken = str_repeat('*', strlen($setting->adminToken));
}
$this->view->title = $this->lang->zai->setting;
$this->view->setting = $setting;
$this->view->mode = $mode;
$this->display();
}
/**
* Ajax: 获取当前用户的ZAI Authorization token。
* Ajax: Get ZAI Authorization Token of current user.
*
* @access public
* @return void
*/
public function ajaxGetToken()
{
return $this->send($this->zai->getToken());
}
/**
* 禅道数据向量化。
* Vectorized data of ZenTao.
*
* @access public
* @return void
*/
public function vectorized()
{
$info = $this->zai->getVectorizedInfo();
$this->view->info = $info;
$this->view->title = $this->lang->zai->vectorized;
$this->view->zaiSetting = $this->zai->getSetting();
$this->view->syncTypes = zaiModel::getSyncTypes();
$this->display();
}
/**
* Ajax: 启用数据向量化。
* Ajax: Enable data vectorization.
*
* @access public
* @return void
*/
public function ajaxEnableVectorization()
{
if($_SERVER['REQUEST_METHOD'] !== 'POST')
{
return $this->send(array('result' => 'failed', 'message' => $this->lang->zai->onlyPostRequest));
}
$force = isset($_POST['force']) && $_POST['force'] === 'true';
$result = $this->zai->enableVectorization($force);
return $this->send($result);
}
/**
* Ajax: 同步禅道向量化数据到 ZAI 知识库。
* Ajax: Sync vectorized data of ZenTao to ZAI knowledge base.
*
* @access public
* @return void
*/
public function ajaxSyncVectorization()
{
$info = $this->zai->getVectorizedInfo();
if($_SERVER['REQUEST_METHOD'] !== 'POST')
{
return $this->send(array('result' => 'success', 'data' => $info));
}
if(empty($info->key)) return $this->send(array('result' => 'failed', 'message' => $this->lang->zai->vectorizedUnavailableHint, 'data' => $info));
$force = isset($_POST['force']) && $_POST['force'] === 'true';
if($info->status === 'synced' && $force)
{
$info->status = 'wait';
$info->syncedTime = 0;
$info->syncedCount = 0;
$info->syncFailedCount = 0;
$info->syncTime = 0;
$info->syncingType = zaiModel::getNextSyncType();
$info->syncingID = 0;
$info->syncDetails = new stdClass();
}
if($info->status !== 'wait' && $info->status !== 'syncing')
{
return $this->send(array('result' => 'success', 'data' => $info));
}
if($info->status !== 'syncing')
{
$info->status = 'syncing';
$info->synced = 0;
}
$startSyncTime = microtime(true) * 1000;
$info->syncTime = time();
$result = $this->zai->syncNextTarget($info->key, $info->syncingType, $info->syncingID);
$syncingType = $info->syncingType;
if(!isset($info->syncDetails->$syncingType))
{
$syncDetail = new stdClass();
$syncDetail->failed = 0;
$syncDetail->synced = 0;
$info->syncDetails->$syncingType = $syncDetail;
}
if($result)
{
if(isset($result['fatal']) && $result['fatal'])
{
$info->status = 'synced';
$info->syncFailedCount++;
$info->syncDetails->$syncingType->failed++;
$this->zai->setVectorizedInfo($info);
return $this->send(array('result' => 'failed', 'message' => $result['message'], 'data' => $info, 'request' => $this->app->config->debug > 5 ? $result : null));
}
if($result['result'] == 'success')
{
$info->syncedCount++;
$info->syncDetails->$syncingType->synced++;
}
else
{
$info->syncFailedCount++;
$info->syncDetails->$syncingType->failed++;
}
$info->syncingID = (isset($result['id']) ? $result['id'] : $info->syncingID) + 1;
$info->lastSync = ['time' => (microtime(true) * 1000) - $startSyncTime, 'contentLength' => isset($result['syncedData']) ? strlen($result['syncedData']['content']) : 0, 'type' => $info->syncingType, 'id' => $info->syncingID];
}
else
{
$nextSyncType = zaiModel::getNextSyncType($syncingType);
if(empty($nextSyncType))
{
$info->status = 'synced';
$info->syncedTime = $info->syncTime;
$info->syncingID = 0;
$info->syncingType = zaiModel::getNextSyncType();
}
else
{
$info->syncingType = $nextSyncType;
$info->syncingID = 0;
}
}
$this->zai->setVectorizedInfo($info);
unset($info->key);
return $this->send(array('result' => 'success', 'data' => $info));
}
/**
* Ajax: 搜索知识库。
* Ajax: Search knowledge base.
*
* @param string $type 'chunk'(块) | 'content'(内容)
* @param int $limit
* @access public
* @return void
*/
public function ajaxSearchKnowledges(string $type = 'chunk', int $limit = 5)
{
if($_SERVER['REQUEST_METHOD'] !== 'POST')
{
return $this->send(array('result' => 'failed', 'message' => $this->lang->zai->onlyPostRequest));
}
$userPrompt = zget($_POST, 'userPrompt', '');
$filters = json_decode(zget($_POST, 'filters', '{}'), true);
if(empty($userPrompt) || empty($filters)) return $this->send(array('result' => 'failed', 'message' => $this->lang->fail));
$knowledges = $this->zai->searchKnowledgesInCollections($userPrompt, $filters, $type, $limit, 0.5);
$results = [];
foreach($knowledges as $knowledge)
{
if($type === 'chunk')
{
$results[] = ['key' => $knowledge['content_key'], 'similarity' => $knowledge['similarity'], 'id' => $knowledge['chunk_id'], 'content' => $knowledge['chunk_content'], 'attrs' => $knowledge['content_attrs']];
}
else
{
$results[] = ['key' => $knowledge['key'], 'similarity' => $knowledge['similarity'], 'id' => $knowledge['id'], 'content' => $knowledge['content'], 'attrs' => $knowledge['attrs']];
}
if(count($results) >= $limit) break;
}
return $this->send(array('result' => 'success', 'data' => $results));
}
}