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.
 
 
 
 
 
 

280 lines
8.1 KiB

<?php
namespace App\Services;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use RuntimeException;
use Throwable;
class ProjectSearchChatService
{
private const SESSION_KEY = 'project_search_chat_session_uuid';
public function isAvailable(): bool
{
try {
return DB::connection('project_search')->getSchemaBuilder()->hasTable('project_search_chat_sessions');
} catch (Throwable) {
return false;
}
}
/**
* @return array<string, mixed>|null
*/
public function activeSession(string $username): ?array
{
$uuid = session(self::SESSION_KEY);
if (! is_string($uuid) || $uuid === '') {
return null;
}
$row = DB::connection('project_search')
->table('project_search_chat_sessions')
->where('session_uuid', $uuid)
->where('username', $username)
->where('status', 'active')
->first();
return $row ? $this->mapSession($row) : null;
}
/**
* @param array<int, string> $sources
* @return array<string, mixed>
*/
public function getOrCreateActiveSession(string $username, array $sources = []): array
{
if (! $this->isAvailable()) {
throw new RuntimeException('Tabel chat project search belum tersedia.');
}
$existing = $this->activeSession($username);
if ($existing !== null) {
return $existing;
}
$uuid = (string) Str::uuid();
$id = DB::connection('project_search')
->table('project_search_chat_sessions')
->insertGetId([
'session_uuid' => $uuid,
'username' => $username,
'status' => 'active',
'sources' => json_encode($sources),
'started_at' => now(),
'message_count' => 0,
]);
session([self::SESSION_KEY => $uuid]);
return [
'id' => (int) $id,
'session_uuid' => $uuid,
'username' => $username,
'status' => 'active',
'sources' => $sources,
'started_at' => now()->toIso8601String(),
'ended_at' => null,
'message_count' => 0,
];
}
/**
* @return array<int, array<string, mixed>>
*/
public function messagesForActiveSession(string $username): array
{
$session = $this->activeSession($username);
if ($session === null) {
return [];
}
return $this->messagesForSessionId((int) $session['id']);
}
/**
* @return array<int, array<string, mixed>>
*/
public function messagesForSessionId(int $sessionId): array
{
return DB::connection('project_search')
->table('project_search_chat_messages')
->where('session_id', $sessionId)
->orderBy('id')
->get()
->map(fn ($row) => $this->mapMessage($row))
->all();
}
/**
* @return array<int, array{role: string, content: string}>
*/
public function conversationHistoryForOllama(int $sessionId): array
{
return DB::connection('project_search')
->table('project_search_chat_messages')
->where('session_id', $sessionId)
->whereIn('role', ['user', 'assistant'])
->orderBy('id')
->get(['role', 'content'])
->map(fn ($row) => [
'role' => $row->role === 'assistant' ? 'assistant' : 'user',
'content' => (string) $row->content,
])
->all();
}
/**
* @return array<string, mixed>
*/
public function addUserMessage(int $sessionId, string $content): array
{
$message = $this->insertMessage($sessionId, 'user', $content);
DB::connection('project_search')
->table('project_search_chat_sessions')
->where('id', $sessionId)
->increment('message_count');
return $message;
}
/**
* @param array<int, array<string, mixed>> $results
* @param array<string, mixed> $meta
* @return array<string, mixed>
*/
public function addAssistantMessage(int $sessionId, string $content, array $results = [], array $meta = []): array
{
$message = $this->insertMessage($sessionId, 'assistant', $content, $results, $meta);
DB::connection('project_search')
->table('project_search_chat_sessions')
->where('id', $sessionId)
->increment('message_count');
return $message;
}
public function endActiveSession(string $username): bool
{
$session = $this->activeSession($username);
if ($session === null) {
session()->forget(self::SESSION_KEY);
return false;
}
DB::connection('project_search')
->table('project_search_chat_sessions')
->where('id', $session['id'])
->update([
'status' => 'ended',
'ended_at' => now(),
]);
session()->forget(self::SESSION_KEY);
return true;
}
/**
* @return array<int, array<string, mixed>>
*/
public function recentEndedSessions(string $username, int $limit = 10): array
{
if (! $this->isAvailable()) {
return [];
}
return DB::connection('project_search')
->table('project_search_chat_sessions')
->where('username', $username)
->where('status', 'ended')
->orderByDesc('ended_at')
->limit($limit)
->get()
->map(fn ($row) => $this->mapSession($row))
->all();
}
/**
* @param array<int, array<string, mixed>> $results
* @param array<string, mixed> $meta
* @return array<string, mixed>
*/
private function insertMessage(int $sessionId, string $role, string $content, array $results = [], array $meta = []): array
{
$id = DB::connection('project_search')
->table('project_search_chat_messages')
->insertGetId([
'session_id' => $sessionId,
'role' => $role,
'content' => $content,
'results' => $results !== [] ? json_encode($results) : null,
'meta' => $meta !== [] ? json_encode($meta) : null,
'created_at' => now(),
]);
return [
'id' => (int) $id,
'session_id' => $sessionId,
'role' => $role,
'content' => $content,
'results' => $results,
'meta' => $meta,
'created_at' => now()->toIso8601String(),
];
}
/**
* @return array<string, mixed>
*/
private function mapSession(object $row): array
{
$sources = $row->sources ?? null;
if (is_string($sources)) {
$sources = json_decode($sources, true);
}
return [
'id' => (int) $row->id,
'session_uuid' => (string) $row->session_uuid,
'username' => (string) $row->username,
'status' => (string) $row->status,
'sources' => is_array($sources) ? $sources : [],
'started_at' => $row->started_at,
'ended_at' => $row->ended_at,
'message_count' => (int) $row->message_count,
];
}
/**
* @return array<string, mixed>
*/
private function mapMessage(object $row): array
{
$results = $row->results ?? null;
$meta = $row->meta ?? null;
if (is_string($results)) {
$results = json_decode($results, true);
}
if (is_string($meta)) {
$meta = json_decode($meta, true);
}
return [
'id' => (int) $row->id,
'session_id' => (int) $row->session_id,
'role' => (string) $row->role,
'content' => (string) $row->content,
'results' => is_array($results) ? $results : [],
'meta' => is_array($meta) ? $meta : [],
'created_at' => $row->created_at,
];
}
}