# zero PII exputer University - Part 1. 1: створення даних зразка (і зображень) локально

<!--category-- Product, Privacy, LLM, ComfyUI, C# -->
<datetime class="hidden">2025-12-24T20:00</datetime>

Вхід [Частина 1](/blog/zero-pii-customer-intelligence-part1) ми обговорювали філософію: прозорий сегментація без PII. [Частина 2](/blog/zero-pii-customer-intelligence-part2) обговорює профілі сеансів, сигнали та визначення сегментів.

Але спочатку: **Як ви підтверджуєте все це, не торкаючись даних справжнього клієнта?**

Для цієї серії статей я створюю повний штучний набір даних ecommerce локально:

- Каталог продуктів (назви, описи, мітки, ціни)
- Анонімне ⇩s} / personas (pids + gones)
- Зображення продукту (і портрети профілю) за допомогою ComfyUI
- Необов' язковий імпорт DB, щоб реальна програма могла працювати з ним

Це одна з тих, що відчувають, ніби шахраювання йде вперед: ви отримуєте реалістичні входи, ви можете відновити їх будь-коли, і ви ніколи не впроваджуєте PII у середовище вашого dev.

## Чому місцеві синтетичні дані такі потужні

Якщо ви будуєте сегменти / персонализацію, вам потрібні дані, які:

- У вас достатньо варіацій, щоб зламати наївну евристику.
- Є безпечним для спільного використання (в коді, тестах, демонстраціях)
- Чи можна відшліфувати (так, щоб ви могли порівнювати зміни в моделях)

Справжні дані є протилежними: чутливі, безладні, важко пересуватися, і повні історичних відхилень.

Синтетичні дані дають вам три супердержави:

1. **Швидка ітерація**: змінити логіку сегментації, відновлення, повторний запуск.
2. **ХардінгCity in New Jersey USA**: симулювати дивну довгу дистанцію, яку ви виграли, у крихітному наборі даних dev.
3. **Перевірка з' єднання з поясненням**: ви можете *Перевірка кожного створеного поля* И признайте, что у вас есть то, почему со мной все в порядке.

```mermaid
flowchart LR
    Taxonomy[gadget-taxonomy.json] --> Gen[SampleData generator]
    Gen --> Products[products.json]
    Gen --> Profiles[profiles.json]
    Gen --> Images[images/*]
    Products --> Import[Import into Postgres]
    Profiles --> Import

    style Taxonomy stroke:#1971c2,stroke-width:3px
    style Gen stroke:#1971c2,stroke-width:3px
    style Import stroke:#2f9e44,stroke-width:3px
```

## Інструменталізація (Те, що насправді виконується)

Генератор живе в `Mostlylucid.SegmentCommerce.SampleData`.

Вона не має права на увазі, що це прагматичний хрест, який промовляє до:

- **Ольямаjapan. kgm** (локальний LLM) для структурованого покоління JSON.
- **ComfyUI** (локальна різниця) для зображень у стилі фотографії у стилі продукту.
- А **sysonomy JSON** за допомогою цього пункту можна зберігати зв' язок між виводами даних (категорій, типи, різновиди, варіанти, діапазони цін).

Налаштування буде переведено так, щоб ви могли здійснювати його за допомогою змінних середовища:

```csharp
// Mostlylucid.SegmentCommerce.SampleData/Program.cs
var configuration = new ConfigurationBuilder()
    .SetBasePath(AppContext.BaseDirectory)
    .AddJsonFile("appsettings.json", optional: true)
    .AddEnvironmentVariables("SAMPLEDATA_")
    .Build();
```

## Швидкий запуск

Ви зазвичай виконуєте три місцевих послуги поруч з генератором:

```mermaid
flowchart LR
    CLI[SampleData CLI] --> Ollama["Ollama
    http://localhost:11434"]
    CLI --> Comfy["ComfyUI
    http://localhost:8188"]
    CLI -. optional .-> DB[(Postgres)]

    style CLI stroke:#1971c2,stroke-width:3px
    style Ollama stroke:#1971c2,stroke-width:3px
    style Comfy stroke:#2f9e44,stroke-width:3px
    style DB stroke:#fab005,stroke-width:3px
```

Запустити генератор з кореневої теки експропріатора:

```bash
dotnet run --project Mostlylucid.SegmentCommerce.SampleData -- status
```

Після цього створіть набір даних:

```bash
# v1 generator: taxonomy + optional Ollama + optional ComfyUI
# Writes ./Output/products.json, ./Output/profiles.json, ./Output/images/...
dotnet run --project Mostlylucid.SegmentCommerce.SampleData -- generate --count 20
```

Корисні перемикачі:

```bash
# No LLM calls, taxonomy only
dotnet run --project Mostlylucid.SegmentCommerce.SampleData -- generate --no-ollama

# No ComfyUI images
dotnet run --project Mostlylucid.SegmentCommerce.SampleData -- generate --no-images

# Write into Postgres (uses configured connection string)
dotnet run --project Mostlylucid.SegmentCommerce.SampleData -- generate --db
```

Зауваження: якщо ComfyUI є наявним, генератор v1 повертається до зображень заповнювача (вона використовує `picsum.photos`Якщо ви хочете бути строго локальними, біжіть з `--no-images`.

## V2 Генератор: Sllers → Продукти → Клієнти → Порядок → Вмонтовані

Там також йде новіша команда генератора (`gen`) яка робить більш повну "плюс-функцію":

```bash
# v2 generator
# Writes dataset.json plus sellers/products/customers/orders split files
dotnet run --project Mostlylucid.SegmentCommerce.SampleData -- gen --sellers 50 --products 20 --customers 1000
```

Він оркеструє як багатофазовий трубопровод:

```mermaid
flowchart LR
    A[Sellers] --> B[Products]
    B --> C[Customers]
    C --> D[Orders]
    D --> E[Embeddings]

    B -. optional .-> I[ComfyUI images]

    style A stroke:#1971c2,stroke-width:3px
    style B stroke:#1971c2,stroke-width:3px
    style C stroke:#1971c2,stroke-width:3px
    style D stroke:#1971c2,stroke-width:3px
    style E stroke:#2f9e44,stroke-width:3px
    style I stroke:#2f9e44,stroke-width:3px
```

І ви можете побачити ці фази напряму в коді:

```csharp
// Mostlylucid.SegmentCommerce.SampleData/Services/DataGenerator.cs
// 1. Generate Sellers
// 2. Generate Products for each seller
// 3. Generate Customers
// 4. Generate Orders (with fake checkout data via Bogus)
// 5. Generate embeddings for all entities
```

### Вбудовування (local ONNX, кеш після першого запуску)

Генератор v2 може обчислювати вбудовування за допомогою моделі ONNX (типово: `all-MiniLM-L6-v2`). Під час першого запуску програма звантажує модель і vocab до вашої теки виводу.

Це означає:

- Перший запуск потребує доступу до мережі (модель звантаження)
- Подальші запуски є локальними і швидкими
- Якщо ви хочете, щоб мережа "no" коли-небудь, виконайте команду `--no-embeddings`

```csharp
// Mostlylucid.SegmentCommerce.SampleData/Services/EmbeddingService.cs
private const string ModelUrl = "https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2/resolve/main/onnx/model.onnx";
private const string VocabUrl = "https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2/resolve/main/vocab.txt";

// Download model if not exists
if (!File.Exists(_config.ModelPath))
{
    await DownloadFileAsync(ModelUrl, _config.ModelPath, ct);
}
```

## Як ми робимо це? (лише JSON)

Задаток створення продукту навмисно строгий: LLM повинен повернути лише JSON, з вбудованим прикладом схеми JSON.

```csharp
// Mostlylucid.SegmentCommerce.SampleData/Services/OllamaProductGenerator.cs
return $"""
    You are a product catalog generator for an e-commerce store. Generate {count} unique, realistic product listings for the \"{category.DisplayName}\" category.

    Category description: {category.Description}
    Example products in this category: {category.ExampleProducts}
    Price range: £{category.PriceRange.Min:F2} - £{category.PriceRange.Max:F2}

    For each product, provide:
    1. A compelling product name (realistic brand-style naming)
    2. A detailed description (2-3 sentences, highlighting key features and benefits)
    3. A realistic price within the range
    4. Optional original price if on sale (20-40% higher than current price)
    5. 3-5 relevant tags
    6. Whether it's trending (about 20% should be trending)
    7. Whether it's featured (about 15% should be featured)
    8. An image prompt for AI image generation (detailed, product photography style)
    9. 2-3 colour variants for the product

    IMPORTANT: Respond with ONLY valid JSON, no markdown formatting, no code blocks, no explanations.

    Generate {count} diverse products now:
    """;
```

Це має значення через те, що системи знизу (створення зображень + імпорт + вбудовування) хочуть структуровані дані. LM створюється *вхідні до трубопроводу*Я не пишу прозу.

### Відповідь LLM: аналізу JSON, або відступлення назад

LLM - це не компілятори. Навіть з "JS лише JSO," вам все ще потрібно відсторонюватися і граціозно повернути назад.

Генератор v2 робить це через маленького помічника (`LlmService`) що витягує перший `{...}` блок і зменшує його:

```csharp
// Mostlylucid.SegmentCommerce.SampleData/Services/LlmService.cs
var jsonStart = response.IndexOf('{');
var jsonEnd = response.LastIndexOf('}');

if (jsonStart >= 0 && jsonEnd > jsonStart)
{
    var jsonStr = response.Substring(jsonStart, jsonEnd - jsonStart + 1);
    return JsonSerializer.Deserialize<T>(jsonStr, new JsonSerializerOptions
    {
        PropertyNameCaseInsensitive = true
    });
}
```

А канал для загального створення явно перевіряє наявність і зниження доступності до детермінуючих шаблонів, якщо потрібно:

```mermaid
flowchart LR
    A[EnableLlm=true?] -->|no| F[Fallback templates]
    A -->|yes| B[GET /api/tags]
    B -->|model present| C[LLM JSON prompts]
    B -->|not available| F

    style A stroke:#1971c2,stroke-width:3px
    style C stroke:#2f9e44,stroke-width:3px
    style F stroke:#fab005,stroke-width:3px
```

### Приклад: клієнтська особа (v2)

Персонал для клієнтів короткий і структурований так, щоб його можна було швидко створити за допомогою невеличкої локальної моделі:

```csharp
// Mostlylucid.SegmentCommerce.SampleData/Services/DataGenerator.cs
var prompt = $$"""
    Generate a shopper persona interested in: {{string.Join(", ", categoryNames)}}.

    Return JSON only:
    {
      "persona": "Brief persona description (e.g. 'Tech enthusiast who values quality')",
      "name": "Realistic first name",
      "bio": "One sentence about their shopping habits",
      "age": 25,
      "shopping_style": "budget|value|premium|luxury",
      "preferred_categories": ["category1", "category2"]
    }
    """;
```

## ComfyUI: Production Photography через API

ComfyUI є великим, тому що він дає вам контрольований трубопровод (робочий потік), а не зображення у чорній скриньці.

Генератор:

1. Завантажує шаблон робочого процесу (`ComfyUI/workflows/product_image.json`)
2. Латкає запрошення до `CLIPTextEncode`
3. Черги `/prompt`
4. Опитування `/history/{promptId}`
5. Звантажує зображення через `/view?...`

```mermaid
sequenceDiagram
    participant Gen as SampleData
    participant Comfy as ComfyUI

    Gen->>Comfy: POST /prompt (workflow + prompt)
    Comfy-->>Gen: prompt_id
    loop poll
        Gen->>Comfy: GET /history/{prompt_id}
        Comfy-->>Gen: outputs / images
    end
    Gen->>Comfy: GET /view?filename=...&type=output
    Comfy-->>Gen: PNG bytes
```

Вибір моделі ComfyUI також латається до робочого процесу під час запуску (так, щоб ви могли поміняти контрольні пункти без редагування JSON):

```csharp
// Mostlylucid.SegmentCommerce.SampleData/Services/ComfyUIImageGenerator.cs
TryPatchCheckpoint(workflow, _config.ComfyUICheckpointName ?? "sd_xl_base_1.0.safetensors");
TryPatchRefiner(workflow, _config.ComfyUIRefinerName ?? "sd_xl_refiner_1.0.safetensors");
```

А латки спеціально прості і міцні.

```csharp
// Mostlylucid.SegmentCommerce.SampleData/Services/ComfyUIImageGenerator.cs
// Update CLIPTextEncode nodes with our prompt
if (classType == "CLIPTextEncode")
{
    var inputs = nodeObj["inputs"]?.AsObject();
    if (inputs != null && inputs.ContainsKey("text"))
    {
        var currentText = inputs["text"]?.GetValue<string>() ?? "";
        if (!currentText.Contains("bad") && !currentText.Contains("ugly") && !currentText.Contains("deformed"))
        {
            inputs["text"] = prompt;
        }
    }
}

// Update image dimensions
if (classType == "EmptyLatentImage")
{
    var inputs = nodeObj["inputs"]?.AsObject();
    if (inputs != null)
    {
        inputs["width"] = _config.ImageWidth;
        inputs["height"] = _config.ImageHeight;
    }
}
```

## Профілі і особи (корисно, а не похмуро)

Генератор v1 створює анонімні профілі, а потім збагачує їх за допомогою персони (все ще немає п' ятної). У результаті у вас з' являється реалістична " люди- } тестові дані без листів електронної пошти, адрес або будь- чого іншого, що ви могли б випадково відправити.

У V1, профілі, в основному, використовують гаш, так що там нічого не йде до }rese):

```csharp
// Mostlylucid.SegmentCommerce.SampleData/Services/ProfileGenerator.cs
var profileKey = Hash($"fp-{Guid.NewGuid():N}");

private static string Hash(string input)
{
    using var sha = SHA256.Create();
    var bytes = sha.ComputeHash(Encoding.UTF8.GetBytes(input));
    return Convert.ToHexString(bytes).ToLowerInvariant();
}
```

Це точно передає думки всієї серії: ви можете вилити те, що ви ніколи не зберігали.

```mermaid
flowchart TB
    Signals["Generated signals
    views/cart/purchase weights"] --> Persona["Persona enrichment
    Ollama JSON-only"]
    Persona --> Portrait[Portrait prompt]
    Portrait --> Comfy[ComfyUI]

    style Signals stroke:#1971c2,stroke-width:3px
    style Persona stroke:#1971c2,stroke-width:3px
    style Comfy stroke:#2f9e44,stroke-width:3px
```

## Доказ: що це дає вам нагоду доказати

Цей локальний трубопровод потужний, тому що він підтримує *моделювання перевірки*Не лише демонстрації.

- **Розум сегментації**: чи є сегменти, які ви розраховуєте, що ми маємо на увазі, коли ви переглядаєте назви продуктів/ґи і створюєте особи?
- **Рекомендація для пояснення**: чи можу я зрозуміти, чому потрібно вказувати на справжній сигнал, який ви можете перевірити?
- **Холодний початок**: якщо ви знищите набір даних і відтворюєте їх, чи прогнозується поведінка системи?
- **Перевірка регресії**: Регенерувати ту ж форму даних і переконатися, що ваші зміни не перекриють оцінки, оцінки, оцінки та інтерфейсу користувача.

Важлива витонченість: створенням обох частин *текст* і *зображення*Ви можете перевірити весь досвід продукту, а не лише кінцеву математику.

## Що наступне

**[Частина 2](/blog/zero-pii-customer-intelligence-part2)**Е-е-е-е-е-е-е-е-е-е-е-е-е-еф-еф-еф-еф-еф-еф-еф-еф-еф-еф-еф-еф-е...

**Частина 3** Шаблон вихідних, черга завдань і інтерфейс прозорості.

---


*Код генератора: `Mostlylucid.SegmentCommerce.SampleData/`*