deprecated some constructor arguments
2
.gitignore
vendored
@ -20,7 +20,7 @@ gradio/templates/frontend/static
|
||||
*.db
|
||||
*.sqlite3
|
||||
gradio/launches.json
|
||||
flagged
|
||||
flagged/*
|
||||
|
||||
# Tests
|
||||
.coverage
|
||||
|
195
frontend/package-lock.json
generated
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "gradio",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 2,
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
@ -25990,13 +25990,13 @@
|
||||
"acorn-jsx": {
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
|
||||
"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
|
||||
"requires": {}
|
||||
"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="
|
||||
},
|
||||
"acorn-node": {
|
||||
"version": "1.8.2",
|
||||
"resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz",
|
||||
"integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"acorn": "^7.0.0",
|
||||
"acorn-walk": "^7.0.0",
|
||||
@ -26054,14 +26054,12 @@
|
||||
"ajv-errors": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz",
|
||||
"integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==",
|
||||
"requires": {}
|
||||
"integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ=="
|
||||
},
|
||||
"ajv-keywords": {
|
||||
"version": "3.5.2",
|
||||
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
|
||||
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
|
||||
"requires": {}
|
||||
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ=="
|
||||
},
|
||||
"alphanum-sort": {
|
||||
"version": "1.0.2",
|
||||
@ -26152,7 +26150,8 @@
|
||||
"arg": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/arg/-/arg-5.0.1.tgz",
|
||||
"integrity": "sha512-e0hDa9H2Z9AwFkk2qDlwhoMYE4eToKarchkQHovNdLTCYMHZHeRjI71crOh+dio4K6u1IcwubQqo79Ga4CyAQA=="
|
||||
"integrity": "sha512-e0hDa9H2Z9AwFkk2qDlwhoMYE4eToKarchkQHovNdLTCYMHZHeRjI71crOh+dio4K6u1IcwubQqo79Ga4CyAQA==",
|
||||
"dev": true
|
||||
},
|
||||
"argparse": {
|
||||
"version": "1.0.10",
|
||||
@ -26530,8 +26529,7 @@
|
||||
"babel-plugin-named-asset-import": {
|
||||
"version": "0.3.7",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.7.tgz",
|
||||
"integrity": "sha512-squySRkf+6JGnvjoUtDEjSREJEBirnXi9NqP6rjSYsylxQxqBTz+pkmf395i9E2zsvmYUaI40BHo6SqZUdydlw==",
|
||||
"requires": {}
|
||||
"integrity": "sha512-squySRkf+6JGnvjoUtDEjSREJEBirnXi9NqP6rjSYsylxQxqBTz+pkmf395i9E2zsvmYUaI40BHo6SqZUdydlw=="
|
||||
},
|
||||
"babel-plugin-polyfill-corejs2": {
|
||||
"version": "0.2.0",
|
||||
@ -26915,6 +26913,15 @@
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
||||
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA=="
|
||||
},
|
||||
"bindings": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
|
||||
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"file-uri-to-path": "1.0.0"
|
||||
}
|
||||
},
|
||||
"bluebird": {
|
||||
"version": "3.7.2",
|
||||
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
|
||||
@ -27257,7 +27264,8 @@
|
||||
"camelcase-css": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
|
||||
"integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA=="
|
||||
"integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
|
||||
"dev": true
|
||||
},
|
||||
"camelcase-keys": {
|
||||
"version": "6.2.2",
|
||||
@ -28114,7 +28122,8 @@
|
||||
"css-unit-converter": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz",
|
||||
"integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA=="
|
||||
"integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA==",
|
||||
"dev": true
|
||||
},
|
||||
"css-what": {
|
||||
"version": "3.4.2",
|
||||
@ -28498,7 +28507,8 @@
|
||||
"defined": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",
|
||||
"integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM="
|
||||
"integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=",
|
||||
"dev": true
|
||||
},
|
||||
"del": {
|
||||
"version": "4.1.1",
|
||||
@ -28630,6 +28640,7 @@
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz",
|
||||
"integrity": "sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"acorn-node": "^1.6.1",
|
||||
"defined": "^1.0.0",
|
||||
@ -28639,7 +28650,8 @@
|
||||
"didyoumean": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
|
||||
"integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw=="
|
||||
"integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
|
||||
"dev": true
|
||||
},
|
||||
"diff-sequences": {
|
||||
"version": "26.6.2",
|
||||
@ -29213,8 +29225,7 @@
|
||||
"eslint-config-prettier": {
|
||||
"version": "8.3.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz",
|
||||
"integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==",
|
||||
"requires": {}
|
||||
"integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew=="
|
||||
},
|
||||
"eslint-config-react-app": {
|
||||
"version": "6.0.0",
|
||||
@ -29400,8 +29411,7 @@
|
||||
"eslint-plugin-react-hooks": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz",
|
||||
"integrity": "sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ==",
|
||||
"requires": {}
|
||||
"integrity": "sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ=="
|
||||
},
|
||||
"eslint-plugin-testing-library": {
|
||||
"version": "3.10.2",
|
||||
@ -30223,6 +30233,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"file-uri-to-path": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
|
||||
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
|
||||
"optional": true
|
||||
},
|
||||
"filelist": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.2.tgz",
|
||||
@ -31159,7 +31175,8 @@
|
||||
"html-tags": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.1.0.tgz",
|
||||
"integrity": "sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg=="
|
||||
"integrity": "sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg==",
|
||||
"dev": true
|
||||
},
|
||||
"html-webpack-plugin": {
|
||||
"version": "4.5.0",
|
||||
@ -32435,8 +32452,7 @@
|
||||
"jest-pnp-resolver": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz",
|
||||
"integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==",
|
||||
"requires": {}
|
||||
"integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w=="
|
||||
},
|
||||
"jest-regex-util": {
|
||||
"version": "26.0.0",
|
||||
@ -33018,7 +33034,8 @@
|
||||
"lilconfig": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.4.tgz",
|
||||
"integrity": "sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA=="
|
||||
"integrity": "sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA==",
|
||||
"dev": true
|
||||
},
|
||||
"lines-and-columns": {
|
||||
"version": "1.1.6",
|
||||
@ -33150,7 +33167,8 @@
|
||||
"lodash.topath": {
|
||||
"version": "4.5.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.topath/-/lodash.topath-4.5.2.tgz",
|
||||
"integrity": "sha1-NhY1Hzu6YZlKCTGYlmC9AyVP0Ak="
|
||||
"integrity": "sha1-NhY1Hzu6YZlKCTGYlmC9AyVP0Ak=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.truncate": {
|
||||
"version": "4.4.2",
|
||||
@ -33616,7 +33634,8 @@
|
||||
"modern-normalize": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/modern-normalize/-/modern-normalize-1.1.0.tgz",
|
||||
"integrity": "sha512-2lMlY1Yc1+CUy0gw4H95uNN7vjbpoED7NNRSBHE25nWfLBdmMzFCsPshlzbxHz+gYMcBEUN8V4pU16prcdPSgA=="
|
||||
"integrity": "sha512-2lMlY1Yc1+CUy0gw4H95uNN7vjbpoED7NNRSBHE25nWfLBdmMzFCsPshlzbxHz+gYMcBEUN8V4pU16prcdPSgA==",
|
||||
"dev": true
|
||||
},
|
||||
"move-concurrently": {
|
||||
"version": "1.0.1",
|
||||
@ -33740,6 +33759,7 @@
|
||||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz",
|
||||
"integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lodash": "^4.17.21"
|
||||
}
|
||||
@ -34009,7 +34029,8 @@
|
||||
"object-hash": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz",
|
||||
"integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw=="
|
||||
"integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==",
|
||||
"dev": true
|
||||
},
|
||||
"object-inspect": {
|
||||
"version": "1.9.0",
|
||||
@ -34413,7 +34434,8 @@
|
||||
"picocolors": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
|
||||
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
|
||||
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
|
||||
"dev": true
|
||||
},
|
||||
"picomatch": {
|
||||
"version": "2.2.2",
|
||||
@ -34913,6 +34935,7 @@
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-functions/-/postcss-functions-3.0.0.tgz",
|
||||
"integrity": "sha1-DpTQFERwCkgd4g3k1V+yZAVkJQ4=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"glob": "^7.1.2",
|
||||
"object-assign": "^4.1.1",
|
||||
@ -34924,6 +34947,7 @@
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-convert": "^1.9.0"
|
||||
}
|
||||
@ -34932,6 +34956,7 @@
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
@ -34942,6 +34967,7 @@
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
@ -34949,22 +34975,26 @@
|
||||
"color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
|
||||
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
|
||||
"dev": true
|
||||
},
|
||||
"escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
|
||||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
|
||||
"dev": true
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
|
||||
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
|
||||
"dev": true
|
||||
},
|
||||
"postcss": {
|
||||
"version": "6.0.23",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
|
||||
"integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chalk": "^2.4.1",
|
||||
"source-map": "^0.6.1",
|
||||
@ -34974,12 +35004,14 @@
|
||||
"postcss-value-parser": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
|
||||
"integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ=="
|
||||
"integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
|
||||
"dev": true
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
@ -35016,6 +35048,7 @@
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-2.0.3.tgz",
|
||||
"integrity": "sha512-zS59pAk3deu6dVHyrGqmC3oDXBdNdajk4k1RyxeVXCrcEDBUBHoIhE4QTsmhxgzXxsaqFDAkUZfmMa5f/N/79w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"camelcase-css": "^2.0.1",
|
||||
"postcss": "^7.0.18"
|
||||
@ -35294,6 +35327,7 @@
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-4.2.3.tgz",
|
||||
"integrity": "sha512-rOv0W1HquRCamWy2kFl3QazJMMe1ku6rCFoAAH+9AcxdbpDeBr6k968MLWuLjvjMcGEip01ak09hKOEgpK9hvw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"postcss": "^7.0.32",
|
||||
"postcss-selector-parser": "^6.0.2"
|
||||
@ -36485,7 +36519,8 @@
|
||||
"pretty-hrtime": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz",
|
||||
"integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE="
|
||||
"integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=",
|
||||
"dev": true
|
||||
},
|
||||
"process": {
|
||||
"version": "0.11.10",
|
||||
@ -36619,6 +36654,7 @@
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/purgecss/-/purgecss-4.1.3.tgz",
|
||||
"integrity": "sha512-99cKy4s+VZoXnPxaoM23e5ABcP851nC2y2GROkkjS8eJaJtlciGavd7iYAw2V84WeBqggZ12l8ef44G99HmTaw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"commander": "^8.0.0",
|
||||
"glob": "^7.1.7",
|
||||
@ -36629,12 +36665,14 @@
|
||||
"commander": {
|
||||
"version": "8.3.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
|
||||
"integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww=="
|
||||
"integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==",
|
||||
"dev": true
|
||||
},
|
||||
"glob": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
|
||||
"integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
@ -36647,12 +36685,14 @@
|
||||
"nanoid": {
|
||||
"version": "3.1.30",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz",
|
||||
"integrity": "sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ=="
|
||||
"integrity": "sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==",
|
||||
"dev": true
|
||||
},
|
||||
"postcss": {
|
||||
"version": "8.4.5",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz",
|
||||
"integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"nanoid": "^3.1.30",
|
||||
"picocolors": "^1.0.0",
|
||||
@ -36663,6 +36703,7 @@
|
||||
"version": "6.0.7",
|
||||
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.7.tgz",
|
||||
"integrity": "sha512-U+b/Deoi4I/UmE6KOVPpnhS7I7AYdKbhGcat+qTQ27gycvaACvNEw11ba6RrkwVmDVRW7sigWgLj4/KbbJjeDA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cssesc": "^3.0.0",
|
||||
"util-deprecate": "^1.0.2"
|
||||
@ -36712,7 +36753,8 @@
|
||||
"quick-lru": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
|
||||
"integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA=="
|
||||
"integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
|
||||
"dev": true
|
||||
},
|
||||
"raf": {
|
||||
"version": "3.4.1",
|
||||
@ -36800,8 +36842,7 @@
|
||||
"react-chartjs-2": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-3.3.0.tgz",
|
||||
"integrity": "sha512-4Mt0SR2aiUbWi/4762odRBYSnbNKSs4HWc0o3IW43py5bMfmfpeZU95w6mbvtuLZH/M3GsPJMU8DvDc+5U9blQ==",
|
||||
"requires": {}
|
||||
"integrity": "sha512-4Mt0SR2aiUbWi/4762odRBYSnbNKSs4HWc0o3IW43py5bMfmfpeZU95w6mbvtuLZH/M3GsPJMU8DvDc+5U9blQ=="
|
||||
},
|
||||
"react-cropper": {
|
||||
"version": "2.1.8",
|
||||
@ -37073,8 +37114,7 @@
|
||||
"react-webcam": {
|
||||
"version": "5.2.3",
|
||||
"resolved": "https://registry.npmjs.org/react-webcam/-/react-webcam-5.2.3.tgz",
|
||||
"integrity": "sha512-7rBh4Veeumpy45ObkZCsG6zezaamkwK5Iqxc0AFhX2ZzWQZXZ+f61yJ1yIb9Y62U4d7KkfP/xEduBCRzzcN4Dw==",
|
||||
"requires": {}
|
||||
"integrity": "sha512-7rBh4Veeumpy45ObkZCsG6zezaamkwK5Iqxc0AFhX2ZzWQZXZ+f61yJ1yIb9Y62U4d7KkfP/xEduBCRzzcN4Dw=="
|
||||
},
|
||||
"read-pkg": {
|
||||
"version": "2.0.0",
|
||||
@ -37202,6 +37242,7 @@
|
||||
"version": "2.1.8",
|
||||
"resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-2.1.8.tgz",
|
||||
"integrity": "sha512-8liAVezDmUcH+tdzoEGrhfbGcP7nOV4NkGE3a74+qqvE7nt9i4sKLGBuZNOnpI4WiGksiNPklZxva80061QiPg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"css-unit-converter": "^1.1.1",
|
||||
"postcss-value-parser": "^3.3.0"
|
||||
@ -37210,7 +37251,8 @@
|
||||
"postcss-value-parser": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
|
||||
"integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ=="
|
||||
"integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -38691,7 +38733,8 @@
|
||||
"source-map-js": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.1.tgz",
|
||||
"integrity": "sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA=="
|
||||
"integrity": "sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA==",
|
||||
"dev": true
|
||||
},
|
||||
"source-map-resolve": {
|
||||
"version": "0.6.0",
|
||||
@ -38997,21 +39040,6 @@
|
||||
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
|
||||
"integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM="
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
|
||||
"requires": {
|
||||
"safe-buffer": "~5.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"string-length": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz",
|
||||
@ -39075,6 +39103,21 @@
|
||||
"define-properties": "^1.1.3"
|
||||
}
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
|
||||
"requires": {
|
||||
"safe-buffer": "~5.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"stringify-object": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz",
|
||||
@ -39294,6 +39337,7 @@
|
||||
"version": "npm:@tailwindcss/postcss7-compat@2.2.17",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/postcss7-compat/-/postcss7-compat-2.2.17.tgz",
|
||||
"integrity": "sha512-3h2svqQAqYHxRZ1KjsJjZOVTQ04m29LjfrLjXyZZEJuvUuJN+BCIF9GI8vhE1s0plS0mogd6E6YLg6mu4Wv/Vw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"arg": "^5.0.1",
|
||||
"autoprefixer": "^9",
|
||||
@ -39336,6 +39380,7 @@
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
"supports-color": "^7.1.0"
|
||||
@ -39345,6 +39390,7 @@
|
||||
"version": "3.5.2",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz",
|
||||
"integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"anymatch": "~3.1.2",
|
||||
"braces": "~3.0.2",
|
||||
@ -39360,6 +39406,7 @@
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-glob": "^4.0.1"
|
||||
}
|
||||
@ -39370,6 +39417,7 @@
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/color/-/color-4.1.0.tgz",
|
||||
"integrity": "sha512-o2rkkxyLGgYoeUy1OodXpbPAQNmlNBrirQ8ODO8QutzDiDMNdezSOZLNnusQ6pUpCQJUsaJIo9DZJKqa2HgH7A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-convert": "^2.0.1",
|
||||
"color-string": "^1.9.0"
|
||||
@ -39379,6 +39427,7 @@
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.0.tgz",
|
||||
"integrity": "sha512-9Mrz2AQLefkH1UvASKj6v6hj/7eWgjnT/cVsR8CumieLoT+g900exWeNogqtweI8dxloXN9BDQTYro1oWu/5CQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-name": "^1.0.0",
|
||||
"simple-swizzle": "^0.2.2"
|
||||
@ -39388,6 +39437,7 @@
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz",
|
||||
"integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/parse-json": "^4.0.0",
|
||||
"import-fresh": "^3.2.1",
|
||||
@ -39400,6 +39450,7 @@
|
||||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz",
|
||||
"integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@nodelib/fs.stat": "^2.0.2",
|
||||
"@nodelib/fs.walk": "^1.2.3",
|
||||
@ -39412,6 +39463,7 @@
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-glob": "^4.0.1"
|
||||
}
|
||||
@ -39422,6 +39474,7 @@
|
||||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz",
|
||||
"integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^6.0.1",
|
||||
@ -39432,6 +39485,7 @@
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
|
||||
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-glob": "^4.0.3"
|
||||
},
|
||||
@ -39440,6 +39494,7 @@
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
|
||||
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-extglob": "^2.1.1"
|
||||
}
|
||||
@ -39450,6 +39505,7 @@
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-3.0.0.tgz",
|
||||
"integrity": "sha512-4pnzH16plW+hgvRECbDWpQl3cqtvSofHWh44met7ESfZ8UZOWWddm8hEyDTqREJ9RbYHY8gi8DqmaelApoOGMg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"import-from": "^3.0.0"
|
||||
}
|
||||
@ -39458,6 +39514,7 @@
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/import-from/-/import-from-3.0.0.tgz",
|
||||
"integrity": "sha512-CiuXOFFSzkU5x/CR0+z7T91Iht4CXgfCxVOFRhh2Zyhg5wOpWvvDLQUsWl+gcN+QscYBjez8hDCt85O7RLDttQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"resolve-from": "^5.0.0"
|
||||
}
|
||||
@ -39466,6 +39523,7 @@
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz",
|
||||
"integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"braces": "^3.0.1",
|
||||
"picomatch": "^2.2.3"
|
||||
@ -39474,7 +39532,8 @@
|
||||
"picomatch": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
|
||||
"integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw=="
|
||||
"integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -39482,6 +39541,7 @@
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.0.tgz",
|
||||
"integrity": "sha512-ipM8Ds01ZUophjDTQYSVP70slFSYg3T0/zyfII5vzhN6V57YSxMgG5syXuwi5VtS8wSf3iL30v0uBdoIVx4Q0g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"import-cwd": "^3.0.0",
|
||||
"lilconfig": "^2.0.3",
|
||||
@ -39492,6 +39552,7 @@
|
||||
"version": "6.0.7",
|
||||
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.7.tgz",
|
||||
"integrity": "sha512-U+b/Deoi4I/UmE6KOVPpnhS7I7AYdKbhGcat+qTQ27gycvaACvNEw11ba6RrkwVmDVRW7sigWgLj4/KbbJjeDA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cssesc": "^3.0.0",
|
||||
"util-deprecate": "^1.0.2"
|
||||
@ -39501,6 +39562,7 @@
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"picomatch": "^2.2.1"
|
||||
}
|
||||
@ -39509,6 +39571,7 @@
|
||||
"version": "1.20.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
|
||||
"integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-core-module": "^2.2.0",
|
||||
"path-parse": "^1.0.6"
|
||||
@ -39777,6 +39840,7 @@
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
|
||||
"integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"rimraf": "^3.0.0"
|
||||
}
|
||||
@ -41311,14 +41375,6 @@
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"requires": {
|
||||
"safe-buffer": "~5.1.0"
|
||||
}
|
||||
},
|
||||
"string-width": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
|
||||
@ -41344,6 +41400,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"requires": {
|
||||
"safe-buffer": "~5.1.0"
|
||||
}
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
||||
@ -41869,8 +41933,7 @@
|
||||
"ws": {
|
||||
"version": "7.4.4",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.4.tgz",
|
||||
"integrity": "sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw==",
|
||||
"requires": {}
|
||||
"integrity": "sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw=="
|
||||
},
|
||||
"xml-name-validator": {
|
||||
"version": "3.0.0",
|
||||
|
@ -1,6 +1,7 @@
|
||||
from gradio.interface import * # This makes it possible to import `Interface` as `gradio.Interface`.
|
||||
from gradio.networking import get_state, set_state
|
||||
from gradio.mix import *
|
||||
from gradio.flagging import *
|
||||
import pkg_resources
|
||||
|
||||
current_pkg_version = pkg_resources.require("gradio")[0].version
|
||||
|
248
gradio/flagging.py
Normal file
@ -0,0 +1,248 @@
|
||||
import gradio as gr
|
||||
import os
|
||||
import datetime
|
||||
from gradio import encryptor
|
||||
import csv
|
||||
import io
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
|
||||
class FlaggingCallback(ABC):
|
||||
"""
|
||||
An abstract class for defining the methods that any FlaggingCallback should have.
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def setup(self, flagging_dir):
|
||||
"""
|
||||
This method should be overridden and ensure that everything is set up correctly for flag().
|
||||
This method gets called once at the beginning of the Interface.launch() method.
|
||||
Parameters:
|
||||
flagging_dir: A string, typically containing the path to the directory where the flagging file should be storied (provided as an argument to Interface.__init__()).
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def flag(self, interface, input_data, output_data, flag_option=None, flag_index=None, username=None):
|
||||
"""
|
||||
This method should be overridden by the FlaggingCallback subclass and may contain optional additional arguments.
|
||||
This gets called every time the <flag> button is pressed.
|
||||
Parameters:
|
||||
interface: The Interface object that is being used to launch the flagging interface.
|
||||
input_data: The input data to be flagged.
|
||||
output_data: The output data to be flagged.
|
||||
flag_option (optional): In the case that flagging_options are provided, the flag option that is being used.
|
||||
flag_index (optional): The index of the sample that is being flagged.
|
||||
username (optional): The username of the user that is flagging the data, if logged in.
|
||||
Returns:
|
||||
(int) The total number of samples that have been flagged.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class SimpleCSVLogger(FlaggingCallback):
|
||||
"""
|
||||
A simple example implementation of the FlaggingCallback abstract class
|
||||
provided for illustrative purposes.
|
||||
"""
|
||||
def setup(self, flagging_dir):
|
||||
self.flagging_dir = flagging_dir
|
||||
os.makedirs(flagging_dir, exist_ok=True)
|
||||
|
||||
def flag(self, interface, input_data, output_data, flag_option=None, flag_index=None, username=None):
|
||||
flagging_dir = self.flagging_dir
|
||||
log_filepath = "{}/log.csv".format(flagging_dir)
|
||||
|
||||
csv_data = []
|
||||
for i, input in enumerate(interface.input_components):
|
||||
csv_data.append(input.save_flagged(
|
||||
flagging_dir, interface.config["input_components"][i]["label"], input_data[i], None))
|
||||
for i, output in enumerate(interface.output_components):
|
||||
csv_data.append(output.save_flagged(
|
||||
flagging_dir, interface.config["output_components"][i]["label"], output_data[i], None) if
|
||||
output_data[i] is not None else "")
|
||||
|
||||
with open(log_filepath, "a", newline="") as csvfile:
|
||||
writer = csv.writer(csvfile)
|
||||
writer.writerow(csv_data)
|
||||
|
||||
with open(log_filepath, "r") as csvfile:
|
||||
line_count = len([None for row in csv.reader(csvfile)]) - 1
|
||||
return line_count
|
||||
|
||||
|
||||
class CSVLogger(FlaggingCallback):
|
||||
"""
|
||||
The default implementation of the FlaggingCallback abstract class.
|
||||
Logs the input and output data to a CSV file.
|
||||
"""
|
||||
def setup(self, flagging_dir):
|
||||
self.flagging_dir = flagging_dir
|
||||
os.makedirs(flagging_dir, exist_ok=True)
|
||||
|
||||
def flag(self, interface, input_data, output_data, flag_option=None, flag_index=None, username=None):
|
||||
flagging_dir = self.flagging_dir
|
||||
log_fp = "{}/log.csv".format(flagging_dir)
|
||||
encryption_key = interface.encryption_key if interface.encrypt else None
|
||||
is_new = not os.path.exists(log_fp)
|
||||
|
||||
if flag_index is None:
|
||||
csv_data = []
|
||||
for i, input in enumerate(interface.input_components):
|
||||
csv_data.append(input.save_flagged(
|
||||
flagging_dir, interface.config["input_components"][i]["label"], input_data[i], encryption_key))
|
||||
for i, output in enumerate(interface.output_components):
|
||||
csv_data.append(output.save_flagged(
|
||||
flagging_dir, interface.config["output_components"][i]["label"], output_data[i], encryption_key) if
|
||||
output_data[i] is not None else "")
|
||||
if flag_option is not None:
|
||||
csv_data.append(flag_option)
|
||||
if username is not None:
|
||||
csv_data.append(username)
|
||||
csv_data.append(str(datetime.datetime.now()))
|
||||
if is_new:
|
||||
headers = [interface["label"]
|
||||
for interface in interface.config["input_components"]]
|
||||
headers += [interface["label"]
|
||||
for interface in interface.config["output_components"]]
|
||||
if interface.flagging_options is not None:
|
||||
headers.append("flag")
|
||||
if username is not None:
|
||||
headers.append("username")
|
||||
headers.append("timestamp")
|
||||
|
||||
def replace_flag_at_index(file_content):
|
||||
file_content = io.StringIO(file_content)
|
||||
content = list(csv.reader(file_content))
|
||||
header = content[0]
|
||||
flag_col_index = header.index("flag")
|
||||
content[flag_index][flag_col_index] = flag_option
|
||||
output = io.StringIO()
|
||||
writer = csv.writer(output)
|
||||
writer.writerows(content)
|
||||
return output.getvalue()
|
||||
|
||||
if interface.encrypt:
|
||||
output = io.StringIO()
|
||||
if not is_new:
|
||||
with open(log_fp, "rb") as csvfile:
|
||||
encrypted_csv = csvfile.read()
|
||||
decrypted_csv = encryptor.decrypt(
|
||||
interface.encryption_key, encrypted_csv)
|
||||
file_content = decrypted_csv.decode()
|
||||
if flag_index is not None:
|
||||
file_content = replace_flag_at_index(file_content)
|
||||
output.write(file_content)
|
||||
writer = csv.writer(output)
|
||||
if flag_index is None:
|
||||
if is_new:
|
||||
writer.writerow(headers)
|
||||
writer.writerow(csv_data)
|
||||
with open(log_fp, "wb") as csvfile:
|
||||
csvfile.write(encryptor.encrypt(
|
||||
interface.encryption_key, output.getvalue().encode()))
|
||||
else:
|
||||
if flag_index is None:
|
||||
with open(log_fp, "a", newline="") as csvfile:
|
||||
writer = csv.writer(csvfile)
|
||||
if is_new:
|
||||
writer.writerow(headers)
|
||||
writer.writerow(csv_data)
|
||||
else:
|
||||
with open(log_fp) as csvfile:
|
||||
file_content = csvfile.read()
|
||||
file_content = replace_flag_at_index(file_content)
|
||||
with open(log_fp, "w", newline="") as csvfile: # newline parameter needed for Windows
|
||||
csvfile.write(file_content)
|
||||
with open(log_fp, "r") as csvfile:
|
||||
line_count = len([None for row in csv.reader(csvfile)]) - 1
|
||||
return line_count
|
||||
|
||||
|
||||
class HuggingFaceDatasetSaver(FlaggingCallback):
|
||||
"""
|
||||
A FlaggingCallback that saves flagged data to a HuggingFace dataset.
|
||||
"""
|
||||
def __init__(self, hf_foken, dataset_name, organization=None,
|
||||
private=False, verbose=True):
|
||||
"""
|
||||
Params:
|
||||
hf_token (str): The token to use to access the huggingface API.
|
||||
dataset_name (str): The name of the dataset to save the data to, e.g.
|
||||
"image-classifier-1"
|
||||
organization (str): The name of the organization to which to attach
|
||||
the datasets. If None, the dataset attaches to the user only.
|
||||
private (bool): If the dataset does not already exist, whether it
|
||||
should be created as a private dataset or public. Private datasets
|
||||
may require paid huggingface.co accounts
|
||||
verbose (bool): Whether to print out the status of the dataset
|
||||
creation.
|
||||
"""
|
||||
self.hf_foken = hf_foken
|
||||
self.dataset_name = dataset_name
|
||||
self.organization_name = organization
|
||||
self.dataset_private = private
|
||||
self.verbose = verbose
|
||||
|
||||
def setup(self, flagging_dir):
|
||||
"""
|
||||
Params:
|
||||
flagging_dir (str): local directory where the dataset is cloned,
|
||||
updated, and pushed from.
|
||||
"""
|
||||
try:
|
||||
import huggingface_hub
|
||||
except (ImportError, ModuleNotFoundError):
|
||||
raise ImportError("Package `huggingface_hub` not found is needed "
|
||||
"for HuggingFaceDatasetSaver. Try 'pip install huggingface_hub'.")
|
||||
path_to_dataset_repo = huggingface_hub.create_repo(
|
||||
name=self.dataset_name, token=self.hf_foken,
|
||||
private=self.dataset_private, repo_type="dataset", exist_ok=True)
|
||||
self.flagging_dir = flagging_dir
|
||||
self.dataset_dir = os.path.join(flagging_dir, self.dataset_name)
|
||||
self.repo = huggingface_hub.Repository(
|
||||
local_dir=self.dataset_dir, clone_from=path_to_dataset_repo,
|
||||
use_auth_token=self.hf_foken)
|
||||
self.repo.git_pull()
|
||||
|
||||
#Should filename be user-specified?
|
||||
self.log_file = os.path.join(self.dataset_dir, "data.csv")
|
||||
|
||||
def flag(self, interface, input_data, output_data, flag_option=None,
|
||||
flag_index=None, username=None, path=None):
|
||||
# Note flag_index, username, path are not currently used
|
||||
is_new = not os.path.exists(self.log_file)
|
||||
with open(self.log_file, "a", newline="") as csvfile:
|
||||
writer = csv.writer(csvfile)
|
||||
|
||||
# Generate the headers
|
||||
if is_new:
|
||||
headers = [interface["label"] for interface in interface.config["input_components"]]
|
||||
headers += [interface["label"] for interface in interface.config["output_components"]]
|
||||
if interface.flagging_options is not None:
|
||||
headers.append("flag")
|
||||
writer.writerow(headers)
|
||||
|
||||
# Generate the row corresponding to the flagged sample
|
||||
csv_data = []
|
||||
for i, input in enumerate(interface.input_components):
|
||||
csv_data.append(input.save_flagged(self.dataset_dir, interface.config["input_components"][i]["label"], input_data[i], None))
|
||||
for i, output in enumerate(interface.output_components):
|
||||
csv_data.append(output.save_flagged(self.dataset_dir, interface.config["output_components"][i]["label"], output_data[i], None) if
|
||||
output_data[i] is not None else "")
|
||||
if flag_option is not None:
|
||||
csv_data.append(flag_option)
|
||||
|
||||
# Write the rows
|
||||
writer.writerow(csv_data)
|
||||
|
||||
# return number of samples in dataset
|
||||
with open(self.log_file, "r") as csvfile:
|
||||
line_count = len([None for row in csv.reader(csvfile)]) - 1
|
||||
|
||||
# push the repo
|
||||
self.repo.push_to_hub(
|
||||
commit_message="Flagged sample #{}".format(line_count))
|
||||
|
||||
return line_count
|
||||
|
@ -11,26 +11,30 @@ import markdown2
|
||||
import numpy as np
|
||||
import os
|
||||
import pkg_resources
|
||||
import requests
|
||||
import random
|
||||
import sys
|
||||
import time
|
||||
import warnings
|
||||
import webbrowser
|
||||
import weakref
|
||||
|
||||
from gradio import networking, strings, utils, encryptor, queue
|
||||
from gradio.inputs import get_input_instance
|
||||
from gradio.outputs import get_output_instance
|
||||
from gradio.interpretation import quantify_difference_in_label, get_regression_or_classification_value
|
||||
from gradio.external import load_interface, load_from_pipeline
|
||||
from gradio.flagging import FlaggingCallback, CSVLogger
|
||||
from gradio.inputs import get_input_instance
|
||||
from gradio.interpretation import quantify_difference_in_label, get_regression_or_classification_value
|
||||
from gradio.outputs import get_output_instance
|
||||
|
||||
|
||||
class Interface:
|
||||
"""
|
||||
Interfaces are created with Gradio by constructing a `gradio.Interface()` object or by calling `gradio.Interface.load()`.
|
||||
Gradio interfaces are created by constructing a `Interface` object
|
||||
with a locally-defined function, or with `Interface.load()` with the path
|
||||
to a repo or by `Interface.from_pipeline()` with a Transformers Pipeline.
|
||||
"""
|
||||
|
||||
instances = weakref.WeakSet() # stores references to all currently existing Interface instances
|
||||
# stores references to all currently existing Interface instances
|
||||
instances = weakref.WeakSet()
|
||||
|
||||
@classmethod
|
||||
def get_instances(cls):
|
||||
@ -76,8 +80,9 @@ class Interface:
|
||||
examples_per_page=10, live=False, layout="unaligned", show_input=True, show_output=True,
|
||||
capture_session=None, interpretation=None, num_shap=2.0, theme=None, repeat_outputs_per_model=True,
|
||||
title=None, description=None, article=None, thumbnail=None,
|
||||
css=None, height=500, width=900, allow_screenshot=True, allow_flagging=None, flagging_options=None,
|
||||
encrypt=False, show_tips=None, flagging_dir="flagged", analytics_enabled=None, enable_queue=None, api_mode=None):
|
||||
css=None, height=None, width=None, allow_screenshot=True, allow_flagging=None, flagging_options=None,
|
||||
encrypt=None, show_tips=None, flagging_dir="flagged", analytics_enabled=None, enable_queue=None, api_mode=None,
|
||||
flagging_callback=CSVLogger()):
|
||||
"""
|
||||
Parameters:
|
||||
fn (Callable): the function to wrap an interface around.
|
||||
@ -100,7 +105,7 @@ class Interface:
|
||||
allow_screenshot (bool): if False, users will not see a button to take a screenshot of the interface.
|
||||
allow_flagging (bool): if False, users will not see a button to flag an input and output.
|
||||
flagging_options (List[str]): if not None, provides options a user must select when flagging.
|
||||
encrypt (bool): If True, flagged data will be encrypted by key provided by creator at launch
|
||||
encrypt (bool): DEPRECATED. If True, flagged data will be encrypted by key provided by creator at launch
|
||||
flagging_dir (str): what to name the dir where flagged data is stored.
|
||||
show_tips (bool): DEPRECATED. if True, will occasionally show tips about new Gradio features
|
||||
enable_queue (bool): DEPRECATED. if True, inference requests will be served through a queue instead of with parallel threads. Required for longer inference times (> 1min) to prevent timeout.
|
||||
@ -142,7 +147,7 @@ class Interface:
|
||||
self.capture_session = capture_session
|
||||
|
||||
if capture_session is not None:
|
||||
warnings.warn("The `capture_session` parameter in the `Interface` will be deprecated in the near future.")
|
||||
warnings.warn("The `capture_session` parameter in the `Interface` is deprecated and has no effect.")
|
||||
|
||||
self.session = None
|
||||
self.title = title
|
||||
@ -177,12 +182,14 @@ class Interface:
|
||||
|
||||
self.simple_server = None
|
||||
self.allow_screenshot = allow_screenshot
|
||||
|
||||
# For allow_flagging and analytics_enabled: (1) first check for parameter, (2) check for environment variable, (3) default to True
|
||||
self.allow_flagging = allow_flagging if allow_flagging is not None else os.getenv("GRADIO_ALLOW_FLAGGING", "True") == "True"
|
||||
self.analytics_enabled = analytics_enabled if analytics_enabled is not None else os.getenv("GRADIO_ANALYTICS_ENABLED", "True") == "True"
|
||||
self.analytics_enabled = analytics_enabled if analytics_enabled is not None else os.getenv("GRADIO_ANALYTICS_ENABLED", "True")=="True"
|
||||
self.allow_flagging = allow_flagging if allow_flagging is not None else os.getenv("GRADIO_ALLOW_FLAGGING", "True")=="True"
|
||||
self.flagging_options = flagging_options
|
||||
self.flagging_callback: FlaggingCallback = flagging_callback
|
||||
self.flagging_dir = flagging_dir
|
||||
self.encrypt = encrypt
|
||||
|
||||
self.save_to = None
|
||||
self.share = None
|
||||
self.share_url = None
|
||||
@ -197,25 +204,30 @@ class Interface:
|
||||
|
||||
self.enable_queue = enable_queue
|
||||
if self.enable_queue is not None:
|
||||
warnings.warn("The `enable_queue` parameter in the `Interface` will be deprecated. Please use the `enable_queue` parameter in `launch()` instead")
|
||||
warnings.warn("The `enable_queue` parameter in the `Interface`"
|
||||
"will be deprecated and may not work properly. "
|
||||
"Please use the `enable_queue` parameter in "
|
||||
"`launch()` instead")
|
||||
|
||||
self.height = height
|
||||
self.width = width
|
||||
if self.height is not None or self.width is not None:
|
||||
warnings.warn(
|
||||
"The `width` and `height` parameters in the `Interface` class"
|
||||
"will be deprecated. Please provide these parameters"
|
||||
"in `launch()` instead")
|
||||
|
||||
self.encrypt = encrypt
|
||||
if self.encrypt is not None:
|
||||
warnings.warn(
|
||||
"The `encrypt` parameter in the `Interface` class"
|
||||
"will be deprecated. Please provide this parameter"
|
||||
"in `launch()` instead")
|
||||
|
||||
if api_mode is not None:
|
||||
warnings.warn("The `api_mode` parameter in the `Interface` is deprecated.")
|
||||
self.api_mode = False
|
||||
|
||||
if self.capture_session:
|
||||
try:
|
||||
import tensorflow as tf
|
||||
self.session = tf.get_default_graph(), \
|
||||
tf.keras.backend.get_session()
|
||||
except (ImportError, AttributeError):
|
||||
# If they are using TF >= 2.0 or don't have TF,
|
||||
# just ignore this.
|
||||
pass
|
||||
|
||||
if self.allow_flagging:
|
||||
os.makedirs(self.flagging_dir, exist_ok=True)
|
||||
|
||||
data = {'fn': fn,
|
||||
'inputs': inputs,
|
||||
'outputs': outputs,
|
||||
@ -351,18 +363,7 @@ class Interface:
|
||||
|
||||
for predict_fn in self.predict:
|
||||
start = time.time()
|
||||
if self.capture_session and self.session is not None:
|
||||
graph, sess = self.session
|
||||
with graph.as_default(), sess.as_default():
|
||||
prediction = predict_fn(*processed_input)
|
||||
else:
|
||||
try:
|
||||
prediction = predict_fn(*processed_input)
|
||||
except ValueError as exception:
|
||||
if str(exception).endswith("is not an element of this graph."):
|
||||
raise ValueError(strings.en["TF1_ERROR"])
|
||||
else:
|
||||
raise exception
|
||||
prediction = predict_fn(*processed_input)
|
||||
duration = time.time() - start
|
||||
|
||||
if len(self.output_components) == len(self.predict):
|
||||
@ -509,19 +510,7 @@ class Interface:
|
||||
processed_input = [input_component.preprocess(raw_input[i])
|
||||
for i, input_component in enumerate(self.input_components)]
|
||||
interpreter = self.interpretation
|
||||
|
||||
if self.capture_session and self.session is not None:
|
||||
graph, sess = self.session
|
||||
with graph.as_default(), sess.as_default():
|
||||
interpretation = interpreter(*processed_input)
|
||||
else:
|
||||
try:
|
||||
interpretation = interpreter(*processed_input)
|
||||
except ValueError as exception:
|
||||
if str(exception).endswith("is not an element of this graph."):
|
||||
raise ValueError(strings.en["TF1_ERROR"])
|
||||
else:
|
||||
raise exception
|
||||
interpretation = interpreter(*processed_input)
|
||||
if len(raw_input) == 1:
|
||||
interpretation = [interpretation]
|
||||
return interpretation, []
|
||||
@ -557,7 +546,8 @@ class Interface:
|
||||
def launch(self, inline=None, inbrowser=None, share=False, debug=False,
|
||||
auth=None, auth_message=None, private_endpoint=None,
|
||||
prevent_thread_lock=False, show_error=True, server_name=None,
|
||||
server_port=None, show_tips=False, enable_queue=False):
|
||||
server_port=None, show_tips=False, enable_queue=False,
|
||||
height=500, width=900, encrypt=False):
|
||||
"""
|
||||
Launches the webserver that serves the UI for the interface.
|
||||
Parameters:
|
||||
@ -578,6 +568,9 @@ class Interface:
|
||||
app (flask.Flask): Flask app object
|
||||
path_to_local_server (str): Locally accessible link
|
||||
share_url (str): Publicly accessible link (if share=True)
|
||||
width (bool): The width of the <iframe> element containing the interface (used if inline=True)
|
||||
height (bool): The height of the <iframe> element containing the interface (used if inline=True)
|
||||
encrypt (bool): If True, flagged data will be encrypted by key provided by creator at launch
|
||||
"""
|
||||
# Set up local flask server
|
||||
config = self.get_config_file()
|
||||
@ -588,6 +581,10 @@ class Interface:
|
||||
self.auth_message = auth_message
|
||||
self.show_tips = show_tips
|
||||
self.show_error = show_error
|
||||
self.height = self.height or height # if height is not set in constructor, use the one provided here
|
||||
self.width = self.width or width # if width is not set in constructor, use the one provided here
|
||||
if self.encrypt is None:
|
||||
self.encrypt = encrypt # if encrypt is not set in constructor, use the one provided here
|
||||
|
||||
# Request key for encryption
|
||||
if self.encrypt:
|
||||
@ -598,6 +595,10 @@ class Interface:
|
||||
if self.enable_queue is None:
|
||||
self.enable_queue = enable_queue
|
||||
|
||||
# Setup flagging
|
||||
if self.allow_flagging:
|
||||
self.flagging_callback.setup(self.flagging_dir)
|
||||
|
||||
# Launch local flask server
|
||||
server_port, path_to_local_server, app, thread, server = networking.start_server(
|
||||
self, server_name, server_port, self.auth)
|
||||
|
@ -25,8 +25,8 @@ import urllib.parse
|
||||
import urllib.request
|
||||
from werkzeug.security import safe_join
|
||||
from werkzeug.serving import make_server
|
||||
from gradio import encryptor
|
||||
from gradio import queue
|
||||
|
||||
from gradio import encryptor, queue
|
||||
from gradio.tunneling import create_tunnel
|
||||
|
||||
# By default, the http server will try to open on port 7860. If not available, 7861, 7862, etc.
|
||||
@ -209,9 +209,10 @@ def predict():
|
||||
output = {"data": prediction, "durations": durations, "avg_durations": avg_durations}
|
||||
if app.interface.allow_flagging == "auto":
|
||||
try:
|
||||
flag_index = flag_data(raw_input, prediction,
|
||||
flag_index = app.interface.flagging_handler.flag(raw_input, prediction,
|
||||
flag_option=(None if app.interface.flagging_options is None else ""),
|
||||
username=current_user.id if current_user.is_authenticated else None)
|
||||
username=current_user.id if current_user.is_authenticated else None,
|
||||
flag_path=os.path.join(app.cwd, app.interface.flagging_dir))
|
||||
output["flag_index"] = flag_index
|
||||
except Exception as e:
|
||||
print(str(e))
|
||||
@ -281,90 +282,12 @@ def log_feature_analytics(feature):
|
||||
pass # do not push analytics if no network
|
||||
|
||||
|
||||
def flag_data(input_data, output_data, flag_option=None, flag_index=None, username=None, flag_path=None):
|
||||
if flag_path is None:
|
||||
flag_path = os.path.join(app.cwd, app.interface.flagging_dir)
|
||||
log_fp = "{}/log.csv".format(flag_path)
|
||||
encryption_key = app.interface.encryption_key if app.interface.encrypt else None
|
||||
is_new = not os.path.exists(log_fp)
|
||||
|
||||
if flag_index is None:
|
||||
csv_data = []
|
||||
for i, interface in enumerate(app.interface.input_components):
|
||||
csv_data.append(interface.save_flagged(
|
||||
flag_path, app.interface.config["input_components"][i]["label"], input_data[i], encryption_key))
|
||||
for i, interface in enumerate(app.interface.output_components):
|
||||
csv_data.append(interface.save_flagged(
|
||||
flag_path, app.interface.config["output_components"][i]["label"], output_data[i], encryption_key) if output_data[i] is not None else "")
|
||||
if flag_option is not None:
|
||||
csv_data.append(flag_option)
|
||||
if username is not None:
|
||||
csv_data.append(username)
|
||||
csv_data.append(str(datetime.datetime.now()))
|
||||
if is_new:
|
||||
headers = [interface["label"]
|
||||
for interface in app.interface.config["input_components"]]
|
||||
headers += [interface["label"]
|
||||
for interface in app.interface.config["output_components"]]
|
||||
if app.interface.flagging_options is not None:
|
||||
headers.append("flag")
|
||||
if username is not None:
|
||||
headers.append("username")
|
||||
headers.append("timestamp")
|
||||
|
||||
def replace_flag_at_index(file_content):
|
||||
file_content = io.StringIO(file_content)
|
||||
content = list(csv.reader(file_content))
|
||||
header = content[0]
|
||||
flag_col_index = header.index("flag")
|
||||
content[flag_index][flag_col_index] = flag_option
|
||||
output = io.StringIO()
|
||||
writer = csv.writer(output)
|
||||
writer.writerows(content)
|
||||
return output.getvalue()
|
||||
|
||||
if app.interface.encrypt:
|
||||
output = io.StringIO()
|
||||
if not is_new:
|
||||
with open(log_fp, "rb") as csvfile:
|
||||
encrypted_csv = csvfile.read()
|
||||
decrypted_csv = encryptor.decrypt(
|
||||
app.interface.encryption_key, encrypted_csv)
|
||||
file_content = decrypted_csv.decode()
|
||||
if flag_index is not None:
|
||||
file_content = replace_flag_at_index(file_content)
|
||||
output.write(file_content)
|
||||
writer = csv.writer(output)
|
||||
if flag_index is None:
|
||||
if is_new:
|
||||
writer.writerow(headers)
|
||||
writer.writerow(csv_data)
|
||||
with open(log_fp, "wb") as csvfile:
|
||||
csvfile.write(encryptor.encrypt(
|
||||
app.interface.encryption_key, output.getvalue().encode()))
|
||||
else:
|
||||
if flag_index is None:
|
||||
with open(log_fp, "a", newline="") as csvfile:
|
||||
writer = csv.writer(csvfile)
|
||||
if is_new:
|
||||
writer.writerow(headers)
|
||||
writer.writerow(csv_data)
|
||||
else:
|
||||
with open(log_fp) as csvfile:
|
||||
file_content = csvfile.read()
|
||||
file_content = replace_flag_at_index(file_content)
|
||||
with open(log_fp, "w", newline="") as csvfile: # newline parameter needed for Windows
|
||||
csvfile.write(file_content)
|
||||
with open(log_fp, "r") as csvfile:
|
||||
line_count = len([None for row in csv.reader(csvfile)]) - 1
|
||||
return line_count
|
||||
|
||||
@app.route("/api/flag/", methods=["POST"])
|
||||
@login_check
|
||||
def flag():
|
||||
log_feature_analytics('flag')
|
||||
data = request.json['data']
|
||||
flag_data(data['input_data'], data['output_data'], data.get("flag_option"), data.get("flag_index"),
|
||||
app.interface.flagging_callback.flag(app.interface, data['input_data'], data['output_data'], data.get("flag_option"), data.get("flag_index"),
|
||||
current_user.id if current_user.is_authenticated else None)
|
||||
return jsonify(success=True)
|
||||
|
||||
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 295 KiB After Width: | Height: | Size: 364 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 40 KiB |
@ -9,7 +9,7 @@ import transformers
|
||||
WARNING: These tests have an external dependency: namely that Hugging Face's Hub and Space APIs do not change, and they keep their most famous models up. So if, e.g. Spaces is down, then these test will not pass.
|
||||
"""
|
||||
|
||||
os.environ["GRADIO_ANALYTICS_ENABLED"] = "" # Disables analytics
|
||||
os.environ["GRADIO_ANALYTICS_ENABLED"] = "False"
|
||||
|
||||
|
||||
class TestHuggingFaceModelAPI(unittest.TestCase):
|
||||
|
31
test/test_flagging.py
Normal file
@ -0,0 +1,31 @@
|
||||
import gradio as gr
|
||||
from gradio import flagging
|
||||
import tempfile
|
||||
import unittest
|
||||
import unittest.mock as mock
|
||||
|
||||
|
||||
class TestFlagging(unittest.TestCase):
|
||||
def test_default_flagging_handler(self):
|
||||
with tempfile.TemporaryDirectory() as tmpdirname:
|
||||
io = gr.Interface(lambda x: x, "text", "text", flagging_dir=tmpdirname)
|
||||
io.launch(prevent_thread_lock=True)
|
||||
row_count = io.flagging_callback.flag(io, ["test"], ["test"])
|
||||
self.assertEqual(row_count, 1) # 2 rows written including header
|
||||
row_count = io.flagging_callback.flag(io, ["test"], ["test"])
|
||||
self.assertEqual(row_count, 2) # 3 rows written including header
|
||||
io.close()
|
||||
|
||||
def test_simple_csv_flagging_handler(self):
|
||||
with tempfile.TemporaryDirectory() as tmpdirname:
|
||||
io = gr.Interface(lambda x: x, "text", "text", flagging_dir=tmpdirname, flagging_callback=flagging.SimpleCSVLogger())
|
||||
io.launch(prevent_thread_lock=True)
|
||||
row_count = io.flagging_callback.flag(io, ["test"], ["test"])
|
||||
self.assertEqual(row_count, 0) # no header
|
||||
row_count = io.flagging_callback.flag(io, ["test"], ["test"])
|
||||
self.assertEqual(row_count, 1) # no header
|
||||
io.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
@ -10,7 +10,7 @@ import tempfile
|
||||
import json
|
||||
|
||||
|
||||
os.environ["GRADIO_ANALYTICS_ENABLED"] = "" # Disables analytics
|
||||
os.environ["GRADIO_ANALYTICS_ENABLED"] = "False"
|
||||
|
||||
|
||||
class InputComponent(unittest.TestCase):
|
||||
|
@ -1,15 +1,14 @@
|
||||
from gradio import networking
|
||||
import gradio as gr
|
||||
from gradio import networking, Interface, reset_all, flagging
|
||||
import unittest
|
||||
import unittest.mock as mock
|
||||
import ipaddress
|
||||
import requests
|
||||
import warnings
|
||||
import tempfile
|
||||
from unittest.mock import ANY
|
||||
from unittest.mock import ANY, MagicMock
|
||||
import urllib.request
|
||||
import os
|
||||
|
||||
|
||||
os.environ["GRADIO_ANALYTICS_ENABLED"] = "False"
|
||||
|
||||
|
||||
@ -59,7 +58,7 @@ class TestPort(unittest.TestCase):
|
||||
|
||||
class TestFlaskRoutes(unittest.TestCase):
|
||||
def setUp(self) -> None:
|
||||
self.io = gr.Interface(lambda x: x, "text", "text")
|
||||
self.io = Interface(lambda x: x, "text", "text")
|
||||
self.app, _, _ = self.io.launch(prevent_thread_lock=True)
|
||||
self.client = self.app.test_client()
|
||||
|
||||
@ -106,12 +105,12 @@ class TestFlaskRoutes(unittest.TestCase):
|
||||
|
||||
def tearDown(self) -> None:
|
||||
self.io.close()
|
||||
gr.reset_all()
|
||||
reset_all()
|
||||
|
||||
|
||||
class TestAuthenticatedFlaskRoutes(unittest.TestCase):
|
||||
def setUp(self) -> None:
|
||||
self.io = gr.Interface(lambda x: x, "text", "text")
|
||||
self.io = Interface(lambda x: x, "text", "text")
|
||||
self.app, _, _ = self.io.launch(auth=("test", "correct_password"), prevent_thread_lock=True)
|
||||
self.client = self.app.test_client()
|
||||
|
||||
@ -127,11 +126,12 @@ class TestAuthenticatedFlaskRoutes(unittest.TestCase):
|
||||
|
||||
def tearDown(self) -> None:
|
||||
self.io.close()
|
||||
gr.reset_all()
|
||||
reset_all()
|
||||
|
||||
|
||||
class TestInterfaceCustomParameters(unittest.TestCase):
|
||||
def test_show_error(self):
|
||||
io = gr.Interface(lambda x: 1/x, "number", "number")
|
||||
io = Interface(lambda x: 1/x, "number", "number")
|
||||
app, _, _ = io.launch(show_error=True, prevent_thread_lock=True)
|
||||
client = app.test_client()
|
||||
response = client.post('/api/predict/', json={"data": [0]})
|
||||
@ -141,47 +141,39 @@ class TestInterfaceCustomParameters(unittest.TestCase):
|
||||
|
||||
def test_feature_logging(self):
|
||||
with mock.patch('requests.post') as mock_post:
|
||||
io = gr.Interface(lambda x: 1/x, "number", "number", analytics_enabled=True)
|
||||
io = Interface(lambda x: 1/x, "number", "number", analytics_enabled=True)
|
||||
io.launch(show_error=True, prevent_thread_lock=True)
|
||||
networking.log_feature_analytics("test_feature")
|
||||
mock_post.assert_called_with(networking.GRADIO_FEATURE_ANALYTICS_URL, data=ANY, timeout=ANY)
|
||||
io.close()
|
||||
|
||||
io = gr.Interface(lambda x: 1/x, "number", "number")
|
||||
print(io.analytics_enabled)
|
||||
io = Interface(lambda x: 1/x, "number", "number")
|
||||
io.launch(show_error=True, prevent_thread_lock=True)
|
||||
with mock.patch('requests.post') as mock_post:
|
||||
networking.log_feature_analytics("test_feature")
|
||||
mock_post.assert_not_called()
|
||||
io.close()
|
||||
|
||||
class TestFlagging(unittest.TestCase):
|
||||
def test_num_rows_written(self):
|
||||
io = gr.Interface(lambda x: x, "text", "text")
|
||||
io.launch(prevent_thread_lock=True)
|
||||
with tempfile.TemporaryDirectory() as tmpdirname:
|
||||
row_count = networking.flag_data(["test"], ["test"], flag_path=tmpdirname)
|
||||
self.assertEquals(row_count, 1) # 2 rows written including header
|
||||
row_count = networking.flag_data("test", "test", flag_path=tmpdirname)
|
||||
self.assertEquals(row_count, 2) # 3 rows written including header
|
||||
io.close()
|
||||
|
||||
class TestFlagging(unittest.TestCase):
|
||||
@mock.patch("requests.post")
|
||||
@mock.patch("gradio.networking.flag_data")
|
||||
def test_flagging_analytics(self, mock_flag, mock_post):
|
||||
io = gr.Interface(lambda x: x, "text", "text", analytics_enabled=True)
|
||||
def test_flagging_analytics(self, mock_post):
|
||||
callback = flagging.CSVLogger()
|
||||
callback.flag = mock.MagicMock()
|
||||
io = Interface(lambda x: x, "text", "text", analytics_enabled=True, flagging_callback=callback)
|
||||
app, _, _ = io.launch(show_error=True, prevent_thread_lock=True)
|
||||
client = app.test_client()
|
||||
response = client.post('/api/flag/', json={"data": {"input_data": ["test"], "output_data": ["test"]}})
|
||||
mock_post.assert_any_call(networking.GRADIO_FEATURE_ANALYTICS_URL, data=ANY, timeout=ANY)
|
||||
mock_flag.assert_called_once()
|
||||
callback.flag.assert_called_once()
|
||||
self.assertEqual(response.status_code, 200)
|
||||
io.close()
|
||||
|
||||
|
||||
@mock.patch("requests.post")
|
||||
class TestInterpretation(unittest.TestCase):
|
||||
def test_interpretation(self, mock_post):
|
||||
io = gr.Interface(lambda x: len(x), "text", "label", interpretation="default", analytics_enabled=True)
|
||||
io = Interface(lambda x: len(x), "text", "label", interpretation="default", analytics_enabled=True)
|
||||
app, _, _ = io.launch(prevent_thread_lock=True)
|
||||
client = app.test_client()
|
||||
io.interpret = mock.MagicMock(return_value=(None, None))
|
||||
@ -192,30 +184,30 @@ class TestInterpretation(unittest.TestCase):
|
||||
|
||||
class TestState(unittest.TestCase):
|
||||
def test_state_initialization(self):
|
||||
io = gr.Interface(lambda x: len(x), "text", "label")
|
||||
io = Interface(lambda x: len(x), "text", "label")
|
||||
app, _, _ = io.launch(prevent_thread_lock=True)
|
||||
with app.test_request_context():
|
||||
self.assertIsNone(networking.get_state())
|
||||
|
||||
def test_state_value(self):
|
||||
io = gr.Interface(lambda x: len(x), "text", "label")
|
||||
io = Interface(lambda x: len(x), "text", "label")
|
||||
app, _, _ = io.launch(prevent_thread_lock=True)
|
||||
with app.test_request_context():
|
||||
networking.set_state("test")
|
||||
client = app.test_client()
|
||||
client.post('/api/predict/', json={"data": [0]})
|
||||
self.assertEquals(networking.get_state(), "test")
|
||||
self.assertEqual(networking.get_state(), "test")
|
||||
|
||||
class TestURLs(unittest.TestCase):
|
||||
def test_url_ok(self):
|
||||
urllib.request.urlopen = mock.MagicMock(return_value="test")
|
||||
res = networking.url_request("http://www.gradio.app")
|
||||
self.assertEquals(res, "test")
|
||||
self.assertEqual(res, "test")
|
||||
|
||||
def test_setup_tunnel(self):
|
||||
networking.create_tunnel = mock.MagicMock(return_value="test")
|
||||
res = networking.setup_tunnel(None, None)
|
||||
self.assertEquals(res, "test")
|
||||
self.assertEqual(res, "test")
|
||||
|
||||
def test_url_ok(self):
|
||||
res = networking.url_ok("https://www.gradio.app")
|
||||
@ -224,7 +216,7 @@ class TestURLs(unittest.TestCase):
|
||||
|
||||
class TestQueuing(unittest.TestCase):
|
||||
def test_queueing(self):
|
||||
io = gr.Interface(lambda x: x, "text", "text")
|
||||
io = Interface(lambda x: x, "text", "text")
|
||||
app, _, _ = io.launch(prevent_thread_lock=True)
|
||||
client = app.test_client()
|
||||
# mock queue methods and post method
|
||||
|