mirror of
https://github.com/aaronpo97/the-biergarten-app.git
synced 2026-07-16 17:47:22 +00:00
Pipeline: Add LLM and mocked user generation to the pipeline (#230)
This commit is contained in:
@@ -28,12 +28,16 @@ class DataGenerator {
|
||||
const std::string& region_context) = 0;
|
||||
|
||||
/**
|
||||
* @brief Generates a user profile for a locale.
|
||||
* @brief Generates a user profile grounded in a sampled name and persona.
|
||||
*
|
||||
* @param locale Locale hint used by generator.
|
||||
* @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 std::string& locale) = 0;
|
||||
virtual UserResult GenerateUser(const EnrichedCity& city,
|
||||
const UserPersona& persona,
|
||||
const Name& name) = 0;
|
||||
};
|
||||
|
||||
#endif // BIERGARTEN_PIPELINE_INCLUDES_DATA_GENERATION_DATA_GENERATOR_H_
|
||||
|
||||
52
tooling/pipeline/includes/data_generation/json_grammars.h
Normal file
52
tooling/pipeline/includes/data_generation/json_grammars.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#ifndef BIERGARTEN_PIPELINE_INCLUDES_DATA_GENERATION_JSON_GRAMMARS_H_
|
||||
#define BIERGARTEN_PIPELINE_INCLUDES_DATA_GENERATION_JSON_GRAMMARS_H_
|
||||
|
||||
/**
|
||||
* @file data_generation/json_grammars.h
|
||||
* @brief GBNF grammars constraining structured JSON output from
|
||||
* LlamaGenerator inference calls.
|
||||
*/
|
||||
|
||||
#include <string_view>
|
||||
|
||||
// GBNF grammar for structured user JSON output.
|
||||
// thought-block permits the model to emit free-form reasoning before the
|
||||
// JSON object (the prompts explicitly invite this); only the "{...}" tail is
|
||||
// constrained to the expected shape.
|
||||
inline constexpr std::string_view kUserJsonGrammar = R"json_user(
|
||||
root ::= thought-block (
|
||||
"{" ws
|
||||
"\"username\"" ws ":" ws string ws "," ws
|
||||
"\"bio\"" ws ":" ws string ws "," ws
|
||||
"\"activity_weight\"" ws ":" ws number ws
|
||||
"}" ws
|
||||
)
|
||||
thought-block ::= [^{]*
|
||||
ws ::= [ \t\n\r]*
|
||||
string ::= "\"" char+ "\""
|
||||
char ::= [^"\\\x7F\x00-\x1F] | [\\] escape
|
||||
escape ::= ["\\/bfnrt] | "u" hex hex hex hex
|
||||
hex ::= [0-9a-fA-F]
|
||||
number ::= "-"? ("0" | [1-9] [0-9]*) ("." [0-9]+)?
|
||||
)json_user";
|
||||
|
||||
// GBNF grammar for structured brewery JSON output (see thought-block note
|
||||
// above).
|
||||
inline constexpr std::string_view kBreweryJsonGrammar = R"json_brewery(
|
||||
root ::= thought-block (
|
||||
"{" ws
|
||||
"\"name_en\"" ws ":" ws string ws "," ws
|
||||
"\"description_en\"" ws ":" ws string ws "," ws
|
||||
"\"name_local\"" ws ":" ws string ws "," ws
|
||||
"\"description_local\"" ws ":" ws string ws
|
||||
"}" ws
|
||||
)
|
||||
thought-block ::= [^{]*
|
||||
ws ::= [ \t\n\r]*
|
||||
string ::= "\"" char+ "\""
|
||||
char ::= [^"\\\x7F\x00-\x1F] | [\\] escape
|
||||
escape ::= ["\\/bfnrt] | "u" hex hex hex hex
|
||||
hex ::= [0-9a-fA-F]
|
||||
)json_brewery";
|
||||
|
||||
#endif // BIERGARTEN_PIPELINE_INCLUDES_DATA_GENERATION_JSON_GRAMMARS_H_
|
||||
@@ -1,24 +1,23 @@
|
||||
#ifndef BIERGARTEN_PIPELINE_INCLUDES_DATA_GENERATION_LLAMA_GENERATOR_H_
|
||||
#define BIERGARTEN_PIPELINE_INCLUDES_DATA_GENERATION_LLAMA_GENERATOR_H_
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
/**
|
||||
* @file data_generation/llama_generator.h
|
||||
* @brief llama.cpp-backed implementation of DataGenerator.
|
||||
*/
|
||||
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include "../services/prompting/prompt_directory.h"
|
||||
#include "data_generation/data_generator.h"
|
||||
#include "data_generation/prompt_formatting/prompt_formatter.h"
|
||||
#include "data_model/models.h"
|
||||
#include "services/logging/logger.h"
|
||||
#include "services/prompting/prompt_directory.h"
|
||||
|
||||
struct llama_model;
|
||||
struct llama_context;
|
||||
@@ -44,14 +43,9 @@ class LlamaGenerator final : public DataGenerator {
|
||||
|
||||
~LlamaGenerator() override;
|
||||
|
||||
// disable copy constructor
|
||||
LlamaGenerator(const LlamaGenerator&) = delete;
|
||||
|
||||
// disable copy assignment operator
|
||||
LlamaGenerator& operator=(const LlamaGenerator&) = delete;
|
||||
// disable move constructor
|
||||
LlamaGenerator(LlamaGenerator&&) = delete;
|
||||
// disable move assignment operator
|
||||
LlamaGenerator& operator=(LlamaGenerator&&) = delete;
|
||||
|
||||
/**
|
||||
@@ -65,12 +59,15 @@ class LlamaGenerator final : public DataGenerator {
|
||||
const std::string& region_context) override;
|
||||
|
||||
/**
|
||||
* @brief Generates a user profile for the provided locale.
|
||||
* @brief Generates a user profile grounded in a sampled name and persona.
|
||||
*
|
||||
* @param locale Locale hint.
|
||||
* @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 std::string& locale) override;
|
||||
UserResult GenerateUser(const EnrichedCity& city, const UserPersona& persona,
|
||||
const Name& name) override;
|
||||
|
||||
private:
|
||||
static constexpr int32_t kDefaultMaxTokens = 10000;
|
||||
|
||||
@@ -47,4 +47,18 @@ void AppendTokenPiece(const llama_vocab* vocab, llama_token token,
|
||||
std::optional<std::string> ValidateBreweryJson(const std::string& raw,
|
||||
BreweryResult& brewery_out);
|
||||
|
||||
/**
|
||||
* @brief Validates and parses user JSON output.
|
||||
*
|
||||
* Only populates `username`, `bio`, and `activity_weight` -- `first_name`
|
||||
* and `last_name` are not LLM-authored and are set separately from the
|
||||
* sampled Name.
|
||||
*
|
||||
* @param raw Raw model output.
|
||||
* @param user_out Parsed user payload.
|
||||
* @return Validation error message if invalid, or std::nullopt on success.
|
||||
*/
|
||||
std::optional<std::string> ValidateUserJson(const std::string& raw,
|
||||
UserResult& user_out);
|
||||
|
||||
#endif // BIERGARTEN_PIPELINE_INCLUDES_DATA_GENERATION_LLAMA_GENERATOR_HELPERS_H_
|
||||
|
||||
@@ -28,12 +28,16 @@ class MockGenerator final : public DataGenerator {
|
||||
const std::string& region_context) override;
|
||||
|
||||
/**
|
||||
* @brief Generates deterministic user data for a locale.
|
||||
* @brief Generates deterministic user data grounded in a sampled name and
|
||||
* persona.
|
||||
*
|
||||
* @param locale Locale hint.
|
||||
* @param city Enriched city the user is associated with.
|
||||
* @param persona Persona archetype.
|
||||
* @param name Sampled first/last name, copied directly into the result.
|
||||
* @return Generated user result.
|
||||
*/
|
||||
UserResult GenerateUser(const std::string& locale) override;
|
||||
UserResult GenerateUser(const EnrichedCity& city, const UserPersona& persona,
|
||||
const Name& name) override;
|
||||
|
||||
private:
|
||||
/**
|
||||
@@ -44,12 +48,25 @@ class MockGenerator final : public DataGenerator {
|
||||
*/
|
||||
static size_t DeterministicHash(const Location& 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 Location& 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;
|
||||
|
||||
static constexpr std::array<std::string_view, 18> kBreweryAdjectives = {
|
||||
"Craft", "Heritage", "Local", "Artisan", "Pioneer", "Golden",
|
||||
@@ -124,7 +141,8 @@ class MockGenerator final : public DataGenerator {
|
||||
"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."};
|
||||
"Keeping a running list of must-try collab releases and tap "
|
||||
"takeovers."};
|
||||
};
|
||||
|
||||
#endif // BIERGARTEN_PIPELINE_INCLUDES_DATA_GENERATION_MOCK_GENERATOR_H_
|
||||
|
||||
Reference in New Issue
Block a user