Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@

## Unreleased

## [1.4.0] - 2026-08-21

### Added

- 旧Verification Platformおよび現行版で保存した入力JSONを、Web画面から
アップロードして計算できるようにした。旧JSONに存在しない項目は、JSONで
選択されている暖房・冷房方式に対応する現行デフォルトで補完し、明示された値と
未知の旧キーは保持する。
- JSON未選択、不正なUTF-8・JSON形式、オブジェクト以外の最上位構造、5 MBを超える
入力を計算前に検出し、計算ログへ理由を表示するようにした。

## [1.3.1] - 2026-08-20

### Fixed
Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,19 @@

## 公開Web版

**[Verification Platform Next ver.1.3.1をブラウザで開く](https://verification-platform-next-dnoeszca4a-an.a.run.app/)**
**[Verification Platform Next ver.1.4.0をブラウザで開く](https://verification-platform-next-dnoeszca4a-an.a.run.app/)**

公開Web版では、インストールせずに入力、計算、結果ファイルの取得を行えます。
計算は1件ずつ処理するため、混雑時は画面に表示される順番をお待ちください。
詳細CSVは通常計算時には作成せず、「出力ファイル」タブの
「CSVファイルを出力」を押したときだけ作成します。
「JSONファイルから計算」では、旧版と現行版の入力JSONを実行できます。旧JSONで
不足する追加項目は、現在版のデフォルト値で自動的に補完されます。
入力ファイルと計算成果物は一時的に保存されるため、機密情報や個人情報を含む
データはアップロードしないでください。

住宅の省エネルギー性能を検証するための計算エンジン、入力スキーマ、Gradio UIを
まとめたPythonモノレポです。正式版は **ver.1.3.1** です。
まとめたPythonモノレポです。正式版は **ver.1.4.0** です。

本リポジトリは、建築研究所が公開する住宅のエネルギー消費性能計算プログラム
`pyhees`を基礎とし、検証用の入力画面、床下空調などの拡張計算、数値回帰試験を
Expand Down
2 changes: 1 addition & 1 deletion apps/gradio/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"

[tool.poetry]
name = "verification-platform-app"
version = "1.3.1"
version = "1.4.0"
description = "Gradio application for Verification Platform"
authors = ["iguchi-lab"]
packages = [{ include = "verification_app", from = "src" }]
Expand Down
69 changes: 69 additions & 0 deletions apps/gradio/src/verification_app/form_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,25 @@ def build_app(
elem_classes=["default-reset-note"],
)

with gr.Accordion("JSONファイルから計算", open=False):
gr.Markdown(
"旧Verification Platformまたは現在の画面で保存した入力JSONを"
"そのまま実行できます。旧JSONに存在しない項目は、現在の"
"デフォルト値で補完します。アップロード内容は画面上の入力欄には"
"反映されないため、実行後の「計算入力」タブで確認してください。"
)
with gr.Row():
json_upload = gr.File(
label="入力JSONファイル",
file_types=[".json"],
file_count="single",
type="filepath",
)
json_run = gr.Button(
"JSONファイルをアップロードして計算",
variant="secondary",
)

components: dict[str, Any] = {}
containers: dict[str, Any] = {}
field_dom_ids: dict[str, str] = {}
Expand Down Expand Up @@ -318,6 +337,13 @@ def calculate(*raw_values: Any) -> tuple[Any, ...]:
result = calculation_service.run(values, include_graphs=False)
return _calculation_outputs(result)

def calculate_uploaded_json(uploaded_file: str | None) -> tuple[Any, ...]:
result = calculation_service.run_uploaded_json(
uploaded_file,
include_graphs=False,
)
return _calculation_outputs(result)

def generate_graphs(result: CalculationResult | None) -> tuple[Any, ...]:
if result is None:
return _graph_outputs(None)
Expand Down Expand Up @@ -400,6 +426,49 @@ def export_csv_files(
show_progress="full",
)

json_calculation_started = json_run.click(
_calculation_started_outputs,
outputs=[
status,
annual_summary,
preview,
log,
graph_status,
*graphs,
csv_status,
export_csv_button,
files,
],
queue=False,
api_visibility="private",
)
json_calculation_finished = json_calculation_started.then(
calculate_uploaded_json,
inputs=json_upload,
outputs=[
result_state,
status,
annual_summary,
preview,
log,
graph_status,
csv_status,
export_csv_button,
files,
],
concurrency_limit=1,
concurrency_id="calculation",
show_progress="full",
)
json_calculation_finished.then(
generate_graphs,
inputs=result_state,
outputs=[graph_status, log, *graphs],
concurrency_limit=1,
concurrency_id="calculation",
show_progress="full",
)

conditional_fields = tuple(
field for field in form.schema.fields if field.enabled_when is not None
)
Expand Down
64 changes: 61 additions & 3 deletions apps/gradio/src/verification_app/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from typing import Any, Callable, ContextManager, Mapping
from uuid import uuid4

from verification_core import build_input_data
from verification_core import build_input_data, load_compatible_input_json

CalculationFunction = Callable[[dict[str, Any]], Any]
VersionFunction = Callable[[], str]
Expand All @@ -24,6 +24,7 @@
CsvExportSessionFactory = Callable[[], ContextManager[Any]]

_CALCULATION_CWD_LOCK = threading.Lock()
_MAX_INPUT_JSON_BYTES = 5 * 1024 * 1024


def _captured_dataframe(csv_exports: Any | None, path: Path) -> Any | None:
Expand Down Expand Up @@ -96,14 +97,20 @@ def run(
values: Mapping[str, Any],
*,
include_graphs: bool = True,
prepared_input_data: Mapping[str, Any] | None = None,
input_source: str = "画面入力",
) -> CalculationResult:
input_data: dict[str, Any] | None = None
run_id: str | None = None
artifact_dir: Path | None = None
csv_exports: Any | None = None
output = io.StringIO()
try:
input_data = build_input_data(values)
input_data = (
dict(prepared_input_data)
if prepared_input_data is not None
else build_input_data(values)
)
_validate_case_name(input_data.get("case_name", "default"))
csv_session = (
self._csv_export_session()
Expand Down Expand Up @@ -150,6 +157,7 @@ def run(
annual_summary,
output.getvalue(),
pending_csv_count,
input_source,
),
files=files,
graph_status="計算完了後にグラフを表示します。",
Expand Down Expand Up @@ -190,6 +198,55 @@ def run(
graphs=(),
)

def run_uploaded_json(
self,
uploaded_file: str | Path | None,
*,
include_graphs: bool = True,
) -> CalculationResult:
"""Run an input JSON saved by an old or current platform version."""

try:
if uploaded_file is None:
raise ValueError("実行するJSONファイルを選択してください。")
path = Path(uploaded_file)
if not path.is_file():
raise ValueError("選択したJSONファイルを読み取れません。")
if path.stat().st_size > _MAX_INPUT_JSON_BYTES:
raise ValueError("入力JSONは5 MB以下にしてください。")
compatible = load_compatible_input_json(path.read_bytes())
count = len(compatible.supplemented_paths)
input_source = (
"アップロードJSON(不足項目なし)"
if count == 0
else f"アップロードJSON(不足していた{count}項目を現行デフォルトで補完)"
)
return self.run(
{},
include_graphs=include_graphs,
prepared_input_data=compatible.input_data,
input_source=input_source,
)
except Exception:
return CalculationResult(
succeeded=False,
status="❌ 入力JSONエラー",
input_data=None,
run_id=None,
artifact_dir=None,
log=_format_failure_log(
None,
None,
self._version_info(),
None,
"",
traceback.format_exc(),
),
files=(),
graph_status="計算完了後にグラフを表示します。",
graphs=(),
)

def generate_graphs(self, result: CalculationResult) -> CalculationResult:
if not result.succeeded or result.input_data is None:
return result
Expand Down Expand Up @@ -433,6 +490,7 @@ def _format_success_log(
annual_summary: AnnualSummary | None,
engine_log: str,
pending_csv_count: int = 0,
input_source: str = "画面入力",
) -> str:
output_step = (
f"4) 詳細CSV {pending_csv_count}件をメモリに保持(画面のボタンで出力)"
Expand All @@ -446,7 +504,7 @@ def _format_success_log(
f"成果物版: {version}",
"",
"===== 2. 実行した処理 =====",
"1) 画面入力を検証し、計算エンジン用input_dataへ変換",
f"1) {input_source}を検証し、計算エンジン用input_dataを準備",
"2) 暖房・冷房の8760時間計算を順番に実行",
"3) 一次エネルギー、未処理負荷、機器・ファン電力を集計",
output_step,
Expand Down
5 changes: 5 additions & 0 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ Phase 5 完了後は、このモノレポがUI、入力契約、計算エンジ
解釈する評価器は製品APIではなく、Phase 5で旧版との一致を確認するための非公開回帰専用
モジュールです。製品コードから旧フォーム評価器へ依存させません。

保存済み入力JSONを再実行する場合は、JSON内の明示値を優先し、選択されている
暖房・冷房方式に対応する現行デフォルトを不足キーだけへ補完します。これにより、
旧JSONを旧フォーム評価器へ戻さず、現行の入力契約と計算サービスへ直接合流させます。
未知の旧キーは比較・後方互換のため保持し、配列と単一値は部分的に書き換えません。

## 製品版と計算成果物

製品版の正本は`jjjexperiment.release`です。UI、入力契約、計算エンジンを
Expand Down
22 changes: 11 additions & 11 deletions docs/RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
Verification Platform Nextは、製品全体を1つの
[Semantic Versioning](https://semver.org/) で管理します。

- Pythonパッケージ版: `1.3.1`
- 表示名: `ver.1.3.1`
- Gitタグ: `v1.3.1`
- 成果物接尾辞: `_v1.3.1`
- Pythonパッケージ版: `1.4.0`
- 表示名: `ver.1.4.0`
- Gitタグ: `v1.4.0`
- 成果物接尾辞: `_v1.4.0`

製品版の正本は
`packages/pyhees-jjj/src/jjjexperiment/release.py`です。ルート、
Expand All @@ -23,10 +23,10 @@ Verification Platform Nextは、製品全体を1つの
成果物名には安定した版接尾辞を付けます。

```text
<case_name>_v1.3.1_input.json
<case_name>_v1.3.1_output1.csv
<case_name>_v1.3.1_output2.csv
<case_name>_v1.3.1_manifest.json
<case_name>_v1.4.0_input.json
<case_name>_v1.4.0_output1.csv
<case_name>_v1.4.0_output2.csv
<case_name>_v1.4.0_manifest.json
```

計算が正常終了すると、マニフェストへ次を記録します。
Expand Down Expand Up @@ -67,9 +67,9 @@ GitHub Actionsがすべて成功した後、PRをマージし、マージコミ
```bash
git switch main
git pull --ff-only
git tag -a v1.3.1 -m "Verification Platform Next ver.1.3.1"
git push origin v1.3.1
gh release create v1.3.1 --title "Verification Platform Next ver.1.3.1"
git tag -a v1.4.0 -m "Verification Platform Next ver.1.4.0"
git push origin v1.4.0
gh release create v1.4.0 --title "Verification Platform Next ver.1.4.0"
```

GitHub Releaseには`CHANGELOG.md`の該当版、試験結果、既知の制約を記載します。
Expand Down
18 changes: 18 additions & 0 deletions docs/input_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,24 @@ Verification Platform Nextの入力画面は、建築研究所の住宅のエネ
「入力をデフォルトに戻す」を押すと、全項目がデフォルト値へ戻り、選択した方式に
不要な項目も再び非表示になります。

### JSONファイルから計算する

画面上部の「JSONファイルから計算」を開くと、次の入力JSONをアップロードして
計算できます。

- 旧Verification Platformで保存した入力JSON
- Verification Platform Nextの計算結果に含まれる`*_input.json`

旧JSONに現在の追加項目がない場合は、その項目だけ現在版のデフォルト値で補完します。
JSONに記録されている既存項目は、デフォルトで上書きしません。辞書形式の階層は
不足キーごとに補完し、配列と単一の値はJSONの指定をそのまま使用します。

アップロードしたJSONは画面の入力欄を書き換えません。実際に計算へ使用した値は、
計算完了後の「計算入力」タブで確認できます。`climateFile`または`loadFile`に外部
ファイル名を指定したJSONを公開Web版で使う場合、その外部ファイル自体はJSONに
含まれないため利用できません。標準同梱データを使う場合は従来どおり`"-"`を指定
してください。

## 2. 入力する順番

| 順番 | セクション | 主な内容 |
Expand Down
2 changes: 1 addition & 1 deletion packages/pyhees-jjj/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"

[tool.poetry]
name = "pyhees-jjj"
version = "1.3.1"
version = "1.4.0"
description = "Pyheesの検証用のフォークプロジェクトです"
homepage = "https://github.com/izumi-system-development/pyhees-jjj"
authors = ["Pyhees Development Team"]
Expand Down
8 changes: 4 additions & 4 deletions packages/pyhees-jjj/src/jjjexperiment/release.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
from typing import Any, Mapping


VERSION = "1.3.1"
DISPLAY_VERSION = "ver.1.3.1"
RELEASE_DATE = "2026-08-20"
ARTIFACT_VERSION = "_v1.3.1"
VERSION = "1.4.0"
DISPLAY_VERSION = "ver.1.4.0"
RELEASE_DATE = "2026-08-21"
ARTIFACT_VERSION = "_v1.4.0"

UPSTREAM_PYHEES_VERSION = "3.10.0"
UPSTREAM_PYHEES_COMMIT = "d5224c4a01def00a8421bcd2fcc0d4b4a5b88644"
Expand Down
Loading