<?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;
    }
}
