PluginProbe
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! / trunk
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! vtrunk
3.8.0 3.7.5 3.7.4 3.7.3 3.7.2 1-final 3.7.1 3.7.0 3.6.8 3.6.7 3.6.6 3.6.5 3.6.4 3.6.3 3.6.2 3.6.1 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 All 112 releases
templately / modules / full-site-import / Utils / AIContentResolver.php

AIContentResolver.php in Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! trunk, at modules/full-site-import/Utils/AIContentResolver.php

166 lines 6.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Templately\Modules\FullSiteImport\Utils;
4
5 use Templately\Modules\FullSiteImport\Utils\Providers\ChatAIContentProvider;
6 use Templately\Modules\FullSiteImport\Utils\Providers\ClassicAIContentProvider;
7 use Templately\Utils\Helper;
8
9 /**
10 * Central, source-agnostic seam for making an AI-generated page's `.ai.json`
11 * available at finalize time.
12 *
13 * The Finalizer no longer knows *how* a page's AI content arrives. It calls
14 * {@see AIContentResolver::ensure_page_ready()} for every AI page; each AI
15 * content "source" (the classic per-page `ai-update` callback flow, the chat-id
16 * pull flow, and any future source) registers a provider on the
17 * `templately_ai_stage_page` filter. A provider that owns the current process
18 * pulls/writes the missing `.ai.json` and returns `true`; otherwise the shared
19 * SSE-wait/timeout runs — identical behaviour for every source.
20 *
21 * Extending in the future is additive and needs no core edit:
22 * add_filter( AIContentResolver::STAGE_HOOK, [ MyProvider::class, 'stage' ], 10, 2 );
23 * (optionally from a `templately_register_ai_content_providers` action listener).
24 */
25 class AIContentResolver {
26
27 /**
28 * Filter run for each AI page that still needs its `.ai.json`.
29 *
30 * @param bool $staged Whether a provider has already produced the file.
31 * @param array $context See {@see ensure_page_ready()} for the shape.
32 */
33 const STAGE_HOOK = 'templately_ai_stage_page';
34
35 /**
36 * Action fired once, right before the first stage dispatch, so external
37 * modules can register additional providers without touching core.
38 */
39 const REGISTER_HOOK = 'templately_register_ai_content_providers';
40
41 /**
42 * @var bool Guards one-time registration of the built-in providers.
43 */
44 private static $booted = false;
45
46 /**
47 * Register the built-in AI content providers exactly once, then let external
48 * code add its own. Both shipped AI-content versions hook in here.
49 *
50 * @return void
51 */
52 public static function boot_default_providers() {
53 if ( self::$booted ) {
54 return;
55 }
56 self::$booted = true;
57
58 add_filter( self::STAGE_HOOK, [ ClassicAIContentProvider::class, 'stage' ], 10, 2 );
59 add_filter( self::STAGE_HOOK, [ ChatAIContentProvider::class, 'stage' ], 10, 2 );
60
61 do_action( self::REGISTER_HOOK );
62 }
63
64 /**
65 * Ensure the `.ai.json` for `$context['content_id']` is on disk, pulling it
66 * via whichever source owns this process, then (if still absent) SSE-waiting
67 * with timeout.
68 *
69 * @param array $context {
70 * @type string $session_id Import session id.
71 * @type string|null $process_id AI process id (keys process/progress data).
72 * @type string|int $content_id The AI page id being finalized.
73 * @type array $ai_page_ids `type/sub_type => [content_id,...]` map.
74 * @type array $updated_ids `templately_ai_processed_pages[process_id]` snapshot.
75 * @type callable $sse_callback Callback used to emit the SSE `wait` message.
76 * @type array $additional_sse_data Extra fields merged into the SSE `wait` payload.
77 * @type string $progress_id Progress bucket key (default `ai_content_time`).
78 * @type int $timeout Wait timeout in seconds (default 420).
79 * }
80 * @return bool True to continue finalizing the page (file ready or timed out).
81 * Note: the shared wait handler may `exit()` to stream a `wait`.
82 */
83 public static function ensure_page_ready( array $context ): bool {
84 self::boot_default_providers();
85
86 $process_id = $context['process_id'] ?? null;
87 $process_data = ! empty( $process_id ) ? AIUtils::get_ai_process_data_by_process_id( $process_id ) : null;
88 $context['process_data'] = is_array( $process_data ) ? $process_data : [];
89
90 // Give the owning source a chance to stage (pull + write) the page.
91 $staged = apply_filters( self::STAGE_HOOK, false, $context );
92 if ( $staged === true ) {
93 return true;
94 }
95
96 // Re-read the progress counters. The caller snapshots `updated_ids` BEFORE
97 // calling us (Finalizer.php), but a provider may have just written several
98 // pages — using the stale snapshot would under-report progress to the wait.
99 if ( ! empty( $process_id ) ) {
100 $processed_pages = get_option( 'templately_ai_processed_pages', [] );
101 $context['updated_ids'] = ( isset( $processed_pages[ $process_id ] ) && is_array( $processed_pages[ $process_id ] ) )
102 ? $processed_pages[ $process_id ]
103 : ( $context['updated_ids'] ?? [] );
104 }
105
106 // No source produced the page yet → the shared SSE-wait/timeout, which
107 // behaves identically regardless of where the content ultimately comes
108 // from. This can `exit()` after emitting a `wait` message.
109 return AIUtils::handle_sse_wait_with_timeout(
110 $context['session_id'],
111 $context['progress_id'] ?? 'ai_content_time',
112 $context['updated_ids'] ?? [],
113 AIUtils::flatten_ai_page_ids( $context['ai_page_ids'] ?? [] ),
114 $context['sse_callback'],
115 $context['additional_sse_data'] ?? [],
116 $context['content_id'] ?? null,
117 $context['timeout'] ?? 420
118 );
119 }
120
121 /**
122 * Flatten the `type/sub_type => [content_id,...]` map into a single list of
123 * page ids.
124 *
125 * @deprecated Use {@see AIUtils::flatten_ai_page_ids()} — kept as a thin
126 * delegate so existing provider/extension code keeps working.
127 *
128 * @param mixed $ai_page_ids Nested map, JSON string, or an already-flat list.
129 * @return array Flat list of content-id strings.
130 */
131 public static function flatten_page_ids( $ai_page_ids ): array {
132 return AIUtils::flatten_ai_page_ids( $ai_page_ids );
133 }
134
135 /**
136 * Whether the `.ai.json` for the context's page now exists on disk. Providers
137 * call this after a pull attempt to report success back to the resolver.
138 *
139 * @param array $context The same context passed to {@see ensure_page_ready()}.
140 * @return bool
141 */
142 public static function page_staged( array $context ): bool {
143 $session_id = $context['session_id'] ?? '';
144 $content_id = $context['content_id'] ?? null;
145 $ai_page_ids = AIUtils::normalize_ai_page_ids( $context['ai_page_ids'] ?? [] );
146
147 if ( empty( $session_id ) || $content_id === null || $content_id === '' || empty( $ai_page_ids ) ) {
148 return false;
149 }
150
151 $tmp_dir = Helper::upload_dir( 'tmp' ) . $session_id . DIRECTORY_SEPARATOR;
152
153 foreach ( $ai_page_ids as $key => $ids ) {
154 if ( in_array( (string) $content_id, $ids, true ) ) {
155 $sub_path = str_replace( '/', DIRECTORY_SEPARATOR, (string) $key );
156 $file_path = $tmp_dir . $sub_path . DIRECTORY_SEPARATOR . $content_id . '.ai.json';
157 if ( file_exists( $file_path ) ) {
158 return true;
159 }
160 }
161 }
162
163 return false;
164 }
165 }
166