fix screenshot, image editor;

This commit is contained in:
Ali Abid 2021-06-30 13:12:27 -07:00
parent 7deb0aa22f
commit dc211822ca
24 changed files with 388 additions and 59 deletions

View File

@ -13,9 +13,11 @@
"@testing-library/jest-dom": "^5.11.10",
"@testing-library/react": "^11.2.6",
"@testing-library/user-event": "^12.8.3",
"@toast-ui/react-image-editor": "^3.14.2",
"audio-react-recorder": "^1.0.4",
"classnames": "^2.3.1",
"fabric": "^4.5.0",
"html2canvas-objectfit-fix": "^1.2.0",
"jspreadsheet-ce": "^4.7.3",
"react": "^17.0.2",
"react-dom": "^17.0.2",
@ -2578,6 +2580,18 @@
"@testing-library/dom": ">=7.21.4"
}
},
"node_modules/@toast-ui/react-image-editor": {
"version": "3.14.2",
"resolved": "https://registry.npmjs.org/@toast-ui/react-image-editor/-/react-image-editor-3.14.2.tgz",
"integrity": "sha512-FWnEBTESI6yqM9eDqkGTNbnN6lM9/XxxrxMlg06sW9Dh5LvQsIYdz0G8J77brR0Qm+FXdwAK/n2jltitcTnB0Q==",
"dependencies": {
"fabric": "^4.2.0",
"tui-image-editor": "^3.14.2"
},
"peerDependencies": {
"react": "^16.0.0"
}
},
"node_modules/@types/anymatch": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/@types/anymatch/-/anymatch-1.3.1.tgz",
@ -4321,6 +4335,14 @@
"resolved": "https://registry.npmjs.org/base16/-/base16-1.0.0.tgz",
"integrity": "sha1-4pf2DX7BAUp6lxo568ipjAtoHnA="
},
"node_modules/base64-arraybuffer": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.2.0.tgz",
"integrity": "sha512-7emyCsu1/xiBXgQZrscw/8KPRT44I4Yq9Pe6EGs3aPRTsWuggML1/1DTuZUuIaJPIm1FTDUVXl4x/yW8s0kQDQ==",
"engines": {
"node": ">= 0.6.0"
}
},
"node_modules/base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
@ -5694,6 +5716,14 @@
"node": ">=4"
}
},
"node_modules/css-line-break": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-1.1.1.tgz",
"integrity": "sha512-1feNVaM4Fyzdj4mKPIQNL2n70MmuYzAXZ1aytlROFX1JsOo070OsugwGjj7nl6jnDJWHDM8zRZswkmeYVWZJQA==",
"dependencies": {
"base64-arraybuffer": "^0.2.0"
}
},
"node_modules/css-loader": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/css-loader/-/css-loader-4.3.0.tgz",
@ -9610,6 +9640,17 @@
"node": ">=4.0.0"
}
},
"node_modules/html2canvas-objectfit-fix": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/html2canvas-objectfit-fix/-/html2canvas-objectfit-fix-1.2.0.tgz",
"integrity": "sha512-eBQPJyJJPgAlgtMioB42Kv+wHXGgfjUyPdYWZKbF8jUlss4J6xdj5tJM8n2uZ/94NU2UEooN97ypGdzbFE562A==",
"dependencies": {
"css-line-break": "1.1.1"
},
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/htmlparser2": {
"version": "3.10.1",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
@ -18884,6 +18925,27 @@
"resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
"integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY="
},
"node_modules/tui-code-snippet": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/tui-code-snippet/-/tui-code-snippet-1.5.2.tgz",
"integrity": "sha512-6UqTlQaaC1KLcmC0HAoq5dtl1G4Fib+R+NC7pmaV7kiIlZ7JqKhUmnOoGRcreAyzd81UTK/vCvhrw9QJskpCFQ=="
},
"node_modules/tui-color-picker": {
"version": "2.2.7",
"resolved": "https://registry.npmjs.org/tui-color-picker/-/tui-color-picker-2.2.7.tgz",
"integrity": "sha512-y7gUe6PdVBq8ruZbiOkeaN7N/DX+ogVyLkK53OM4qW5Vrc4pDWYEKlnOBCsPODb4/RSzS9iTd6fXYirXxeakJA=="
},
"node_modules/tui-image-editor": {
"version": "3.14.3",
"resolved": "https://registry.npmjs.org/tui-image-editor/-/tui-image-editor-3.14.3.tgz",
"integrity": "sha512-zNbC+nKVYdLSvUuHK+ZWTJw6T5Jr02oPBKrdEjfGAP7gx2yfWzHbpmrsivLyiCJzKV580N4mt0mAXttB2EClYg==",
"dependencies": {
"core-js-pure": "^3.6.4",
"fabric": "^4.2.0",
"tui-code-snippet": "^1.5.0",
"tui-color-picker": "^2.2.6"
}
},
"node_modules/tunnel-agent": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
@ -23264,6 +23326,15 @@
"@babel/runtime": "^7.12.5"
}
},
"@toast-ui/react-image-editor": {
"version": "3.14.2",
"resolved": "https://registry.npmjs.org/@toast-ui/react-image-editor/-/react-image-editor-3.14.2.tgz",
"integrity": "sha512-FWnEBTESI6yqM9eDqkGTNbnN6lM9/XxxrxMlg06sW9Dh5LvQsIYdz0G8J77brR0Qm+FXdwAK/n2jltitcTnB0Q==",
"requires": {
"fabric": "^4.2.0",
"tui-image-editor": "^3.14.2"
}
},
"@types/anymatch": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/@types/anymatch/-/anymatch-1.3.1.tgz",
@ -24703,6 +24774,11 @@
"resolved": "https://registry.npmjs.org/base16/-/base16-1.0.0.tgz",
"integrity": "sha1-4pf2DX7BAUp6lxo568ipjAtoHnA="
},
"base64-arraybuffer": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.2.0.tgz",
"integrity": "sha512-7emyCsu1/xiBXgQZrscw/8KPRT44I4Yq9Pe6EGs3aPRTsWuggML1/1DTuZUuIaJPIm1FTDUVXl4x/yW8s0kQDQ=="
},
"base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
@ -25818,6 +25894,14 @@
}
}
},
"css-line-break": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-1.1.1.tgz",
"integrity": "sha512-1feNVaM4Fyzdj4mKPIQNL2n70MmuYzAXZ1aytlROFX1JsOo070OsugwGjj7nl6jnDJWHDM8zRZswkmeYVWZJQA==",
"requires": {
"base64-arraybuffer": "^0.2.0"
}
},
"css-loader": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/css-loader/-/css-loader-4.3.0.tgz",
@ -28904,6 +28988,14 @@
}
}
},
"html2canvas-objectfit-fix": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/html2canvas-objectfit-fix/-/html2canvas-objectfit-fix-1.2.0.tgz",
"integrity": "sha512-eBQPJyJJPgAlgtMioB42Kv+wHXGgfjUyPdYWZKbF8jUlss4J6xdj5tJM8n2uZ/94NU2UEooN97ypGdzbFE562A==",
"requires": {
"css-line-break": "1.1.1"
}
},
"htmlparser2": {
"version": "3.10.1",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
@ -36222,6 +36314,27 @@
"resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
"integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY="
},
"tui-code-snippet": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/tui-code-snippet/-/tui-code-snippet-1.5.2.tgz",
"integrity": "sha512-6UqTlQaaC1KLcmC0HAoq5dtl1G4Fib+R+NC7pmaV7kiIlZ7JqKhUmnOoGRcreAyzd81UTK/vCvhrw9QJskpCFQ=="
},
"tui-color-picker": {
"version": "2.2.7",
"resolved": "https://registry.npmjs.org/tui-color-picker/-/tui-color-picker-2.2.7.tgz",
"integrity": "sha512-y7gUe6PdVBq8ruZbiOkeaN7N/DX+ogVyLkK53OM4qW5Vrc4pDWYEKlnOBCsPODb4/RSzS9iTd6fXYirXxeakJA=="
},
"tui-image-editor": {
"version": "3.14.3",
"resolved": "https://registry.npmjs.org/tui-image-editor/-/tui-image-editor-3.14.3.tgz",
"integrity": "sha512-zNbC+nKVYdLSvUuHK+ZWTJw6T5Jr02oPBKrdEjfGAP7gx2yfWzHbpmrsivLyiCJzKV580N4mt0mAXttB2EClYg==",
"requires": {
"core-js-pure": "^3.6.4",
"fabric": "^4.2.0",
"tui-code-snippet": "^1.5.0",
"tui-color-picker": "^2.2.6"
}
},
"tunnel-agent": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",

View File

@ -8,9 +8,11 @@
"@testing-library/jest-dom": "^5.11.10",
"@testing-library/react": "^11.2.6",
"@testing-library/user-event": "^12.8.3",
"@toast-ui/react-image-editor": "^3.14.2",
"audio-react-recorder": "^1.0.4",
"classnames": "^2.3.1",
"fabric": "^4.5.0",
"html2canvas-objectfit-fix": "^1.2.0",
"jspreadsheet-ce": "^4.7.3",
"react": "^17.0.2",
"react-dom": "^17.0.2",

View File

@ -1,4 +1,7 @@
import React from 'react';
import html2canvas from 'html2canvas-objectfit-fix';
import { saveAs } from './utils';
import ReactDOM from "react-dom";
import classNames from "classnames";
import { AudioInput, AudioInputExample } from './interfaces/input/audio';
@ -67,6 +70,7 @@ export class GradioInterface extends React.Component {
this.flag = this.flag.bind(this);
this.interpret = this.interpret.bind(this);
this.removeInterpret = this.removeInterpret.bind(this);
this.takeScreenshot = this.takeScreenshot.bind(this);
this.handleExampleChange = this.handleExampleChange.bind(this);
this.state = this.get_default_state();
this.state["examples_page"] = 0;
@ -162,6 +166,11 @@ export class GradioInterface extends React.Component {
removeInterpret() {
this.setState({ "interpretation": null });
}
takeScreenshot() {
html2canvas(ReactDOM.findDOMNode(this)).then(canvas => {
saveAs(canvas.toDataURL(), 'screenshot.png');
});
}
handleChange(_id, value) {
let state_change = { [_id]: value, "has_changed": true };
if (this.props.live && !(this.state.submitting)) {
@ -238,7 +247,7 @@ export class GradioInterface extends React.Component {
: false
}
{this.props.allow_screenshot ?
<button className="panel_button hidden">Screenshot</button>
<button onClick={this.takeScreenshot} className="panel_button">Screenshot</button>
: false}
{this.props.allow_flagging ?
(this.props.flagging_options === null ?

View File

@ -1,7 +1,7 @@
import React from 'react';
import { DataURLComponentExample } from '../component_example';
import AudioReactRecorder, { RecordState } from 'audio-react-recorder'
import { getSaliencyColor } from '../utils';
import { getSaliencyColor } from '../../utils';
class AudioInput extends React.Component {
constructor(props) {

View File

@ -1,7 +1,7 @@
import React from 'react';
import ComponentExample from '../component_example';
import classNames from "classnames";
import { getSaliencyColor } from '../utils';
import { getSaliencyColor } from '../../utils';
class CheckboxInput extends React.Component {
constructor(props) {

View File

@ -1,7 +1,7 @@
import React from 'react';
import ComponentExample from '../component_example';
import classNames from "classnames";
import { getSaliencyColor } from '../utils';
import { getSaliencyColor } from '../../utils';
class CheckboxGroupInput extends React.Component {
constructor(props) {

View File

@ -1,7 +1,7 @@
import React from 'react';
import ComponentExample from '../component_example';
import classNames from "classnames";
import { getSaliencyColor } from '../utils';
import { getSaliencyColor } from '../../utils';
class DropdownInput extends React.Component {
constructor(props) {

View File

@ -1,6 +1,6 @@
import React from 'react';
import ComponentExample from '../component_example';
import {prettyBytes} from '../utils';
import {prettyBytes} from '../../utils';
class FileInput extends React.Component {
constructor(props) {

View File

@ -2,7 +2,9 @@ import React from 'react';
import { DataURLComponentExample } from '../component_example';
import Webcam from "react-webcam";
import { SketchField, Tools } from '../../vendor/ReactSketch';
import { getObjectFitSize, paintSaliency } from '../utils';
import { getObjectFitSize, paintSaliency } from '../../utils';
import 'tui-image-editor/dist/tui-image-editor.css';
import ImageEditor from '@toast-ui/react-image-editor';
class ImageInput extends React.Component {
constructor(props) {
@ -14,12 +16,17 @@ class ImageInput extends React.Component {
this.load_preview_from_files = this.load_preview_from_files.bind(this);
this.load_preview_from_upload = this.load_preview_from_upload.bind(this);
this.load_preview_from_drop = this.load_preview_from_drop.bind(this);
this.saveEditor = this.saveEditor.bind(this);
this.cancelEditor = this.cancelEditor.bind(this);
this.snapshot = this.snapshot.bind(this);
this.getSketch = this.getSketch.bind(this);
this.openEditor = this.openEditor.bind(this);
this.imgRef = React.createRef();
this.webcamRef = React.createRef();
this.sketchRef = React.createRef();
this.editorRef = React.createRef();
this.sketchKey = 0;
this.state = { editorMode: false };
}
handleChange(data) {
this.props.handleChange(data);
@ -35,10 +42,25 @@ class ImageInput extends React.Component {
let imageSrc = this.sketchRef.current.toDataURL();
this.handleChange(imageSrc);
}
onImgLoad({target:img}) {
this.setState({dimensions:{height:img.offsetHeight,
width:img.offsetWidth}});
}
cancelEditor() {
this.setState({"editorMode": false});
}
saveEditor() {
const editorInstance = this.editorRef.current.getInstance();
this.handleChange(editorInstance.toDataURL());
this.setState({"editorMode": false});
}
onImgLoad({ target: img }) {
this.setState({
dimensions: {
height: img.offsetHeight,
width: img.offsetWidth
}
});
}
openEditor() {
this.setState({ editorMode: true })
}
render() {
let no_action = (evt) => {
evt.preventDefault();
@ -65,6 +87,29 @@ class ImageInput extends React.Component {
return (
<div className="input_image">
<div className="image_preview_holder">
{this.state.editorMode ?
<div className="image_editor">
<div className="image_editor_buttons">
<button onClick={this.saveEditor}>Save</button>
<button onClick={this.cancelEditor}>Cancel</button>
</div>
<ImageEditor
ref={this.editorRef}
includeUI={{
loadImage: {path: this.props.value, name: "value"},
uiSize: {
width: '800px',
height: '600px',
},
menuBarPosition: 'left',
}}
cssMaxHeight={500}
cssMaxWidth={700}
usageStatistics={false}
/>
</div>
:
<button className="edit_button" onClick={this.openEditor}>Edit</button>}
<img ref={this.imgRef} onLoad={this.onImgLoad} className="image_preview" alt="" src={this.props.value} />
</div>
{interpretation}
@ -101,7 +146,7 @@ class ImageInput extends React.Component {
lineWidth={20}
backgroundColor="white"
onChange={this.getSketch}
/>
/>
</div>
</div>);
}

View File

@ -1,6 +1,6 @@
import React from 'react';
import ComponentExample from '../component_example';
import { getSaliencyColor } from '../utils';
import { getSaliencyColor } from '../../utils';
class NumberInput extends React.Component {
constructor(props) {

View File

@ -1,7 +1,7 @@
import React from 'react';
import ComponentExample from '../component_example';
import classNames from "classnames";
import { getSaliencyColor } from '../utils';
import { getSaliencyColor } from '../../utils';
class RadioInput extends React.Component {
constructor(props) {

View File

@ -1,6 +1,6 @@
import React from 'react';
import ComponentExample from '../component_example';
import { getSaliencyColor } from '../utils';
import { getSaliencyColor } from '../../utils';
class SliderInput extends React.Component {
constructor(props) {

View File

@ -1,6 +1,6 @@
import React from 'react';
import ComponentExample from '../component_example';
import { getSaliencyColor } from '../utils';
import { getSaliencyColor } from '../../utils';
class TextboxInput extends React.Component {
constructor(props) {

View File

@ -1,6 +1,6 @@
import React from 'react';
import ComponentExample from '../component_example';
import {prettyBytes} from '../utils';
import {prettyBytes} from '../../utils';
class FileOutput extends React.Component {
render() {

View File

@ -160,6 +160,26 @@
.image_preview_holder {
@apply w-full h-full flex justify-center items-center bg-gray-200 relative inline-block;
}
.edit_button {
@apply absolute top-1 right-1 bg-yellow-500 text-white px-2 py-1;
}
.image_editor {
@apply fixed w-screen h-screen top-0 left-0 bg-black bg-opacity-50 z-40 flex flex-col justify-center items-center;
.image_editor_buttons {
width: 800px;
@apply flex justify-end gap-1;
button {
@apply px-2 py-1 text-xl bg-black text-white font-semibold rounded-t;
}
}
.tui-image-editor-header-buttons {
@apply hidden;
}
.tui-colorpicker-palette-button {
width: 12px;
height: 12px;
}
}
.image_preview,
video {
@apply w-full h-full object-contain;

View File

@ -11,7 +11,7 @@
@apply pb-4;
}
.article {
@apply pt-8 pb-4 max-w-none;
@apply pt-8 pb-4 max-w-none;
}
}
@ -40,6 +40,23 @@
.panel_buttons {
@apply flex gap-4 my-4;
}
.flag {
@apply relative;
.dropcontent {
@apply hidden absolute top-8 left-0 bg-white border-gray-200 border-2 w-full;
div {
@apply p-2;
}
div:hover {
@apply bg-gray-100;
}
}
}
.flag:hover:not(.disabled) {
.dropcontent {
@apply block;
}
}
.screenshot_set {
@apply hidden flex hidden flex-grow;
}
@ -86,33 +103,71 @@
}
}
/* Input Components */
.input_text textarea {
@apply w-full p-3 border rounded-lg shadow-inner outline-none focus:ring-1 focus:ring-inset focus:ring-indigo-200 focus:shadow-inner placeholder-gray-400;
.input_text {
textarea {
@apply w-full p-3 border rounded-lg shadow-inner outline-none focus:ring-1 focus:ring-inset focus:ring-indigo-200 focus:shadow-inner placeholder-gray-400;
}
input {
@apply w-full p-3 border rounded-lg shadow-inner outline-none focus:ring-1 focus:ring-inset focus:ring-indigo-200 focus:shadow-inner placeholder-gray-400;
}
.interpretation {
.interpretation_box {
@apply inline-block whitespace-pre-wrap;
}
}
}
.input_text input {
@apply w-full p-3 border rounded-lg shadow-inner outline-none focus:ring-1 focus:ring-inset focus:ring-indigo-200 focus:shadow-inner placeholder-gray-400;
}
.input_number input {
@apply w-full p-3 border rounded-lg shadow-inner outline-none focus:ring-1 focus:ring-inset focus:ring-indigo-200 focus:shadow-inner placeholder-gray-400;
.input_number {
input {
@apply w-full p-3 border rounded-lg shadow-inner outline-none focus:ring-1 focus:ring-inset focus:ring-indigo-200 focus:shadow-inner placeholder-gray-400;
}
.interpretation {
@apply flex h-6;
.interpretation_box {
@apply flex-grow;
}
}
}
.input_image {
@apply w-full h-80;
@apply w-full h-80 relative;
.upload_zone {
@apply border-8 border-gray-300 border-dashed w-full h-full flex justify-center items-center text-3xl text-gray-400 text-center cursor-pointer leading-10;
}
.image_preview_holder {
@apply w-full h-full flex justify-center items-center bg-gray-300 relative inline-block;
}
.sketch > div {
@apply bg-white;
.edit_button {
@apply absolute top-1 right-1 bg-indigo-500 text-white px-2 py-1;
}
.image_editor {
@apply fixed w-screen h-screen top-0 left-0 bg-black bg-opacity-50 z-40 flex flex-col justify-center items-center;
.image_editor_buttons {
width: 800px;
@apply flex justify-end gap-1;
button {
@apply px-2 py-1 text-xl bg-black text-white font-semibold rounded-t;
}
}
.tui-image-editor-header-buttons {
@apply hidden;
}
.tui-colorpicker-palette-button {
width: 12px;
height: 12px;
}
}
.image_preview,
video {
@apply w-full h-full object-contain;
}
.sketch > div {
@apply bg-white;
}
.snapshot {
@apply absolute bottom-0 w-full bg-white bg-opacity-90 py-3 font-bold text-lg text-center;
}
.interpretation {
@apply w-full h-full absolute top-0 left-0 flex justify-center items-center opacity-90 hover:opacity-20 transition;
}
}
.input_image_example {
@apply h-24;
@ -157,6 +212,20 @@
stroke-width: 4;
stroke-linecap: round;
}
.interpretation {
@apply flex;
.interpretation_box {
@apply flex-grow h-4 w-4;
}
.interpret_check {
@apply w-full h-full;
}
.interpret_check line {
stroke: gray;
stroke-width: 4;
stroke-linecap: round;
}
}
}
.input_checkbox {
@apply flex flex-wrap gap-2;
@ -183,6 +252,20 @@
stroke-width: 4;
stroke-linecap: round;
}
.interpretation {
@apply flex;
.interpretation_box {
@apply flex-grow h-4 w-4;
}
.interpret_check {
@apply w-full h-full;
}
.interpret_check line {
stroke: gray;
stroke-width: 4;
stroke-linecap: round;
}
}
}
.input_dropdown {
@apply inline-block relative;
@ -210,6 +293,9 @@
:hover .dropdown_menu {
@apply block;
}
.interpretation_box {
@apply p-1;
}
}
.input_slider {
@apply text-center;
@ -226,6 +312,12 @@
.value {
@apply inline-block mx-auto mt-1 px-2 py-0.5 bg-gray-100 text-gray-700 rounded shadow-inner;
}
.interpret_range {
@apply flex h-6;
div {
@apply flex-grow;
}
}
}
.input_audio {
.audio-react-recorder {
@ -239,6 +331,12 @@
}
audio {
@apply w-full;
.interpret_range {
@apply flex h-4;
div {
@apply flex-grow h-full;
}
}
}
}
.input_video {
@ -268,7 +366,6 @@
@apply text-2xl p-2;
}
}
/* Output Components */
.output_text {
word-break: break-word;

View File

@ -63,13 +63,29 @@ export function paintSaliency(data, ctx, width, height) {
var cell_width = width / data[0].length
var cell_height = height / data.length
var r = 0
data.forEach(function(row) {
var c = 0
row.forEach(function(cell) {
ctx.fillStyle = getSaliencyColor(cell);
ctx.fillRect(c * cell_width, r * cell_height, cell_width, cell_height);
c++;
})
r++;
data.forEach(function (row) {
var c = 0
row.forEach(function (cell) {
ctx.fillStyle = getSaliencyColor(cell);
ctx.fillRect(c * cell_width, r * cell_height, cell_width, cell_height);
c++;
})
r++;
})
}
export function saveAs(uri, filename) {
var link = document.createElement('a');
if (typeof link.download === 'string') {
link.href = uri;
link.download = filename;
//Firefox requires the link to be in the body
document.body.appendChild(link);
//simulate click
link.click();
//remove the link when done
document.body.removeChild(link);
} else {
window.open(uri);
}
}

View File

@ -26,6 +26,30 @@ gradio.egg-info/requires.txt
gradio.egg-info/top_level.txt
gradio/frontend/asset-manifest.json
gradio/frontend/index.html
gradio/frontend/static/bundle.css
gradio/frontend/static/bundle.css.map
gradio/frontend/static/bundle.js
gradio/frontend/static/bundle.js.LICENSE.txt
gradio/frontend/static/bundle.js.map
gradio/frontend/static/css/main.20be28ac.css
gradio/frontend/static/css/main.20be28ac.css.map
gradio/frontend/static/css/main.2b64a968.css
gradio/frontend/static/css/main.2b64a968.css.map
gradio/frontend/static/css/main.380e3222.css
gradio/frontend/static/css/main.380e3222.css.map
gradio/frontend/static/css/main.4aea80f8.css
gradio/frontend/static/css/main.4aea80f8.css.map
gradio/frontend/static/css/main.4f157d97.css
gradio/frontend/static/css/main.4f157d97.css.map
gradio/frontend/static/css/main.5c663906.css
gradio/frontend/static/css/main.5c663906.css.map
gradio/frontend/static/css/main.99922310.css
gradio/frontend/static/css/main.99922310.css.map
gradio/frontend/static/css/main.acb02c85.css
gradio/frontend/static/css/main.acb02c85.css.map
gradio/frontend/static/css/main.cbbf8898.css
gradio/frontend/static/css/main.cbbf8898.css.map
gradio/frontend/static/media/logo_loading.e93acd82.jpg
test/test_demos.py
test/test_inputs.py
test/test_interfaces.py

View File

@ -7,8 +7,9 @@ class Component():
A class for defining the methods that all gradio input and output components should have.
"""
def __init__(self, label):
def __init__(self, label, requires_permissions=False):
self.label = label
self.requires_permissions = requires_permissions
def __str__(self):
return self.__repr__()

View File

@ -1,17 +1,17 @@
{
"files": {
"main.css": "/static/css/main.4f157d97.css",
"main.css": "/static/css/main.5c663906.css",
"main.js": "/static/bundle.js",
"main.js.map": "/static/bundle.js.map",
"index.html": "/index.html",
"static/bundle.css.map": "/static/bundle.css.map",
"static/bundle.js.LICENSE.txt": "/static/bundle.js.LICENSE.txt",
"static/css/main.4f157d97.css.map": "/static/css/main.4f157d97.css.map",
"static/css/main.5c663906.css.map": "/static/css/main.5c663906.css.map",
"static/media/logo_loading.e93acd82.jpg": "/static/media/logo_loading.e93acd82.jpg"
},
"entrypoints": [
"static/bundle.css",
"static/css/main.4f157d97.css",
"static/css/main.5c663906.css",
"static/bundle.js"
]
}

View File

@ -8,4 +8,4 @@
window.config = {{ config|tojson }};
} catch (e) {
window.config = {};
}</script><title>Gradio</title><link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet"><link href="static/bundle.css" rel="stylesheet"><link href="static/css/main.4f157d97.css" rel="stylesheet"></head><body><div id="root"></div><script src="static/bundle.js"></script></body></html>
}</script><title>Gradio</title><link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet"><link href="static/bundle.css" rel="stylesheet"><link href="static/css/main.5c663906.css" rel="stylesheet"></head><body><div id="root"></div><script src="static/bundle.js"></script></body></html>

View File

@ -28,9 +28,9 @@ class InputComponent(Component):
"""
Input Component. All input components subclass this.
"""
def __init__(self, label):
def __init__(self, label, requires_permissions=False):
self.interpret()
super().__init__(label)
super().__init__(label, requires_permissions)
def preprocess(self, x):
"""
@ -642,11 +642,12 @@ class Image(InputComponent):
self.shape = shape
self.image_mode = image_mode
self.source = source
requires_permissions = source == "webcam"
self.tool = tool
self.type = type
self.invert_colors = invert_colors
self.test_input = test_data.BASE64_IMAGE
super().__init__(label)
super().__init__(label, requires_permissions)
@classmethod
def get_shortcut_implementations(cls):
@ -821,9 +822,10 @@ class Audio(InputComponent):
label (str): component name in interface.
"""
self.source = source
requires_permissions = source == "microphone"
self.type = type
self.test_input = test_data.BASE64_AUDIO
super().__init__(label)
super().__init__(label, requires_permissions)
def get_template_context(self):
return {

View File

@ -183,6 +183,7 @@ class Interface:
self.local_url = None
self.embedding = embedding
self.show_tips = show_tips
self.requires_permissions = any([component.requires_permissions for component in self.input_components])
data = {'fn': fn,
'inputs': inputs,
@ -486,6 +487,8 @@ class Interface:
print(strings.en["COLAB_DEBUG_FALSE"])
else:
print(strings.en["RUNNING_LOCALLY"].format(path_to_local_server))
if is_colab and self.requires_permissions:
print(strings.en["MEDIA_PERMISSIONS_IN_COLAB"])
if private_endpoint is not None:
share = True
@ -567,18 +570,9 @@ class Interface:
def show_tip(io):
if not(io.show_tips):
if not(io.show_tips) or random.random() < 0.5: # Only show tip every other use.
return
if random.random() < 0.8: # Only show tips once every 5 uses
return
relevant_tips = []
if io.interpretation is None:
relevant_tips.append(strings.en["TIP_INTERPRETATION"])
if io.embedding is None and not(io.examples is None) and len(io.examples)>4:
relevant_tips.append(strings.en["TIP_EMBEDDING"])
if len(relevant_tips)==0:
return
print(random.choice(relevant_tips))
print(random.choice(strings.en.TIPS))
def launch_counter():
try:

View File

@ -23,8 +23,14 @@ en = {
"SHARE_LINK_MESSAGE": "This share link will expire in 24 hours. If you need a permanent link, visit: https://gradio.app/introducing-hosted (NEW!)",
"SHARE_LINK_DISPLAY": "Running on External URL: {}",
"INLINE_DISPLAY_BELOW": "Interface loading below...",
"TIP_INTERPRETATION": "Tip: Add interpretation to your model by simply adding `interpretation=\"default\"` to `Interface()`",
"TIP_EMBEDDING": "Tip: View embeddings of your dataset by simply adding `embedding=\"default\"` to `Interface()`",
"MEDIA_PERMISSIONS_IN_COLAB": "Your interface requires microphone or webcam permissions - this may cause issues in Colab. Use the External URL in case of issues.",
"TIPS": [
"You can add authentication to your app with the auth= kwarg in the launch command; for example: gr.Interface(...).launch(auth=('username', 'password'))",
"Let users specify why they flagged input with the flagging_options= kwarg; for example: gr.Interface(..., flagging_options=['too slow', 'incorrect output', 'other'])",
"You can show or hide the buttons for flagging, screenshots, and interpretation with the allow_*= kwargs; for example: gr.Interface(..., allow_screenshot=True, allow_flagging=False)",
"The inputs and outputs flagged by the users are stored in the flagging directory, specified by the flagging_dir= kwarg. You can view this data through the interface by setting the examples= kwarg to the flagging directory; for example gr.Interface(..., examples='flagged')",
"You can add a title and description to your interface using the title= and description= kwargs. The article= kwarg can be used to add markdown or HTML under the interface; for example gr.Interface(..., title='My app', description='Lorem ipsum')"
]
}
try: