diff --git a/package-lock.json b/package-lock.json index 509d998..90c5b9b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,20 +8,20 @@ "name": "omniai-web-preview", "version": "0.1.0", "dependencies": { - "@ant-design/icons": "^5.3.0", - "@xyflow/react": "^12.10.2", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "zustand": "^5.0.13" + "@ant-design/icons": "5.3.0", + "@xyflow/react": "12.10.2", + "react": "18.2.0", + "react-dom": "18.2.0", + "zustand": "5.0.13" }, "devDependencies": { - "@types/react": "^18.2.0", - "@types/react-dom": "^18.2.0", - "@vitejs/plugin-react": "^4.2.1", - "playwright": "^1.60.0", - "sharp": "^0.34.5", - "typescript": "^5.3.3", - "vite": "^5.1.0", + "@types/react": "18.2.0", + "@types/react-dom": "18.2.0", + "@vitejs/plugin-react": "4.2.1", + "playwright": "1.60.0", + "sharp": "0.34.5", + "typescript": "5.3.3", + "vite": "5.1.0", "vite-plugin-compression2": "2.5.3" } }, @@ -47,14 +47,14 @@ } }, "node_modules/@ant-design/icons": { - "version": "5.6.1", - "resolved": "https://registry.npmmirror.com/@ant-design/icons/-/icons-5.6.1.tgz", - "integrity": "sha512-0/xS39c91WjPAZOWsvi1//zjx6kAp4kxWwctR6kuU6p133w8RU0D2dSCvZC19uQyharg/sAvYxGYWl01BbZZfg==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-5.3.0.tgz", + "integrity": "sha512-69FgBsIkeCjw72ZU3fJpqjhmLCPrzKGEllbrAZK7MUdt1BrKsyG6A8YDCBPKea27UQ0tRXi33PcjR4tp/tEXMg==", "license": "MIT", "dependencies": { "@ant-design/colors": "^7.0.0", "@ant-design/icons-svg": "^4.4.0", - "@babel/runtime": "^7.24.8", + "@babel/runtime": "^7.11.2", "classnames": "^2.2.6", "rc-util": "^5.31.1" }, @@ -103,7 +103,6 @@ "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", @@ -376,9 +375,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", + "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==", "cpu": [ "ppc64" ], @@ -393,9 +392,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz", + "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==", "cpu": [ "arm" ], @@ -410,9 +409,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz", + "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==", "cpu": [ "arm64" ], @@ -427,9 +426,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz", + "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==", "cpu": [ "x64" ], @@ -444,9 +443,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz", + "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==", "cpu": [ "arm64" ], @@ -461,9 +460,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz", + "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==", "cpu": [ "x64" ], @@ -478,9 +477,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz", + "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==", "cpu": [ "arm64" ], @@ -495,9 +494,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz", + "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==", "cpu": [ "x64" ], @@ -512,9 +511,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz", + "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==", "cpu": [ "arm" ], @@ -529,9 +528,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz", + "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==", "cpu": [ "arm64" ], @@ -546,9 +545,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz", + "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==", "cpu": [ "ia32" ], @@ -563,9 +562,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz", + "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==", "cpu": [ "loong64" ], @@ -580,9 +579,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz", + "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==", "cpu": [ "mips64el" ], @@ -597,9 +596,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz", + "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==", "cpu": [ "ppc64" ], @@ -614,9 +613,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz", + "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==", "cpu": [ "riscv64" ], @@ -631,9 +630,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz", + "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==", "cpu": [ "s390x" ], @@ -648,9 +647,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz", + "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==", "cpu": [ "x64" ], @@ -665,9 +664,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz", + "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==", "cpu": [ "x64" ], @@ -682,9 +681,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz", + "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==", "cpu": [ "x64" ], @@ -699,9 +698,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz", + "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==", "cpu": [ "x64" ], @@ -716,9 +715,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz", + "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==", "cpu": [ "arm64" ], @@ -733,9 +732,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz", + "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==", "cpu": [ "ia32" ], @@ -750,9 +749,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz", + "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==", "cpu": [ "x64" ], @@ -1306,13 +1305,6 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.27", - "resolved": "https://registry.npmmirror.com/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", - "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", - "dev": true, - "license": "MIT" - }, "node_modules/@rollup/pluginutils": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", @@ -1795,46 +1787,52 @@ "license": "MIT" }, "node_modules/@types/react": { - "version": "18.3.28", - "resolved": "https://registry.npmmirror.com/@types/react/-/react-18.3.28.tgz", - "integrity": "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.0.tgz", + "integrity": "sha512-0FLj93y5USLHdnhIhABk83rm8XEGA7kH3cr+YUlvxoUGp1xNt/DINUMvqPxLyOQMzLmZe8i4RTHbvb8MC7NmrA==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "@types/prop-types": "*", - "csstype": "^3.2.2" + "@types/scheduler": "*", + "csstype": "^3.0.2" } }, "node_modules/@types/react-dom": { - "version": "18.3.7", - "resolved": "https://registry.npmmirror.com/@types/react-dom/-/react-dom-18.3.7.tgz", - "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@types/react": "^18.0.0" - } - }, - "node_modules/@vitejs/plugin-react": { - "version": "4.7.0", - "resolved": "https://registry.npmmirror.com/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", - "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-8yQrvS6sMpSwIovhPOwfyNf2Wz6v/B62LFSVYQ85+Rq3tLsBIG7rP5geMxaijTUxSkrO6RzN/IRuIAADYQsleA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.28.0", - "@babel/plugin-transform-react-jsx-self": "^7.27.1", - "@babel/plugin-transform-react-jsx-source": "^7.27.1", - "@rolldown/pluginutils": "1.0.0-beta.27", + "@types/react": "*" + } + }, + "node_modules/@types/scheduler": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.26.0.tgz", + "integrity": "sha512-WFHp9YUJQ6CKshqoC37iOlHnQSmxNc795UhB26CyBBttrN9svdIrUjl/NjnNmfcwtncN0h/0PPAFWv9ovP8mLA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.2.1.tgz", + "integrity": "sha512-oojO9IDc4nCUUi8qIR11KoQm0XFFLIwsRBwHRR4d/88IWghn1y6ckz/bJ8GHDCsYEJee8mDzqtJxh15/cisJNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.23.5", + "@babel/plugin-transform-react-jsx-self": "^7.23.3", + "@babel/plugin-transform-react-jsx-source": "^7.23.3", "@types/babel__core": "^7.20.5", - "react-refresh": "^0.17.0" + "react-refresh": "^0.14.0" }, "engines": { "node": "^14.18.0 || >=16.0.0" }, "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + "vite": "^4.2.0 || ^5.0.0" } }, "node_modules/@xyflow/react": { @@ -1930,7 +1928,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.10.12", "caniuse-lite": "^1.0.30001782", @@ -2049,7 +2046,6 @@ "resolved": "https://registry.npmmirror.com/d3-selection/-/d3-selection-3.0.0.tgz", "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", "license": "ISC", - "peer": true, "engines": { "node": ">=12" } @@ -2134,9 +2130,9 @@ "license": "ISC" }, "node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", + "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -2147,29 +2143,29 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" + "@esbuild/aix-ppc64": "0.19.12", + "@esbuild/android-arm": "0.19.12", + "@esbuild/android-arm64": "0.19.12", + "@esbuild/android-x64": "0.19.12", + "@esbuild/darwin-arm64": "0.19.12", + "@esbuild/darwin-x64": "0.19.12", + "@esbuild/freebsd-arm64": "0.19.12", + "@esbuild/freebsd-x64": "0.19.12", + "@esbuild/linux-arm": "0.19.12", + "@esbuild/linux-arm64": "0.19.12", + "@esbuild/linux-ia32": "0.19.12", + "@esbuild/linux-loong64": "0.19.12", + "@esbuild/linux-mips64el": "0.19.12", + "@esbuild/linux-ppc64": "0.19.12", + "@esbuild/linux-riscv64": "0.19.12", + "@esbuild/linux-s390x": "0.19.12", + "@esbuild/linux-x64": "0.19.12", + "@esbuild/netbsd-x64": "0.19.12", + "@esbuild/openbsd-x64": "0.19.12", + "@esbuild/sunos-x64": "0.19.12", + "@esbuild/win32-arm64": "0.19.12", + "@esbuild/win32-ia32": "0.19.12", + "@esbuild/win32-x64": "0.19.12" } }, "node_modules/escalade": { @@ -2399,7 +2395,7 @@ }, "node_modules/rc-util": { "version": "5.44.4", - "resolved": "https://registry.npmmirror.com/rc-util/-/rc-util-5.44.4.tgz", + "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.44.4.tgz", "integrity": "sha512-resueRJzmHG9Q6rI/DfK6Kdv9/Lfls05vzMs1Sk3M2P+3cJa+MakaZyWY8IPfehVuhPJFKrIY1IK4GqbiaiY5w==", "license": "MIT", "dependencies": { @@ -2412,11 +2408,10 @@ } }, "node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmmirror.com/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", "license": "MIT", - "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -2425,29 +2420,28 @@ } }, "node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmmirror.com/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", "license": "MIT", - "peer": true, "dependencies": { "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" + "scheduler": "^0.23.0" }, "peerDependencies": { - "react": "^18.3.1" + "react": "^18.2.0" } }, "node_modules/react-is": { "version": "18.3.1", - "resolved": "https://registry.npmmirror.com/react-is/-/react-is-18.3.1.tgz", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "license": "MIT" }, "node_modules/react-refresh": { - "version": "0.17.0", - "resolved": "https://registry.npmmirror.com/react-refresh/-/react-refresh-0.17.0.tgz", - "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", + "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", "dev": true, "license": "MIT", "engines": { @@ -2602,9 +2596,9 @@ "optional": true }, "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -2656,16 +2650,15 @@ } }, "node_modules/vite": { - "version": "5.4.21", - "resolved": "https://registry.npmmirror.com/vite/-/vite-5.4.21.tgz", - "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.0.tgz", + "integrity": "sha512-STmSFzhY4ljuhz14bg9LkMTk3d98IO6DIArnTY6MeBwiD1Za2StcQtz7fzOUnRCqrHSD5+OS2reg4HOz1eoLnw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.43", - "rollup": "^4.20.0" + "esbuild": "^0.19.3", + "postcss": "^8.4.35", + "rollup": "^4.2.0" }, "bin": { "vite": "bin/vite.js" @@ -2684,7 +2677,6 @@ "less": "*", "lightningcss": "^1.21.0", "sass": "*", - "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" @@ -2702,9 +2694,6 @@ "sass": { "optional": true }, - "sass-embedded": { - "optional": true - }, "stylus": { "optional": true }, diff --git a/src/App.tsx b/src/App.tsx index 4f20bfc..318a603 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1218,6 +1218,8 @@ function App() { onOpenEcommerce={() => handleSetView("ecommerce")} onOpenScriptReview={() => handleSetView("scriptTokens")} onOpenTokenMonitor={() => handleSetView("tokenUsage")} + onSelectView={handleSetView} + onOpenImageTool={handleOpenImageWorkbenchTool} /> ); } diff --git a/src/assets/toolbox/toolbox_img_0.png b/src/assets/toolbox/toolbox_img_0.png new file mode 100644 index 0000000..c620c4d Binary files /dev/null and b/src/assets/toolbox/toolbox_img_0.png differ diff --git a/src/assets/toolbox/toolbox_img_1.png b/src/assets/toolbox/toolbox_img_1.png new file mode 100644 index 0000000..3ff5165 Binary files /dev/null and b/src/assets/toolbox/toolbox_img_1.png differ diff --git a/src/assets/toolbox/去水印前.png b/src/assets/toolbox/去水印前.png new file mode 100644 index 0000000..f734abf Binary files /dev/null and b/src/assets/toolbox/去水印前.png differ diff --git a/src/assets/toolbox/去水印后.png b/src/assets/toolbox/去水印后.png new file mode 100644 index 0000000..0648e8f Binary files /dev/null and b/src/assets/toolbox/去水印后.png differ diff --git a/src/assets/toolbox/牛仔.png b/src/assets/toolbox/牛仔.png new file mode 100644 index 0000000..c620c4d Binary files /dev/null and b/src/assets/toolbox/牛仔.png differ diff --git a/src/assets/toolbox/西装.png b/src/assets/toolbox/西装.png new file mode 100644 index 0000000..3ff5165 Binary files /dev/null and b/src/assets/toolbox/西装.png differ diff --git a/src/features/home/HomePage.tsx b/src/features/home/HomePage.tsx index 15faf38..425802d 100644 --- a/src/features/home/HomePage.tsx +++ b/src/features/home/HomePage.tsx @@ -8,7 +8,10 @@ import { ThunderboltOutlined, } from "@ant-design/icons"; import { useCallback, useEffect, useMemo, useRef, useState, type CSSProperties } from "react"; +import type { WebViewKey, WebImageWorkbenchTool } from "../../types"; import WelcomeSplash from "./WelcomeSplash"; +import ToolboxSection from "./ToolboxSection"; +import ScriptReviewVisual from "./ScriptReviewVisual"; const OSS_MUBAN = "https://stringtest.oss-cn-hangzhou.aliyuncs.com/muban"; const heroImage1 = `${OSS_MUBAN}/hero-1.png`; @@ -24,6 +27,8 @@ interface HomePageProps { onOpenEcommerce: () => void; onOpenScriptReview?: () => void; onOpenTokenMonitor?: () => void; + onSelectView: (view: WebViewKey) => void; + onOpenImageTool?: (tool: WebImageWorkbenchTool) => void; } const HOME_BACKGROUND_VIDEO = "https://stringtest.oss-cn-hangzhou.aliyuncs.com/%E6%A0%B7%E7%89%87.mp4"; @@ -112,7 +117,7 @@ function getHomeCarouselCardStyle(offset: number): CSSProperties { } as CSSProperties; } -function HomePage({ onOpenGenerate, onOpenEcommerce, onOpenScriptReview, onOpenTokenMonitor }: HomePageProps) { +function HomePage({ onOpenGenerate, onOpenEcommerce, onOpenScriptReview, onOpenTokenMonitor, onSelectView, onOpenImageTool }: HomePageProps) { const [splashDismissed, setSplashDismissed] = useState(() => sessionStorage.getItem("omniai:splash-seen") === "1"); const [activeSlideIndex, setActiveSlideIndex] = useState(0); const [carouselMotion, setCarouselMotion] = useState(null); @@ -296,7 +301,11 @@ function HomePage({ onOpenGenerate, onOpenEcommerce, onOpenScriptReview, onOpenT + + diff --git a/src/features/home/ScriptReviewVisual.tsx b/src/features/home/ScriptReviewVisual.tsx new file mode 100644 index 0000000..14981b7 --- /dev/null +++ b/src/features/home/ScriptReviewVisual.tsx @@ -0,0 +1,133 @@ +import { useEffect, useRef, useState } from "react"; + +const DIMS = [ + { name: "钩子设计", score: 19, max: 20, hue: 145 }, + { name: "角色塑造", score: 13, max: 15, hue: 155 }, + { name: "剧情结构", score: 18, max: 20, hue: 165 }, + { name: "逻辑严密", score: 14, max: 15, hue: 175 }, + { name: "场景构建", score: 15, max: 15, hue: 185 }, + { name: "内容深度", score: 15, max: 15, hue: 195 }, +]; + +function ScriptReviewVisual() { + const [animated, setAnimated] = useState(false); + const [activeDim, setActiveDim] = useState(null); + const [score, setScore] = useState(0); + const scoreRef = useRef(0); + const frameRef = useRef(null); + + useEffect(() => { + const el = document.getElementById("script-review-visual"); + if (!el) return; + + const observer = new IntersectionObserver( + ([entry]) => { + if (entry?.isIntersecting) { + setAnimated(true); + observer.disconnect(); + } + }, + { threshold: 0.3 } + ); + observer.observe(el); + return () => observer.disconnect(); + }, []); + + useEffect(() => { + if (!animated) return; + const start = performance.now(); + const target = 94; + const dur = 1400; + function tick(now: number) { + const t = Math.min((now - start) / dur, 1); + const e = 1 - Math.pow(1 - t, 3); + setScore(Math.round(e * target)); + if (t < 1) frameRef.current = requestAnimationFrame(tick); + } + frameRef.current = requestAnimationFrame(tick); + return () => { if (frameRef.current) cancelAnimationFrame(frameRef.current); }; + }, [animated]); + + const totalScore = 94; + const grade = "S"; + + return ( +
+
+
+ {score} + / 100 +
+ + {grade}级 +
+
+
+
+
+
+ 击败全国 92% 剧本 +
+
+ +
+
+ {DIMS.map((dim, i) => { + const pct = dim.score / dim.max; + const lossPct = (dim.max - dim.score) / dim.max; + const isPerfect = dim.score === dim.max; + const height = animated ? pct * 76 : 0; + const lossHeight = animated ? lossPct * 76 : 0; + + return ( +
setActiveDim(activeDim === i ? null : i)} + > +
+ {lossPct > 0 && ( +
+ )} +
+
+
+ {dim.name} +
+
+ ); + })} +
+ + {activeDim !== null && (() => { + const d = DIMS[activeDim]!; + return ( +
+ {d.name} + + {d.score}/{d.max} + {d.score === d.max && " ★"} + +
+ ); + })()} + +
+ 得分 + 扣分 +
+
+
+ ); +} + +export default ScriptReviewVisual; diff --git a/src/features/home/ToolboxSection.tsx b/src/features/home/ToolboxSection.tsx new file mode 100644 index 0000000..7a7fbca --- /dev/null +++ b/src/features/home/ToolboxSection.tsx @@ -0,0 +1,233 @@ +import { ToolOutlined } from "@ant-design/icons"; +import type { WebViewKey, WebImageWorkbenchTool } from "../../types"; +import toolImageBefore from "../../assets/toolbox/牛仔.png"; +import toolImageAfter from "../../assets/toolbox/西装.png"; +import watermarkBefore from "../../assets/toolbox/去水印前.png"; +import watermarkAfter from "../../assets/toolbox/去水印后.png"; + +interface ToolboxSectionProps { + onSelectView: (view: WebViewKey) => void; + onOpenImageTool?: (tool: WebImageWorkbenchTool) => void; +} + +const TOOLS = [ + { + key: "image-studio", + icon: "🎨", + name: "图片工作室", + desc: "图片二次加工,调色裁剪特效风格迁移", + }, + { + key: "lens-lab", + icon: "📷", + name: "镜头实验室", + desc: "多视角镜头生成,不同角度与姿势", + }, + { + key: "digital-human", + icon: "🧑", + name: "一键数字人", + desc: "上传图片和音频,生成数字人视频", + }, + { + key: "watermark-removal", + icon: "✨", + name: "去除水印", + desc: "AI智能识别去除图片视频水印", + }, +]; + +const CARDS = [ + { + key: "image-studio", + title: "图片工作室", + tag: "图片加工", + icon: "🎨", + features: ["二次加工", "调色", "裁剪", "风格迁移"], + targetView: "imageWorkbench" as WebViewKey, + render: () => ( +
+
+
+ 图片加工前 +
+
原始图片
+
+
+
+
+ 图片加工后 +
+
处理后
+
+
+ ), + }, + { + key: "lens-lab", + title: "镜头实验室", + tag: "多视角", + icon: "📷", + features: ["正面", "45°侧", "俯拍", "仰拍", "背面"], + targetView: "imageWorkbench" as WebViewKey, + render: () => ( +
+ {["正面", "45°侧", "俯拍", "仰拍", "背面"].map((angle) => ( +
+
+
+
{angle}
+
+ ))} +
+ ), + }, + { + key: "digital-human", + title: "一键数字人", + tag: "视频生成", + icon: "🧑", + features: ["上传人像", "匹配音频", "唇形同步", "生成视频"], + targetView: "digitalHuman" as WebViewKey, + render: () => ( +
+
+
+
STATIC
+
+
静态人像
+
+
+
+
+
+
+
+ +
+
+
LIVE
+
+
数字人视频
+
+
+ ), + }, + { + key: "watermark-removal", + title: "去除水印", + tag: "AI清除", + icon: "✨", + features: ["智能识别", "精准去除", "无损画质"], + targetView: "watermarkRemoval" as WebViewKey, + render: () => ( +
+
+
+ 去水印前 +
+
含水印
+
+
+
+
+ 去水印后 +
+
已清除
+
+
+ ), + }, +]; + +function ToolboxSection({ onSelectView, onOpenImageTool }: ToolboxSectionProps) { + const handleCardClick = (targetView: WebViewKey) => { + onSelectView(targetView); + }; + + return ( +
+
+ {/* Left Panel */} + + + {/* Grid Area */} +
+ {CARDS.map((card) => ( +
handleCardClick(card.targetView)} + > +
+
+
{card.icon}
+
{card.title}
+
+
{card.tag}
+
+
+ {card.render()} +
+
+ {card.features.map((feat, i) => ( + + {i > 0 && |} + {feat} + + ))} +
+
+ ))} +
+
+
+ ); +} + +export default ToolboxSection; diff --git a/src/features/script-tokens/ScriptTokensPage.tsx b/src/features/script-tokens/ScriptTokensPage.tsx index 9e43d2a..ace66b0 100644 --- a/src/features/script-tokens/ScriptTokensPage.tsx +++ b/src/features/script-tokens/ScriptTokensPage.tsx @@ -1,13 +1,20 @@ -import { CopyOutlined, DownOutlined, DownloadOutlined, FileTextOutlined, ReloadOutlined, TrophyOutlined, UploadOutlined } from "@ant-design/icons"; -import { useMemo, useRef, useState, type ChangeEvent, type KeyboardEvent } from "react"; +import { + CheckCircleFilled, + CopyOutlined, + DownloadOutlined, + FileTextOutlined, + UploadOutlined, +} from "@ant-design/icons"; +import { useEffect, useRef, useState, type ChangeEvent, type KeyboardEvent } from "react"; import { evaluateScript } from "../../api/scriptEvalClient"; +import { useSessionStore } from "../../stores"; interface ScoreDimension { key: string; label: string; maxScore: number; - weight: number; - description: string; + hint: string; + detail: string; } interface EvalResult { @@ -20,103 +27,46 @@ interface EvalResult { suggestions: string[]; } -const RADAR_CENTER = 100; -const RADAR_RADIUS = 82; -const RADAR_ANGLES = [-90, -30, 30, 90, 150, 210]; +interface HistoryEntry { + name: string; + date: string; + timestamp: number; + score: number; + grade: string; +} -const scoreDimensions: ScoreDimension[] = [ - { - key: "hook", - label: "钩子设计", - maxScore: 20, - weight: 0.2, - description: "开篇吸引力、悬念设置、黄金三秒法则", - }, - { - key: "character", - label: "角色塑造", - maxScore: 15, - weight: 0.15, - description: "人物立体度、动机合理性、弧光设计", - }, - { - key: "plot", - label: "剧情结构", - maxScore: 20, - weight: 0.2, - description: "起承转合、节奏把控、冲突设计", - }, - { - key: "dialogue", - label: "台词对白", - maxScore: 15, - weight: 0.15, - description: "语言质感、角色差异化、潜台词", - }, - { - key: "visual", - label: "画面表现", - maxScore: 15, - weight: 0.15, - description: "镜头感、空间层次、视觉冲击力", - }, - { - key: "content", - label: "内容深度", - maxScore: 15, - weight: 0.15, - description: "主题表达、情感共鸣、思想内核", - }, +function getGrade(score: number): string { + if (score >= 97) return "S+"; + if (score >= 93) return "S"; + if (score >= 88) return "A+"; + if (score >= 83) return "A"; + if (score >= 78) return "B+"; + if (score >= 70) return "B"; + return "C"; +} + +const HISTORY_KEY = "omniai:script-eval-history"; + +function loadHistory(): HistoryEntry[] { + try { + const raw = localStorage.getItem(HISTORY_KEY); + return raw ? (JSON.parse(raw) as HistoryEntry[]) : []; + } catch { return []; } +} + +function saveHistory(entries: HistoryEntry[]) { + try { localStorage.setItem(HISTORY_KEY, JSON.stringify(entries.slice(0, 20))); } catch { /* quota exceeded */ } +} + +const SCORE_DIMENSIONS: ScoreDimension[] = [ + { key: "hook", label: "钩子设计", maxScore: 20, hint: "开篇吸引力·悬念设置·黄金三秒", detail: "开篇即抛出高概念钩子,悬念设置紧凑有力。" }, + { key: "character", label: "角色塑造", maxScore: 15, hint: "人物立体度·动机合理性·弧光设计", detail: "主角动机有铺垫,配角功能性较强,人物弧光尚可进一步深化。" }, + { key: "plot", label: "剧情结构", maxScore: 20, hint: "起承转合·节奏把控·冲突设计", detail: "起承转合完整,节奏把控稳健,冲突设计有张力。" }, + { key: "logic", label: "逻辑严密", maxScore: 15, hint: "世界观自洽·伏笔回收·因果链", detail: "世界观整体自洽,伏笔设置到位。" }, + { key: "visual", label: "场景构建", maxScore: 15, hint: "空间描写·视听语言·画面想象力", detail: "视觉意象统一而强烈,场景描写极具画面感。" }, + { key: "content", label: "内容深度", maxScore: 15, hint: "主题表达·情感共鸣·思想内核", detail: "核心设定将科技伦理与人性困境紧密结合,主题表达深刻有力。" }, ]; -function radarPoint(angle: number, radius: number) { - const radians = (angle * Math.PI) / 180; - return { - x: RADAR_CENTER + radius * Math.cos(radians), - y: RADAR_CENTER + radius * Math.sin(radians), - }; -} - -function makeRadarPoints(scores: Record | null) { - if (!scores) return "100,100 100,100 100,100 100,100 100,100 100,100"; - - return scoreDimensions - .map((dimension, index) => { - const ratio = Math.max(0, Math.min(1, (scores[dimension.key] ?? 0) / dimension.maxScore)); - const point = radarPoint(RADAR_ANGLES[index] ?? 0, RADAR_RADIUS * ratio); - return `${point.x.toFixed(1)},${point.y.toFixed(1)}`; - }) - .join(" "); -} - -function RadarPreview({ result }: { result: EvalResult | null }) { - return ( -
- -
- ); -} - function formatReportMarkdown(result: EvalResult, script: string): string { const lines: string[] = []; lines.push(`# 剧本评测报告`); @@ -127,10 +77,10 @@ function formatReportMarkdown(result: EvalResult, script: string): string { lines.push(result.summary); lines.push(""); lines.push(`## 六维评分`); - for (const dim of scoreDimensions) { + for (const dim of SCORE_DIMENSIONS) { const score = result.dimensionScores[dim.key] ?? 0; const pct = Math.round((score / dim.maxScore) * 100); - lines.push(`- **${dim.label}**: ${score}/${dim.maxScore} (${pct}%) — ${dim.description}`); + lines.push(`- **${dim.label}**: ${score}/${dim.maxScore} (${pct}%) — ${dim.hint}`); } if (result.highlights.length > 0) { lines.push(""); @@ -150,13 +100,6 @@ function formatReportMarkdown(result: EvalResult, script: string): string { lines.push(""); lines.push(`---`); lines.push(`*评测时间: ${new Date().toLocaleString("zh-CN")}*`); - lines.push(""); - lines.push(`
原始剧本 (${script.length} 字)`); - lines.push(""); - lines.push("```"); - lines.push(script.slice(0, 2000) + (script.length > 2000 ? "\n...(已截断)" : "")); - lines.push("```"); - lines.push("
"); return lines.join("\n"); } @@ -165,39 +108,44 @@ function ScriptTokensPage() { const [loading, setLoading] = useState(false); const [result, setResult] = useState(null); const [evalError, setEvalError] = useState(null); - const [detailsExpanded, setDetailsExpanded] = useState(true); const [uploadedFile, setUploadedFile] = useState<{ name: string; size: number } | null>(null); const [copied, setCopied] = useState(false); + const [activeDim, setActiveDim] = useState(null); + const [animatedScore, setAnimatedScore] = useState(0); + const [history, setHistory] = useState(loadHistory); const fileInputRef = useRef(null); + const scoreFrameRef = useRef(null); + const session = useSessionStore((s) => s.session); const hasContent = Boolean(script.trim()); - const lineNumbers = useMemo(() => { - const count = Math.min(160, Math.max(10, script.split(/\r\n|\r|\n/).length)); - return Array.from({ length: count }, (_, index) => index + 1); - }, [script]); - const handleUploadKeyDown = (event: KeyboardEvent) => { - if (event.key !== "Enter" && event.key !== " ") return; - event.preventDefault(); - fileInputRef.current?.click(); - }; + // Score animation + useEffect(() => { + if (!result) return; + const start = performance.now(); + const target = result.totalScore; + const dur = 1400; + function tick(now: number) { + const t = Math.min((now - start) / dur, 1); + const e = 1 - Math.pow(1 - t, 3); + setAnimatedScore(Math.round(e * target)); + if (t < 1) scoreFrameRef.current = requestAnimationFrame(tick); + } + scoreFrameRef.current = requestAnimationFrame(tick); + return () => { if (scoreFrameRef.current) cancelAnimationFrame(scoreFrameRef.current); }; + }, [result]); const handleFileUpload = async (event: ChangeEvent) => { const file = event.target.files?.[0]; if (!file) return; - const ext = file.name.slice(file.name.lastIndexOf(".")).toLowerCase(); const readable = [".txt", ".md"].includes(ext) || file.type === "text/plain" || file.type === "text/markdown"; setUploadedFile({ name: file.name, size: file.size }); - if (readable) { setScript(await file.text()); } else { - setScript( - `[已上传文件:${file.name}]\n\n暂不支持解析 ${ext.toUpperCase()} 格式,请上传 TXT 或 MD 文件,或直接粘贴剧本文本后开始评测。`, - ); + setScript(`[已上传文件:${file.name}]\n\n暂不支持解析 ${ext.toUpperCase()} 格式,请上传 TXT 或 MD 文件。`); } - event.target.value = ""; }; @@ -206,22 +154,36 @@ function ScriptTokensPage() { setLoading(true); setResult(null); setEvalError(null); + setAnimatedScore(0); + setActiveDim(null); try { const aiResult = await evaluateScript(script); setResult(aiResult); + const g = getGrade(aiResult.totalScore); + const entry: HistoryEntry = { + name: uploadedFile?.name?.replace(/\.[^.]+$/, "") ?? `剧本 ${new Date().toLocaleDateString("zh-CN")}`, + date: new Date().toLocaleDateString("zh-CN", { month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit" }), + timestamp: Date.now(), + score: aiResult.totalScore, + grade: g, + }; + const updated = [entry, ...loadHistory().filter((h) => h.name !== entry.name || h.score !== entry.score)]; + saveHistory(updated); + setHistory(updated); } catch (err) { setEvalError(err instanceof Error ? err.message : "评测服务暂时不可用,请稍后重试"); } - setDetailsExpanded(true); setLoading(false); }; const handleReset = () => { setScript(""); setResult(null); - setDetailsExpanded(true); + setEvalError(null); setUploadedFile(null); setCopied(false); + setAnimatedScore(0); + setActiveDim(null); if (fileInputRef.current) fileInputRef.current.value = ""; }; @@ -260,226 +222,348 @@ function ScriptTokensPage() { URL.revokeObjectURL(url); }; - const scoreStatus = loading ? "评测中" : result ? "评测完成" : "待生成评分"; - const scoreHint = - result?.summary ?? - (hasContent ? "点击「开始评测」生成六维雷达评分和优化路径。" : "粘贴完整剧本后,点击「开始评测」生成六维雷达评分和优化路径。"); + const uploadKeyDown = (event: KeyboardEvent) => { + if (event.key !== "Enter" && event.key !== " ") return; + event.preventDefault(); + fileInputRef.current?.click(); + }; + + const grade = result ? getGrade(result.totalScore) : null; + const beatPct = result ? (result.totalScore >= 95 ? 97 : result.totalScore >= 88 ? 92 : result.totalScore >= 80 ? 85 : 72) : 0; + const compactTitle = uploadedFile?.name?.replace(/\.[^.]+$/, "") ?? "剧本评测"; return ( -
-
-
-
-
-
fileInputRef.current?.click()} - onKeyDown={handleUploadKeyDown} - > - -
- {uploadedFile ? uploadedFile.name : "粘贴文本或上传文档"} -
- {uploadedFile ? `${(uploadedFile.size / 1024).toFixed(1)}KB,已载入文件信息` : "建议包含场景、角色、动作和台词"} -
+
+
+ {/* Left Panel */} +