(2026/04/06 commit: 53f12097e2d9f4f481ca90b7df2ccee994073a97 )
hierarchical_result.json のスキーマ定義がプロジェクト内でどこに存在し、それぞれが一致しているかを調査した結果をまとめる。
| 場所 | 役割 | 備考 |
|---|---|---|
packages/analysis-core/src/analysis_core/steps/hierarchical_aggregation.py (37-56行) |
生成コードの TypedDict | Argument / Cluster のみ。ルートオブジェクトの型定義は無い |
packages/analysis-core/tests/e2e/schemas/hierarchical_result.py |
Pydantic スキーマ(テスト用) | HierarchicalResult / Argument / Cluster。バリデーションロジック付き |
apps/public-viewer/type.ts (61-99行) |
TypeScript 型定義 | Result / Argument / Cluster / Config。API層の追加フィールドも含む |
docs/development/plugin-output-data-structures.md (174-216行) |
ドキュメント | JSON例付きのフィールド説明 |
統一的な JSON Schema ファイル(.json 形式)は存在しない。
| フィールド | TypeScript (type.ts) |
Python TypedDict | Pydantic (テスト) | 実データ (新) | 実データ (旧) |
|---|---|---|---|---|---|
Argument.comment_id |
number |
str |
欠落 | int |
int |
Argument.attributes |
Record<string, string | number>? |
dict[str, str] | None |
dict[str, str] | None |
- | - |
Cluster.density_rank_percentile |
number (non-null) |
float | None |
float | None |
float |
None |
Result.comments |
Comments (必須) |
コード上 {} で出力 |
欠落 | 無し (新版) | 有り (旧版) |
Result.comment_num |
number (必須) |
コード上出力 | int (必須) |
有り | 無し (旧版) |
Result.filteredArgumentIds |
string[]? |
- | - | - | - |
Result.visibility |
ReportVisibility? |
- | - | - | - |
Result.visualizationConfig |
ReportDisplayConfig? |
- | - | - | - |
Cluster.allFiltered |
boolean? |
- | - | - | - |
Cluster.filtered |
boolean? |
- | - | - | - |
- 生成コード(Python)は
str(comment_id)としている →strのはず - しかし実データは
int→ 旧コードで生成された例が残っている可能性 - TypeScript側は
numberと定義 - Pydanticスキーマには そもそもフィールドが無い
- Python側:
dict[str, str](文字列のみ) - TypeScript側:
Record<string, string | number>(数値も許容) - 実際の生成コード(
hierarchical_aggregation.py308-312行)はint/floatもそのまま入れる → TypeScript側が正しい
- Python側:
float | None(正しい。ルートクラスタでは0を設定するが、旧データには無い) - TypeScript側:
number(nullを許容していない → バグの可能性)
- 旧コードでは実データを入れていたが、現在のコードではコメントアウトされ常に
{} - TypeScript側は型定義が残っている
- Pydanticスキーマからは既に削除済み
- → 非推奨化の過渡期
filteredArgumentIds,visibility,visualizationConfig,allFiltered,filteredはパイプライン出力にはなく、API/フロントエンド層で付加される- これらが TypeScript の
Result型に混在しているため、「パイプライン出力の型」と「API応答の型」の区別がない
JSONを生成するのはPython側であり、型の実態を決めるのは書く側。TypeScript側は消費するだけなので、生成側に合わせるのが自然。
-
Pydanticスキーマを
analysis-core/src/に昇格させ、正式なスキーマとするcomment_idを追加attributesの値型をstr | int | floatに修正- 生成コード(
hierarchical_aggregation.py)でもこのスキーマでバリデーションする
-
TypeScript側を2層に分離する
PipelineResult= パイプラインが出力する純粋なJSON構造(Python Pydantic と1:1対応)Result= API経由で受け取る構造(PipelineResult+visibility+visualizationConfig等)
-
commentsフィールドの廃止を明確化する- 現在は空オブジェクトを出力しているが使われていない
{
"arguments": [],
"clusters": [],
"comments": {},
"comment_num": 0,
"overview": "",
"propertyMap": {},
"translations": {},
"config": {}
}| フィールド | 型 | 説明 |
|---|---|---|
arguments |
Argument[] |
抽出された意見リスト |
clusters |
Cluster[] |
階層クラスタ構造 |
comments |
Record<string, {comment: string}> |
コメントマップ(現在は常に空) |
comment_num |
int |
元コメント総数 |
overview |
string |
LLM生成の全体概要 |
propertyMap |
Record<string, Record<string, any>> |
属性マッピング(カテゴリ等) |
translations |
Record<string, any> |
翻訳データ(設定時のみ) |
config |
Config |
パイプライン実行時の設定全体 |
{
"arg_id": "A1_0",
"argument": "意見本文",
"comment_id": "1",
"x": 0.123,
"y": -0.456,
"p": 0,
"cluster_ids": ["0", "1_3", "2_7"],
"attributes": {"author": "山田太郎"},
"url": "https://..."
}| フィールド | 型 | 説明 |
|---|---|---|
arg_id |
string |
"A{comment-id}_{index}" 形式の一意識別子 |
argument |
string |
抽出された意見テキスト |
comment_id |
string ※型不整合あり |
元コメントID |
x |
float |
UMAP X座標 |
y |
float |
UMAP Y座標 |
p |
float |
常に0(将来用) |
cluster_ids |
string[] |
先頭は必ず "0"、以降 "{level}_{num}" 形式 |
attributes |
Record<string, string | number> | null |
attribute_ プレフィックスの属性(プレフィックス除去済み) |
url |
string | null |
enable_source_link=true 時のみ |
{
"level": 1,
"id": "1_3",
"label": "交通",
"takeaway": "交通に関する意見",
"value": 42,
"parent": "0",
"density_rank_percentile": 0.83
}| フィールド | 型 | 説明 |
|---|---|---|
level |
int |
0=ルート、1以上=子階層 |
id |
string |
"0" or "{level}_{num}" 形式 |
label |
string |
LLM生成のラベル |
takeaway |
string |
LLM生成の要約 |
value |
int |
クラスタ内の意見数 |
parent |
string |
親クラスタID(ルートは空文字 "") |
density_rank_percentile |
float | null |
密度パーセンタイル |
- レベル0のルートクラスタ(id=
"0", label="全体")が必ず1つ存在する - 非ルートクラスタの
parentは有効なクラスタIDを参照する - 各 Argument の
cluster_idsは先頭に必ず"0"を含む - クラスタIDの形式:
"{level}_{cluster_number}"(例:"1_5","2_9","3_17")