GeoNetAgent, LDAPWeb, server-audit, server-connection
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

@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