{"id":3291,"date":"2026-09-07T08:39:33","date_gmt":"2026-09-07T05:39:33","guid":{"rendered":"https:\/\/digitalegiz.kz\/?page_id=3291"},"modified":"2026-09-09T09:16:57","modified_gmt":"2026-09-09T06:16:57","slug":"ar-generator","status":"publish","type":"page","link":"https:\/\/digitalegiz.kz\/?page_id=3291","title":{"rendered":"AR-Generator"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"3291\" class=\"elementor elementor-3291\">\n\t\t\t\t<div class=\"elementor-element elementor-element-f0797a3 e-flex e-con-boxed e-con e-parent\" data-id=\"f0797a3\" data-element_type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-3b77c35 elementor-widget elementor-widget-heading\" data-id=\"3b77c35\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h1 class=\"elementor-heading-title elementor-size-default\">Automatic AR generator<\/h1>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-6df9b99 e-con-full e-flex e-con e-parent\" data-id=\"6df9b99\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-80ee9d8 elementor-widget elementor-widget-text-editor\" data-id=\"80ee9d8\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h2>AR Factory<\/h2>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-069d39a elementor-widget elementor-widget-text-editor\" data-id=\"069d39a\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<style>\n    \/* Styles adapted for your Elementor *\/\n    .ar-generator-app {\n        font-family: 'Segoe UI', sans-serif;\n        color: #ffffff;\n        text-align: center;\n        max-width: 500px;\n        margin: 0 auto;\n        padding: 20px;\n    }\n    .ar-generator-app .hidden { display: none !important; }\n    \n    .ar-generator-app button, \n    .ar-generator-app .file-upload-btn {\n        background-color: #d89f45; \/* Gold color to match your style *\/\n        color: #020617; \/* Dark text for contrast *\/\n        border: none;\n        padding: 14px 24px;\n        margin: 10px 5px;\n        border-radius: 8px;\n        cursor: pointer;\n        font-size: 16px;\n        font-weight: bold;\n        transition: transform 0.2s, background 0.3s;\n        display: inline-block;\n        width: 100%;\n        box-sizing: border-box;\n    }\n    .ar-generator-app button:hover, \n    .ar-generator-app .file-upload-btn:hover { \n        background-color: #f1b354; \n        transform: translateY(-2px);\n    }\n    .ar-generator-app button.secondary { \n        background-color: transparent; \n        color: #d89f45;\n        border: 2px solid #d89f45;\n    }\n    .ar-generator-app button.secondary:hover {\n        background-color: rgba(216, 159, 69, 0.1);\n    }\n    .ar-generator-app input[type=\"file\"] { display: none; }\n    \n    .ar-generator-app .loader {\n        border: 4px solid rgba(255,255,255,0.1); \n        border-top: 4px solid #d89f45;\n        border-radius: 50%; width: 50px; height: 50px;\n        animation: spin 1s linear infinite; margin: 30px auto;\n    }\n    @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }\n    .ar-generator-app img.result-qr { width: 100%; margin: 0; border-radius: 12px; }\n    .ar-generator-app .upload-preview { max-width: 230px; border-radius: 12px; margin: 12px auto; display: block; box-shadow: 0 4px 18px rgba(0,0,0,0.25); }\n    .ar-generator-app .stage-text { color: #d89f45; font-weight: bold; font-size: 15px; margin-top: 8px; }\n    .ar-generator-app .elapsed-text { font-size: 13px; color: #a1a1a1; }\n    .ar-generator-app video.result-video { width: 100%; border-radius: 12px; display: block; }\n    .ar-generator-app .result-row { display: flex; gap: 20px; justify-content: center; align-items: flex-start; flex-wrap: wrap; margin: 14px 0; }\n    .ar-generator-app .result-col { flex: 1 1 220px; max-width: 260px; }\n    .ar-generator-app .result-caption { color: #d89f45; font-weight: bold; margin-bottom: 8px; }\n    .ar-generator-app .gen-input { width: 100%; box-sizing: border-box; padding: 10px 12px; margin: 6px 0; border-radius: 8px; border: 1px solid #d0d0d0; font-size: 14px; color: #333; font-family: inherit; }\n    .ar-generator-app .quality-row { margin: 10px 0 4px; text-align: left; }\n    .ar-generator-app .q-opt { display: block; font-size: 14px; margin: 6px 0; color: #555; cursor: pointer; font-weight: normal; }\n    .ar-generator-app .q-opt input { margin-right: 8px; }\n<\/style>\n\n<div class=\"ar-generator-app\">\n    <div id=\"screen-home\">\n        <p style=\"font-size: 18px; margin-bottom: 25px;\">Choose an action:<\/p>\n        <button onclick=\"window.location.href='https:\/\/digitalegiz.kz\/?page_id=3326'\">Browse the catalog of ready-made models<\/button>\n        <button class=\"secondary\" onclick=\"switchScreen('screen-upload')\">Create your own model<\/button>\n    <\/div>\n\n    <div id=\"screen-upload\" class=\"hidden\">\n        <h3 style=\"color: #d89f45;\">New AR model<\/h3>\n        <p>Upload a well-lit photo of the equipment.<\/p>\n        \n        <label class=\"file-upload-btn\">\n            <input type=\"file\" id=\"imageInput\" accept=\"image\/png, image\/jpeg\">\n            \ud83d\udcce Choose a photo\n        <\/label>\n        <p id=\"fileName\" style=\"font-size: 14px; color: #a1a1a1; margin-top: 10px;\"><\/p>\n        <img decoding=\"async\" id=\"uploadPreview\" class=\"upload-preview hidden\" src=\"\" alt=\"\">\n        <input type=\"text\" id=\"nameInput\" class=\"gen-input\" maxlength=\"80\" placeholder=\"Item name (e.g. Lamb pilaf)\">\n        <textarea id=\"infoInput\" class=\"gen-input\" rows=\"2\" maxlength=\"400\" placeholder=\"Additional information (description, ingredients, price...)\"><\/textarea>\n        <input type=\"number\" id=\"sizeInput\" class=\"gen-input\" min=\"1\" max=\"2000\" step=\"0.5\" placeholder=\"Size in cm (longest side) \u2014 for life-size display in AR\">\n        <div class=\"quality-row\">\n            <label class=\"q-opt\"><input type=\"radio\" name=\"genQuality\" value=\"fast\" checked>\u26a1 Fast \u2014 standard quality (~5 minutes)<\/label>\n            <label class=\"q-opt\"><input type=\"radio\" name=\"genQuality\" value=\"high\">\ud83d\udc8e High quality (~20 minutes)<\/label>\n        <\/div>\n        \n        <button onclick=\"startGeneration()\" id=\"generateBtn\" disabled style=\"opacity: 0.5;\">Generate<\/button>\n        <button class=\"secondary\" onclick=\"switchScreen('screen-home')\">Back<\/button>\n    <\/div>\n\n    <div id=\"screen-loading\" class=\"hidden\">\n        <h3 style=\"color: #d89f45;\">Generating the model&#8230;<\/h3>\n        <img decoding=\"async\" id=\"loadingPreview\" class=\"upload-preview\" src=\"\" alt=\"\">\n        <div class=\"loader\"><\/div>\n        <p id=\"stageText\" class=\"stage-text\"><\/p>\n        <p id=\"elapsedText\" class=\"elapsed-text\"><\/p>\n        <p id=\"etaText\" style=\"font-size: 14px; color: #a1a1a1;\">Please do not close this tab.<\/p>\n    <\/div>\n\n    <div id=\"screen-result\" class=\"hidden\">\n        <h3 style=\"color: #d89f45;\">Your model is ready!<\/h3>\n        <div class=\"result-row\">\n            <div class=\"result-col\" id=\"previewCol\">\n                <p class=\"result-caption\">Preview<\/p>\n                <video id=\"previewVideo\" class=\"result-video\" autoplay loop muted playsinline><\/video>\n            <\/div>\n            <div class=\"result-col\">\n                <p class=\"result-caption\">QR code<\/p>\n                <img decoding=\"async\" id=\"qrImage\" class=\"result-qr\" src=\"\" alt=\"QR Code\">\n            <\/div>\n        <\/div>\n        \n        <button id=\"downloadBtn\">\ud83d\udce5 Download for printing<\/button>\n        <button class=\"secondary\" onclick=\"switchScreen('screen-home')\">Create another<\/button>\n    <\/div>\n<\/div>\n\n<script>\n    \/\/ --- UI logic ---\n    function switchScreen(screenId) {\n        document.getElementById('screen-home').classList.add('hidden');\n        document.getElementById('screen-upload').classList.add('hidden');\n        document.getElementById('screen-loading').classList.add('hidden');\n        document.getElementById('screen-result').classList.add('hidden');\n        document.getElementById(screenId).classList.remove('hidden');\n    }\n\n    const imageInput = document.getElementById('imageInput');\n    const generateBtn = document.getElementById('generateBtn');\n    \n    imageInput.addEventListener('change', function() {\n        if (this.files && this.files[0]) {\n            document.getElementById('fileName').innerText = \"Selected file: \" + this.files[0].name;\n            const reader = new FileReader();\n            reader.onload = function(e) {\n                const up = document.getElementById('uploadPreview');\n                up.src = e.target.result;\n                up.classList.remove('hidden');\n                document.getElementById('loadingPreview').src = e.target.result;\n            };\n            reader.readAsDataURL(this.files[0]);\n            generateBtn.disabled = false;\n            generateBtn.style.opacity = \"1\";\n        }\n    });\n\n    \/\/ --- Server communication logic ---\n    const API_BASE = \"http:\/\/192.168.0.211:8000\"; \n    let pollingInterval;\n    let genStartTime, elapsedInterval;\n\n    async function startGeneration() {\n        const file = imageInput.files[0];\n        if (!file) return;\n\n        switchScreen('screen-loading');\n        document.getElementById('stageText').innerText = 'Uploading the photo...';\n        genStartTime = Date.now();\n        clearInterval(elapsedInterval);\n        elapsedInterval = setInterval(() => {\n            const s = Math.floor((Date.now() - genStartTime) \/ 1000);\n            document.getElementById('elapsedText').innerText = 'Elapsed: ' + Math.floor(s \/ 60) + ' min ' + (s % 60) + ' sec';\n        }, 1000);\n        const formData = new FormData();\n        formData.append('image', file);\n        formData.append('name', document.getElementById('nameInput').value.trim());\n        formData.append('info', document.getElementById('infoInput').value.trim());\n        const sz = document.getElementById('sizeInput').value;\n        if (sz) formData.append('size_cm', sz);\n        const q = document.querySelector('input[name=\"genQuality\"]:checked').value;\n        formData.append('quality', q);\n        document.getElementById('etaText').innerText = (q === 'high'\n            ? 'High quality: usually about 20 minutes. '\n            : 'Usually takes about 5 minutes. ') + 'Please do not close this tab.';\n\n        try {\n            const response = await fetch(`${API_BASE}\/api\/generate_model`, { method: 'POST', body: formData });\n            if (!response.ok) throw new Error(\"The server did not accept the file\");\n            \n            const data = await response.json();\n            startPolling(data.task_id);\n        } catch (error) {\n            console.error(error);\n            alert(\"Error communicating with the server!\");\n            switchScreen('screen-upload');\n        }\n    }\n\n    function startPolling(taskId) {\n        pollingInterval = setInterval(async () => {\n            try {\n                const response = await fetch(`${API_BASE}\/api\/check_status?task_id=${taskId}`);\n                const data = await response.json();\n\n                if (data.status === \"completed\") {\n                    clearInterval(pollingInterval);\n                    clearInterval(elapsedInterval);\n                    showResult(data);\n                } else if (data.status === \"error\") {\n                    clearInterval(pollingInterval);\n                    clearInterval(elapsedInterval);\n                    alert(\"An error occurred during generation on the server.\");\n                    switchScreen('screen-home');\n                } else if (data.stage) {\n                    document.getElementById('stageText').innerText = data.stage;\n                }\n            } catch (error) {\n                console.error(\"Polling error:\", error);\n            }\n        }, 15000); \n    }\n\n    function showResult(data) {\n        const pv = document.getElementById('previewVideo');\n        const pvCol = document.getElementById('previewCol');\n        if (data.preview_url) { pv.src = data.preview_url; pvCol.classList.remove('hidden'); }\n        else { pvCol.classList.add('hidden'); pv.removeAttribute('src'); }\n        const qrImage = document.getElementById('qrImage');\n        qrImage.src = data.qr_url.startsWith('http') ? data.qr_url : `${API_BASE}${data.qr_url}`;\n        \n        const downloadBtn = document.getElementById('downloadBtn');\n        downloadBtn.onclick = () => window.open(qrImage.src, '_blank');\n\n        \/\/ Add a button that opens the scanner\n        const resultScreen = document.getElementById('screen-result');\n        let goBtn = document.getElementById('goToScannerBtn');\n        if (!goBtn) {\n            goBtn = document.createElement('button');\n            goBtn.id = 'goToScannerBtn';\n            goBtn.innerText = '\ud83d\udc40 View in AR Scanner';\n            resultScreen.insertBefore(goBtn, downloadBtn);\n        }\n        goBtn.onclick = () => {\n            window.location.href = data.ar_url || ('https:\/\/digitalegiz.kz\/?page_id=2962&model=' + (data.model_url || ''));\n        };\n\n        switchScreen('screen-result');\n        imageInput.value = \"\";\n        generateBtn.disabled = true;\n        generateBtn.style.opacity = \"0.5\";\n        document.getElementById('fileName').innerText = \"\";\n    }\n<\/script>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_kad_post_transparent":"","_kad_post_title":"hide","_kad_post_layout":"fullwidth","_kad_post_sidebar_id":"","_kad_post_content_style":"unboxed","_kad_post_vertical_padding":"hide","_kad_post_feature":"hide","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"footnotes":""},"class_list":["post-3291","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/digitalegiz.kz\/index.php?rest_route=\/wp\/v2\/pages\/3291","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/digitalegiz.kz\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/digitalegiz.kz\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/digitalegiz.kz\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/digitalegiz.kz\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3291"}],"version-history":[{"count":5,"href":"https:\/\/digitalegiz.kz\/index.php?rest_route=\/wp\/v2\/pages\/3291\/revisions"}],"predecessor-version":[{"id":3382,"href":"https:\/\/digitalegiz.kz\/index.php?rest_route=\/wp\/v2\/pages\/3291\/revisions\/3382"}],"wp:attachment":[{"href":"https:\/\/digitalegiz.kz\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3291"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}