暂存
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace app\service;
|
||||
|
||||
use Throwable;
|
||||
use support\Db;
|
||||
|
||||
class ArchiveRepository
|
||||
@@ -24,8 +25,6 @@ class ArchiveRepository
|
||||
'series' => $archive['series'] ?? null,
|
||||
'tags' => json_encode($archive['tags'] ?? [], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
|
||||
'metadata' => json_encode($archive['metadata'] ?? [], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
|
||||
'content' => $archive['content'] ?? null,
|
||||
'raw' => $archive['raw'] ?? null,
|
||||
'chunks' => json_encode($chunkUids, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
|
||||
]
|
||||
);
|
||||
@@ -194,6 +193,79 @@ class ArchiveRepository
|
||||
Db::table('archives')->where('archive_uid', $archiveUid)->update($updates);
|
||||
}
|
||||
|
||||
public function queuePendingAiMetadataArchives(int $limit): array
|
||||
{
|
||||
$limit = max(1, $limit);
|
||||
$rows = Db::table('archives')
|
||||
->where(function ($query): void {
|
||||
$query
|
||||
->whereNull('title')
|
||||
->orWhere('title', '')
|
||||
->orWhereNull('summary')
|
||||
->orWhere('summary', '')
|
||||
->orWhereNull('author')
|
||||
->orWhere('author', '')
|
||||
->orWhereNull('year')
|
||||
->orWhere('year', '<=', 0)
|
||||
->orWhereRaw("tags = '[]'::jsonb")
|
||||
->orWhereRaw("metadata #>> '{title_source}' = 'fallback'");
|
||||
})
|
||||
->orderByDesc('updated_time')
|
||||
->limit(max($limit * 5, 50))
|
||||
->get()
|
||||
->all();
|
||||
|
||||
$archiveUids = [];
|
||||
foreach ($rows as $row) {
|
||||
$archive = $this->archiveToArray($row);
|
||||
if (!$this->archiveNeedsMetadata($archive) || !$this->shouldQueueAiMetadata($archive)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$archiveUids[] = (string) $archive['archive_uid'];
|
||||
$this->markAiMetadataStatus((string) $archive['archive_uid'], 'queued', null);
|
||||
|
||||
if (count($archiveUids) >= $limit) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $archiveUids;
|
||||
}
|
||||
|
||||
public function markAiMetadataStatus(string $archiveUid, string $status, ?string $error = null, array $extra = []): void
|
||||
{
|
||||
$archive = $this->findArchive($archiveUid);
|
||||
if ($archive === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$metadata = is_array($archive['metadata'] ?? null) ? $archive['metadata'] : [];
|
||||
$aiMeta = is_array($metadata['ai_enrichment'] ?? null) ? $metadata['ai_enrichment'] : [];
|
||||
$attempt = ((int) ($aiMeta['attempt'] ?? 0)) + ($status === 'processing' ? 1 : 0);
|
||||
|
||||
$metadata['ai_enrichment'] = array_merge($aiMeta, $extra, [
|
||||
'status' => $status,
|
||||
'attempt' => $attempt,
|
||||
'updated_at' => date(DATE_ATOM),
|
||||
'error' => $error,
|
||||
]);
|
||||
|
||||
Db::table('archives')->where('archive_uid', $archiveUid)->update([
|
||||
'metadata' => json_encode($metadata, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
|
||||
]);
|
||||
}
|
||||
|
||||
public function isAiMetadataRetryable(Throwable $exception): bool
|
||||
{
|
||||
if (!$exception instanceof \app\service\LLM\LLMRequestException) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$statusCode = $exception->statusCode();
|
||||
return $statusCode === null || $statusCode === 429 || $statusCode >= 500;
|
||||
}
|
||||
|
||||
public function archiveNeedsMetadata(array $archive): bool
|
||||
{
|
||||
foreach (['title', 'year', 'author', 'tags', 'summary'] as $field) {
|
||||
@@ -227,12 +299,29 @@ class ArchiveRepository
|
||||
'series' => $archive->series,
|
||||
'tags' => json_decode($archive->tags ?? '[]', true) ?: [],
|
||||
'metadata' => json_decode($archive->metadata ?? '{}', true) ?: [],
|
||||
'content' => $archive->content,
|
||||
'raw' => $archive->raw,
|
||||
'chunks' => json_decode($archive->chunks ?? '[]', true) ?: [],
|
||||
];
|
||||
}
|
||||
|
||||
private function shouldQueueAiMetadata(array $archive): bool
|
||||
{
|
||||
$aiMeta = is_array($archive['metadata']['ai_enrichment'] ?? null) ? $archive['metadata']['ai_enrichment'] : [];
|
||||
$status = (string) ($aiMeta['status'] ?? '');
|
||||
if ($status === 'failed_terminal') {
|
||||
return false;
|
||||
}
|
||||
|
||||
$updatedAt = strtotime((string) ($aiMeta['updated_at'] ?? '')) ?: 0;
|
||||
$staleAfter = max(60, (int) config('queue.ai_metadata.stale_after_seconds', 900));
|
||||
$isFresh = $updatedAt > 0 && (time() - $updatedAt) < $staleAfter;
|
||||
|
||||
if (in_array($status, ['queued', 'processing'], true) && $isFresh) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function chunkRowToArray(object $row): array
|
||||
{
|
||||
return [
|
||||
|
||||
Reference in New Issue
Block a user