diff --git a/application/admin/controller/deepseek/Question.php b/application/admin/controller/deepseek/Question.php
new file mode 100644
index 0000000..3cbc3c6
--- /dev/null
+++ b/application/admin/controller/deepseek/Question.php
@@ -0,0 +1,71 @@
+model = new \app\admin\model\deepseek\Question;
+
+ }
+
+
+
+ /**
+ * 默认生成的控制器所继承的父类中有index/add/edit/del/multi五个基础方法、destroy/restore/recyclebin三个回收站方法
+ * 因此在当前控制器中可不用编写增删改查的代码,除非需要自己控制这部分逻辑
+ * 需要将application/admin/library/traits/Backend.php中对应的方法复制到当前控制器,然后进行修改
+ */
+
+
+ /**
+ * 查看
+ */
+ public function index()
+ {
+ //当前是否为关联查询
+ $this->relationSearch = true;
+ //设置过滤方法
+ $this->request->filter(['strip_tags', 'trim']);
+ if ($this->request->isAjax()) {
+ //如果发送的来源是Selectpage,则转发到Selectpage
+ if ($this->request->request('keyField')) {
+ return $this->selectpage();
+ }
+ list($where, $sort, $order, $offset, $limit) = $this->buildparams();
+
+ $list = $this->model
+ ->with(['user'])
+ ->where($where)
+ ->order($sort, $order)
+ ->paginate($limit);
+
+ foreach ($list as $row) {
+
+ $row->getRelation('user')->visible(['nickname','mobile','avatar']);
+ }
+
+ $result = array("total" => $list->total(), "rows" => $list->items());
+
+ return json($result);
+ }
+ return $this->view->fetch();
+ }
+
+}
diff --git a/application/admin/controller/deepseek/Stream.php b/application/admin/controller/deepseek/Stream.php
new file mode 100644
index 0000000..cfcdda8
--- /dev/null
+++ b/application/admin/controller/deepseek/Stream.php
@@ -0,0 +1,71 @@
+model = new \app\admin\model\deepseek\Stream;
+
+ }
+
+
+
+ /**
+ * 默认生成的控制器所继承的父类中有index/add/edit/del/multi五个基础方法、destroy/restore/recyclebin三个回收站方法
+ * 因此在当前控制器中可不用编写增删改查的代码,除非需要自己控制这部分逻辑
+ * 需要将application/admin/library/traits/Backend.php中对应的方法复制到当前控制器,然后进行修改
+ */
+
+
+ /**
+ * 查看
+ */
+ public function index()
+ {
+ //当前是否为关联查询
+ $this->relationSearch = true;
+ //设置过滤方法
+ $this->request->filter(['strip_tags', 'trim']);
+ if ($this->request->isAjax()) {
+ //如果发送的来源是Selectpage,则转发到Selectpage
+ if ($this->request->request('keyField')) {
+ return $this->selectpage();
+ }
+ list($where, $sort, $order, $offset, $limit) = $this->buildparams();
+
+ $list = $this->model
+ ->with(['question'])
+ ->where($where)
+ ->order($sort, $order)
+ ->paginate($limit);
+
+ foreach ($list as $row) {
+
+ $row->getRelation('question')->visible(['user_id','content']);
+ }
+
+ $result = array("total" => $list->total(), "rows" => $list->items());
+
+ return json($result);
+ }
+ return $this->view->fetch();
+ }
+
+}
diff --git a/application/admin/lang/zh-cn/deepseek/question.php b/application/admin/lang/zh-cn/deepseek/question.php
new file mode 100644
index 0000000..35fda66
--- /dev/null
+++ b/application/admin/lang/zh-cn/deepseek/question.php
@@ -0,0 +1,12 @@
+ '提问id',
+ 'User_id' => '提问用户',
+ 'Content' => '提问的问题',
+ 'Createtime' => '创建时间',
+ 'Endtime' => '答完时间',
+ 'User.nickname' => '昵称',
+ 'User.mobile' => '手机号',
+ 'User.avatar' => '头像'
+];
diff --git a/application/admin/lang/zh-cn/deepseek/stream.php b/application/admin/lang/zh-cn/deepseek/stream.php
new file mode 100644
index 0000000..3d8c595
--- /dev/null
+++ b/application/admin/lang/zh-cn/deepseek/stream.php
@@ -0,0 +1,15 @@
+ 'id',
+ 'Question_id' => '提问id',
+ 'Assistant_id' => '应答id',
+ 'Object' => '应答对象',
+ 'Created_time' => '应答时间',
+ 'Model' => '应答模型',
+ 'Usage_json' => 'usagejson',
+ 'Choices_json' => '应答实体json',
+ 'Createtime' => '创建时间',
+ 'Question.user_id' => '提问用户',
+ 'Question.content' => '提问的问题'
+];
diff --git a/application/admin/model/deepseek/Question.php b/application/admin/model/deepseek/Question.php
new file mode 100644
index 0000000..326182e
--- /dev/null
+++ b/application/admin/model/deepseek/Question.php
@@ -0,0 +1,52 @@
+belongsTo('app\admin\model\User', 'user_id', 'id', [], 'LEFT')->setEagerlyType(0);
+ }
+}
diff --git a/application/admin/model/deepseek/Stream.php b/application/admin/model/deepseek/Stream.php
new file mode 100644
index 0000000..657a5fc
--- /dev/null
+++ b/application/admin/model/deepseek/Stream.php
@@ -0,0 +1,52 @@
+belongsTo('Question', 'question_id', 'id', [], 'LEFT')->setEagerlyType(0);
+ }
+}
diff --git a/application/admin/validate/deepseek/Question.php b/application/admin/validate/deepseek/Question.php
new file mode 100644
index 0000000..b5bfd6d
--- /dev/null
+++ b/application/admin/validate/deepseek/Question.php
@@ -0,0 +1,27 @@
+ [],
+ 'edit' => [],
+ ];
+
+}
diff --git a/application/admin/validate/deepseek/Stream.php b/application/admin/validate/deepseek/Stream.php
new file mode 100644
index 0000000..2f0801b
--- /dev/null
+++ b/application/admin/validate/deepseek/Stream.php
@@ -0,0 +1,27 @@
+ [],
+ 'edit' => [],
+ ];
+
+}
diff --git a/application/admin/view/deepseek/question/add.html b/application/admin/view/deepseek/question/add.html
new file mode 100644
index 0000000..c10bedd
--- /dev/null
+++ b/application/admin/view/deepseek/question/add.html
@@ -0,0 +1,27 @@
+
diff --git a/application/admin/view/deepseek/question/edit.html b/application/admin/view/deepseek/question/edit.html
new file mode 100644
index 0000000..4d8b3b9
--- /dev/null
+++ b/application/admin/view/deepseek/question/edit.html
@@ -0,0 +1,27 @@
+
diff --git a/application/admin/view/deepseek/question/index.html b/application/admin/view/deepseek/question/index.html
new file mode 100644
index 0000000..e19d226
--- /dev/null
+++ b/application/admin/view/deepseek/question/index.html
@@ -0,0 +1,29 @@
+
+ {:build_heading()}
+
+
+
diff --git a/application/admin/view/deepseek/stream/add.html b/application/admin/view/deepseek/stream/add.html
new file mode 100644
index 0000000..53ca01a
--- /dev/null
+++ b/application/admin/view/deepseek/stream/add.html
@@ -0,0 +1,71 @@
+
diff --git a/application/admin/view/deepseek/stream/edit.html b/application/admin/view/deepseek/stream/edit.html
new file mode 100644
index 0000000..cfb3385
--- /dev/null
+++ b/application/admin/view/deepseek/stream/edit.html
@@ -0,0 +1,71 @@
+
diff --git a/application/admin/view/deepseek/stream/index.html b/application/admin/view/deepseek/stream/index.html
new file mode 100644
index 0000000..606e5ab
--- /dev/null
+++ b/application/admin/view/deepseek/stream/index.html
@@ -0,0 +1,29 @@
+
+ {:build_heading()}
+
+
+
diff --git a/application/api/controller/deepseek/Deepseek.php b/application/api/controller/deepseek/Deepseek.php
new file mode 100644
index 0000000..031dc7c
--- /dev/null
+++ b/application/api/controller/deepseek/Deepseek.php
@@ -0,0 +1,239 @@
+model = new Question();
+ $this->listmodel = new Stream();
+ parent::_initialize();
+
+ //判断登录用户是否是员工
+
+ }
+
+
+ /**
+ * @ApiTitle(deepseek提问)
+ * @ApiSummary(deepseek提问)
+ * @ApiMethod(POST)
+ * @ApiParams(name = "messages", type = "string",required=true,description = "提问数组 {'role': 'user', 'content': '中原算力是一个什么样的公司'},{'role': 'assistant', 'content': ''} ")
+ * @ApiParams(name = "key", type = "string",required=true,description = "单次提问唯一key")
+ * @ApiParams(name = "session_key", type = "string",required=false,description = "会话唯一key:不传默认取当前日期")
+ * @ApiReturn({
+
+ *
+ *})
+ */
+ public function question(){
+
+ $this->setUrlLock("all","deepseek-question");
+
+ $messages = $this->request->post('messages/s',"");
+ $messages = htmlspecialchars_decode($messages);
+ $key = $this->request->post('key/s',"");
+ $session_key = $this->request->post('session_key/s',"");
+ //不传默认取当前日期
+ if(!$session_key) $session_key = date("Ymd");
+// $messages = "[{'role': 'user', 'content': '中原算力是一个什么样的公司'},{'role': 'assistant', 'content': ''}]";
+// var_dump($messages);
+ $user_id = 0;
+ $user = $this->auth->getUser();//登录用户
+ if($user)$user_id = $user['id'];
+// if(empty($id)){
+// $this->error(__('缺少必要参数'));
+// }
+
+ try {
+ $res = $this->model->question($messages,$user_id,$key,$session_key,false);
+ } catch (\Exception $e){
+// Log::log($e->getMessage());
+ $this->error($e->getMessage(),['errcode'=>$e->getCode()]);
+ }
+ $this->success('请求成功,请求结果请轮询查询结果接口', ['detail' => $res]);
+ }
+
+
+
+
+ /**
+ * @ApiTitle( 输出结果查询接口-list为空数组为在思考中)
+ * @ApiSummary(输出结果查询接口)
+ * @ApiMethod(GET)
+ * @ApiParams(name = "key", type = "string",required=false,description = "提问时自定义的key或提问id")
+ * @ApiParams(name = "page", type = "string",required=true,description = "页数")
+ * @ApiParams(name = "limit", type = "string",required=true,description = "条数")
+ * @ApiParams(name = "session_key", type = "string",required=false,description = "会话id")
+ * @ApiReturn({
+ *
+ *})
+ */
+ public function answer_list()
+ {
+ $user_id = 0;
+ $user = $this->auth->getUser();//登录用户
+ if($user)$user_id = $user['id'];
+
+ $params = [];
+ $my = $this->request->get('my/d', 0); //我的评价
+ if($my && $user_id){
+ $params['user_id'] = $user_id;
+ }
+ $page = $this->request->get('page/d', 1); //页数
+ $limit = $this->request->get('limit/d', 10); //条数
+ $params["key"] = $this->request->get('key/s', ''); //搜索关键字
+ $params["session_key"] = $this->request->get('session_key/s', ''); //搜索关键字
+
+
+ try{
+ //当前申请状态
+ $res = $this->listmodel::answerList($page, $limit,$params);
+// if($user_id =='670153'){
+// file_put_contents("ceshi66.txt",(new AppointmentOrder())->getLastSql());
+// }
+ }catch (\Exception $e){
+
+ $this->error($e->getMessage());
+ }
+ $this->success('查询成功', $res);
+ }
+
+
+
+ /**
+ * @ApiTitle( 查询我的所有会话)
+ * @ApiSummary(查询我的所有会话)
+ * @ApiMethod(GET)
+ * @ApiReturn({
+ *
+ *})
+ */
+ public function seesion_list()
+ {
+ $user_id = 0;
+ $user = $this->auth->getUser();//登录用户
+ if($user)$user_id = $user['id'];
+
+// $params = [];
+// $my = $this->request->get('my/d', 0); //我的评价
+// if($my && $user_id){
+// $params['user_id'] = $user_id;
+// }
+// $page = $this->request->get('page/d', 1); //页数
+// $limit = $this->request->get('limit/d', 1000); //条数
+// $params["key"] = $this->request->get('key/s', ''); //搜索关键字
+// $params["session_key"] = $this->request->get('session_key/s', ''); //搜索关键字
+
+
+ try{
+ //当前申请状态
+ $res = $this->model->getSeesionlist($user_id);
+// if($user_id =='670153'){
+// file_put_contents("ceshi66.txt",(new AppointmentOrder())->getLastSql());
+// }
+ }catch (\Exception $e){
+
+ $this->error($e->getMessage());
+ }
+ $this->success('查询成功', $res);
+ }
+
+
+
+
+
+ /**
+ * @ApiTitle( 提问记录记录)
+ * @ApiSummary(提问记录)
+ * @ApiMethod(GET)
+ * @ApiParams(name = "page", type = "string",required=true,description = "页数")
+ * @ApiParams(name = "limit", type = "string",required=true,description = "条数")
+ * @ApiParams(name = "session_key", type = "string",required=false,description = "会话id")
+ * @ApiReturn({
+ *
+ *})
+ */
+ public function question_list()
+ {
+ $user_id = 0;
+ $user = $this->auth->getUser();//登录用户
+ if($user)$user_id = $user['id'];
+
+ $params = [];
+// $my = $this->request->get('my/d', 0); //我的评价
+ if($user_id){
+ $params['user_id'] = $user_id;
+ }
+ $page = $this->request->get('page/d', 1); //页数
+ $limit = $this->request->get('limit/d', 10); //条数
+ $params["session_key"] = $this->request->get('session_key/s', ''); //搜索关键字
+
+
+ try{
+ //当前申请状态
+ $res = $this->model::questionList($page, $limit,$params);
+// if($user_id =='670153'){
+// file_put_contents("ceshi66.txt",(new AppointmentOrder())->getLastSql());
+// }
+ }catch (\Exception $e){
+
+ $this->error($e->getMessage());
+ }
+ $this->success('查询成功', $res);
+ }
+
+
+
+
+
+ /**
+ * @ApiTitle( 删除会话)
+ * @ApiSummary(删除会话)
+ * @ApiMethod(GET)
+ * @ApiParams(name = "session_key", type = "string",required=false,description = "会话id")
+ * @ApiReturn({
+ *
+ *})
+ */
+ public function delete_session()
+ { $user_id = 0;
+ $user = $this->auth->getUser();//登录用户
+ if($user)$user_id = $user['id'];
+
+ $session_key = $this->request->get('session_key/s', ''); //搜索关键字
+
+
+ try{
+ //当前申请状态
+ $res = $this->model->session_del($session_key,true);
+// if($user_id =='670153'){
+// file_put_contents("ceshi66.txt",(new AppointmentOrder())->getLastSql());
+// }
+ }catch (\Exception $e){
+
+ $this->error($e->getMessage());
+ }
+ $this->success('查询成功', $res);
+
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/application/common/controller/Api.php b/application/common/controller/Api.php
index f685ca2..dbaa983 100644
--- a/application/common/controller/Api.php
+++ b/application/common/controller/Api.php
@@ -86,6 +86,33 @@ class Api
}
}
+
+ protected $needUrlLock = [];
+
+ protected function setUrlLock($url_key="",$url_suffix="",$model=null){
+ if(($this->request->isPost() || (!empty($this->needUrlLock) && in_array($this->request->action(),$this->needUrlLock))) && (!empty($this->model) || $model)){
+ $user_id = 0;
+ $user = $this->auth->getUser();//登录用户
+ if($user)$user_id = $user['id'];
+
+ $modulename = $this->request->module();
+ $controllername = Loader::parseName($this->request->controller());
+ $actionname = strtolower($this->request->action());
+ $path = $modulename . '/' . str_replace('.', '/', $controllername) . '/' . $actionname;
+ if(!$model){
+ $this->model::$url_lock_key = $url_key ?: $user_id;
+ $this->model::$url_lock_suffix = $url_suffix ?: $path."lock-suffix";
+ $this->model::$url_lock = true;
+ }else{
+ $model::$url_lock_key = $url_key ?: $user_id;
+ $model::$url_lock_suffix = $url_suffix ?: $path."lock-suffix";
+ $model::$url_lock = true;
+ }
+
+ }
+ }
+
+
/**
* 初始化操作
* @access protected
diff --git a/application/common/controller/Backend.php b/application/common/controller/Backend.php
index 3963be4..5355aa4 100644
--- a/application/common/controller/Backend.php
+++ b/application/common/controller/Backend.php
@@ -3,6 +3,7 @@
namespace app\common\controller;
use app\admin\library\Auth;
+use app\admin\model\Admin;
use think\Config;
use think\Controller;
use think\Hook;
@@ -114,6 +115,75 @@ class Backend extends Controller
*/
use \app\admin\library\traits\Backend;
+ protected $qSwitch = false;
+ protected $qFields = [];
+
+ protected function checkAssemblyParameters(){
+ if(!$this->qSwitch)return false;
+ //得到所有get参数
+ $get = $this->request->get();
+ //得到当前model所有字段
+
+
+ $fields = $this->model->getTableFields();
+
+// $commonFields = (new Field())->getCommonFields();
+// var_dump($commonFields);
+ $fieldLists = $fields;
+// foreach ($commonFields as $commonField) {
+// if (!in_array($commonField['column_name'], $fields)) {
+// $fieldLists[] = $commonField;
+// }
+// }
+ $q_fields = [];
+
+ foreach ($get as $kay=>$getField) {
+ if (in_array($kay, $fieldLists)) {
+ $q_fields[$kay] = $getField;
+ }
+ }
+
+
+ //将q_fields塞入模板中
+ foreach ($q_fields as $k=>$v) {
+ //渲染站点配置
+ $this->assign('q_'.$k, $v);
+ }
+
+ foreach ($this->qFields as $k) {
+ //渲染站点配置
+ if(!isset($q_fields[$k]))$this->assign('q_'.$k, "");
+ }
+
+
+ }
+
+ protected $needUrlLock = [];
+
+ public function setUrlLock($url_key="",$url_suffix="",$model=null){
+ if(($this->request->isPost() || (!empty($this->needUrlLock) && in_array($this->request->action(),$this->needUrlLock))) && (!empty($this->model) || $model)){
+ $user_id = $this->auth->id ?? 0;
+// $user = $this->auth->getUser();//登录用户
+// if($user)$user_id = $user['id'];
+
+ $modulename = $this->request->module();
+ $controllername = Loader::parseName($this->request->controller());
+ $actionname = strtolower($this->request->action());
+ $path = $modulename . '/' . str_replace('.', '/', $controllername) . '/' . $actionname;
+ if(!$model){
+ $this->model::$url_lock_key = $url_key ?: $user_id;
+ $this->model::$url_lock_suffix = $url_suffix ?: $path."lock-suffix";
+ $this->model::$url_lock = true;
+ }else{
+ $model::$url_lock_key = $url_key ?: $user_id;
+ $model::$url_lock_suffix = $url_suffix ?: $path."lock-suffix";
+ $model::$url_lock = true;
+ }
+
+ }
+ }
+
+
public function _initialize()
{
$modulename = $this->request->module();
@@ -228,6 +298,8 @@ class Backend extends Controller
$this->assign('auth', $this->auth);
//渲染管理员对象
$this->assign('admin', Session::get('admin'));
+
+ $this->checkAssemblyParameters();
}
/**
@@ -259,7 +331,7 @@ class Backend extends Controller
* @param boolean $relationSearch 是否关联查询
* @return array
*/
- protected function buildparams($searchfields = null, $relationSearch = null)
+ protected function buildparams($searchfields = null, $relationSearch = null,$excludefields = [])
{
$searchfields = is_null($searchfields) ? $this->searchFields : $searchfields;
$relationSearch = is_null($relationSearch) ? $this->relationSearch : $relationSearch;
@@ -281,6 +353,7 @@ class Backend extends Controller
$op = (array)json_decode($op, true);
$filter = $filter ? $filter : [];
$where = [];
+ $excludearray = [];
$alias = [];
$bind = [];
$name = '';
@@ -314,6 +387,19 @@ class Backend extends Controller
continue;
}
$sym = $op[$k] ?? '=';
+ //忽略的查询条件出现在忽略数组中 2022年9月6日18:55:17
+ if(in_array($k, $excludefields)){
+ $excludearray[$k]['value'] = $v;
+ $excludearray[$k]['op'] = $sym;
+
+ if (stripos($k, ".") === false) {
+ $excludearray[$k]['alias'] = $aliasName;
+ }
+ unset($filter[$k]);
+ unset($op[$k]);
+ continue;
+ }
+
if (stripos($k, ".") === false) {
$k = $aliasName . $k;
}
@@ -368,8 +454,8 @@ class Backend extends Controller
case 'NOT BETWEEN':
$arr = array_slice(explode(',', $v), 0, 2);
if (stripos($v, ',') === false || !array_filter($arr, function ($v) {
- return $v != '' && $v !== false && $v !== null;
- })) {
+ return $v != '' && $v !== false && $v !== null;
+ })) {
continue 2;
}
//当出现一边为空时改变操作符
@@ -434,7 +520,7 @@ class Backend extends Controller
}
}
};
- return [$where, $sort, $order, $offset, $limit, $page, $alias, $bind];
+ return [$where, $sort, $order, $offset, $limit, $page, $alias, $bind,$excludearray];
}
/**
diff --git a/application/common/model/deepseek/Question.php b/application/common/model/deepseek/Question.php
new file mode 100644
index 0000000..1218e06
--- /dev/null
+++ b/application/common/model/deepseek/Question.php
@@ -0,0 +1,350 @@
+where('reasoning', 1)->order('created_time asc,reasoning desc,id asc')->column("content");
+ return implode("", $contents);
+ }
+
+ public function getAnswerTextAttr($value, $data)
+ {
+ $value = $value ? $value : (isset($data['id']) ? $data['id'] : '');
+ $contents = Stream::where('question_id', $value)->where('reasoning', 0)->order('created_time asc,reasoning desc,id asc')->column("content");
+ return implode("", $contents);
+ }
+
+
+
+
+ public function getEndtimeTextAttr($value, $data)
+ {
+ $value = $value ? $value : (isset($data['endtime']) ? $data['endtime'] : '');
+ return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
+ }
+
+ protected function setEndtimeAttr($value)
+ {
+ return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value);
+ }
+
+
+ public function user()
+ {
+ return $this->belongsTo('app\common\model\User', 'user_id', 'id', [], 'LEFT')->setEagerlyType(0);
+ }
+
+
+ public function question($messages, $user_id, $key,$session_key,$trans = false)
+ {
+ if (!$messages) throw new \Exception('缺少必要参数1');
+ if (!$key) throw new \Exception('缺少必要参数2');
+
+ $self = self::where('key', $key)->find();
+ if($self) throw new \Exception('key已被消耗');
+ //解析json成属数组
+ $messages = json_decode($messages, true);
+ if (!$messages) throw new \Exception('json解析失败');
+ //messages的json格式为{"role": "user", "content": "中原算力是一个什么样的公司"},{"role": "assistant", "content": ""}
+ //messages得到最后一个role名为assistant的对象并向上一个role为user的对象
+
+ //得到官网请求地址
+ $deepseek_web_url = config("site.deepseek_web_url");
+ //得到官网请求密钥
+ $deepseek_key = "Bearer " . config("site.deepseek_key");
+ //得到本地部署的请求地址
+ $deepseek_local_url = config("site.deepseek_local_url");
+ //得到切换开关
+ $deepseek_switch = config("site.deepseek_switch");
+ $reasoning =true;
+ $last = end($messages);
+ if ($last['role'] == 'assistant') {
+ $last = prev($messages);
+ if ($last['role'] != 'user') {
+ throw new \Exception('messages参数错误!');
+ }
+ }
+
+ //访问deepseek脚本存在超时可能会超时,所以需要设置超时时间为10分钟
+ set_time_limit(6000);
+
+ //组转json请求参数准备请求deepseekapi :{
+ //"model": "qwen",
+ //"messages": [
+ //{"role": "user", "content": "中原算力是一个什么样的公司"},{"role": "assistant", "content": ""}
+ //],
+ //"stream": true,
+ //"temperature":0.6
+ //}
+ $data = [
+ 'model' => $deepseek_switch ? 'qwen':'deepseek-reasoner',
+ 'messages' => $messages,
+ 'stream' => true,
+ 'temperature' => 0.6,
+ ];
+
+// var_dump($data);die;
+
+
+
+ //判断逻辑
+ if ($trans) {
+ self::beginTrans();
+ }
+ $res = true;
+ try {
+
+ //保存本次请求model
+ $datas = [
+ 'user_id' => $user_id,
+ 'content' => $last["content"],
+ "key"=>$key,
+ "session_key" => $session_key,
+ ];
+ //保存数据库并得自增id
+ $self = self::create($datas);
+// var_dump($self);die;
+ $question_id = $self->id;
+
+
+ // 判断逻辑
+ $url = $deepseek_switch ? $deepseek_local_url : $deepseek_web_url;
+ $headers = $deepseek_switch ? [] : ['Authorization:' . $deepseek_key];
+
+
+ // 发送curl post json格式的 stream式请求
+ $ch = curl_init();
+ curl_setopt($ch, CURLOPT_URL, $url);
+ curl_setopt($ch, CURLOPT_POST, 1);
+ curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
+ curl_setopt($ch, CURLOPT_HTTPHEADER, array_merge(['Content-Type: application/json'], $headers));
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, false);
+ curl_setopt($ch, CURLOPT_WRITEFUNCTION, function ($ch, $data) use (&$response,$question_id,$deepseek_switch,&$reasoning,$session_key) {
+// var_dump($data);
+
+ if (!$data) {
+ return 0; // 结束流式请求
+ }
+
+// var_dump($data);
+ $data = htmlspecialchars_decode($data);
+ // 处理每一部分数据
+// $lines = explode("\n", trim($data));
+ $lines = explode("\n",$data);
+ foreach ($lines as $line) {
+ if (strpos($line, "data: ") === 0) {
+ $json = substr($line, 6);
+ $chunk = json_decode($json, true);
+
+
+ if (isset($chunk['choices'][0]['delta']['reasoning_content'])) {
+ $chunk['choices'][0]['delta']['reasoning_content'] = htmlspecialchars_decode($chunk['choices'][0]['delta']['reasoning_content']);
+
+ // 将数据写入数据库
+ // 假设有一个方法 saveStreamData 用于保存数据
+ $this->saveStreamData($chunk['choices'][0]['delta']['reasoning_content'],$chunk,$question_id,true,$session_key);
+ }
+
+ if (isset($chunk['choices'][0]['delta']['content'])) {
+
+ $chunk['choices'][0]['delta']['content'] = htmlspecialchars_decode($chunk['choices'][0]['delta']['content']);
+
+ if($deepseek_switch){
+ //本地部署为结尾
+ if(strpos($chunk['choices'][0]['delta']['content'],'')!==false){
+ $reasoning = false;
+ }else{
+ $this->saveStreamData($chunk['choices'][0]['delta']['content'],$chunk,$question_id,$reasoning,$session_key);
+ }
+
+ }else{
+ //官方调用
+
+
+ // 将数据写入数据库
+ // 假设有一个方法 saveStreamData 用于保存数据
+ $this->saveStreamData($chunk['choices'][0]['delta']['content'],$chunk,$question_id,false,$session_key);
+
+
+ }
+
+ }
+ }
+ }
+
+ // 处理每一部分数据
+// $json = $data;
+// $chunk = json_decode($json, true);
+// if (isset($chunk['choices'][0]['delta']['content'])) {
+// // 将数据写入数据库
+// // 假设有一个方法 saveStreamData 用于保存数据
+// $this->saveStreamData($chunk['choices'][0]['delta']['content'],$chunk,$question_id);
+// }
+
+ return strlen($data);
+ });
+
+ curl_exec($ch);
+ $curl_error = curl_error($ch);
+ curl_close($ch);
+
+ if ($curl_error) {
+ throw new \Exception('Curl error: ' . $curl_error);
+ }
+
+
+
+ if ($trans) {
+ self::commitTrans();
+ }
+ } catch (\Exception $e) {
+ if ($trans) {
+ self::rollbackTrans();
+ }
+ throw new \Exception($e->getMessage() . $e->getFile() . $e->getLine());
+ }
+ return $res;
+ }
+
+ // 假设有一个方法 saveStreamData 用于保存数据
+ protected function saveStreamData($content,$chunk,$question_id,$reasoning = false,$session_key)
+ {
+ // 实现保存数据到数据库的逻辑
+ $data = [
+ 'question_id' => $question_id,
+ 'assistant_id' => $chunk["id"],
+ 'object' => $chunk["object"],
+ "created_time" => $chunk["created"],
+ "model" => $chunk["model"],
+ "usage_json" => isset($chunk["usage"])? htmlspecialchars_decode(json_encode( $chunk["usage"])) : '',
+ "choices_json" => isset($chunk["choices"])? htmlspecialchars_decode(json_encode($chunk["choices"])): '',
+ "content" => $content,
+ "reasoning" => $reasoning,
+ "session_key" =>$session_key
+ ];
+ Stream::create($data);
+
+ }
+
+
+ public function getSeesionlist($user_id=0){
+ //用当前模型查询问题qusetion列表,返回每个会话session_key下的最后一个问题,组成列表返回
+ $list = self::where("user_id",$user_id)->group("session_key")->order("createtime desc")->select();
+ return $list;
+ }
+
+
+
+ /**得到基础条件
+ * @param $status
+ * @param null $model
+ * @param string $alisa
+ */
+ public static function getBaseWhere($whereData = [], $model = null, $alisa = '',$with = false)
+ {
+
+ if (!$model) {
+ $model = new static;
+ if ($alisa&&!$with) $model = $model->alias($alisa);
+ }
+ if ($alisa) $alisa = $alisa . '.';
+ $tableFields = (new static)->getTableFields();
+ foreach ($tableFields as $fields)
+ {
+// if(in_array($fields, ['key']))continue;
+// if (isset($whereData[$fields]) && $whereData[$fields]) $model = $model->where("{$alisa}{$fields}", '=', $whereData[$fields]);
+
+ if (isset($whereData[$fields]) && $whereData[$fields]){
+ if(is_array($whereData[$fields])){
+ $model = $model->where("{$alisa}{$fields}", $whereData[$fields][0], $whereData[$fields][1]);
+ }else{
+ $model = $model->where("{$alisa}{$fields}", '=', $whereData[$fields]);
+ }
+
+ }
+
+
+ }
+
+ if (isset($whereData['time'])&&$whereData['time']){
+ $model = $model->time(["{$alisa}createtime",$whereData['time']]);
+ }
+
+
+
+
+ return $model;
+ }
+
+
+ public static function questionList($page, $limit,$params=[]){
+ $with_field = [
+ 'base'=>['*'],
+ ];
+// $alisa = (new self)->getWithAlisaName();
+ $sort = "id asc";
+ $serch_where = [];
+ $serch_where = array_merge($serch_where,$params);
+ return (new self)->getBaseList($serch_where, $page, $limit,$sort,$with_field);
+ }
+
+
+
+ public function session_del($session_key,$trans=false){
+//判断逻辑
+ if($trans){
+ self::beginTrans();
+ }
+ $res = true;
+ try{
+ //根据session_key删除问题
+ $question_list = self::where("session_key",$session_key)->delete();
+ //根据session_key删除stream
+ $stream_list = Stream::where("session_key",$session_key)->delete();
+
+ if($trans){
+ self::commitTrans();
+ }
+ }catch (\Exception $e){
+ if($trans){
+ self::rollbackTrans();
+ }
+ throw new \Exception($e->getMessage().$e->getFile().$e->getLine());
+ }
+ return $res;
+ }
+
+}
diff --git a/application/common/model/deepseek/Stream.php b/application/common/model/deepseek/Stream.php
new file mode 100644
index 0000000..db46894
--- /dev/null
+++ b/application/common/model/deepseek/Stream.php
@@ -0,0 +1,133 @@
+belongsTo('Question', 'question_id', 'id', [], 'LEFT')->setEagerlyType(0);
+ }
+
+
+ public function getUsageJsonAttr($value, $data)
+ {
+ return $value === '' ? [] : json_decode($value, true);
+ }
+
+
+ public function getChoicesJsonAttr($value, $data)
+ {
+ return $value === '' ? [] : json_decode($value, true);
+ }
+
+
+
+
+
+ /**得到基础条件
+ * @param $status
+ * @param null $model
+ * @param string $alisa
+ */
+ public static function getBaseWhere($whereData = [], $model = null, $alisa = '',$with = false)
+ {
+
+ if (!$model) {
+ $model = new static;
+ if ($alisa&&!$with) $model = $model->alias($alisa);
+ }
+ if ($alisa) $alisa = $alisa . '.';
+ $tableFields = (new static)->getTableFields();
+ foreach ($tableFields as $fields)
+ {
+ if(in_array($fields, ['key']))continue;
+// if (isset($whereData[$fields]) && $whereData[$fields]) $model = $model->where("{$alisa}{$fields}", '=', $whereData[$fields]);
+
+ if (isset($whereData[$fields]) && $whereData[$fields]){
+ if(is_array($whereData[$fields])){
+ $model = $model->where("{$alisa}{$fields}", $whereData[$fields][0], $whereData[$fields][1]);
+ }else{
+ $model = $model->where("{$alisa}{$fields}", '=', $whereData[$fields]);
+ }
+
+ }
+
+
+ }
+
+
+ if (isset($whereData['key'])&&$whereData['key']){
+ $question = Question::where("id|key", '=', $whereData['key'])->find();
+ if(!$question){
+ $model = $model->where("{$alisa}question_id", '=', -1);
+ }else{
+ $model = $model->where("{$alisa}question_id", '=', $question["id"]);
+ }
+
+ }
+ if (isset($whereData['time'])&&$whereData['time']){
+ $model = $model->time(["{$alisa}created_time",$whereData['time']]);
+ }
+
+
+
+
+ return $model;
+ }
+
+
+ public static function answerList($page, $limit,$params=[]){
+ $with_field = [
+ 'base'=>['*'],
+ ];
+// $alisa = (new self)->getWithAlisaName();
+ $sort = "created_time asc,reasoning desc,id asc";
+ $serch_where = [];
+ $serch_where = array_merge($serch_where,$params);
+ return (new self)->getBaseList($serch_where, $page, $limit,$sort,$with_field);
+ }
+
+}
diff --git a/application/config.php b/application/config.php
index 86da54d..4ac7cd6 100644
--- a/application/config.php
+++ b/application/config.php
@@ -18,7 +18,7 @@ return [
// 应用命名空间
'app_namespace' => 'app',
// 应用调试模式
- 'app_debug' => Env::get('app.debug', false),
+ 'app_debug' => Env::get('app.debug', true),
// 应用Trace
'app_trace' => Env::get('app.trace', false),
// 应用模式状态
@@ -159,7 +159,7 @@ return [
// 错误显示信息,非调试模式有效
'error_message' => '你所浏览的页面暂时无法访问',
// 显示错误信息
- 'show_error_msg' => false,
+ 'show_error_msg' => true,
// 异常处理handle类 留空使用 \think\exception\Handle
'exception_handle' => '',
// +----------------------------------------------------------------------
@@ -306,4 +306,13 @@ return [
//API接口地址
'api_url' => 'https://api.fastadmin.net',
],
+ //增加 redis 配置
+ 'redis' => [
+ 'host' => '127.0.0.1', // redis 主机地址
+ 'password' => '', // redis 密码
+ 'port' => 6379, // redis 端口
+ 'select' => 3, // redis 数据库
+ 'timeout' => 0, // redis 超时时间
+ 'persistent' => false, // redis 持续性,连接复用
+ ]
];
diff --git a/public/assets/js/backend/deepseek/question.js b/public/assets/js/backend/deepseek/question.js
new file mode 100644
index 0000000..d0612ee
--- /dev/null
+++ b/public/assets/js/backend/deepseek/question.js
@@ -0,0 +1,57 @@
+define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) {
+
+ var Controller = {
+ index: function () {
+ // 初始化表格参数配置
+ Table.api.init({
+ extend: {
+ index_url: 'deepseek/question/index' + location.search,
+ add_url: 'deepseek/question/add',
+ edit_url: 'deepseek/question/edit',
+ del_url: 'deepseek/question/del',
+ multi_url: 'deepseek/question/multi',
+ import_url: 'deepseek/question/import',
+ table: 'deepseek_question',
+ }
+ });
+
+ var table = $("#table");
+
+ // 初始化表格
+ table.bootstrapTable({
+ url: $.fn.bootstrapTable.defaults.extend.index_url,
+ pk: 'id',
+ sortName: 'id',
+ columns: [
+ [
+ {checkbox: true},
+ {field: 'id', title: __('Id')},
+ {field: 'user_id', title: __('User_id')},
+ {field: 'content', title: __('Content'), operate: 'LIKE', table: table, class: 'autocontent', formatter: Table.api.formatter.content},
+ {field: 'createtime', title: __('Createtime'), operate:'RANGE', addclass:'datetimerange', autocomplete:false, formatter: Table.api.formatter.datetime},
+ {field: 'endtime', title: __('Endtime'), operate:'RANGE', addclass:'datetimerange', autocomplete:false, formatter: Table.api.formatter.datetime},
+ {field: 'user.nickname', title: __('User.nickname'), operate: 'LIKE'},
+ {field: 'user.mobile', title: __('User.mobile'), operate: 'LIKE'},
+ {field: 'user.avatar', title: __('User.avatar'), operate: 'LIKE', events: Table.api.events.image, formatter: Table.api.formatter.image},
+ {field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate}
+ ]
+ ]
+ });
+
+ // 为表格绑定事件
+ Table.api.bindevent(table);
+ },
+ add: function () {
+ Controller.api.bindevent();
+ },
+ edit: function () {
+ Controller.api.bindevent();
+ },
+ api: {
+ bindevent: function () {
+ Form.api.bindevent($("form[role=form]"));
+ }
+ }
+ };
+ return Controller;
+});
diff --git a/public/assets/js/backend/deepseek/stream.js b/public/assets/js/backend/deepseek/stream.js
new file mode 100644
index 0000000..ccafd70
--- /dev/null
+++ b/public/assets/js/backend/deepseek/stream.js
@@ -0,0 +1,58 @@
+define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) {
+
+ var Controller = {
+ index: function () {
+ // 初始化表格参数配置
+ Table.api.init({
+ extend: {
+ index_url: 'deepseek/stream/index' + location.search,
+ add_url: 'deepseek/stream/add',
+ edit_url: 'deepseek/stream/edit',
+ del_url: 'deepseek/stream/del',
+ multi_url: 'deepseek/stream/multi',
+ import_url: 'deepseek/stream/import',
+ table: 'deepseek_stream',
+ }
+ });
+
+ var table = $("#table");
+
+ // 初始化表格
+ table.bootstrapTable({
+ url: $.fn.bootstrapTable.defaults.extend.index_url,
+ pk: 'id',
+ sortName: 'id',
+ columns: [
+ [
+ {checkbox: true},
+ {field: 'id', title: __('Id')},
+ {field: 'question_id', title: __('Question_id')},
+ {field: 'assistant_id', title: __('Assistant_id'), operate: 'LIKE', table: table, class: 'autocontent', formatter: Table.api.formatter.content},
+ {field: 'object', title: __('Object'), operate: 'LIKE', table: table, class: 'autocontent', formatter: Table.api.formatter.content},
+ {field: 'created_time', title: __('Created_time'), operate:'RANGE', addclass:'datetimerange', autocomplete:false, formatter: Table.api.formatter.datetime},
+ {field: 'model', title: __('Model'), operate: 'LIKE', table: table, class: 'autocontent', formatter: Table.api.formatter.content},
+ {field: 'createtime', title: __('Createtime'), operate:'RANGE', addclass:'datetimerange', autocomplete:false, formatter: Table.api.formatter.datetime},
+ {field: 'question.user_id', title: __('Question.user_id')},
+ {field: 'question.content', title: __('Question.content'), operate: 'LIKE', table: table, class: 'autocontent', formatter: Table.api.formatter.content},
+ {field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate}
+ ]
+ ]
+ });
+
+ // 为表格绑定事件
+ Table.api.bindevent(table);
+ },
+ add: function () {
+ Controller.api.bindevent();
+ },
+ edit: function () {
+ Controller.api.bindevent();
+ },
+ api: {
+ bindevent: function () {
+ Form.api.bindevent($("form[role=form]"));
+ }
+ }
+ };
+ return Controller;
+});