diff --git a/tooling/pipeline/includes/data_generation/data_generator.h b/tooling/pipeline/includes/data_generation/data_generator.h index 1f74713a..c150277e 100644 --- a/tooling/pipeline/includes/data_generation/data_generator.h +++ b/tooling/pipeline/includes/data_generation/data_generator.h @@ -14,28 +14,28 @@ * @brief Interface for data generator implementations. */ class DataGenerator { - public: - virtual ~DataGenerator() = default; + public: + virtual ~DataGenerator() = default; - /** - * @brief Generates brewery data for a location. - * - * @param city Enriched city the brewery is associated with. - * @return Brewery generation result. - */ - virtual BreweryResult GenerateBrewery(const EnrichedCity& city) = 0; + /** + * @brief Generates brewery data for a location. + * + * @param city Enriched city the brewery is associated with. + * @return Brewery generation result. + */ + virtual BreweryResult GenerateBrewery(const EnrichedCity& city) = 0; - /** - * @brief Generates a user profile grounded in a sampled name and persona. - * - * @param city Enriched city the user is associated with. - * @param persona Persona archetype grounding the generated bio. - * @param name Sampled first/last name (and gender) - * @return User generation result. - */ - virtual UserResult GenerateUser(const EnrichedCity& city, - const UserPersona& persona, - const Name& name) = 0; + /** + * @brief Generates a user profile grounded in a sampled name and persona. + * + * @param city Enriched city the user is associated with. + * @param persona Persona archetype grounding the generated bio. + * @param name Sampled first/last name (and gender) + * @return User generation result. + */ + virtual UserResult GenerateUser(const EnrichedCity& city, + const UserPersona& persona, + const Name& name) = 0; }; #endif // BIERGARTEN_PIPELINE_INCLUDES_DATA_GENERATION_DATA_GENERATOR_H_ diff --git a/tooling/pipeline/includes/data_generation/llama_generator.h b/tooling/pipeline/includes/data_generation/llama_generator.h index c0754ddd..0c732976 100644 --- a/tooling/pipeline/includes/data_generation/llama_generator.h +++ b/tooling/pipeline/includes/data_generation/llama_generator.h @@ -26,110 +26,112 @@ struct llama_context; * @brief Data generator implementation backed by llama.cpp. */ class LlamaGenerator final : public DataGenerator { - public: - /** - * @brief Constructs a generator using parsed application options and loads - * the configured model immediately. - * - * @param options Parsed application options. - * @param model_path Filesystem path to GGUF model assets. - * @param prompt_formatter Formatter that produces model-specific prompts. - * @param prompt_directory Directory service for loading named prompt files. - */ - LlamaGenerator(const ApplicationOptions& options, - const std::string& model_path, std::shared_ptr logger, - std::unique_ptr prompt_formatter, - std::unique_ptr prompt_directory); + public: + /** + * @brief Constructs a generator using parsed application options and loads + * the configured model immediately. + * + * @param options Parsed application options. + * @param model_path Filesystem path to GGUF model assets. + * @param prompt_formatter Formatter that produces model-specific prompts. + * @param prompt_directory Directory service for loading named prompt files. + */ + LlamaGenerator(const ApplicationOptions& options, + const std::string& model_path, + std::shared_ptr logger, + std::unique_ptr prompt_formatter, + std::unique_ptr prompt_directory); - ~LlamaGenerator() override; + ~LlamaGenerator() override; - LlamaGenerator(const LlamaGenerator&) = delete; - LlamaGenerator& operator=(const LlamaGenerator&) = delete; - LlamaGenerator(LlamaGenerator&&) = delete; - LlamaGenerator& operator=(LlamaGenerator&&) = delete; + LlamaGenerator(const LlamaGenerator&) = delete; + LlamaGenerator& operator=(const LlamaGenerator&) = delete; + LlamaGenerator(LlamaGenerator&&) = delete; + LlamaGenerator& operator=(LlamaGenerator&&) = delete; - /** - * @brief Generates brewery data for a specific location. - * - * @param location City object. - * @param region_context Additional regional context. - * @return Generated brewery result. - */ - BreweryResult GenerateBrewery(const EnrichedCity&) override; + /** + * @brief Generates brewery data for a specific location. + * + * @param location City object. + * @param region_context Additional regional context. + * @return Generated brewery result. + */ + BreweryResult GenerateBrewery(const EnrichedCity&) override; - /** - * @brief Generates a user profile grounded in a sampled name and persona. - * - * @param city Enriched city the user is associated with. - * @param persona Persona archetype grounding the generated bio. - * @param name Sampled first/last name -- not LLM-invented. - * @return Generated user profile. - */ - UserResult GenerateUser(const EnrichedCity& city, const UserPersona& persona, - const Name& name) override; + /** + * @brief Generates a user profile grounded in a sampled name and persona. + * + * @param city Enriched city the user is associated with. + * @param persona Persona archetype grounding the generated bio. + * @param name Sampled first/last name -- not LLM-invented. + * @return Generated user profile. + */ + UserResult GenerateUser(const EnrichedCity& city, const UserPersona& persona, + const Name& name) override; - private: - static constexpr int32_t kDefaultMaxTokens = 10000; - static constexpr float kDefaultSamplingTopP = 0.95F; - static constexpr uint32_t kDefaultSamplingTopK = 64; - static constexpr uint32_t kDefaultContextSize = 8192; + private: + static constexpr int32_t kDefaultMaxTokens = 10000; + static constexpr float kDefaultSamplingTopP = 0.95F; + static constexpr uint32_t kDefaultSamplingTopK = 64; + static constexpr uint32_t kDefaultContextSize = 8192; - struct ModelDeleter { - void operator()(llama_model* model) const noexcept; - }; - struct ContextDeleter { - void operator()(llama_context* context) const noexcept; - }; + struct ModelDeleter { + void operator()(llama_model* model) const noexcept; + }; + struct ContextDeleter { + void operator()(llama_context* context) const noexcept; + }; - using ModelHandle = std::unique_ptr; - using ContextHandle = std::unique_ptr; + using ModelHandle = std::unique_ptr; + using ContextHandle = std::unique_ptr; - /** - * @brief Loads model and prepares inference context. - * - * @param model_path Filesystem path to GGUF model. - */ - void Load(const std::string& model_path); + /** + * @brief Loads model and prepares inference context. + * + * @param model_path Filesystem path to GGUF model. + */ + void Load(const std::string& model_path); - /** - * @brief Infers text from separate system and user prompts. - * - * This helps chat-capable models preserve system-role behavior instead of - * concatenating system text into user input. - * - * @param system_prompt System role prompt. - * @param prompt User prompt. - * @param max_tokens Maximum tokens to generate. - * @param grammar Optional GBNF grammar constraining generated output. - * @return Generated text. - */ - std::string Infer(const std::string& system_prompt, const std::string& prompt, - int max_tokens = kDefaultMaxTokens, - std::string_view grammar = {}); + /** + * @brief Infers text from separate system and user prompts. + * + * This helps chat-capable models preserve system-role behavior instead of + * concatenating system text into user input. + * + * @param system_prompt System role prompt. + * @param prompt User prompt. + * @param max_tokens Maximum tokens to generate. + * @param grammar Optional GBNF grammar constraining generated output. + * @return Generated text. + */ + std::string Infer(const std::string& system_prompt, + const std::string& prompt, + int max_tokens = kDefaultMaxTokens, + std::string_view grammar = {}); - /** - * @brief Runs inference on an already-formatted prompt. - * - * @param formatted_prompt Prompt preformatted for model chat template. - * @param max_tokens Maximum tokens to generate. - * @param grammar Optional GBNF grammar constraining generated output. - * @return Generated text. - */ - std::string InferFormatted(const std::string& formatted_prompt, - int max_tokens = kDefaultMaxTokens, - std::string_view grammar = {}); + /** + * @brief Runs inference on an already-formatted prompt. + * + * @param formatted_prompt Prompt preformatted for model chat template. + * @param max_tokens Maximum tokens to generate. + * @param grammar Optional GBNF grammar constraining generated output. + * @return Generated text. + */ + std::string InferFormatted(const std::string& formatted_prompt, + int max_tokens = kDefaultMaxTokens, + std::string_view grammar = {}); - ModelHandle model_; - ContextHandle context_; - float sampling_temperature_ = 1.0F; - float sampling_top_p_ = kDefaultSamplingTopP; - uint32_t sampling_top_k_ = kDefaultSamplingTopK; - std::mt19937 rng_; - uint32_t n_ctx_ = kDefaultContextSize; - int n_gpu_layers_ = 0; - std::shared_ptr logger_; - std::unique_ptr prompt_formatter_; - std::unique_ptr prompt_directory_; + ModelHandle model_; + ContextHandle context_; + float sampling_temperature_ = 1.0F; + float sampling_top_p_ = kDefaultSamplingTopP; + uint32_t sampling_top_k_ = kDefaultSamplingTopK; + std::mt19937 rng_; + uint32_t n_ctx_ = kDefaultContextSize; + int n_gpu_layers_ = 0; + std::shared_ptr logger_; + std::unique_ptr prompt_formatter_; + std::unique_ptr prompt_directory_; }; #endif // BIERGARTEN_PIPELINE_INCLUDES_DATA_GENERATION_LLAMA_GENERATOR_H_ diff --git a/tooling/pipeline/includes/data_generation/mock_generator.h b/tooling/pipeline/includes/data_generation/mock_generator.h index 7d090372..3c208c3d 100644 --- a/tooling/pipeline/includes/data_generation/mock_generator.h +++ b/tooling/pipeline/includes/data_generation/mock_generator.h @@ -16,128 +16,129 @@ * @brief Mock generator used for deterministic, model-free outputs. */ class MockGenerator final : public DataGenerator { - public: - /** - * @brief Generates deterministic brewery data for a location. - * - * @param enriched_city - * @return Generated brewery result. - */ + public: + /** + * @brief Generates deterministic brewery data for a location. + * + * @param enriched_city + * @return Generated brewery result. + */ - BreweryResult GenerateBrewery(const EnrichedCity& enriched_city) override; - /** - * @brief Generates deterministic user data grounded in a sampled name and - * persona. + BreweryResult GenerateBrewery(const EnrichedCity& enriched_city) override; + /** + * @brief Generates deterministic user data grounded in a sampled name and + * persona. - * @return Generated user result. - */ - UserResult GenerateUser(const EnrichedCity& city, const UserPersona& persona, - const Name& name) override; + * @return Generated user result. + */ + UserResult GenerateUser(const EnrichedCity& city, const UserPersona& persona, + const Name& name) override; - private: - /** - * @brief Combines two strings into a stable hash value. - * - * @param location City and country names. - * @return Deterministic hash value. - */ - static size_t DeterministicHash(const City& location); + private: + /** + * @brief Combines two strings into a stable hash value. + * + * @param location City and country names. + * @return Deterministic hash value. + */ + static size_t DeterministicHash(const City& location); - /** - * @brief Combines city, persona, and name into a stable hash value. - * - * @param location City and country names. - * @param persona Persona archetype. - * @param name Sampled first/last name. - * @return Deterministic hash value. - */ - static size_t DeterministicHash(const City& location, - const UserPersona& persona, const Name& name); + /** + * @brief Combines city, persona, and name into a stable hash value. + * + * @param location City and country names. + * @param persona Persona archetype. + * @param name Sampled first/last name. + * @return Deterministic hash value. + */ + static size_t DeterministicHash(const City& location, + const UserPersona& persona, + const Name& name); - // Hash stride constants for deterministic distribution across fixed-size - // arrays. These coprime strides spread hash values uniformly without - // clustering, ensuring diverse output across different hash inputs. - static constexpr size_t kNounHashStride = 7; - static constexpr size_t kDescriptionHashStride = 13; - static constexpr size_t kBioHashStride = 11; - static constexpr size_t kActivityWeightHashStride = 17; - static constexpr size_t kActivityWeightHashRange = 1000; + // Hash stride constants for deterministic distribution across fixed-size + // arrays. These coprime strides spread hash values uniformly without + // clustering, ensuring diverse output across different hash inputs. + static constexpr size_t kNounHashStride = 7; + static constexpr size_t kDescriptionHashStride = 13; + static constexpr size_t kBioHashStride = 11; + static constexpr size_t kActivityWeightHashStride = 17; + static constexpr size_t kActivityWeightHashRange = 1000; - static constexpr std::array kBreweryAdjectives = { - "Craft", "Heritage", "Local", "Artisan", "Pioneer", "Golden", - "Modern", "Classic", "Summit", "Northern", "Riverstone", "Barrel", - "Hinterland", "Harbor", "Wild", "Granite", "Copper", "Maple"}; + static constexpr std::array kBreweryAdjectives = { + "Craft", "Heritage", "Local", "Artisan", "Pioneer", "Golden", + "Modern", "Classic", "Summit", "Northern", "Riverstone", "Barrel", + "Hinterland", "Harbor", "Wild", "Granite", "Copper", "Maple"}; - static constexpr std::array kBreweryNouns = { - "Brewing Co.", "Brewery", "Bier Haus", "Taproom", "Works", - "House", "Fermentery", "Ale Co.", "Cellars", "Collective", - "Project", "Foundry", "Malthouse", "Public House", "Co-op", - "Lab", "Beer Hall", "Guild"}; + static constexpr std::array kBreweryNouns = { + "Brewing Co.", "Brewery", "Bier Haus", "Taproom", "Works", + "House", "Fermentery", "Ale Co.", "Cellars", "Collective", + "Project", "Foundry", "Malthouse", "Public House", "Co-op", + "Lab", "Beer Hall", "Guild"}; - static constexpr std::array kBreweryDescriptions = { - "Handcrafted pale ales and seasonal IPAs with local ingredients.", - "Traditional lagers and experimental sours in small batches.", - "Award-winning stouts and wildly hoppy blonde ales.", - "Craft brewery specializing in Belgian-style triples and dark " - "porters.", - "Modern brewery blending tradition with bold experimental flavors.", - "Neighborhood-focused taproom pouring crisp pilsners and citrusy " - "pale " - "ales.", - "Small-batch brewery known for barrel-aged releases and smoky " - "lagers.", - "Independent brewhouse pairing farmhouse ales with rotating food " - "pop-ups.", - "Community brewpub making balanced bitters, saisons, and hazy IPAs.", - "Experimental nanobrewery exploring local yeast and regional " - "grains.", - "Family-run brewery producing smooth amber ales and robust porters.", - "Urban brewery crafting clean lagers and bright, fruit-forward " - "sours.", - "Riverfront brewhouse featuring oak-matured ales and seasonal " - "blends.", - "Modern taproom focused on sessionable lagers and classic pub " - "styles.", - "Brewery rooted in tradition with a lineup of malty reds and crisp " - "lagers.", - "Creative brewery offering rotating collaborations and limited " - "draft-only " - "pours.", - "Locally inspired brewery serving approachable ales with bold hop " - "character.", - "Destination taproom known for balanced IPAs and cocoa-rich " - "stouts."}; + static constexpr std::array kBreweryDescriptions = { + "Handcrafted pale ales and seasonal IPAs with local ingredients.", + "Traditional lagers and experimental sours in small batches.", + "Award-winning stouts and wildly hoppy blonde ales.", + "Craft brewery specializing in Belgian-style triples and dark " + "porters.", + "Modern brewery blending tradition with bold experimental flavors.", + "Neighborhood-focused taproom pouring crisp pilsners and citrusy " + "pale " + "ales.", + "Small-batch brewery known for barrel-aged releases and smoky " + "lagers.", + "Independent brewhouse pairing farmhouse ales with rotating food " + "pop-ups.", + "Community brewpub making balanced bitters, saisons, and hazy IPAs.", + "Experimental nanobrewery exploring local yeast and regional " + "grains.", + "Family-run brewery producing smooth amber ales and robust porters.", + "Urban brewery crafting clean lagers and bright, fruit-forward " + "sours.", + "Riverfront brewhouse featuring oak-matured ales and seasonal " + "blends.", + "Modern taproom focused on sessionable lagers and classic pub " + "styles.", + "Brewery rooted in tradition with a lineup of malty reds and crisp " + "lagers.", + "Creative brewery offering rotating collaborations and limited " + "draft-only " + "pours.", + "Locally inspired brewery serving approachable ales with bold hop " + "character.", + "Destination taproom known for balanced IPAs and cocoa-rich " + "stouts."}; - static constexpr std::array kUsernames = { - "hopseeker", "malttrail", "yeastwhisper", "lagerlane", - "barrelbound", "foamfinder", "taphunter", "graingeist", - "brewscout", "aleatlas", "caskcompass", "hopsandmaps", - "mashpilot", "pintnomad", "fermentfriend", "stoutsignal", - "sessionwander", "kettlekeeper"}; + static constexpr std::array kUsernames = { + "hopseeker", "malttrail", "yeastwhisper", "lagerlane", + "barrelbound", "foamfinder", "taphunter", "graingeist", + "brewscout", "aleatlas", "caskcompass", "hopsandmaps", + "mashpilot", "pintnomad", "fermentfriend", "stoutsignal", + "sessionwander", "kettlekeeper"}; - static constexpr std::array kBios = { - "Always chasing balanced IPAs and crisp lagers across local taprooms.", - "Weekend brewery explorer with a soft spot for dark, roasty stouts.", - "Documenting tiny brewpubs, fresh pours, and unforgettable beer " - "gardens.", - "Fan of farmhouse ales, food pairings, and long tasting flights.", - "Collecting favorite pilsners one city at a time.", - "Hops-first drinker who still saves room for classic malt-forward " - "styles.", - "Finding hidden tap lists and sharing the best seasonal releases.", - "Brewery road-tripper focused on local ingredients and clean " - "fermentation.", - "Always comparing house lagers and ranking patio pint vibes.", - "Curious about yeast strains, barrel programs, and cellar experiments.", - "Believes every neighborhood deserves a great community taproom.", - "Looking for session beers that taste great from first sip to last.", - "Belgian ale enthusiast who never skips a new saison.", - "Hazy IPA critic with deep respect for a perfectly clear pilsner.", - "Visits breweries for the stories, stays for the flagship pours.", - "Craft beer fan mapping tasting notes and favorite brew routes.", - "Always ready to trade recommendations for underrated local breweries.", - "Keeping a running list of must-try collab releases and tap " - "takeovers."}; + static constexpr std::array kBios = { + "Always chasing balanced IPAs and crisp lagers across local taprooms.", + "Weekend brewery explorer with a soft spot for dark, roasty stouts.", + "Documenting tiny brewpubs, fresh pours, and unforgettable beer " + "gardens.", + "Fan of farmhouse ales, food pairings, and long tasting flights.", + "Collecting favorite pilsners one city at a time.", + "Hops-first drinker who still saves room for classic malt-forward " + "styles.", + "Finding hidden tap lists and sharing the best seasonal releases.", + "Brewery road-tripper focused on local ingredients and clean " + "fermentation.", + "Always comparing house lagers and ranking patio pint vibes.", + "Curious about yeast strains, barrel programs, and cellar experiments.", + "Believes every neighborhood deserves a great community taproom.", + "Looking for session beers that taste great from first sip to last.", + "Belgian ale enthusiast who never skips a new saison.", + "Hazy IPA critic with deep respect for a perfectly clear pilsner.", + "Visits breweries for the stories, stays for the flagship pours.", + "Craft beer fan mapping tasting notes and favorite brew routes.", + "Always ready to trade recommendations for underrated local breweries.", + "Keeping a running list of must-try collab releases and tap " + "takeovers."}; }; #endif // BIERGARTEN_PIPELINE_INCLUDES_DATA_GENERATION_MOCK_GENERATOR_H_