c5_labsci/web/ambap/ai.php
2026-01-27 00:52:00 +08:00

289 lines
12 KiB
PHP

<?php
namespace web\ambap;
class ai {
public static function json_rawai($param = null, $debug = false) {
global $db;
$post = new \ciy\post($param);
$aikey = $post->getint('aikey');
$aikeyrow = null;
if ($aikey > 0) {
$csql = new \ciy\sql('zc_ai_key');
$csql->where('id', $aikey);
$aikeyrow = $db->getone($csql);
if (!is_array($aikeyrow))
return errjson('AI Key不存在');
}
if (!is_array($aikeyrow)) {
$csql = new \ciy\sql('zc_ai_key');
$csql->where('id', 1);
$aikeyrow = $db->getone($csql);
if (!is_array($aikeyrow))
return errjson('AI Key未设置');
}
$system = $post->get('system');
$chat = $post->get('chat');
if (empty($chat))
return errjson('请输入聊天内容');
$openai = new \ciy\openai($aikeyrow);
$openai->debug($debug);
$openai->setparam($post->get('aiprange'));
$openai->newsystem($system);
$retai = $openai->completion($chat, strpos($chat . $system, 'JSON') !== false);
if (is_string($retai))
return errjson($retai);
$ret['ai'] = $retai;
return succjson($ret);
}
public static function json_aidecision($param = null, $debug = false) {
global $db;
set_time_limit(0);
$timespan = time();
$post = new \ciy\post($param);
$id = $post->getint('id');
$csql = new \ciy\sql('zc_ai_decision');
$csql->where('id', $id);
$decisionrow = $db->getone($csql);
if (!is_array($decisionrow))
return errjson('AI决策单元不存在');
$csql = new \ciy\sql('zc_ai_key');
$csql->where('id', $decisionrow['aikey']);
$aikeyrow = $db->getone($csql);
if (!is_array($aikeyrow))
return errjson('AI Key未设置');
$funcdatarows = null;
if (!empty($decisionrow['funcids'])) {
$csql = new \ciy\sql('zc_ai_funcdata');
$csql->where('id in', trim($decisionrow['funcids'], ','));
$funcdatarows = $db->get($csql);
}
if (strpos($decisionrow['sysprompt'] . $decisionrow['roleprompt'], '{{know.') === false) {
$csql = new \ciy\sql('zc_ai_knowcata');
$knowcatarows = $db->get($csql);
if (count($knowcatarows) > 0) {
if ($funcdatarows == null)
$funcdatarows = array();
$descs = '';
foreach ($knowcatarows as $knowcatarow) {
$descs .= "\n{知识库ID:" . $knowcatarow['id'] . ", " . $knowcatarow['name'] . ',' . $knowcatarow['aiguide'] . '}';
}
$funcdatarows[] = array(
'id' => 0,
'name' => 'know',
'funcname' => 'know',
'descs' => '如果需要补充学习专业知识库信息,调用该函数。知识库列表有,' . $descs,
'paramjson' => '*ID=准确的知识库ID',
'funcparam' => ''
);
}
}
$csql = new \ciy\sql('zc_ai_key');
$csql->where('id', $decisionrow['aikey']);
$aikeyrow = $db->getone($csql);
if (!is_array($aikeyrow))
return errjson('AI Key不存在');
$system = preg_replace_callback('/\{\{([^}]+)\}\}/', function ($matches) use ($db, $post) {
$key = $matches[1];
if (substr($key, 0, 5) == 'know.') {
$knowcataname = substr($key, 5);
$csql = new \ciy\sql('zc_ai_knowcata');
$csql->where('name', $knowcataname);
$knowcatarow = $db->getone($csql);
if (!is_array($knowcatarow))
return '';
$csql = new \ciy\sql('zc_ai_knowledge');
$csql->where('cataid', $knowcatarow['id']);
$knowrows = $db->get($csql);
$knowstr = '';
foreach ($knowrows as $knowrow) {
$knowstr .= $knowrow['content'] . "\n";
}
return $knowstr;
}
$val = $post->get($key);
if (is_array($val))
$val = json_encode($val, JSON_UNESCAPED_UNICODE);
return $val . '';
}, $decisionrow['sysprompt']);
$roleprompt = preg_replace_callback('/\{\{([^}]+)\}\}/', function ($matches) use ($db, $post) {
$key = $matches[1];
if (substr($key, 0, 5) == 'know.') {
$knowcataname = substr($key, 5);
$csql = new \ciy\sql('zc_ai_knowcata');
$csql->where('name', $knowcataname);
$knowcatarow = $db->getone($csql);
if (!is_array($knowcatarow))
return '';
$csql = new \ciy\sql('zc_ai_knowledge');
$csql->where('cataid', $knowcatarow['id']);
$knowrows = $db->get($csql);
$knowstr = '';
foreach ($knowrows as $knowrow) {
$knowstr .= $knowrow['content'] . "\n";
}
return $knowstr;
}
$val = $post->get($key);
if (is_array($val))
$val = json_encode($val, JSON_UNESCAPED_UNICODE);
return $val . '';
}, $decisionrow['roleprompt']);
$openai = new \ciy\openai($aikeyrow);
$openai->debug($debug);
$openai->setparam($decisionrow['aiprange']);
$openai->newsystem($system);
$retai = $openai->completion($roleprompt, strpos($roleprompt . $system, 'JSON') !== false, $funcdatarows, function ($funcarray) use ($funcdatarows) {
$funcdatarow = ccode($funcdatarows, substr($funcarray['name'], 1), 'id', null);
if (!is_array($funcdatarow))
return 'ERR未定义函数:' . $funcarray['name'];
$funcname = $funcdatarow['funcname'];
if ($funcname[0] != '\\')
$funcname = '\\web\\admin\\aifunc\\' . $funcname;
if (!class_exists($funcname))
return 'ERR无效类:' . $funcname;
if (!method_exists($funcname, 'main'))
return 'ERR无效函数:' . $funcname . '::main';
$funcname .= '::main';
$arguments = json_decode($funcarray['arguments'], true);
$funcparams = getstrparam($funcdatarow['funcparam'], "\n");
foreach ($funcparams as $key => $val) {
$arguments[$key] = $val;
}
return call_user_func($funcname, $arguments);
});
if (is_string($retai)) {
$ret = array();
$ret['sec'] = time() - $timespan + 1; //用时
$ret['ci'] = 0; //置信度
$ret['version'] = $decisionrow['version'];
if ($post->get('_more') == 'ok') {
$ret['messages'] = $openai->messages; //交互过程
$ret['roleprompt'] = $roleprompt; //提示词
$ret['system'] = $system; //角色描述
}
return errjson('AI执行失败: ' . $retai, 10, $ret);
}
$decci = 0;
$aichat = json_encode($openai->messages, JSON_UNESCAPED_UNICODE);
$resulttxt = json_encode($retai, JSON_UNESCAPED_UNICODE);
if ($decisionrow['aicalkey'] > 0 && !empty($decisionrow['calprompt'])) {
$post->post['result.ai'] = $aichat;
$post->post['result.data'] = $resulttxt;
$csql = new \ciy\sql('zc_ai_key');
$csql->where('id', $decisionrow['aicalkey']);
$aikeyrow = $db->getone($csql);
if (!is_array($aikeyrow))
return errjson('置信度 AI Key不存在');
$calprompt = preg_replace_callback('/\{\{([^}]+)\}\}/', function ($matches) use ($db, $post) {
$key = $matches[1];
if (substr($key, 0, 5) == 'know.') {
$knowcataname = substr($key, 5);
$csql = new \ciy\sql('zc_ai_knowcata');
$csql->where('name', $knowcataname);
$knowcatarow = $db->getone($csql);
if (!is_array($knowcatarow))
return '';
$csql = new \ciy\sql('zc_ai_knowledge');
$csql->where('cataid', $knowcatarow['id']);
$knowrows = $db->get($csql);
$knowstr = '';
foreach ($knowrows as $knowrow) {
$knowstr .= $knowrow['content'] . "\n";
}
return $knowstr;
}
$val = $post->get($key);
if (is_array($val))
$val = json_encode($val, JSON_UNESCAPED_UNICODE);
return $val . '';
}, $decisionrow['calprompt']);
$openai = new \ciy\openai($aikeyrow);
$openai->debug($debug);
$openai->setparam($decisionrow['aicalprange']);
$openai->newsystem();
$retcalai = $openai->completion($calprompt, true);
$decci = (int)$retcalai['confidence'];
} else if ($decisionrow['aicalkey'] == 0 && !empty($decisionrow['aicalfunc'])) {
$funcname = $decisionrow['aicalfunc'];
if ($funcname[0] != '\\')
$funcname = '\\web\\admin\\aifunc\\' . $funcname;
if (!class_exists($funcname))
return errjson('置信度 无效类:' . $funcname);
if (!method_exists($funcname, 'main'))
return errjson('置信度 无效函数:' . $funcname . '::main');
$funcname .= '::main';
$decci = call_user_func($funcname, $retai, $decisionrow['calprompt']);
}
$ret['sec'] = time() - $timespan + 1; //用时
$ret['ci'] = $decci; //置信度
$ret['ai'] = $retai; //结果
$ret['version'] = $decisionrow['version'];
if ($post->get('_more') == 'ok') {
$ret['messages'] = $openai->messages; //交互过程
$ret['roleprompt'] = $roleprompt; //提示词
$ret['system'] = $system; //角色描述
}
return succjson($ret);
}
public static function multiparam($input, $sep) {
$len = strlen($input);
$ips = array();
$i = 0;
$inMultiline = false;
$currentParam = '';
$currentValue = '';
while ($i < $len) {
if (!$inMultiline) {
$paramStart = $i;
while ($i < $len && $input[$i] !== $sep) {
if ($input[$i] === "\n")
return '参数格式不合法';
$i++;
}
if ($i == $len)
return '参数格式不合法,应用' . $sep . '号分隔';
$currentParam = trim(substr($input, $paramStart, $i - $paramStart));
if (empty($currentParam))
return '参数没有参数名';
$i++;
if ($i < $len && $input[$i] === '`') {
$inMultiline = true;
$i++;
$currentValue = '';
} else {
$valueStart = $i;
while ($i < $len && $input[$i] !== "\n")
$i++;
$currentValue = trim(substr($input, $valueStart, $i - $valueStart));
$ips[] = $currentParam . $sep . $currentValue;
$i++;
}
} else {
$valueStart = $i;
while ($i < $len && $input[$i] !== '`')
$i++;
$currentValue .= trim(substr($input, $valueStart, $i - $valueStart));
if ($i < $len && $input[$i] === '`') {
$ips[] = $currentParam . $sep . $currentValue;
$inMultiline = false;
$i++;
if ($i < $len && $input[$i] === "\n") {
$i++;
}
} else {
$ips[] = $currentParam . $sep . $currentValue;
break;
}
}
}
if (count($ips) == 0)
return '参数都不符合条件';
return $ips;
}
}