Add user generation feature

This commit is contained in:
Aaron Po
2026-06-21 11:59:55 -04:00
parent 93aabf230b
commit e3574d56a8
30 changed files with 53719 additions and 59 deletions

View File

@@ -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) -- not LLM-invented.
* @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_

View File

@@ -65,12 +65,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;

View File

@@ -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_

View File

@@ -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. Unused for mock generation.
* @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,26 @@ 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",