From 7ce570bc98a5ad813cd5ad3220a5275aa02622df Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Fri, 3 Feb 2017 20:24:38 -0500 Subject: Combined advice methods because of weird memory things? --- advice.cpp | 518 +++++++++++++++++++++++++++++-------------------------------- advice.h | 8 - 2 files changed, 243 insertions(+), 283 deletions(-) diff --git a/advice.cpp b/advice.cpp index 320f719..b9ab3f9 100644 --- a/advice.cpp +++ b/advice.cpp @@ -35,315 +35,283 @@ advice::advice( generator_ = std::unique_ptr(new sentence(*database_, rng_)); } -verbly::word advice::generateImageNoun() const -{ - verbly::filter whitelist = - (verbly::notion::wnid == 109287968) // Geological formations - || (verbly::notion::wnid == 109208496) // Asterisms (collections of stars) - || (verbly::notion::wnid == 109239740) // Celestial bodies - || (verbly::notion::wnid == 109277686) // Exterrestrial objects (comets and meteroids) - || (verbly::notion::wnid == 109403211) // Radiators (supposedly natural radiators but actually these are just pictures of radiators) - || (verbly::notion::wnid == 109416076) // Rocks - || (verbly::notion::wnid == 105442131) // Chromosomes - || (verbly::notion::wnid == 100324978) // Tightrope walking - || (verbly::notion::wnid == 100326094) // Rock climbing - || (verbly::notion::wnid == 100433458) // Contact sports - || (verbly::notion::wnid == 100433802) // Gymnastics - || (verbly::notion::wnid == 100439826) // Track and field - || (verbly::notion::wnid == 100440747) // Skiing - || (verbly::notion::wnid == 100441824) // Water sport - || (verbly::notion::wnid == 100445351) // Rowing - || (verbly::notion::wnid == 100446980) // Archery - // TODO: add more sports - || (verbly::notion::wnid == 100021939) // Artifacts - || (verbly::notion::wnid == 101471682) // Vertebrates - ; - - verbly::filter blacklist = - (verbly::notion::wnid == 106883725) // swastika - || (verbly::notion::wnid == 104416901) // tetraskele - || (verbly::notion::wnid == 102512053) // fish - || (verbly::notion::wnid == 103575691) // instrument of execution - ; - - verbly::query pictureQuery = database_->words( - (verbly::notion::fullHypernyms %= whitelist) - && !(verbly::notion::fullHypernyms %= blacklist) - && (verbly::notion::partOfSpeech == verbly::part_of_speech::noun) - && (verbly::notion::numOfImages >= 1)); - - return pictureQuery.first(); -} - -Magick::Image advice::getImageForNoun(verbly::word pictured) const +void advice::run() const { - // Accept string from Google Chrome - std::string accept = "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"; - curl::curl_header headers; - headers.add(accept); - - int backoff = 0; - - std::cout << "Generating noun..." << std::endl; - std::cout << "Noun: " << pictured.getBaseForm() << std::endl; - std::cout << "Getting URLs..." << std::endl; - - std::string lstdata; - while (lstdata.empty()) + for (;;) { - std::ostringstream lstbuf; - curl::curl_ios lstios(lstbuf); - curl::curl_easy lsthandle(lstios); - std::string lsturl = pictured.getNotion().getImageNetUrl(); - lsthandle.add(lsturl.c_str()); - try { - lsthandle.perform(); - } catch (const curl::curl_easy_exception& e) - { - e.print_traceback(); - - backoff++; - std::cout << "Waiting for " << backoff << " seconds..." << std::endl; - - std::this_thread::sleep_for(std::chrono::seconds(backoff)); - - continue; - } - - backoff = 0; - - if (lsthandle.get_info().get() != 200) - { - throw could_not_get_images(); - } + verbly::filter whitelist = + (verbly::notion::wnid == 109287968) // Geological formations + || (verbly::notion::wnid == 109208496) // Asterisms (collections of stars) + || (verbly::notion::wnid == 109239740) // Celestial bodies + || (verbly::notion::wnid == 109277686) // Exterrestrial objects (comets and meteroids) + || (verbly::notion::wnid == 109403211) // Radiators (supposedly natural radiators but actually these are just pictures of radiators) + || (verbly::notion::wnid == 109416076) // Rocks + || (verbly::notion::wnid == 105442131) // Chromosomes + || (verbly::notion::wnid == 100324978) // Tightrope walking + || (verbly::notion::wnid == 100326094) // Rock climbing + || (verbly::notion::wnid == 100433458) // Contact sports + || (verbly::notion::wnid == 100433802) // Gymnastics + || (verbly::notion::wnid == 100439826) // Track and field + || (verbly::notion::wnid == 100440747) // Skiing + || (verbly::notion::wnid == 100441824) // Water sport + || (verbly::notion::wnid == 100445351) // Rowing + || (verbly::notion::wnid == 100446980) // Archery + // TODO: add more sports + || (verbly::notion::wnid == 100021939) // Artifacts + || (verbly::notion::wnid == 101471682) // Vertebrates + ; + + verbly::filter blacklist = + (verbly::notion::wnid == 106883725) // swastika + || (verbly::notion::wnid == 104416901) // tetraskele + || (verbly::notion::wnid == 102512053) // fish + || (verbly::notion::wnid == 103575691) // instrument of execution + ; + + verbly::query pictureQuery = database_->words( + (verbly::notion::fullHypernyms %= whitelist) + && !(verbly::notion::fullHypernyms %= blacklist) + && (verbly::notion::partOfSpeech == verbly::part_of_speech::noun) + && (verbly::notion::numOfImages >= 1)); + + verbly::word pictured = pictureQuery.first(); + + // Accept string from Google Chrome + std::string accept = "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"; + curl::curl_header headers; + headers.add(accept); + + int backoff = 0; + + std::cout << "Generating noun..." << std::endl; + std::cout << "Noun: " << pictured.getBaseForm() << std::endl; + std::cout << "Getting URLs..." << std::endl; + + std::string lstdata; + while (lstdata.empty()) + { + std::ostringstream lstbuf; + curl::curl_ios lstios(lstbuf); + curl::curl_easy lsthandle(lstios); + std::string lsturl = pictured.getNotion().getImageNetUrl(); + lsthandle.add(lsturl.c_str()); - std::cout << "Got URLs." << std::endl; - lstdata = lstbuf.str(); - } + try + { + lsthandle.perform(); + } catch (const curl::curl_easy_exception& e) + { + e.print_traceback(); - std::vector lstvec = verbly::split>(lstdata, "\r\n"); - if (lstvec.empty()) - { - throw could_not_get_images(); - } + backoff++; + std::cout << "Waiting for " << backoff << " seconds..." << std::endl; - std::shuffle(std::begin(lstvec), std::end(lstvec), rng_); + std::this_thread::sleep_for(std::chrono::seconds(backoff)); - std::deque urls; - for (std::string& url : lstvec) - { - urls.push_back(url); - } + continue; + } - bool found = false; - Magick::Blob img; - Magick::Image pic; + backoff = 0; - while (!found && !urls.empty()) - { - std::string url = urls.front(); - urls.pop_front(); + if (lsthandle.get_info().get() != 200) + { + throw could_not_get_images(); + } - std::ostringstream imgbuf; - curl::curl_ios imgios(imgbuf); - curl::curl_easy imghandle(imgios); + std::cout << "Got URLs." << std::endl; + lstdata = lstbuf.str(); + } - imghandle.add(headers.get()); - imghandle.add(url.c_str()); - imghandle.add(30); + std::vector lstvec = verbly::split>(lstdata, "\r\n"); + if (lstvec.empty()) + { + throw could_not_get_images(); + } - try - { - imghandle.perform(); - } catch (curl::curl_easy_exception error) { - error.print_traceback(); + std::shuffle(std::begin(lstvec), std::end(lstvec), rng_); - continue; - } + std::deque urls; + for (std::string& url : lstvec) + { + urls.push_back(url); + } - if (imghandle.get_info().get() != 200) - { - continue; - } + bool found = false; + Magick::Blob img; + Magick::Image pic; - std::string content_type = imghandle.get_info().get(); - if (content_type.substr(0, 6) != "image/") - { - continue; - } + while (!found && !urls.empty()) + { + std::string url = urls.front(); + urls.pop_front(); + + std::ostringstream imgbuf; + curl::curl_ios imgios(imgbuf); + curl::curl_easy imghandle(imgios); + + imghandle.add(headers.get()); + imghandle.add(url.c_str()); + imghandle.add(30); + + try + { + imghandle.perform(); + } catch (curl::curl_easy_exception error) { + error.print_traceback(); + + continue; + } + + if (imghandle.get_info().get() != 200) + { + continue; + } + + std::string content_type = imghandle.get_info().get(); + if (content_type.substr(0, 6) != "image/") + { + continue; + } + + std::string imgstr = imgbuf.str(); + img = Magick::Blob(imgstr.c_str(), imgstr.length()); + pic.read(img); + if (pic.rows() == 0) + { + continue; + } + + // Too small! + if (pic.columns() < 400) + { + continue; + } + + std::cout << url << std::endl; + found = true; + } - std::string imgstr = imgbuf.str(); - img = Magick::Blob(imgstr.c_str(), imgstr.length()); - pic.read(img); - if (pic.rows() == 0) - { - continue; - } + if (!found) + { + throw could_not_get_images(); + } + + std::string title = generator_->generate(); - // Too small! - if (pic.columns() < 400) - { - continue; - } + // Want a 16:9 aspect + int idealwidth = pic.rows()*(16.0/9.0); + if (idealwidth > pic.columns()) + { + // If the image is narrower than the ideal width, use full width. + int newheight = pic.columns()*(9.0/16.0); - std::cout << url << std::endl; - found = true; - } + // Just take a slice out of the middle of the image. + int cropy = ((double)(pic.rows() - newheight))/2.0; - if (!found) - { - throw could_not_get_images(); - } + pic.crop(Magick::Geometry(pic.columns(), newheight, 0, cropy)); + } else { + // If the image is wider than the ideal width, use full height. + // Just take a slice out of the middle of the image. + int cropx = ((double)(pic.columns() - idealwidth))/2.0; - return pic; -} + pic.crop(Magick::Geometry(idealwidth, pic.rows(), cropx, 0)); + } -Magick::Image advice::layoutImage(Magick::Image pic, std::string title) const -{ - // Want a 16:9 aspect - int idealwidth = pic.rows()*(16.0/9.0); - if (idealwidth > pic.columns()) - { - // If the image is narrower than the ideal width, use full width. - int newheight = pic.columns()*(9.0/16.0); + pic.zoom(Magick::Geometry(400, 225)); - // Just take a slice out of the middle of the image. - int cropy = ((double)(pic.rows() - newheight))/2.0; + // Layout the text. + std::list words = verbly::split>(title, " "); + std::vector lines; + std::list cur; + Magick::TypeMetric metric; + pic.fontPointsize(20); + pic.font("@coolvetica.ttf"); - pic.crop(Magick::Geometry(pic.columns(), newheight, 0, cropy)); - } else { - // If the image is wider than the ideal width, use full height. - // Just take a slice out of the middle of the image. - int cropx = ((double)(pic.columns() - idealwidth))/2.0; + while (!words.empty()) + { + cur.push_back(words.front()); + + std::string prefixText = verbly::implode(std::begin(cur), std::end(cur), " "); + pic.fontTypeMetrics(prefixText, &metric); + + if (metric.textWidth() > 380) + { + if (cur.size() == 1) + { + words.pop_front(); + } else { + cur.pop_back(); + } + + prefixText = verbly::implode(std::begin(cur), std::end(cur), " "); + lines.push_back(prefixText); + cur.clear(); + } else { + words.pop_front(); + } + } - pic.crop(Magick::Geometry(idealwidth, pic.rows(), cropx, 0)); - } + if (!cur.empty()) + { + std::string prefixText = verbly::implode(std::begin(cur), std::end(cur), " "); + lines.push_back(prefixText); + } - pic.zoom(Magick::Geometry(400, 225)); + int lineHeight = metric.textHeight()-2; + int blockHeight = lineHeight * lines.size() + 18; + std::cout << "line " << lineHeight << "; block " << blockHeight << std::endl; + + std::list drawList; + drawList.push_back(Magick::DrawableFillColor("black")); + drawList.push_back(Magick::DrawableFillOpacity(0.5)); + drawList.push_back(Magick::DrawableStrokeColor("transparent")); + drawList.push_back(Magick::DrawableRectangle(0, 225-blockHeight-20, 400, 255)); // 0, 225-60, 400, 255 + pic.draw(drawList); + + drawList.clear(); + drawList.push_back(Magick::DrawableFont("@coolvetica.ttf")); + drawList.push_back(Magick::DrawableFillColor("white")); + drawList.push_back(Magick::DrawablePointSize(14)); + drawList.push_back(Magick::DrawableText(10, 225-blockHeight+4, "How to")); // 10, 255-62-4 + pic.draw(drawList); + + for (int i=0; i words = verbly::split>(title, " "); - std::vector lines; - std::list cur; - Magick::TypeMetric metric; - pic.fontPointsize(20); - pic.font("@coolvetica.ttf"); + Magick::Blob outputimg; - while (!words.empty()) - { - cur.push_back(words.front()); + try + { + pic.magick("png"); + pic.write(&outputimg); + } catch (const Magick::WarningCoder& e) + { + // Ignore + } - std::string prefixText = verbly::implode(std::begin(cur), std::end(cur), " "); - pic.fontTypeMetrics(prefixText, &metric); + std::cout << "Generated image!" << std::endl << "Tweeting..." << std::endl; - if (metric.textWidth() > 380) - { - if (cur.size() == 1) + std::string tweetText; + size_t tweetLim = 140 - client_->getConfiguration().getCharactersReservedPerMedia(); + if (title.length() > tweetLim) { - words.pop_front(); + tweetText = title.substr(0, tweetLim - 1) + "…"; } else { - cur.pop_back(); + tweetText = title; } - prefixText = verbly::implode(std::begin(cur), std::end(cur), " "); - lines.push_back(prefixText); - cur.clear(); - } else { - words.pop_front(); - } - } - - if (!cur.empty()) - { - std::string prefixText = verbly::implode(std::begin(cur), std::end(cur), " "); - lines.push_back(prefixText); - } - - int lineHeight = metric.textHeight()-2; - int blockHeight = lineHeight * lines.size() + 18; - std::cout << "line " << lineHeight << "; block " << blockHeight << std::endl; - - std::list drawList; - drawList.push_back(Magick::DrawableFillColor("black")); - drawList.push_back(Magick::DrawableFillOpacity(0.5)); - drawList.push_back(Magick::DrawableStrokeColor("transparent")); - drawList.push_back(Magick::DrawableRectangle(0, 225-blockHeight-20, 400, 255)); // 0, 225-60, 400, 255 - pic.draw(drawList); - - drawList.clear(); - drawList.push_back(Magick::DrawableFont("@coolvetica.ttf")); - drawList.push_back(Magick::DrawableFillColor("white")); - drawList.push_back(Magick::DrawablePointSize(14)); - drawList.push_back(Magick::DrawableText(10, 225-blockHeight+4, "How to")); // 10, 255-62-4 - pic.draw(drawList); - - for (int i=0; igetConfiguration().getCharactersReservedPerMedia(); - if (title.length() > tweetLim) - { - tweetText = title.substr(0, tweetLim - 1) + "…"; - } else { - tweetText = title; - } - - long media_id = client_->uploadMedia("image/png", (const char*) outputimg.data(), outputimg.length()); - client_->updateStatus(tweetText, {media_id}); -} - -void advice::run() const -{ - for (;;) - { - try - { - // Pick a noun to use for the picture. - verbly::word pictured = generateImageNoun(); - - // Find an image of the picked noun. - Magick::Image pic = getImageForNoun(pictured); - - // Generate the image text. - std::string title = generator_->generate(); - - // Layout the image. - Magick::Image output = layoutImage(std::move(pic), title); - - // Tweet the image. - sendTweet(std::move(output), title); - - std::cout << "Done!" << std::endl << "Waiting..." << std::endl << std::endl; - - // Wait. + long media_id = client_->uploadMedia("image/png", (const char*) outputimg.data(), outputimg.length()); + client_->updateStatus(tweetText, {media_id}); + std::this_thread::sleep_for(std::chrono::hours(1)); } catch (const could_not_get_images& ex) { diff --git a/advice.h b/advice.h index 33dc531..fb83c90 100644 --- a/advice.h +++ b/advice.h @@ -29,14 +29,6 @@ private: } }; - verbly::word generateImageNoun() const; - - Magick::Image getImageForNoun(verbly::word pictured) const; - - Magick::Image layoutImage(Magick::Image bg, std::string title) const; - - void sendTweet(Magick::Image pic, std::string title) const; - std::mt19937& rng_; std::unique_ptr database_; std::unique_ptr generator_; -- cgit 1.4.1