feat(api): add AI text-to-deck generation, wallet deposit structure, and profile/notification endpoints

Fills the gaps between the admin panel screens and the backend: a full
free-text + slide-count + language -> AI-generated presentation flow with
new slide-cloning logic in TemplateFillService, a "my presentations" list
endpoint, a swappable payment-gateway structure for wallet top-ups (fake
driver for now), and avatar upload / public-profile toggle / account
deletion / password change / notification preference endpoints.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-29 01:36:17 +03:30
parent fe2090a5af
commit 46ae711a20
42 changed files with 1632 additions and 44 deletions

View File

@@ -2,14 +2,18 @@
namespace App\Jobs;
use App\Enums\TemplateGenerationSource;
use App\Enums\TemplateGenerationStatus;
use App\Models\AiProvider;
use App\Models\TemplateGeneration;
use App\Services\Ai\OpenAiCompatibleTextGenerator;
use App\Services\TemplateFillService;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use RuntimeException;
use Throwable;
class GenerateTemplateJob implements ShouldQueue
@@ -18,12 +22,14 @@ class GenerateTemplateJob implements ShouldQueue
public function __construct(private readonly TemplateGeneration $generation) {}
public function handle(TemplateFillService $templateFillService): void
public function handle(TemplateFillService $templateFillService, OpenAiCompatibleTextGenerator $outlineGenerator): void
{
$this->generation->update(['status' => TemplateGenerationStatus::Processing]);
try {
$outputPath = $templateFillService->fill($this->generation);
$outputPath = $this->generation->source === TemplateGenerationSource::AiText
? $this->fillFromAiText($templateFillService, $outlineGenerator)
: $templateFillService->fill($this->generation);
$this->generation->update([
'status' => TemplateGenerationStatus::Completed,
@@ -36,4 +42,24 @@ class GenerateTemplateJob implements ShouldQueue
]);
}
}
private function fillFromAiText(TemplateFillService $templateFillService, OpenAiCompatibleTextGenerator $outlineGenerator): string
{
$provider = AiProvider::resolveActiveDefault();
if (! $provider) {
throw new RuntimeException('هیچ سرویس هوش مصنوعی فعالی تنظیم نشده است.');
}
$outline = $outlineGenerator->generateOutline(
$this->generation->template,
(string) $this->generation->title,
(string) $this->generation->source_text,
(int) $this->generation->slide_count,
(string) $this->generation->language,
$provider,
);
return $templateFillService->fillAiGeneration($this->generation, $outline);
}
}