xiaoai/php_server/app/api/logic/KnowledgeLogic.php

1704 lines
66 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace app\api\logic;
use app\common\model\knowledge\Knowledge;
use app\common\model\knowledge\KnowledgeFile;
use app\common\enum\FileEnum;
use app\common\model\knowledge\KnowledgeFileSlice;
use app\common\model\knowledge\KnowledgeRetrieve;
use app\common\model\knowledge\KnowledgeRetrieveSlice;
use app\common\model\knowledge\KnowledgeUseSceneRecord;
use app\common\model\knowledge\KnowledgeBind;
use app\common\service\UploadService;
use app\api\logic\service\TokenLogService;
use app\common\enum\user\AccountLogEnum;
use app\common\logic\AccountLogLogic;
use app\common\model\user\User;
use Exception;
/**
* index
* Class IndexLogic
* @package app\api\logic
*/
class KnowledgeLogic extends ApiLogic
{
const KNOELEDGE_CREATE = 'knowledge_create'; //知识库创建
const KNOELEDGE_RETRIEVE = 'knowledge_retrieve'; //知识库检索
const KNOELEDGE_CHAT = 'knowledge_chat'; //知识库聊天
const RERANK_MIN_SCORE = 0.2; //知识库检索最小分数
/**
* 知识库列表
*
* @param array $data
* @return void
*/
public static function getListData(array $params){
$params['name'] = $params['name'] ?? '';
$result = Knowledge::where(['user_id' => self::$uid])
->when($params['name'], function ($query) use($params) {
$query->where('name', 'like', '%'. $params['name']. '%');
})
->select()
->each(function ($item) {
$item->file_count = KnowledgeFile::where(['index_id' => $item['index_id']])->count();
})
->toArray();
$data = [
'lists' => $result,
'count' => Knowledge::where(['user_id' => self::$uid])
->when($params['name'], function ($query) use($params) {
$query->where('name', 'like', '%'. $params['name']. '%');
})->count(),
'page_no' => $params['page_no'] ?? 1,
'page_size' => $params['page_size'] ?? 10,
];
return $data;
}
/**
* 知识库创建
*
* @param array $data
* @return void
*/
public static function add(array $params){
if(!isset($params['name']) || empty($params['name'])){
throw new \Exception('知识库名称不能为空');
}
if(mb_strlen($params['name'], "UTF-8") > 12){
throw new \Exception('知识名称不能超过12个字符');
}
if(mb_strlen($params['description'], "UTF-8") > 1000){
throw new \Exception('知识库描述不能超过1000个字符');
}
$find = Knowledge::where('name', $params['name'])->where('user_id', self::$uid)->limit(1)->find();
if (!empty($find)){
message('知识库名称已存在');
}
if(strpos($params['description'], $_SERVER['HTTP_HOST']) === false){
$params['description'] = $params['description'];
}
$params['site'] = $_SERVER['HTTP_HOST'];
# 检查创建知识库的算力是否足够,不够则提示
//计费
$unit = TokenLogService::checkToken(self::$uid, self::KNOELEDGE_CREATE);
# 1 创建分类
$knowledgeNmae = $params['name'].bin2hex(random_bytes(4));
$cateRes = \app\common\service\ToolsService::Knowledge()->createCategory([
'name' => $knowledgeNmae
]);
if((int)$cateRes['code'] === 10000){
if(isset($cateRes['data']['status']) && (int)$cateRes['data']['status'] === 1){
message($cateRes['data']['msg']);
return false;
}
# 2 创建同名分类知识库
$params['category_id'] = $cateRes['data']['CategoryId'];
$params['task_id'] = generate_unique_task_id();
$request = $params;
$request['name'] = $knowledgeNmae;
$request['description'] = $params['site'] . ' '.$params['description'];
$indexRes = self::requestUrl($request, self::KNOELEDGE_CREATE, self::$uid);
if($indexRes){
unset($params['task_id']);
$addData = $params;
$addData['user_id'] = self::$uid;
$addData['index_id'] = $indexRes['Id'];
$addData['category_id'] = $cateRes['data']['CategoryId'];
$addData['create_time'] = time();
$addData['status'] = 1;
$addData['is_bind'] = 0;
$addData['rerank_min_score'] = $params['rerank_min_score'] ?? self::RERANK_MIN_SCORE;
$detial = new Knowledge();
if($detial->save($addData)){
if(!empty($params['documents'])){
$file_ids = array_column($params['documents'], 'file_id');
$addDocRes = \app\common\service\ToolsService::Knowledge()->addDocJobIndex([
'indexid' => $indexRes['Id'],
'documentIds' => $file_ids,
]);
if((int)$addDocRes['code'] === 10000){
$docs = array_map(function($doc) use ($detial, $params, $indexRes){
$_tmp = array();
$_tmp['file_id'] = $doc['file_id'];
$_tmp['category_id'] = $doc['category_id'] ?? '';
$_tmp['status'] = $doc['status'] ?? 'PARSE_SUCCESS';
$_tmp['type'] = $doc['type'] ?? '';
$_tmp['name'] = $doc['name'];
$_tmp['size'] = $doc['size'] ?? 0;
$_tmp['parser'] = $doc['parser'] ?? 'DASHSCOPE_DOCMIND';
$_tmp['user_id'] = self::$uid;
$_tmp['index_id'] = $indexRes['Id'];
$_tmp['kid'] = $detial->id;
$_tmp['file_url'] = $doc['uri'] ?? ($doc['file_url'] ?? '');
$_tmp['create_time'] = time();
return $_tmp;
}, $params['documents']);
if(!empty($docs)){
$detialFile = new KnowledgeFile();
$detialFile->saveAll($docs);
}
}else{
message($addDocRes['message']);
}
}
self::$returnData = $detial->toArray();
return true;
}
}else{
message('知识库创建失败');
}
}else{
message($cateRes['message']);
}
}
public static function edit(array $params){
$find = Knowledge::where('id', $params['id'])->where('user_id', self::$uid)->findOrEmpty();
if ($find->isEmpty()){
message('知识库不存在');
}
if(mb_strlen($params['name'], "UTF-8") > 12){
throw new \Exception('知识名称不能超过12个字符');
}
if(mb_strlen($params['description'], "UTF-8") > 1000){
message('知识库描述不能超过1000个字符');
}
$row = Knowledge::where('name', $params['name'])->where('id', '<>', $params['id'])->where('user_id', self::$uid)->limit(1)->find();
if (!empty($row)){
message('知识库名称重复');
}
// if($params['overlap_size'] > $params['chunk_size']){
// message('分段预估长度必须大于分段重叠长度');
// }
$addData = $params;
$addData['update_time'] = time();
unset($addData['create_time']);
if($find->save($addData)){
}
self::$returnData = $find->toArray();
return true;
}
public static function edit1(array $params){
$find = Knowledge::where('id', $params['id'])->where('user_id', self::$uid)->findOrEmpty();
if ($find->isEmpty()){
message('知识库不存在');
}
if(strlen($params['description']) > 1000){
message('知识库描述不能超过1000个字符');
}
$addData = $params;
$addData['update_time'] = time();
unset($addData['create_time']);
if($find->save($addData)){
KnowledgeFile::where('user_id', '=', self::$uid)->where('kid', '=', $params['id'])->select()->delete();
if(!empty($params['documents'])){
$file_ids = array_column($params['documents'], 'file_id');
//先删除在添加
$delDocRes = \app\common\service\ToolsService::Knowledge()->deleteDocIndex([
'indexid' => $find['index_id'],
'documentids' => $file_ids,
]);
if((int)$delDocRes['code'] === 10000){
$addDocRes = \app\common\service\ToolsService::Knowledge()->addDocJobIndex([
'indexid' => $find['index_id'],
'documentIds' => $file_ids,
]);
if((int)$addDocRes['code'] !== 10000){
message($addDocRes['message']);
}
$docs = array_map(function($doc) use ($find, $params){
$_tmp['file_id'] = $doc['file_id'];
$_tmp['category_id'] = $doc['category_id'] ?? '';
$_tmp['status'] = $doc['status'] ?? 'PARSE_SUCCESS';
$_tmp['type'] = $doc['type'] ?? '';
$_tmp['name'] = $doc['name'];
$_tmp['size'] = $doc['size'] ?? 0;
$_tmp['parser'] = $doc['parser'] ?? 'DASHSCOPE_DOCMIND';
$_tmp['user_id'] = self::$uid;
$_tmp['index_id'] = $find['index_id'];
$_tmp['kid'] = $find->id;
$_tmp['file_url'] = $doc['uri'] ?? ($doc['file_url'] ?? '');
$_tmp['create_time'] = time();
return $_tmp;
}, $params['documents']);
if(!empty($docs)){
$detialFile = new KnowledgeFile();
$detialFile->saveAll($docs);
}
}else{
message($delDocRes['message']);
}
}
}
self::$returnData = $find->toArray();
return true;
}
public static function detail(array $param){
$find = Knowledge::where('id', $param['id'])->limit(1)->find();
if(empty($find)){
message('知识库不存在');
}
$files = KnowledgeFile::field('*')->where(['user_id' => self::$uid])->where('kid', $find['id'])->select()
->toArray();
if(!empty($files)){
$find->is_bind = 1;
$find->update_time = time();
$find->save();
}
$result = $find->toArray();
$result['documents'] = $files;
return $result;
}
/**
* 知识库删除
*
* @param array $params
* @return void
*/
public static function delete(array $params){
$find = Knowledge::where('id', $params['id'])->where('user_id', self::$uid)->fetchSql(false)->limit(1)->find();
if (empty($find)){
message('知识库不存在');
}
try {
// 请求查询接口
$response = \app\common\service\ToolsService::Knowledge()->deleteIndex([
'id' => $find['index_id'],
]);
$cateRes = \app\common\service\ToolsService::Knowledge()->deleteCategory([
'categoryid' => $find['category_id'],
]);
if((int)$response['code'] !== 10000){
message($response['message']);
}
Knowledge::destroy(['id' => $params['id'], 'user_id' => self::$uid]);
KnowledgeFile::destroy(['kid' => $params['id'], 'user_id' => self::$uid]);
return true;
} catch (\Throwable $e) {
return false;
}
}
/**
* 知识库检索
*
* @param array $params
* @return void
*/
public static function retrieve(array $params){
if(!isset($params['prompt']) || empty($params['prompt'])){
message('提示词 不能为空');
}
try {
// 请求查询接口
$response = \app\common\service\ToolsService::Knowledge()->retrieveIndex($params);
if((int)$response['code'] !== 10000){
message($response['message']);
}
return self::__insertRetrieveData($params, $response['data']);
} catch (\Throwable $e) {
message($e->getMessage());
}
}
private static function __insertRetrieveData(array $params, array $data){
$knowledge = Knowledge::where('index_id', $params['indexid'])->where('user_id', self::$uid)->fetchSql(false)->limit(1)->find();
if(empty($knowledge)){
message('知识库不存在');
}
try {
$retrieveData = [
'user_id' => self::$uid,
'kid' => $knowledge['id'],
'index_id' => $params['indexid'],
'rerank_min_score' => $params['rerank_min_score'] ?? self::RERANK_MIN_SCORE, // 默认为0
'prompt' => $params['prompt'],
'create_time' => time(),
];
$_retrieve = new KnowledgeRetrieve();
if($_retrieve->save($retrieveData)){
if(isset($data['Nodes']) && !empty($data['Nodes'])){
$items = array_map(function($item) use ($_retrieve, $params){
$hash = hash_hmac('sha256', $item['Text'], 'knowledge');
$_row = KnowledgeRetrieveSlice::field('content, hash')
->where('index_id', $params['indexid'])
->where('user_id', self::$uid)
->where('rid', $_retrieve->id)
->where('hash', $hash)
->limit(1)->find();
if(empty($_row)){
$filename = KnowledgeFile::field('name')
->where('file_id', $item['Metadata']['doc_id'])
->where('index_id', $params['indexid'])
//->where('user_id', self::$uid)
->limit(1)->value('name');
$tmp = [
'user_id' => self::$uid,
'rid' => $_retrieve->id,
'index_id' => $params['indexid'],
'content' => $item['Text'],
'score' => $item['Score'],
'hash' => $hash,
'metadata' => json_encode($item['Metadata'], JSON_UNESCAPED_UNICODE), // 假设Metadata是一个数组你可以根据实际情况调整
'create_time' => time(),
'source' => $filename ?? $item['Metadata']['doc_name'],
];
return $tmp;
}
}, $data['Nodes']);
$items = array_filter($items);
if(!empty($items)){
$_slice = new KnowledgeRetrieveSlice();
$_slice->saveAll($items);
}
return $items;
}
}
return [];
} catch (\Exception $e) {
message($e->getMessage());
}
}
public static function historyTest(array $params){
$params['page_no'] = $params['page_no'] ?? 1;
$params['page_size'] = $params['page_size'] ?? 15;
$pageSize = $params['page_size'];
$pageNo = ($params['page_no'] - 1) * $params['page_size'];
$keywords = $params['keywords']?? '';
if(!isset($params['indexid']) || empty($params['indexid'])){
message('知识库ID 不能为空');
}
$list = KnowledgeRetrieve::where('user_id', self::$uid)
->where('index_id', $params['indexid'])
->when($keywords, function ($query) use ($keywords) {
$query->where('prompt', 'like', '%' . $keywords . '%');
})
->limit($pageNo, $pageSize)
->order('create_time', 'desc')
->select()
->toArray();
$data = [
'lists' => $list,
'count' => KnowledgeRetrieve::where('user_id', self::$uid)
->where('index_id', $params['indexid'])
->when($keywords, function ($query) use ($keywords) {
$query->where('prompt', 'like', '%' . $keywords . '%');
})->count(),
'page_no' => $params['page_no'],
'page_size' => $params['page_size'],
];
return $data;
}
public static function testDetail(array $params){
$params['page_no'] = $params['page_no'] ?? 1;
$params['page_size'] = $params['page_size'] ?? 15;
$pageSize = $params['page_size'];
$pageNo = ($params['page_no'] - 1) * $params['page_size'];
if(!isset($params['id']) || empty($params['id'])){
message('检索ID 不能为空');
}
$list = KnowledgeRetrieveSlice::where('user_id', self::$uid)
->where('rid', $params['id'])
->order('create_time', 'desc')
->limit($pageNo, $pageSize)
->select()
->toArray();
$data = [
'lists' => $list,
'count' => KnowledgeRetrieveSlice::where('user_id', self::$uid) ->where('rid', $params['id'])->count(),
'page_no' => $params['page_no'],
'page_size' => $params['page_size'],
];
return $data;
}
/**
* 知识库详情-文档列表
*
* @param array $params
* @return void
*/
public static function indexFileList(array $param){
$find = Knowledge::where('id', $param['id'])->limit(1)->find();
if(empty($find)){
message('知识库不存在');
}
$result = KnowledgeFile::where(['user_id' => self::$uid])->where('index_id', $find['index_id'])->select()
->toArray();
$data = [
'lists' => $result,
'count' => KnowledgeFile::where(['user_id' => self::$uid])->where('index_id', $find['index_id'])->count(),
'page_no' => $params['page_no'] ?? 1,
'page_size' => $params['page_size'] ?? 10,
];
return $data;
}
/**
* 知识库分片
*
* @param array $params
* @return void
*/
public static function chunkLists(array $params){
try {
// 请求查询接口
$response = \app\common\service\ToolsService::Knowledge()->chunkIndex($params);
if((int)$response['code'] !== 10000){
message($response['message']);
}
return $response['data'];
} catch (\Throwable $e) {
message($e->getMessage());
}
}
public static function fileUpload(array $params){
if(!isset($params['indexid']) || empty($params['indexid'])){
message('请选择知识库');
}
$index = Knowledge::where('index_id', $params['indexid'])->limit(1)->find();
if(empty($index)){
message('知识库不存在');
}
$file = request()->file('file');
$exts = [
'doc', 'docx', 'wps', 'ppt', 'pptx', 'xls', 'xlsx', 'md', 'txt', 'pdf', 'png',
'jpg', 'jpeg', 'bmp', 'gif','aac', 'amr', 'flac', 'flv', 'm4a', 'mp3', 'mpeg',
'ogg', 'opus', 'wav', 'webm', 'wma','mp4', 'mkv', 'avi', 'mov', 'wmv'
];
if($file){
$ext = $file->getOriginalExtension();
if(!in_array($ext, $exts)){
message('知识库暂时不支持csv文件');
}
}
try
{
$result = UploadService::file(0, self::$uid, FileEnum::SOURCE_USER, 'uploads/file/knowledge');
if(!empty($result)){
$response = \app\common\service\ToolsService::Knowledge()->createFile([
'file_url' => $result['uri'],
'category_id' => $index['category_id']
]);
if((int)$response['code'] === 10000){
$fileinfo = \app\common\service\ToolsService::Knowledge()->infoFile([
'id' => $response['data']['FileId']
]);
if((int)$fileinfo['code'] === 10000){
$result['category_id'] = $fileinfo['data']['CategoryId'];
$result['status'] = $fileinfo['data']['Status'];
$result['type'] = $fileinfo['data']['FileType'];
$result['name'] = $result['name'] ?? $fileinfo['data']['FileName'];
$result['size'] = $fileinfo['data']['SizeInBytes'];
$result['parser'] = $fileinfo['data']['Parser'];
}
$result['file_id'] = $response['data']['FileId'];
$result['parser'] = $response['data']['Parser'];
return $result;
}else{
message($response['message']);
}
}else{
message('文件上传失败');
}
}
catch (\Exception $e)
{
message($e->getMessage());
}
}
public static function fileLists(array $params){
$pageNo = ($params['page_no'] - 1) * $params['page_size'];
$pageSize = $params['page_size'];
$name = $params['name']?? '';
$takeover_mode = $params['takeover_mode']?? '';
$modes = array(
0 => 'PARSING',
1 => 'PARSE_SUCCESS',
2 => 'PARSE_FAILED'
);
$status = $modes[$takeover_mode] ?? ''; // 默认为0即未完成的任务你可以根据需要修改这个值
$result = KnowledgeFile::where(['user_id' => self::$uid])
->where('category_id', $params['category_id'])
->when($name, function ($query) use ($name)
{
$query->where('name', 'like', '%' . $name . '%');
})
->when($status, function ($query) use ($status)
{
$query->where('status', '=', $status);
})
->limit($pageNo, $pageSize)
->select()
->toArray();
$data = [
'lists' => $result,
'count' => KnowledgeFile::where(['user_id' => self::$uid])
->when($name, function ($query) use ($name)
{
$query->where('name', 'like', '%' . $name . '%');
})
->when($status, function ($query) use ($status)
{
$query->where('status', '=', $status);
})
->where('category_id', $params['category_id'])->count(),
'page_no' => $params['page_no'],
'page_size' => $params['page_size'],
];
return $data;
}
public static function fileAdd(array $params){
$find = Knowledge::where('category_id', $params['category_id'])->limit(1)->find();
if(empty($find)){
message('知识库不存在');
}
$addData = array(
'description' => $params['description'] ?? $find['description'],
'rerank_min_score' => $params['rerank_min_score'] ?? ($find['rerank_min_score'] ?? self::RERANK_MIN_SCORE), // 默认为0
'separator' => $params['separator'] ?? $find['separator'],
'chunk_size' => $params['chunk_size'] ?? $find['chunk_size'],
'overlap_size' => $params['overlap_size'] ?? $find['overlap_size'],
'structure_type' => $params['structure_type'] ?? $find['structure_type'],
'source_type' => $params['source_type'] ?? $find['source_type'],
'sink_type' => $params['sink_type'] ?? $find['sink_type'],
'strategy' => $params['strategy'] ?? $find['strategy'],
'is_bind' => !empty($params['documents']) ? 1: 0,
'site' => $params['site'] ?? $_SERVER['HTTP_HOST'],
'update_time' => time(),
);
// if($addData['overlap_size'] > $addData['chunk_size']){
// message('分段预估长度必须大于分段重叠长度');
// }
if(!$find->save($addData)){
message('知识库信息更新失败');
}
if(!empty($params['documents'])){
foreach($params['documents'] as $key => $val){
$file = KnowledgeFile::where('file_id', $val['file_id'])->where('user_id', self::$uid)->limit(1)->find();
if(!empty($file)){
unset($params['documents'][$key]);
}
}
if(empty($params['documents'])){
message('请上传文件');
}
$fileids = array_column($params['documents'], 'file_id');
$addDocRes = \app\common\service\ToolsService::Knowledge()->addDocJobIndex([
'indexid' => $find['index_id'],
'documentIds' => $fileids
]);
if((int)$addDocRes['code'] === 10000){
if(isset($addDocRes['data']['status']) && (int)$addDocRes['data']['status'] === 400){
$find->delete();
message('知识库数据异常:' . $addDocRes['data']['msg']);
}
$docs = array_map(function($doc) use ($find, $params){
$_tmp = array();
$_tmp['file_id'] = $doc['file_id'];
$_tmp['category_id'] = $params['category_id'];
$_tmp['status'] = $doc['status'] ?? 'INIT';
$_tmp['type'] = $doc['type'] ?? '';
$_tmp['name'] = $doc['name'];
$_tmp['size'] = $doc['size'] ?? 0;
$_tmp['parser'] = $doc['parser'] ?? 'DASHSCOPE_DOCMIND';
$_tmp['user_id'] = self::$uid;
$_tmp['index_id'] = $find['index_id'];
$_tmp['kid'] = $find->id;
$_tmp['file_url'] = $doc['uri'] ?? ($doc['file_url'] ?? '');
$_tmp['create_time'] = time();
return $_tmp;
}, $params['documents']);
if(!empty($docs)){
$detialFile = new KnowledgeFile();
$detialFile->saveAll($docs);
}
return true;
}else{
message($addDocRes['message']);
}
}
return true;
}
public static function fileDetial(array $params){
$find = KnowledgeFile::where(['user_id' => self::$uid])->where('file_id', $params['file_id'])->limit(1)->find();
if(empty($find)){
message('文件不存在');
}
if($find['status'] !== 'PARSE_SUCCESS'){
$fileinfo = \app\common\service\ToolsService::Knowledge()->infoFile([
'id' => $find['file_id']
]);
if((int)$fileinfo['code'] === 10000){
$find['status'] = $fileinfo['data']['Status'];
$find['update_time'] = time();
$find['type'] = $fileinfo['data']['FileType'];
$find['name'] = $fileinfo['data']['FileName'];
$find['size'] = $fileinfo['data']['SizeInBytes'];
$find['parser'] = $fileinfo['data']['Parser'];
$find->save();
}
}
return $find->toArray();
}
public static function fileDelete(array $params){
$find = KnowledgeFile::where('id', $params['id'])->where('user_id', self::$uid)->fetchSql(false)->limit(1)->find();
if (empty($find)){
message('文档不存在');
}
KnowledgeFile::destroy(['id' => $params['id'], 'user_id' => self::$uid]);
// 请求查询接口
$response = \app\common\service\ToolsService::Knowledge()->deleteFile([
'id' => $find['file_id']
]);
// if((int)$response['code'] !== 10000){
// //throw new \Exception($response['message']);
// message($response['message']);
// }
return true;
}
/**
* 知识库分片
*
* @param array $params
* @return void
*/
public static function fileChunkLists(array $params){
$find = KnowledgeFile::where('id', $params['id'])->where('user_id', self::$uid)->fetchSql(false)->limit(1)->find();
if (empty($find)){
message('文档不存在');
}
$params['page_no'] = $params['page_no'] ?? 1;
$params['page_size'] = $params['page_size'] ?? 15;
$pageSize = $params['page_size'];
$pageNo = ($params['page_no'] - 1) * $params['page_size'];
$keywords = $params['keywords']?? '';
$result = KnowledgeFileSlice::where('file_id', $find['file_id'])
->where('index_id', $find['index_id'])
->where('user_id', self::$uid)
->when($keywords, function ($query) use ($keywords) {
$query->where('content', 'like', '%' . $keywords . '%');
})
->limit($pageNo, $pageSize)
->select()->toArray();
if(empty($result)){
// 请求查询接口
$response = \app\common\service\ToolsService::Knowledge()->chunkIndex([
'indexid' => $find['index_id'],
'fileid' => $find['file_id'],
'pageNum' => 1,
'pageSize' => 100,
]);
if((int)$response['code'] === 10000){
if(!isset($response['data']['Nodes'])){
message('查询失败');
}
$nodes = $response['data']['Nodes'];
if(!empty($nodes)){
$items = array_map(function($item) use ($find, $params){
$hash = hash_hmac('sha256', $item['Text'], 'knowledge');
$_row = KnowledgeFileSlice::field('content, hash')
->where('file_id', $find['file_id'])
->where('index_id', $find['index_id'])
->where('user_id', self::$uid)
->where('hash', $hash)
->limit(1)->find();
if(empty($_row)){
$tmp = [
'user_id' => self::$uid,
'rid' => $find->id,
'index_id' => $find['index_id'],
'file_id' => $find['file_id'],
'content' => $item['Text'],
'score' => $item['Score'],
'hash' => $hash,
'metadata' => json_encode($item['Metadata'], JSON_UNESCAPED_UNICODE), // 假设Metadata是一个数组你可以根据实际情况调整
'create_time' => time(),
'source' => $find['name'] ?? $item['Metadata']['doc_name']
];
return $tmp;
}
}, $nodes);
$items = array_filter($items);
if(!empty($items)){
$_slice = new KnowledgeFileSlice();
$_slice->saveAll($items);
}
}
}
$result = KnowledgeFileSlice::where('user_id', self::$uid)
->where('index_id', $find['index_id'])
->where('file_id', $find['file_id'])
->when($keywords, function ($query) use ($keywords){
$query->where('content', 'like', '%' . $keywords . '%');
})
->limit($pageNo, $pageSize)
->select()
->each(function ($item) {
$item['metadata'] = json_decode($item['metadata'], true); // 假设metadata是一个JSON字符串
return $item;
})
->toArray();
}
$data = [
'lists' => $result,
'count' => KnowledgeFileSlice::where('user_id', self::$uid)
->where('index_id', $find['index_id'])
->where('file_id', $find['file_id'])
->when($keywords, function ($query) use ($keywords){
$query->where('content', 'like', '%' . $keywords . '%');
})->count(),
'page_no' => $params['page_no'],
'page_size' => $params['page_size'],
];
return $data;
}
public static function updateTagFile(array $params){
try {
// 请求查询接口
$response = \app\common\service\ToolsService::Knowledge()->updateTagFile($params);
if((int)$response['code'] !== 10000){
throw new \Exception($response['message']);
}
return $response['data'];
} catch (\Throwable $e) {
throw new \Exception($e->getMessage());
}
}
/**
* 绑定知识库
*
* @param array $params
* @param [type] $data
* @return void
*/
public static function bind(array $params, $data){
//删除原来的绑定 添加新的绑定信息
KnowledgeBind::where('data_id', $data['id'])
->where('user_id', self::$uid)
->where('type', $params['type'])
->select()
->delete();
if(isset($params['index_id']) && !empty($params['index_id'])){
$knowledge = Knowledge::where('index_id', $params['index_id'])->limit(1)->find();
if(empty($knowledge)){
throw new \Exception('知识库不存在');
return false;
}
//挂载知识库
KnowledgeBind::create([
'user_id' => self::$uid,
'kid' => $knowledge['id'],
'data_id' => $data['id'],
'type' => $params['type'],
'index_id' => $params['index_id'],
'rerank_min_score' => $params['rerank_min_score'] ?? self::RERANK_MIN_SCORE,
'create_time' => time(),
]);
}
}
/**
* 将训练内容上传到知识库
*
* @param array $params
* @return void
*/
public static function ladderPlayerUpload(array $params){
# 1 根据已经选择的数据生成文本文件
# 2 上传文件到分类
# 3 文档追加到指定的知识库
# 4 获取文件的信息
if(!isset($params['ids']) || empty($params['ids'])){
message('请选择需要上传的记录');
}
$knowledge = Knowledge::where('index_id', $params['indexid'])->where('user_id', self::$uid)->limit(1)->find();
if(empty($knowledge)){
message('知识库不存在');
}
# 提取文本信息
$data = \app\common\model\lianlian\LlChat::alias('c')
->field('c.ask, c.reply, c.performance, c.speechcraft')
->join('ll_analysis l', 'l.id = c.analysis_id', 'left')
->where('l.id', 'in', $params['ids'])
->select()->toArray();
try {
$content = array();
foreach($data as $item){
$content[] = $item['ask'] . "\n" . $item['reply'] . "\n" . $item['performance'] . "\n" . $item['speechcraft'];
}
$content = implode("\n", $content);
$uri = 'uploads/file/knowledge/'.date('Ymd').'/话术1.txt';
$filepath = root_path(). '/public/' . $uri;
!is_dir(dirname($filepath)) && mkdir(dirname($filepath), 0777, true);
$size = file_put_contents($filepath, $content);
if($size === false){
message('文件写入失败');
}
$uri = config('app.app_host') . '/' . $uri;
$fileRes = \app\common\service\ToolsService::Knowledge()->createFile([
'file_url' => $uri,
'category_id' => $knowledge['category_id']
]);
if((int)$fileRes['code'] === 10000){
$fileinfo = \app\common\service\ToolsService::Knowledge()->infoFile([
'id' => $fileRes['data']['FileId']
]);
if((int)$fileinfo['code'] === 10000){
$addDocRes = \app\common\service\ToolsService::Knowledge()->addDocJobIndex([
'indexid' => $knowledge['index_id'],
'documentIds' => [$fileRes['data']['FileId']]
]);
if((int)$addDocRes['code'] === 10000){
$result = array();
$result['file_id'] = $fileRes['data']['FileId'];
$result['category_id'] = $knowledge['category_id'];
$result['status'] = $fileinfo['data']['Status'];
$result['type'] = $fileinfo['data']['FileType'];
$result['name'] = $result['name'] ?? $fileinfo['data']['FileName'];
$result['size'] = $fileinfo['data']['SizeInBytes'];
$result['parser'] = $fileinfo['data']['Parser'];
$result['user_id'] = self::$uid;
$result['index_id'] = $knowledge['index_id'];
$result['kid'] = $knowledge->id;
$result['file_url'] = $uri;
$result['create_time'] = time();
$detialFile = new KnowledgeFile();
$detialFile->save($result);
self::$returnData = $result;
return true;
}else{
message('文件追加到知识库失败');
}
}else{
message('获取文件信息失败');
}
}else{
message('上传文件失败');
}
} catch (\Throwable $th) {
message($th->getMessage());
}
return false;
}
/******************请求接口以及扣费************************ */
/**
* 请求上游接口与计费
* @param array $request
* @param string $scene
* @param int $userId
* @param string $taskId
* @return array
* @throws \Exception
*/
private static function requestUrl(array $request, string $scene, int $userId, array $record = []): array
{
$requestService = \app\common\service\ToolsService::Knowledge();
[$tokenScene, $tokenCode] = match ($scene) {
self::KNOELEDGE_CREATE => ['knowledge_create', AccountLogEnum::TOKENS_DEC_KNOWLEDGE_CREATE],
self::KNOELEDGE_RETRIEVE => ['knowledge_retrieve', AccountLogEnum::TOKENS_DEC_KNOWLEDGE_RETRIEVE],
self::KNOELEDGE_CHAT => ['knowledge_chat', AccountLogEnum::TOKENS_DEC_KNOWLEDGE_CHAT],
};
//计费
$unit = TokenLogService::checkToken($userId, $tokenScene);
switch ($scene) {
case self::KNOELEDGE_CREATE:
$response = $requestService->createIndex($request);
break;
case self::KNOELEDGE_RETRIEVE:
$response = $requestService->retrievePrompt($request);
break;
case self::KNOELEDGE_CHAT:
$response = $requestService->promptChat($request);
break;
default:
}
//print_r($response);die;
if($scene == self::KNOELEDGE_CHAT && $request['stream'] == true){
exit;
}
//clogger('response: '. json_encode($response, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
//成功响应,需要扣费
if (isset($response['code']) && $response['code'] == 10000) {
if($scene === self::KNOELEDGE_CREATE){
$tokens = $unit;
$points = $unit;
$knowlwdge_tokens = $points;
}else{
$usage = $response['data']['usage'];
$tokens = $usage['total_tokens'] + $request['knowledge_tokens'];
//计算消耗tokens
$points = $unit > 0 ? ceil($tokens / $unit) : 0;
$knowlwdge_tokens = $request['knowledge_tokens'];
}
//clogger($points.'|'.$userId);
if ($points > 0) {
$extra = ['总消耗tokens数' => $tokens, '知识库消耗tokens数' => $knowlwdge_tokens, '算力单价' => $unit, '实际消耗算力' => $points];
//clogger('extra: '. json_encode($extra, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
//token扣除
User::userTokensChange($userId, $points);
//记录日志
AccountLogLogic::recordUserTokensLog(true, $userId, $tokenCode, $points, $request['task_id'], $extra);
self::saveKnowledgeRecord($request, $response['data']);
}
}
return $response['data'] ?? [];
}
public static function saveKnowledgeRecord(array $request, array $response){
try {
$record = $request['knowledge_record'];
$record['content'] = $response['content'] ?? ( $response['choices'][0]['message']['content']?? '');
$record['prompt_tokens'] = $response['usage']['prompt_tokens'];
$record['completion_tokens'] = $response['usage']['completion_tokens'];
$record['total_tokens'] = $response['usage']['total_tokens'];
$record['tokens'] = $record['retrieve_tokens'] + $record['total_tokens'];
$record['task_id'] = $request['task_id'];
$record['create_time'] = time();
$res = (new KnowledgeUseSceneRecord())->save($record);
$knowlwdge = Knowledge::where('index_id', $request['indexid'])->where('user_id', $request['user_id'])->fetchSql(false)->limit(1)->find();
//请求成功知识库调用+1
$knowlwdge->inc('request_count', 1)->inc('tokens', $record['retrieve_tokens'])->save();
} catch (\Throwable $th) {
//clogger($th);
}
}
/******************定时任务-文件状态************************ */
public static function setFileStatus(){
try {
// clogger('setFileStatus ' . date('Y-m-d H:i:s', time()), 'cron');
$files = KnowledgeFile::where('status', 'not in',['PARSE_SUCCESS', 'PARSE_FAILED'])->order('id asc')->limit(10)->select();
foreach ($files as $key => $file) {
//clogger('开始处理文件:' . $file['file_id'], 'cron');
$fileinfo = \app\common\service\ToolsService::Knowledge()->infoFile([
'id' => $file['file_id']
]);
if((int)$fileinfo['code'] === 10000){
if(isset($fileinfo['data']['no_exist']) && (int)$fileinfo['data']['no_exist'] === 1){
$file['status'] = 'PARSE_FAILED';
$file['remark'] = $fileinfo['data']['msg'];
//clogger('文件不存在:'. $file['file_id'], 'cron');
}else{
$file['status'] = $fileinfo['data']['Status'];
}
$file['update_time'] = time();
$file->save();
}
sleep(2);
}
return true;
} catch (\Throwable $th) {
//clogger('文件处理失败:'. $th->getMessage(), 'cron');
return false;
}
}
public static function fileChunksPull(){
try {
//clogger('fileChunksPull:' . date('Y-m-d H:i:s', time()), 'cron');
$files = KnowledgeFile::where('status', 'PARSE_SUCCESS')
->where('is_completed', 0)
->order('update_time asc')->limit(5)->select();
foreach ($files as $key => $file) {
//clogger('开始处理文件:'. $file['file_id'], 'cron');
# 首次拉取
# 按照分页拉取
$totalRes = \app\common\service\ToolsService::Knowledge()->chunkIndex([
'indexid' => $file['index_id'],
'fileid' => $file['file_id'],
'pageNum' => 1,
'pageSize' => 1,
]);
if((int)$totalRes['code'] === 10000){
if(isset($totalRes['data']['no_exist']) && (int)$totalRes['data']['no_exist'] === 1){
$file['status'] = 'PARSE_FAILED';
//clogger('文件或知识库不存在:'. $file['file_id'].'||'. $file['index_id'], 'cron');
//删除本地文件
$file['status'] = 'PARSE_FAILED';
$file['remark'] = $totalRes['data']['msg'];
$file['is_completed'] = 1;
$file['update_time'] = time();
$file['delete_time'] = time();
$file->save();
}else{
$total = $totalRes['data']['Total'];
$totalPage = ceil($total / 100);
for($page = 1; $page <= $totalPage; $page++){
$response = \app\common\service\ToolsService::Knowledge()->chunkIndex([
'indexid' => $file['index_id'],
'fileid' => $file['file_id'],
'pageNum' => $page,
'pageSize' => 100,
]);
if((int)$response['code'] === 10000){
$nodes = $response['data']['Nodes'];
if(!empty($nodes)){
$items = array_map(function($item) use ($file){
$hash = hash_hmac('sha256', $item['Text'], 'knowledge');
$_row = KnowledgeFileSlice::field('content, hash')
->where('file_id', $file['file_id'])
->where('index_id', $file['index_id'])
->where('user_id', $file['user_id'])
->where('hash', $hash)
->limit(1)->find();
if(empty($_row)){
$tmp = [
'user_id' => $file['user_id'],
'rid' => $file->id,
'index_id' => $file['index_id'],
'file_id' => $file['file_id'],
'content' => $item['Text'],
'score' => $item['Score'],
'hash' => $hash,
'metadata' => json_encode($item['Metadata'], JSON_UNESCAPED_UNICODE), // 假设Metadata是一个数组你可以根据实际情况调整
'create_time' => time(),
'source' => $file['name'] ?? $item['Metadata']['doc_name']
];
return $tmp;
}
}, $nodes);
$items = array_filter($items);
if(!empty($items)){
$_slice = new KnowledgeFileSlice();
$_slice->saveAll($items);
}
}
}
sleep(2);
}
$file['is_completed'] = 1;
$file['slice_count'] = $total;
$file['update_time'] = time();
$file->save();
}
}
sleep(2);
}
return true;
} catch (\Throwable $th) {
//clogger('文件处理失败:'. $th->getMessage(), 'cron');
return false;
}
}
/******************chat************************ */
public static function chat($params){
set_time_limit(0);
if(!isset($params['message']) || empty($params['message'])){
message('提示词 不能为空');
}
$uid = $params['user_id'] ?? self::$uid;
$knowlwdge = Knowledge::where('index_id', $params['indexid'])->where('user_id', $uid)->fetchSql(false)->limit(1)->find();
if(empty($knowlwdge)){
message('知识库不存在');
}
$message = $params['message'];
// 表单变量替换
$message_ext = $params['message_ext'] ?? '';
if ($message_ext) {
$message_ext_text = self::parseMsg($message_ext, '');
$message = $message_ext_text . $message;
}
$request = [
'indexid' => $params['indexid'],
'prompt' => $message,
'rerank_min_score' => $params['rerank_min_score'] ?? ($knowledge['rerank_min_score'] ?? self::RERANK_MIN_SCORE), // 默认为0
'stream' => (bool)$params['stream'] ?? true,
'task_id' => $params['task_id'] ?? generate_unique_task_id(),
'scene' => $params['scene'] ?? '未知聊天',
'assistant_id' => $params['assistant_id'] ?? 0
];
if($params['scene'] == '陪练聊天'){
$request['voice'] = $params['voice']?? '';
$request['emotion'] = $params['emotion']?? '';
$request['intensity'] = $params['intensity']?? '';
}
self::__getRequestData($request, $params);
try {
$record = array(
'user_id' => $uid,
'index_id' => $params['indexid'],
'prompt' => $message,
'rerank_min_score' => $params['rerank_min_score'] ?? self::RERANK_MIN_SCORE, // 默认为0
'scene' => $params['scene'] ?? '未知聊天',
);
// 根据用户提示词检索
$response = \app\common\service\ToolsService::Knowledge()->retrievePrompt($request);
// 拼接切片内容
if((int)$response['code'] === 10000){
if(isset($response['data']['Nodes'])){
$texts = implode("\n", array_column($response['data']['Nodes'], 'Text'));
}else{
$texts = '';
}
$textLength = mb_strlen($texts, 'utf-8');
$record['retrieve_content'] = $texts;
$record['retrieve_length'] = $textLength;
$record['retrieve_tokens'] = ceil($textLength / 4); //2个字一个token
$prompt = "请根据以下知识库内容回答问题:
{$texts}
问题:{$message}";
$request['user_id'] = $uid; // 替换为实际的用户ID
$request['prompt'] = $prompt;
$request['knowledge_tokens'] = ceil($textLength / 4);
$request['chat_type'] = 9006;
$request['now'] = time();
$request['knowledge_record'] = $record;
$result = self::requestUrl($request, self::KNOELEDGE_CHAT, $uid, $record);
self::$returnData = $result;
return $result;
}
return true;
} catch (\Throwable $e) {
// clogger($e);
if($params['scene'] !== 'socket'){
message($e->getMessage());
}else{
self::$returnData = [];
return false;
}
}
}
public static function socketChat($params){
set_time_limit(0);
try {
if(!isset($params['message']) || empty($params['message'])){
return [false, '提示词 不能为空'];
}
$uid = $params['user_id'] ?? self::$uid;
$knowlwdge = Knowledge::where('index_id', $params['indexid'])->where('user_id', $uid)->fetchSql(false)->limit(1)->find();
if(empty($knowlwdge)){
return [false, '知识库不存在'];
}
$message = $params['message'];
// 表单变量替换
$message_ext = $params['message_ext'] ?? '';
if ($message_ext) {
$message_ext_text = self::parseMsg($message_ext, '');
$message = $message_ext_text . $message;
}
$request = [
'indexid' => $params['indexid'],
'prompt' => $message,
'rerank_min_score' => $params['rerank_min_score'] ?? ($knowledge['rerank_min_score'] ?? self::RERANK_MIN_SCORE), // 默认为0
'stream' => (bool)$params['stream'] ?? true,
'task_id' => $params['task_id'] ?? generate_unique_task_id(),
'scene' => $params['scene'] ?? '未知聊天',
'assistant_id' => $params['assistant_id'] ?? 0
];
if($params['scene'] == '陪练聊天'){
$request['voice'] = $params['voice']?? '';
$request['emotion'] = $params['emotion']?? '';
$request['intensity'] = $params['intensity']?? '';
}
self::__getRequestData($request, $params);
$record = array(
'user_id' => $uid,
'index_id' => $params['indexid'],
'prompt' => $message,
'rerank_min_score' => $params['rerank_min_score'] ?? self::RERANK_MIN_SCORE, // 默认为0
'scene' => $params['scene'] ?? '未知聊天',
);
// 根据用户提示词检索
$response = \app\common\service\ToolsService::Knowledge()->retrievePrompt($request);
// 拼接切片内容
if((int)$response['code'] === 10000){
if(isset($response['data']['Nodes'])){
$texts = implode("\n", array_column($response['data']['Nodes'], 'Text'));
}else{
$texts = '';
}
$textLength = mb_strlen($texts, 'utf-8');
$record['retrieve_content'] = $texts;
$record['retrieve_length'] = $textLength;
$record['retrieve_tokens'] = ceil($textLength / 4); //2个字一个token
$prompt = "请根据以下知识库内容回答问题:
{$texts}
问题:{$message}";
$request['user_id'] = $uid; // 替换为实际的用户ID
$request['prompt'] = $prompt;
$request['knowledge_tokens'] = ceil($textLength / 4);
$request['chat_type'] = 9006;
$request['now'] = time();
$request['knowledge_record'] = $record;
$result = self::requestUrl($request, self::KNOELEDGE_CHAT, $uid, $record);
return [true, $result];
}else{
return [false, $response['message'] ?? '知识库检索失败'];
}
} catch (\Throwable $e) {
return [false, $e->getMessage()];
}
}
public static function sceneChat($params){
set_time_limit(0);
if (empty($params['message']) && empty($params['message_ext'])) {
message('提示词 不能为空');
}
$assistant = \app\common\model\chat\Assistants::where('id', $params['assistant_id'])->findOrEmpty();
if ($assistant->isEmpty()) {
message('助手不存在');
}
$uid = $params['user_id'] ?? self::$uid;
$knowlwdge = Knowledge::where('index_id', $params['indexid'])->where('user_id', $uid)->fetchSql(false)->limit(1)->find();
if(empty($knowlwdge)){
message('知识库不存在');
}
$message = $params['message'];
$request = [
'indexid' => $params['indexid'],
'prompt' => $message,
'rerank_min_score' => $params['rerank_min_score'] ?? ($knowlwdge['rerank_min_score'] ?? self::RERANK_MIN_SCORE), // 默认为0
'stream' => (bool)$params['stream'] ?? true,
'task_id' => $params['task_id'] ?? generate_unique_task_id(),
'scene' => $params['scene'] ?? '未知聊天',
'assistant_id' => $params['assistant_id'] ?? 0
];
//clogger(json_encode($request, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
if(mb_strlen(mb_trim($message), 'utf-8') == 0){
message('提示词 不能为空');
}
if($params['scene'] == '陪练聊天'){
$request['voice'] = $params['voice']?? '';
$request['emotion'] = $params['emotion']?? '';
$request['intensity'] = $params['intensity']?? '';
}
self::__getRequestData($request, $params);
try {
$record = array(
'user_id' => $uid,
'index_id' => $params['indexid'],
'prompt' => $message,
'rerank_min_score' => $request['rerank_min_score'], // 默认为0
'scene' => $params['scene'] ?? '未知聊天',
);
// 根据用户提示词检索
$response = \app\common\service\ToolsService::Knowledge()->retrievePrompt($request);
// 拼接切片内容
if((int)$response['code'] === 10000){
if(isset($response['data']['Nodes'])){
$texts = implode("\n", array_column($response['data']['Nodes'], 'Text'));
}else{
$texts = '';
}
//clogger($texts);
// 表单变量替换
$message_ext = $params['message_ext'] ?? '';
if ($message_ext) {
$message_ext_text = self::parseMsg($message_ext, $assistant['form_info']);// $assistant['form_info']
$texts = $message_ext_text . $texts;
}
$textLength = mb_strlen($texts, 'utf-8');
$record['retrieve_content'] = $texts;
$record['retrieve_length'] = $textLength;
$record['retrieve_tokens'] = ceil($textLength / 4); //2个字一个token
$prompt = "请根据以下知识库内容回答问题:
{$texts}
问题:{$message}";
$request['user_id'] = $uid; // 替换为实际的用户ID
$request['prompt'] = $prompt;
$request['knowledge_tokens'] = ceil($textLength / 4);
$request['chat_type'] = 9006;
$request['now'] = time();
$request['knowledge_record'] = $record;
//clogger(json_encode($request, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
$result = self::requestUrl($request, self::KNOELEDGE_CHAT, $uid, $record);
self::$returnData = $result;
return $result;
}
return true;
} catch (\Throwable $e) {
message($e->getMessage());
}
}
public static function ladderPlayerChat($params){
set_time_limit(0);
if (empty($params['message']) && empty($params['message_ext'])) {
message('提示词 不能为空');
}
$uid = $params['user_id'] ?? self::$uid;
$knowlwdge = Knowledge::where('index_id', $params['indexid'])->where('user_id', $uid)->fetchSql(false)->limit(1)->find();
if(empty($knowlwdge)){
message('知识库不存在');
}
$message = $params['message'];
$request = [
'indexid' => $params['indexid'],
'prompt' => $message,
'rerank_min_score' => $params['rerank_min_score'] ?? ($knowlwdge['rerank_min_score'] ?? self::RERANK_MIN_SCORE), // 默认为0
'stream' => (bool)$params['stream'] ?? true,
'task_id' => $params['task_id'] ?? generate_unique_task_id(),
'scene' => $params['scene'] ?? '未知聊天',
'assistant_id' => $params['assistant_id'] ?? 0
];
$request['rerank_min_score'] = self::RERANK_MIN_SCORE;
$request['voice'] = $params['voice']?? '';
$request['emotion'] = $params['emotion']?? '';
$request['intensity'] = $params['intensity']?? '';
self::__getRequestData($request, $params);
try {
$record = array(
'user_id' => $uid,
'index_id' => $params['indexid'],
'prompt' => $message,
'rerank_min_score' => $request['rerank_min_score'], // 默认为0
'scene' => $params['scene'] ?? '未知聊天',
);
//clogger(json_encode($request, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), 'll');
// 根据用户提示词检索
$response = \app\common\service\ToolsService::Knowledge()->retrievePrompt($request);
//clogger(json_encode($response, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), 'll');
// 拼接切片内容
if((int)$response['code'] === 10000){
if(isset($response['data']['Nodes'])){
$texts = implode("\n", array_column($response['data']['Nodes'], 'Text'));
}else{
$texts = '';
}
$textLength = mb_strlen($texts, 'utf-8');
$record['retrieve_content'] = $texts;
$record['retrieve_length'] = $textLength;
$record['retrieve_tokens'] = ceil($textLength / 4); //2个字一个token
$prompt = "请根据以下知识库内容回答问题:
{$texts}
问题:{$message}";
$request['user_id'] = $uid; // 替换为实际的用户ID
$request['prompt'] = $prompt;
$request['knowledge_tokens'] = ceil($textLength / 4);
$request['chat_type'] = 9006;
$request['now'] = time();
$request['knowledge_record'] = $record;
$result = self::requestUrl($request, self::KNOELEDGE_CHAT, $uid, $record);
self::$returnData = $result;
return $result;
}
return true;
} catch (\Throwable $e) {
message($e->getMessage());
}
}
private static function parseMsg($message_ext, $form_info){
$message_ext = json_decode($message_ext, true);
if (empty($message_ext)) {
return '';
}
preg_match_all('/\${([^\}]+)}/u', $form_info, $matches);
$keys = $matches[1];
if (empty($keys)) {
return '';
}
foreach ($message_ext as $key => $value) {
foreach ($keys as $keyword) {
if ($keyword == $key) {
if (!empty($value) && is_array($value)) {
$value = implode(',', $value);
}
$form_info = str_replace('${' . $keyword . '}', $value, $form_info);
}
}
}
return $form_info;
}
private static function __getRequestData(array &$request, array $params){
if(isset($params['rerankTopN']) && !empty($params['rerankTopN'])){
$request['rerankTopN'] = $params['rerankTopN'];
}
if(isset($params['denseSimilarityTopK']) && !empty($params['denseSimilarityTopK'])){
$request['denseSimilarityTopK'] = $params['denseSimilarityTopK'];
}
if(isset($params['enableReranking']) && !empty($params['enableReranking'])){
$request['enableReranking'] = $params['enableReranking'];
}
if(isset($params['enableRewrite']) && !empty($params['enableRewrite'])){
$request['enableRewrite'] = $params['enableRewrite'];
}
if(isset($params['sparseSimilarityTopK']) && !empty($params['sparseSimilarityTopK'])){
$request['sparseSimilarityTopK'] = $params['sparseSimilarityTopK'];
}
if(isset($params['saveRetrieverHistory']) && !empty($params['saveRetrieverHistory'])){
$request['saveRetrieverHistory'] = $params['saveRetrieverHistory'];
}
}
}