AI Image Generator — C++ source
Turn a text prompt into a 1024×1024 image with FLUX.1 [schnell] on Cloudflare Workers AI. No account, no API key — rate-limited for fair use. Your prompt goes to the model through our Worker; we store no prompts and no images.
This is the C++ implementation — the same logic the interactive tool runs, in a shareable, citable form.
// AI Image Generator — prompt validation, gate verdicts, and ?prompt= URL
// state for FLUX.1-schnell (C++17, stdlib only). Port of src/lib/image-gen.ts.
#include <cctype>
#include <cstdint>
#include <optional>
#include <string>
namespace image_gen {
inline constexpr auto MODEL = "@cf/black-forest-labs/flux-1-schnell"; // + 4 steps = 57.6 n/img
inline constexpr int STEPS = 4;
inline constexpr std::size_t PROMPT_MAX_CHARS = 600; // UX clamp below the 2048 max
inline constexpr int IP_HOUR_CAP = 10, DAILY_CAP = 100;
enum class PromptInvalid { Empty, TooLong, ControlChars };
enum class GateError { Ip, Daily };
inline int hexval(char c) { return c <= '9' ? c - '0' : (c | 32) - 'a' + 10; }
// Normalize CRLF/CR -> \n, trim, enforce 1..600 chars, reject control chars
// except \n. Bytes: length is stricter than the TS char count for non-ASCII;
// C1 is exactly lead 0xC2 + continuation 0x80..0x9F.
std::optional<std::string> validate_prompt(const std::string& raw, PromptInvalid& reason)
{
std::string prompt;
bool started = false;
for (std::size_t i = 0; i < raw.size(); ++i) {
char c = raw[i];
if (c == '\r') { if (i + 1 < raw.size() && raw[i + 1] == '\n') continue; c = '\n'; }
if (!started && std::isspace(static_cast<unsigned char>(c))) continue;
started = true;
prompt.push_back(c);
}
while (!prompt.empty() && std::isspace(static_cast<unsigned char>(prompt.back()))) prompt.pop_back();
if (prompt.empty()) { reason = PromptInvalid::Empty; return std::nullopt; }
if (prompt.size() > PROMPT_MAX_CHARS) { reason = PromptInvalid::TooLong; return std::nullopt; }
for (std::size_t i = 0; i < prompt.size(); ++i) {
unsigned char c = static_cast<unsigned char>(prompt[i]);
bool cont = (c & 0xC0) == 0x80; // UTF-8 continuation byte
bool c1 = c == 0xC2 && i + 1 < prompt.size() && (static_cast<unsigned char>(prompt[i + 1]) & 0xE0) == 0x80;
if (!cont && (c1 || (c < 0x20 && c != '\n') || c == 0x7F)) {
reason = PromptInvalid::ControlChars; return std::nullopt;
}
}
return prompt;
}
// Daily cap wins (resets at UTC midnight); the IP window is a fixed hour.
std::optional<GateError> check_gate(int ip_count, int daily_count, std::uint64_t now_ms, int& retry)
{
if (daily_count >= DAILY_CAP) {
retry = static_cast<int>((86400000ULL - now_ms % 86400000ULL + 59999ULL) / 60000ULL);
return GateError::Daily;
}
if (ip_count >= IP_HOUR_CAP) { retry = 60; return GateError::Ip; }
return std::nullopt;
}
// Encode the shareable state ("" when empty): unreserved passes, else %XX.
std::string encode_url_state(const std::string& prompt)
{
if (prompt.empty()) return "";
static const char* hex = "0123456789ABCDEF";
std::string out = "?prompt=";
for (unsigned char c : prompt) {
if (std::isalnum(c) || c == '-' || c == '.' || c == '_' || c == '~') out.push_back(static_cast<char>(c));
else { out.push_back('%'); out.push_back(hex[c >> 4]); out.push_back(hex[c & 15]); }
}
return out;
}
// Inverse of encode_url_state — decode the leading ?prompt= pair (%XX assumed).
std::string decode_url_state(const std::string& search)
{
std::string out;
if (search.compare(0, 8, "?prompt=") != 0) return out;
for (std::size_t i = 8; i < search.size() && search[i] != '&';) {
if (search[i] == '%' && i + 2 < search.size()) {
out.push_back(static_cast<char>(hexval(search[i + 1]) << 4 | hexval(search[i + 2]));
i += 3;
} else out.push_back(search[i++]);
}
return out;
}
} // namespace image_gen
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →