Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 69 additions & 19 deletions Classes/Controller/GenerateController.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
use Neos\Eel\FlowQuery\FlowQuery;
use Neos\Eel\Utility;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\RequestException;
use JvMTECH\AIToolkit\ModelHandlers\ModelHandlerFactory;
use JvMTECH\AIToolkit\ModelConnectors\ModelConnectorFactory;
use JvMTECH\AIToolkit\Traits\RequestArgumentsTrait;
Expand Down Expand Up @@ -170,28 +172,76 @@ protected function getNodeWithContextPath($contextPath)
}

/**
* @throws \GuzzleHttp\Exception\GuzzleException
* Fetch document HTML with error handling
*
* @param string $url The URL to fetch
* @param array $cookies Cookies to send with the request
* @return string The HTML content, or empty string on error
*/
protected function fetchDocumentHtml($url, $cookies): string
{
$client = new Client(
array_merge(
[
'cookies' => true
],
$this->configuration['backendRequest']['auth'] ? ['auth' => $this->configuration['backendRequest']['auth']] : []
)
);

$response = $client->get($url, [
'headers' => [
'Cookie' => implode('; ', array_map(fn($key, $value) => "$key=$value", array_keys($cookies), $cookies)),
]
]);

$html = $response->getBody()->getContents();

return $html;
try {
$client = new Client(
array_merge(
[
'cookies' => true,
'timeout' => 30,
'connect_timeout' => 10,
'http_errors' => false, // Don't throw exceptions on 4xx/5xx responses
],
$this->configuration['backendRequest']['auth'] ? ['auth' => $this->configuration['backendRequest']['auth']] : []
)
);

$response = $client->get($url, [
'headers' => [
'Cookie' => implode('; ', array_map(fn($key, $value) => "$key=$value", array_keys($cookies), $cookies)),
]
]);

$statusCode = $response->getStatusCode();

// Only return content for successful responses (2xx)
if ($statusCode >= 200 && $statusCode < 300) {
return $response->getBody()->getContents();
}

// Log non-success responses
$this->logger->warning(sprintf(
'AI Toolkit: Failed to fetch document HTML - HTTP %d from %s',
$statusCode,
$url
));

return '';

} catch (ConnectException $e) {
// Connection errors (DNS failure, timeout, connection refused, etc.)
$this->logger->error(sprintf(
'AI Toolkit: Connection error fetching document HTML from %s: %s',
$url,
$e->getMessage()
));
return '';

} catch (RequestException $e) {
// Other HTTP request errors
$this->logger->error(sprintf(
'AI Toolkit: Request error fetching document HTML from %s: %s',
$url,
$e->getMessage()
));
return '';

} catch (\Exception $e) {
// Catch any other unexpected errors
$this->logger->error(sprintf(
'AI Toolkit: Unexpected error fetching document HTML from %s: %s',
$url,
$e->getMessage()
));
return '';
}
}

/**
Expand Down
36 changes: 31 additions & 5 deletions Classes/Controller/PageController.php
Original file line number Diff line number Diff line change
@@ -1,21 +1,47 @@
<?php
namespace JvMTECH\AIToolkit\Controller;

use Neos\Flow\Annotations as Flow;
use Neos\ContentRepository\Core\Projection\ContentGraph\Node;
use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry;
use Neos\Eel\FlowQuery\FlowQuery;
use Neos\Flow\Annotations as Flow;
use Neos\Flow\Mvc\Controller\ActionController;
use Neos\Flow\Mvc\Exception\StopActionException;
use Neos\Flow\Property\PropertyMapper;
use Neos\Neos\FrontendRouting\SiteDetection\SiteDetectionResult;

class PageController extends ActionController
{
#[Flow\Inject(lazy: false)]
protected ContentRepositoryRegistry $contentRepositoryRegistry;

/**
* @param Node $node
* Neos 9 compatibility: Node is passed as NodeAddress JSON string
* This action finds the document node and renders its preview
*
* @param string $node NodeAddress as JSON string
* @throws StopActionException
*/
public function renderPreviewPageAction(Node $node): void
public function renderPreviewPageAction(string $node): void
{
// Convert NodeAddress JSON string to Node object
$propertyMapper = $this->objectManager->get(PropertyMapper::class);
$contentNode = $propertyMapper->convert($node, Node::class);

// Find the document node (content nodes need their parent document)
$currentContentRepositoryId = SiteDetectionResult::fromRequest($this->request->getHttpRequest())->contentRepositoryId;
$currentContentRepository = $this->contentRepositoryRegistry->get($currentContentRepositoryId);

$q = new FlowQuery([$contentNode]);
$documentNode = $currentContentRepository->getNodeTypeManager()
->getNodeType($contentNode->nodeTypeName)
->isOfType('Neos.Neos:Document')
? $contentNode
: $q->closest('[instanceof Neos.Neos:Document]')->get(0);

// Forward to preview with document node
$this->forward('preview', 'Frontend\Node', 'Neos.Neos', [
'node' => $node,
'node' => $documentNode,
]);
}
}
}
2 changes: 2 additions & 0 deletions Resources/Private/Scripts/Common/Helpers.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
export default class Helpers {
static getDocumentContentUrl = (location, nodeContextPath) => {
const port = location.port ? `:${location.port}` : '';
return (
location.protocol +
"//" +
location.hostname +
port +
"/ai-toolkit/page/renderPreviewPage?node=" +
encodeURIComponent(nodeContextPath)
);
Expand Down
3 changes: 2 additions & 1 deletion Resources/Public/TextAreaEditor/Plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -538,7 +538,8 @@
Helpers = class {
};
Helpers.getDocumentContentUrl = (location, nodeContextPath) => {
return location.protocol + "//" + location.hostname + "/ai-toolkit/page/renderPreviewPage?node=" + encodeURIComponent(nodeContextPath);
const port = location.port ? `:${location.port}` : '';
return location.protocol + "//" + location.hostname + port + "/ai-toolkit/page/renderPreviewPage?node=" + encodeURIComponent(nodeContextPath);
};
Helpers.getDocumentContent = async (documentContentUrl) => {
return await fetch(documentContentUrl).then((response) => {
Expand Down
3 changes: 2 additions & 1 deletion Resources/Public/TextFieldEditor/Plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,8 @@
Helpers = class {
};
Helpers.getDocumentContentUrl = (location, nodeContextPath) => {
return location.protocol + "//" + location.hostname + "/ai-toolkit/page/renderPreviewPage?node=" + encodeURIComponent(nodeContextPath);
const port = location.port ? `:${location.port}` : '';
return location.protocol + "//" + location.hostname + port + "/ai-toolkit/page/renderPreviewPage?node=" + encodeURIComponent(nodeContextPath);
};
Helpers.getDocumentContent = async (documentContentUrl) => {
return await fetch(documentContentUrl).then((response) => {
Expand Down