feat: API for content
This commit is contained in:
@@ -3,9 +3,11 @@
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Document;
|
||||
use App\Models\Guide;
|
||||
use App\Models\GuidePage;
|
||||
use App\Models\GuidePageEdge;
|
||||
use App\Models\KnowledgeBase;
|
||||
use App\Services\KnowledgeContextService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -168,6 +170,66 @@ class TerminalApiController extends Controller
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/terminal/documents/{document}/content
|
||||
* 读取文档全文或指定行号区间
|
||||
*/
|
||||
public function documentContent(Request $request, int $documentId): JsonResponse
|
||||
{
|
||||
$request->validate([
|
||||
'start_line' => 'sometimes|integer|min:1',
|
||||
'end_line' => 'sometimes|integer|min:1',
|
||||
]);
|
||||
|
||||
$terminal = $request->attributes->get('terminal');
|
||||
|
||||
// Find document and verify access through station → knowledge_base
|
||||
$accessibleKbIds = KnowledgeBase::where(function ($q) use ($terminal) {
|
||||
$q->whereDoesntHave('stations'); // global knowledge bases
|
||||
if ($terminal->station_id) {
|
||||
$q->orWhereHas('stations', fn ($sq) => $sq->where('stations.id', $terminal->station_id));
|
||||
}
|
||||
})->where('status', 'active')->pluck('id');
|
||||
|
||||
$document = Document::where('id', $documentId)
|
||||
->whereIn('knowledge_base_id', $accessibleKbIds)
|
||||
->where('conversion_status', 'completed')
|
||||
->first();
|
||||
|
||||
if (!$document) {
|
||||
return response()->json(['error' => 'Document not found'], 404);
|
||||
}
|
||||
|
||||
$content = $document->getMarkdownContent();
|
||||
if ($content === null) {
|
||||
return response()->json(['error' => 'Document content unavailable'], 404);
|
||||
}
|
||||
|
||||
$lines = explode("\n", $content);
|
||||
$totalLines = count($lines);
|
||||
|
||||
$startLine = $request->integer('start_line', 1);
|
||||
$endLine = $request->integer('end_line', min($startLine + 49, $totalLines));
|
||||
$endLine = min($endLine, $totalLines);
|
||||
|
||||
if ($startLine > $totalLines) {
|
||||
return response()->json([
|
||||
'error' => "start_line ({$startLine}) exceeds total lines ({$totalLines})",
|
||||
], 422);
|
||||
}
|
||||
|
||||
$slice = array_slice($lines, $startLine - 1, $endLine - $startLine + 1);
|
||||
|
||||
return response()->json([
|
||||
'id' => $document->id,
|
||||
'title' => $document->title,
|
||||
'total_lines' => $totalLines,
|
||||
'start_line' => $startLine,
|
||||
'end_line' => $endLine,
|
||||
'content' => implode("\n", $slice),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/terminal/heartbeat
|
||||
* 终端心跳上报
|
||||
|
||||
@@ -37,9 +37,12 @@ class KnowledgeContextService
|
||||
}
|
||||
|
||||
$context .= $snippet . "\n\n";
|
||||
|
||||
$fullContent = $document->getMarkdownContent() ?? '';
|
||||
$sources[] = [
|
||||
'title' => $document->title,
|
||||
'id' => 'kb-doc-' . str_pad($document->id, 3, '0', STR_PAD_LEFT),
|
||||
'id' => $document->id,
|
||||
'total_lines' => $fullContent !== '' ? substr_count($fullContent, "\n") + 1 : 0,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -52,11 +55,12 @@ class KnowledgeContextService
|
||||
private function extractSnippet($document): string
|
||||
{
|
||||
$content = $document->getMarkdownContent() ?? $document->description ?? '';
|
||||
$header = "【{$document->title}】(ID:{$document->id})";
|
||||
|
||||
if (mb_strlen($content) <= 500) {
|
||||
return "【{$document->title}】\n{$content}";
|
||||
return "{$header}\n{$content}";
|
||||
}
|
||||
|
||||
return "【{$document->title}】\n" . mb_substr($content, 0, 500) . '...';
|
||||
return "{$header}\n" . mb_substr($content, 0, 500) . '...';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,12 +4,15 @@ use App\Http\Controllers\Api\TerminalApiController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::middleware('identify.terminal')->group(function () {
|
||||
Route::get('/knowledge', [TerminalApiController::class, 'knowledge']);
|
||||
|
||||
Route::prefix('terminal')->group(function () {
|
||||
Route::post('/heartbeat', [TerminalApiController::class, 'heartbeat']);
|
||||
|
||||
Route::get('/config', [TerminalApiController::class, 'config']);
|
||||
|
||||
Route::get('/guides', [TerminalApiController::class, 'guides']);
|
||||
Route::post('/guides/pages', [TerminalApiController::class, 'guidePages']);
|
||||
Route::post('/heartbeat', [TerminalApiController::class, 'heartbeat']);
|
||||
|
||||
Route::get('/knowledge', [TerminalApiController::class, 'knowledge']);
|
||||
Route::get('/documents/{document}/content', [TerminalApiController::class, 'documentContent']);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user