diff --git a/database/wordpress_tables_part_al b/database/wordpress_tables_part_al
index 4e447a8..d4b6af6 100644
--- a/database/wordpress_tables_part_al
+++ b/database/wordpress_tables_part_al
@@ -577,7 +577,7 @@ INSERT INTO `wp_snippets` VALUES
(34,'LT-8、9','','add_action(\'wp_footer\', function () {\n if (!is_page([\'lt-8、9\'])) return;\n ?>\n \n \n\n\n\n [\'GET\', \'POST\'],\n \'permission_callback\' => \'__return_true\',\n\n \'callback\' => function (WP_REST_Request $request) {\n\n $base = \'http://192.168.110.201:3002\';\n $api_key = \'muser_68600856036340bcafc01930eb4bd839_1774418104_97221b69\';\n\n // Demo UUID provided for current search demo.\n $demo_uuid = \'aeed71342a899fe4b4c57b7d41bcb692\';\n\n $mode = sanitize_text_field($request->get_param(\'mode\'));\n $query = sanitize_text_field($request->get_param(\'query\'));\n\n if (!$query) {\n return new WP_REST_Response([\n \'success\' => false,\n \'message\' => \'Missing query\'\n ], 400);\n }\n\n if ($mode === \'semantic\') {\n\n $url = $base . \'/api/v1/search/smart\';\n $body = [\n \'file_uuid\' => $demo_uuid,\n \'query\' => $query,\n \'limit\' => 20,\n \'page\' => 1,\n \'page_size\' => 20,\n ];\n\n $args = [\n \'method\' => \'POST\',\n \'timeout\' => 60,\n \'headers\' => [\n \'Content-Type\' => \'application/json\',\n \'X-API-Key\' => $api_key,\n ],\n \'body\' => wp_json_encode($body),\n ];\n\n } elseif ($mode === \'people\') {\n\n $url = $base . \'/api/v1/identities/search?q=\' . rawurlencode($query)\n . \'&limit=20\'\n . \'&page=1\'\n . \'&page_size=20\';\n $args = [\n \'method\' => \'GET\',\n \'timeout\' => 60,\n \'headers\' => [\n \'X-API-Key\' => $api_key,\n ],\n ];\n\n } else {\n\n // Default: keyword / universal search.\n $url = $base . \'/api/v1/search/universal\';\n $body = [\n \'file_uuid\' => $demo_uuid,\n \'query\' => $query,\n \'limit\' => 20,\n \'page\' => 1,\n \'page_size\' => 20,\n ];\n\n $args = [\n \'method\' => \'POST\',\n \'timeout\' => 60,\n \'headers\' => [\n \'Content-Type\' => \'application/json\',\n \'X-API-Key\' => $api_key,\n ],\n \'body\' => wp_json_encode($body),\n ];\n }\n\n $response = wp_remote_request($url, $args);\n\n if (is_wp_error($response)) {\n return new WP_REST_Response([\n \'success\' => false,\n \'message\' => $response->get_error_message(),\n ], 500);\n }\n\n $code = wp_remote_retrieve_response_code($response);\n $raw_body = wp_remote_retrieve_body($response);\n $decoded = json_decode($raw_body, true);\n\n if ($decoded === null && json_last_error() !== JSON_ERROR_NONE) {\n return new WP_REST_Response([\n \'success\' => false,\n \'message\' => \'Invalid JSON from upstream API\',\n \'raw\' => $raw_body,\n ], $code ?: 500);\n }\n\n return new WP_REST_Response($decoded, $code);\n }\n ]);\n});\n\nadd_action(\'wp_head\', function () {\n if (!is_page(\'search-chat\')) return;\n ?>\n\n\n\n \n\n [\'GET\', \'POST\'],\n \'permission_callback\' => \'__return_true\',\n\n \'callback\' => function (WP_REST_Request $request) {\n\n $base = \'http://192.168.110.201:3002\';\n $api_key = \'muser_68600856036340bcafc01930eb4bd839_1774418104_97221b69\';\n\n $mode = sanitize_text_field($request->get_param(\'mode\'));\n $query = sanitize_text_field($request->get_param(\'query\'));\n\n if (!$query) {\n return new WP_REST_Response([\n \'success\' => false,\n \'message\' => \'Missing query\'\n ], 400);\n }\n\n if ($mode === \'semantic\') {\n\n $url = $base . \'/api/v1/search/smart\';\n $body = [\n \'query\' => $query,\n \'limit\' => 20,\n \'page\' => 1,\n \'page_size\' => 20,\n ];\n\n $args = [\n \'method\' => \'POST\',\n \'timeout\' => 60,\n \'headers\' => [\n \'Content-Type\' => \'application/json\',\n \'X-API-Key\' => $api_key,\n ],\n \'body\' => wp_json_encode($body),\n ];\n\n } elseif ($mode === \'people\') {\n\n $url = $base . \'/api/v1/identities/search?q=\' . rawurlencode($query)\n . \'&limit=20\'\n . \'&page=1\'\n . \'&page_size=20\';\n $args = [\n \'method\' => \'GET\',\n \'timeout\' => 60,\n \'headers\' => [\n \'X-API-Key\' => $api_key,\n ],\n ];\n\n } else {\n\n // Default: keyword / universal search.\n $url = $base . \'/api/v1/search/universal\';\n $body = [\n \'query\' => $query,\n \'limit\' => 20,\n \'page\' => 1,\n \'page_size\' => 20,\n ];\n\n $args = [\n \'method\' => \'POST\',\n \'timeout\' => 60,\n \'headers\' => [\n \'Content-Type\' => \'application/json\',\n \'X-API-Key\' => $api_key,\n ],\n \'body\' => wp_json_encode($body),\n ];\n }\n\n $response = wp_remote_request($url, $args);\n\n if (is_wp_error($response)) {\n return new WP_REST_Response([\n \'success\' => false,\n \'message\' => $response->get_error_message(),\n ], 500);\n }\n\n $code = wp_remote_retrieve_response_code($response);\n $raw_body = wp_remote_retrieve_body($response);\n $decoded = json_decode($raw_body, true);\n\n if ($decoded === null && json_last_error() !== JSON_ERROR_NONE) {\n return new WP_REST_Response([\n \'success\' => false,\n \'message\' => \'Invalid JSON from upstream API\',\n \'raw\' => $raw_body,\n ], $code ?: 500);\n }\n\n return new WP_REST_Response($decoded, $code);\n }\n ]);\n});\n\nadd_action(\'wp_head\', function () {\n if (!is_page(\'search-chat\')) return;\n ?>\n\n\n\n \n\n 登入畫面包含輪播圖等等
','add_action(\'init\', function () {\n if (empty($_GET[\'ms_login_local_img\'])) return;\n\n $base = \'/Users/accusys/momentry/var/sftpgo/data/demo/\';\n $file = basename($_GET[\'ms_login_local_img\']);\n $path = $base . $file;\n\n if (!file_exists($path)) {\n status_header(404);\n exit(\'Image not found\');\n }\n\n header(\'Content-Type: \' . mime_content_type($path));\n header(\'Content-Length: \' . filesize($path));\n readfile($path);\n exit;\n});\n\nadd_shortcode(\'ms_login_form\', function () {\n\n if (is_user_logged_in()) {\n $logout_url = wp_logout_url(home_url(\'/login/?loggedout=true\'));\n\n return \'\n \n\n \';\n }\n\n $redirect_to = !empty($_GET[\'redirect_to\'])\n ? esc_url_raw($_GET[\'redirect_to\'])\n : home_url(\'/lt-searching/\');\n\n ob_start(); ?>\n\n \n\n \n
\n\n
\n

\" alt=\"Momentry Studio\">\n\n

\" alt=\"Momentry Studio\">\n\n

\" alt=\"Momentry Studio\">\n\n

\" alt=\"Momentry Studio\">\n \n \n \n \n \n \n
\n
\n
\n \n \n \n \n\n
\n
\n\n \n \n
\n\n
Log in to Momentry Studio
\n\n \n
\n Incorrect username or password, please try again.\n
\n \n\n
\n\n
\n\n
\n
\n\n $row) {\n if (\n empty($row[\'expires\']) ||\n !is_numeric($row[\'expires\']) ||\n (int) $row[\'expires\'] < $now\n ) {\n unset($store[$device_key]);\n }\n }\n return $store;\n }\n}\n\nif (!function_exists(\'ms_switch_register_device_token\')) {\n function ms_switch_register_device_token($user_id, $device_key) {\n $store = ms_switch_cleanup_store(ms_switch_get_store($user_id));\n\n $selector = wp_generate_password(12, false, false);\n $validator = wp_generate_password(32, false, false);\n $token = $selector . \'.\' . $validator;\n $expires = time() + DAY_IN_SECONDS;\n\n $store[$device_key] = [\n \'selector\' => $selector,\n \'hash\' => wp_hash_password($validator),\n \'expires\' => $expires,\n \'issued\' => time(),\n ];\n\n ms_switch_save_store($user_id, $store);\n\n return [\n \'token\' => $token,\n \'expires\' => $expires,\n ];\n }\n}\n\nif (!function_exists(\'ms_switch_verify_token\')) {\n function ms_switch_verify_token($user_id, $device_key, $token) {\n if (!$user_id || !$device_key || !$token) return false;\n\n $store = ms_switch_cleanup_store(ms_switch_get_store($user_id));\n ms_switch_save_store($user_id, $store);\n\n if (empty($store[$device_key])) return false;\n\n $row = $store[$device_key];\n\n if (empty($row[\'selector\']) || empty($row[\'hash\']) || empty($row[\'expires\'])) {\n return false;\n }\n\n if ((int) $row[\'expires\'] < time()) {\n return false;\n }\n\n $parts = explode(\'.\', $token, 2);\n if (count($parts) !== 2) return false;\n\n list($selector, $validator) = $parts;\n\n if (!hash_equals((string) $row[\'selector\'], (string) $selector)) {\n return false;\n }\n\n if (!wp_check_password($validator, $row[\'hash\'])) {\n return false;\n }\n\n return true;\n }\n}\n\n/* =========================================================\n * 2) REST API\n * ========================================================= */\nadd_action(\'rest_api_init\', function () {\n\n register_rest_route(\'momentry/v1\', \'/register-switch-device\', [\n \'methods\' => \'POST\',\n \'permission_callback\' => function () {\n return is_user_logged_in();\n },\n \'callback\' => function (WP_REST_Request $request) {\n $user = wp_get_current_user();\n if (!$user || !$user->ID) {\n return new WP_REST_Response([\n \'ok\' => false,\n \'message\' => \'Not logged in\'\n ], 401);\n }\n\n $device_key = sanitize_text_field((string) $request->get_param(\'device_key\'));\n if (!$device_key) {\n return new WP_REST_Response([\n \'ok\' => false,\n \'message\' => \'Missing device_key\'\n ], 400);\n }\n\n $issued = ms_switch_register_device_token($user->ID, $device_key);\n\n return new WP_REST_Response([\n \'ok\' => true,\n \'data\' => [\n \'token\' => $issued[\'token\'],\n \'expires\' => $issued[\'expires\'],\n \'login\' => $user->user_login,\n ]\n ]);\n }\n ]);\n\n register_rest_route(\'momentry/v1\', \'/account-switch\', [\n \'methods\' => \'POST\',\n \'permission_callback\' => function () {\n return is_user_logged_in();\n },\n \'callback\' => function (WP_REST_Request $request) {\n $target_login = sanitize_user((string) $request->get_param(\'login\'));\n $device_key = sanitize_text_field((string) $request->get_param(\'device_key\'));\n $switch_token = sanitize_text_field((string) $request->get_param(\'switch_token\'));\n\n if (!$target_login || !$device_key || !$switch_token) {\n return new WP_REST_Response([\n \'ok\' => false,\n \'message\' => \'Missing switch data\',\n \'requires_login\' => true\n ], 400);\n }\n\n $target_user = get_user_by(\'login\', $target_login);\n if (!$target_user || !$target_user->ID) {\n return new WP_REST_Response([\n \'ok\' => false,\n \'message\' => \'Target user not found\',\n \'requires_login\' => true\n ], 404);\n }\n\n $valid = ms_switch_verify_token($target_user->ID, $device_key, $switch_token);\n\n if (!$valid) {\n return new WP_REST_Response([\n \'ok\' => false,\n \'message\' => \'Token invalid or expired\',\n \'requires_login\' => true\n ], 403);\n }\n\n wp_clear_auth_cookie();\n wp_set_current_user($target_user->ID);\n wp_set_auth_cookie($target_user->ID, true, is_ssl());\n\n do_action(\'wp_login\', $target_user->user_login, $target_user);\n\n return new WP_REST_Response([\n \'ok\' => true,\n \'data\' => [\n \'redirect\' => home_url(\'/search/\'),\n \'login\' => $target_user->user_login,\n ]\n ]);\n }\n ]);\n\n});\n\n/* =========================================================\n * 3) Main layer wrapper\n * ========================================================= */\nadd_filter(\'the_content\', function ($content) {\n\n if (!is_page([\n \'lt-searching\',\n \'search-chat\',\n \'upgrade-plan\',\n \'personalization\',\n \'settings\',\n \'help\',\n \'ww-04-07-api\',\n \'library\',\n \'people\',\n \'progress\',\n \'momentry-api-console\',\n \'logs\',\n \'metrics\',\n \'measure\',\n \'Evaluation\',\n \'raptor-api-console\',\n \'demo\'\n\n\n ])) return $content;\n\n if (strpos($content, \'class=\"ms-app\"\') !== false) return $content;\n\n $is_search_lab = is_page(\'search-lab\');\n $can_view_search_lab = true;\n if ($is_search_lab) {\n if (!is_user_logged_in()) {\n $can_view_search_lab = false;\n } else {\n $u_check = wp_get_current_user();\n $allowed_roles = [\'administrator\', \'editor\'];\n $can_view_search_lab = !empty(array_intersect($allowed_roles, (array) $u_check->roles));\n }\n }\n\n $home_url = home_url(\'/lt-searching/\');\n $login_url = wp_login_url($home_url);\n $logout_login_template = wp_logout_url(add_query_arg(\'ms_prefill\', \'__LOGIN__\', $login_url));\n $logout_to_login = wp_logout_url($login_url);\n\n ob_start(); ?>\n\n \n\n \n\n data-current-login=\"user_login); ?>\"data-current-login=\"guest\">\n\n
\n\n roles)) $ms_role = \'admin\';\n elseif (in_array(\'editor\', $current_user->roles)) $ms_role = \'editor\';\n else $ms_role = \'member\';\n }\n ?>\n \n\n
\n \n \n
🔒
\n
Access Restricted
\n
\n Evaluation 僅限 Administrator 與 Editor 角色查看。
\n 如需存取權限,請聯繫管理員。\n
\n
\n 返回首頁\n \n
\n \n \n \n \n\n
\n\n \n \n \n\n
-
- Require all denied
-
-
- Require all granted
-
-
-
- Order allow,deny
- Deny from all
-
- Order allow,deny
- Allow from all
-
-
-
- AddType text/plain .log
-
-
- DirectoryIndex index.php
-
-
- Options -Indexes
-
\ No newline at end of file
diff --git a/plugins/all-in-one-wp-migration/storage/web.config b/plugins/all-in-one-wp-migration/storage/web.config
deleted file mode 100644
index 7ec4c66..0000000
--- a/plugins/all-in-one-wp-migration/storage/web.config
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/themes/momentry/page-api-demo-query.php b/themes/momentry/page-api-demo-query.php
index 3213e04..05cd6e3 100644
--- a/themes/momentry/page-api-demo-query.php
+++ b/themes/momentry/page-api-demo-query.php
@@ -479,9 +479,9 @@ async function semanticSearch() {
data-end-time="${endTime}"
data-text="${textAttr}">
${i.name} (${i.source || 'unknown'})
- ${i.file_uuid} | ${startTime.toFixed(1)}s - ${endTime.toFixed(1)}s
- ${i.text_content || '無內容'}
-
+ ${startTime.toFixed(1)}s - ${endTime.toFixed(1)}s${i.chunk_id ? ` | ${i.chunk_id}` : ''}
+ ${i.text_content || ''}
+
`;
}).join('');
resultEl.innerHTML = `找到 ${data.total || 0} 個身份相關片段
${resultsHtml || '沒有結果
'}`;
@@ -503,10 +503,10 @@ async function semanticSearch() {
data-start-time="${startTime}"
data-end-time="${endTime}"
data-text="${textAttr}">
- ${r.file_uuid} | ${startTime.toFixed(1)}s - ${endTime.toFixed(1)}s
- ${r.text || '無內容'}
+ ${startTime.toFixed(1)}s - ${endTime.toFixed(1)}s${r.chunk_id ? ` | ${r.chunk_id}` : ''}
+ ${r.text || ''}
相似度: ${(r.score * 100).toFixed(1)}%
-
+
`;
}).join('');
resultEl.innerHTML = `找到 ${data.total || 0} 個片段
${resultsHtml || '沒有結果
'}`;