diff --git a/Test Notebook.ipynb b/Test Notebook.ipynb
index dc27277049..9f70607095 100644
--- a/Test Notebook.ipynb
+++ b/Test Notebook.ipynb
@@ -29,15 +29,8 @@
"outputs": [],
"source": [
"inp = gradio.inputs.ImageUpload(image_width=299, image_height=299)\n",
- "out = gradio.outputs.Label(label_names='imagenet1000', max_label_length=8)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "metadata": {},
- "outputs": [],
- "source": [
+ "out = gradio.outputs.Label(label_names='imagenet1000', max_label_length=8, num_top_classes=5)\n",
+ "\n",
"iface = gradio.Interface(inputs=inp, \n",
" outputs=out,\n",
" model=model, \n",
@@ -54,8 +47,8 @@
"output_type": "stream",
"text": [
"NOTE: Gradio is in beta stage, please report all bugs to: a12d@stanford.edu\n",
- "Model is running locally at: http://localhost:7860/interface.html\n",
- "Model available publicly for 8 hours at: https://efb97fa5.ngrok.io/interface.html\n"
+ "Model is running locally at: http://localhost:7861/interface.html\n",
+ "Model available publicly for 8 hours at: http://4d315e61.ngrok.io/interface.html\n"
]
},
{
@@ -65,50 +58,63 @@
" \n",
" "
],
"text/plain": [
- ""
+ ""
]
},
"metadata": {},
"output_type": "display_data"
},
- {
- "data": {
- "text/plain": [
- "('http://localhost:7860/interface.html', 'https://efb97fa5.ngrok.io')"
- ]
- },
- "execution_count": 5,
- "metadata": {},
- "output_type": "execute_result"
- },
{
"name": "stderr",
"output_type": "stream",
"text": [
- "127.0.0.1 - - [06/Mar/2019 11:24:00] \"GET /interface.html HTTP/1.1\" 200 -\n",
- "127.0.0.1 - - [06/Mar/2019 11:24:00] \"GET /interface.html HTTP/1.1\" 200 -\n",
- "127.0.0.1 - - [06/Mar/2019 11:24:00] \"GET /static/js/all-io.js HTTP/1.1\" 200 -\n",
- "127.0.0.1 - - [06/Mar/2019 11:24:00] \"GET /static/js/all-io.js HTTP/1.1\" 200 -\n"
- ]
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "dddddddddddddddddddd cleaver,\n",
- "dddddddddddddddddddd cleaver,\n"
+ "127.0.0.1 - - [06/Mar/2019 11:55:01] \"GET /interface.html HTTP/1.1\" 200 -\n",
+ "127.0.0.1 - - [06/Mar/2019 11:55:01] \"GET /interface.html HTTP/1.1\" 200 -\n",
+ "127.0.0.1 - - [06/Mar/2019 11:55:01] \"GET /static/css/gradio.css HTTP/1.1\" 200 -\n",
+ "127.0.0.1 - - [06/Mar/2019 11:55:01] \"GET /static/js/all-io.js HTTP/1.1\" 200 -\n",
+ "127.0.0.1 - - [06/Mar/2019 11:55:01] \"GET /static/js/image-upload-input.js HTTP/1.1\" 200 -\n",
+ "127.0.0.1 - - [06/Mar/2019 11:55:01] \"GET /static/js/all-io.js HTTP/1.1\" 200 -\n",
+ "127.0.0.1 - - [06/Mar/2019 11:55:01] \"GET /static/js/class-output.js HTTP/1.1\" 200 -\n",
+ "127.0.0.1 - - [06/Mar/2019 11:55:02] code 404, message File not found\n",
+ "127.0.0.1 - - [06/Mar/2019 11:55:02] \"GET /favicon.ico HTTP/1.1\" 404 -\n",
+ "127.0.0.1 - - [06/Mar/2019 11:55:08] \"GET /interface.html HTTP/1.1\" 200 -\n",
+ "127.0.0.1 - - [06/Mar/2019 11:55:09] \"GET /static/css/style.css HTTP/1.1\" 200 -\n",
+ "127.0.0.1 - - [06/Mar/2019 11:55:09] \"GET /static/css/gradio.css HTTP/1.1\" 200 -\n",
+ "127.0.0.1 - - [06/Mar/2019 11:55:09] \"GET /static/js/utils.js HTTP/1.1\" 200 -\n",
+ "127.0.0.1 - - [06/Mar/2019 11:55:09] \"GET /static/js/all-io.js HTTP/1.1\" 200 -\n",
+ "127.0.0.1 - - [06/Mar/2019 11:55:09] \"GET /static/img/logo_inline.png HTTP/1.1\" 200 -\n",
+ "127.0.0.1 - - [06/Mar/2019 11:55:09] \"GET /static/js/image-upload-input.js HTTP/1.1\" 200 -\n",
+ "127.0.0.1 - - [06/Mar/2019 11:55:09] \"GET /static/js/class-output.js HTTP/1.1\" 200 -\n",
+ "127.0.0.1 - - [06/Mar/2019 11:55:10] code 404, message File not found\n",
+ "127.0.0.1 - - [06/Mar/2019 11:55:10] \"GET /favicon.ico HTTP/1.1\" 404 -\n",
+ "127.0.0.1 - - [06/Mar/2019 11:58:07] \"GET /interface.html HTTP/1.1\" 200 -\n",
+ "127.0.0.1 - - [06/Mar/2019 11:58:07] \"GET /static/css/gradio.css HTTP/1.1\" 200 -\n",
+ "127.0.0.1 - - [06/Mar/2019 11:58:07] \"GET /static/js/all-io.js HTTP/1.1\" 200 -\n",
+ "127.0.0.1 - - [06/Mar/2019 11:58:07] \"GET /static/js/image-upload-input.js HTTP/1.1\" 200 -\n",
+ "127.0.0.1 - - [06/Mar/2019 11:58:07] \"GET /static/js/class-output.js HTTP/1.1\" 200 -\n",
+ "127.0.0.1 - - [06/Mar/2019 11:58:31] \"GET /interface.html HTTP/1.1\" 200 -\n",
+ "127.0.0.1 - - [06/Mar/2019 11:58:43] \"GET /interface.html HTTP/1.1\" 200 -\n",
+ "127.0.0.1 - - [06/Mar/2019 11:58:44] \"GET /static/js/utils.js HTTP/1.1\" 200 -\n",
+ "127.0.0.1 - - [06/Mar/2019 11:58:44] \"GET /static/css/gradio.css HTTP/1.1\" 200 -\n",
+ "127.0.0.1 - - [06/Mar/2019 11:58:44] \"GET /static/js/all-io.js HTTP/1.1\" 200 -\n",
+ "127.0.0.1 - - [06/Mar/2019 11:58:44] \"GET /static/css/style.css HTTP/1.1\" 200 -\n",
+ "127.0.0.1 - - [06/Mar/2019 11:58:44] \"GET /static/js/image-upload-input.js HTTP/1.1\" 200 -\n",
+ "127.0.0.1 - - [06/Mar/2019 11:58:44] \"GET /static/js/class-output.js HTTP/1.1\" 200 -\n",
+ "127.0.0.1 - - [06/Mar/2019 11:58:44] \"GET /static/img/logo_inline.png HTTP/1.1\" 200 -\n",
+ "127.0.0.1 - - [06/Mar/2019 11:58:45] code 404, message File not found\n",
+ "127.0.0.1 - - [06/Mar/2019 11:58:45] \"GET /favicon.ico HTTP/1.1\" 404 -\n"
]
}
],
"source": [
- "iface.launch(inline=True, browser=True, share=True)"
+ "iface.launch(inline=True, browser=True, share=True);"
]
}
],
diff --git a/build/lib/gradio/__init__.py b/build/lib/gradio/__init__.py
index ee12ab164f..4b898437e3 100644
--- a/build/lib/gradio/__init__.py
+++ b/build/lib/gradio/__init__.py
@@ -1 +1 @@
-from gradio.interface import Interface # This makes Interface importable as gradio.Interface.
+from gradio.interface import Interface # This makes it possible to import `Interface` as `gradio.Interface`.
diff --git a/build/lib/gradio/imagenet_class_labels.py b/build/lib/gradio/imagenet_class_labels.py
new file mode 100644
index 0000000000..b8ed7a7682
--- /dev/null
+++ b/build/lib/gradio/imagenet_class_labels.py
@@ -0,0 +1,1000 @@
+NAMES1000 = {0: 'tench, Tinca tinca',
+ 1: 'goldfish, Carassius auratus',
+ 2: 'great white shark, white shark, man-eater, man-eating shark, Carcharodon carcharias',
+ 3: 'tiger shark, Galeocerdo cuvieri',
+ 4: 'hammerhead, hammerhead shark',
+ 5: 'electric ray, crampfish, numbfish, torpedo',
+ 6: 'stingray',
+ 7: 'cock',
+ 8: 'hen',
+ 9: 'ostrich, Struthio camelus',
+ 10: 'brambling, Fringilla montifringilla',
+ 11: 'goldfinch, Carduelis carduelis',
+ 12: 'house finch, linnet, Carpodacus mexicanus',
+ 13: 'junco, snowbird',
+ 14: 'indigo bunting, indigo finch, indigo bird, Passerina cyanea',
+ 15: 'robin, American robin, Turdus migratorius',
+ 16: 'bulbul',
+ 17: 'jay',
+ 18: 'magpie',
+ 19: 'chickadee',
+ 20: 'water ouzel, dipper',
+ 21: 'kite',
+ 22: 'bald eagle, American eagle, Haliaeetus leucocephalus',
+ 23: 'vulture',
+ 24: 'great grey owl, great gray owl, Strix nebulosa',
+ 25: 'European fire salamander, Salamandra salamandra',
+ 26: 'common newt, Triturus vulgaris',
+ 27: 'eft',
+ 28: 'spotted salamander, Ambystoma maculatum',
+ 29: 'axolotl, mud puppy, Ambystoma mexicanum',
+ 30: 'bullfrog, Rana catesbeiana',
+ 31: 'tree frog, tree-frog',
+ 32: 'tailed frog, bell toad, ribbed toad, tailed toad, Ascaphus trui',
+ 33: 'loggerhead, loggerhead turtle, Caretta caretta',
+ 34: 'leatherback turtle, leatherback, leathery turtle, Dermochelys coriacea',
+ 35: 'mud turtle',
+ 36: 'terrapin',
+ 37: 'box turtle, box tortoise',
+ 38: 'banded gecko',
+ 39: 'common iguana, iguana, Iguana iguana',
+ 40: 'American chameleon, anole, Anolis carolinensis',
+ 41: 'whiptail, whiptail lizard',
+ 42: 'agama',
+ 43: 'frilled lizard, Chlamydosaurus kingi',
+ 44: 'alligator lizard',
+ 45: 'Gila monster, Heloderma suspectum',
+ 46: 'green lizard, Lacerta viridis',
+ 47: 'African chameleon, Chamaeleo chamaeleon',
+ 48: 'Komodo dragon, Komodo lizard, dragon lizard, giant lizard, Varanus komodoensis',
+ 49: 'African crocodile, Nile crocodile, Crocodylus niloticus',
+ 50: 'American alligator, Alligator mississipiensis',
+ 51: 'triceratops',
+ 52: 'thunder snake, worm snake, Carphophis amoenus',
+ 53: 'ringneck snake, ring-necked snake, ring snake',
+ 54: 'hognose snake, puff adder, sand viper',
+ 55: 'green snake, grass snake',
+ 56: 'king snake, kingsnake',
+ 57: 'garter snake, grass snake',
+ 58: 'water snake',
+ 59: 'vine snake',
+ 60: 'night snake, Hypsiglena torquata',
+ 61: 'boa constrictor, Constrictor constrictor',
+ 62: 'rock python, rock snake, Python sebae',
+ 63: 'Indian cobra, Naja naja',
+ 64: 'green mamba',
+ 65: 'sea snake',
+ 66: 'horned viper, cerastes, sand viper, horned asp, Cerastes cornutus',
+ 67: 'diamondback, diamondback rattlesnake, Crotalus adamanteus',
+ 68: 'sidewinder, horned rattlesnake, Crotalus cerastes',
+ 69: 'trilobite',
+ 70: 'harvestman, daddy longlegs, Phalangium opilio',
+ 71: 'scorpion',
+ 72: 'black and gold garden spider, Argiope aurantia',
+ 73: 'barn spider, Araneus cavaticus',
+ 74: 'garden spider, Aranea diademata',
+ 75: 'black widow, Latrodectus mactans',
+ 76: 'tarantula',
+ 77: 'wolf spider, hunting spider',
+ 78: 'tick',
+ 79: 'centipede',
+ 80: 'black grouse',
+ 81: 'ptarmigan',
+ 82: 'ruffed grouse, partridge, Bonasa umbellus',
+ 83: 'prairie chicken, prairie grouse, prairie fowl',
+ 84: 'peacock',
+ 85: 'quail',
+ 86: 'partridge',
+ 87: 'African grey, African gray, Psittacus erithacus',
+ 88: 'macaw',
+ 89: 'sulphur-crested cockatoo, Kakatoe galerita, Cacatua galerita',
+ 90: 'lorikeet',
+ 91: 'coucal',
+ 92: 'bee eater',
+ 93: 'hornbill',
+ 94: 'hummingbird',
+ 95: 'jacamar',
+ 96: 'toucan',
+ 97: 'drake',
+ 98: 'red-breasted merganser, Mergus serrator',
+ 99: 'goose',
+ 100: 'black swan, Cygnus atratus',
+ 101: 'tusker',
+ 102: 'echidna, spiny anteater, anteater',
+ 103: 'platypus, duckbill, duckbilled platypus, duck-billed platypus, Ornithorhynchus anatinus',
+ 104: 'wallaby, brush kangaroo',
+ 105: 'koala, koala bear, kangaroo bear, native bear, Phascolarctos cinereus',
+ 106: 'wombat',
+ 107: 'jellyfish',
+ 108: 'sea anemone, anemone',
+ 109: 'brain coral',
+ 110: 'flatworm, platyhelminth',
+ 111: 'nematode, nematode worm, roundworm',
+ 112: 'conch',
+ 113: 'snail',
+ 114: 'slug',
+ 115: 'sea slug, nudibranch',
+ 116: 'chiton, coat-of-mail shell, sea cradle, polyplacophore',
+ 117: 'chambered nautilus, pearly nautilus, nautilus',
+ 118: 'Dungeness crab, Cancer magister',
+ 119: 'rock crab, Cancer irroratus',
+ 120: 'fiddler crab',
+ 121: 'king crab, Alaska crab, Alaskan king crab, Alaska king crab, Paralithodes camtschatica',
+ 122: 'American lobster, Northern lobster, Maine lobster, Homarus americanus',
+ 123: 'spiny lobster, langouste, rock lobster, crawfish, crayfish, sea crawfish',
+ 124: 'crayfish, crawfish, crawdad, crawdaddy',
+ 125: 'hermit crab',
+ 126: 'isopod',
+ 127: 'white stork, Ciconia ciconia',
+ 128: 'black stork, Ciconia nigra',
+ 129: 'spoonbill',
+ 130: 'flamingo',
+ 131: 'little blue heron, Egretta caerulea',
+ 132: 'American egret, great white heron, Egretta albus',
+ 133: 'bittern',
+ 134: 'crane',
+ 135: 'limpkin, Aramus pictus',
+ 136: 'European gallinule, Porphyrio porphyrio',
+ 137: 'American coot, marsh hen, mud hen, water hen, Fulica americana',
+ 138: 'bustard',
+ 139: 'ruddy turnstone, Arenaria interpres',
+ 140: 'red-backed sandpiper, dunlin, Erolia alpina',
+ 141: 'redshank, Tringa totanus',
+ 142: 'dowitcher',
+ 143: 'oystercatcher, oyster catcher',
+ 144: 'pelican',
+ 145: 'king penguin, Aptenodytes patagonica',
+ 146: 'albatross, mollymawk',
+ 147: 'grey whale, gray whale, devilfish, Eschrichtius gibbosus, Eschrichtius robustus',
+ 148: 'killer whale, killer, orca, grampus, sea wolf, Orcinus orca',
+ 149: 'dugong, Dugong dugon',
+ 150: 'sea lion',
+ 151: 'Chihuahua',
+ 152: 'Japanese spaniel',
+ 153: 'Maltese dog, Maltese terrier, Maltese',
+ 154: 'Pekinese, Pekingese, Peke',
+ 155: 'Shih-Tzu',
+ 156: 'Blenheim spaniel',
+ 157: 'papillon',
+ 158: 'toy terrier',
+ 159: 'Rhodesian ridgeback',
+ 160: 'Afghan hound, Afghan',
+ 161: 'basset, basset hound',
+ 162: 'beagle',
+ 163: 'bloodhound, sleuthhound',
+ 164: 'bluetick',
+ 165: 'black-and-tan coonhound',
+ 166: 'Walker hound, Walker foxhound',
+ 167: 'English foxhound',
+ 168: 'redbone',
+ 169: 'borzoi, Russian wolfhound',
+ 170: 'Irish wolfhound',
+ 171: 'Italian greyhound',
+ 172: 'whippet',
+ 173: 'Ibizan hound, Ibizan Podenco',
+ 174: 'Norwegian elkhound, elkhound',
+ 175: 'otterhound, otter hound',
+ 176: 'Saluki, gazelle hound',
+ 177: 'Scottish deerhound, deerhound',
+ 178: 'Weimaraner',
+ 179: 'Staffordshire bullterrier, Staffordshire bull terrier',
+ 180: 'American Staffordshire terrier, Staffordshire terrier, American pit bull terrier, pit bull terrier',
+ 181: 'Bedlington terrier',
+ 182: 'Border terrier',
+ 183: 'Kerry blue terrier',
+ 184: 'Irish terrier',
+ 185: 'Norfolk terrier',
+ 186: 'Norwich terrier',
+ 187: 'Yorkshire terrier',
+ 188: 'wire-haired fox terrier',
+ 189: 'Lakeland terrier',
+ 190: 'Sealyham terrier, Sealyham',
+ 191: 'Airedale, Airedale terrier',
+ 192: 'cairn, cairn terrier',
+ 193: 'Australian terrier',
+ 194: 'Dandie Dinmont, Dandie Dinmont terrier',
+ 195: 'Boston bull, Boston terrier',
+ 196: 'miniature schnauzer',
+ 197: 'giant schnauzer',
+ 198: 'standard schnauzer',
+ 199: 'Scotch terrier, Scottish terrier, Scottie',
+ 200: 'Tibetan terrier, chrysanthemum dog',
+ 201: 'silky terrier, Sydney silky',
+ 202: 'soft-coated wheaten terrier',
+ 203: 'West Highland white terrier',
+ 204: 'Lhasa, Lhasa apso',
+ 205: 'flat-coated retriever',
+ 206: 'curly-coated retriever',
+ 207: 'golden retriever',
+ 208: 'Labrador retriever',
+ 209: 'Chesapeake Bay retriever',
+ 210: 'German short-haired pointer',
+ 211: 'vizsla, Hungarian pointer',
+ 212: 'English setter',
+ 213: 'Irish setter, red setter',
+ 214: 'Gordon setter',
+ 215: 'Brittany spaniel',
+ 216: 'clumber, clumber spaniel',
+ 217: 'English springer, English springer spaniel',
+ 218: 'Welsh springer spaniel',
+ 219: 'cocker spaniel, English cocker spaniel, cocker',
+ 220: 'Sussex spaniel',
+ 221: 'Irish water spaniel',
+ 222: 'kuvasz',
+ 223: 'schipperke',
+ 224: 'groenendael',
+ 225: 'malinois',
+ 226: 'briard',
+ 227: 'kelpie',
+ 228: 'komondor',
+ 229: 'Old English sheepdog, bobtail',
+ 230: 'Shetland sheepdog, Shetland sheep dog, Shetland',
+ 231: 'collie',
+ 232: 'Border collie',
+ 233: 'Bouvier des Flandres, Bouviers des Flandres',
+ 234: 'Rottweiler',
+ 235: 'German shepherd, German shepherd dog, German police dog, alsatian',
+ 236: 'Doberman, Doberman pinscher',
+ 237: 'miniature pinscher',
+ 238: 'Greater Swiss Mountain dog',
+ 239: 'Bernese mountain dog',
+ 240: 'Appenzeller',
+ 241: 'EntleBucher',
+ 242: 'boxer',
+ 243: 'bull mastiff',
+ 244: 'Tibetan mastiff',
+ 245: 'French bulldog',
+ 246: 'Great Dane',
+ 247: 'Saint Bernard, St Bernard',
+ 248: 'Eskimo dog, husky',
+ 249: 'malamute, malemute, Alaskan malamute',
+ 250: 'Siberian husky',
+ 251: 'dalmatian, coach dog, carriage dog',
+ 252: 'affenpinscher, monkey pinscher, monkey dog',
+ 253: 'basenji',
+ 254: 'pug, pug-dog',
+ 255: 'Leonberg',
+ 256: 'Newfoundland, Newfoundland dog',
+ 257: 'Great Pyrenees',
+ 258: 'Samoyed, Samoyede',
+ 259: 'Pomeranian',
+ 260: 'chow, chow chow',
+ 261: 'keeshond',
+ 262: 'Brabancon griffon',
+ 263: 'Pembroke, Pembroke Welsh corgi',
+ 264: 'Cardigan, Cardigan Welsh corgi',
+ 265: 'toy poodle',
+ 266: 'miniature poodle',
+ 267: 'standard poodle',
+ 268: 'Mexican hairless',
+ 269: 'timber wolf, grey wolf, gray wolf, Canis lupus',
+ 270: 'white wolf, Arctic wolf, Canis lupus tundrarum',
+ 271: 'red wolf, maned wolf, Canis rufus, Canis niger',
+ 272: 'coyote, prairie wolf, brush wolf, Canis latrans',
+ 273: 'dingo, warrigal, warragal, Canis dingo',
+ 274: 'dhole, Cuon alpinus',
+ 275: 'African hunting dog, hyena dog, Cape hunting dog, Lycaon pictus',
+ 276: 'hyena, hyaena',
+ 277: 'red fox, Vulpes vulpes',
+ 278: 'kit fox, Vulpes macrotis',
+ 279: 'Arctic fox, white fox, Alopex lagopus',
+ 280: 'grey fox, gray fox, Urocyon cinereoargenteus',
+ 281: 'tabby, tabby cat',
+ 282: 'tiger cat',
+ 283: 'Persian cat',
+ 284: 'Siamese cat, Siamese',
+ 285: 'Egyptian cat',
+ 286: 'cougar, puma, catamount, mountain lion, painter, panther, Felis concolor',
+ 287: 'lynx, catamount',
+ 288: 'leopard, Panthera pardus',
+ 289: 'snow leopard, ounce, Panthera uncia',
+ 290: 'jaguar, panther, Panthera onca, Felis onca',
+ 291: 'lion, king of beasts, Panthera leo',
+ 292: 'tiger, Panthera tigris',
+ 293: 'cheetah, chetah, Acinonyx jubatus',
+ 294: 'brown bear, bruin, Ursus arctos',
+ 295: 'American black bear, black bear, Ursus americanus, Euarctos americanus',
+ 296: 'ice bear, polar bear, Ursus Maritimus, Thalarctos maritimus',
+ 297: 'sloth bear, Melursus ursinus, Ursus ursinus',
+ 298: 'mongoose',
+ 299: 'meerkat, mierkat',
+ 300: 'tiger beetle',
+ 301: 'ladybug, ladybeetle, lady beetle, ladybird, ladybird beetle',
+ 302: 'ground beetle, carabid beetle',
+ 303: 'long-horned beetle, longicorn, longicorn beetle',
+ 304: 'leaf beetle, chrysomelid',
+ 305: 'dung beetle',
+ 306: 'rhinoceros beetle',
+ 307: 'weevil',
+ 308: 'fly',
+ 309: 'bee',
+ 310: 'ant, emmet, pismire',
+ 311: 'grasshopper, hopper',
+ 312: 'cricket',
+ 313: 'walking stick, walkingstick, stick insect',
+ 314: 'cockroach, roach',
+ 315: 'mantis, mantid',
+ 316: 'cicada, cicala',
+ 317: 'leafhopper',
+ 318: 'lacewing, lacewing fly',
+ 319: "dragonfly, darning needle, devil's darning needle, sewing needle, snake feeder, snake doctor, mosquito hawk, skeeter hawk",
+ 320: 'damselfly',
+ 321: 'admiral',
+ 322: 'ringlet, ringlet butterfly',
+ 323: 'monarch, monarch butterfly, milkweed butterfly, Danaus plexippus',
+ 324: 'cabbage butterfly',
+ 325: 'sulphur butterfly, sulfur butterfly',
+ 326: 'lycaenid, lycaenid butterfly',
+ 327: 'starfish, sea star',
+ 328: 'sea urchin',
+ 329: 'sea cucumber, holothurian',
+ 330: 'wood rabbit, cottontail, cottontail rabbit',
+ 331: 'hare',
+ 332: 'Angora, Angora rabbit',
+ 333: 'hamster',
+ 334: 'porcupine, hedgehog',
+ 335: 'fox squirrel, eastern fox squirrel, Sciurus niger',
+ 336: 'marmot',
+ 337: 'beaver',
+ 338: 'guinea pig, Cavia cobaya',
+ 339: 'sorrel',
+ 340: 'zebra',
+ 341: 'hog, pig, grunter, squealer, Sus scrofa',
+ 342: 'wild boar, boar, Sus scrofa',
+ 343: 'warthog',
+ 344: 'hippopotamus, hippo, river horse, Hippopotamus amphibius',
+ 345: 'ox',
+ 346: 'water buffalo, water ox, Asiatic buffalo, Bubalus bubalis',
+ 347: 'bison',
+ 348: 'ram, tup',
+ 349: 'bighorn, bighorn sheep, cimarron, Rocky Mountain bighorn, Rocky Mountain sheep, Ovis canadensis',
+ 350: 'ibex, Capra ibex',
+ 351: 'hartebeest',
+ 352: 'impala, Aepyceros melampus',
+ 353: 'gazelle',
+ 354: 'Arabian camel, dromedary, Camelus dromedarius',
+ 355: 'llama',
+ 356: 'weasel',
+ 357: 'mink',
+ 358: 'polecat, fitch, foulmart, foumart, Mustela putorius',
+ 359: 'black-footed ferret, ferret, Mustela nigripes',
+ 360: 'otter',
+ 361: 'skunk, polecat, wood pussy',
+ 362: 'badger',
+ 363: 'armadillo',
+ 364: 'three-toed sloth, ai, Bradypus tridactylus',
+ 365: 'orangutan, orang, orangutang, Pongo pygmaeus',
+ 366: 'gorilla, Gorilla gorilla',
+ 367: 'chimpanzee, chimp, Pan troglodytes',
+ 368: 'gibbon, Hylobates lar',
+ 369: 'siamang, Hylobates syndactylus, Symphalangus syndactylus',
+ 370: 'guenon, guenon monkey',
+ 371: 'patas, hussar monkey, Erythrocebus patas',
+ 372: 'baboon',
+ 373: 'macaque',
+ 374: 'langur',
+ 375: 'colobus, colobus monkey',
+ 376: 'proboscis monkey, Nasalis larvatus',
+ 377: 'marmoset',
+ 378: 'capuchin, ringtail, Cebus capucinus',
+ 379: 'howler monkey, howler',
+ 380: 'titi, titi monkey',
+ 381: 'spider monkey, Ateles geoffroyi',
+ 382: 'squirrel monkey, Saimiri sciureus',
+ 383: 'Madagascar cat, ring-tailed lemur, Lemur catta',
+ 384: 'indri, indris, Indri indri, Indri brevicaudatus',
+ 385: 'Indian elephant, Elephas maximus',
+ 386: 'African elephant, Loxodonta africana',
+ 387: 'lesser panda, red panda, panda, bear cat, cat bear, Ailurus fulgens',
+ 388: 'giant panda, panda, panda bear, coon bear, Ailuropoda melanoleuca',
+ 389: 'barracouta, snoek',
+ 390: 'eel',
+ 391: 'coho, cohoe, coho salmon, blue jack, silver salmon, Oncorhynchus kisutch',
+ 392: 'rock beauty, Holocanthus tricolor',
+ 393: 'anemone fish',
+ 394: 'sturgeon',
+ 395: 'gar, garfish, garpike, billfish, Lepisosteus osseus',
+ 396: 'lionfish',
+ 397: 'puffer, pufferfish, blowfish, globefish',
+ 398: 'abacus',
+ 399: 'abaya',
+ 400: "academic gown, academic robe, judge's robe",
+ 401: 'accordion, piano accordion, squeeze box',
+ 402: 'acoustic guitar',
+ 403: 'aircraft carrier, carrier, flattop, attack aircraft carrier',
+ 404: 'airliner',
+ 405: 'airship, dirigible',
+ 406: 'altar',
+ 407: 'ambulance',
+ 408: 'amphibian, amphibious vehicle',
+ 409: 'analog clock',
+ 410: 'apiary, bee house',
+ 411: 'apron',
+ 412: 'ashcan, trash can, garbage can, wastebin, ash bin, ash-bin, ashbin, dustbin, trash barrel, trash bin',
+ 413: 'assault rifle, assault gun',
+ 414: 'backpack, back pack, knapsack, packsack, rucksack, haversack',
+ 415: 'bakery, bakeshop, bakehouse',
+ 416: 'balance beam, beam',
+ 417: 'balloon',
+ 418: 'ballpoint, ballpoint pen, ballpen, Biro',
+ 419: 'Band Aid',
+ 420: 'banjo',
+ 421: 'bannister, banister, balustrade, balusters, handrail',
+ 422: 'barbell',
+ 423: 'barber chair',
+ 424: 'barbershop',
+ 425: 'barn',
+ 426: 'barometer',
+ 427: 'barrel, cask',
+ 428: 'barrow, garden cart, lawn cart, wheelbarrow',
+ 429: 'baseball',
+ 430: 'basketball',
+ 431: 'bassinet',
+ 432: 'bassoon',
+ 433: 'bathing cap, swimming cap',
+ 434: 'bath towel',
+ 435: 'bathtub, bathing tub, bath, tub',
+ 436: 'beach wagon, station wagon, wagon, estate car, beach waggon, station waggon, waggon',
+ 437: 'beacon, lighthouse, beacon light, pharos',
+ 438: 'beaker',
+ 439: 'bearskin, busby, shako',
+ 440: 'beer bottle',
+ 441: 'beer glass',
+ 442: 'bell cote, bell cot',
+ 443: 'bib',
+ 444: 'bicycle-built-for-two, tandem bicycle, tandem',
+ 445: 'bikini, two-piece',
+ 446: 'binder, ring-binder',
+ 447: 'binoculars, field glasses, opera glasses',
+ 448: 'birdhouse',
+ 449: 'boathouse',
+ 450: 'bobsled, bobsleigh, bob',
+ 451: 'bolo tie, bolo, bola tie, bola',
+ 452: 'bonnet, poke bonnet',
+ 453: 'bookcase',
+ 454: 'bookshop, bookstore, bookstall',
+ 455: 'bottlecap',
+ 456: 'bow',
+ 457: 'bow tie, bow-tie, bowtie',
+ 458: 'brass, memorial tablet, plaque',
+ 459: 'brassiere, bra, bandeau',
+ 460: 'breakwater, groin, groyne, mole, bulwark, seawall, jetty',
+ 461: 'breastplate, aegis, egis',
+ 462: 'broom',
+ 463: 'bucket, pail',
+ 464: 'buckle',
+ 465: 'bulletproof vest',
+ 466: 'bullet train, bullet',
+ 467: 'butcher shop, meat market',
+ 468: 'cab, hack, taxi, taxicab',
+ 469: 'caldron, cauldron',
+ 470: 'candle, taper, wax light',
+ 471: 'cannon',
+ 472: 'canoe',
+ 473: 'can opener, tin opener',
+ 474: 'cardigan',
+ 475: 'car mirror',
+ 476: 'carousel, carrousel, merry-go-round, roundabout, whirligig',
+ 477: "carpenter's kit, tool kit",
+ 478: 'carton',
+ 479: 'car wheel',
+ 480: 'cash machine, cash dispenser, automated teller machine, automatic teller machine, automated teller, automatic teller, ATM',
+ 481: 'cassette',
+ 482: 'cassette player',
+ 483: 'castle',
+ 484: 'catamaran',
+ 485: 'CD player',
+ 486: 'cello, violoncello',
+ 487: 'cellular telephone, cellular phone, cellphone, cell, mobile phone',
+ 488: 'chain',
+ 489: 'chainlink fence',
+ 490: 'chain mail, ring mail, mail, chain armor, chain armour, ring armor, ring armour',
+ 491: 'chain saw, chainsaw',
+ 492: 'chest',
+ 493: 'chiffonier, commode',
+ 494: 'chime, bell, gong',
+ 495: 'china cabinet, china closet',
+ 496: 'Christmas stocking',
+ 497: 'church, church building',
+ 498: 'cinema, movie theater, movie theatre, movie house, picture palace',
+ 499: 'cleaver, meat cleaver, chopper',
+ 500: 'cliff dwelling',
+ 501: 'cloak',
+ 502: 'clog, geta, patten, sabot',
+ 503: 'cocktail shaker',
+ 504: 'coffee mug',
+ 505: 'coffeepot',
+ 506: 'coil, spiral, volute, whorl, helix',
+ 507: 'combination lock',
+ 508: 'computer keyboard, keypad',
+ 509: 'confectionery, confectionary, candy store',
+ 510: 'container ship, containership, container vessel',
+ 511: 'convertible',
+ 512: 'corkscrew, bottle screw',
+ 513: 'cornet, horn, trumpet, trump',
+ 514: 'cowboy boot',
+ 515: 'cowboy hat, ten-gallon hat',
+ 516: 'cradle',
+ 517: 'crane',
+ 518: 'crash helmet',
+ 519: 'crate',
+ 520: 'crib, cot',
+ 521: 'Crock Pot',
+ 522: 'croquet ball',
+ 523: 'crutch',
+ 524: 'cuirass',
+ 525: 'dam, dike, dyke',
+ 526: 'desk',
+ 527: 'desktop computer',
+ 528: 'dial telephone, dial phone',
+ 529: 'diaper, nappy, napkin',
+ 530: 'digital clock',
+ 531: 'digital watch',
+ 532: 'dining table, board',
+ 533: 'dishrag, dishcloth',
+ 534: 'dishwasher, dish washer, dishwashing machine',
+ 535: 'disk brake, disc brake',
+ 536: 'dock, dockage, docking facility',
+ 537: 'dogsled, dog sled, dog sleigh',
+ 538: 'dome',
+ 539: 'doormat, welcome mat',
+ 540: 'drilling platform, offshore rig',
+ 541: 'drum, membranophone, tympan',
+ 542: 'drumstick',
+ 543: 'dumbbell',
+ 544: 'Dutch oven',
+ 545: 'electric fan, blower',
+ 546: 'electric guitar',
+ 547: 'electric locomotive',
+ 548: 'entertainment center',
+ 549: 'envelope',
+ 550: 'espresso maker',
+ 551: 'face powder',
+ 552: 'feather boa, boa',
+ 553: 'file, file cabinet, filing cabinet',
+ 554: 'fireboat',
+ 555: 'fire engine, fire truck',
+ 556: 'fire screen, fireguard',
+ 557: 'flagpole, flagstaff',
+ 558: 'flute, transverse flute',
+ 559: 'folding chair',
+ 560: 'football helmet',
+ 561: 'forklift',
+ 562: 'fountain',
+ 563: 'fountain pen',
+ 564: 'four-poster',
+ 565: 'freight car',
+ 566: 'French horn, horn',
+ 567: 'frying pan, frypan, skillet',
+ 568: 'fur coat',
+ 569: 'garbage truck, dustcart',
+ 570: 'gasmask, respirator, gas helmet',
+ 571: 'gas pump, gasoline pump, petrol pump, island dispenser',
+ 572: 'goblet',
+ 573: 'go-kart',
+ 574: 'golf ball',
+ 575: 'golfcart, golf cart',
+ 576: 'gondola',
+ 577: 'gong, tam-tam',
+ 578: 'gown',
+ 579: 'grand piano, grand',
+ 580: 'greenhouse, nursery, glasshouse',
+ 581: 'grille, radiator grille',
+ 582: 'grocery store, grocery, food market, market',
+ 583: 'guillotine',
+ 584: 'hair slide',
+ 585: 'hair spray',
+ 586: 'half track',
+ 587: 'hammer',
+ 588: 'hamper',
+ 589: 'hand blower, blow dryer, blow drier, hair dryer, hair drier',
+ 590: 'hand-held computer, hand-held microcomputer',
+ 591: 'handkerchief, hankie, hanky, hankey',
+ 592: 'hard disc, hard disk, fixed disk',
+ 593: 'harmonica, mouth organ, harp, mouth harp',
+ 594: 'harp',
+ 595: 'harvester, reaper',
+ 596: 'hatchet',
+ 597: 'holster',
+ 598: 'home theater, home theatre',
+ 599: 'honeycomb',
+ 600: 'hook, claw',
+ 601: 'hoopskirt, crinoline',
+ 602: 'horizontal bar, high bar',
+ 603: 'horse cart, horse-cart',
+ 604: 'hourglass',
+ 605: 'iPod',
+ 606: 'iron, smoothing iron',
+ 607: "jack-o'-lantern",
+ 608: 'jean, blue jean, denim',
+ 609: 'jeep, landrover',
+ 610: 'jersey, T-shirt, tee shirt',
+ 611: 'jigsaw puzzle',
+ 612: 'jinrikisha, ricksha, rickshaw',
+ 613: 'joystick',
+ 614: 'kimono',
+ 615: 'knee pad',
+ 616: 'knot',
+ 617: 'lab coat, laboratory coat',
+ 618: 'ladle',
+ 619: 'lampshade, lamp shade',
+ 620: 'laptop, laptop computer',
+ 621: 'lawn mower, mower',
+ 622: 'lens cap, lens cover',
+ 623: 'letter opener, paper knife, paperknife',
+ 624: 'library',
+ 625: 'lifeboat',
+ 626: 'lighter, light, igniter, ignitor',
+ 627: 'limousine, limo',
+ 628: 'liner, ocean liner',
+ 629: 'lipstick, lip rouge',
+ 630: 'Loafer',
+ 631: 'lotion',
+ 632: 'loudspeaker, speaker, speaker unit, loudspeaker system, speaker system',
+ 633: "loupe, jeweler's loupe",
+ 634: 'lumbermill, sawmill',
+ 635: 'magnetic compass',
+ 636: 'mailbag, postbag',
+ 637: 'mailbox, letter box',
+ 638: 'maillot',
+ 639: 'maillot, tank suit',
+ 640: 'manhole cover',
+ 641: 'maraca',
+ 642: 'marimba, xylophone',
+ 643: 'mask',
+ 644: 'matchstick',
+ 645: 'maypole',
+ 646: 'maze, labyrinth',
+ 647: 'measuring cup',
+ 648: 'medicine chest, medicine cabinet',
+ 649: 'megalith, megalithic structure',
+ 650: 'microphone, mike',
+ 651: 'microwave, microwave oven',
+ 652: 'military uniform',
+ 653: 'milk can',
+ 654: 'minibus',
+ 655: 'miniskirt, mini',
+ 656: 'minivan',
+ 657: 'missile',
+ 658: 'mitten',
+ 659: 'mixing bowl',
+ 660: 'mobile home, manufactured home',
+ 661: 'Model T',
+ 662: 'modem',
+ 663: 'monastery',
+ 664: 'monitor',
+ 665: 'moped',
+ 666: 'mortar',
+ 667: 'mortarboard',
+ 668: 'mosque',
+ 669: 'mosquito net',
+ 670: 'motor scooter, scooter',
+ 671: 'mountain bike, all-terrain bike, off-roader',
+ 672: 'mountain tent',
+ 673: 'mouse, computer mouse',
+ 674: 'mousetrap',
+ 675: 'moving van',
+ 676: 'muzzle',
+ 677: 'nail',
+ 678: 'neck brace',
+ 679: 'necklace',
+ 680: 'nipple',
+ 681: 'notebook, notebook computer',
+ 682: 'obelisk',
+ 683: 'oboe, hautboy, hautbois',
+ 684: 'ocarina, sweet potato',
+ 685: 'odometer, hodometer, mileometer, milometer',
+ 686: 'oil filter',
+ 687: 'organ, pipe organ',
+ 688: 'oscilloscope, scope, cathode-ray oscilloscope, CRO',
+ 689: 'overskirt',
+ 690: 'oxcart',
+ 691: 'oxygen mask',
+ 692: 'packet',
+ 693: 'paddle, boat paddle',
+ 694: 'paddlewheel, paddle wheel',
+ 695: 'padlock',
+ 696: 'paintbrush',
+ 697: "pajama, pyjama, pj's, jammies",
+ 698: 'palace',
+ 699: 'panpipe, pandean pipe, syrinx',
+ 700: 'paper towel',
+ 701: 'parachute, chute',
+ 702: 'parallel bars, bars',
+ 703: 'park bench',
+ 704: 'parking meter',
+ 705: 'passenger car, coach, carriage',
+ 706: 'patio, terrace',
+ 707: 'pay-phone, pay-station',
+ 708: 'pedestal, plinth, footstall',
+ 709: 'pencil box, pencil case',
+ 710: 'pencil sharpener',
+ 711: 'perfume, essence',
+ 712: 'Petri dish',
+ 713: 'photocopier',
+ 714: 'pick, plectrum, plectron',
+ 715: 'pickelhaube',
+ 716: 'picket fence, paling',
+ 717: 'pickup, pickup truck',
+ 718: 'pier',
+ 719: 'piggy bank, penny bank',
+ 720: 'pill bottle',
+ 721: 'pillow',
+ 722: 'ping-pong ball',
+ 723: 'pinwheel',
+ 724: 'pirate, pirate ship',
+ 725: 'pitcher, ewer',
+ 726: "plane, carpenter's plane, woodworking plane",
+ 727: 'planetarium',
+ 728: 'plastic bag',
+ 729: 'plate rack',
+ 730: 'plow, plough',
+ 731: "plunger, plumber's helper",
+ 732: 'Polaroid camera, Polaroid Land camera',
+ 733: 'pole',
+ 734: 'police van, police wagon, paddy wagon, patrol wagon, wagon, black Maria',
+ 735: 'poncho',
+ 736: 'pool table, billiard table, snooker table',
+ 737: 'pop bottle, soda bottle',
+ 738: 'pot, flowerpot',
+ 739: "potter's wheel",
+ 740: 'power drill',
+ 741: 'prayer rug, prayer mat',
+ 742: 'printer',
+ 743: 'prison, prison house',
+ 744: 'projectile, missile',
+ 745: 'projector',
+ 746: 'puck, hockey puck',
+ 747: 'punching bag, punch bag, punching ball, punchball',
+ 748: 'purse',
+ 749: 'quill, quill pen',
+ 750: 'quilt, comforter, comfort, puff',
+ 751: 'racer, race car, racing car',
+ 752: 'racket, racquet',
+ 753: 'radiator',
+ 754: 'radio, wireless',
+ 755: 'radio telescope, radio reflector',
+ 756: 'rain barrel',
+ 757: 'recreational vehicle, RV, R.V.',
+ 758: 'reel',
+ 759: 'reflex camera',
+ 760: 'refrigerator, icebox',
+ 761: 'remote control, remote',
+ 762: 'restaurant, eating house, eating place, eatery',
+ 763: 'revolver, six-gun, six-shooter',
+ 764: 'rifle',
+ 765: 'rocking chair, rocker',
+ 766: 'rotisserie',
+ 767: 'rubber eraser, rubber, pencil eraser',
+ 768: 'rugby ball',
+ 769: 'rule, ruler',
+ 770: 'running shoe',
+ 771: 'safe',
+ 772: 'safety pin',
+ 773: 'saltshaker, salt shaker',
+ 774: 'sandal',
+ 775: 'sarong',
+ 776: 'sax, saxophone',
+ 777: 'scabbard',
+ 778: 'scale, weighing machine',
+ 779: 'school bus',
+ 780: 'schooner',
+ 781: 'scoreboard',
+ 782: 'screen, CRT screen',
+ 783: 'screw',
+ 784: 'screwdriver',
+ 785: 'seat belt, seatbelt',
+ 786: 'sewing machine',
+ 787: 'shield, buckler',
+ 788: 'shoe shop, shoe-shop, shoe store',
+ 789: 'shoji',
+ 790: 'shopping basket',
+ 791: 'shopping cart',
+ 792: 'shovel',
+ 793: 'shower cap',
+ 794: 'shower curtain',
+ 795: 'ski',
+ 796: 'ski mask',
+ 797: 'sleeping bag',
+ 798: 'slide rule, slipstick',
+ 799: 'sliding door',
+ 800: 'slot, one-armed bandit',
+ 801: 'snorkel',
+ 802: 'snowmobile',
+ 803: 'snowplow, snowplough',
+ 804: 'soap dispenser',
+ 805: 'soccer ball',
+ 806: 'sock',
+ 807: 'solar dish, solar collector, solar furnace',
+ 808: 'sombrero',
+ 809: 'soup bowl',
+ 810: 'space bar',
+ 811: 'space heater',
+ 812: 'space shuttle',
+ 813: 'spatula',
+ 814: 'speedboat',
+ 815: "spider web, spider's web",
+ 816: 'spindle',
+ 817: 'sports car, sport car',
+ 818: 'spotlight, spot',
+ 819: 'stage',
+ 820: 'steam locomotive',
+ 821: 'steel arch bridge',
+ 822: 'steel drum',
+ 823: 'stethoscope',
+ 824: 'stole',
+ 825: 'stone wall',
+ 826: 'stopwatch, stop watch',
+ 827: 'stove',
+ 828: 'strainer',
+ 829: 'streetcar, tram, tramcar, trolley, trolley car',
+ 830: 'stretcher',
+ 831: 'studio couch, day bed',
+ 832: 'stupa, tope',
+ 833: 'submarine, pigboat, sub, U-boat',
+ 834: 'suit, suit of clothes',
+ 835: 'sundial',
+ 836: 'sunglass',
+ 837: 'sunglasses, dark glasses, shades',
+ 838: 'sunscreen, sunblock, sun blocker',
+ 839: 'suspension bridge',
+ 840: 'swab, swob, mop',
+ 841: 'sweatshirt',
+ 842: 'swimming trunks, bathing trunks',
+ 843: 'swing',
+ 844: 'switch, electric switch, electrical switch',
+ 845: 'syringe',
+ 846: 'table lamp',
+ 847: 'tank, army tank, armored combat vehicle, armoured combat vehicle',
+ 848: 'tape player',
+ 849: 'teapot',
+ 850: 'teddy, teddy bear',
+ 851: 'television, television system',
+ 852: 'tennis ball',
+ 853: 'thatch, thatched roof',
+ 854: 'theater curtain, theatre curtain',
+ 855: 'thimble',
+ 856: 'thresher, thrasher, threshing machine',
+ 857: 'throne',
+ 858: 'tile roof',
+ 859: 'toaster',
+ 860: 'tobacco shop, tobacconist shop, tobacconist',
+ 861: 'toilet seat',
+ 862: 'torch',
+ 863: 'totem pole',
+ 864: 'tow truck, tow car, wrecker',
+ 865: 'toyshop',
+ 866: 'tractor',
+ 867: 'trailer truck, tractor trailer, trucking rig, rig, articulated lorry, semi',
+ 868: 'tray',
+ 869: 'trench coat',
+ 870: 'tricycle, trike, velocipede',
+ 871: 'trimaran',
+ 872: 'tripod',
+ 873: 'triumphal arch',
+ 874: 'trolleybus, trolley coach, trackless trolley',
+ 875: 'trombone',
+ 876: 'tub, vat',
+ 877: 'turnstile',
+ 878: 'typewriter keyboard',
+ 879: 'umbrella',
+ 880: 'unicycle, monocycle',
+ 881: 'upright, upright piano',
+ 882: 'vacuum, vacuum cleaner',
+ 883: 'vase',
+ 884: 'vault',
+ 885: 'velvet',
+ 886: 'vending machine',
+ 887: 'vestment',
+ 888: 'viaduct',
+ 889: 'violin, fiddle',
+ 890: 'volleyball',
+ 891: 'waffle iron',
+ 892: 'wall clock',
+ 893: 'wallet, billfold, notecase, pocketbook',
+ 894: 'wardrobe, closet, press',
+ 895: 'warplane, military plane',
+ 896: 'washbasin, handbasin, washbowl, lavabo, wash-hand basin',
+ 897: 'washer, automatic washer, washing machine',
+ 898: 'water bottle',
+ 899: 'water jug',
+ 900: 'water tower',
+ 901: 'whiskey jug',
+ 902: 'whistle',
+ 903: 'wig',
+ 904: 'window screen',
+ 905: 'window shade',
+ 906: 'Windsor tie',
+ 907: 'wine bottle',
+ 908: 'wing',
+ 909: 'wok',
+ 910: 'wooden spoon',
+ 911: 'wool, woolen, woollen',
+ 912: 'worm fence, snake fence, snake-rail fence, Virginia fence',
+ 913: 'wreck',
+ 914: 'yawl',
+ 915: 'yurt',
+ 916: 'web site, website, internet site, site',
+ 917: 'comic book',
+ 918: 'crossword puzzle, crossword',
+ 919: 'street sign',
+ 920: 'traffic light, traffic signal, stoplight',
+ 921: 'book jacket, dust cover, dust jacket, dust wrapper',
+ 922: 'menu',
+ 923: 'plate',
+ 924: 'guacamole',
+ 925: 'consomme',
+ 926: 'hot pot, hotpot',
+ 927: 'trifle',
+ 928: 'ice cream, icecream',
+ 929: 'ice lolly, lolly, lollipop, popsicle',
+ 930: 'French loaf',
+ 931: 'bagel, beigel',
+ 932: 'pretzel',
+ 933: 'cheeseburger',
+ 934: 'hotdog, hot dog, red hot',
+ 935: 'mashed potato',
+ 936: 'head cabbage',
+ 937: 'broccoli',
+ 938: 'cauliflower',
+ 939: 'zucchini, courgette',
+ 940: 'spaghetti squash',
+ 941: 'acorn squash',
+ 942: 'butternut squash',
+ 943: 'cucumber, cuke',
+ 944: 'artichoke, globe artichoke',
+ 945: 'bell pepper',
+ 946: 'cardoon',
+ 947: 'mushroom',
+ 948: 'Granny Smith',
+ 949: 'strawberry',
+ 950: 'orange',
+ 951: 'lemon',
+ 952: 'fig',
+ 953: 'pineapple, ananas',
+ 954: 'banana',
+ 955: 'jackfruit, jak, jack',
+ 956: 'custard apple',
+ 957: 'pomegranate',
+ 958: 'hay',
+ 959: 'carbonara',
+ 960: 'chocolate sauce, chocolate syrup',
+ 961: 'dough',
+ 962: 'meat loaf, meatloaf',
+ 963: 'pizza, pizza pie',
+ 964: 'potpie',
+ 965: 'burrito',
+ 966: 'red wine',
+ 967: 'espresso',
+ 968: 'cup',
+ 969: 'eggnog',
+ 970: 'alp',
+ 971: 'bubble',
+ 972: 'cliff, drop, drop-off',
+ 973: 'coral reef',
+ 974: 'geyser',
+ 975: 'lakeside, lakeshore',
+ 976: 'promontory, headland, head, foreland',
+ 977: 'sandbar, sand bar',
+ 978: 'seashore, coast, seacoast, sea-coast',
+ 979: 'valley, vale',
+ 980: 'volcano',
+ 981: 'ballplayer, baseball player',
+ 982: 'groom, bridegroom',
+ 983: 'scuba diver',
+ 984: 'rapeseed',
+ 985: 'daisy',
+ 986: "yellow lady's slipper, yellow lady-slipper, Cypripedium calceolus, Cypripedium parviflorum",
+ 987: 'corn',
+ 988: 'acorn',
+ 989: 'hip, rose hip, rosehip',
+ 990: 'buckeye, horse chestnut, conker',
+ 991: 'coral fungus',
+ 992: 'agaric',
+ 993: 'gyromitra',
+ 994: 'stinkhorn, carrion fungus',
+ 995: 'earthstar',
+ 996: 'hen-of-the-woods, hen of the woods, Polyporus frondosus, Grifola frondosa',
+ 997: 'bolete',
+ 998: 'ear, spike, capitulum',
+ 999: 'toilet tissue, toilet paper, bathroom tissue'}
\ No newline at end of file
diff --git a/build/lib/gradio/inputs.py b/build/lib/gradio/inputs.py
index 02a3e7c6eb..415f720bd4 100644
--- a/build/lib/gradio/inputs.py
+++ b/build/lib/gradio/inputs.py
@@ -1,9 +1,15 @@
+"""
+This module defines various classes that can serve as the `input` to an interface. Each class must inherit from
+`AbstractInput`, and each class must define a path to its template. All of the subclasses of `AbstractInput` are
+automatically added to a registry, which allows them to be easily referenced in other parts of the code.
+"""
+
from abc import ABC, abstractmethod
import base64
-from PIL import Image
+from gradio import preprocessing_utils
from io import BytesIO
import numpy as np
-from gradio import preprocessing_utils
+from PIL import Image
class AbstractInput(ABC):
"""
@@ -12,84 +18,115 @@ class AbstractInput(ABC):
"""
def __init__(self, preprocessing_fn=None):
+ """
+ :param preprocessing_fn: an optional preprocessing function that overrides the default
+ """
if preprocessing_fn is not None:
- self._pre_process = preprocessing_fn
+ if not callable(preprocessing_fn):
+ raise ValueError('`preprocessing_fn` must be a callable function')
+ self.preprocess = preprocessing_fn
super().__init__()
@abstractmethod
- def _get_template_path(self):
+ def get_template_path(self):
"""
All interfaces should define a method that returns the path to its template.
"""
pass
@abstractmethod
- def _pre_process(self):
+ def preprocess(self, inp):
"""
- All interfaces should define a method that returns the path to its template.
+ All interfaces should define a default preprocessing method
"""
pass
class Sketchpad(AbstractInput):
+ def __init__(self, preprocessing_fn=None, image_width=28, image_height=28):
+ self.image_width = image_width
+ self.image_height = image_height
+ super().__init__(preprocessing_fn=preprocessing_fn)
- def _get_template_path(self):
+ def get_template_path(self):
return 'templates/sketchpad_input.html'
- def _pre_process(self, imgstring):
+ def preprocess(self, inp):
"""
+ Default preprocessing method for the SketchPad is to convert the sketch to black and white and resize 28x28
"""
- content = imgstring.split(';')[1]
+ content = inp.split(';')[1]
image_encoded = content.split(',')[1]
- body = base64.decodebytes(image_encoded.encode('utf-8'))
im = Image.open(BytesIO(base64.b64decode(image_encoded))).convert('L')
- im = preprocessing_utils.resize_and_crop(im, (28, 28))
- array = np.array(im).flatten().reshape(1, 28, 28, 1)
+ im = preprocessing_utils.resize_and_crop(im, (self.image_width, self.image_height))
+ array = np.array(im).flatten().reshape(1, self.image_width, self.image_height, 1)
return array
class Webcam(AbstractInput):
+ def __init__(self, preprocessing_fn=None, image_width=224, image_height=224, num_channels=3):
+ self.image_width = image_width
+ self.image_height = image_height
+ self.num_channels = num_channels
+ super().__init__(preprocessing_fn=preprocessing_fn)
- def _get_template_path(self):
+ def get_template_path(self):
return 'templates/webcam_input.html'
- def _pre_process(self, imgstring):
+ def preprocess(self, inp):
"""
+ Default preprocessing method for is to convert the picture to black and white and resize to be 48x48
"""
- content = imgstring.split(';')[1]
+ content = inp.split(';')[1]
image_encoded = content.split(',')[1]
- body = base64.decodebytes(image_encoded.encode('utf-8'))
- im = Image.open(BytesIO(base64.b64decode(image_encoded))).convert('L')
- im = preprocessing_utils.resize_and_crop(im, (48, 48))
- array = np.array(im).flatten().reshape(1, 48, 48, 1)
+ im = Image.open(BytesIO(base64.b64decode(image_encoded))).convert('RGB')
+ im = preprocessing_utils.resize_and_crop(im, (self.image_width, self.image_height))
+ array = np.array(im).flatten().reshape(1, self.image_width, self.image_height, self.num_channels)
return array
class Textbox(AbstractInput):
- def _get_template_path(self):
+ def get_template_path(self):
return 'templates/textbox_input.html'
- def _pre_process(self, text):
+ def preprocess(self, inp):
"""
+ By default, no pre-processing is applied to text.
"""
- return text
+ return inp
+
class ImageUpload(AbstractInput):
+ def __init__(self, preprocessing_fn=None, image_width=224, image_height=224, num_channels=3, image_mode='RGB',
+ scale = 1/127.5, shift = -1):
+ self.image_width = image_width
+ self.image_height = image_height
+ self.num_channels = num_channels
+ self.image_mode = image_mode
+ self.scale = scale
+ self.shift = shift
+ super().__init__(preprocessing_fn=preprocessing_fn)
- def _get_template_path(self):
+ def get_template_path(self):
return 'templates/image_upload_input.html'
- def _pre_process(self, imgstring):
+ def preprocess(self, inp):
"""
+ Default preprocessing method for is to convert the picture to black and white and resize to be 48x48
"""
- content = imgstring.split(';')[1]
+ content = inp.split(';')[1]
image_encoded = content.split(',')[1]
- body = base64.decodebytes(image_encoded.encode('utf-8'))
- im = Image.open(BytesIO(base64.b64decode(image_encoded))).convert('L')
- im = preprocessing_utils.resize_and_crop(im, (48, 48))
- array = np.array(im).flatten().reshape(1, 48, 48, 1)
+ im = Image.open(BytesIO(base64.b64decode(image_encoded))).convert(self.image_mode)
+ im = preprocessing_utils.resize_and_crop(im, (self.image_width, self.image_height))
+ im = np.array(im).flatten()
+ im = im * self.scale + self.shift
+ if self.num_channels is None:
+ array = im.reshape(1, self.image_width, self.image_height)
+ else:
+ array = im.reshape(1, self.image_width, self.image_height, self.num_channels)
return array
+# Automatically adds all subclasses of AbstractInput into a dictionary (keyed by class name) for easy referencing.
registry = {cls.__name__.lower(): cls for cls in AbstractInput.__subclasses__()}
diff --git a/build/lib/gradio/interface.py b/build/lib/gradio/interface.py
index 91360dcc24..366cfb83b1 100644
--- a/build/lib/gradio/interface.py
+++ b/build/lib/gradio/interface.py
@@ -1,14 +1,15 @@
+'''
+This is the core file in the `gradio` package, and defines the Interface class, including methods for constructing the
+interface using the input and output types.
+'''
+
import asyncio
import websockets
import nest_asyncio
import webbrowser
-import pkg_resources
-from bs4 import BeautifulSoup
-from gradio import inputs
-from gradio import outputs
+import gradio.inputs
+import gradio.outputs
from gradio import networking
-import os
-import shutil
import tempfile
nest_asyncio.apply()
@@ -17,46 +18,53 @@ LOCALHOST_IP = '127.0.0.1'
INITIAL_WEBSOCKET_PORT = 9200
TRY_NUM_PORTS = 100
-BASE_TEMPLATE = pkg_resources.resource_filename('gradio', 'templates/base_template.html')
-JS_PATH_LIB = pkg_resources.resource_filename('gradio', 'js/')
-CSS_PATH_LIB = pkg_resources.resource_filename('gradio', 'css/')
-JS_PATH_TEMP = 'js/'
-CSS_PATH_TEMP = 'css/'
-TEMPLATE_TEMP = 'interface.html'
-BASE_JS_FILE = 'js/all-io.js'
-
-class Interface():
+class Interface:
"""
+ The Interface class represents a general input/output interface for a machine learning model. During construction,
+ the appropriate inputs and outputs
"""
# Dictionary in which each key is a valid `model_type` argument to constructor, and the value being the description.
VALID_MODEL_TYPES = {'sklearn': 'sklearn model', 'keras': 'keras model', 'function': 'python function'}
- def __init__(self, input, output, model, model_type=None, preprocessing_fn=None, postprocessing_fn=None):
+ def __init__(self, inputs, outputs, model, model_type=None, preprocessing_fns=None, postprocessing_fns=None,
+ verbose=True):
"""
- :param model_type: what kind of trained model, can be 'keras' or 'sklearn'.
+ :param inputs: a string or `AbstractInput` representing the input interface.
+ :param outputs: a string or `AbstractOutput` representing the output interface.
:param model_obj: the model object, such as a sklearn classifier or keras model.
- :param model_params: additional model parameters.
+ :param model_type: what kind of trained model, can be 'keras' or 'sklearn' or 'function'. Inferred if not
+ provided.
+ :param preprocessing_fns: an optional function that overrides the preprocessing function of the input interface.
+ :param postprocessing_fns: an optional function that overrides the postprocessing fn of the output interface.
"""
- self.input_interface = inputs.registry[input](preprocessing_fn)
- self.output_interface = outputs.registry[output](postprocessing_fn)
+ if isinstance(inputs, str):
+ self.input_interface = gradio.inputs.registry[inputs.lower()](preprocessing_fns)
+ elif isinstance(inputs, gradio.inputs.AbstractInput):
+ self.input_interface = inputs
+ else:
+ raise ValueError('Input interface must be of type `str` or `AbstractInput`')
+ if isinstance(outputs, str):
+ self.output_interface = gradio.outputs.registry[outputs.lower()](postprocessing_fns)
+ elif isinstance(outputs, gradio.outputs.AbstractOutput):
+ self.output_interface = outputs
+ else:
+ raise ValueError('Output interface must be of type `str` or `AbstractOutput`')
self.model_obj = model
if model_type is None:
model_type = self._infer_model_type(model)
- if model_type is None:
- raise ValueError("model_type could not be inferred, please specify parameter `model_type`")
- else:
+ if verbose:
print("Model type not explicitly identified, inferred to be: {}".format(
- self.VALID_MODEL_TYPES[model_type]))
+ self.VALID_MODEL_TYPES[model_type]))
elif not(model_type.lower() in self.VALID_MODEL_TYPES):
ValueError('model_type must be one of: {}'.format(self.VALID_MODEL_TYPES))
self.model_type = model_type
+ self.verbose = verbose
- def _infer_model_type(self, model):
- if callable(model):
- return 'function'
-
+ @staticmethod
+ def _infer_model_type(model):
+ """ Helper method that attempts to identify the type of trained ML model."""
try:
import sklearn
if isinstance(model, sklearn.base.BaseEstimator):
@@ -78,124 +86,100 @@ class Interface():
except ImportError:
pass
- return None
+ if callable(model):
+ return 'function'
- def _build_template(self, temp_dir):
- input_template_path = pkg_resources.resource_filename(
- 'gradio', self.input_interface._get_template_path())
- output_template_path = pkg_resources.resource_filename(
- 'gradio', self.output_interface._get_template_path())
- input_page = open(input_template_path)
- output_page = open(output_template_path)
- input_soup = BeautifulSoup(input_page.read(), features="html.parser")
- output_soup = BeautifulSoup(output_page.read(), features="html.parser")
-
- all_io_page = open(BASE_TEMPLATE)
- all_io_soup = BeautifulSoup(all_io_page.read(), features="html.parser")
- input_tag = all_io_soup.find("div", {"id": "input"})
- output_tag = all_io_soup.find("div", {"id": "output"})
-
- input_tag.replace_with(input_soup)
- output_tag.replace_with(output_soup)
-
- f = open(os.path.join(temp_dir, TEMPLATE_TEMP), "w")
- f.write(str(all_io_soup.prettify))
-
- self._copy_files(JS_PATH_LIB, os.path.join(temp_dir, JS_PATH_TEMP))
- self._copy_files(CSS_PATH_LIB, os.path.join(temp_dir, CSS_PATH_TEMP))
- return
-
- def _copy_files(self, src_dir, dest_dir):
- if not os.path.exists(dest_dir):
- os.makedirs(dest_dir)
- src_files = os.listdir(src_dir)
- for file_name in src_files:
- full_file_name = os.path.join(src_dir, file_name)
- if os.path.isfile(full_file_name):
- shutil.copy(full_file_name, dest_dir)
-
- def _set_socket_url_in_js(self, temp_dir, socket_url):
- with open(os.path.join(temp_dir, BASE_JS_FILE)) as fin:
- lines = fin.readlines()
- lines[0] = 'var NGROK_URL = "{}"\n'.format(socket_url.replace('http', 'ws'))
-
- with open(os.path.join(temp_dir, BASE_JS_FILE), 'w') as fout:
- for line in lines:
- fout.write(line)
-
- def _set_socket_port_in_js(self, temp_dir, socket_port):
- with open(os.path.join(temp_dir, BASE_JS_FILE)) as fin:
- lines = fin.readlines()
- lines[1] = 'var SOCKET_PORT = {}\n'.format(socket_port)
-
- with open(os.path.join(temp_dir, BASE_JS_FILE), 'w') as fout:
- for line in lines:
- fout.write(line)
-
- def predict(self, array):
- if self.model_type=='sklearn':
- return self.model_obj.predict(array)
- elif self.model_type=='keras':
- return self.model_obj.predict(array)
- elif self.model_type=='function':
- return self.model_obj(array)
- else:
- ValueError('model_type must be one of: {}'.format(self.VALID_MODEL_TYPES))
+ raise ValueError("model_type could not be inferred, please specify parameter `model_type`")
async def communicate(self, websocket, path):
"""
- Method that defines how this interface communicates with the websocket.
- :param websocket: a Websocket object used to communicate with the interface frontend
- :param path: ignored
+ Method that defines how this interface should communicates with the websocket. (1) When an input is received by
+ the websocket, it is passed into the input interface and preprocssed. (2) Then the model is called to make a
+ prediction. (3) Finally, the prediction is postprocessed to get something to be displayed by the output.
+ :param websocket: a Websocket server used to communicate with the interface frontend
+ :param path: not used, but required for compliance with websocket library
"""
while True:
try:
msg = await websocket.recv()
- processed_input = self.input_interface._pre_process(msg)
+ processed_input = self.input_interface.preprocess(msg)
prediction = self.predict(processed_input)
- processed_output = self.output_interface._post_process(prediction)
+ processed_output = self.output_interface.postprocess(prediction)
await websocket.send(str(processed_output))
except websockets.exceptions.ConnectionClosed:
pass
+ # except Exception as e:
+ # print(e)
- def launch(self, share_link=False, verbose=True):
+ def predict(self, preprocessed_input):
"""
- Standard method shared by interfaces that launches a websocket at a specified IP address.
+ Method that calls the relevant method of the model object to make a prediction.
+ :param preprocessed_input: the preprocessed input returned by the input interface
+ """
+ if self.model_type=='sklearn':
+ return self.model_obj.predict(preprocessed_input)
+ elif self.model_type=='keras':
+ return self.model_obj.predict(preprocessed_input)
+ elif self.model_type=='function':
+ return self.model_obj(preprocessed_input)
+ else:
+ ValueError('model_type must be one of: {}'.format(self.VALID_MODEL_TYPES))
+
+ def launch(self, inline=None, browser=None, share=False):
+ """
+ Standard method shared by interfaces that creates the interface and sets up a websocket to communicate with it.
+ :param share: boolean. If True, then a share link is generated using ngrok is displayed to the user.
"""
output_directory = tempfile.mkdtemp()
+
+ # Set up a port to serve the directory containing the static files with interface.
server_port = networking.start_simple_server(output_directory)
path_to_server = 'http://localhost:{}/'.format(server_port)
- self._build_template(output_directory)
+ networking.build_template(output_directory, self.input_interface, self.output_interface)
- ports_in_use = networking.get_ports_in_use(INITIAL_WEBSOCKET_PORT, INITIAL_WEBSOCKET_PORT + TRY_NUM_PORTS)
- for i in range(TRY_NUM_PORTS):
- if not ((INITIAL_WEBSOCKET_PORT + i) in ports_in_use):
- break
- else:
- raise OSError("All ports from {} to {} are in use. Please close a port.".format(
- INITIAL_WEBSOCKET_PORT, INITIAL_WEBSOCKET_PORT + TRY_NUM_PORTS))
-
- start_server = websockets.serve(self.communicate, LOCALHOST_IP, INITIAL_WEBSOCKET_PORT + i)
- self._set_socket_port_in_js(output_directory, INITIAL_WEBSOCKET_PORT + i)
- if verbose:
+ # Set up a port to serve a websocket that sets up the communication between the front-end and model.
+ websocket_port = networking.get_first_available_port(
+ INITIAL_WEBSOCKET_PORT, INITIAL_WEBSOCKET_PORT + TRY_NUM_PORTS)
+ start_server = websockets.serve(self.communicate, LOCALHOST_IP, websocket_port)
+ networking.set_socket_port_in_js(output_directory, websocket_port) # sets the websocket port in the JS file.
+ if self.verbose:
print("NOTE: Gradio is in beta stage, please report all bugs to: a12d@stanford.edu")
- print("Model available locally at: {}".format(path_to_server + TEMPLATE_TEMP))
+ print("Model is running locally at: {}".format(path_to_server + networking.TEMPLATE_TEMP))
- if share_link:
- networking.kill_processes([4040, 4041])
- site_ngrok_url = networking.setup_ngrok(server_port)
- socket_ngrok_url = networking.setup_ngrok(INITIAL_WEBSOCKET_PORT, api_url=networking.NGROK_TUNNELS_API_URL2)
- self._set_socket_url_in_js(output_directory, socket_ngrok_url)
- if verbose:
- print("Model available publicly for 8 hours at: {}".format(site_ngrok_url + '/' + TEMPLATE_TEMP))
+ if share:
+ site_ngrok_url = networking.setup_ngrok(server_port, websocket_port, output_directory)
+ if self.verbose:
+ print("Model available publicly for 8 hours at: {}".format(
+ site_ngrok_url + '/' + networking.TEMPLATE_TEMP))
else:
- if verbose:
- print("To create a public link, set `share_link=True` in the argument to `launch()`")
+ if self.verbose:
+ print("To create a public link, set `share=True` in the argument to `launch()`")
+ site_ngrok_url = None
+ # Keep the server running in the background.
asyncio.get_event_loop().run_until_complete(start_server)
try:
asyncio.get_event_loop().run_forever()
except RuntimeError: # Runtime errors are thrown in jupyter notebooks because of async.
pass
- webbrowser.open(path_to_server + TEMPLATE_TEMP)
+ if inline is None:
+ try: # Check if running interactively using ipython.
+ _ = get_ipython()
+ inline = True
+ if browser is None:
+ browser = False
+ except NameError:
+ inline = False
+ if browser is None:
+ browser = True
+ else:
+ if browser is None:
+ browser = False
+ if browser:
+ webbrowser.open(path_to_server + networking.TEMPLATE_TEMP) # Open a browser tab with the interface.
+ if inline:
+ from IPython.display import IFrame
+ display(IFrame(path_to_server + networking.TEMPLATE_TEMP, width=1000, height=500))
+
+ return path_to_server + networking.TEMPLATE_TEMP, site_ngrok_url
\ No newline at end of file
diff --git a/build/lib/gradio/networking.py b/build/lib/gradio/networking.py
index 2ace36072b..7183b57510 100644
--- a/build/lib/gradio/networking.py
+++ b/build/lib/gradio/networking.py
@@ -1,3 +1,7 @@
+'''
+Defines helper methods useful for setting up ports, launching servers, and handling `ngrok`
+'''
+
import subprocess
import requests
import zipfile
@@ -5,21 +9,31 @@ import io
import sys
import os
import socket
-from psutil import process_iter, AccessDenied
+from psutil import process_iter, AccessDenied, NoSuchProcess
from signal import SIGTERM # or SIGKILL
import threading
from http.server import HTTPServer as BaseHTTPServer, SimpleHTTPRequestHandler
import stat
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry
+import pkg_resources
+from bs4 import BeautifulSoup
+from distutils import dir_util
-INITIAL_PORT_VALUE = 7860
-TRY_NUM_PORTS = 100
+INITIAL_PORT_VALUE = 7860 # The http server will try to open on port 7860. If not available, 7861, 7862, etc.
+TRY_NUM_PORTS = 100 # Number of ports to try before giving up and throwing an exception.
LOCALHOST_NAME = 'localhost'
-LOCALHOST_PREFIX = 'localhost:'
NGROK_TUNNELS_API_URL = "http://localhost:4040/api/tunnels" # TODO(this should be captured from output)
NGROK_TUNNELS_API_URL2 = "http://localhost:4041/api/tunnels" # TODO(this should be captured from output)
+
+BASE_TEMPLATE = pkg_resources.resource_filename('gradio', 'templates/base_template.html')
+STATIC_PATH_LIB = pkg_resources.resource_filename('gradio', 'static/')
+STATIC_PATH_TEMP = 'static/'
+TEMPLATE_TEMP = 'interface.html'
+BASE_JS_FILE = 'static/js/all-io.js'
+
+
NGROK_ZIP_URLS = {
"linux": "https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip",
"darwin": "https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-darwin-amd64.zip",
@@ -27,48 +41,83 @@ NGROK_ZIP_URLS = {
}
-def get_ports_in_use(start, stop):
- ports_in_use = []
- for port in range(start, stop):
+def build_template(temp_dir, input_interface, output_interface):
+ """
+ Builds a complete HTML template with supporting JS and CSS files in a given directory.
+ :param temp_dir: string with path to temp directory in which the template should be built
+ :param input_interface: an AbstractInput object which includes is used to get the input template
+ :param output_interface: an AbstractInput object which includes is used to get the input template
+ """
+ input_template_path = pkg_resources.resource_filename('gradio', input_interface.get_template_path())
+ output_template_path = pkg_resources.resource_filename('gradio', output_interface.get_template_path())
+ input_page = open(input_template_path)
+ output_page = open(output_template_path)
+ input_soup = BeautifulSoup(input_page.read(), features="html.parser")
+ output_soup = BeautifulSoup(output_page.read(), features="html.parser")
+
+ all_io_page = open(BASE_TEMPLATE)
+ all_io_soup = BeautifulSoup(all_io_page.read(), features="html.parser")
+ input_tag = all_io_soup.find("div", {"id": "input"})
+ output_tag = all_io_soup.find("div", {"id": "output"})
+
+ input_tag.replace_with(input_soup)
+ output_tag.replace_with(output_soup)
+
+ f = open(os.path.join(temp_dir, TEMPLATE_TEMP), "w")
+ f.write(str(all_io_soup))
+
+ copy_files(STATIC_PATH_LIB, os.path.join(temp_dir, STATIC_PATH_TEMP))
+
+
+def copy_files(src_dir, dest_dir):
+ """
+ Copies all the files from one directory to another
+ :param src_dir: string path to source directory
+ :param dest_dir: string path to destination directory
+ """
+ dir_util.copy_tree(src_dir, dest_dir)
+
+
+#TODO(abidlabs): Handle the http vs. https issue that sometimes happens (a ws cannot be loaded from an https page)
+def set_socket_url_in_js(temp_dir, socket_url):
+ with open(os.path.join(temp_dir, BASE_JS_FILE)) as fin:
+ lines = fin.readlines()
+ lines[0] = 'var NGROK_URL = "{}"\n'.format(socket_url.replace('http', 'ws'))
+
+ with open(os.path.join(temp_dir, BASE_JS_FILE), 'w') as fout:
+ for line in lines:
+ fout.write(line)
+
+
+def set_socket_port_in_js(temp_dir, socket_port):
+ with open(os.path.join(temp_dir, BASE_JS_FILE)) as fin:
+ lines = fin.readlines()
+ lines[1] = 'var SOCKET_PORT = {}\n'.format(socket_port)
+
+ with open(os.path.join(temp_dir, BASE_JS_FILE), 'w') as fout:
+ for line in lines:
+ fout.write(line)
+
+
+def get_first_available_port(initial, final):
+ """
+ Gets the first open port in a specified range of port numbers
+ :param initial: the initial value in the range of port numbers
+ :param final: final (exclusive) value in the range of port numbers, should be greater than `initial`
+ :return:
+ """
+ for port in range(initial, final):
try:
s = socket.socket() # create a socket object
s.bind((LOCALHOST_NAME, port)) # Bind to the port
s.close()
+ return port
except OSError:
- ports_in_use.append(port)
- return ports_in_use
- # ports_in_use = []
- # try:
- # for proc in process_iter():
- # for conns in proc.connections(kind='inet'):
- # ports_in_use.append(conns.laddr.port)
- # except AccessDenied:
- # pass # TODO(abidlabs): somehow find a way to handle this issue?
- # return ports_in_use
+ pass
+ raise OSError("All ports from {} to {} are in use. Please close a port.".format(initial, final))
def serve_files_in_background(port, directory_to_serve=None):
- # class Handler(http.server.SimpleHTTPRequestHandler):
- # def __init__(self, *args, **kwargs):
- # super().__init__(*args, directory=directory_to_serve, **kwargs)
- #
- # server = socketserver.ThreadingTCPServer(('localhost', port), Handler)
- # # Ensures that Ctrl-C cleanly kills all spawned threads
- # server.daemon_threads = True
- # # Quicker rebinding
- # server.allow_reuse_address = True
- #
- # # A custom signal handle to allow us to Ctrl-C out of the process
- # def signal_handler(signal, frame):
- # print('Exiting http server (Ctrl+C pressed)')
- # try:
- # if (server):
- # server.server_close()
- # finally:
- # sys.exit(0)
- #
- # # Install the keyboard interrupt handler
- # signal.signal(signal.SIGINT, signal_handler)
class HTTPHandler(SimpleHTTPRequestHandler):
"""This handler uses server.base_path instead of always using os.getcwd()"""
@@ -101,21 +150,9 @@ def serve_files_in_background(port, directory_to_serve=None):
def start_simple_server(directory_to_serve=None):
- # TODO(abidlabs): increment port number until free port is found
- ports_in_use = get_ports_in_use(start=INITIAL_PORT_VALUE, stop=INITIAL_PORT_VALUE + TRY_NUM_PORTS)
- for i in range(TRY_NUM_PORTS):
- if not((INITIAL_PORT_VALUE + i) in ports_in_use):
- break
- else:
- raise OSError("All ports from {} to {} are in use. Please close a port.".format(
- INITIAL_PORT_VALUE, INITIAL_PORT_VALUE + TRY_NUM_PORTS))
- serve_files_in_background(INITIAL_PORT_VALUE + i, directory_to_serve)
- # if directory_to_serve is None:
- # subprocess.Popen(['python', '-m', 'http.server', str(INITIAL_PORT_VALUE + i)])
- # else:
- # cmd = ' '.join(['python', '-m', 'http.server', '-d', directory_to_serve, str(INITIAL_PORT_VALUE + i)])
- # subprocess.Popen(cmd, shell=True) # Doesn't seem to work if list is passed for some reason.
- return INITIAL_PORT_VALUE + i
+ port = get_first_available_port(INITIAL_PORT_VALUE, INITIAL_PORT_VALUE + TRY_NUM_PORTS)
+ serve_files_in_background(port, directory_to_serve)
+ return port
def download_ngrok():
@@ -133,7 +170,7 @@ def download_ngrok():
os.chmod('ngrok', st.st_mode | stat.S_IEXEC)
-def setup_ngrok(local_port, api_url=NGROK_TUNNELS_API_URL):
+def create_ngrok_tunnel(local_port, api_url):
if not(os.path.isfile('ngrok.exe') or os.path.isfile('ngrok')):
download_ngrok()
if sys.platform == 'win32':
@@ -147,18 +184,26 @@ def setup_ngrok(local_port, api_url=NGROK_TUNNELS_API_URL):
session.mount('https://', adapter)
r = session.get(api_url)
for tunnel in r.json()['tunnels']:
- if LOCALHOST_PREFIX + str(local_port) in tunnel['config']['addr']:
+ if '{}:'.format(LOCALHOST_NAME) + str(local_port) in tunnel['config']['addr']:
return tunnel['public_url']
raise RuntimeError("Not able to retrieve ngrok public URL")
-def kill_processes(process_ids):
+def setup_ngrok(server_port, websocket_port, output_directory):
+ kill_processes([4040, 4041]) #TODO(abidlabs): better way to do this
+ site_ngrok_url = create_ngrok_tunnel(server_port, NGROK_TUNNELS_API_URL)
+ socket_ngrok_url = create_ngrok_tunnel(websocket_port, NGROK_TUNNELS_API_URL2)
+ set_socket_url_in_js(output_directory, socket_ngrok_url)
+ return site_ngrok_url
+
+
+def kill_processes(process_ids): #TODO(abidlabs): remove this, we shouldn't need to kill
for proc in process_iter():
try:
for conns in proc.connections(kind='inet'):
if conns.laddr.port in process_ids:
proc.send_signal(SIGTERM) # or SIGKILL
- except AccessDenied:
+ except (AccessDenied, NoSuchProcess):
pass
diff --git a/build/lib/gradio/outputs.py b/build/lib/gradio/outputs.py
index 9a0e5b6fc0..3223ffb1a5 100644
--- a/build/lib/gradio/outputs.py
+++ b/build/lib/gradio/outputs.py
@@ -1,5 +1,13 @@
+"""
+This module defines various classes that can serve as the `output` to an interface. Each class must inherit from
+`AbstractOutput`, and each class must define a path to its template. All of the subclasses of `AbstractOutput` are
+automatically added to a registry, which allows them to be easily referenced in other parts of the code.
+"""
+
from abc import ABC, abstractmethod
import numpy as np
+import json
+from gradio import imagenet_class_labels
class AbstractOutput(ABC):
"""
@@ -9,52 +17,86 @@ class AbstractOutput(ABC):
def __init__(self, postprocessing_fn=None):
"""
+ :param postprocessing_fn: an optional postprocessing function that overrides the default
"""
if postprocessing_fn is not None:
- self._post_process = postprocessing_fn
+ self.postprocess = postprocessing_fn
super().__init__()
@abstractmethod
- def _get_template_path(self):
+ def get_template_path(self):
"""
All interfaces should define a method that returns the path to its template.
"""
pass
@abstractmethod
- def _post_process(self):
+ def postprocess(self, prediction):
"""
- All interfaces should define a method that returns the path to its template.
+ All interfaces should define a default postprocessing method
"""
pass
-class Class(AbstractOutput):
+class Label(AbstractOutput):
+ LABEL_KEY = 'label'
+ CONFIDENCES_KEY = 'confidences'
+ CONFIDENCE_KEY = 'confidence'
- def _get_template_path(self):
- return 'templates/class_output.html'
+ def __init__(self, postprocessing_fn=None, num_top_classes=3, show_confidences=True, label_names=None,
+ max_label_length=None):
+ self.num_top_classes = num_top_classes
+ self.show_confidences = show_confidences
+ self.label_names = label_names
+ self.max_label_length = max_label_length
+ super().__init__(postprocessing_fn=postprocessing_fn)
- def _post_process(self, prediction):
+ def get_label_name(self, label):
+ if self.label_names is None:
+ name = label
+ elif self.label_names == 'imagenet1000':
+ name = imagenet_class_labels.NAMES1000[label]
+ else: # if list or dictionary
+ name = self.label_names[label]
+ if self.max_label_length is not None:
+ name = name[:self.max_label_length]
+ return name
+
+ def get_template_path(self):
+ return 'templates/label_output.html'
+
+ def postprocess(self, prediction):
"""
"""
+ response = dict()
+ # TODO(abidlabs): check if list, if so convert to numpy array
if isinstance(prediction, np.ndarray):
prediction = prediction.squeeze()
- if prediction.size == 1:
- return prediction
- else:
- return prediction.argmax()
+ if prediction.size == 1: # if it's single value
+ response[Label.LABEL_KEY] = self.get_label_name(np.asscalar(prediction))
+ elif len(prediction.shape) == 1: # if a 1D
+ response[Label.LABEL_KEY] = self.get_label_name(int(prediction.argmax()))
+ if self.show_confidences:
+ response[Label.CONFIDENCES_KEY] = []
+ for i in range(self.num_top_classes):
+ response[Label.CONFIDENCES_KEY].append({
+ Label.LABEL_KEY: self.get_label_name(int(prediction.argmax())),
+ Label.CONFIDENCE_KEY: float(prediction.max()),
+ })
+ prediction[prediction.argmax()] = 0
elif isinstance(prediction, str):
- return prediction
+ response[Label.LABEL_KEY] = prediction
else:
raise ValueError("Unable to post-process model prediction.")
+ return json.dumps(response)
class Textbox(AbstractOutput):
- def _get_template_path(self):
+ def get_template_path(self):
return 'templates/textbox_output.html'
- def _post_process(self, prediction):
+ def postprocess(self, prediction):
"""
"""
return prediction
diff --git a/build/lib/gradio/templates/base_template.html b/build/lib/gradio/templates/base_template.html
new file mode 100644
index 0000000000..a8e29e925f
--- /dev/null
+++ b/build/lib/gradio/templates/base_template.html
@@ -0,0 +1,28 @@
+
+
+
+ Gradio
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/build/lib/gradio/templates/image_upload_input.html b/build/lib/gradio/templates/image_upload_input.html
index f6a2f33b97..ee02413ecb 100644
--- a/build/lib/gradio/templates/image_upload_input.html
+++ b/build/lib/gradio/templates/image_upload_input.html
@@ -1,31 +1,11 @@
-
-
-
Image Upload Input:
-
-
-
Click here
or
drag and drop
an image
-
![]()
-
-
-
-
-
-
-
-
-
-
+
+
+
diff --git a/build/lib/gradio/templates/label_output.html b/build/lib/gradio/templates/label_output.html
new file mode 100644
index 0000000000..f9303439eb
--- /dev/null
+++ b/build/lib/gradio/templates/label_output.html
@@ -0,0 +1,7 @@
+
+
diff --git a/dist/gradio-0.2.1-py3-none-any.whl b/dist/gradio-0.3.1-py3-none-any.whl
similarity index 95%
rename from dist/gradio-0.2.1-py3-none-any.whl
rename to dist/gradio-0.3.1-py3-none-any.whl
index 1bf896e798..fcd096178e 100644
Binary files a/dist/gradio-0.2.1-py3-none-any.whl and b/dist/gradio-0.3.1-py3-none-any.whl differ
diff --git a/dist/gradio-0.3.1.tar.gz b/dist/gradio-0.3.1.tar.gz
new file mode 100644
index 0000000000..2d5ea3c796
Binary files /dev/null and b/dist/gradio-0.3.1.tar.gz differ
diff --git a/gradio.egg-info/PKG-INFO b/gradio.egg-info/PKG-INFO
index 67b60844b1..b51346b024 100644
--- a/gradio.egg-info/PKG-INFO
+++ b/gradio.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.0
Name: gradio
-Version: 0.2.1
+Version: 0.3.1
Summary: Python library for easily interacting with trained machine learning models
Home-page: https://github.com/abidlabs/gradio
Author: Abubakar Abid
diff --git a/gradio.egg-info/SOURCES.txt b/gradio.egg-info/SOURCES.txt
index a9a72989e6..f1b286bf3b 100644
--- a/gradio.egg-info/SOURCES.txt
+++ b/gradio.egg-info/SOURCES.txt
@@ -2,6 +2,7 @@ MANIFEST.in
README.md
setup.py
gradio/__init__.py
+gradio/imagenet_class_labels.py
gradio/inputs.py
gradio/interface.py
gradio/networking.py
@@ -12,50 +13,10 @@ gradio.egg-info/SOURCES.txt
gradio.egg-info/dependency_links.txt
gradio.egg-info/requires.txt
gradio.egg-info/top_level.txt
-gradio/css/.DS_Store
-gradio/css/bootstrap-grid.css
-gradio/css/bootstrap-grid.css.map
-gradio/css/bootstrap-grid.min.css
-gradio/css/bootstrap-grid.min.css.map
-gradio/css/bootstrap-reboot.css
-gradio/css/bootstrap-reboot.css.map
-gradio/css/bootstrap-reboot.min.css
-gradio/css/bootstrap-reboot.min.css.map
-gradio/css/bootstrap.css
-gradio/css/bootstrap.css.map
-gradio/css/bootstrap.min.css
-gradio/css/bootstrap.min.css.map
-gradio/css/draw-a-digit.css
-gradio/css/dropzone.css
-gradio/css/index.css
-gradio/js/all-io.js
-gradio/js/audio-input.js
-gradio/js/bootstrap-notify.min.js
-gradio/js/bootstrap.bundle.js
-gradio/js/bootstrap.bundle.js.map
-gradio/js/bootstrap.bundle.min.js
-gradio/js/bootstrap.bundle.min.js.map
-gradio/js/bootstrap.js
-gradio/js/bootstrap.js.map
-gradio/js/bootstrap.min.js
-gradio/js/bootstrap.min.js.map
-gradio/js/class-output.js
-gradio/js/draw-a-digit.js
-gradio/js/dropzone.js
-gradio/js/emotion-detector.js
-gradio/js/image-upload-input.js
-gradio/js/jquery-3.3.1.min.js
-gradio/js/sketchpad-input.js
-gradio/js/textbox-input.js
-gradio/js/textbox-output.js
-gradio/js/webcam-input.js
-gradio/templates/all_io.html
-gradio/templates/audio_input.html
-gradio/templates/class_output.html
-gradio/templates/draw_a_digit.html
-gradio/templates/emotion_detector.html
+gradio/templates/base_template.html
gradio/templates/image_upload_input.html
-gradio/templates/sketchpad_input.html
-gradio/templates/textbox_input.html
-gradio/templates/textbox_output.html
-gradio/templates/webcam_input.html
\ No newline at end of file
+gradio/templates/label_output.html
+test/test_inputs.py
+test/test_interface.py
+test/test_networking.py
+test/test_outputs.py
\ No newline at end of file
diff --git a/gradio/outputs.py b/gradio/outputs.py
index 281cdb3662..3223ffb1a5 100644
--- a/gradio/outputs.py
+++ b/gradio/outputs.py
@@ -69,7 +69,6 @@ class Label(AbstractOutput):
"""
"""
response = dict()
- print('dddddddddddddddddddd', self.get_label_name(499))
# TODO(abidlabs): check if list, if so convert to numpy array
if isinstance(prediction, np.ndarray):
prediction = prediction.squeeze()
diff --git a/gradio/static/js/class-output.js b/gradio/static/js/class-output.js
index 22babf9ba3..5daba2d036 100644
--- a/gradio/static/js/class-output.js
+++ b/gradio/static/js/class-output.js
@@ -27,19 +27,19 @@ try {
sleep(300).then(() => {
// $(".output_class").text(event.data);
var data = JSON.parse(event.data)
- data = {
- label: "happy",
- confidences : [
- {
- label : "happy",
- confidence: 0.7
- },
- {
- label : "sad",
- confidence: 0.3
- },
- ]
- }
+ // data = {
+ // label: "happy",
+ // confidences : [
+ // {
+ // label : "happy",
+ // confidence: 0.7
+ // },
+ // {
+ // label : "sad",
+ // confidence: 0.3
+ // },
+ // ]
+ // }
$(".output_class").text(data["label"])
$(".confidence_intervals").empty()
if ("confidences" in data) {
diff --git a/gradio/static/js/image-upload-input.js b/gradio/static/js/image-upload-input.js
index 6dec0cdc98..cf9986f015 100644
--- a/gradio/static/js/image-upload-input.js
+++ b/gradio/static/js/image-upload-input.js
@@ -1,4 +1,4 @@
-var cropper;
+// var cropper;
$('body').on('click', ".input_image.drop_mode", function (e) {
$(this).parent().find(".hidden_upload").click();
@@ -17,10 +17,10 @@ function loadPreviewFromFiles(files) {
$(".input_image").removeClass("drop_mode")
var image = $(".input_image img")
image.attr("src", this.result)
- image.cropper({aspectRatio : 1.0});
- if (!cropper) {
- cropper = image.data('cropper');
- }
+ // image.cropper({aspectRatio : 1.0});
+ // if (!cropper) {
+ // cropper = image.data('cropper');
+ // }
}
}
@@ -50,10 +50,10 @@ $('body').on('click', '.submit', function(e) {
})
$('body').on('click', '.clear', function(e) {
- if (cropper) {
- cropper.destroy();
- cropper = null
- }
+ // if (cropper) {
+ // cropper.destroy();
+ // cropper = null
+ // }
$(".input_caption").show()
$(".input_image img").removeAttr("src");
$(".input_image").addClass("drop_mode")
diff --git a/setup.py b/setup.py
index 9b55184831..c9ef587a2a 100644
--- a/setup.py
+++ b/setup.py
@@ -5,7 +5,7 @@ except ImportError:
setup(
name='gradio',
- version='0.2.1',
+ version='0.3.1',
include_package_data=True,
description='Python library for easily interacting with trained machine learning models',
author='Abubakar Abid',