Add OpenAI

Add OpenAI blade

fixed openai route

优化 openai

wip

wip

wip

wip

fixed description

logo

fixed name and description

wip

wip

wip

wip

wip

code format

fixed name and description
This commit is contained in:
Edward Yang 2023-02-27 11:55:43 +08:00
parent 575469ca3d
commit ff6c2211a0
10 changed files with 349 additions and 0 deletions

1
plugins/.gitignore vendored
View File

@ -1,6 +1,7 @@
*
!FlatShipping
!LatestProducts
!Openai
!Paypal
!Social
!Stripe

View File

@ -0,0 +1,33 @@
<?php
/**
* Bootstrap.php
*
* @copyright 2023 beikeshop.com - All Rights Reserved
* @link https://beikeshop.com
* @author Edward Yang <yangjin@guangda.work>
* @created 2023-02-27 13:57:38
* @modified 2023-02-27 13:57:38
*/
namespace Plugin\Openai;
class Bootstrap
{
public function boot()
{
add_hook_filter('admin.sidebar.home.prefix', function ($data) {
$data[] = 'openai';
return $data;
});
add_hook_filter('admin.sidebar.home_routes', function ($data) {
$data[] = [
'route' => 'openai',
'title' => 'ChatGPT',
];
return $data;
});
}
}

View File

@ -0,0 +1,28 @@
<?php
/**
* OpenaiController.php
*
* @copyright 2023 beikeshop.com - All Rights Reserved
* @link https://beikeshop.com
* @author Edward Yang <yangjin@guangda.work>
* @created 2023-02-27 16:13:08
* @modified 2023-02-27 16:13:08
*/
namespace Plugin\Openai\Controllers;
use Beike\Admin\Http\Controllers\Controller;
class OpenaiController extends Controller
{
public function index()
{
$plugin = app('plugin')->getPlugin('openai');
$data = [
'name' => $plugin->getLocaleName(),
'description' => $plugin->getLocaleDescription(),
];
return view('Openai::admin.openai', $data);
}
}

View File

@ -0,0 +1,23 @@
<?php
/**
* setting.php
*
* @copyright 2022 beikeshop.com - All Rights Reserved
* @link https://beikeshop.com
* @author Edward Yang <yangjin@guangda.work>
* @created 2022-08-11 15:26:18
* @modified 2022-08-11 15:26:18
*/
return [
// Text
'title' => 'OpenAI intelligent chat assistant',
'sub_title' => 'Based on OpenAI GPT3.0 integrated development If you have any questions, please consult qq group 639108380',
'no_question' => 'Please enter the search content in the box below',
'enter_question' => 'Please enter a question',
'loading' => 'loading...',
'no_more' => 'no more',
'qa_q' => 'ask',
'qa_a' => 'answer',
'number_free' => 'The remaining free times of the day',
];

View File

@ -0,0 +1,23 @@
<?php
/**
* setting.php
*
* @copyright 2022 beikeshop.com - All Rights Reserved
* @link https://beikeshop.com
* @author Edward Yang <yangjin@guangda.work>
* @created 2022-08-11 15:26:18
* @modified 2022-08-11 15:26:18
*/
return [
// Text
'title' => 'OpenAI 智能聊天助手',
'sub_title' => '基于OpenAI GPT3.0 集成开发 如有疑问详询qq群639108380',
'no_question' => '请在下面输入框搜索内容',
'enter_question' => '请输入问题',
'loading' => '加载中...',
'no_more' => '没有更多了',
'qa_q' => '问',
'qa_a' => '答',
'number_free' => '当日剩余免费次数',
];

View File

@ -0,0 +1,23 @@
<?php
/**
* setting.php
*
* @copyright 2022 beikeshop.com - All Rights Reserved
* @link https://beikeshop.com
* @author Edward Yang <yangjin@guangda.work>
* @created 2022-08-11 15:26:18
* @modified 2022-08-11 15:26:18
*/
return [
// Text
'title' => 'OpenAI 智能聊天助手',
'sub_title' => '基於OpenAI GPT3.0 集成開發 如有疑問詳詢qq群639108380',
'no_question' => '請在下面輸入框搜索內容',
'enter_question' => '請輸入問題',
'loading' => '加載中...',
'no_more' => '没有更多了',
'qa_q' => '問',
'qa_a' => '答',
'number_free' => '當日剩餘免費次數',
];

View File

@ -0,0 +1,15 @@
<?php
/**
* admin.php
*
* @copyright 2022 beikeshop.com - All Rights Reserved
* @link https://beikeshop.com
* @author Edward Yang <yangjin@guangda.work>
* @created 2022-08-04 16:17:53
* @modified 2022-08-04 16:17:53
*/
use Illuminate\Support\Facades\Route;
use Plugin\Openai\Controllers\OpenaiController;
Route::get('/openai', [OpenaiController::class, 'index'])->name('openai');

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -0,0 +1,185 @@
@extends('admin::layouts.master')
@section('title', $name)
@section('content')
<div class="row">
<div class="col-md-7 col-12 answer-wrap">
<div class="border p-3 bg-white" id="answer"><div class="not-answer"><i class="bi bi-activity"></i> {{ __('Openai::common.no_question') }}</div></div>
<div class="input-group mb-3 mt-4">
<input type="text" id="ai-input" class="form-control rounded-0 form-control-lg" placeholder="{{ __('Openai::common.enter_question') }}" aria-label="{{ __('Openai::common.enter_question') }}" aria-describedby="button-addon2">
<button class="btn btn-primary px-4 rounded-0" type="button" id="ai-submit"><i class="bi bi-send-fill"></i> {{ __('common.confirm') }}</button>
</div>
</div>
<div class="col-md-5 col-12">
<div class="mb-2"><i class="bi bi-megaphone text-secondary fs-3"></i> </div>
<div class="number-free mb-3 fs-5">{{ __('Openai::common.number_free') }}: <span>{{ __('Openai::common.loading') }}</span></div>
<div class="text-secondary">{{ $description }}</div>
</div>
</div>
<script>
let last_page = 0;
let current_page = 1;
$('#answer').scroll(function() {
if ($(this).scrollTop() == 0) {
if (current_page < last_page) {
if (!$('.text-loading').length) {
$('#answer').prepend('<div class="text-center py-3 text-secondary text-loading"><i class="bi bi-activity"></i> {{ __('Openai::common.loading') }}</div>');
}
clearTimeout(timer);
var timer = setTimeout(function() {
loadHistories(current_page + 1);
}, 300);
}
if (current_page == last_page) {
if (!$('.text-loading').length) {
$('#answer').prepend('<div class="text-center py-3 text-secondary text-loading"><i class="bi bi-activity"></i> {{ __('Openai::common.no_more') }}</div>');
}
}
}
});
$('#answer').height($(window).height() - 260);
$(document).ready(function() {
loadQuantities();
loadHistories();
$('#ai-input').keydown(function(e) {
if (e.keyCode == 13) {
$('#ai-submit').click();
}
})
$('#ai-submit').click(function() {
var question = $('#ai-input').val();
if (!question) {
return;
}
const $btn = $(this);
const btnHtml = $(this).html();
const loadHtml = '<span class="spinner-border spinner-border-sm"></span>';
let html = '';
$.ajax({
url: `${config.api_url}/api/openai/completions`,
type: 'POST',
headers: {
'token': '{{ system_setting('base.developer_token') ?? '' }}'
},
data: {
prompt: question,
domain: config.app_url,
},
beforeSend: function() { $btn.html(loadHtml).prop('disabled', true) },
complete: function() { $btn.html(btnHtml).prop('disabled', false) },
success: function(data) {
if ($('.not-answer').length) {
$('.not-answer').remove();
}
if (data.error) {
layer.msg(data.error);
return;
}
$('.number-free span').text(data.available)
let answer = data.response.choices[0].text.trim();
html += '<div class="answer-list">',
html += '<div class="d-flex mb-2"><div class="text-secondary">{{ __('Openai::common.qa_q') }}</div><div class="w-100">' + question + '</div></div>',
html += '<div class="d-flex"><div class="text-secondary">{{ __('Openai::common.qa_a') }}</div><div class="w-100">' + answer + '</div></div>'
html += '</div>'
$('#ai-input').val('');
$('#answer').append(html);
$('#answer').scrollTop($('#answer')[0].scrollHeight);
}
})
})
})
function loadQuantities() {
$.ajax({
url: `${config.api_url}/api/openai/quantities?domain=${config.app_url}`,
headers: {
'token': '{{ system_setting('base.developer_token') ?? '' }}'
},
success: function(data) {
$('.number-free span').text(data.available)
}
})
}
function loadHistories(page = 1) {
$.ajax({
url: `${config.api_url}/api/openai/histories?domain=${config.app_url}&page=${page}`,
headers: {
'token': '{{ system_setting('base.developer_token') ?? '' }}'
},
success: function(data) {
$('.text-loading').remove();
last_page = data.last_page;
current_page = data.current_page;
if (data.data.length) {
$('.not-answer').remove();
let html = '';
data.data.forEach(function(item, index) {
html += '<div class="answer-list '+ (!index ? 'first' : '') +'">',
html += '<div class="d-flex mb-2"><div class="text-secondary">{{ __('Openai::common.qa_q') }}</div><div class="w-100">' + item.question + '</div></div>',
html += '<div class="d-flex"><div class="text-secondary">{{ __('Openai::common.qa_a') }}</div><div class="w-100">' + item.answer + '</div></div>'
html += '</div>'
})
$('#answer').prepend(html);
if (page == 1) {
$('#answer').scrollTop($('#answer')[0].scrollHeight);
} else {
$('#answer').scrollTop($('#answer .answer-list.first:eq(1)').offset().top - 100 - $('#answer').offset().top);
}
}
}
})
}
</script>
<style>
body {
background-color: #f4f4f4;
}
#answer {
overflow-y: auto;
border-radius: 0.25rem;
white-space: pre-wrap;
}
.not-answer {
text-align: center;
padding: 100px 0;
font-size: 20px;
color: #999;
}
.answer-wrap {
max-width: 740px;
}
.answer-list {
padding-bottom: 20px;
margin-bottom: 20px;
border-bottom: 1px solid #eee;
}
.answer-list:last-child {
border-bottom: none;
}
</style>
@endsection

View File

@ -0,0 +1,18 @@
{
"code": "openai",
"name": {
"zh_cn": "ChatGPT(OpenAI)智能聊天助手",
"en": "Integration with OpenAI"
},
"description": {
"zh_cn": "ChatGPT(OpenAI)智能聊天助手, 基于OpenAI GPT3.0 集成开发, 如有疑问详询QQ群 639108380",
"en": "Integration with OpenAI"
},
"type": "feature",
"version": "v1.0.0",
"icon": "/image/logo.png",
"author": {
"name": "成都光大网络科技有限公司",
"email": "yangjin@guangda.work"
}
}