Protokoll #4814
| ID | 4814 |
|---|---|
| Zeitstempel | 2025-12-22 15:21:36.619380 |
| Client | root |
| IP | Warning: Undefined array key "request_ip" in /var/www/dev.campus.systemische-tools.de/src/View/protokoll/show.php on line 13 Deprecated: htmlspecialchars(): Passing null to parameter #1 ($string) of type string is deprecated in /var/www/dev.campus.systemische-tools.de/src/View/protokoll/show.php on line 13 |
| Modell | claude-sonnet-4-20250514 |
| Status | completed |
| Tokens | 5,268 (Input: 0, Output: 0) |
| Dauer | 89 ms |
| Request-Zeit | Warning: Undefined array key "request_timestamp" in /var/www/dev.campus.systemische-tools.de/src/View/protokoll/show.php on line 18 |
| Response-Zeit | - |
Warning: Undefined array key "error_message" in /var/www/dev.campus.systemische-tools.de/src/View/protokoll/show.php on line 22
Request
{
"event": "PreToolUse",
"tool_name": "Edit",
"tool_input": {
"file_path": "\/var\/www\/dev.campus.systemische-tools.de\/src\/Controller\/ContentPipelineController.php",
"old_string": " private function createDefaultSteps(int $pipelineId): void\n {\n $defaultSteps = [\n ['step_type' => 'detect', 'config' => ['hash_algorithm' => 'sha256'], 'sort_order' => 1, 'enabled' => 1],\n ['step_type' => 'extract', 'config' => ['ocr_enabled' => true, 'ocr_language' => 'deu'], 'sort_order' => 2, 'enabled' => 1],\n ['step_type' => 'chunk', 'config' => ['min_size' => 100, 'max_size' => 2000, 'overlap' => 0.1], 'sort_order' => 3, 'enabled' => 1],\n ['step_type' => 'embed', 'config' => ['model' => 'mxbai-embed-large', 'collection' => 'documents', 'dimensions' => 1024], 'sort_order' => 4, 'enabled' => 1],\n ['step_type' => 'analyze', 'config' => ['extract_entities' => true, 'extract_relations' => true, 'classify_taxonomy' => true], 'sort_order' => 5, 'enabled' => 0],\n ];\n\n foreach ($defaultSteps as $step) {\n $this->repository->addStep($pipelineId, $step);\n }\n }\n}",
"new_string": " private function createDefaultSteps(int $pipelineId): void\n {\n $defaultSteps = [\n ['step_type' => 'detect', 'config' => ['hash_algorithm' => 'sha256'], 'sort_order' => 1, 'enabled' => 1],\n ['step_type' => 'extract', 'config' => ['ocr_enabled' => true, 'ocr_language' => 'deu'], 'sort_order' => 2, 'enabled' => 1],\n ['step_type' => 'chunk', 'config' => ['min_size' => 100, 'max_size' => 2000, 'overlap' => 0.1], 'sort_order' => 3, 'enabled' => 1],\n ['step_type' => 'embed', 'config' => ['model' => 'mxbai-embed-large', 'collection' => 'documents', 'dimensions' => 1024], 'sort_order' => 4, 'enabled' => 1],\n ['step_type' => 'analyze', 'config' => ['extract_entities' => true, 'extract_relations' => true, 'classify_taxonomy' => true], 'sort_order' => 5, 'enabled' => 0],\n ];\n\n foreach ($defaultSteps as $step) {\n $this->repository->addStep($pipelineId, $step);\n }\n }\n\n \/**\n * Get available Qdrant collections.\n *\n * @return array<string, string>\n *\/\n private function getAvailableCollections(): array\n {\n return [\n 'documents' => 'Documents (Schulungsunterlagen)',\n 'mail' => 'Mail (E-Mails)',\n 'entities' => 'Entities (Entitäten)',\n 'knowledge' => 'Knowledge (Wissensbasis)',\n ];\n }\n\n \/**\n * POST \/content-pipeline\/{id}\/steps\/{stepId}\/collection (AJAX)\n * Update step collection configuration\n *\/\n public function updateStepCollection(string $id, string $stepId): void\n {\n $pipeline = $this->repository->findById((int) $id);\n\n if ($pipeline === null) {\n $this->json(['error' => 'Pipeline nicht gefunden'], 404);\n\n return;\n }\n\n $collection = trim($_POST['collection'] ?? '');\n $validCollections = array_keys($this->getAvailableCollections());\n\n if ($collection === '' || !in_array($collection, $validCollections, true)) {\n $this->json(['error' => 'Ungültige Collection'], 400);\n\n return;\n }\n\n \/\/ Find step\n $stepFound = false;\n foreach ($pipeline['steps'] as $step) {\n if ((int) $step['id'] === (int) $stepId) {\n $stepFound = true;\n $config = $step['config'] ?? [];\n $config['collection'] = $collection;\n\n $this->repository->updateStep((int) $stepId, [\n 'config' => $config,\n ]);\n break;\n }\n }\n\n if (!$stepFound) {\n $this->json(['error' => 'Schritt nicht gefunden'], 404);\n\n return;\n }\n\n $this->json([\n 'success' => true,\n 'collection' => $collection,\n 'label' => $this->getAvailableCollections()[$collection] ?? $collection,\n ]);\n }\n}"
}
}
Response
{
"tool_response": {
"filePath": "\/var\/www\/dev.campus.systemische-tools.de\/src\/Controller\/ContentPipelineController.php",
"oldString": " private function createDefaultSteps(int $pipelineId): void\n {\n $defaultSteps = [\n ['step_type' => 'detect', 'config' => ['hash_algorithm' => 'sha256'], 'sort_order' => 1, 'enabled' => 1],\n ['step_type' => 'extract', 'config' => ['ocr_enabled' => true, 'ocr_language' => 'deu'], 'sort_order' => 2, 'enabled' => 1],\n ['step_type' => 'chunk', 'config' => ['min_size' => 100, 'max_size' => 2000, 'overlap' => 0.1], 'sort_order' => 3, 'enabled' => 1],\n ['step_type' => 'embed', 'config' => ['model' => 'mxbai-embed-large', 'collection' => 'documents', 'dimensions' => 1024], 'sort_order' => 4, 'enabled' => 1],\n ['step_type' => 'analyze', 'config' => ['extract_entities' => true, 'extract_relations' => true, 'classify_taxonomy' => true], 'sort_order' => 5, 'enabled' => 0],\n ];\n\n foreach ($defaultSteps as $step) {\n $this->repository->addStep($pipelineId, $step);\n }\n }\n}",
"newString": " private function createDefaultSteps(int $pipelineId): void\n {\n $defaultSteps = [\n ['step_type' => 'detect', 'config' => ['hash_algorithm' => 'sha256'], 'sort_order' => 1, 'enabled' => 1],\n ['step_type' => 'extract', 'config' => ['ocr_enabled' => true, 'ocr_language' => 'deu'], 'sort_order' => 2, 'enabled' => 1],\n ['step_type' => 'chunk', 'config' => ['min_size' => 100, 'max_size' => 2000, 'overlap' => 0.1], 'sort_order' => 3, 'enabled' => 1],\n ['step_type' => 'embed', 'config' => ['model' => 'mxbai-embed-large', 'collection' => 'documents', 'dimensions' => 1024], 'sort_order' => 4, 'enabled' => 1],\n ['step_type' => 'analyze', 'config' => ['extract_entities' => true, 'extract_relations' => true, 'classify_taxonomy' => true], 'sort_order' => 5, 'enabled' => 0],\n ];\n\n foreach ($defaultSteps as $step) {\n $this->repository->addStep($pipelineId, $step);\n }\n }\n\n \/**\n * Get available Qdrant collections.\n *\n * @return array<string, string>\n *\/\n private function getAvailableCollections(): array\n {\n return [\n 'documents' => 'Documents (Schulungsunterlagen)',\n 'mail' => 'Mail (E-Mails)',\n 'entities' => 'Entities (Entitäten)',\n 'knowledge' => 'Knowledge (Wissensbasis)',\n ];\n }\n\n \/**\n * POST \/content-pipeline\/{id}\/steps\/{stepId}\/collection (AJAX)\n * Update step collection configuration\n *\/\n public function updateStepCollection(string $id, string $stepId): void\n {\n $pipeline = $this->repository->findById((int) $id);\n\n if ($pipeline === null) {\n $this->json(['error' => 'Pipeline nicht gefunden'], 404);\n\n return;\n }\n\n $collection = trim($_POST['collection'] ?? '');\n $validCollections = array_keys($this->getAvailableCollections());\n\n if ($collection === '' || !in_array($collection, $validCollections, true)) {\n $this->json(['error' => 'Ungültige Collection'], 400);\n\n return;\n }\n\n \/\/ Find step\n $stepFound = false;\n foreach ($pipeline['steps'] as $step) {\n if ((int) $step['id'] === (int) $stepId) {\n $stepFound = true;\n $config = $step['config'] ?? [];\n $config['collection'] = $collection;\n\n $this->repository->updateStep((int) $stepId, [\n 'config' => $config,\n ]);\n break;\n }\n }\n\n if (!$stepFound) {\n $this->json(['error' => 'Schritt nicht gefunden'], 404);\n\n return;\n }\n\n $this->json([\n 'success' => true,\n 'collection' => $collection,\n 'label' => $this->getAvailableCollections()[$collection] ?? $collection,\n ]);\n }\n}",
"originalFile": "<?php\n\nnamespace Controller;\n\nuse Framework\\Controller;\nuse Infrastructure\\AI\\ModelConfig;\nuse Infrastructure\\Persistence\\PipelineRepository;\n\nclass ContentPipelineController extends Controller\n{\n private PipelineRepository $repository;\n\n public function __construct()\n {\n $this->repository = new PipelineRepository();\n }\n\n \/**\n * GET \/content-pipeline\n *\/\n public function index(): void\n {\n $pipelines = $this->repository->findAll();\n $stats = $this->repository->getStatistics();\n\n $this->view('content-pipeline.index', [\n 'title' => 'Content Pipeline',\n 'pipelines' => $pipelines,\n 'stats' => $stats,\n ]);\n }\n\n \/**\n * GET \/content-pipeline\/import\n *\/\n public function import(): void\n {\n $pipeline = $this->repository->findDefault();\n\n if ($pipeline === null) {\n $pipelines = $this->repository->findAll(1);\n $pipeline = $pipelines[0] ?? null;\n }\n\n $latestRun = $pipeline !== null\n ? $this->repository->findLatestRun((int) $pipeline['id'])\n : null;\n\n $this->view('content-pipeline.import', [\n 'title' => 'Import Pipeline',\n 'pipeline' => $pipeline,\n 'latestRun' => $latestRun,\n ]);\n }\n\n \/**\n * GET \/content-pipeline\/new\n *\/\n public function pipelineNew(): void\n {\n $this->view('content-pipeline.form', [\n 'title' => 'Neue Pipeline',\n 'pipeline' => null,\n 'stepTypes' => $this->getStepTypes(),\n ]);\n }\n\n \/**\n * GET \/content-pipeline\/{id}\n *\/\n public function show(string $id): void\n {\n $pipeline = $this->repository->findById((int) $id);\n\n if ($pipeline === null) {\n $this->notFound('Pipeline nicht gefunden');\n }\n\n $runs = $this->repository->findRuns((int) $id, 10);\n\n $this->view('content-pipeline.show', [\n 'title' => 'Pipeline: ' . $pipeline['name'],\n 'pipeline' => $pipeline,\n 'runs' => $runs,\n 'stepTypes' => $this->getStepTypes(),\n 'models' => ModelConfig::getAll(),\n 'defaultModel' => ModelConfig::DEFAULT_MODEL,\n 'collections' => $this->getAvailableCollections(),\n ]);\n }\n\n \/**\n * GET \/content-pipeline\/{id}\/edit\n *\/\n public function edit(string $id): void\n {\n $pipeline = $this->repository->findById((int) $id);\n\n if ($pipeline === null) {\n $this->notFound('Pipeline nicht gefunden');\n }\n\n $this->view('content-pipeline.form', [\n 'title' => 'Pipeline bearbeiten: ' . $pipeline['name'],\n 'pipeline' => $pipeline,\n 'stepTypes' => $this->getStepTypes(),\n ]);\n }\n\n \/**\n * POST \/content-pipeline\n *\/\n public function store(): void\n {\n $this->requireCsrf();\n\n $name = trim($_POST['name'] ?? '');\n $description = trim($_POST['description'] ?? '');\n $sourcePath = trim($_POST['source_path'] ?? '\/var\/www\/nextcloud\/data\/root\/files\/Documents');\n $extensions = $this->parseExtensions($_POST['extensions'] ?? '');\n $isDefault = isset($_POST['is_default']) ? 1 : 0;\n\n if ($name === '') {\n $_SESSION['error'] = 'Name ist erforderlich.';\n header('Location: \/content-pipeline\/new');\n exit;\n }\n\n $pipelineId = $this->repository->create([\n 'name' => $name,\n 'description' => $description,\n 'source_path' => $sourcePath,\n 'extensions' => $extensions,\n 'is_default' => $isDefault,\n ]);\n\n \/\/ Standard-Steps hinzufuegen\n $this->createDefaultSteps($pipelineId);\n\n $_SESSION['success'] = 'Pipeline erfolgreich erstellt.';\n header('Location: \/content-pipeline\/' . $pipelineId);\n exit;\n }\n\n \/**\n * POST \/content-pipeline\/{id}\n *\/\n public function update(string $id): void\n {\n $this->requireCsrf();\n\n $pipeline = $this->repository->findById((int) $id);\n\n if ($pipeline === null) {\n $this->notFound('Pipeline nicht gefunden');\n }\n\n $name = trim($_POST['name'] ?? '');\n $description = trim($_POST['description'] ?? '');\n $sourcePath = trim($_POST['source_path'] ?? '');\n $extensions = $this->parseExtensions($_POST['extensions'] ?? '');\n $isDefault = isset($_POST['is_default']) ? 1 : 0;\n\n if ($name === '') {\n $_SESSION['error'] = 'Name ist erforderlich.';\n header('Location: \/content-pipeline\/' . $id . '\/edit');\n exit;\n }\n\n $this->repository->update((int) $id, [\n 'name' => $name,\n 'description' => $description,\n 'source_path' => $sourcePath,\n 'extensions' => $extensions,\n 'is_default' => $isDefault,\n ]);\n\n $_SESSION['success'] = 'Pipeline aktualisiert.';\n header('Location: \/content-pipeline\/' . $id);\n exit;\n }\n\n \/**\n * POST \/content-pipeline\/{id}\/run\n *\/\n public function run(string $id): void\n {\n $this->requireCsrf();\n\n $pipeline = $this->repository->findById((int) $id);\n\n if ($pipeline === null) {\n $this->notFound('Pipeline nicht gefunden');\n }\n\n \/\/ Neuen Run erstellen\n $runId = $this->repository->createRun((int) $id);\n\n \/\/ Pipeline im Hintergrund starten\n $pipelineScript = '\/opt\/scripts\/pipeline\/pipeline.py';\n $venvPython = '\/opt\/scripts\/pipeline\/venv\/bin\/python';\n $logFile = '\/tmp\/pipeline_run_' . $runId . '.log';\n\n $cmd = sprintf(\n 'nohup %s %s all --pipeline-id=%d --run-id=%d > %s 2>&1 &',\n escapeshellarg($venvPython),\n escapeshellarg($pipelineScript),\n (int) $id,\n $runId,\n escapeshellarg($logFile)\n );\n\n exec($cmd);\n\n $_SESSION['success'] = 'Pipeline gestartet (Run #' . $runId . ')';\n header('Location: \/content-pipeline\/' . $id);\n exit;\n }\n\n \/**\n * GET \/content-pipeline\/{id}\/status\n * AJAX endpoint for run status\n *\/\n public function status(string $id): void\n {\n $pipeline = $this->repository->findById((int) $id);\n\n if ($pipeline === null) {\n $this->json(['error' => 'Pipeline nicht gefunden'], 404);\n\n return;\n }\n\n $latestRun = $this->repository->findLatestRun((int) $id);\n\n $this->json([\n 'pipeline_id' => (int) $id,\n 'run' => $latestRun,\n ]);\n }\n\n \/**\n * POST \/content-pipeline\/{id}\/steps\/{stepId}\/toggle\n *\/\n public function toggleStep(string $id, string $stepId): void\n {\n $this->requireCsrf();\n\n $pipeline = $this->repository->findById((int) $id);\n\n if ($pipeline === null) {\n $this->notFound('Pipeline nicht gefunden');\n }\n\n \/\/ Find step and toggle\n foreach ($pipeline['steps'] as $step) {\n if ((int) $step['id'] === (int) $stepId) {\n $this->repository->updateStep((int) $stepId, [\n 'enabled' => $step['enabled'] ? 0 : 1,\n ]);\n break;\n }\n }\n\n header('Location: \/content-pipeline\/' . $id);\n exit;\n }\n\n \/**\n * POST \/content-pipeline\/{id}\/steps\/{stepId}\/model (AJAX)\n * Update step model configuration\n *\/\n public function updateStepModel(string $id, string $stepId): void\n {\n $pipeline = $this->repository->findById((int) $id);\n\n if ($pipeline === null) {\n $this->json(['error' => 'Pipeline nicht gefunden'], 404);\n\n return;\n }\n\n $model = trim($_POST['model'] ?? '');\n\n if ($model === '' || !ModelConfig::isValid($model)) {\n $this->json(['error' => 'Ungültiges Modell'], 400);\n\n return;\n }\n\n \/\/ Find step\n $stepFound = false;\n foreach ($pipeline['steps'] as $step) {\n if ((int) $step['id'] === (int) $stepId) {\n $stepFound = true;\n $config = $step['config'] ?? [];\n\n \/\/ Determine provider from model\n $provider = ModelConfig::isLocal($model) ? 'ollama' : 'anthropic';\n\n \/\/ Update config with new model\n $config['model'] = ModelConfig::isLocal($model)\n ? substr($model, 7) \/\/ Remove 'ollama:' prefix\n : $model;\n $config['provider'] = $provider;\n\n $this->repository->updateStep((int) $stepId, [\n 'config' => $config,\n ]);\n break;\n }\n }\n\n if (!$stepFound) {\n $this->json(['error' => 'Schritt nicht gefunden'], 404);\n\n return;\n }\n\n $this->json([\n 'success' => true,\n 'model' => $model,\n 'label' => ModelConfig::getLabel($model),\n ]);\n }\n\n \/**\n * POST \/content-pipeline\/{id}\/delete\n *\/\n public function delete(string $id): void\n {\n $this->requireCsrf();\n\n $pipeline = $this->repository->findById((int) $id);\n\n if ($pipeline === null) {\n $this->notFound('Pipeline nicht gefunden');\n }\n\n $this->repository->delete((int) $id);\n\n $_SESSION['success'] = 'Pipeline geloescht.';\n header('Location: \/content-pipeline');\n exit;\n }\n\n \/**\n * @return array<string, array<string, mixed>>\n *\/\n private function getStepTypes(): array\n {\n return [\n \/\/ Phase 1: Vorverarbeitung\n 'detect' => [\n 'label' => 'Erkennung',\n 'description' => 'Dateien scannen und Format prüfen',\n 'phase' => 'Vorverarbeitung',\n 'storage' => null,\n ],\n 'validate' ... [TRUNCATED-f3550bdb99edc80f]",
"structuredPatch": [
{
"oldStart": 562,
"oldLines": 4,
"newStart": 562,
"newLines": 70,
"lines": [
" $this->repository->addStep($pipelineId, $step);",
" }",
" }",
"+",
"+ \/**",
"+ * Get available Qdrant collections.",
"+ *",
"+ * @return array<string, string>",
"+ *\/",
"+ private function getAvailableCollections(): array",
"+ {",
"+ return [",
"+ 'documents' => 'Documents (Schulungsunterlagen)',",
"+ 'mail' => 'Mail (E-Mails)',",
"+ 'entities' => 'Entities (Entitäten)',",
"+ 'knowledge' => 'Knowledge (Wissensbasis)',",
"+ ];",
"+ }",
"+",
"+ \/**",
"+ * POST \/content-pipeline\/{id}\/steps\/{stepId}\/collection (AJAX)",
"+ * Update step collection configuration",
"+ *\/",
"+ public function updateStepCollection(string $id, string $stepId): void",
"+ {",
"+ $pipeline = $this->repository->findById((int) $id);",
"+",
"+ if ($pipeline === null) {",
"+ $this->json(['error' => 'Pipeline nicht gefunden'], 404);",
"+",
"+ return;",
"+ }",
"+",
"+ $collection = trim($_POST['collection'] ?? '');",
"+ $validCollections = array_keys($this->getAvailableCollections());",
"+",
"+ if ($collection === '' || !in_array($collection, $validCollections, true)) {",
"+ $this->json(['error' => 'Ungültige Collection'], 400);",
"+",
"+ return;",
"+ }",
"+",
"+ \/\/ Find step",
"+ $stepFound = false;",
"+ foreach ($pipeline['steps'] as $step) {",
"+ if ((int) $step['id'] === (int) $stepId) {",
"+ $stepFound = true;",
"+ $config = $step['config'] ?? [];",
"+ $config['collection'] = $collection;",
"+",
"+ $this->repository->updateStep((int) $stepId, [",
"+ 'config' => $config,",
"+ ]);",
"+ break;",
"+ }",
"+ }",
"+",
"+ if (!$stepFound) {",
"+ $this->json(['error' => 'Schritt nicht gefunden'], 404);",
"+",
"+ return;",
"+ }",
"+",
"+ $this->json([",
"+ 'success' => true,",
"+ 'collection' => $collection,",
"+ 'label' => $this->getAvailableCollections()[$collection] ?? $collection,",
"+ ]);",
"+ }",
" }"
]
}
],
"userModified": false,
"replaceAll": false
}
}