104 lines
3.2 KiB
PHP
104 lines
3.2 KiB
PHP
<?php
|
||
|
||
/**
|
||
* KI-Kontierungsvorschlag – Batch-Verarbeitung (CLI-Einstiegspunkt).
|
||
*
|
||
* Verarbeitet EINEN ausstehenden Beleg pro Aufruf (ki_vorschlag IS NULL, locked = 0).
|
||
* Verhindert so, dass mehrere Vision-Model-Anfragen parallel an Ollama geschickt werden.
|
||
*
|
||
* Voraussetzung: ki_vorschlag_aktiv = 1 in den Einstellungen, Ollama erreichbar.
|
||
*
|
||
* Aufruf:
|
||
* docker compose exec web php scripts/ki-batch.php
|
||
*
|
||
* Für optionalen eigenen Cronjob (manuelle Uploads ohne Nextcloud):
|
||
* *\/5 * * * * docker compose -f /opt/steuerkram/docker-compose.yml exec -T web \
|
||
* php scripts/ki-batch.php >> /var/log/steuerkram-ki.log 2>&1
|
||
*/
|
||
|
||
declare(strict_types=1);
|
||
|
||
chdir(dirname(__DIR__));
|
||
|
||
// DB-Zugangsdaten aus .env laden (für CLI-Kontext ohne Apache-Umgebung)
|
||
if (file_exists('.env')) {
|
||
foreach (file('.env', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) as $line) {
|
||
if (str_starts_with(trim($line), '#') || !str_contains($line, '=')) {
|
||
continue;
|
||
}
|
||
[$key, $value] = explode('=', $line, 2);
|
||
$key = trim($key);
|
||
$value = trim($value, " \t\n\r\0\x0B\"'");
|
||
if (!array_key_exists($key, $_ENV)) {
|
||
$_ENV[$key] = $value;
|
||
putenv("{$key}={$value}");
|
||
}
|
||
}
|
||
}
|
||
|
||
require_once 'vendor/autoload.php';
|
||
|
||
use Steuerkram\Config;
|
||
use Steuerkram\Database;
|
||
use Steuerkram\Models\Beleg;
|
||
use Steuerkram\Models\Setting;
|
||
use Steuerkram\Services\KontierungsvorschlagService;
|
||
|
||
Config::load();
|
||
|
||
$tag = '[ki-batch]';
|
||
|
||
// KI-Erkennung in den Einstellungen aktiv?
|
||
$settings = Setting::get();
|
||
if (empty($settings['ki_vorschlag_aktiv'])) {
|
||
echo "{$tag} KI-Erkennung ist in den Einstellungen deaktiviert – nichts zu tun." . PHP_EOL;
|
||
exit(0);
|
||
}
|
||
|
||
$svc = new KontierungsvorschlagService();
|
||
|
||
if (!$svc->isEnabled()) {
|
||
echo "{$tag} LLM nicht erreichbar – Abbruch." . PHP_EOL;
|
||
exit(1);
|
||
}
|
||
|
||
// Optionale Beleg-ID als CLI-Argument: php ki-batch.php 123
|
||
$argId = isset($argv[1]) && ctype_digit((string)$argv[1]) ? (int)$argv[1] : null;
|
||
|
||
// Beleg holen: wenn ID angegeben, diesen direkt verarbeiten; sonst ältesten ausstehenden
|
||
$row = $argId !== null
|
||
? Database::fetchOne('SELECT id FROM belege WHERE id = ? AND ki_vorschlag IS NULL AND locked = 0', [$argId])
|
||
: Database::fetchOne('SELECT id FROM belege WHERE ki_vorschlag IS NULL AND locked = 0 ORDER BY id ASC LIMIT 1');
|
||
|
||
if (!$row) {
|
||
echo "{$tag} Kein ausstehender Beleg gefunden." . PHP_EOL;
|
||
exit(0);
|
||
}
|
||
|
||
$belegId = (int)$row['id'];
|
||
$beleg = Beleg::find($belegId);
|
||
|
||
if (!$beleg) {
|
||
echo "{$tag} Beleg #{$belegId} nicht ladbar – Abbruch." . PHP_EOL;
|
||
exit(1);
|
||
}
|
||
|
||
echo "{$tag} Verarbeite Beleg #{$belegId} ({$beleg['beleg_nr']}) ..." . PHP_EOL;
|
||
|
||
$start = microtime(true);
|
||
$result = $svc->generateForBeleg($beleg);
|
||
|
||
if ($result === null) {
|
||
echo "{$tag} Beleg #{$belegId}: Kein Vorschlag generiert (nicht unterstützter Typ oder LLM-Fehler)." . PHP_EOL;
|
||
// Leeres Array speichern damit der Beleg nicht erneut verarbeitet wird
|
||
Beleg::saveKiVorschlag($belegId, []);
|
||
exit(0);
|
||
}
|
||
|
||
Beleg::saveKiVorschlag($belegId, $result);
|
||
|
||
$elapsed = round(microtime(true) - $start, 1);
|
||
$zeilen = count($result);
|
||
echo "{$tag} Beleg #{$belegId}: {$zeilen} Buchungszeile(n) generiert in {$elapsed}s." . PHP_EOL;
|
||
|
||
exit(0);
|