{"id":324,"date":"2025-10-01T20:12:40","date_gmt":"2025-10-01T12:12:40","guid":{"rendered":"http:\/\/43.128.105.238\/?page_id=324"},"modified":"2025-10-02T00:04:11","modified_gmt":"2025-10-01T16:04:11","slug":"324-2","status":"publish","type":"page","link":"https:\/\/archim.top\/index.php\/324-2\/","title":{"rendered":"\u89d2\u8272\u505a\u6210 Character Creator"},"content":{"rendered":"<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>\u89d2\u8272\u751f\u6210\u5668<\/title>\n    <script src=\"https:\/\/cdn.tailwindcss.com\"><\/script>\n    <link rel=\"preconnect\" href=\"https:\/\/fonts.googleapis.com\">\n    <link rel=\"preconnect\" href=\"https:\/\/fonts.gstatic.com\" crossorigin>\n    <link href=\"https:\/\/fonts.googleapis.com\/css2?family=Merriweather:ital,wght@0,400;0,700;1,400&#038;family=Playfair+Display:wght@700&#038;display=swap\" rel=\"stylesheet\">\n    <style>\n        body {\n            font-family: 'Merriweather', serif;\n            background-color: #FFFFFF; \/* \u7eaf\u767d\u80cc\u666f *\/\n            color: #2c2c2c;\n        }\n        h1, .font-display {\n            font-family: 'Playfair Display', serif;\n        }\n        .cv-card {\n            background-color: #FDFBF4; \/* \u7c73\u9ec4\u8272\u6846\u67b6 *\/\n            border: 1px solid #BFBFBF; \/* \u7a0d\u6df1\u7684\u8fb9\u6846 *\/\n            box-shadow: 0 10px 15px -3px rgb(0 0 0 \/ 0.05), 0 4px 6px -4px rgb(0 0 0 \/ 0.05);\n        }\n        .cv-section-title {\n            font-size: 1.25rem; \/* text-xl *\/\n            font-weight: 700; \/* font-bold *\/\n            color: #334155; \/* slate-800 *\/\n            border-bottom: 3px double #BFBFBF; \/* double border *\/\n            padding-bottom: 0.5rem;\n            margin-bottom: 1.5rem;\n            font-family: 'Playfair Display', serif;\n        }\n        .cv-subsection-title {\n            font-weight: 700;\n            color: #475569; \/* slate-600 *\/\n            margin-top: 1.5rem;\n            margin-bottom: 1rem;\n            font-size: 1rem;\n        }\n        .loader {\n            border: 5px solid #E2E8F0;\n            border-top: 5px solid #4a5568; \/* gray-700 *\/\n            border-radius: 50%;\n            width: 50px;\n            height: 50px;\n            animation: spin 1s linear infinite;\n        }\n        @keyframes spin {\n            0% { transform: rotate(0deg); }\n            100% { transform: rotate(360deg); }\n        }\n        .editable-field {\n            background: transparent;\n            border: 1px solid transparent;\n            border-radius: 2px;\n            padding: 2px 4px;\n            width: 100%;\n            transition: all 0.2s ease-in-out;\n            color: #2c2c2c;\n            font-family: 'Merriweather', serif;\n            line-height: 1.6;\n        }\n        .editable-field:hover {\n            border-color: #cbd5e1; \/* slate-300 *\/\n        }\n        .editable-field:focus {\n            outline: none;\n            border-color: #4a5568; \/* gray-700 *\/\n            background-color: #f8fafc; \/* slate-50 *\/\n            box-shadow: 0 0 0 1px #4a5568;\n        }\n        textarea.editable-field {\n            resize: none;\n            overflow: hidden;\n        }\n        .newspaper-divider {\n            border-top: 1px solid #BFBFBF;\n            border-bottom: 1px solid #BFBFBF;\n            height: 4px;\n            background-color: #F8F8F4;\n        }\n        .field-group {\n            margin-bottom: 1.25rem;\n        }\n        .field-group strong {\n             color: #64748B; \/* slate-500 *\/\n             font-weight: bold;\n             display: block;\n             margin-bottom: 0.25rem;\n        }\n        details > summary {\n            cursor: pointer;\n            font-family: 'Playfair Display', serif;\n            font-size: 1.125rem;\n            font-weight: 700;\n        }\n        #historyDropdown {\n            font-family: 'Merriweather', serif;\n        }\n    <\/style>\n<\/head>\n<body class=\"min-h-screen flex flex-col items-center p-4 lg:p-8\">\n\n    <!-- \u5168\u5c4f\u52a0\u8f7d\/\u9519\u8bef\u906e\u7f69 -->\n    <div id=\"loading-overlay\" class=\"hidden fixed inset-0 bg-white\/80 backdrop-blur-sm z-50 flex items-center justify-center p-4 transition-opacity duration-300\">\n        <div class=\"text-center\">\n            <div id=\"loader-container\">\n                 <div class=\"loader mx-auto\"><\/div>\n                 <p id=\"loader-text\" class=\"mt-4 text-gray-700 text-lg font-semibold\">\u6b63\u5728\u8c03\u53d6\u6863\u6848\uff0c\u8bf7\u7a0d\u5019&#8230;<\/p>\n            <\/div>\n            <div id=\"error-container\" class=\"hidden\">\n                 <div class=\"mx-auto bg-red-100 border-2 border-red-300 rounded-full h-16 w-16 flex items-center justify-center\">\n                    <svg class=\"h-8 w-8 text-red-600\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n                        <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" \/>\n                    <\/svg>\n                 <\/div>\n                 <p class=\"mt-4 text-red-700 font-bold text-xl\">\u751f\u6210\u5931\u8d25<\/p>\n                 <p class=\"text-slate-600 mt-1\">\u53ef\u80fd\u662f\u7f51\u7edc\u6ce2\u52a8\uff0c\u8bf7\u7a0d\u540e\u518d\u8bd5\u4e00\u6b21\u3002<\/p>\n                 <button id=\"close-error-btn\" class=\"mt-6 bg-slate-700 hover:bg-slate-800 text-white font-bold py-2 px-6 rounded-md text-sm\">\u5173\u95ed<\/button>\n            <\/div>\n        <\/div>\n    <\/div>\n\n    <div class=\"w-full max-w-screen-xl mx-auto\">\n        \n        <!-- \u9876\u90e8\u64cd\u4f5c\u680f -->\n        <div class=\"flex justify-between items-center mb-6 px-2\">\n            <div>\n                <label for=\"historyDropdown\" class=\"text-sm font-semibold text-slate-600 mr-2\">\u751f\u6210\u5386\u53f2:<\/label>\n                <select id=\"historyDropdown\" class=\"bg-white border border-slate-300 rounded-md shadow-sm py-1 px-2 focus:outline-none focus:ring-2 focus:ring-slate-500 text-sm\">\n                    <option value=\"-1\">&#8212; \u6682\u65e0\u5386\u53f2 &#8212;<\/option>\n                <\/select>\n            <\/div>\n            <button id=\"clearBtn\" class=\"bg-amber-700 hover:bg-amber-800 text-white font-bold py-2 px-4 rounded-md shadow-sm transition-colors focus:outline-none focus:ring-2 focus:ring-amber-500 focus:ring-opacity-50 text-sm\">\n                \u6e05\u7a7a\u5f53\u524d\u6863\u6848\n            <\/button>\n        <\/div>\n\n\n        <header class=\"text-center mb-8\">\n            <h1 class=\"text-4xl md:text-5xl font-bold text-gray-900 tracking-wider\">\u89d2\u8272\u751f\u6210\u5668<\/h1>\n            <p class=\"text-gray-600 mt-2 text-base\">Character Creator<\/p>\n        <\/header>\n\n        <div class=\"text-center mb-8 flex justify-center items-center space-x-4\">\n            <button id=\"generateBtn\" class=\"bg-slate-800 hover:bg-slate-900 text-white font-bold py-2 px-6 rounded-md shadow-sm transition-colors focus:outline-none focus:ring-2 focus:ring-slate-500 focus:ring-opacity-50\">\n                <span id=\"btn-text\">\u751f\u6210\u6863\u6848<\/span>\n                <svg id=\"btn-spinner\" class=\"animate-spin h-5 w-5 text-white hidden\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" fill=\"none\" viewBox=\"0 0 24 24\">\n                    <circle class=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\"><\/circle>\n                    <path class=\"opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"><\/path>\n                <\/svg>\n            <\/button>\n            <button id=\"downloadBtn\" class=\"bg-slate-600 hover:bg-slate-700 text-white font-bold py-2 px-6 rounded-md shadow-sm transition-colors focus:outline-none focus:ring-2 focus:ring-slate-400 focus:ring-opacity-50 disabled:opacity-50 disabled:cursor-not-allowed\" disabled>\n                \u4e0b\u8f7d JSON\n            <\/button>\n        <\/div>\n        \n        <!-- \u81ea\u5b9a\u4e49\u4fe1\u606f\u533a\u57df -->\n        <div class=\"space-y-4 mb-8\">\n            <!-- \u4e16\u754c\u89c2\u80cc\u666f -->\n            <details class=\"cv-card p-4\">\n                <summary class=\"text-slate-700\">\u4e16\u754c\u89c2\u80cc\u666f (Worldview Context)<\/summary>\n                <div class=\"mt-4\">\n                    <div class=\"flex justify-end mb-2\">\n                        <input type=\"file\" id=\"worldview_upload_input\" class=\"hidden\" accept=\".json\">\n                        <button id=\"worldview_upload_btn\" class=\"text-sm bg-slate-200 hover:bg-slate-300 text-slate-700 font-semibold py-1 px-3 rounded-md transition-colors\">\u4e0a\u4f20 JSON<\/button>\n                    <\/div>\n                    <textarea id=\"worldview_context\" placeholder=\"\u5728\u6b64\u8f93\u5165\u4e16\u754c\u89c2\u8bbe\u5b9a\uff0c\u6216\u4e0a\u4f20JSON\u6587\u4ef6...\" class=\"editable-field w-full h-32 p-2 border border-slate-200 rounded-md focus:border-slate-400\"><\/textarea>\n                <\/div>\n            <\/details>\n            <!-- \u5176\u4ed6\u89d2\u8272\u4fe1\u606f -->\n            <details class=\"cv-card p-4\">\n                <summary class=\"text-slate-700\">\u5176\u4ed6\u89d2\u8272\u4fe1\u606f (Other Characters Context)<\/summary>\n                 <div class=\"mt-4\">\n                    <div class=\"flex justify-end mb-2\">\n                         <input type=\"file\" id=\"other_characters_upload_input\" class=\"hidden\" accept=\".json\">\n                        <button id=\"other_characters_upload_btn\" class=\"text-sm bg-slate-200 hover:bg-slate-300 text-slate-700 font-semibold py-1 px-3 rounded-md transition-colors\">\u4e0a\u4f20 JSON<\/button>\n                    <\/div>\n                    <textarea id=\"other_characters_context\" placeholder=\"\u5728\u6b64\u8f93\u5165\u5176\u4ed6\u76f8\u5173\u89d2\u8272\u7684\u4fe1\u606f\uff0c\u6216\u4e0a\u4f20JSON\u6587\u4ef6...\" class=\"editable-field w-full h-32 p-2 border border-slate-200 rounded-md focus:border-slate-400\"><\/textarea>\n                <\/div>\n            <\/details>\n        <\/div>\n\n\n        <!-- \u89d2\u8272\u4fe1\u606f\u5c55\u793a\u533a\u57df -->\n        <div id=\"character-sheet\" class=\"cv-card p-6 md:p-8\">\n            <!-- \u89d2\u8272\u7b80\u5386\u5185\u5bb9 -->\n            <div id=\"character-content\">\n                \n                <div class=\"grid grid-cols-1 lg:grid-cols-3 gap-8\">\n                    <div class=\"lg:col-span-1\">\n                        <!-- \u8096\u50cf -->\n                         <div class=\"sticky top-8\">\n                            <div id=\"image-container\" class=\"w-full aspect-square bg-gray-50 flex items-center justify-center border-2 border-dashed border-gray-300 mb-4\">\n                                    <div id=\"image-loader\" class=\"text-center hidden\"><div class=\"loader mx-auto\"><\/div><p class=\"mt-4 text-gray-500 text-sm\">\u6b63\u5728\u7ed8\u5236\u8096\u50cf&#8230;<\/p><\/div>\n                                    <div id=\"image-placeholder\" class=\"text-center text-gray-400\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"w-16 h-16 mx-auto\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1\" d=\"M5.121 17.804A13.937 13.937 0 0112 16c2.5 0 4.847.655 6.879 1.804M15 10a3 3 0 11-6 0 3 3 0 016 0z\" \/><\/svg><p class=\"mt-2 text-sm\">\u89d2\u8272\u8096\u50cf<\/p><\/div>\n                                    <p id=\"image-error\" class=\"text-red-500 hidden p-4 text-center\">\u8096\u50cf\u7ed8\u5236\u5931\u8d25<\/p>\n                                    <img id=\"character-image\" class=\"w-full h-full object-cover hidden\" alt=\"\u89d2\u8272\u8096\u50cf\">\n                            <\/div>\n                             <div class=\"field-group mb-4\">\n                                 <strong >\u56fe\u50cf\u63d0\u793a\u8bcd (Image Prompt):<\/strong>\n                                 <textarea id=\"image_prompt\" placeholder=\"AI\u751f\u6210\u7684\u82f1\u6587\u63d0\u793a\u8bcd\u5c06\u663e\u793a\u5728\u8fd9\u91cc...\" class=\"editable-field w-full h-24 p-2 border border-slate-200 focus:border-slate-400\"><\/textarea>\n                             <\/div>\n                            <div class=\"text-center\">\n                                <button id=\"generateImageBtn\" class=\"bg-slate-700 hover:bg-slate-800 text-white font-bold py-2 px-5 rounded-md shadow-sm transition-colors focus:outline-none focus:ring-2 focus:ring-slate-500 focus:ring-opacity-50 disabled:opacity-50 disabled:cursor-not-allowed text-sm\" disabled>\u751f\u6210\u8096\u50cf<\/button>\n                            <\/div>\n                        <\/div>\n                    <\/div>\n                    <div class=\"lg:col-span-2\">\n                        <!-- \u7b2c\u4e00\u90e8\u5206: \u6838\u5fc3\u6863\u6848 -->\n                        <section class=\"mb-8\">\n                            <h3 class=\"cv-section-title\">\u7b2c\u4e00\u90e8\u5206\uff1a\u6838\u5fc3\u6863\u6848 (Core Information)<\/h3>\n                            <div class=\"grid grid-cols-1 md:grid-cols-2 gap-6 mb-4\">\n                                <div class=\"field-group\"><strong>\u59d3\u540d (Name):<\/strong> <textarea rows=\"1\" id=\"name\" placeholder=\"\u8f93\u5165\u89d2\u8272\u59d3\u540d\" class=\"editable-field\"><\/textarea><\/div>\n                                <div class=\"field-group\"><strong>\u79cd\u65cf (Race):<\/strong> <textarea rows=\"1\" id=\"race\" placeholder=\"\u4f8b\u5982: \u4eba\u7c7b, \u7cbe\u7075, \u517d\u4eba\" class=\"editable-field\"><\/textarea><\/div>\n                                <div class=\"field-group\"><strong>\u5e74\u9f84 (Age):<\/strong> <textarea rows=\"1\" id=\"age\" placeholder=\"\u8f93\u5165\u89d2\u8272\u5e74\u9f84\" class=\"editable-field\"><\/textarea><\/div>\n                                <div class=\"field-group\"><strong>\u6027\u522b (Gender):<\/strong> <textarea rows=\"1\" id=\"gender\" placeholder=\"\u8f93\u5165\u89d2\u8272\u6027\u522b\" class=\"editable-field\"><\/textarea><\/div>\n                            <\/div>\n                            <div class=\"field-group\"><strong >\u8eab\u4efd\u8ba4\u77e5 (Identities):<\/strong><textarea id=\"identities\" placeholder=\"\u89d2\u8272\u7684\u793e\u4f1a\u8eab\u4efd\u3001\u804c\u4e1a\u6216\u81ea\u6211\u8ba4\u77e5\" class=\"editable-field\"><\/textarea><\/div>\n                            <div class=\"field-group\"><strong >\u6210\u957f\u7ecf\u5386 (Growth Experience):<\/strong><textarea id=\"growth_experience\" placeholder=\"\u7b80\u8ff0\u5f71\u54cd\u89d2\u8272\u7684\u5173\u952e\u6210\u957f\u8282\u70b9\" class=\"editable-field\"><\/textarea><\/div>\n                            <div class=\"field-group\"><strong >\u5bb6\u5ead\u80cc\u666f (Family Background):<\/strong><textarea id=\"family_background\" placeholder=\"\u63cf\u8ff0\u89d2\u8272\u7684\u5bb6\u5ead\u6210\u5458\u3001\u9636\u5c42\u7b49\" class=\"editable-field\"><\/textarea><\/div>\n                            <div class=\"field-group\"><strong >\u5173\u952e\u7ebf\u7d22 (Key Events):<\/strong><textarea id=\"key_events\" placeholder=\"\u63a8\u52a8\u6545\u4e8b\u53d1\u5c55\u7684\u5173\u952e\u4e8b\u4ef6\u6216\u79d8\u5bc6\" class=\"editable-field\"><\/textarea><\/div>\n                            <div class=\"field-group\"><strong >\u539f\u578b (Archetype):<\/strong><textarea id=\"archetype\" placeholder=\"\u5206\u6790\u5e76\u786e\u5b9a\u89d2\u8272\u7684\u539f\u578b\uff0c\u5982\u201c\u8d24\u8005\u201d\u3001\u201c\u5b64\u513f\u201d...\" class=\"editable-field\"><\/textarea><\/div>\n                            <div class=\"field-group\"><strong >\u89d2\u8272\u5b9a\u4f4d (Character Role):<\/strong><textarea id=\"character_role\" placeholder=\"\u5206\u6790\u8be5\u89d2\u8272\u5728\u6545\u4e8b\u4e2d\u9002\u5408\u7684\u5b9a\u4f4d\" class=\"editable-field\"><\/textarea><\/div>\n                        <\/section>\n                    <\/div>\n                <\/div>\n\n                <div class=\"newspaper-divider my-8\"><\/div>\n\n                <!-- \u7b2c\u4e8c\u90e8\u5206: \u5916\u8c8c\u7279\u5f81 -->\n                <section class=\"mb-8\">\n                    <h3 class=\"cv-section-title\">\u7b2c\u4e8c\u90e8\u5206\uff1a\u5916\u8c8c\u7279\u5f81 (Appearance)<\/h3>\n                     <div class=\"field-group\"><strong >\u603b\u4f53\u5370\u8c61 (Overall Impression):<\/strong><textarea id=\"overall_impression\" placeholder=\"\u6982\u62ec\u89d2\u8272\u7ed9\u4eba\u7684\u7b2c\u4e00\u5916\u8c8c\u5370\u8c61\" class=\"editable-field\"><\/textarea><\/div>\n                     \n                     <div class=\"grid grid-cols-1 md:grid-cols-2 gap-x-8\">\n                        <div>\n                            <h4 class=\"cv-subsection-title\">\u8eab\u4f53\u7279\u5f81 (Physique)<\/h4>\n                            <div class=\"space-y-4\">\n                                <div class=\"field-group\"><strong>\u8eab\u9ad8 (Height):<\/strong><textarea rows=\"1\" id=\"height\" placeholder=\"\u4f8b\u5982: 175cm\" class=\"editable-field\"><\/textarea><\/div>\n                                <div class=\"field-group\"><strong>\u4f53\u91cd (Weight):<\/strong><textarea rows=\"1\" id=\"weight\" placeholder=\"\u4f8b\u5982: 60kg\" class=\"editable-field\"><\/textarea><\/div>\n                                <div class=\"field-group\"><strong>\u8eab\u6750 (Body Shape):<\/strong><textarea rows=\"1\" id=\"body_shape\" placeholder=\"\u4f8b\u5982: \u5300\u79f0\u3001\u7ea4\u7ec6\u3001\u5065\u58ee\" class=\"editable-field\"><\/textarea><\/div>\n                                <div class=\"field-group\"><strong>\u7f69\u676f\u5c3a\u5bf8 (Cup Size):<\/strong><textarea rows=\"1\" id=\"cup_size\" placeholder=\"\uff08\u53ef\u9009\uff09\" class=\"editable-field\"><\/textarea><\/div>\n                                <div class=\"field-group\"><strong>\u7eb9\u9970 (Markings):<\/strong><textarea rows=\"1\" id=\"markings\" placeholder=\"\u4f8b\u5982: \u7eb9\u8eab\u3001\u75a4\u75d5\u3001\u5370\u8bb0\" class=\"editable-field\"><\/textarea><\/div>\n                            <\/div>\n                        <\/div>\n                        <div>\n                            <h4 class=\"cv-subsection-title\">\u8138\u90e8\u7279\u5f81 (Facial Features)<\/h4>\n                            <div class=\"space-y-4\">\n                                <div class=\"field-group\"><strong>\u8138\u578b (Face Shape):<\/strong><textarea rows=\"1\" id=\"face_shape\" placeholder=\"\u4f8b\u5982: \u9e45\u86cb\u8138\u3001\u5706\u5f62\u8138\" class=\"editable-field\"><\/textarea><\/div>\n                                <div class=\"field-group\"><strong>\u80a4\u8272 (Skin Tone):<\/strong><textarea rows=\"1\" id=\"skin_tone\" placeholder=\"\u4f8b\u5982: \u5c0f\u9ea6\u8272\u3001\u51b7\u767d\u76ae\" class=\"editable-field\"><\/textarea><\/div>\n                                <div class=\"field-group\"><strong>\u9f3b\u6881 (Nose):<\/strong><textarea rows=\"1\" id=\"nose\" placeholder=\"\u4f8b\u5982: \u9ad8\u633a\u3001\u5c0f\u5de7\" class=\"editable-field\"><\/textarea><\/div>\n                                <div class=\"field-group\"><strong>\u5634\u5507 (Lips):<\/strong><textarea rows=\"1\" id=\"lips\" placeholder=\"\u4f8b\u5982: \u4e30\u6ee1\u3001\u8584\u5507\" class=\"editable-field\"><\/textarea><\/div>\n                                <div class=\"field-group\"><strong>\u773c\u775b (Eyes):<\/strong><textarea id=\"eyes\" placeholder=\"\u63cf\u8ff0\u773c\u775b\u7684\u5f62\u72b6\u3001\u795e\u6001\u548c\u77b3\u8272\" class=\"editable-field\"><\/textarea><\/div>\n                            <\/div>\n                        <\/div>\n                     <\/div>\n\n                     <div class=\"field-group mt-4\"><strong>\u53d1\u578b (Hair Style):<\/strong><textarea id=\"hair_style\" placeholder=\"\u63cf\u8ff0\u53d1\u578b\u3001\u53d1\u8d28\u548c\u53d1\u8272\" class=\"editable-field\"><\/textarea><\/div>\n                <\/section>\n                \n                <div class=\"newspaper-divider my-8\"><\/div>\n\n                <!-- \u7b2c\u4e09\u90e8\u5206: \u6027\u683c\u4e0e\u884c\u4e3a -->\n                <section class=\"mb-8\">\n                    <h3 class=\"cv-section-title\">\u7b2c\u4e09\u90e8\u5206\uff1a\u6027\u683c\u4e0e\u884c\u4e3a (Personality &#038; Behavior)<\/h3>\n                    <div class=\"grid grid-cols-1 md:grid-cols-3 gap-x-8\">\n                        <div class=\"field-group\"><strong>\u6838\u5fc3\u6027\u683c (Core Personality):<\/strong><textarea id=\"personality_core\" placeholder=\"\u89d2\u8272\u6700\u672c\u8d28\u7684\u6027\u683c, \u53ef\u7528';'\u5206\u70b9\" class=\"editable-field\"><\/textarea><\/div>\n                        <div class=\"field-group\"><strong>\u8868\u9762\u6027\u683c (Surface Personality):<\/strong><textarea id=\"personality_surface\" placeholder=\"\u89d2\u8272\u5bf9\u5916\u5c55\u73b0\u7684\u6027\u683c, \u53ef\u7528';'\u5206\u70b9\" class=\"editable-field\"><\/textarea><\/div>\n                        <div class=\"field-group\"><strong>\u5185\u5728\u6027\u683c (Inner Personality):<\/strong><textarea id=\"personality_inner\" placeholder=\"\u89d2\u8272\u5185\u5fc3\u6df1\u5904\u7684\u771f\u5b9e\u6027\u683c, \u53ef\u7528';'\u5206\u70b9\" class=\"editable-field\"><\/textarea><\/div>\n                    <\/div>\n                    <div class=\"field-group\"><strong >\u6c14\u8d28 (Temperament):<\/strong><textarea id=\"temperament\" placeholder=\"\u89d2\u8272\u4e0d\u8a00\u8bed\u65f6\u7ed9\u4eba\u7684\u611f\u89c9\" class=\"editable-field\"><\/textarea><\/div>\n                    <div class=\"field-group\"><strong >\u793e\u4ea4\u4e3e\u6b62 (Social Deportment):<\/strong><textarea id=\"social_deportment\" placeholder=\"\u63cf\u8ff0\u89d2\u8272\u7684\u793e\u4ea4\u98ce\u683c\u548c\u884c\u4e3a\" class=\"editable-field\"><\/textarea><\/div>\n                    <div class=\"field-group\"><strong >\u4e60\u60ef\u6027\u5c0f\u52a8\u4f5c (Habitual Mannerisms):<\/strong><textarea id=\"habitual_mannerisms\" placeholder=\"\u89d2\u8272\u4e0b\u610f\u8bc6\u7684\u6807\u5fd7\u6027\u52a8\u4f5c, \u53ef\u7528';'\u5206\u70b9\" class=\"editable-field\"><\/textarea><\/div>\n                    <div class=\"field-group\"><strong >\u5904\u4e8b\u98ce\u683c (Handling Style):<\/strong><textarea id=\"handling_style\" placeholder=\"\u63cf\u8ff0\u89d2\u8272\u5904\u7406\u95ee\u9898\u548c\u51b2\u7a81\u7684\u65b9\u5f0f\" class=\"editable-field\"><\/textarea><\/div>\n                <\/section>\n\n                <div class=\"newspaper-divider my-8\"><\/div>\n\n                <!-- \u7b2c\u56db\u90e8\u5206: \u751f\u6d3b\u65b9\u5f0f -->\n                <section class=\"mb-8\">\n                     <h3 class=\"cv-section-title\">\u7b2c\u56db\u90e8\u5206\uff1a\u751f\u6d3b\u65b9\u5f0f (Lifestyle)<\/h3>\n                     <h4 class=\"cv-subsection-title\">\u7a7f\u8863\u98ce\u683c (Clothing Style)<\/h4>\n                     <div class=\"grid grid-cols-1 md:grid-cols-3 gap-x-8\">\n                        <div class=\"field-group\"><strong>\u65e5\u5e38\u7740\u88c5 (Daily Clothing):<\/strong><textarea id=\"clothing_daily\" placeholder=\"\u63cf\u8ff0\u65e5\u5e38\u7684\u7a7f\u7740\u98ce\u683c, \u53ef\u7528';'\u5206\u70b9\" class=\"editable-field\"><\/textarea><\/div>\n                        <div class=\"field-group\"><strong>\u7279\u5b9a\u573a\u5408 (Specific Occasions):<\/strong><textarea id=\"clothing_specific_occasions\" placeholder=\"\u63cf\u8ff0\u7279\u6b8a\u573a\u5408\u7684\u7740\u88c5, \u53ef\u7528';'\u5206\u70b9\" class=\"editable-field\"><\/textarea><\/div>\n                        <div class=\"field-group\"><strong>\u914d\u9970\u504f\u597d (Accessories):<\/strong><textarea id=\"accessories\" placeholder=\"\u63cf\u8ff0\u504f\u597d\u7684\u914d\u9970, \u53ef\u7528';'\u5206\u70b9\" class=\"editable-field\"><\/textarea><\/div>\n                     <\/div>\n                     <div class=\"field-group\"><strong >\u7231\u597d (Hobbies):<\/strong><textarea id=\"hobbies\" placeholder=\"\u63cf\u8ff0\u89d2\u8272\u7684\u5174\u8da3\u7231\u597d, \u53ef\u7528';'\u5206\u70b9\" class=\"editable-field\"><\/textarea><\/div>\n                     <h4 class=\"cv-subsection-title\">\u4eba\u751f\u76ee\u6807 (Life Goals)<\/h4>\n                     <div class=\"field-group\"><strong>\u77ed\u671f\u76ee\u6807 (Short-term Goals):<\/strong><textarea id=\"short_term_goals\" placeholder=\"\u89d2\u8272\u8fd1\u671f\u7684\u5177\u4f53\u76ee\u6807; \u53ef\u7528';'\u5206\u70b9\" class=\"editable-field\"><\/textarea><\/div>\n                     <div class=\"field-group\"><strong>\u957f\u671f\u76ee\u6807 (Long-term Goals):<\/strong><textarea id=\"long_term_goals\" placeholder=\"\u89d2\u8272\u7684\u7ec8\u6781\u8ffd\u6c42\u6216\u4eba\u751f\u7406\u60f3; \u53ef\u7528';'\u5206\u70b9\" class=\"editable-field\"><\/textarea><\/div>\n                     <div class=\"field-group\"><strong>\u4ef7\u503c\u89c2 (Values):<\/strong><textarea id=\"values\" placeholder=\"\u89d2\u8272\u8861\u91cf\u662f\u975e\u5bf9\u9519\u7684\u6838\u5fc3\u6807\u51c6; \u53ef\u7528';'\u5206\u70b9\" class=\"editable-field\"><\/textarea><\/div>\n                <\/section>\n\n                <div class=\"newspaper-divider my-8\"><\/div>\n\n                <!-- \u7b2c\u4e94\u90e8\u5206: \u6c9f\u901a\u7279\u5f81 -->\n                <section class=\"mb-8\">\n                    <h3 class=\"cv-section-title\">\u7b2c\u4e94\u90e8\u5206\uff1a\u6c9f\u901a\u7279\u5f81 (Communication)<\/h3>\n                    <div class=\"field-group\"><strong >\u53e3\u5934\u7985\/\u5e38\u7528\u8bcd (Common Phrases):<\/strong><textarea id=\"common_phrases\" placeholder=\"\u89d2\u8272\u7684\u53e3\u5934\u7985\u6216\u5e38\u7528\u8bed, \u53ef\u7528';'\u5206\u70b9\" class=\"editable-field\"><\/textarea><\/div>\n                    <div class=\"field-group\"><strong >\u4eba\u9645\u5173\u7cfb (Relationships):<\/strong><textarea id=\"relationships\" placeholder=\"\u63cf\u8ff0\u89d2\u8272\u7684\u4eba\u9645\u4ea4\u5f80\u72b6\u51b5\u548c\u91cd\u8981\u5173\u7cfb\" class=\"editable-field\"><\/textarea><\/div>\n                <\/section>\n\n                <div class=\"newspaper-divider my-8\"><\/div>\n\n                <!-- \u7b2c\u516d\u90e8\u5206: \u89d2\u8272\u5c0f\u4f20 -->\n                <section>\n                    <h3 class=\"cv-section-title\">\u7b2c\u516d\u90e8\u5206\uff1a\u89d2\u8272\u5c0f\u4f20 (Character Biography)<\/h3>\n                    <div class=\"field-group\"><strong >\u5c0f\u4f20 (Biography):<\/strong><textarea id=\"biography\" placeholder=\"\u8be6\u7ec6\u63cf\u8ff0\u89d2\u8272\u7684\u80cc\u666f\u6545\u4e8b\u3001\u7ecf\u5386\u548c\u52a8\u673a...\" class=\"editable-field\"><\/textarea><\/div>\n                <\/section>\n            <\/div>\n        <\/div>\n    <\/div>\n\n    <script>\n        \/\/ --- Global State ---\n        let sessionHistory = [];\n        let lastUserInputs = null;\n\n        \/\/ --- DOM Elements ---\n        const generateBtn = document.getElementById('generateBtn');\n        const btnText = document.getElementById('btn-text');\n        const btnSpinner = document.getElementById('btn-spinner');\n        const downloadBtn = document.getElementById('downloadBtn');\n        const characterContent = document.getElementById('character-content');\n        const generateImageBtn = document.getElementById('generateImageBtn');\n        const imageLoader = document.getElementById('image-loader');\n        const imageError = document.getElementById('image-error');\n        const characterImage = document.getElementById('character-image');\n        const imagePlaceholder = document.getElementById('image-placeholder');\n        const imagePrompt = document.getElementById('image_prompt');\n        const clearBtn = document.getElementById('clearBtn');\n        const historyDropdown = document.getElementById('historyDropdown');\n        \n        \/\/ Custom context elements\n        const worldviewUploadBtn = document.getElementById('worldview_upload_btn');\n        const worldviewUploadInput = document.getElementById('worldview_upload_input');\n        const worldviewContext = document.getElementById('worldview_context');\n        const otherCharactersUploadBtn = document.getElementById('other_characters_upload_btn');\n        const otherCharactersUploadInput = document.getElementById('other_characters_upload_input');\n        const otherCharactersContext = document.getElementById('other_characters_context');\n\n        \/\/ Loading Overlay Elements\n        const loadingOverlay = document.getElementById('loading-overlay');\n        const loaderContainer = document.getElementById('loader-container');\n        const errorContainer = document.getElementById('error-container');\n        const closeErrorBtn = document.getElementById('close-error-btn');\n\n        const fieldIdToNameMap = {\n            name: \"\u59d3\u540d\", age: \"\u5e74\u9f84\", gender: \"\u6027\u522b\", race: \"\u79cd\u65cf\", identities: \"\u8eab\u4efd\u8ba4\u77e5\", \n            growth_experience: \"\u6210\u957f\u7ecf\u5386\", family_background: \"\u5bb6\u5ead\u80cc\u666f\", key_events: \"\u5173\u952e\u7ebf\u7d22\", archetype: \"\u539f\u578b\", character_role: \"\u89d2\u8272\u5b9a\u4f4d\",\n            overall_impression: \"\u603b\u4f53\u5370\u8c61\", height: \"\u8eab\u9ad8\", weight: \"\u4f53\u91cd\", body_shape: \"\u8eab\u6750\", cup_size: \"\u7f69\u676f\u5c3a\u5bf8\", markings: \"\u7eb9\u9970\",\n            face_shape: \"\u8138\u578b\", skin_tone: \"\u76ae\u80a4\u989c\u8272\", nose: \"\u9f3b\u6881\", lips: \"\u5634\u5507\", eyes: \"\u773c\u775b\", hair_style: \"\u53d1\u578b\",\n            personality_core: \"\u6838\u5fc3\u6027\u683c\", personality_surface: \"\u8868\u9762\u6027\u683c\", personality_inner: \"\u5185\u5728\u6027\u683c\", \n            temperament: \"\u6c14\u8d28\", social_deportment: \"\u793e\u4ea4\u4e3e\u6b62\", habitual_mannerisms: \"\u4e60\u60ef\u6027\u5c0f\u52a8\u4f5c\", handling_style: \"\u5904\u4e8b\u98ce\u683c\",\n            clothing_daily: \"\u65e5\u5e38\u7740\u88c5\", clothing_specific_occasions: \"\u7279\u5b9a\u573a\u5408\", accessories: \"\u914d\u9970\u504f\u597d\", hobbies: \"\u7231\u597d\",\n            short_term_goals: \"\u77ed\u671f\u76ee\u6807\", long_term_goals: \"\u957f\u671f\u76ee\u6807\", values: \"\u4ef7\u503c\u89c2\",\n            common_phrases: \"\u53e3\u5934\u7985\/\u5e38\u7528\u8bcd\", relationships: \"\u4eba\u9645\u5173\u7cfb\", image_prompt: \"\u56fe\u50cf\u63d0\u793a\u8bcd\",\n            biography: \"\u89d2\u8272\u5c0f\u4f20\"\n        };\n        \n        const resetLastInputs = () => {\n            lastUserInputs = null;\n        };\n\n\n        const fieldIds = [\n            'name', 'age', 'gender', 'race', 'identities', 'growth_experience', 'family_background', 'key_events', 'archetype', 'character_role',\n            'overall_impression', 'height', 'weight', 'body_shape', 'cup_size', 'markings',\n            'face_shape', 'skin_tone', 'nose', 'lips', 'eyes', 'hair_style',\n            'personality_core', 'personality_surface', 'personality_inner', 'temperament', 'social_deportment', 'habitual_mannerisms', 'handling_style',\n            'clothing_daily', 'clothing_specific_occasions', 'accessories', 'hobbies', 'short_term_goals', 'long_term_goals', 'values',\n            'common_phrases', 'relationships',\n            'image_prompt',\n            'biography'\n        ];\n\n        \/\/ --- API Config ---\n        const apiKey = \"AIzaSyC40qEHSKeIxe-pRGaxayG0LzP-S5YAP60\";\n        const textApiUrl = `https:\/\/generativelanguage.googleapis.com\/v1beta\/models\/gemini-flash-latest:generateContent?key=${apiKey}`;\n        const imageApiUrl = `https:\/\/generativelanguage.googleapis.com\/v1beta\/models\/imagen-3.0-generate-002:predict?key=${apiKey}`;\n\n        \/\/ --- Functions ---\n        const autoResizeTextarea = (textarea) => {\n            if (!textarea) return;\n            textarea.style.height = 'auto';\n            textarea.style.height = (textarea.scrollHeight) + 'px';\n        };\n        \n        const updateUI = (data) => {\n            for (const id in data) {\n                const element = document.getElementById(id);\n                if (element) {\n                    element.value = data[id] || '';\n                    if (element.tagName.toLowerCase() === 'textarea') {\n                        autoResizeTextarea(element);\n                    }\n                }\n            }\n            generateImageBtn.disabled = false;\n            downloadBtn.disabled = false;\n            imagePlaceholder.classList.remove('hidden');\n            characterImage.classList.add('hidden');\n            document.querySelectorAll('textarea').forEach(autoResizeTextarea);\n        };\n        \n        const updateHistoryDropdown = () => {\n            historyDropdown.innerHTML = ''; \/\/ Clear existing options\n            if (sessionHistory.length === 0) {\n                const option = document.createElement('option');\n                option.value = \"-1\";\n                option.textContent = \"-- \u6682\u65e0\u5386\u53f2 --\";\n                historyDropdown.appendChild(option);\n            } else {\n                 sessionHistory.forEach((character, index) => {\n                    const option = document.createElement('option');\n                    option.value = index;\n                    option.textContent = character.name || `\u672a\u547d\u540d\u89d2\u8272 ${index + 1}`;\n                    historyDropdown.appendChild(option);\n                });\n                historyDropdown.value = sessionHistory.length - 1; \/\/ Select the latest one\n            }\n        };\n\n        const clearCharacterSheet = () => {\n            \/\/ Clear main character sheet fields\n            fieldIds.forEach(id => {\n                const element = document.getElementById(id);\n                if (element) {\n                    element.value = '';\n                }\n            });\n\n            \/\/ Reset image placeholder and buttons\n            imagePlaceholder.classList.remove('hidden');\n            characterImage.classList.add('hidden');\n            imageError.classList.add('hidden');\n            imageLoader.classList.add('hidden');\n            generateImageBtn.disabled = true;\n            downloadBtn.disabled = true;\n\n            \/\/ Reset history dropdown to placeholder\n            if (historyDropdown.options.length > 0) {\n                historyDropdown.value = \"-1\";\n            }\n            \n            resetLastInputs();\n\n            \/\/ Re-run auto-resize on all textareas to collapse them\n            document.querySelectorAll('textarea').forEach(autoResizeTextarea);\n        };\n        \n        const showLoadingOverlay = () => {\n            loaderContainer.classList.remove('hidden');\n            errorContainer.classList.add('hidden');\n            loadingOverlay.classList.remove('hidden');\n            document.body.style.overflow = 'hidden';\n        };\n\n        const showErrorOverlay = () => {\n            loaderContainer.classList.add('hidden');\n            errorContainer.classList.remove('hidden');\n            loadingOverlay.classList.remove('hidden');\n             document.body.style.overflow = 'hidden';\n        };\n\n        const hideOverlay = () => {\n            loadingOverlay.classList.add('hidden');\n            document.body.style.overflow = '';\n        };\n\n        const setButtonLoadingState = (isLoading) => {\n             generateBtn.disabled = isLoading;\n             btnText.classList.toggle('hidden', isLoading);\n             btnSpinner.classList.toggle('hidden', !isLoading);\n        };\n\n\n        const generateCharacter = async (retryCount = 0) => {\n            setButtonLoadingState(true);\n            \n            if(retryCount === 0) {\n                 showLoadingOverlay();\n            }\n            \n            if (lastUserInputs === null) {\n                const constraints = [];\n                fieldIds.forEach(id => {\n                    if (id === 'image_prompt') return;\n                    const element = document.getElementById(id);\n                    const value = element ? element.value.trim() : '';\n                    if (value) {\n                        constraints.push(`\u89d2\u8272\u7684'${fieldIdToNameMap[id]}'\u5fc5\u987b\u662f'${value}'\u3002`);\n                    }\n                });\n                \n                lastUserInputs = {\n                    constraints: constraints,\n                    worldContext: worldviewContext.value.trim(),\n                    otherCharsContext: otherCharactersContext.value.trim()\n                };\n            }\n\n            let userQuery = `\u8bf7\u4ee5\u4e2d\u6587\u968f\u673a\u751f\u6210\u4e00\u4e2a\u8be6\u7ec6\u7684\u89d2\u8272\u6863\u6848\uff0c\u6863\u6848\u9700\u4e25\u683c\u9075\u5faa\u6240\u6709\u6307\u5b9a\u7684\u5b57\u6bb5\u3002\u8bf7\u53c2\u8003\u6bcf\u4e2a\u5b57\u6bb5\u7684\u5360\u4f4d\u7b26\uff08placeholder\uff09\u6765\u7406\u89e3\u671f\u671b\u7684\u5185\u5bb9\u683c\u5f0f\u548c\u98ce\u683c\u3002\u5bf9\u4e8e\u591a\u70b9\u63cf\u8ff0\u7684\u5b57\u6bb5\uff08\u4f8b\u5982\u6027\u683c\uff09\uff0c\u8bf7\u4f7f\u7528';'\u7b26\u53f7\u5206\u70b9\u3002\u786e\u4fdd\u751f\u6210\u7684\u5185\u5bb9\u8fde\u8d2f\u3001\u8be6\u7ec6\u4e14\u5bcc\u6709\u521b\u610f\u3002\u5bf9\u4e8e\u201c\u89d2\u8272\u5c0f\u4f20\u201d\u5b57\u6bb5\uff0c\u5185\u5bb9\u957f\u5ea6\u4e0d\u5f97\u5c11\u4e8e750\u4e2a\u6c49\u5b57\u3002\u540c\u65f6\uff0c\u8bf7\u6839\u636e\u751f\u6210\u89d2\u8272\u7684\u5916\u8c8c\u7279\u5f81\uff0c\u989d\u5916\u751f\u6210\u4e00\u6bb5\u7eaf\u82f1\u6587\u7684\u3001\u7b26\u5408Midjourney\u8bed\u6cd5\u7684\u8be6\u7ec6\u56fe\u50cf\u63d0\u793a\u8bcd\uff08prompt\uff09\uff0c\u5e76\u5c06\u5176\u653e\u5165'image_prompt'\u5b57\u6bb5\u4e2d\u3002\u8fd9\u6bb5\u63d0\u793a\u8bcd\u5fc5\u987b\u5305\u542b\u4ee5\u4e0b\u56fa\u5b9a\u6807\u7b7e\uff1aconcept art, character design sheet, pure white background\u3002`;\n            \n            if (lastUserInputs.constraints.length > 0) {\n                userQuery += `\\n\\n\u8bf7\u4e25\u683c\u9075\u5b88\u4ee5\u4e0b\u8bbe\u5b9a\uff1a\\n${lastUserInputs.constraints.join('\\n')}\\n\u5bf9\u4e8e\u7528\u6237\u672a\u6307\u5b9a\u7684\u5176\u4ed6\u6240\u6709\u5c5e\u6027\uff0c\u8bf7\u4f60\u968f\u673a\u751f\u6210\u3002`;\n            }\n\n            if (lastUserInputs.worldContext) {\n                userQuery += `\\n\\n\u6b64\u5916\uff0c\u8bf7\u5c06\u89d2\u8272\u7f6e\u4e8e\u4ee5\u4e0b\u4e16\u754c\u89c2\u80cc\u666f\u4e2d\u8fdb\u884c\u521b\u4f5c\uff1a\\n${lastUserInputs.worldContext}`;\n            }\n\n            if (lastUserInputs.otherCharsContext) {\n                userQuery += `\\n\\n\u8bf7\u5728\u521b\u4f5c\u65f6\u53c2\u8003\u4ee5\u4e0b\u5176\u4ed6\u89d2\u8272\u7684\u4fe1\u606f\uff1a\\n${lastUserInputs.otherCharsContext}`;\n            }\n\n            const systemPrompt = `\u4f60\u662f\u4e00\u4f4d\u9876\u7ea7\u7684\u521b\u610f\u4f5c\u5bb6\u548c\u89d2\u8272\u8bbe\u8ba1\u5e08\u3002\u5728\u751f\u6210\u89d2\u8272\u65f6\uff0c\u4f60\u5fc5\u987b\u6df1\u5165\u601d\u8003\u5e76\u786e\u4fdd\u89d2\u8272\u5177\u6709\u5f3a\u70c8\u7684\u5f20\u529b\u3001\u72ec\u7279\u6027\u548c\u5185\u5728\u903b\u8f91\u3002\u8bf7\u4e25\u683c\u9075\u5faa\u4ee5\u4e0b\u6838\u5fc3\u8bbe\u8ba1\u539f\u5219\uff0c\u5c06\u5b83\u4eec\u8d2f\u7a7f\u4e8e\u4f60\u521b\u9020\u7684\u6bcf\u4e00\u4e2a\u7ec6\u8282\u4e2d\uff1a\n\n**\u4e00\u3001 \u6838\u5fc3\u5185\u5728\u8981\u7d20 (Core Internal Elements):**\n* **\u52a8\u673a (Motivation):** \u660e\u786e\u89d2\u8272\u6700\u6e34\u671b\u5f97\u5230\u4ec0\u4e48\uff0c\u8fd9\u662f\u9a71\u52a8TA\u884c\u52a8\u7684\u6838\u5fc3\u71c3\u6599\u3002\n* **\u6050\u60e7\/\u5f31\u70b9 (Fear\/Weakness):** \u601d\u8003\u89d2\u8272\u6700\u5bb3\u6015\u5931\u53bb\u4ec0\u4e48\uff0c\u8fd9\u6784\u6210\u4e86TA\u7684\u8f6f\u808b\u548c\u6f5c\u5728\u7684\u60b2\u5267\u6027\u3002\n* **\u77db\u76fe\u4e0e\u7f3a\u9677 (Conflict & Flaws):** \u8d4b\u4e88\u89d2\u8272\u4e0d\u5b8c\u7f8e\u7684\u3001\u751a\u81f3\u662f\u76f8\u4e92\u77db\u76fe\u7684\u7279\u8d28\u3002\u4e00\u4e2a\u6709\u7f3a\u9677\u7684\u89d2\u8272\u624d\u66f4\u771f\u5b9e\u53ef\u4fe1\u3002\n* **\u4fe1\u5ff5\u4e0e\u4ef7\u503c\u89c2 (Beliefs & Values):** \u5efa\u7acb\u89d2\u8272\u575a\u5b9a\u7684\u6838\u5fc3\u4fe1\u5ff5\uff0c\u8fd9\u5c06\u51b3\u5b9aTA\u5728\u91cd\u5927\u6289\u62e9\u9762\u524d\u7684\u7acb\u573a\u548c\u884c\u52a8\u3002\n* **\u6210\u957f\u5f27\u7ebf (Growth Arc):** \u6784\u601d\u89d2\u8272\u4ece\u6545\u4e8b\u5f00\u59cb\u5230\u7ed3\u675f\u53ef\u80fd\u53d1\u751f\u7684\u53d8\u5316\uff0c\u65e0\u8bba\u662f\u53d8\u5f97\u66f4\u597d\u8fd8\u662f\u66f4\u574f\u3002\n\n**\u4e8c\u3001 \u5916\u5728\u8868\u73b0\u8981\u7d20 (External Expression):**\n* **\u89c6\u89c9\u7279\u5f81 (Visual Features):** \u7cbe\u5fc3\u8bbe\u8ba1\u89d2\u8272\u7684\u53d1\u578b\u3001\u9762\u5bb9\u3001\u8eab\u6750\u3001\u80a4\u8272\u3002\n* **\u670d\u9970\u98ce\u683c (Clothing Style):** \u89d2\u8272\u7684\u7a7f\u7740\u5e94\u53cd\u6620\u5176\u6587\u5316\u3001\u9636\u5c42\u3001\u6027\u683c\uff0c\u6ce8\u610f\u989c\u8272\u3001\u6750\u8d28\u548c\u6587\u5316\u611f\u3002\n* **\u72ec\u7279\u6807\u5fd7 (Unique Marks):** \u4e3a\u89d2\u8272\u8bbe\u8ba1\u4e00\u4e2a\u72ec\u7279\u7684\u6807\u5fd7\uff0c\u5982\u4f24\u75a4\u3001\u9970\u54c1\u3001\u9053\u5177\u6216\u4e60\u60ef\u6027\u52a8\u4f5c\u3002\n* **\u6c14\u8d28\u4e0e\u59ff\u6001 (Temperament & Posture):** \u63cf\u8ff0\u89d2\u8272\u9759\u6b62\u65f6\u7684\u72b6\u6001\uff0c\u662f\u9ad8\u50b2\u3001\u968f\u6027\u3001\u62d8\u8c28\u8fd8\u662f\u8b66\u60d5\uff1f\n\n**\u4e09\u3001 \u80cc\u666f\u4e0e\u5173\u7cfb (Background & Relationships):**\n* **\u51fa\u8eab\u4e0e\u7ecf\u5386 (Origin & Experience):** \u8bbe\u5b9a\u5173\u952e\u7684\u7ae5\u5e74\u4e8b\u4ef6\u3001\u6559\u80b2\u80cc\u666f\u3001\u521b\u4f24\u6216\u8363\u8000\u65f6\u523b\uff0c\u8fd9\u4e9b\u5171\u540c\u5851\u9020\u4e86TA\u3002\n* **\u6587\u5316\u73af\u5883 (Cultural Environment):** \u601d\u8003\u89d2\u8272\u6240\u5904\u7684\u793e\u4f1a\u3001\u4e16\u754c\u89c2\u5982\u4f55\u5f71\u54cd\u4e86TA\u7684\u8a00\u884c\u4e3e\u6b62\u548c\u601d\u7ef4\u65b9\u5f0f\u3002\n* **\u4eba\u9645\u5173\u7cfb (Interpersonal Relationships):** \u81f3\u5c11\u8bbe\u5b9a\u4e00\u4e2a\u5bf9\u89d2\u8272\u81f3\u5173\u91cd\u8981\u7684\u5173\u7cfb\uff0c\u5982\u670b\u53cb\u3001\u654c\u4eba\u3001\u5bfc\u5e08\u6216\u5bf9\u624b\u3002\n* **\u4e0e\u6545\u4e8b\u4e3b\u7ebf\u7684\u8054\u7cfb (Plot Connection):** \u601d\u8003\u8fd9\u4e2a\u89d2\u8272\u5728\u5b8f\u5927\u53d9\u4e8b\u4e2d\u626e\u6f14\u7684\u89d2\u8272\uff0cTA\u4f1a\u63a8\u52a8\u3001\u963b\u788d\u6216\u6539\u53d8\u4ec0\u4e48\uff1f\n\n**\u56db\u3001 \u8868\u73b0\u65b9\u5f0f (Methods of Expression):**\n* **\u8bed\u8a00\u98ce\u683c (Language Style):** \u8bbe\u8ba1\u89d2\u8272\u7684\u8bf4\u8bdd\u4e60\u60ef\u3001\u5e38\u7528\u8bcd\u3001\u53e3\u5934\u7985\u548c\u8bed\u6c14\u3002\n* **\u52a8\u4f5c\u4e0e\u7ec6\u8282 (Actions & Details):** \u6784\u601d\u89d2\u8272\u65e0\u610f\u8bc6\u7684\u5c0f\u52a8\u4f5c\u3001\u6807\u5fd7\u6027\u7684\u624b\u52bf\u6216\u7ad9\u59ff\u3002\n* **\u8c61\u5f81\u6027\u5143\u7d20 (Symbolic Elements):** \u4e3a\u89d2\u8272\u5173\u8054\u4e00\u4e2a\u8c61\u5f81\u7269\uff0c\u5982\u4e00\u6735\u82b1\u3001\u4e00\u9996\u6b4c\u3001\u4e00\u628a\u5251\u6216\u4e00\u6bb5\u683c\u8a00\uff0c\u4ee5\u589e\u52a0\u5176\u6df1\u5ea6\u3002\n* **\u4ee3\u5165\u611f (Empathy):** \u786e\u4fdd\u89d2\u8272\u7684\u884c\u4e3a\u903b\u8f91\u5408\u7406\uff0c\u52a8\u673a\u53ef\u88ab\u7406\u89e3\uff0c\u5373\u4f7f\u662f\u53cd\u6d3e\uff0c\u4e5f\u8981\u8ba9\u8bfb\u8005\u80fd\u660e\u767d\u5176\u884c\u4e3a\u7684\u6839\u6e90\u3002\n\n**\u4e94\u3001 \u4e13\u9879\u6307\u4ee4 (Specific Instructions):**\n* **\u539f\u578b\u5206\u6790 (Archetype Analysis):** \u5728'archetype'\u5b57\u6bb5\u4e2d\uff0c\u5fc5\u987b\u786e\u5b9a\u89d2\u8272\u6700\u7b26\u5408\u7684\u4e00\u4e2a\u539f\u578b\uff08\u5982\u82f1\u96c4\u3001\u5bfc\u5e08\u3001\u53cd\u53db\u8005\u7b49\uff09\uff0c\u5e76\u63d0\u4f9b\u4e00\u6bb5\u8be6\u7ec6\u7684\u5206\u6790\u8bf4\u660e\u4e3a\u4ec0\u4e48\u3002\n* **\u89d2\u8272\u5b9a\u4f4d (Character Role):** \u5728'character_role'\u5b57\u6bb5\u4e2d\uff0c\u5fc5\u987b\u5206\u6790\u5e76\u8bf4\u660e\u8be5\u89d2\u8272\u6700\u9002\u5408\u7684\u5b9a\u4f4d\uff08\u5982\u4e3b\u89d2\u3001\u914d\u89d2\u3001\u53cd\u6d3e\u3001\u53cb\u65b9NPC\u7b49\uff09\uff0c\u5e76\u89e3\u91ca\u539f\u56e0\u3002\n* **\u547d\u540d\u89c4\u5219 (Naming Convention):** \u89d2\u8272\u7684\u59d3\u540d\u5fc5\u987b\u4e25\u683c\u8d34\u5408\u7528\u6237\u63d0\u4f9b\u7684\u2018\u4e16\u754c\u89c2\u80cc\u666f\u2019\u3002\u82e5\u7528\u6237\u672a\u63d0\u4f9b\u4e16\u754c\u89c2\uff0c\u5219\u89d2\u8272\u7684\u59d3\u540d\u5e94\u66f4\u591a\u6837\u5316\uff0c\u968f\u673a\u53d6\u81ea\u4e0d\u540c\u7684\u6587\u5316\u80cc\u666f\u548c\u547d\u540d\u65b9\u5f0f\uff08\u4f8b\u5982\uff0c\u4e1c\u65b9\u3001\u897f\u65b9\u3001\u5947\u5e7b\u3001\u79d1\u5e7b\u7b49\uff09\u3002\n\n**\u6700\u7ec8\u8981\u6c42:**\n* **\u72ec\u7279\u4e14\u4e00\u81f4:** \u907f\u514d\u8138\u8c31\u5316\u548c\u523b\u677f\u5370\u8c61\uff0c\u786e\u4fdd\u89d2\u8272\u7684\u6240\u6709\u8bbe\u5b9a\u76f8\u4e92\u547c\u5e94\uff0c\u5f62\u6210\u4e00\u4e2a\u6709\u673a\u7684\u6574\u4f53\u3002\n* **\u903b\u8f91\u5408\u7406:** \u89d2\u8272\u7684\u6240\u6709\u884c\u4e3a\u90fd\u5fc5\u987b\u7b26\u5408\u5176\u6027\u683c\u548c\u52a8\u673a\uff0c\u4e0d\u80fd\u51fa\u73b0OOC\uff08Out of Character\uff09\u7684\u60c5\u51b5\u3002\n* **\u5185\u5916\u547c\u5e94:** \u89d2\u8272\u7684\u5916\u5728\u7ec6\u8282\uff08\u5982\u670d\u9970\u3001\u4f24\u75a4\uff09\u5fc5\u987b\u80fd\u591f\u53cd\u6620\u5176\u5185\u5728\u7684\u6027\u683c\u6216\u7ecf\u5386\u3002\n\n\u5728\u9075\u5faa\u4ee5\u4e0a\u6240\u6709\u539f\u5219\u7684\u57fa\u7840\u4e0a\uff0c\u8bf7\u6839\u636e\u7528\u6237\u7684\u5177\u4f53\u8f93\u5165\uff08\u5305\u62ec\u6863\u6848\u5b57\u6bb5\u3001\u4e16\u754c\u89c2\u3001\u5176\u4ed6\u89d2\u8272\u4fe1\u606f\uff09\uff0c\u4ee5JSON\u683c\u5f0f\u8fd4\u56de\u4e00\u4e2a\u5b8c\u6574\u3001\u6df1\u523b\u3001\u5bcc\u6709\u751f\u547d\u529b\u7684\u89d2\u8272\u6863\u6848\u3002`;\n            \n            const payload = {\n                contents: [{ parts: [{ text: userQuery }] }],\n                systemInstruction: { parts: [{ text: systemPrompt }] },\n                generationConfig: {\n                    responseMimeType: \"application\/json\",\n                    responseSchema: { type: \"OBJECT\", properties: fieldIds.reduce((obj, id) => ({ ...obj, [id]: { type: \"STRING\" } }), {}) },\n                    temperature: 1.0, topP: 0.95,\n                }\n            };\n            try {\n                const response = await fetch(textApiUrl, { method: 'POST', headers: { 'Content-Type': 'application\/json' }, body: JSON.stringify(payload) });\n                if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);\n                const result = await response.json();\n                const candidate = result.candidates?.[0];\n                if (candidate?.content?.parts?.[0]?.text) {\n                    const characterData = JSON.parse(candidate.content.parts[0].text);\n                    sessionHistory.push(characterData);\n                    updateHistoryDropdown();\n                    updateUI(characterData);\n                    hideOverlay();\n                    setButtonLoadingState(false);\n                } else { \n                    throw new Error(\"\u672a\u80fd\u4eceAPI\u54cd\u5e94\u4e2d\u89e3\u6790\u51fa\u6709\u6548\u5185\u5bb9\u3002\"); \n                }\n            } catch (error) {\n                console.error('API\u8bf7\u6c42\u5931\u8d25:', error);\n                if (retryCount < 3) {\n                    setTimeout(() => generateCharacter(retryCount + 1), Math.pow(2, retryCount) * 1000);\n                } else {\n                    showErrorOverlay();\n                    setButtonLoadingState(false);\n                }\n            }\n        };\n\n        const generateImage = async () => {\n            const prompt = imagePrompt.value.trim();\n            if (!prompt) {\n                alert('\u56fe\u50cf\u63d0\u793a\u8bcd\u4e0d\u80fd\u4e3a\u7a7a\uff01');\n                return;\n            }\n\n            generateImageBtn.disabled = true;\n            imageLoader.classList.remove('hidden');\n            imagePlaceholder.classList.add('hidden');\n            characterImage.classList.add('hidden');\n            imageError.classList.add('hidden');\n            \n            const payload = { instances: [{ prompt: prompt }], parameters: { \"sampleCount\": 1 } };\n            try {\n                const response = await fetch(imageApiUrl, { method: 'POST', headers: { 'Content-Type': 'application\/json' }, body: JSON.stringify(payload) });\n                if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);\n                const result = await response.json();\n                if (result.predictions?.[0]?.bytesBase64Encoded) {\n                    characterImage.src = `data:image\/png;base64,${result.predictions[0].bytesBase64Encoded}`;\n                    characterImage.classList.remove('hidden');\n                } else { throw new Error(\"API\u672a\u8fd4\u56de\u6709\u6548\u7684\u56fe\u7247\u6570\u636e\u3002\"); }\n            } catch (error) {\n                console.error(\"\u56fe\u7247\u751f\u6210\u5931\u8d25:\", error);\n                imageError.classList.remove('hidden');\n                imagePlaceholder.classList.remove('hidden');\n            } finally {\n                imageLoader.classList.add('hidden');\n                generateImageBtn.disabled = false;\n            }\n        };\n        \n        const downloadJson = () => {\n            const characterData = {};\n            fieldIds.forEach(id => {\n                const element = document.getElementById(id);\n                characterData[id] = element ? element.value : '';\n            });\n\n            const characterName = document.getElementById('name').value.trim() || 'character';\n            const filename = `${characterName}.json`;\n            const jsonStr = JSON.stringify(characterData, null, 2); \/\/ \u683c\u5f0f\u5316JSON\n            const blob = new Blob([jsonStr], { type: 'application\/json' });\n            const url = URL.createObjectURL(blob);\n\n            const a = document.createElement('a');\n            a.href = url;\n            a.download = filename;\n            document.body.appendChild(a);\n            a.click();\n            document.body.removeChild(a);\n            URL.revokeObjectURL(url);\n        };\n        \n        const handleFileUpload = (event, targetTextarea) => {\n            const file = event.target.files[0];\n            if (!file) return;\n            const reader = new FileReader();\n            reader.onload = (e) => {\n                try {\n                    const json = JSON.parse(e.target.result);\n                    targetTextarea.value = JSON.stringify(json, null, 2); \/\/ Pretty-print\n                    autoResizeTextarea(targetTextarea);\n                    resetLastInputs(); \/\/ Changing context should be a new input\n                } catch (error) {\n                    alert('\u65e0\u6548\u7684 JSON \u6587\u4ef6\uff01');\n                    console.error(\"JSON parsing error:\", error);\n                }\n            };\n            reader.readAsText(file);\n             event.target.value = ''; \/\/ Reset input\n        };\n\n        const loadCharacterFromHistory = (event) => {\n            const selectedIndex = parseInt(event.target.value, 10);\n            if (selectedIndex >= 0 && selectedIndex < sessionHistory.length) {\n                const characterData = sessionHistory[selectedIndex];\n                updateUI(characterData);\n                resetLastInputs(); \/\/ Loading from history is like a new input, forcing re-capture if user generates again\n            }\n        };\n\n        \/\/ --- Event Listeners ---\n        generateBtn.addEventListener('click', () => generateCharacter());\n        generateImageBtn.addEventListener('click', generateImage);\n        downloadBtn.addEventListener('click', downloadJson);\n        closeErrorBtn.addEventListener('click', hideOverlay);\n        clearBtn.addEventListener('click', clearCharacterSheet);\n        historyDropdown.addEventListener('change', loadCharacterFromHistory);\n\n        document.querySelectorAll('textarea.editable-field').forEach(textarea => {\n            textarea.addEventListener('input', () => autoResizeTextarea(textarea));\n        });\n\n        \/\/ File Upload Listeners\n        worldviewUploadBtn.addEventListener('click', () => worldviewUploadInput.click());\n        worldviewUploadInput.addEventListener('change', (e) => handleFileUpload(e, worldviewContext));\n        \n        otherCharactersUploadBtn.addEventListener('click', () => otherCharactersUploadInput.click());\n        otherCharactersUploadInput.addEventListener('change', (e) => handleFileUpload(e, otherCharactersContext));\n\n        \/\/ Listen for any input changes to reset the generation constraints\n        fieldIds.forEach(id => {\n            const element = document.getElementById(id);\n            if (element) {\n                element.addEventListener('input', resetLastInputs);\n            }\n        });\n        worldviewContext.addEventListener('input', resetLastInputs);\n        otherCharactersContext.addEventListener('input', resetLastInputs);\n\n\n        \/\/ Initial resize for all textareas on page load\n        window.addEventListener('load', () => {\n             document.querySelectorAll('textarea.editable-field').forEach(autoResizeTextarea);\n        });\n    <\/script>\n<\/body>\n<\/html>\n\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-324","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/archim.top\/index.php\/wp-json\/wp\/v2\/pages\/324","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/archim.top\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/archim.top\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/archim.top\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/archim.top\/index.php\/wp-json\/wp\/v2\/comments?post=324"}],"version-history":[{"count":12,"href":"https:\/\/archim.top\/index.php\/wp-json\/wp\/v2\/pages\/324\/revisions"}],"predecessor-version":[{"id":351,"href":"https:\/\/archim.top\/index.php\/wp-json\/wp\/v2\/pages\/324\/revisions\/351"}],"wp:attachment":[{"href":"https:\/\/archim.top\/index.php\/wp-json\/wp\/v2\/media?parent=324"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}