Setzt den in #84 skizzierten Workflow um: record.html nimmt im Handy-Browser eine Sprachnotiz per MediaRecorder auf und laedt sie unauthentifiziert zu POST /api/v1/agents/{id}/recordings hoch. Ein Klick auf die Personen-Figur jedes registrierten Agenten in der Buero-Visualisierung verlinkt dorthin, ein Zaehler am Schreibtisch zeigt offene Aufnahmen. Der Agent selbst holt seine Warteschlange ueber die bestehenden Api-Key-authentifizierten Endpunkte ab (GET .../recordings, GET /recordings/{id}/audio) und markiert eine Aufnahme nach der Transkription per PATCH als erledigt - die eigentliche Transkription (whisper.cpp/faster-whisper) bleibt agent-seitig, siehe fds2610/Agent#17. Schliesst #85
78 lines
2.6 KiB
PHP
78 lines
2.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Monitor\Api\Controller;
|
|
|
|
use InvalidArgumentException;
|
|
use Monitor\Api\Http\Request;
|
|
use Monitor\Api\Http\Response;
|
|
use Monitor\Api\Repository\AgentRepository;
|
|
use Monitor\Api\Repository\VoiceRecordingRepository;
|
|
|
|
final class AgentController
|
|
{
|
|
public function __construct(
|
|
private readonly AgentRepository $agents,
|
|
private readonly VoiceRecordingRepository $recordings,
|
|
) {
|
|
}
|
|
|
|
/**
|
|
* Issue #85: jeder Agent traegt zusaetzlich pending_recordings - die Anzahl offener
|
|
* Sprachaufnahmen in seiner Warteschlange, Grundlage fuer den Zaehler auf seinem
|
|
* Schreibtisch in der Buero-Visualisierung.
|
|
*/
|
|
public function index(Request $request): Response
|
|
{
|
|
$pendingCounts = $this->recordings->pendingCountsByAgent();
|
|
|
|
$agents = array_map(
|
|
fn (array $agent) => $agent + ['pending_recordings' => $pendingCounts[(int) $agent['id']] ?? 0],
|
|
$this->agents->all()
|
|
);
|
|
|
|
return Response::json(['agents' => $agents]);
|
|
}
|
|
|
|
public function register(Request $request): Response
|
|
{
|
|
$displayName = trim((string) ($request->body['display_name'] ?? ''));
|
|
$role = (string) ($request->body['role'] ?? '');
|
|
|
|
if ($displayName === '') {
|
|
return Response::error('Feld "display_name" ist erforderlich.', 422);
|
|
}
|
|
|
|
try {
|
|
$result = $this->agents->register($displayName, $role);
|
|
} catch (InvalidArgumentException $e) {
|
|
return Response::error($e->getMessage(), 422);
|
|
}
|
|
|
|
// Der Klartext-API-Key wird nur bei der Registrierung einmalig zurueckgegeben.
|
|
return Response::json(['agent' => $result['agent'], 'api_key' => $result['api_key']], 201);
|
|
}
|
|
|
|
/**
|
|
* @param array<string, string> $params
|
|
* @param array<string, mixed> $authenticatedAgent
|
|
*/
|
|
public function activity(Request $request, array $params, array $authenticatedAgent): Response
|
|
{
|
|
if ((int) $params['id'] !== (int) $authenticatedAgent['id']) {
|
|
return Response::error('Ein Agent darf nur seine eigene Aktivitaet melden.', 403);
|
|
}
|
|
|
|
$state = (string) ($request->body['state'] ?? '');
|
|
if ($state === '') {
|
|
return Response::error('Feld "state" ist erforderlich.', 422);
|
|
}
|
|
|
|
$currentTicketId = isset($request->body['current_ticket']) ? (int) $request->body['current_ticket'] : null;
|
|
|
|
$agent = $this->agents->updateActivity((int) $params['id'], $state, $currentTicketId);
|
|
|
|
return Response::json(['agent' => $agent]);
|
|
}
|
|
}
|