Skip to main content
Glama
civilian7

korean-people-persona

by civilian7

korean-people-persona

A collection of tools for converting and searching the HuggingFace nvidia/Nemotron-Personas-Korea dataset (approx. 1 million rows, 9 parquet files) using SQLite.

Overview

  • Source: NVIDIA, Nemotron-Personas-Koreahttps://huggingface.co/datasets/nvidia/Nemotron-Personas-Korea

  • License: Follows the license terms on the original dataset page

  • DB File: database/persona.db

  • Original parquet: data/train-*-of-*.parquet

  • Tables: persona (main) + persona_fts (FTS5 external content index)

  • Target SQLite: 3.37+ (uses FTS5, STRICT tables, JSON1)

  • Python: 3.10 or higher (3.11+ recommended)

  • Dependencies: pyarrow >= 15.0, huggingface_hub >= 0.24 (see requirements.txt)

  • Disk Space: Approx. 5 GB (parquet ~2GB + DB ~3GB)

Related MCP server: Legal Search MCP

Data Source

Item

Value

Repository

nvidia/Nemotron-Personas-Korea

Files

train-0000{0..8}-of-00009.parquet (9 files)

Rows per file

Approx. 111,112

Total rows

1,000,000

Missing values

0 in all columns (NOT NULL guaranteed)

country

All South Korea (single value)

*_list

Python repr format strings → normalized to JSON arrays

Folder Structure

korean-people-persona/
├── data/                  # 원본 parquet (gitignore — 약 2GB)
│   └── train-*-of-*.parquet
├── database/              # 생성된 SQLite (gitignore — 약 3GB)
│   └── persona.db
├── src/
│   ├── convert/                # parquet → SQLite 변환기
│   │   ├── __init__.py
│   │   └── __main__.py
│   └── mcp_server/             # (예정) MCP 서버
├── build.sh / build.bat / build.ps1
├── requirements.txt
└── README.md

data/ and database/ are excluded via .gitignore due to their large size.

Downloading the Dataset

Choose one of the three methods. The resulting files must be placed in the data/ folder as train-*-of-*.parquet.

Automatically fetches if the src/convert package is missing:

pip install huggingface_hub pyarrow
PYTHONPATH=src python -m convert --download              # 없을 때만 받음
PYTHONPATH=src python -m convert --download --force-download   # 항상 재다운로드

2) Using huggingface-cli directly

pip install huggingface_hub
huggingface-cli download nvidia/Nemotron-Personas-Korea \
    --repo-type dataset \
    --include "train-*-of-*.parquet" \
    --local-dir ./data

3) git lfs clone

git lfs install
git clone https://huggingface.co/datasets/nvidia/Nemotron-Personas-Korea
mv Nemotron-Personas-Korea/train-*.parquet ./data/

Authentication: For private or gated models, huggingface-cli login or the HF_TOKEN environment variable is required. This dataset (as of the public release) can be downloaded without authentication.

Size: Total of 9 parquet files is approx. 1~2 GB.

Main Table persona

CREATE TABLE persona (
  uuid                       TEXT    PRIMARY KEY,                                  -- 32자 hex 문자열 (대시 없음)
  -- 페르소나 서술 (긴 한국어 텍스트) ----------------------------------------------
  persona                    TEXT    NOT NULL,                                     -- 핵심 1~2문장 요약
  professional_persona       TEXT    NOT NULL,                                     -- 직업/업무 페르소나
  sports_persona             TEXT    NOT NULL,                                     -- 스포츠/운동 페르소나
  arts_persona               TEXT    NOT NULL,                                     -- 예술/문화 페르소나
  travel_persona             TEXT    NOT NULL,                                     -- 여행 페르소나
  culinary_persona           TEXT    NOT NULL,                                     -- 식문화/요리 페르소나
  family_persona             TEXT    NOT NULL,                                     -- 가족 관계 페르소나
  cultural_background        TEXT    NOT NULL,                                     -- 문화·성장 배경 서술
  skills_and_expertise       TEXT    NOT NULL,                                     -- 보유 기술/전문성 서술
  hobbies_and_interests      TEXT    NOT NULL,                                     -- 취미·관심사 서술
  career_goals_and_ambitions TEXT    NOT NULL,                                     -- 향후 목표/포부
  -- 리스트 (JSON 배열로 저장) -----------------------------------------------------
  skills_and_expertise_list  TEXT    NOT NULL CHECK(json_valid(skills_and_expertise_list)),   -- 스킬 키워드 JSON 배열
  hobbies_and_interests_list TEXT    NOT NULL CHECK(json_valid(hobbies_and_interests_list)),  -- 취미 키워드 JSON 배열
  -- 인구통계 ---------------------------------------------------------------------
  sex              TEXT    NOT NULL,                                               -- 성별: 남자 / 여자
  age              INTEGER NOT NULL CHECK(age >= 0),                               -- 나이 (정수)
  marital_status   TEXT    NOT NULL,                                               -- 결혼상태 (4종: 미혼/기혼/이혼/사별 등)
  military_status  TEXT    NOT NULL,                                               -- 병역상태 (군필/해당없음 등)
  family_type      TEXT    NOT NULL,                                               -- 가구 유형 (39종: 1인 가구, 배우자와 자녀 등)
  housing_type     TEXT    NOT NULL,                                               -- 주거 형태 (6종: 아파트, 단독주택 등)
  education_level  TEXT    NOT NULL,                                               -- 최종 학력 (7종: 초등학교 ~ 대학원)
  bachelors_field  TEXT    NOT NULL,                                               -- 학사 전공 분야
  occupation       TEXT    NOT NULL,                                               -- 직업 (자유 텍스트)
  district         TEXT    NOT NULL,                                               -- 시군구 (예: 강남-서초)
  province         TEXT    NOT NULL,                                               -- 시도 (17종)
  country          TEXT    NOT NULL DEFAULT '대한민국'                             -- 국가 (단일값: 대한민국)
) STRICT;

Indexes

Name

Columns

Purpose

idx_persona_demo

(sex, age)

Sex/age distribution query

idx_persona_region

(province, district)

Regional filter

idx_persona_edu_occ

(education_level, occupation)

Education/occupation analysis

idx_persona_family

(family_type, marital_status)

Household/marital analysis

Column Definitions

Column

Description

Example

uuid

32-char hex string (no dashes). PK

03b4f36a18e6469386d0286dddd513c8

persona

Core 1-2 sentence summary

"A man in his 70s who has worked in agriculture all his life in a rural area..."

*_persona

Detailed persona by domain (paragraph length)

Occupation/Sports/Arts/Travel/Food/Family

cultural_background

Cultural/growth background description

skills_and_expertise

Skills description

skills_and_expertise_list

Keyword list for the above (JSON array)

["Excel proficiency","Document writing"]

hobbies_and_interests

Hobbies/interests description

hobbies_and_interests_list

Keyword list for the above (JSON array)

["Hiking","Fishing"]

career_goals_and_ambitions

Future goals

sex

Male / Female

age

Integer

marital_status

4 types

Single / Married / Divorced / Widowed, etc.

military_status

2 types

Served / N/A, etc.

family_type

39 types

Spouse and children, Single-person household, etc.

housing_type

6 types

Apartment, Detached house, etc.

education_level

7 types

Elementary ~ Graduate school

bachelors_field

Bachelor's major field

occupation

Occupation (free text)

district

City/County/District

Gangnam-Seocho

province

Province/City

Seoul, Gyeonggi, etc. (17 types)

country

Country

South Korea (single value)

Indexes 10 long Korean descriptive columns using the external content method.

CREATE VIRTUAL TABLE persona_fts USING fts5(
  professional_persona,
  sports_persona,
  arts_persona,
  travel_persona,
  culinary_persona,
  family_persona,
  cultural_background,
  skills_and_expertise,
  hobbies_and_interests,
  career_goals_and_ambitions,
  content='persona',
  content_rowid='rowid',
  tokenize='unicode61 remove_diacritics 2',
  prefix='2 3 4'
);

Tokenizer: unicode61 + 2/3/4 character prefix index. For Korean particle handling, prefix matching like hiking* is recommended during search. If morphological analysis is required, replace with a custom tokenizer based on mecab-ko / kiwi.

FTS Synchronization: Since the dataset is static, build once with INSERT INTO persona_fts(rowid, ...) SELECT .... Add triggers if changes are made.

AI Agent Utilization (MCP Server)

This repository provides an MCP (Model Context Protocol) server, allowing MCP-compatible agents like Claude Desktop, Cursor, and Cline to directly search and sample data.

Execution

PYTHONPATH=src python -m mcp_server          # stdio 서버 시작

Registration by Agent

All examples must replace the absolute path to the repository /abs/path/to/korean-people-persona with your own environment path. If you created a virtual environment (.venv), specifying the command as the Python inside the venv avoids dependency conflicts. (e.g., macOS/Linux /abs/path/.venv/bin/python, Windows C:/abs/path/.venv/Scripts/python.exe)

Claude Desktop

Config file location:

OS

Path

macOS

~/Library/Application Support/Claude/claude_desktop_config.json

Windows

%APPDATA%\Claude\claude_desktop_config.json

Linux

~/.config/Claude/claude_desktop_config.json

Or via the app menu: Settings → Developer → Edit Config.

{
  "mcpServers": {
    "korean-persona": {
      "command": "python",
      "args": ["-m", "mcp_server"],
      "env": {
        "PYTHONPATH": "/abs/path/to/korean-people-persona/src",
        "PYTHONIOENCODING": "utf-8"
      }
    }
  }
}

After saving, restart Claude Desktop → verify 5 tools appear in the hammer (🔨) icon at the bottom right of the chat window.

Claude Code (CLI)

Register in one line via CLI command:

claude mcp add korean-persona python -m mcp_server \
  -e PYTHONPATH=/abs/path/to/korean-people-persona/src \
  -e PYTHONIOENCODING=utf-8

Or write directly to .mcp.json in the project root or user settings ~/.claude/settings.json:

{
  "mcpServers": {
    "korean-persona": {
      "command": "python",
      "args": ["-m", "mcp_server"],
      "env": { "PYTHONPATH": "/abs/path/to/korean-people-persona/src" }
    }
  }
}

Verification: claude mcp list → After activation, tools can be called via the /mcp slash command.

Cursor

Project-specific .cursor/mcp.json or global user ~/.cursor/mcp.json:

{
  "mcpServers": {
    "korean-persona": {
      "command": "python",
      "args": ["-m", "mcp_server"],
      "env": { "PYTHONPATH": "/abs/path/to/korean-people-persona/src" }
    }
  }
}

Or use the Settings → MCP → Add new MCP Server UI. After restarting Cursor, call with @korean-persona.

ChatGPT (Developer Mode / Connectors)

ChatGPT's MCP integration operates based on HTTP/SSE transport (remote connector). Since this server is a stdio server, it cannot be registered as-is; it must be wrapped with an HTTP adapter.

  1. Run the server with the mcp SDK's HTTP transport:

    PYTHONPATH=src python -m mcp_server --transport sse --port 8765

    (Currently, this repository's server.py only calls stdio. To use HTTP/SSE mode, you need to add a branch for mcp.run(transport="sse", port=8765).)

  2. Expose externally via ngrok / Cloudflare Tunnel, etc.:

    ngrok http 8765
  3. ChatGPT → Settings → Connectors → Developer mode → Add custom connector

    • URL: https://<ngrok>/sse

    • Authentication: Add Bearer token header if necessary (MCP_AUTH_TOKEN)

  4. In a new chat, activate the connector in the Tools menu to call tools.

Security Warning: Since ChatGPT connectors expose tools outside the model, ensure the public URL is protected by authentication. For local-only use, we recommend using stdio-based Claude Desktop / Cursor.

Gemini CLI

Google gemini-cli user settings ~/.gemini/settings.json:

{
  "mcpServers": {
    "korean-persona": {
      "command": "python",
      "args": ["-m", "mcp_server"],
      "env": { "PYTHONPATH": "/abs/path/to/korean-people-persona/src" },
      "cwd": "/abs/path/to/korean-people-persona"
    }
  }
}

Verification: gemini mcp list (or /mcp command within CLI) → tools are automatically exposed.

Common Troubleshooting

Symptom

Cause / Solution

Tools not visible

Forgot to restart the app. Claude Desktop requires a full exit (including tray icon)

ModuleNotFoundError: mcp_server

Check if PYTHONPATH points to src (absolute path recommended)

Korean text garbled

Add env.PYTHONIOENCODING=utf-8 (especially on Windows)

python command not found

Use absolute path for command (e.g., /usr/bin/python3, C:/Python311/python.exe, venv python)

Permission error

Path spaces on Windows → use quotes or change path

Exposed Tools

Tool

Description

search_persona(query, fields, filters, limit, full)

FTS5 free-text search + demographic filter combination (BM25 sorted)

get_persona(uuid)

Retrieve full single persona by uuid

sample_persona(filters, n, full)

Conditional random sampling

aggregate(group_by, filters, limit)

Demographic GROUP BY COUNT

stats()

Full dataset statistics and available column guide

Agent Utilization Samples

1) Marketing Interview Simulation

"Sample 10 women aged 60+ who enjoy hiking, and simulate their reactions to the ad copy for a newly released knee brace."

Agent workflow:

  1. search_persona(query="hiking*", filters={"sex":"female","age_min":60}, limit=10, full=True)

  2. Inject each persona into the system prompt → generate 1 response per person evaluating the ad copy

  3. Summarize insights after response clustering

2) Region-based Character Casting

"Find a persona of a self-employed person in their 50s living in Yeongdo-gu, Busan, and organize it for use as a protagonist in a short story."

search_persona(
  filters={"province":"부산", "district_like":"%영도%",
           "age_min":50, "age_max":59,
           "occupation_like":"%자영%"},
  limit=5, full=True
)

3) Policy Impact Analysis

"Analyze the distribution to see which province has the highest number of single-person households aged 70+ whose highest level of education is elementary school."

aggregate(
  group_by=["province"],
  filters={"education_level":"초등학교", "age_min":70,
           "family_type_like":"%혼자%"},
  limit=20
)

4) Semantic Search + Citation

"Find a persona who grew up in a rural area and has grandchildren, and provide it along with a citation of their cultural_background."

search_persona(
  query='"농촌" AND 손주*',
  fields=["cultural_background", "family_persona"],
  limit=5, full=True
)

5) Synthetic Survey

"Stratified sample 100 people proportional to the national population distribution, then ask each of them, 'Do you agree with the introduction of a 4-day work week?'"

  1. aggregate(group_by=["province","sex","age"]) → calculate distribution ratios

  2. Call sample_persona according to the ratios for each province×sex×age group

  3. Request 1:1 responses from the LLM for each persona

  4. Aggregate results → calculate weighted approval/disapproval distribution

Direct Use (Code)

Call directly from Python without MCP:

import sys; sys.path.insert(0, "src")
from mcp_server import tools

tools.stats()
tools.search_persona(query="용접*", filters={"sex":"남자"}, limit=5)
tools.sample_persona(filters={"province":"제주"}, n=3, full=True)

Direct SQL Query

-- 1) 등산을 좋아하고 트로트 관련 언급이 있는 60대 여성
SELECT p.uuid, p.age, p.province, p.occupation
FROM persona_fts f
JOIN persona p ON p.rowid = f.rowid
WHERE persona_fts MATCH '등산* AND 트로트*'
  AND p.sex = '여자' AND p.age BETWEEN 60 AND 79
ORDER BY bm25(persona_fts) LIMIT 20;

-- 2) 특정 컬럼 검색 + 스니펫
SELECT p.uuid, snippet(persona_fts, 7, '<b>', '</b>', '...', 10) AS hit
FROM persona_fts f JOIN persona p ON p.rowid = f.rowid
WHERE f.skills_and_expertise MATCH '용접*' LIMIT 10;

-- 3) JSON 리스트 펼치기
SELECT p.uuid, j.value AS hobby
FROM persona p, json_each(p.hobbies_and_interests_list) j
WHERE j.value LIKE '%낚시%' LIMIT 10;

-- 4) 인구통계 분포
SELECT province, sex, COUNT(*) cnt
FROM persona GROUP BY province, sex ORDER BY cnt DESC;

PRAGMA Settings (Loading/Operation)

PRAGMA journal_mode = WAL;
PRAGMA synchronous  = NORMAL;
PRAGMA temp_store   = MEMORY;
PRAGMA cache_size   = -262144;   -- 256MB

Build Procedure

Wrapper scripts for each OS automatically create a virtual environment → install dependencies → download → convert.

Platform

Command

Linux / macOS

chmod +x build.sh && ./build.sh

Windows (cmd)

build.bat

Windows (PowerShell)

.\build.ps1

Re-download options are passed identically:

./build.sh --force-download
build.bat --force-download
.\build.ps1 --force-download

If you get an execution policy error in PowerShell: PowerShell -ExecutionPolicy Bypass -File .\build.ps1

Manual Execution

python -m venv .venv
# Linux/macOS: source .venv/bin/activate
# Windows:     .venv\Scripts\activate
pip install -r requirements.txt
PYTHONPATH=src python -m convert [--download] [--force-download]

Internal processing:

  1. (Optional) --download fetches missing parquet files from HuggingFace

  2. Create new persona.db (deletes existing file)

  3. Apply PRAGMA settings + create schema/indexes

  4. Sequentially read 9 parquet files, normalize row-by-row, and load via executemany (transaction unit: 1 file)

  5. *_list columns converted via ast.literal_evaljson.dumps(ensure_ascii=False)

  6. Create FTS5 virtual table + build once with INSERT ... SELECT

  7. INSERT INTO persona_fts(persona_fts) VALUES('optimize') followed by ANALYZE

  8. Exit after WAL checkpoint

Disk Estimation

  • Main table + indexes: approx. 1.5 ~ 2.5 GB

  • FTS5 including prefix: additional 1 ~ 3 GB

  • Total expected approx. 3 ~ 5 GB (updated after actual loading).

Related MCP Connectors

Related MCP Servers