130 lines
4.4 KiB
PHP
130 lines
4.4 KiB
PHP
<?php
|
||
|
||
namespace Plugins\Neatstudio\AiModeration\Filament\Pages;
|
||
|
||
use App\Models\Post;
|
||
use App\Models\Setting;
|
||
use Filament\Actions\Action;
|
||
use Filament\Forms\Components\Select;
|
||
use Filament\Forms\Components\Textarea;
|
||
use Filament\Forms\Components\TextInput;
|
||
use Filament\Forms\Components\Toggle;
|
||
use Filament\Forms\Concerns\InteractsWithForms;
|
||
use Filament\Notifications\Notification;
|
||
use Filament\Pages\Page;
|
||
use Filament\Schemas\Schema;
|
||
use Plugins\Neatstudio\AiModeration\Jobs\AiPolishContentJob;
|
||
|
||
class AiSettings extends Page
|
||
{
|
||
use InteractsWithForms;
|
||
|
||
protected static \UnitEnum|string|null $navigationGroup = '管理';
|
||
|
||
protected static string|\BackedEnum|null $navigationIcon = 'heroicon-o-sparkles';
|
||
|
||
protected static ?string $navigationLabel = 'AI 设置';
|
||
|
||
protected string $view = 'plugin.ai-moderation::ai-settings';
|
||
|
||
public array $data = [];
|
||
|
||
public ?string $polishPost = null;
|
||
|
||
public ?string $polishResult = null;
|
||
|
||
public function mount(): void
|
||
{
|
||
$this->form->fill([
|
||
'llm_base_url' => Setting::get('llm_base_url', env('LLM_BASE_URL')),
|
||
'llm_api_key' => Setting::get('llm_api_key', env('LLM_API_KEY')),
|
||
'llm_model' => Setting::get('llm_model', env('LLM_MODEL', 'gpt-4o-mini')),
|
||
'ai_moderation_enabled' => (int) Setting::get('ai_moderation_enabled', 1) === 1,
|
||
'ai_moderation_system_prompt' => Setting::get('ai_moderation_system_prompt', '你是博客评论审核员。判断评论是否包含:广告/垃圾、人身攻击、违法内容、无关灌水。只回复 JSON:{"verdict":"approved|rejected|spam","reason":"简短理由"}'),
|
||
]);
|
||
}
|
||
|
||
public function form(Schema $schema): Schema
|
||
{
|
||
return $schema
|
||
->components([
|
||
\Filament\Schemas\Components\Section::make('LLM 配置')
|
||
->description('OpenAI 兼容接口:OpenAI / DeepSeek / 通义 / 自建代理')
|
||
->schema([
|
||
TextInput::make('llm_base_url')->label('Base URL')->placeholder('https://api.openai.com/v1')->required(),
|
||
TextInput::make('llm_api_key')->label('API Key')->password()->required(),
|
||
TextInput::make('llm_model')->label('模型')->default('gpt-4o-mini')->required(),
|
||
]),
|
||
\Filament\Schemas\Components\Section::make('评论审核')
|
||
->schema([
|
||
Toggle::make('ai_moderation_enabled')->label('新评论启用 AI 自动审核'),
|
||
Textarea::make('ai_moderation_system_prompt')->label('审核提示词')->rows(4)->columnSpanFull(),
|
||
]),
|
||
])
|
||
->statePath('data');
|
||
}
|
||
|
||
public function save(): void
|
||
{
|
||
$data = $this->form->getState();
|
||
|
||
foreach ($data as $key => $value) {
|
||
Setting::set($key, is_bool($value) ? (string) (int) $value : (string) $value);
|
||
}
|
||
|
||
Notification::make()->title('AI 设置已保存')->success()->send();
|
||
}
|
||
|
||
public function polish(Post $post): void
|
||
{
|
||
$this->polishPost = (string) $post->id;
|
||
|
||
if ($post->meta['ai_polished'] ?? null) {
|
||
$this->polishResult = $post->meta['ai_polished'];
|
||
|
||
return;
|
||
}
|
||
|
||
dispatch(new AiPolishContentJob($post->id))->onQueue('ai');
|
||
Notification::make()->title('润色任务已提交(由 Workerman 异步执行)')->info()->send();
|
||
}
|
||
|
||
public function acceptPolish(Post $post): void
|
||
{
|
||
$polished = $post->meta['ai_polished'] ?? null;
|
||
|
||
if (! $polished) {
|
||
Notification::make()->title('没有可采纳的润色结果')->warning()->send();
|
||
|
||
return;
|
||
}
|
||
|
||
$post->update([
|
||
'content' => $polished,
|
||
'content_format' => 'markdown',
|
||
'meta' => array_merge($post->meta ?? [], ['ai_polished' => null]),
|
||
]);
|
||
|
||
Notification::make()->title('已采纳润色结果')->success()->send();
|
||
$this->polishResult = null;
|
||
}
|
||
|
||
public function getPendingPolishesProperty(): \Illuminate\Support\Collection
|
||
{
|
||
return Post::query()
|
||
->where('meta->ai_polished', '!=', null)
|
||
->latest()
|
||
->limit(10)
|
||
->get(['id', 'title']);
|
||
}
|
||
|
||
protected function getFormActions(): array
|
||
{
|
||
return [
|
||
Action::make('save')
|
||
->label('保存')
|
||
->submit('save'),
|
||
];
|
||
}
|
||
}
|