控制台应用,yzncms本身基于tp5.1框架,里面的队列用不了,bug,坑
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Ai.php 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | Yzncms [ 御宅男工作室 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2018 http://yzncms.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8. // +----------------------------------------------------------------------
  9. // | fastadmin: https://www.fastadmin.net/
  10. // +----------------------------------------------------------------------
  11. // +----------------------------------------------------------------------
  12. // | 邮箱验证码接口
  13. // +----------------------------------------------------------------------
  14. namespace app\api\controller;
  15. use app\member\controller\MemberApi;
  16. use think\Db;
  17. /**
  18. * @title 邮箱验证码接口
  19. * @controller api\controller\Ems
  20. * @group base
  21. */
  22. class Ai extends MemberApi
  23. {
  24. protected $noNeedLogin = ['login', 'register','uploadCsv','uploadCsvFrom','exportCsv'];
  25. protected $noNeedRight = [];
  26. //初始化
  27. protected function initialize()
  28. {
  29. //yzncms本身已经做了跨域处理 妈的
  30. //$this->getHook();
  31. parent::initialize();
  32. }
  33. public static function getHook()
  34. {
  35. //需要使用静态方法Facade 不然会报错
  36. \think\Facade\Hook::listen('response_send');
  37. }
  38. /*
  39. * 业务控制器
  40. * 上传csv关键词数据
  41. * https://console.zx2049.com/api/ai/uploadCsv?file=20240504/eebcb4ca6a8a69fdd9e0f60c16b55746.csv
  42. */
  43. public function uploadCsv(){
  44. //测试
  45. $url = request()->get('file',0);
  46. if($url !== 0){
  47. $this->csvHandle('./uploads/'.$url);
  48. return json([]);
  49. }
  50. $file = request()->file('file'); //$file = $_FILES['file'];
  51. $info = $file->move( './uploads');
  52. if($info){
  53. // 成功上传后 获取上传信息
  54. // 输出 jpg
  55. //$url = $info->getExtension();
  56. // 输出 20160820/42a79759f284b767dfcb2a0197904287.jpg
  57. $url = $info->getSaveName();
  58. // 输出 42a79759f284b767dfcb2a0197904287.jpg
  59. //echo $info->getFilename();
  60. $data = ['code' => 0, 'msg' => '文件上传成功', 'data' =>['src'=>$url]];
  61. }else{
  62. // 上传失败获取错误信息
  63. $info = $file->getError();
  64. $data = ['code' => 1, 'msg' => '文件上传失败', 'data' =>$info];
  65. }
  66. return json($data);
  67. }
  68. /*
  69. * 业务控制器
  70. * 处理表单
  71. */
  72. public function uploadCsvFrom(){
  73. $post = request()->post();
  74. /*
  75. * rule:
  76. 0
  77. title:
  78. 建筑职称
  79. file:
  80. url:
  81. 20240505/2aff80b14c861480183278bbc9442f56.csv
  82. */
  83. //判断关键词是否存在
  84. $one = Db::name('options')->where('title','=',$post['title'])->where('status','=',1)->find();
  85. if(empty($one)){
  86. $data = ['code' => 1, 'msg' => '关键词不存在', 'data' => []];
  87. return json($data);
  88. }
  89. if(!empty($post['url'])){
  90. $this->csvHandle('./uploads/'.$post['url'],$post['rule'],$post['title']);
  91. $data = ['code' => 0, 'msg' => '提交成功', 'data' =>$post];
  92. }else{
  93. $data = ['code' => 1, 'msg' => '提交失败', 'data' => []];
  94. }
  95. return json($data);
  96. }
  97. /*
  98. * 逻辑控制器
  99. * 规则的指令集和创意 如果为空 调用全局的即可 同样优先调用自身规则
  100. */
  101. public function csvHandle($url,$rule,$title){
  102. // 读取CSV文件
  103. $filename = $url;
  104. if (file_exists($filename)) {
  105. $file = fopen($filename, 'r');
  106. //任务批次
  107. $task_no = date('YmdHis',time()).'-'.rand(1,10000);
  108. $pid = time(); //不考虑并发提交多次间隔也是秒级
  109. $num = 1;
  110. $log_content = '';
  111. $log_content_error = '';
  112. $s_num = 0;
  113. $f_num = 0;
  114. while (($line = fgetcsv($file)) !== FALSE) {
  115. // $line是一个数组,包含CSV的一行数据
  116. //print_r($line);
  117. if($num === 1){
  118. $row = $line;
  119. }else{
  120. if(!empty($line[0])) {
  121. //关键词步骤省略 需要去站长之家搜索并导出 这个步骤由人工操作
  122. //判断是否存在短标题 重复性检测
  123. //相同规则 短标题只能存在一个
  124. $one = Db::name('cms_zl')
  125. ->where('title', '=', $line[0])
  126. ->where('catid', '=', 18)
  127. ->where('gzxh', '=', $rule)
  128. ->find();
  129. if (empty($one)) {
  130. //过滤标题是否合法的函数 这个可以用定时任务处理
  131. [$is_use, $desc, $rule_id] = $this->titleHandle($line[0], $rule, $title);
  132. //构建详情
  133. $html = '';
  134. for ($i = 1; $i < 10; $i++) {
  135. $html .= $row[$i] . ':' . $line[$i] . '<br/>';
  136. }
  137. $data = [
  138. 'catid' => 18, //短标题
  139. 'title' => $line[0], //短标题
  140. 'content' => $html,
  141. 'create_time' => time(),
  142. 'update_time' => time(),
  143. 'status' => 0, //默认禁用状态 定时手动开启 自动化再读取即可
  144. 'pid' => $pid, //关联日志的aid,可查询到规则序号 主词 文件地址 执行情况
  145. 'ptlx' => 0,
  146. 'is_use' => $is_use, //是否合法
  147. 'desc' => $desc, //非法原因 或者 合法匹配结果
  148. 'gzxh' => $rule,
  149. 'is_use_id' => (int)$rule_id, //写入具体规则id 可查询到对应规则是什么 判断是否合法
  150. ];
  151. //dump($data);
  152. //插入记录
  153. $doc_id = Db::name('cms_zl')->insertGetId($data);
  154. //写入日志
  155. $log_content .= '指令id-' . $doc_id . '-' . json_encode($line, JSON_UNESCAPED_UNICODE) . '<br/>';
  156. $s_num++;
  157. } else {
  158. //写日志
  159. $log_content_error .= '<p>短标题-' . $line[0] . '-已存在-指令短标题id:' . $one['id'] . '</p>';
  160. $f_num++;
  161. }
  162. }
  163. }
  164. $num++;
  165. }
  166. //每次操作 1-2条 日志记录
  167. if(!empty($log_content)){
  168. Db::name('log')->insert([
  169. 'catid' => 27,
  170. 'title' => '批次'.$task_no.'成功导入处理-'.$s_num.'条数据',
  171. 'keywords' => $title, //主词
  172. 'description' => $filename,//对应文件地址
  173. 'create_time' => time(),
  174. 'update_time' => time(),
  175. 'status' => 1,
  176. 'site_id'=> 1,
  177. 'cid' => (int)$rule, //规则序号
  178. 'aid' => $pid, //对应记录id
  179. 'content' => '<p>'.$log_content.'</p>',
  180. ]);
  181. }
  182. if(!empty($log_content_error)){
  183. Db::name('log')->insert([
  184. 'catid' => 27,
  185. 'title' => '批次'.$task_no.'导入处理已存在-'.$f_num.'条数据',
  186. 'keywords' => $title, //主词
  187. 'description' => $filename,//对应文件地址
  188. 'create_time' => time(),
  189. 'update_time' => time(),
  190. 'status' => 1,
  191. 'site_id'=> 1,
  192. 'cid' => (int)$rule, //规则序号
  193. 'aid' => $pid, //对应记录id
  194. 'content' => '<p>'.$log_content_error.'</p>',
  195. ]);
  196. }
  197. fclose($file);
  198. }
  199. /*// 写入CSV文件
  200. $data = [
  201. ['Name', 'Age', 'Email'],
  202. ['Alice', 25, 'alice@example.com'],
  203. ['Bob', 30, 'bob@example.com']
  204. ];
  205. $filename = 'output.csv';
  206. $file = fopen($filename, 'w');
  207. foreach ($data as $row) {
  208. fputcsv($file, $row);
  209. }
  210. fclose($file);*/
  211. }
  212. /*
  213. * 模型控制器 操作数据
  214. */
  215. /*
  216. * 处理函数
  217. * $title 主词
  218. */
  219. public function titleHandle($line,$rule,$title){
  220. //规则1
  221. $desc = '';
  222. //是否完全匹配主词
  223. if (strpos($line, $title) !== false) {
  224. //包含主词
  225. }else{
  226. return [0,'短标题不包含主词['.$title.']',0];
  227. }
  228. //1.查询是否存在主词规则
  229. $one = Db::name('cms_zl')
  230. ->where('catid','=',17)
  231. ->where('title','=',$title) //只能一条 已做标题重复校验
  232. ->where('is_qj','=',0) //非全局
  233. ->where('zllx','=',1) //指令类型是 主词
  234. ->where('gzxh','=',$rule)
  235. ->where('status','=',1) //多条需要控制开关
  236. ->order('id asc') //可能添加多条 以第一条为主 理论每个规则只添加一条
  237. ->find();
  238. //2.查询全局主词规则
  239. if(empty($one)){
  240. $one = Db::name('cms_zl')
  241. ->where('catid','=',17)
  242. ->where('title','=','全局-主词类型') //只能一条 已做标题重复校验
  243. ->where('is_qj','=',1) //是全局
  244. ->where('zllx','=',1) //指令类型是 主词
  245. ->where('gzxh','=',$rule)
  246. ->where('status','=',1) //多条需要控制开关
  247. ->order('id asc') //可能添加多条 以第一条为主 理论每个规则只添加一条
  248. ->find();
  249. }
  250. //3.查询全局规则
  251. if(empty($one)){
  252. $one = Db::name('cms_zl')
  253. ->where('catid','=',17)
  254. ->where('title','=','全局-非主非副') //只能一条 已做标题重复校验
  255. ->where('is_qj','=',1) //是全局
  256. ->where('zllx','=',0) //指令类型是 非主非副
  257. ->where('gzxh','=',$rule)
  258. ->where('status','=',1) //多条需要控制开关
  259. ->order('id asc') //可能添加多条 以第一条为主 理论每个规则只添加一条
  260. ->find();
  261. }
  262. if(empty($one)){
  263. return [0,'不存在全局通用规则,全局主词规则,当前主词规则',0];
  264. }
  265. //4.获取到全局或主词的副词
  266. $two = [];
  267. if(empty($one['fclb']) || (string)$one['fclb'] === '0'){
  268. //不存在副词规则
  269. $desc .= '不存在副词规则-|-';
  270. }else{
  271. //存在副词规则
  272. $one['fclb'] = $one['fclb'].',';
  273. $fclb = explode(',',$one['fclb']);
  274. $line_sor = str_replace($title, "", $line); //短标题去除主词
  275. $is_bh = 0;
  276. $fc = '';
  277. $fc_num = 0;
  278. foreach ($fclb as $k => $v) {
  279. //该判断 主词和副词 不一定是连在一起的
  280. if(!empty($v)) {
  281. if (strpos($line_sor, $v) !== false) {
  282. //包含
  283. $is_bh = 1;
  284. $fc = $v;
  285. //break; //跳出 目前只匹配一个 存在多个不做处理 以第一个为主
  286. $fc_num++;
  287. }
  288. }
  289. }
  290. //存在多个副词 不合理
  291. if($fc_num > 1){
  292. return [0,'存在多个副词,不合法',$one['id']];
  293. }
  294. //5.查询是否存在副词
  295. if($is_bh === 1){
  296. //6.查询主词+副词是否存在规则
  297. $two = Db::name('cms_zl')
  298. ->where('catid','=',17)
  299. ->where('title','=',$title.$fc) //查询设置 按照主词+副词 格式查询 //只能一条 已做标题重复校验
  300. ->where('is_qj','=',0) //非全局
  301. ->where('zllx','=',2) //指令类型是 副词
  302. ->where('gzxh','=',$rule)
  303. ->where('status','=',1) //多条需要控制开关
  304. ->order('id asc') //可能添加多条 以第一条为主 理论每个规则只添加一条
  305. ->find();
  306. //7.查询副词通用全局规则
  307. if(empty($two)){
  308. $two = Db::name('cms_zl')
  309. ->where('catid','=',17)
  310. ->where('title','=','全局-副词类型') //查询设置 按照主词+副词 格式查询 //只能一条 已做标题重复校验
  311. ->where('is_qj','=',1) //非全局
  312. ->where('zllx','=',2) //指令类型是 副词
  313. ->where('gzxh','=',$rule)
  314. ->where('status','=',1) //多条需要控制开关
  315. ->order('id asc') //可能添加多条 以第一条为主 理论每个规则只添加一条
  316. ->find();
  317. }
  318. }else{
  319. //短标题不包含副词
  320. $desc .= '短标题不包含副词-|-';
  321. }
  322. }
  323. //短标题的主词和副词 不一定是连在一起的
  324. if(!empty($two)){
  325. //存在副词规则 按照此规则执行
  326. $data = $two;
  327. }else{
  328. //按照$one规则记录执行
  329. $data = $one;
  330. }
  331. //8.判断是否合法 地区词
  332. [$is_bh,$fc] = $this->isInRule($data['dqc'],$line);
  333. if($is_bh > 0){
  334. $desc .= '存在地区词'.$fc.',不合法-|-';
  335. return [0,$desc,$data['id']];
  336. }
  337. //9.判断是否合法 分类词
  338. [$is_bh,$fc] = $this->isInRule($data['flc'],$line);
  339. if($is_bh > 0){
  340. $desc .= '存在分类词'.$fc.',不合法-|-';
  341. return [0,$desc,$data['id']];
  342. }
  343. //10.判断是否合法 时间词
  344. [$is_bh,$fc] = $this->isInRule($data['sjc'],$line);
  345. if($is_bh > 0){
  346. $desc .= '存在时间词'.$fc.',不合法-|-';
  347. return [0,$desc,$data['id']];
  348. }
  349. //11.判断是否合法 屏蔽词
  350. [$is_bh,$fc] = $this->isInRule($data['pbc'],$line);
  351. if($is_bh > 0){
  352. $desc .= '存在屏蔽词'.$fc.',不合法-|-';
  353. return [0,$desc,$data['id']];
  354. }
  355. //12.判断是否合法 同时存在触发词和并发词
  356. [$is_bh1,$fc1] = $this->isInRule($data['cfc'],$line);
  357. [$is_bh2,$fc2] = $this->isInRule($data['bfc'],$line);
  358. if($is_bh1 > 0 && $is_bh2 > 0){
  359. //同时存在
  360. $desc .= '同时存在并发词['.$fc2.']和触发词['.$fc1.']合法';
  361. return [1,$desc,$data['id']];
  362. }else{
  363. $desc .= '不同时存在并发词['.$fc2.']和触发词['.$fc1.'],不合法';
  364. return [0,$desc,$data['id']];
  365. }
  366. }
  367. /*
  368. * 规则设定
  369. */
  370. public function setRule(){
  371. //方案1: 定义config配置文件
  372. //方案2: 直接代码写死
  373. //方案3: 后台设置 -- 采用这个
  374. $json = [
  375. ''
  376. ];
  377. }
  378. /*
  379. * 函数 是否包含
  380. */
  381. public function isInRule($data,$str){
  382. $data = $data.',';
  383. $data = explode(',',$data);
  384. $is_bh = 0;
  385. $fc = '';
  386. foreach ($data as $k => $v) {
  387. //该判断 主词和副词 不一定是连在一起的
  388. if(!empty($v)) {
  389. if (strpos($str, $v) !== false) {
  390. //包含
  391. $is_bh = 1;
  392. $fc = $v;
  393. break; //跳出 目前只匹配一个 存在多个不做处理 以第一个为主
  394. }
  395. }
  396. }
  397. return [$is_bh,$fc];
  398. }
  399. /*
  400. * 导出csv
  401. * http://console.zx2049.com/api/ai/exportCsv
  402. */
  403. public function exportCsv(){
  404. $list = Db::name('cms_zl')->field('id,title,desc')->where('catid','=',18)->select();
  405. /* $data = [
  406. ['Name', 'Age', 'Email'],
  407. ['Alice', 25, 'alice@example.com'],
  408. ['Bob', 30, 'bob@example.com']
  409. ];*/
  410. $filename = 'output.csv';
  411. $file = fopen($filename, 'w');
  412. foreach ($list as $row) {
  413. fputcsv($file, $row);
  414. }
  415. fclose($file);
  416. }
  417. }