You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
141 lines
7.9 KiB
141 lines
7.9 KiB
@extends('layouts.app') |
|
|
|
@section('title', 'Project Search — ' . config('app.name')) |
|
|
|
@section('content') |
|
<div class="max-w-5xl mx-auto px-4 py-6 sm:py-8" |
|
id="project-search-app" |
|
data-ask-url="{{ route('project-search.ask') }}" |
|
data-end-url="{{ route('project-search.end-chat') }}" |
|
data-index-available="{{ $indexAvailable ? '1' : '0' }}" |
|
data-chat-available="{{ $chatAvailable ? '1' : '0' }}"> |
|
<div class="mt-6 mb-6 flex flex-wrap items-start justify-between gap-4"> |
|
<div> |
|
<h1 class="text-3xl font-bold text-white">Project Search</h1> |
|
<p class="text-slate-400 mt-1 text-sm">Chat pencarian folder proyek NAS via Ollama + indeks metadata</p> |
|
</div> |
|
@if ($activeSession) |
|
<button type="button" id="project-search-end-chat" |
|
class="rounded-lg border border-slate-600 hover:border-rose-500 hover:text-rose-300 px-4 py-2 text-sm text-slate-300"> |
|
End Chat |
|
</button> |
|
@endif |
|
</div> |
|
|
|
@unless ($indexAvailable) |
|
<div class="mb-6 rounded-lg bg-amber-950/40 border border-amber-800 p-4 text-sm text-amber-200"> |
|
Indeks <code class="text-amber-100">project_index</code> belum tersedia. Pastikan indexer di VM Ollama sudah dijalankan. |
|
</div> |
|
@endunless |
|
|
|
@unless ($chatAvailable) |
|
<div class="mb-6 rounded-lg bg-amber-950/40 border border-amber-800 p-4 text-sm text-amber-200"> |
|
Tabel chat belum tersedia. Jalankan migrasi <code class="text-amber-100">project_search_chat</code> di PostgreSQL. |
|
</div> |
|
@endunless |
|
|
|
@unless ($ollamaConfigured) |
|
<div class="mb-6 rounded-lg bg-amber-950/40 border border-amber-800 p-4 text-sm text-amber-200"> |
|
<code class="text-amber-100">OLLAMA_BASE_URL</code> belum dikonfigurasi di server. |
|
</div> |
|
@endunless |
|
|
|
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6"> |
|
<div class="lg:col-span-2 space-y-4"> |
|
<div class="ps-chat bg-slate-900 border border-slate-800 rounded-2xl flex flex-col min-h-[28rem] max-h-[calc(100vh-14rem)]"> |
|
<div id="project-search-messages" class="ps-chat__messages flex-1 overflow-y-auto p-4 space-y-4"> |
|
@forelse ($messages as $message) |
|
@include('project-search.partials.message', ['message' => $message]) |
|
@empty |
|
<div class="ps-chat__empty text-center text-slate-500 text-sm py-12" data-chat-empty> |
|
<p class="mb-1">Belum ada percakapan.</p> |
|
<p>Tanyakan lokasi folder proyek, misalnya <span class="text-slate-400">"carikan projek Pertamina"</span>.</p> |
|
</div> |
|
@endforelse |
|
</div> |
|
|
|
<div id="project-search-status" class="ps-chat__status hidden px-4 py-2 text-sm text-slate-400 border-t border-slate-800" aria-live="polite"> |
|
<span class="ps-chat__typing"><span></span><span></span><span></span></span> |
|
Ollama sedang memproses… |
|
</div> |
|
|
|
<div class="ps-chat__composer border-t border-slate-800 p-4"> |
|
<form id="project-search-form" data-ui-no-loading class="space-y-3"> |
|
<label for="project-search-query" class="sr-only">Pertanyaan</label> |
|
<textarea id="project-search-query" name="query" rows="2" required minlength="3" maxlength="500" |
|
placeholder="Tulis pertanyaan… (Enter kirim, Shift+Enter baris baru)" |
|
class="w-full rounded-lg bg-slate-800 border border-slate-700 px-4 py-3 text-sm text-white resize-none" |
|
@disabled(! $indexAvailable || ! $chatAvailable)></textarea> |
|
<div class="flex flex-wrap items-center justify-between gap-3"> |
|
<div class="flex flex-wrap gap-3 text-sm"> |
|
@foreach ($sources as $source) |
|
<label class="flex items-center gap-1.5 text-slate-400"> |
|
<input type="checkbox" name="sources[]" value="{{ $source['id'] }}" class="rounded" checked> |
|
<span>{{ $source['label'] }}</span> |
|
</label> |
|
@endforeach |
|
</div> |
|
<button type="submit" id="project-search-submit" |
|
class="rounded-lg bg-cyan-600 hover:bg-cyan-500 disabled:opacity-50 px-5 py-2 text-sm font-medium text-white" |
|
@disabled(! $indexAvailable || ! $chatAvailable)> |
|
Kirim |
|
</button> |
|
</div> |
|
<p class="text-slate-500 text-xs">Fase POC: metadata folder. Klik <strong class="text-slate-400 font-medium">End Chat</strong> untuk mulai sesi baru.</p> |
|
</form> |
|
</div> |
|
</div> |
|
|
|
<div id="project-search-error" class="hidden rounded-lg bg-red-950/40 border border-red-800 p-3 text-sm text-red-200" role="alert"></div> |
|
</div> |
|
|
|
<aside class="space-y-6"> |
|
@if (! empty($chatHistory)) |
|
<div class="bg-slate-900 border border-slate-800 rounded-2xl p-5"> |
|
<h2 class="text-lg font-semibold text-white mb-3">Riwayat chat</h2> |
|
<div class="space-y-2 max-h-48 overflow-y-auto"> |
|
@foreach ($chatHistory as $hist) |
|
<div class="text-sm border-b border-slate-800 pb-2 last:border-0"> |
|
<p class="text-slate-400 text-xs">{{ $hist['ended_at'] ?? $hist['started_at'] }}</p> |
|
<p class="text-slate-300">{{ $hist['message_count'] }} pesan</p> |
|
</div> |
|
@endforeach |
|
</div> |
|
</div> |
|
@endif |
|
|
|
<div class="bg-slate-900 border border-slate-800 rounded-2xl p-5"> |
|
<h2 class="text-lg font-semibold text-white mb-3">OAuth2 API</h2> |
|
<p class="text-slate-400 text-sm mb-3">Integrasi eksternal via Client Credentials + scope <code class="text-cyan-300">{{ $oauthScope }}</code>.</p> |
|
<dl class="space-y-3 text-sm"> |
|
<div> |
|
<dt class="text-slate-500">Token URL</dt> |
|
<dd class="text-cyan-300 font-mono text-xs break-all mt-1">{{ $oauthTokenUrl }}</dd> |
|
</div> |
|
<div> |
|
<dt class="text-slate-500">Client ID</dt> |
|
<dd class="text-cyan-300 font-mono text-xs break-all mt-1 select-all">{{ $oauthClientId }}</dd> |
|
</div> |
|
</dl> |
|
<a href="{{ route('api-docs.index') }}" class="inline-block mt-4 text-sm text-cyan-400 hover:text-cyan-300">→ API Docs</a> |
|
</div> |
|
|
|
<div class="bg-slate-900 border border-slate-800 rounded-2xl p-5"> |
|
<h2 class="text-lg font-semibold text-white mb-3">Status indeks</h2> |
|
@forelse ($indexRuns as $run) |
|
<div class="text-sm border-b border-slate-800 py-2 last:border-0"> |
|
<p class="text-slate-300">{{ $run['source_id'] }} — <span class="text-emerald-400">{{ $run['status'] }}</span></p> |
|
<p class="text-slate-500 text-xs mt-1">{{ $run['rows_upserted'] }} baris · {{ $run['finished_at'] ?? $run['started_at'] }}</p> |
|
</div> |
|
@empty |
|
<p class="text-slate-500 text-sm">Belum ada run indexer.</p> |
|
@endforelse |
|
</div> |
|
</aside> |
|
</div> |
|
</div> |
|
@endsection |
|
|
|
@push('frame-scripts') |
|
<script src="{{ asset('js/project-search-chat.js') }}" defer></script> |
|
@endpush
|
|
|