Skip to content

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 →