- Added tone instruction retrieval to SupportReplyService. - Improved user feedback when no relevant article is found. - Included article URL and tone instruction in LLM prompt. - Updated response format to include source information. - Enhanced article management UI with search functionality and editing capabilities. - Introduced a new API endpoint for nearest articles based on vector search. - Added confidence badge component to display article confidence levels. - Implemented tests for article searching, editing, and nearest article API. - Removed obsolete .htaccess file.
100 lines
3.3 KiB
PHP
100 lines
3.3 KiB
PHP
<?php
|
|
|
|
namespace Tests\Unit;
|
|
|
|
use App\Models\Article;
|
|
use App\Models\Ticket;
|
|
use App\Services\AppSettingsService;
|
|
use App\Services\SupportReplyService;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Tests\Fakes\FakeLlmClient;
|
|
use Tests\Fakes\FakeTicketProcessingLoggerService;
|
|
use Tests\TestCase;
|
|
|
|
class SupportReplyServiceTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
public function test_it_returns_llm_response_when_available(): void
|
|
{
|
|
$llm = new FakeLlmClient;
|
|
$llm->responses = ['1. Doe X'];
|
|
|
|
$service = new SupportReplyService(
|
|
$this->fakeSettings(),
|
|
$llm,
|
|
new FakeTicketProcessingLoggerService
|
|
);
|
|
|
|
$ticket = Ticket::query()->create(['message' => 'vraag', 'normalized_message' => 'vraag']);
|
|
$article = Article::query()->create(['title' => 'DNS', 'content' => 'steps']);
|
|
|
|
$reply = $service->build($ticket, $article, 'relevant');
|
|
|
|
$this->assertSame('1. Doe X', $reply);
|
|
$this->assertStringContainsString('Gebruikersvraag (genormaliseerd): vraag', $llm->generatedPrompts[0]['prompt']);
|
|
$this->assertStringContainsString('spreek de klant consequent informeel aan met je/jij/jouw', $llm->generatedPrompts[0]['prompt']);
|
|
}
|
|
|
|
public function test_it_falls_back_when_llm_returns_empty(): void
|
|
{
|
|
$llm = new FakeLlmClient;
|
|
$llm->responses = [''];
|
|
|
|
$service = new SupportReplyService(
|
|
$this->fakeSettings(),
|
|
$llm,
|
|
new FakeTicketProcessingLoggerService
|
|
);
|
|
|
|
$ticket = Ticket::query()->create(['message' => 'vraag']);
|
|
$article = Article::query()->create(['title' => 'DNS', 'content' => 'steps']);
|
|
|
|
$reply = $service->build($ticket, $article, 'relevant');
|
|
|
|
$this->assertStringContainsString('Gebruik het kennisbankartikel', $reply);
|
|
}
|
|
|
|
public function test_it_includes_formal_addressing_instruction_when_configured(): void
|
|
{
|
|
$llm = new FakeLlmClient;
|
|
$llm->responses = ['1. Doe X'];
|
|
|
|
$service = new SupportReplyService(
|
|
$this->fakeSettings('u'),
|
|
$llm,
|
|
new FakeTicketProcessingLoggerService
|
|
);
|
|
|
|
$ticket = Ticket::query()->create(['message' => 'vraag', 'normalized_message' => 'vraag']);
|
|
$article = Article::query()->create(['title' => 'DNS', 'content' => 'steps']);
|
|
|
|
$service->build($ticket, $article, 'relevant');
|
|
|
|
$this->assertStringContainsString('spreek de klant consequent formeel aan met u/uw', $llm->generatedPrompts[0]['prompt']);
|
|
$this->assertStringContainsString('Gebruik geen je/jij/jouw', $llm->generatedPrompts[0]['prompt']);
|
|
}
|
|
|
|
private function fakeSettings(string $tone = 'je'): AppSettingsService
|
|
{
|
|
return new class($tone) extends AppSettingsService
|
|
{
|
|
public function __construct(private readonly string $tone) {}
|
|
|
|
public function get(string $key, ?string $default = null): ?string
|
|
{
|
|
if ($key === 'tone_addressing') {
|
|
return $this->tone;
|
|
}
|
|
|
|
return $default;
|
|
}
|
|
|
|
public function getPrompt(string $key, ?string $default = null): ?string
|
|
{
|
|
return 'Prompt';
|
|
}
|
|
};
|
|
}
|
|
}
|