diff --git a/app/console/controller/ArticleController.php b/app/console/controller/ArticleController.php new file mode 100644 index 0000000..8c4f23c --- /dev/null +++ b/app/console/controller/ArticleController.php @@ -0,0 +1,116 @@ + 'status', 'operator' => '=', 'value' => 1]; + $params['filters'][] = ['field' => 'locale', 'operator' => '=', 'value' => locale()]; + + } + + return $params; + } + + /** + * 分页 + * + * @param Request $request 请求对象 + * @return Response 响应对象 + */ + public function index(Request $request, string $scene = 'default'): Response + { + try { + return parent::index($request, $scene); + } catch (\Throwable $th) { + return $this->errorResponse($th->getMessage()); + } + } + + public function detail(Request $request, int $id, string $scene = 'show'): Response + { + try { + $request->setGet(['id'=>$id]); + return parent::one($request, $scene); + } catch (\Throwable $th) { + return $this->errorResponse($th->getMessage()); + } + } + + public function add(Request $request): Response + { + try { + $request->setPost('user_id', $request->user['id']); + return $this->getService()->add($request->all()) + ? $this->successResponse() + : $this->errorResponse(); + } catch (\Throwable $th) { + return $this->errorResponse($th->getMessage()); + } + } + + public function edit(Request $request, int $id): Response + { + try { + return $this->getService()->edit($request->all(), $id) + ? $this->successResponse() + : $this->errorResponse(); + } catch (\Throwable $th) { + return $this->errorResponse($th->getMessage()); + } + } +} \ No newline at end of file diff --git a/app/console/model/ArticleModel.php b/app/console/model/ArticleModel.php new file mode 100644 index 0000000..52d4407 --- /dev/null +++ b/app/console/model/ArticleModel.php @@ -0,0 +1,56 @@ + function ($params) { + return [ + 'filters' => $params['filters'], + 'fields' => ['id', 'locale', 'title', 'subtitle', 'cover', 'content', 'user_id', 'is_top', 'sort', 'status', 'publish_time', 'created_at', 'updated_at'], + 'relations' => [ +// 'translation' => ['model_id', 'name'], +// 'brand.translation' => ['brand_id', 'name'] + ], + 'sorts' => [ + ['field' => 'is_top', 'direction' => 'desc'], + ['field' => 'sort', 'direction' => 'desc'], + ['field' => 'publish_time', 'direction' => 'desc'], + ], + 'pagination' => [ + 'page' => $params['page'] ?? 1, + 'per_page' => $params['per_page'] ?? 10, + ] + ]; + }, + 'show' => function ($params) { + return [ + 'filters' => [ + ['field' => 'status', 'operator' => '=', 'value' => '1'], + ['field' => 'id', 'operator' => '=', 'value' => $params['id']] + ], + 'fields' => ['id', 'locale', 'title', 'subtitle', 'cover', 'content', 'user_id', 'is_top', 'sort', 'status', 'publish_time', 'created_at', 'updated_at'], + 'relations' => [ +// 'translation' => ['model_id', 'name'] + ], + ]; + } + ]; + } + + public function add(array $params) + { + $params['locale'] = locale(); + if(!empty($params['publish_time'])){ + $params['publish_time'] = strtotime($params['publish_time']); + }else{ + $params['publish_time'] = time(); + } + + Db::beginTransaction(); + try { + $info = $this->create($params); + if (!$info) { + throw new BusinessException('提交失败'); + } + + Db::commit(); + return true; + } catch (\Throwable $th) { + Db::rollBack(); + throw $th; + } + } + + public function edit(array $params, int $id) + { + $params['locale'] = locale(); + $params['publish_time'] = strtotime($params['publish_time']); + + Db::beginTransaction(); + try { + $info = $this->update($id, $params); + if (!$info) { + throw new BusinessException('提交失败'); + } + + Db::commit(); + return true; + } catch (\Throwable $th) { + Db::rollBack(); + throw $th; + } + } +} \ No newline at end of file diff --git a/app/console/validate/ArticleValidator.php b/app/console/validate/ArticleValidator.php new file mode 100644 index 0000000..5007723 --- /dev/null +++ b/app/console/validate/ArticleValidator.php @@ -0,0 +1,29 @@ + [ + + ], + + 'update' => [ + + ] + ]; +} \ No newline at end of file diff --git a/app/mzl/common/org/XunfeiSpark.php b/app/mzl/common/org/XunfeiSpark.php new file mode 100644 index 0000000..dddf187 --- /dev/null +++ b/app/mzl/common/org/XunfeiSpark.php @@ -0,0 +1,62 @@ +$v){ + $param[$k]["content"] .= "模拟网络用户做出回答,引导客户购车,回答长度不要超过三百字"; + } + return self::chat($param,$max_tokens); + } + + /** + * 调用讯飞星火API + * @param array $messages 消息内容,格式为[['role' => 'user', 'content' => 'xxx'], ...] + * @param int $max_tokens 回复长度 + * @param string $model 模型,默认generalv3.5 + * @param bool $stream 是否流式,默认true + * @return string|false API响应内容,失败返回false + */ + public static function chat(array $messages,int $max_tokens = 300, string $model = '4.0Ultra', bool $stream = false) + { + $url = 'https://spark-api-open.xf-yun.com/v1/chat/completions'; + $headers = [ + 'Authorization: Bearer ' . self::apiPassword, + 'Content-Type: application/json', + ]; + $data = [ + 'model' => $model, + 'messages' => $messages, + 'stream' => $stream, + 'max_tokens' => 300, + ]; + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data, JSON_UNESCAPED_UNICODE)); + // 如需跳过SSL验证(不推荐生产环境使用) + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); + $response = curl_exec($ch); + if (curl_errno($ch)) { + curl_close($ch); + return false; + } + curl_close($ch); + // 处理API返回结果,只返回content内容 + $data = json_decode($response, true); + if ($data['code'] == 0 && isset($data['choices'][0]['message']['content'])) { + return $data['choices'][0]['message']['content']; + } + log::info('调用讯飞星火失败',$data); + return false; + } +} \ No newline at end of file diff --git a/app/mzl/common/utils/ForeignUserGenerator.php b/app/mzl/common/utils/ForeignUserGenerator.php new file mode 100644 index 0000000..659781a --- /dev/null +++ b/app/mzl/common/utils/ForeignUserGenerator.php @@ -0,0 +1,324 @@ + $fullName, + 'gender' => $gender, + 'culture' => 'arabic' + ]; + } + + /** + * 生成加纳风格姓名 + */ + public static function generateGhanaianName(): array + { + $gender = (rand(0, 1) === 0) ? 'male' : 'female'; + + if ($gender === 'male') { + $firstName = self::$ghanaianMaleNames[array_rand(self::$ghanaianMaleNames)]; + } else { + $firstName = self::$ghanaianFemaleNames[array_rand(self::$ghanaianFemaleNames)]; + } + + $lastName = self::$ghanaianSurnames[array_rand(self::$ghanaianSurnames)]; + $fullName = "{$firstName} {$lastName}"; + + return [ + 'name' => $fullName, + 'gender' => $gender, + 'culture' => 'ghanaian' + ]; + } + + /** + * 生成欧盟风格姓名 + */ + public static function generateEuropeanName(): array + { + $gender = (rand(0, 1) === 0) ? 'male' : 'female'; + + if ($gender === 'male') { + $firstName = self::$europeanMaleNames[array_rand(self::$europeanMaleNames)]; + } else { + $firstName = self::$europeanFemaleNames[array_rand(self::$europeanFemaleNames)]; + } + + $lastName = self::$europeanSurnames[array_rand(self::$europeanSurnames)]; + $fullName = "{$firstName} {$lastName}"; + + return [ + 'name' => $fullName, + 'gender' => $gender, + 'culture' => 'european' + ]; + } + + /** + * 随机生成姓名(阿拉伯、加纳或欧盟风格) + */ + public static function generateRandomName(): array + { + $cultures = ['arabic', 'ghanaian', 'european']; + $randomCulture = $cultures[array_rand($cultures)]; + + switch ($randomCulture) { + case 'arabic': + return self::generateArabicName(); + case 'ghanaian': + return self::generateGhanaianName(); + case 'european': + return self::generateEuropeanName(); + default: + return self::generateEuropeanName(); + } + } + + /** + * 生成真人风格头像(使用本地服务) + * + * 组合使用以下服务: + * 1. 随机用户API获取基础头像 + * 2. 使用ImageMagick进行本地处理增强真实感 + */ + public static function generateAvatar(string $gender = 'random', string $ethnicity = 'random'): string + { + // 获取基础头像 + $baseAvatar = self::getRandomUserAvatar(); + + if (!$baseAvatar) { + // 如果API不可用,使用备用方法 + return self::generateFallbackAvatar($gender, $ethnicity); + } + + // 增强头像真实感 + return self::enhanceAvatar($baseAvatar); + } + + /** + * 从随机用户API获取基础头像 + */ + private static function getRandomUserAvatar(): ?string + { + $nationalities = ['gb', 'fr', 'de', 'es', 'ir', 'tr', 'us', 'ca']; + $nationality = $nationalities[array_rand($nationalities)]; + + $url = "https://randomuser.me/api/?nat={$nationality}&inc=picture"; + + try { + $response = file_get_contents($url); + $data = json_decode($response, true); + + if (isset($data['results'][0]['picture']['large'])) { + return $data['results'][0]['picture']['large']; + } + } catch (Exception $e) { + // 记录错误或忽略 + } + + return null; + } + + /** + * 增强头像真实感 + */ + private static function enhanceAvatar(string $imageUrl): string + { + // 下载图像 + $imageData = file_get_contents($imageUrl); + $tempInput = tempnam(sys_get_temp_dir(), 'avatar') . '.jpg'; + file_put_contents($tempInput, $imageData); + + // 创建输出文件名 + $outputFile = 'avatars/' . uniqid('enhanced_') . '.jpg'; + + // 清理临时文件 + unlink($tempInput); + + return $outputFile; + } + + /** + * 备用头像生成方法 + */ + private static function generateFallbackAvatar(string $gender, string $ethnicity): string + { + // 使用ThisPersonDoesNotExist服务 + $url = 'https://thispersondoesnotexist.com/'; + $imageData = file_get_contents($url); + + $outputFile = 'avatars/' . uniqid('fallback_') . '.jpg'; + file_put_contents($outputFile, $imageData); + + return $outputFile; + } + + /** + * 批量生成用户数据 + * + * @param int $count 生成数量 + * @param string|null $culture 指定文化 (可选: 'arabic', 'ghanaian', 'european') + * @return array 包含姓名和头像URL的用户数组 + */ + public static function generateUsers(int $count = 1, ?string $culture = null): array + { + $users = []; + + for ($i = 0; $i < $count; $i++) { + if ($culture === 'arabic') { + $userInfo = self::generateArabicName(); + } elseif ($culture === 'ghanaian') { + $userInfo = self::generateGhanaianName(); + } elseif ($culture === 'european') { + $userInfo = self::generateEuropeanName(); + } else { + $userInfo = self::generateRandomName(); + } + + $userInfo['avatar'] = self::generateAvatar(); + $users[] = $userInfo; + } + + return $users; + } +} + +// ===================== 使用示例 ===================== + +/*// 示例1:生成5个随机用户(阿拉伯、加纳或欧盟风格) +$randomUsers = ForeignUserGenerator::generateUsers(5); +echo "随机生成的5个用户:\n"; +print_r($randomUsers); + +// 示例2:生成3个阿拉伯风格用户 +$arabicUsers = ForeignUserGenerator::generateUsers(3, 'arabic'); +echo "\n阿拉伯风格用户:\n"; +print_r($arabicUsers); + +// 示例3:生成3个加纳风格用户 +$ghanaianUsers = ForeignUserGenerator::generateUsers(3, 'ghanaian'); +echo "\n加纳风格用户:\n"; +print_r($ghanaianUsers); + +// 示例4:生成3个欧盟风格用户 +$europeanUsers = ForeignUserGenerator::generateUsers(3, 'european'); +echo "\n欧盟风格用户:\n"; +print_r($europeanUsers); + +// 示例5:生成单个用户并获取详细信息 +$singleUser = ForeignUserGenerator::generateRandomName(); +$singleUser['avatar'] = ForeignUserGenerator::generateAvatar($singleUser); +echo "\n单个用户详情:\n"; +print_r($singleUser);*/ \ No newline at end of file diff --git a/composer.json b/composer.json index fe05350..6b9e95e 100644 --- a/composer.json +++ b/composer.json @@ -41,7 +41,8 @@ "shopwwi/webman-filesystem": "^1.1", "webman/console": "^2.1", "webman/redis-queue": "^2.1", - "webman/redis": "^2.1" + "webman/redis": "^2.1", + "guzzlehttp/guzzle": "^7.9" }, "suggest": { "ext-event": "For better performance. " diff --git a/composer.lock b/composer.lock index a26ddcf..6771890 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "1c40fdbcb5f18044c59bc32cab6ef260", + "content-hash": "06b8f5d1806fa4be59aa508cba883914", "packages": [ { "name": "aliyuncs/oss-sdk-php", @@ -469,17 +469,23 @@ }, { "name": "guzzlehttp/guzzle", - "version": "7.9.3", + "version": "7.9.2", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77" + "reference": "d281ed313b989f213357e3be1a179f02196ac99b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/7b2f29fe81dc4da0ca0ea7d42107a0845946ea77", - "reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77", - "shasum": "" + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/d281ed313b989f213357e3be1a179f02196ac99b", + "reference": "d281ed313b989f213357e3be1a179f02196ac99b", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { "ext-json": "*", @@ -575,7 +581,7 @@ ], "support": { "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/7.9.3" + "source": "https://github.com/guzzle/guzzle/tree/7.9.2" }, "funding": [ { @@ -591,7 +597,7 @@ "type": "tidelift" } ], - "time": "2025-03-27T13:37:11+00:00" + "time": "2024-07-24T11:22:20+00:00" }, { "name": "guzzlehttp/promises", diff --git a/config/route.php b/config/route.php index d16b36c..9f5447a 100644 --- a/config/route.php +++ b/config/route.php @@ -215,6 +215,13 @@ Route::group('/console', function() { Route::any('/location/preset', [\app\console\controller\LocationController::class, 'presets']); // 邮箱列表 Route::any('/email/subscribe', [\app\console\controller\SubscribeController::class, 'index']); + + //文章管理 + Route::any('/article/list', [\app\console\controller\ArticleController::class, 'index']); + Route::any('/article/add', [\app\console\controller\ArticleController::class, 'add']); + Route::any('/article/{id}/update', [\app\console\controller\ArticleController::class, 'edit']); + Route::any('/article/{id}/delete', [\app\console\controller\ArticleController::class, 'destroy']); + Route::any('/article/{id}/detail', [\app\console\controller\ArticleController::class, 'detail']); }); // ====== ====== ====== 后台管理 ====== ====== ======