| <?php |
|
|
| namespace App\Http\Controllers; |
|
|
| use App\Models\ChatMessage; |
| use App\Services\OpenAiChatService; |
| use Illuminate\Http\RedirectResponse; |
| use Illuminate\Http\Request; |
| use Illuminate\View\View; |
|
|
| class ChatController extends Controller |
| { |
| public function index(Request $request): View |
| { |
| $conversation = $request->user() |
| ->chatConversations() |
| ->with('messages') |
| ->latest() |
| ->first(); |
|
|
| if (! $conversation) { |
| $conversation = $request->user()->chatConversations()->create([ |
| 'title' => 'Chat AI', |
| ]); |
| $conversation->load('messages'); |
| } |
|
|
| return view('chat.index', [ |
| 'conversation' => $conversation, |
| ]); |
| } |
|
|
| public function store(Request $request, OpenAiChatService $openai): RedirectResponse |
| { |
| $data = $request->validate([ |
| 'prompt' => ['required', 'string', 'max:1000'], |
| ]); |
|
|
| $dailyLimit = max(5, (int) config('services.openai.daily_message_limit', 40)); |
| $todayCount = ChatMessage::query() |
| ->where('role', 'user') |
| ->whereDate('created_at', now()->toDateString()) |
| ->whereHas('conversation', fn ($q) => $q->where('user_id', $request->user()->id)) |
| ->count(); |
|
|
| if ($todayCount >= $dailyLimit) { |
| return redirect() |
| ->route('chat.index') |
| ->with('chat_error', "Batas harian chat ({$dailyLimit}) sudah tercapai. Coba lagi besok atau minta limit dinaikkan."); |
| } |
|
|
| $conversation = $request->user() |
| ->chatConversations() |
| ->latest() |
| ->first(); |
|
|
| if (! $conversation) { |
| $conversation = $request->user()->chatConversations()->create([ |
| 'title' => 'Chat AI', |
| ]); |
| } |
|
|
| $conversation->messages()->create([ |
| 'role' => 'user', |
| 'content' => $data['prompt'], |
| ]); |
|
|
| $historyLimit = max(2, (int) config('services.openai.history_limit', 10)); |
|
|
| $messages = $conversation->messages() |
| ->latest('id') |
| ->limit($historyLimit) |
| ->get(['role', 'content']) |
| ->reverse() |
| ->map(fn ($message) => [ |
| 'role' => $message->role, |
| 'content' => $message->content, |
| ]) |
| ->values() |
| ->all(); |
|
|
| $systemPrompt = config('services.openai.system_prompt'); |
| $languageGuard = 'Aturan wajib: selalu jawab dalam Bahasa Indonesia. Gunakan Bahasa Inggris hanya jika pengguna secara eksplisit memintanya.'; |
|
|
| $finalSystemPrompt = trim((string) $systemPrompt); |
| if ($finalSystemPrompt !== '') { |
| $finalSystemPrompt .= "\n\n".$languageGuard; |
| } else { |
| $finalSystemPrompt = $languageGuard; |
| } |
|
|
| array_unshift($messages, [ |
| 'role' => 'system', |
| 'content' => $finalSystemPrompt, |
| ]); |
|
|
| try { |
| $reply = $openai->reply($messages); |
| } catch (\Throwable $e) { |
| $conversation->messages()->create([ |
| 'role' => 'assistant', |
| 'content' => 'Maaf, AI belum bisa merespons sekarang. Cek konfigurasi OPENAI_API_KEY dan model OpenAI kamu.', |
| ]); |
|
|
| return redirect() |
| ->route('chat.index') |
| ->with('chat_error', $e->getMessage()); |
| } |
|
|
| $conversation->messages()->create([ |
| 'role' => 'assistant', |
| 'content' => $reply, |
| ]); |
|
|
| return redirect()->route('chat.index'); |
| } |
| } |
|
|