amic 2 ヶ月 前
コミット
a08eaa6e45

+ 1 - 0
.gitignore

@@ -4,6 +4,7 @@ vendor
 node_modules
 /web/images
 /web/amic_price_2023.pdf
+/web/amic_price.pdf
 /web/pr
 /web/pr2
 /web/uploads

+ 53 - 0
models/OllamaAI.php

@@ -0,0 +1,53 @@
+<?php
+
+namespace app\models;
+
+use yii;
+use yii\helpers\Url;
+
+class OllamaAI extends \app\models\base\BaseAI
+{
+	public $host = 'http://192.168.0.20:11434';
+	public $model = 'gemma2';
+	public static $urlgen = '/api/generate';
+	public $res = '';
+
+	function OllamaAI(){
+		$this->SetHeader();
+	}
+
+	public function generate( $promt, $context = '' ){
+		$url = $this->host.self::$urlgen;
+
+		$cmd = array(
+			"model" => $this->model,
+			"prompt" => $promt,
+			"stream" => false,
+			'keep_alive' =>'60m'
+		);
+		if( $context ){
+			$cmd['context'] = $context;
+		}
+		$r = $this->Send( $url, $cmd );
+		$this->res = $r;
+		return $r;
+	}
+
+	public function GetTime(){
+		$r = $this->res;
+		$robj = json_decode($r);
+		return $robj->eval_duration;
+	}
+
+	public function Getres(){
+		$r = $this->res;
+		$robj = json_decode($r);
+		return nl2br($robj->response);
+	}
+
+	public function Getcontext(){
+		$r = $this->res;
+		$robj = json_decode($r);
+		return $robj->context;
+	}
+}

+ 50 - 0
models/base/BaseAI.php

@@ -0,0 +1,50 @@
+<?php
+/*
+	      test yandex api
+*/
+namespace app\models\base;
+
+use yii\base\Component;
+use Yii;
+
+class BaseAI extends Component
+{
+	private $header = array();
+	public   $config = array();
+
+	function __construct()
+	{
+		$this->config = [];
+	}
+
+	function SetHeader( $header = null ){
+		if( !is_array( $header ) ){
+			$header = array(
+				'header'=>"Accept-language: ru\r\n" .
+				'Content-Type: application/json;  charset=utf-8;'."\r\n"
+			);
+		}
+
+		$this->header = $header;
+	}
+
+	function Send( $url, $cmd ){
+		$json = json_encode($cmd);
+		$curl_handle=curl_init();
+		curl_setopt($curl_handle, CURLOPT_URL, $url);
+		curl_setopt($curl_handle, CURLOPT_CUSTOMREQUEST, "POST");
+		curl_setopt($curl_handle, CURLOPT_CONNECTTIMEOUT, 20);
+		curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, 1);
+		curl_setopt($curl_handle, CURLOPT_USERAGENT, 'amicru');
+		curl_setopt($curl_handle, CURLOPT_SSL_VERIFYPEER, false );
+		curl_setopt($curl_handle, CURLOPT_SSL_VERIFYHOST, false);
+		curl_setopt($curl_handle, CURLOPT_HTTPHEADER, $this->header);
+		curl_setopt($curl_handle, CURLOPT_POST, 1);
+		curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $json);
+		$query = curl_exec($curl_handle);
+//		echo curl_error($curl_handle);
+//		print_a(curl_getinfo($curl_handle));
+		curl_close($curl_handle);
+		return $query;
+	}
+}

+ 49 - 0
modules/manager/controllers/AiController.php

@@ -0,0 +1,49 @@
+<?php
+namespace manager\controllers;
+
+use app\models\OllamaAI;
+use Yii;
+
+class AiController extends BaseController
+{
+    public function actionIndex()
+    {
+		return 'Используй API для получения данных';
+    }
+
+    public function actionAjaxGetTitle()
+    {
+		if (Yii::$app->request->isPost){
+			$cache = Yii::$app->cache;
+			$type = Yii::$app->request->post('AI');
+			$text = Yii::$app->request->post('text');
+			$progress = Yii::$app->request->post('progress');
+
+			if( $text && $type == 'ollama' ){
+				$ses = false;
+				if( \Yii::$app->session->isActive ){
+					\Yii::$app->session->close();
+					$ses = true;
+				}
+				$ollama = new OllamaAI();
+				$r = $ollama->generate(strip_tags($text));
+				$data = $ollama->Getres();
+				$t = $ollama->GetTime();
+				$key = 'AI_time_mid';
+				$tm = $cache->get($key);
+				if( $tm ){
+					$cache->set($key, ($t+$tm)/2);
+				}else{
+					$cache->set($key, $t);
+				}
+				if( $ses ) \Yii::$app->session->open();
+				return json_encode( ['status'=>'ok', 'data'=>$data, 'progress'=>$progress] );
+			}else{
+				return json_encode( ['status'=>'err', 'msg'=>'Нет доступа до AI '.$type] );
+			}
+		}
+		return json_encode( ['status'=>'err', 'msg'=>'Ошибка получения данных'] );
+	}
+
+
+}

+ 81 - 5
modules/manager/views/default/formNews.php

@@ -29,7 +29,14 @@ $tagsmenu = Yii::$app->cache->getOrSet("tagsmenu",function () use($tmodel){
 	return $tmodel->find()->rightJoin(['m'=>Tagsfilter::find()], 'm.id = tags.id')->orderBy('sort')->All();
 });
 
-//echo $news->text;
+$key = 'AI_time_mid';
+$AI_time_mid = $cache->get($key);
+if( $AI_time_mid == false ){
+	$AI_time_mid = 100;
+}else{
+	$AI_time_mid = $AI_time_mid/1000000000;
+}
+
 ?>
 
 <ul class="nav nav-tabs">
@@ -250,16 +257,29 @@ echo $form->field($news, 'title')->textInput([
 <div class="form-group field-news-title required">
 	<label class="control-label col-form-label" for="news-title">Заголовок</label>
 	<div class="row">
-		<input type="text" maxlength="<?=$tcount?>" id="news-title" class="form-control js-word-count-input col-sm-10 ml-2" name="News[title]" placeholder="Заголовок новости" aria-required="true" value='<?=str_replace("'", '&apos;', $news->title)?>'>
+			<input type="text" maxlength="<?=$tcount?>" id="news-title" class="form-control js-word-count-input col-sm-10 ml-2" name="News[title]" placeholder="Заголовок новости" aria-required="true" value='<?=str_replace("'", '&apos;', $news->title)?>'>
+		<span class="input-group-append">
+			<span type="button" class="btn btn-outline-primary btn-block btn-sm aiget" style="width: fit-content;" id="aititle" data-pb="aiprogress0" data-preprompt="Подскажи привлекательный заголовок для статьи"><i class="fa fa-robot"></i> Гена</span>
+		</span>
 		<div class="help-block px-lg-2"><div class="news__input-word-count"><span class="badge badge-info" id="title_count"></span></div></div>
 		<a class="btn btn-primary  px-lg-2" data-toggle="collapse" href="#collapseSEOTitle" role="button" aria-expanded="false" aria-controls="collapseSEOTitle">SEO title</a>
-		<div class="help-block"></div>
+		<div class="help-block">
+		</div>
 	</div>
+		<div class="progress progress-sm active mt-1 mr-2 hidden">
+			<div class="progress-bar bg-success progress-bar-striped" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%" id="aiprogress0"><span class="sr-only">40</span></div>
+		</div>
 </div>
 <div class="collapse show" id="collapseSEOTitle">
   <div class="card card-body py-1">
+    <span class="input-group-append">
     <input type="text" name="News[meta_title]" maxlength="<?=$tcount?>" value="<?=htmlentities($news->meta_title)?>" placeholder="SEO Title" class="form-control js-word-count-input col-sm-10 ml-1 py-0">
+		<span type="button" class="btn btn-outline-primary btn-block btn-sm aiget" style="width: fit-content;" id="aistitle" data-pb="saiprogressx" data-preprompt="Подскажи SEO заголовок для статьи"><i class="fa fa-robot"></i> Гена</span>
+	</span>
 	<div class="help-block">Поле для альтернативного SEO Title заголовка, если не заполнять совпадёт с основным заголовком</div>
+		<div class="progress progress-sm active hidden" id="saiprogress">
+			<div class="progress-bar bg-success progress-bar-striped" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%" id="saiprogressx"><span class="sr-only">40</span></div>
+		</div>
   </div>
 </div>
 <div class="form-group field-news-lid required">
@@ -848,6 +868,7 @@ if (jQuery('#dt_pub').data('datetimepicker')) { jQuery('#dt_pub').datetimepicker
 });
 $(function() {
 	window.varsubmit = false;
+	window.robotr = false;
     $("input[id='news-title']").keyup(function count(){
         number = $("input[id='news-title']").val().length;
         $("#title_count").html(number);
@@ -915,8 +936,46 @@ $(function() {
 		return false;
       }
     });
+	$(".aiget").click(function(){
+		if( window.robotr ){
+			alert('Может быть только один запрос к роботу, подождите окончания предыдущего запроса.');
+			return;
+		}
+		window.robotr = true;
+		let text = CKEDITOR.instances.js_news_content.getData();
+		let preprompt = $(this).data('preprompt');
+		text = preprompt+': '+text;
+		let pbar = '#'+$(this).data('pb');
+		$(pbar).parent().removeClass('hidden');
+		$(pbar).attr('aria-valuenow', 100);
+		$(pbar).css('width','100%');
+		let data = { timer : null };
+		data.timer = setInterval(countprogress, 1000, pbar, data);
+		$.post("/manager/ai/ajax-get-title", {AI:'ollama',text:text, progress: pbar}, function( data ) {
+			if( data.status == 'ok' ){
+				var data_all = data.data;
+				$("#AItext").html(data_all);
+				$('#AI').modal('show');
+				$(data.progress).css('width','0%');
+				$(data.progress).attr('aria-valuenow', 0);
+			}else{
+				console.log(data.msg);
+				$("#AItext").html(data.msg);
+				$('#AI').modal('show');
+			}
+			window.robotr = false;
+		}, "json");
+	});
 });
-
+function countprogress(pbar, data){
+	val = $(pbar).attr('aria-valuenow');
+	d = 100/<?=$AI_time_mid?>;
+	console.log(100/d);
+	val = val - d;
+	if( val <=0 ) clearTimeout(data.timer);
+	$(pbar).attr('aria-valuenow', val);
+	$(pbar).css('width',val+'%');
+}
 function runSuggestions(element,query) {
 	let sug_area=$(element).parents().eq(2).find('.autocomplete .autocomplete-items');
 	if( query.length > 1 ){
@@ -978,4 +1037,21 @@ window.onbeforeunload = function(e) {
 	echo $this->render('../top-slider/modalform', ['news'=>$news]);
 
 ?>
-
+<div class="modal" tabindex="-1" data-show="true" id="AI">
+  <div class="modal-dialog">
+    <div class="modal-content">
+      <div class="modal-header">
+        <h5 class="modal-title">Генератор текстов от Гены</h5>
+        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+          <span aria-hidden="true">&times;</span>
+        </button>
+      </div>
+      <div class="modal-body">
+        <p id="AItext"></p>
+      </div>
+      <div class="modal-footer">
+        <button type="button" class="btn btn-primary" data-dismiss="modal">Закрыть</button>
+      </div>
+    </div>
+  </div>
+</div>

+ 12 - 3
modules/manager/views/default/test.php

@@ -2,10 +2,19 @@
 
 use yii\helpers\Html;
 use yii\widgets\ActiveForm;
-use app\models\Ya;
+use app\models\OllamaAI;
 
-$ya = new Ya();
+//$ya = new Ya();
 //echo $ya->getToken();
-var_dump($ya->Send());
+//var_dump($ya->Send());
+
+$ollama = new OllamaAI();
+
+$r = $ollama->generate('раскажи что такое дюйм');
+//var_dump($r);
+echo $ollama->Getres();
+//	$c = $ollama->Getcontext();
+//	$r = $ollama->generate('раскажи что такое дюйм', $c);
+//echo $ollama->Getres();
 ?>
 ----

+ 1 - 1
views/layouts/footer.php

@@ -10,7 +10,7 @@ $index = ($action == "index");
                     <li class="footer-nav__item col-md-6"><a href="/news" class="footer-nav__link">Новости на сайте</a></li>
                     <li class="footer-nav__item col-md-6"><a href="https://fmprod.ru" class="footer-nav__link">FM-Продакшн</a></li>
                     <li class="footer-nav__item col-md-6"><a href="/rules" class="footer-nav__link">Пользовательское соглашение</a></li>
-                    <li class="footer-nav__item col-md-6"><a href="/amic_price_2023.pdf" class="footer-nav__link">Реклама на сайте</a></li>
+                    <li class="footer-nav__item col-md-6"><a href="/amic_price.pdf" class="footer-nav__link">Реклама на сайте</a></li>
                     <li class="footer-nav__item col-md-6"><a href="/pr2" class="footer-nav__link">Прайсы на предвыборную агитацию 2024г. по Республике Алтай</a></li>
                     <li class="footer-nav__item col-md-6"><a href="/pr" class="footer-nav__link">Прайсы на предвыборную агитацию 2024г.</a></li>
                     <li class="footer-nav__item col-md-6"><a href="/weather" class="footer-nav__link" title="Погода">Погода</a></li>