!7 cm UltrafaST > DynWebServee { transient SnippetInstaCache snippetCache; transient S microNewsSnippetID = #1034192; transient S downloadURL = //"https://github.com/stefan-reich/gazelle-22/releases/download/2022-6-10/gazelle.jar"; "https://botcompany.de/jar/1033860?withX30=1&withLibs=1&mainClassForManifest=Starter&name=Gazelle.jar"; Set allowedWebhookClientIPs() { ret asSet(tlftj([[ // TradingView.com 52.89.214.238 34.212.75.30 54.218.53.128 52.32.178.7 // Myself 127.0.0.1 161.97.120.94 ]])); } start { snippetCache = new SnippetInstaCache(microNewsSnippetID); print(cachedSnippetIDs := snippetCache.cachedSnippetIDs()); dm_registerAs gazAiHomePage(); } void cleanMeUp { dispose snippetCache; } @Override O html(IWebRequest req) { try object redirectToHTTPS(req); if (req.uriIs("/favicon.ico")) ret serveFavIcon(gazelleFavIconSnippet()); if (req.uriIsIC("/gazelle.jar")) ret subBot_serveRedirect(downloadURL, "application/octet-stream"); if (req.uriIsIC("/webhook")) { S clientIP = req.clientIP(); if (!contains(allowedWebhookClientIPs(), clientIP)) ret subBot_serve500("Not a registered client IP"); S content = mapGet(req.files(), "postData"); appendLineToFile(javaxDataDir("webhook.log"), jsonEncode(litorderedmap(+clientIP, date := formatLocalDate(), +content))); ret "OK"; } if (req.uriIs("/")) { var newsParas = paragraphs(snippetCache.get(microNewsSnippetID)); new L newsObjects; LS newsItems = map( newsParas, item -> { PairS p = splitAtFirstColon(item); S date = pairA(p), text = pairB(p); newsObjects.add(new NewsItem(date, text)); ret text + " [" + date + "]"; } ); //pnl(+newsItems); addAll(newsItems, targetBlank("https://agi.topicbox.com/groups/agi/T419e8a952205967e", "News post") + " [2022/1/22]", targetBlank("https://agi.topicbox.com/groups/agi/T2dea42566ccf6693", "News post") + " [2022/1/7]", targetBlank("https://agi.topicbox.com/groups/agi/T8ca0db34fc106b16/image-recognizers-should-return-mathematical-proofs", "Image recognizers should return mathematical proofs") + " [2021/9/10]", targetBlank("https://agi.topicbox.com/groups/agi/T2771ec3238f217fa/gazelle-looks-at-its-own-logo-and-paints-it-red", "Gazelle looks at its own logo and paints it red") + " [2021/8/20]" ); new LS headings; headings.add(ahref("https://Gaz.AI", "Gaz.AI")); embedded S heading(S text, S extra default "") { headings.add(text); ret aname(text, h3(hcombine( ahref("#top", himgsnippet(#1103033, style := "height: .65em", align := "absmiddle", title := "Back to top")), text, extra))); } S content = h1("Gazelle 22 - a new image recognizer") + (empty(newsObjects) ? "" : p(hcombine(joinNemptiesWithBR( first(newsObjects).date + ":", first(newsObjects).text), ahref("#News", "[More news]")))) + aname("Screenshots") + heading("Latest Screenshots") + new Screenshot(#1103157, "2022/9/5", nlToBr_trim([[ Gazelle is learning to read. (All characters shown are drawn by Gazelle trying to mimic a screenshot.) Not all that bad already! And it wasn't even trained on Courier. And yes, that fancy artwork could be considered a bug. ]])) + new Screenshot(#1103151, "2022/9/3", "Which shape is similar to a 5?") + new Screenshot(#1103149, "2022/9/3", "Gazelle's cheat sheet for all shapes in the extended latin alphabet") + new Screenshot(#1103138, "2022/6/30", "Working on a compressed image format (and the demo is a beautiful main program too)") + new Screenshot(#1103137, "2022/6/2", targetBlank("https://www.youtube.com/watch?v=PgZwlmF5epU&ab_channel=StefanReich", "Recognizing Toilet Paper [Video]")) + new Screenshot(#1103133, "2022/5/22", "A more evolved data graph") + new Screenshot(#1103132, "2022/5/17", "First data graph") + new Screenshot(#1103131, "2022/5/6", "Finding topological graph mappings") + new Screenshot(#1103128, "2022/4/28", "A nice, straight-forward motion detector") + new Screenshot(/*#1103122*/#1103123, "2022/4/17", "Segmenting an image by covering it with single color tiles
(left: input, right: output scaled up)") + new Screenshot(#1103121, "2022/4/6", "Semi-automatic conversion of left-arrow scripts to Java(X)") + new Screenshot(#1103119, "2022/4/2", "Optimized script compilation time to below 1 ms (displayed value is rounded up!)") + new Screenshot(#1103118, "2022/4/1", "PDF Import (commercial feature)") + new Screenshot(#1103116, "2022/3/30", "Learning fonts!") + new Screenshot(#1103112, "2022/3/26", "Training the computer as a math student... :)") + new Screenshot(#1103111, "2022/3/23", "Finding junctions and line ends in the letter skeletons") + new Screenshot(#1103110, "2022/3/22", "Artifact-free reduction of letters to 1 pixel-wide skeletons!") + new Screenshot(#1103105, "2022/3/17", "Finding a polygon's corners (marked red)") + new Screenshot(#1103099, "2022/3/13", "A 5 point gradient is recognized!") + new Screenshot(#1103097, "2022/3/12", "Rendering some multi-point gradients [gradient detection coming up too]") + new Screenshot(#1103095, "2022/3/11", "Some recognition of... something!? LOL") + new Screenshot(#1103094, "2022/3/10", "Checking in how many fonts (out of 88) a letter is actually different.
Turns out \"e\" has the most versions (83) and \"l\" (lowercase L) has the fewest (76).") + new Screenshot(#1103093, "2022/3/8", "Theoretical number of different images at 3*3 pixels and 3 colors") + new Screenshot(#1103092, "2022/3/8", "Each letter reduced to 3x3 pixels and 3 colors. Can you still tell them apart? (Each letter in the grid is an H, e, l or o.)") + new Screenshot(#1103090, "2022/3/8", "Each letter was padded into a square") + new Screenshot(#1103088, "2022/3/8", "Extracted letter matrix ready for learning") + new Screenshot(#1103087, "2022/3/8", "Segmenter usually finds 5 letters as expected (the word is 'Hello'), but a few fonts still confuse it.") + new Screenshot(#1103086, "2022/3/7", "Project story editor with hyperlinks & auto-run mechanism for user scripts") + new Screenshot(#1103083, "2022/3/7", "Gazelle has split a word into invididual letters.") + new Screenshot(#1103072, "This screenshot shows my cute new scripting language which is very flexible.") + new Screenshot(#1103059, "Here you see Gazelle's preprocessing filters applied to a screen cam.") + heading("Quick start (Windows, Mac, Linux)") + p("1. Install " + targetBlank("https://adoptium.net", "Temurin 17") + " or any recent Java version." + " (Their smaller \"" + targetBlank("https://adoptium.net/releases.html", "JRE") + "\" version is fine too. If you already have Java, just go to step 2.)") + p("2. Save and double-click " + ahref(downloadURL, "Gazelle.jar") + " (it's under 30 MB).") + heading("What it does") + p(joinWithBR( "Gazelle 22 watches your screen and recognizes things.", "It is being developed right now by " + targetBlank("https://BotCompany.de", "Stefan Reich") + " at " + ahref("https://gazelle.rocks", "Gaz.AI") + ". " + ahref("mailto:info@botcompany.de","Contact.") + " " /*+ ahref("https://discord.gg/kcKKZEg", "Discord.")*/)) + p(targetBlank("https://code.botcompany.de/1033860", "Source repository") + ". " + "Older releases on " + ahref("https://github.com/stefan-reich/gazelle-22", "GitHub") + ".") + heading("Privacy statement") + p(joinWithBR( "Gazelle 22 runs locally on your machine.", "It does not upload any data to any server.", "Server connections are made only for downloading program parts and checking for updates.", "All code is open source.")) + heading("News") + mapToLines p(newsItems) + p("Imprint: Stefan Reich, Dubenhorst 27, 25474 Ellerbek"); S nav = aname("top", p(hcombine( ahref("https://Gaz.AI", himgsnippet(#1102967, style := "height: 1em; vertical-align: bottom", title := "Gaz.AI Gazelle Logo")), joinWithVBar(map(s -> ahrefAnchor(s, s), headings))))); ret hhtml(hcombine( hhead(hcombine( htitle("Gazelle 22 - a new image recognizer"), hcss_linkColorInherit(), hsansserif(), hmobilefix() )), hbody(hfullcenter(hcombine( nav, content))) )); } // almost works except for image scaling / position if (req.uriIs("/carousel/")) { new HImageCarousel carousel; carousel.add(carousel.new Slide(#1103072, "Scriptable", "This screenshot shows my cute new scripting language which is very flexible.")); carousel.add(carousel.new Slide(#1103059, "Interactive Screen Cam", "Here you see Gazelle's preprocessing filters applied to a screen cam.")); ret hhtml(hhead(carousel.headStuff()) + hbody(carousel.html())); } ret subBot_serve404("Four oh four. Bad URL"); } record noeq Screenshot(S imageID, S date, S text) { *(S *imageID, S *text) {} toString { ret hcombine( p(hsnippetimg_linkToSameImage(imageID, width := 250, title := "Gazelle 22 screenshot - click to enlarge")), pUnlessEmpty(joinNemptiesWithBR(text, squareBracketUnlessEmpty(date))), pNbsp() ); } } srecord NewsItem(S date, S text) {} }