This commit is contained in:
2026-05-08 00:05:51 +08:00
parent 549b706fcc
commit ed70a140a2
40 changed files with 5590 additions and 36 deletions
+160
View File
@@ -75,6 +75,102 @@ class ArchiveRepository
return implode("\n\n", array_map(fn ($chunk): string => (string) $chunk->text, $chunks));
}
public function findChunk(string $chunkUid): ?array
{
$row = Db::table('chunks')
->join('archives', 'chunks.archive_uid', '=', 'archives.archive_uid')
->where('chunks.chunk_uid', $chunkUid)
->first([
'chunks.chunk_uid',
'chunks.archive_uid',
'chunks.chunk_index',
'chunks.page_start',
'chunks.page_end',
'chunks.text',
'chunks.length',
'chunks.embedding_status',
'chunks.embedding_ref',
'chunks.embedding_model',
'chunks.embedding_error',
'chunks.search_index_status',
'chunks.search_index_error',
'archives.title',
'archives.summary',
'archives.year',
'archives.author',
'archives.source',
'archives.series',
'archives.tags',
'archives.metadata',
]);
if (!$row) {
return null;
}
return [
'chunk_uid' => (string) $row->chunk_uid,
'archive_uid' => (string) $row->archive_uid,
'chunk_index' => (int) $row->chunk_index,
'page_start' => $row->page_start === null ? null : (int) $row->page_start,
'page_end' => $row->page_end === null ? null : (int) $row->page_end,
'pages' => $this->pages($row->page_start, $row->page_end),
'text' => (string) $row->text,
'length' => $row->length === null ? null : (int) $row->length,
'embedding_status' => (int) $row->embedding_status,
'embedding_ref' => $this->decodeJson($row->embedding_ref ?? null, null),
'embedding_model' => $row->embedding_model,
'embedding_error' => $row->embedding_error,
'search_index_status' => (int) $row->search_index_status,
'search_index_error' => $row->search_index_error,
'archive' => [
'archive_uid' => (string) $row->archive_uid,
'title' => $row->title,
'summary' => $row->summary,
'year' => $row->year === null ? null : (int) $row->year,
'author' => $row->author,
'source' => $row->source,
'series' => $row->series,
'tags' => $this->decodeJson($row->tags ?? null, []),
'metadata' => $this->decodeJson($row->metadata ?? null, []),
],
];
}
public function findArchiveChunks(string $archiveUid): array
{
$rows = Db::table('chunks')
->join('archives', 'chunks.archive_uid', '=', 'archives.archive_uid')
->where('chunks.archive_uid', $archiveUid)
->orderBy('chunks.chunk_index')
->get([
'chunks.chunk_uid',
'chunks.archive_uid',
'chunks.chunk_index',
'chunks.page_start',
'chunks.page_end',
'chunks.text',
'chunks.length',
'chunks.embedding_status',
'chunks.embedding_ref',
'chunks.embedding_model',
'chunks.embedding_error',
'chunks.search_index_status',
'chunks.search_index_error',
'archives.title',
'archives.summary',
'archives.year',
'archives.author',
'archives.source',
'archives.series',
'archives.tags',
'archives.metadata',
])
->all();
return array_map(fn (object $row): array => $this->chunkRowToArray($row), $rows);
}
public function updateMetadata(string $archiveUid, array $fields, array $aiMeta): void
{
$archive = $this->findArchive($archiveUid);
@@ -136,4 +232,68 @@ class ArchiveRepository
'chunks' => json_decode($archive->chunks ?? '[]', true) ?: [],
];
}
private function chunkRowToArray(object $row): array
{
return [
'chunk_uid' => (string) $row->chunk_uid,
'archive_uid' => (string) $row->archive_uid,
'chunk_index' => (int) $row->chunk_index,
'page_start' => $row->page_start === null ? null : (int) $row->page_start,
'page_end' => $row->page_end === null ? null : (int) $row->page_end,
'pages' => $this->pages($row->page_start, $row->page_end),
'text' => (string) $row->text,
'length' => $row->length === null ? null : (int) $row->length,
'embedding_status' => (int) $row->embedding_status,
'embedding_ref' => $this->decodeJson($row->embedding_ref ?? null, null),
'embedding_model' => $row->embedding_model,
'embedding_error' => $row->embedding_error,
'search_index_status' => (int) $row->search_index_status,
'search_index_error' => $row->search_index_error,
'archive' => [
'archive_uid' => (string) $row->archive_uid,
'title' => $row->title,
'summary' => $row->summary,
'year' => $row->year === null ? null : (int) $row->year,
'author' => $row->author,
'source' => $row->source,
'series' => $row->series,
'tags' => $this->decodeJson($row->tags ?? null, []),
'metadata' => $this->decodeJson($row->metadata ?? null, []),
],
];
}
private function decodeJson(mixed $value, mixed $fallback): mixed
{
if ($value === null) {
return $fallback;
}
if (is_array($value)) {
return $value;
}
if (!is_string($value) || trim($value) === '') {
return $fallback;
}
$decoded = json_decode($value, true);
return $decoded === null && json_last_error() !== JSON_ERROR_NONE ? $fallback : $decoded;
}
private function pages(mixed $pageStart, mixed $pageEnd): array
{
if (!is_numeric($pageStart) || !is_numeric($pageEnd)) {
return array_values(array_filter([$pageStart, $pageEnd], static fn ($value): bool => $value !== null && $value !== ''));
}
$start = (int) $pageStart;
$end = (int) $pageEnd;
if ($end < $start) {
$end = $start;
}
return range($start, $end);
}
}