kaneko-fa-selector 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- kaneko_fa_selector-0.2.0/PKG-INFO +299 -0
- kaneko_fa_selector-0.2.0/README.md +273 -0
- kaneko_fa_selector-0.2.0/pyproject.toml +47 -0
- kaneko_fa_selector-0.2.0/setup.cfg +4 -0
- kaneko_fa_selector-0.2.0/src/kaneko_fa_selector/__init__.py +137 -0
- kaneko_fa_selector-0.2.0/src/kaneko_fa_selector/__main__.py +74 -0
- kaneko_fa_selector-0.2.0/src/kaneko_fa_selector/engine.py +307 -0
- kaneko_fa_selector-0.2.0/src/kaneko_fa_selector/inputs.py +256 -0
- kaneko_fa_selector-0.2.0/src/kaneko_fa_selector/rules/kaneko_fa_rules.yaml +126 -0
- kaneko_fa_selector-0.2.0/src/kaneko_fa_selector.egg-info/PKG-INFO +299 -0
- kaneko_fa_selector-0.2.0/src/kaneko_fa_selector.egg-info/SOURCES.txt +15 -0
- kaneko_fa_selector-0.2.0/src/kaneko_fa_selector.egg-info/dependency_links.txt +1 -0
- kaneko_fa_selector-0.2.0/src/kaneko_fa_selector.egg-info/entry_points.txt +2 -0
- kaneko_fa_selector-0.2.0/src/kaneko_fa_selector.egg-info/requires.txt +9 -0
- kaneko_fa_selector-0.2.0/src/kaneko_fa_selector.egg-info/top_level.txt +1 -0
- kaneko_fa_selector-0.2.0/tests/test_app.py +28 -0
- kaneko_fa_selector-0.2.0/tests/test_selector.py +247 -0
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: kaneko-fa-selector
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: KANEKO flame arrester preselection rule engine (R1-R8): JSON in, JSON out
|
|
5
|
+
Author-email: stkengaposa832@gmail.com
|
|
6
|
+
Keywords: kaneko,flame arrester,rule engine,preselection
|
|
7
|
+
Classifier: Development Status :: 3 - Alpha
|
|
8
|
+
Classifier: Intended Audience :: Manufacturing
|
|
9
|
+
Classifier: Topic :: Scientific/Engineering
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Requires-Python: >=3.10
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
Requires-Dist: PyYAML>=6.0
|
|
20
|
+
Provides-Extra: app
|
|
21
|
+
Requires-Dist: streamlit>=1.35; extra == "app"
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
24
|
+
Requires-Dist: build>=1.0; extra == "dev"
|
|
25
|
+
Requires-Dist: twine>=5.0; extra == "dev"
|
|
26
|
+
|
|
27
|
+
# KANEKO FA Selector
|
|
28
|
+
|
|
29
|
+
Thư viện Python tiền chọn flame arrester KANEKO theo bộ luật R1–R8 (deterministic).
|
|
30
|
+
Gọi một hàm, nhận JSON. Kèm app demo Streamlit chạy trên nền thư viện và CLI.
|
|
31
|
+
|
|
32
|
+
> **Giới hạn kỹ thuật quan trọng.** Đây là bản demo / tiền chọn, không phải công cụ thiết kế đã được phê duyệt.
|
|
33
|
+
> Tài liệu nguồn mô tả bước R5 (lưu lượng / ΔP) nhưng **không** cung cấp điểm đường cong hay hệ số `(a, b)`,
|
|
34
|
+
> nên thư viện cố ý không bịa giá trị ΔP và không bao giờ báo R5 "đạt". Tập tra cứu khí chỉ là một phần nhỏ
|
|
35
|
+
> của bảng 215 chất; chất không nhận diện được sẽ không bị đoán. Acetylene luôn chuyển kỹ thuật.
|
|
36
|
+
> **Mọi model đề xuất đều là tiền chọn và phải được kỹ thuật KANEKO xác nhận trước khi báo giá.**
|
|
37
|
+
|
|
38
|
+
## Cài đặt
|
|
39
|
+
|
|
40
|
+
Thư viện chỉ phụ thuộc PyYAML, chạy trên Python 3.10 trở lên.
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# Từ PyPI (sau khi đã phát hành, xem mục "Phát hành lên PyPI")
|
|
44
|
+
pip install kaneko-fa-selector
|
|
45
|
+
|
|
46
|
+
# Từ thư mục mã nguồn này
|
|
47
|
+
pip install . # bản cố định
|
|
48
|
+
pip install -e ".[app,dev]" # editable (sửa code có hiệu lực ngay) + Streamlit + pytest + build + twine
|
|
49
|
+
|
|
50
|
+
# Từ file wheel đã build (xem mục "Đóng gói")
|
|
51
|
+
pip install dist/kaneko_fa_selector-0.2.0-py3-none-any.whl
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Không cần cài cũng chạy được: thêm thư mục `src` vào `PYTHONPATH` (app demo và test đã tự làm việc này).
|
|
55
|
+
|
|
56
|
+
## Đóng gói
|
|
57
|
+
|
|
58
|
+
```powershell
|
|
59
|
+
.\build_dist.ps1
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Script tự cài công cụ `build` vào `.venv` (hoặc Python mặc định nếu không có `.venv`), xoá `dist/` cũ rồi tạo:
|
|
63
|
+
|
|
64
|
+
- `dist/kaneko_fa_selector-0.2.0-py3-none-any.whl`: file cài đặt, dùng cho `pip install` / `requirements.txt`
|
|
65
|
+
- `dist/kaneko_fa_selector-0.2.0.tar.gz`: mã nguồn đóng gói (sdist)
|
|
66
|
+
|
|
67
|
+
Lệnh tương đương: `python -m build --outdir dist`. Trước khi build bản mới, tăng `__version__` trong
|
|
68
|
+
`src/kaneko_fa_selector/__init__.py` (tên file wheel đổi theo).
|
|
69
|
+
|
|
70
|
+
## Phát hành lên PyPI
|
|
71
|
+
|
|
72
|
+
PyPI là kho **công khai**: ai cũng tải được package, đọc được README và các bảng dữ liệu trong `engine.py`.
|
|
73
|
+
Chỉ phát hành khi chắc chắn dữ liệu KANEKO trong thư viện được phép công khai. Nếu chỉ dùng nội bộ, dùng wheel
|
|
74
|
+
hoặc Git riêng như mục "Dùng trong dự án khác".
|
|
75
|
+
|
|
76
|
+
Chuẩn bị một lần:
|
|
77
|
+
|
|
78
|
+
1. Tạo tài khoản tại https://pypi.org/account/register/ và https://test.pypi.org/account/register/ (để thử), bật xác thực hai lớp.
|
|
79
|
+
2. Tạo API token quyền upload tại https://pypi.org/manage/account/token/ (và trang tương ứng trên TestPyPI).
|
|
80
|
+
Lần đầu chọn scope "Entire account"; sau khi project đã tồn tại thì tạo token riêng cho project.
|
|
81
|
+
Token bắt đầu bằng `pypi-` và chỉ hiển thị một lần.
|
|
82
|
+
3. Khai báo giấy phép: thêm `license = "MIT"` (hoặc giấy phép bạn chọn) vào `[project]` trong `pyproject.toml`
|
|
83
|
+
và tạo file `LICENSE`. Không bắt buộc về kỹ thuật nhưng package công khai nên có.
|
|
84
|
+
4. Kiểm tra lại `authors` trong `pyproject.toml`: email ghi ở đó sẽ hiển thị công khai trên trang PyPI.
|
|
85
|
+
|
|
86
|
+
Mỗi lần phát hành:
|
|
87
|
+
|
|
88
|
+
```powershell
|
|
89
|
+
# 1. Tăng __version__ trong src/kaneko_fa_selector/__init__.py (PyPI không cho đăng lại phiên bản đã có)
|
|
90
|
+
|
|
91
|
+
# 2. Thử trên TestPyPI
|
|
92
|
+
$env:TEST_PYPI_TOKEN = "pypi-..."
|
|
93
|
+
.\publish.ps1 -Test
|
|
94
|
+
pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ kaneko-fa-selector
|
|
95
|
+
|
|
96
|
+
# 3. Phát hành thật
|
|
97
|
+
$env:PYPI_TOKEN = "pypi-..."
|
|
98
|
+
.\publish.ps1
|
|
99
|
+
pip install kaneko-fa-selector
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
`publish.ps1` build lại `dist/`, chạy `twine check --strict` rồi `twine upload`. Token chỉ nằm trong biến môi trường
|
|
103
|
+
của phiên PowerShell hiện tại, không ghi ra file. Nếu Windows chặn chạy script:
|
|
104
|
+
`powershell -ExecutionPolicy Bypass -File .\publish.ps1 -Test`.
|
|
105
|
+
|
|
106
|
+
## Dùng trong dự án khác
|
|
107
|
+
|
|
108
|
+
Đã phát hành lên PyPI thì chỉ cần một dòng trong `requirements.txt` của dự án kia:
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
kaneko-fa-selector>=0.2.0
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Chưa phát hành, hoặc muốn dùng nội bộ, chọn một trong ba cách:
|
|
115
|
+
|
|
116
|
+
1. **Chép file wheel vào dự án đó** (ví dụ thư mục `libs/`), đường dẫn tương đối tính từ nơi chạy `pip`:
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
libs/kaneko_fa_selector-0.2.0-py3-none-any.whl
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
2. **Trỏ thẳng tới file wheel trên máy** bằng URL `file:` (đường dẫn có dấu tiếng Việt / khoảng trắng phải percent-encode):
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
kaneko-fa-selector @ file:///C:/duong/dan/toi/kaneko_fa_selector_app/dist/kaneko_fa_selector-0.2.0-py3-none-any.whl
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Lấy URL đúng bằng:
|
|
129
|
+
`python -c "from pathlib import Path; print(Path('dist/kaneko_fa_selector-0.2.0-py3-none-any.whl').resolve().as_uri())"`
|
|
130
|
+
|
|
131
|
+
3. **Khi đã đưa mã nguồn lên Git** (GitHub / GitLab):
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
kaneko-fa-selector @ git+https://github.com/<tai-khoan>/<repo>.git
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Rồi trong dự án kia chạy `pip install -r requirements.txt`. Không dùng `requirements.txt` thì cài trực tiếp:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
pip install "C:\...\dist\kaneko_fa_selector-0.2.0-py3-none-any.whl" # từ wheel
|
|
141
|
+
pip install "C:\...\kaneko_fa_selector_app" # từ thư mục mã nguồn
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Kiểm tra nhanh sau khi cài:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
python -c "import kaneko_fa_selector as k; print(k.__version__)"
|
|
148
|
+
kaneko-fa-selector '{"gas_name": "methane", "operating_pressure_kpag": 8}'
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Dùng nhanh
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
from kaneko_fa_selector import select, select_json
|
|
155
|
+
|
|
156
|
+
# 1) Nhận chuỗi JSON
|
|
157
|
+
print(select_json({"gas_name": "methane", "operating_pressure_kpag": 8,
|
|
158
|
+
"service_location": "End-of-line", "requested_dn": 50}))
|
|
159
|
+
|
|
160
|
+
# 2) Nhận dict để xử lý tiếp trong Python
|
|
161
|
+
result = select(gas_name="hydrogen", operating_pressure_kpag=5,
|
|
162
|
+
service_location="In-line", pipe_geometry="Exact L/D known", ld_ratio=20,
|
|
163
|
+
ibexu_requirement="yes")
|
|
164
|
+
print(result["status"], result["primary_candidate"]["model_code"])
|
|
165
|
+
|
|
166
|
+
# 3) Đầu vào là chuỗi JSON (ví dụ nhận từ AI agent / HTTP)
|
|
167
|
+
print(select_json('{"gas_name": "ethanol", "operating_pressure_kpag": 12}'))
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Trường bắt buộc duy nhất là `operating_pressure_kpag`; các trường khác có mặc định bảo thủ.
|
|
171
|
+
|
|
172
|
+
Lỗi đầu vào:
|
|
173
|
+
|
|
174
|
+
- `select` ném `SelectorInputError` (thuộc tính `.errors` là danh sách thông báo).
|
|
175
|
+
- `select_json` mặc định **không** ném mà trả JSON với `"status": "INPUT_ERROR"` và danh sách `errors`.
|
|
176
|
+
Dùng `select_json(..., strict=True)` nếu muốn ném exception.
|
|
177
|
+
|
|
178
|
+
## CLI
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
python -m kaneko_fa_selector '{"gas_name": "methane", "operating_pressure_kpag": 8}'
|
|
182
|
+
python -m kaneko_fa_selector --file input.json --compact
|
|
183
|
+
type input.json | python -m kaneko_fa_selector
|
|
184
|
+
python -m kaneko_fa_selector --fields # mô tả các trường đầu vào
|
|
185
|
+
kaneko-fa-selector ... # lệnh tương đương sau khi pip install
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Đầu ra luôn là JSON UTF-8 (thêm `--ascii` để escape tiếng Việt). Đầu vào từ stdin / file là UTF-8 và
|
|
189
|
+
chấp nhận BOM (PowerShell hay chèn BOM khi pipe). Mã thoát `0` khi engine chạy xong
|
|
190
|
+
(kể cả `TECHNICAL_REVIEW` / `NO_CANDIDATE`), `2` khi đầu vào sai.
|
|
191
|
+
|
|
192
|
+
## Trường đầu vào
|
|
193
|
+
|
|
194
|
+
| Trường | Kiểu | Mặc định | Ghi chú |
|
|
195
|
+
|---|---|---|---|
|
|
196
|
+
| `gas_name` | chuỗi | `""` | Tra trong tập demo (không phân biệt hoa/thường). Không nhận diện được → `TECHNICAL_REVIEW`. |
|
|
197
|
+
| `manual_gas_group` | `IIA1` `IIA` `IIB1` `IIB2` `IIB3` `IIB` `IIC` | `null` | Ưu tiên hơn `gas_name`. Acetylene vẫn luôn dừng. |
|
|
198
|
+
| `operating_pressure_kpag` | số ≥ 0 | **bắt buộc** | Áp suất làm việc kPaG. |
|
|
199
|
+
| `service_location` | `End-of-line` \| `In-line` | `In-line` | Alias: `eol`, `end_of_line`, `inline`, `in_line`. |
|
|
200
|
+
| `pipe_geometry` | `Short, unobstructed` \| `Exact L/D known` \| `Long / obstacles / unknown` | `Long / obstacles / unknown` | Alias: `short`, `exact_ld`, `long`, `unknown`. |
|
|
201
|
+
| `ld_ratio` | số > 0 | `null` | Chỉ dùng khi `pipe_geometry = Exact L/D known`. Thiếu → mặc định DETONATION. |
|
|
202
|
+
| `ibexu_requirement` | `yes` \| `no` \| `unknown` | `unknown` | Nhận cả `true`/`false`, `Có`/`Không`/`Chưa rõ`. |
|
|
203
|
+
| `requested_dn` | số hoặc chuỗi | `null` | Chèn **nguyên văn** vào mã model (quy định nguồn), chỉ dùng để ưu tiên xếp hạng. |
|
|
204
|
+
| `ifrt_low_pressure` | bool | `false` | Dùng bảng IFRT áp thấp IBExU. |
|
|
205
|
+
| `flow_rate_m3h` | số > 0 | `null` | R5 hiện chưa tính ΔP; chỉ sinh cảnh báo. |
|
|
206
|
+
| `max_delta_p_kpa` | số > 0 | `null` | Như trên. |
|
|
207
|
+
| `families` | danh sách con của `IFRF` `IFRT` `FCRT` (hoặc chuỗi `"IFRF,IFRT"`) | cả ba | Luôn được sắp về thứ tự IFRF → IFRT → FCRT. |
|
|
208
|
+
|
|
209
|
+
Quy ước: trường tuỳ chọn không có dữ liệu thì để `null`, **không** dùng `0` (tránh L/D = 0 vô tình thành DEFLAGRATION).
|
|
210
|
+
Trường lạ bị từ chối để bắt lỗi gõ sai tên.
|
|
211
|
+
|
|
212
|
+
## Cấu trúc kết quả
|
|
213
|
+
|
|
214
|
+
| Khoá | Ý nghĩa |
|
|
215
|
+
|---|---|
|
|
216
|
+
| `status` | `PRELIMINARY` (có model tiền chọn) · `NO_CANDIDATE` (không model nào qua lọc) · `TECHNICAL_REVIEW` (dừng ở R1) · `INPUT_ERROR` (chỉ `select_json` / CLI) |
|
|
217
|
+
| `decision` | `REVIEW_REQUIRED` · `TECHNICAL_REVIEW` · `STOP` |
|
|
218
|
+
| `gas_group` | Nhóm khí đã xác định, hoặc `null` |
|
|
219
|
+
| `device_type` | `DEFLAGRATION` · `DETONATION` · `null` |
|
|
220
|
+
| `primary_candidate` | Model tiền chọn (R6) hoặc `null`: `series`, `dn`, `pressure_kpag`, `certified`, `gas_letter`, `reason`, `delta_p_status`, `delta_p`, `model_code` |
|
|
221
|
+
| `candidates` | Mọi ứng viên qua bộ lọc R3, đã xếp hạng |
|
|
222
|
+
| `upgrade_suggestions` | Gợi ý tham khảo R7 (tối đa 10, chỉ khi DEFLAGRATION) |
|
|
223
|
+
| `warnings` | Cảnh báo / việc cần kỹ thuật xác nhận (đã khử trùng lặp) |
|
|
224
|
+
| `steps` | Trace từng luật: `rule`, `status`, `detail` theo thứ tự R1 → R2 → R4 → R3 → R5 → R6 → R7 → R8 |
|
|
225
|
+
| `final_note` | Ghi chú cuối |
|
|
226
|
+
| `engine_version` | Phiên bản thư viện |
|
|
227
|
+
| `input` | Đầu vào sau chuẩn hoá (giá trị engine thực sự dùng) |
|
|
228
|
+
| `errors` | Chỉ có khi `status = INPUT_ERROR` |
|
|
229
|
+
|
|
230
|
+
Ví dụ rút gọn với đầu vào `{"gas_name": "methane", "operating_pressure_kpag": 8, "service_location": "End-of-line", "requested_dn": 50}`:
|
|
231
|
+
|
|
232
|
+
```json
|
|
233
|
+
{
|
|
234
|
+
"status": "PRELIMINARY",
|
|
235
|
+
"decision": "REVIEW_REQUIRED",
|
|
236
|
+
"gas_group": "IIA1",
|
|
237
|
+
"device_type": "DEFLAGRATION",
|
|
238
|
+
"primary_candidate": {"series": "IFRF", "dn": 50, "pressure_kpag": 50.0, "certified": false,
|
|
239
|
+
"model_code": "IFRF-50-BB-{IIA1:chưa xác nhận}-P50", "...": "..."},
|
|
240
|
+
"candidates": ["... 20 ứng viên ..."],
|
|
241
|
+
"warnings": ["Kết quả là TIỀN CHỌN; kỹ thuật KANEKO phải xác nhận model trước khi báo giá.", "..."],
|
|
242
|
+
"steps": [{"rule": "R1", "status": "PASS", "detail": "Nhóm khí IIA1."}, "..."],
|
|
243
|
+
"final_note": "Chỉ là tiền chọn. Không dùng để đặt hàng/báo giá trước khi kỹ thuật KANEKO xác nhận."
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## App demo Streamlit
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
pip install -e ".[app]"
|
|
251
|
+
streamlit run app.py
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## Test
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
pip install -e ".[dev]"
|
|
258
|
+
pytest
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
## Cấu trúc thư mục
|
|
262
|
+
|
|
263
|
+
- `src/kaneko_fa_selector/__init__.py`: API công khai `select`, `select_json`, `load_config`
|
|
264
|
+
- `src/kaneko_fa_selector/engine.py`: luật R1–R8 và các bảng tra (nguồn sự thật của logic)
|
|
265
|
+
- `src/kaneko_fa_selector/inputs.py`: chuẩn hoá / kiểm tra đầu vào, `SelectorInputError`
|
|
266
|
+
- `src/kaneko_fa_selector/__main__.py`: CLI
|
|
267
|
+
- `src/kaneko_fa_selector/rules/kaneko_fa_rules.yaml`: cấu hình tham chiếu (đi kèm package)
|
|
268
|
+
- `src/selector.py`: shim tương thích cho code cũ `from selector import ...`
|
|
269
|
+
- `app.py`: demo Streamlit
|
|
270
|
+
- `tests/`: test thư viện, CLI và app demo
|
|
271
|
+
- `pyproject.toml`: metadata và cấu hình đóng gói; `requirements.txt`: cài editable kèm Streamlit cho demo
|
|
272
|
+
- `build_dist.ps1`: build wheel + sdist vào `dist/` (thư mục `dist/` được `.gitignore` bỏ qua)
|
|
273
|
+
- `source_rule_engine.docx`, `docs_flowchart.png`, `van_relation.md`: tài liệu nguồn và sơ đồ dòng sản phẩm
|
|
274
|
+
|
|
275
|
+
## Đã triển khai từ tài liệu nguồn
|
|
276
|
+
|
|
277
|
+
- R1: nhóm khí, tra theo tên hoặc chọn tay; chất lạ và acetylene chuyển kỹ thuật
|
|
278
|
+
- R2: loại thiết bị theo end-of-line, L/D (ngưỡng 30 cho IIC, 50 cho nhóm khác) và điều kiện ống; mặc định bảo thủ DETONATION
|
|
279
|
+
- R4: nhánh IBExU (`yes` chỉ bản chứng nhận, `no` chỉ bản thường, `unknown` cả hai, ưu tiên bản thường)
|
|
280
|
+
- R3: lọc dòng sản phẩm theo bảng rating áp suất trong nguồn
|
|
281
|
+
- R5: báo rõ chưa có hệ số / điểm đường cong; không bịa ΔP
|
|
282
|
+
- R6: chọn ứng viên theo DN khách → DN nhỏ nhất → bản thường trước → rating thấp hơn
|
|
283
|
+
- R7: gợi ý nâng cấp khi kết quả là DEFLAGRATION
|
|
284
|
+
- R8: ghép mã model `{series}-{dn}-BB-{chữ nhóm}-P{rating}[-EX]` kèm cảnh báo
|
|
285
|
+
|
|
286
|
+
## Lưu ý khi đọc logic
|
|
287
|
+
|
|
288
|
+
- File YAML chỉ để tham chiếu / hiển thị. Các bảng tra thực sự nằm trong `engine.py`; sửa YAML không đổi kết quả.
|
|
289
|
+
- Loại thiết bị ở R2 (DEFLAGRATION / DETONATION) chưa được dùng để lọc dòng sản phẩm ở R3; engine xét mọi dòng trong `families`.
|
|
290
|
+
- Bước quy đổi cột biểu đồ A/B/C (`gas_column`) có trong code để tham chiếu nhưng `run_engine` chưa gọi.
|
|
291
|
+
- R7 chỉ là lát cắt của danh sách ứng viên (DN ≥ model chính), không tra bảng model Detonation riêng.
|
|
292
|
+
- Khi có `requested_dn`, mọi mã model đều mang DN đó; cột `dn` trong ứng viên mới là DN catalog thật.
|
|
293
|
+
|
|
294
|
+
## Cần bổ sung để dùng thật
|
|
295
|
+
|
|
296
|
+
1. Bảng đầy đủ 215 chất (EN/JP/MESG).
|
|
297
|
+
2. Đường cong lưu lượng KANEKO đã số hoá và/hoặc hệ số `(a, b)` được phê duyệt cho mọi tổ hợp, kèm khoảng Q hợp lệ.
|
|
298
|
+
3. Catalog DN / áp suất / model và ma trận chứng nhận chính xác.
|
|
299
|
+
4. Kỹ thuật KANEKO rà soát chính thức và bộ test case được chủ sở hữu phê duyệt.
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
# KANEKO FA Selector
|
|
2
|
+
|
|
3
|
+
Thư viện Python tiền chọn flame arrester KANEKO theo bộ luật R1–R8 (deterministic).
|
|
4
|
+
Gọi một hàm, nhận JSON. Kèm app demo Streamlit chạy trên nền thư viện và CLI.
|
|
5
|
+
|
|
6
|
+
> **Giới hạn kỹ thuật quan trọng.** Đây là bản demo / tiền chọn, không phải công cụ thiết kế đã được phê duyệt.
|
|
7
|
+
> Tài liệu nguồn mô tả bước R5 (lưu lượng / ΔP) nhưng **không** cung cấp điểm đường cong hay hệ số `(a, b)`,
|
|
8
|
+
> nên thư viện cố ý không bịa giá trị ΔP và không bao giờ báo R5 "đạt". Tập tra cứu khí chỉ là một phần nhỏ
|
|
9
|
+
> của bảng 215 chất; chất không nhận diện được sẽ không bị đoán. Acetylene luôn chuyển kỹ thuật.
|
|
10
|
+
> **Mọi model đề xuất đều là tiền chọn và phải được kỹ thuật KANEKO xác nhận trước khi báo giá.**
|
|
11
|
+
|
|
12
|
+
## Cài đặt
|
|
13
|
+
|
|
14
|
+
Thư viện chỉ phụ thuộc PyYAML, chạy trên Python 3.10 trở lên.
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# Từ PyPI (sau khi đã phát hành, xem mục "Phát hành lên PyPI")
|
|
18
|
+
pip install kaneko-fa-selector
|
|
19
|
+
|
|
20
|
+
# Từ thư mục mã nguồn này
|
|
21
|
+
pip install . # bản cố định
|
|
22
|
+
pip install -e ".[app,dev]" # editable (sửa code có hiệu lực ngay) + Streamlit + pytest + build + twine
|
|
23
|
+
|
|
24
|
+
# Từ file wheel đã build (xem mục "Đóng gói")
|
|
25
|
+
pip install dist/kaneko_fa_selector-0.2.0-py3-none-any.whl
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Không cần cài cũng chạy được: thêm thư mục `src` vào `PYTHONPATH` (app demo và test đã tự làm việc này).
|
|
29
|
+
|
|
30
|
+
## Đóng gói
|
|
31
|
+
|
|
32
|
+
```powershell
|
|
33
|
+
.\build_dist.ps1
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Script tự cài công cụ `build` vào `.venv` (hoặc Python mặc định nếu không có `.venv`), xoá `dist/` cũ rồi tạo:
|
|
37
|
+
|
|
38
|
+
- `dist/kaneko_fa_selector-0.2.0-py3-none-any.whl`: file cài đặt, dùng cho `pip install` / `requirements.txt`
|
|
39
|
+
- `dist/kaneko_fa_selector-0.2.0.tar.gz`: mã nguồn đóng gói (sdist)
|
|
40
|
+
|
|
41
|
+
Lệnh tương đương: `python -m build --outdir dist`. Trước khi build bản mới, tăng `__version__` trong
|
|
42
|
+
`src/kaneko_fa_selector/__init__.py` (tên file wheel đổi theo).
|
|
43
|
+
|
|
44
|
+
## Phát hành lên PyPI
|
|
45
|
+
|
|
46
|
+
PyPI là kho **công khai**: ai cũng tải được package, đọc được README và các bảng dữ liệu trong `engine.py`.
|
|
47
|
+
Chỉ phát hành khi chắc chắn dữ liệu KANEKO trong thư viện được phép công khai. Nếu chỉ dùng nội bộ, dùng wheel
|
|
48
|
+
hoặc Git riêng như mục "Dùng trong dự án khác".
|
|
49
|
+
|
|
50
|
+
Chuẩn bị một lần:
|
|
51
|
+
|
|
52
|
+
1. Tạo tài khoản tại https://pypi.org/account/register/ và https://test.pypi.org/account/register/ (để thử), bật xác thực hai lớp.
|
|
53
|
+
2. Tạo API token quyền upload tại https://pypi.org/manage/account/token/ (và trang tương ứng trên TestPyPI).
|
|
54
|
+
Lần đầu chọn scope "Entire account"; sau khi project đã tồn tại thì tạo token riêng cho project.
|
|
55
|
+
Token bắt đầu bằng `pypi-` và chỉ hiển thị một lần.
|
|
56
|
+
3. Khai báo giấy phép: thêm `license = "MIT"` (hoặc giấy phép bạn chọn) vào `[project]` trong `pyproject.toml`
|
|
57
|
+
và tạo file `LICENSE`. Không bắt buộc về kỹ thuật nhưng package công khai nên có.
|
|
58
|
+
4. Kiểm tra lại `authors` trong `pyproject.toml`: email ghi ở đó sẽ hiển thị công khai trên trang PyPI.
|
|
59
|
+
|
|
60
|
+
Mỗi lần phát hành:
|
|
61
|
+
|
|
62
|
+
```powershell
|
|
63
|
+
# 1. Tăng __version__ trong src/kaneko_fa_selector/__init__.py (PyPI không cho đăng lại phiên bản đã có)
|
|
64
|
+
|
|
65
|
+
# 2. Thử trên TestPyPI
|
|
66
|
+
$env:TEST_PYPI_TOKEN = "pypi-..."
|
|
67
|
+
.\publish.ps1 -Test
|
|
68
|
+
pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ kaneko-fa-selector
|
|
69
|
+
|
|
70
|
+
# 3. Phát hành thật
|
|
71
|
+
$env:PYPI_TOKEN = "pypi-..."
|
|
72
|
+
.\publish.ps1
|
|
73
|
+
pip install kaneko-fa-selector
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
`publish.ps1` build lại `dist/`, chạy `twine check --strict` rồi `twine upload`. Token chỉ nằm trong biến môi trường
|
|
77
|
+
của phiên PowerShell hiện tại, không ghi ra file. Nếu Windows chặn chạy script:
|
|
78
|
+
`powershell -ExecutionPolicy Bypass -File .\publish.ps1 -Test`.
|
|
79
|
+
|
|
80
|
+
## Dùng trong dự án khác
|
|
81
|
+
|
|
82
|
+
Đã phát hành lên PyPI thì chỉ cần một dòng trong `requirements.txt` của dự án kia:
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
kaneko-fa-selector>=0.2.0
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Chưa phát hành, hoặc muốn dùng nội bộ, chọn một trong ba cách:
|
|
89
|
+
|
|
90
|
+
1. **Chép file wheel vào dự án đó** (ví dụ thư mục `libs/`), đường dẫn tương đối tính từ nơi chạy `pip`:
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
libs/kaneko_fa_selector-0.2.0-py3-none-any.whl
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
2. **Trỏ thẳng tới file wheel trên máy** bằng URL `file:` (đường dẫn có dấu tiếng Việt / khoảng trắng phải percent-encode):
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
kaneko-fa-selector @ file:///C:/duong/dan/toi/kaneko_fa_selector_app/dist/kaneko_fa_selector-0.2.0-py3-none-any.whl
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Lấy URL đúng bằng:
|
|
103
|
+
`python -c "from pathlib import Path; print(Path('dist/kaneko_fa_selector-0.2.0-py3-none-any.whl').resolve().as_uri())"`
|
|
104
|
+
|
|
105
|
+
3. **Khi đã đưa mã nguồn lên Git** (GitHub / GitLab):
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
kaneko-fa-selector @ git+https://github.com/<tai-khoan>/<repo>.git
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Rồi trong dự án kia chạy `pip install -r requirements.txt`. Không dùng `requirements.txt` thì cài trực tiếp:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
pip install "C:\...\dist\kaneko_fa_selector-0.2.0-py3-none-any.whl" # từ wheel
|
|
115
|
+
pip install "C:\...\kaneko_fa_selector_app" # từ thư mục mã nguồn
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Kiểm tra nhanh sau khi cài:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
python -c "import kaneko_fa_selector as k; print(k.__version__)"
|
|
122
|
+
kaneko-fa-selector '{"gas_name": "methane", "operating_pressure_kpag": 8}'
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Dùng nhanh
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
from kaneko_fa_selector import select, select_json
|
|
129
|
+
|
|
130
|
+
# 1) Nhận chuỗi JSON
|
|
131
|
+
print(select_json({"gas_name": "methane", "operating_pressure_kpag": 8,
|
|
132
|
+
"service_location": "End-of-line", "requested_dn": 50}))
|
|
133
|
+
|
|
134
|
+
# 2) Nhận dict để xử lý tiếp trong Python
|
|
135
|
+
result = select(gas_name="hydrogen", operating_pressure_kpag=5,
|
|
136
|
+
service_location="In-line", pipe_geometry="Exact L/D known", ld_ratio=20,
|
|
137
|
+
ibexu_requirement="yes")
|
|
138
|
+
print(result["status"], result["primary_candidate"]["model_code"])
|
|
139
|
+
|
|
140
|
+
# 3) Đầu vào là chuỗi JSON (ví dụ nhận từ AI agent / HTTP)
|
|
141
|
+
print(select_json('{"gas_name": "ethanol", "operating_pressure_kpag": 12}'))
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Trường bắt buộc duy nhất là `operating_pressure_kpag`; các trường khác có mặc định bảo thủ.
|
|
145
|
+
|
|
146
|
+
Lỗi đầu vào:
|
|
147
|
+
|
|
148
|
+
- `select` ném `SelectorInputError` (thuộc tính `.errors` là danh sách thông báo).
|
|
149
|
+
- `select_json` mặc định **không** ném mà trả JSON với `"status": "INPUT_ERROR"` và danh sách `errors`.
|
|
150
|
+
Dùng `select_json(..., strict=True)` nếu muốn ném exception.
|
|
151
|
+
|
|
152
|
+
## CLI
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
python -m kaneko_fa_selector '{"gas_name": "methane", "operating_pressure_kpag": 8}'
|
|
156
|
+
python -m kaneko_fa_selector --file input.json --compact
|
|
157
|
+
type input.json | python -m kaneko_fa_selector
|
|
158
|
+
python -m kaneko_fa_selector --fields # mô tả các trường đầu vào
|
|
159
|
+
kaneko-fa-selector ... # lệnh tương đương sau khi pip install
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Đầu ra luôn là JSON UTF-8 (thêm `--ascii` để escape tiếng Việt). Đầu vào từ stdin / file là UTF-8 và
|
|
163
|
+
chấp nhận BOM (PowerShell hay chèn BOM khi pipe). Mã thoát `0` khi engine chạy xong
|
|
164
|
+
(kể cả `TECHNICAL_REVIEW` / `NO_CANDIDATE`), `2` khi đầu vào sai.
|
|
165
|
+
|
|
166
|
+
## Trường đầu vào
|
|
167
|
+
|
|
168
|
+
| Trường | Kiểu | Mặc định | Ghi chú |
|
|
169
|
+
|---|---|---|---|
|
|
170
|
+
| `gas_name` | chuỗi | `""` | Tra trong tập demo (không phân biệt hoa/thường). Không nhận diện được → `TECHNICAL_REVIEW`. |
|
|
171
|
+
| `manual_gas_group` | `IIA1` `IIA` `IIB1` `IIB2` `IIB3` `IIB` `IIC` | `null` | Ưu tiên hơn `gas_name`. Acetylene vẫn luôn dừng. |
|
|
172
|
+
| `operating_pressure_kpag` | số ≥ 0 | **bắt buộc** | Áp suất làm việc kPaG. |
|
|
173
|
+
| `service_location` | `End-of-line` \| `In-line` | `In-line` | Alias: `eol`, `end_of_line`, `inline`, `in_line`. |
|
|
174
|
+
| `pipe_geometry` | `Short, unobstructed` \| `Exact L/D known` \| `Long / obstacles / unknown` | `Long / obstacles / unknown` | Alias: `short`, `exact_ld`, `long`, `unknown`. |
|
|
175
|
+
| `ld_ratio` | số > 0 | `null` | Chỉ dùng khi `pipe_geometry = Exact L/D known`. Thiếu → mặc định DETONATION. |
|
|
176
|
+
| `ibexu_requirement` | `yes` \| `no` \| `unknown` | `unknown` | Nhận cả `true`/`false`, `Có`/`Không`/`Chưa rõ`. |
|
|
177
|
+
| `requested_dn` | số hoặc chuỗi | `null` | Chèn **nguyên văn** vào mã model (quy định nguồn), chỉ dùng để ưu tiên xếp hạng. |
|
|
178
|
+
| `ifrt_low_pressure` | bool | `false` | Dùng bảng IFRT áp thấp IBExU. |
|
|
179
|
+
| `flow_rate_m3h` | số > 0 | `null` | R5 hiện chưa tính ΔP; chỉ sinh cảnh báo. |
|
|
180
|
+
| `max_delta_p_kpa` | số > 0 | `null` | Như trên. |
|
|
181
|
+
| `families` | danh sách con của `IFRF` `IFRT` `FCRT` (hoặc chuỗi `"IFRF,IFRT"`) | cả ba | Luôn được sắp về thứ tự IFRF → IFRT → FCRT. |
|
|
182
|
+
|
|
183
|
+
Quy ước: trường tuỳ chọn không có dữ liệu thì để `null`, **không** dùng `0` (tránh L/D = 0 vô tình thành DEFLAGRATION).
|
|
184
|
+
Trường lạ bị từ chối để bắt lỗi gõ sai tên.
|
|
185
|
+
|
|
186
|
+
## Cấu trúc kết quả
|
|
187
|
+
|
|
188
|
+
| Khoá | Ý nghĩa |
|
|
189
|
+
|---|---|
|
|
190
|
+
| `status` | `PRELIMINARY` (có model tiền chọn) · `NO_CANDIDATE` (không model nào qua lọc) · `TECHNICAL_REVIEW` (dừng ở R1) · `INPUT_ERROR` (chỉ `select_json` / CLI) |
|
|
191
|
+
| `decision` | `REVIEW_REQUIRED` · `TECHNICAL_REVIEW` · `STOP` |
|
|
192
|
+
| `gas_group` | Nhóm khí đã xác định, hoặc `null` |
|
|
193
|
+
| `device_type` | `DEFLAGRATION` · `DETONATION` · `null` |
|
|
194
|
+
| `primary_candidate` | Model tiền chọn (R6) hoặc `null`: `series`, `dn`, `pressure_kpag`, `certified`, `gas_letter`, `reason`, `delta_p_status`, `delta_p`, `model_code` |
|
|
195
|
+
| `candidates` | Mọi ứng viên qua bộ lọc R3, đã xếp hạng |
|
|
196
|
+
| `upgrade_suggestions` | Gợi ý tham khảo R7 (tối đa 10, chỉ khi DEFLAGRATION) |
|
|
197
|
+
| `warnings` | Cảnh báo / việc cần kỹ thuật xác nhận (đã khử trùng lặp) |
|
|
198
|
+
| `steps` | Trace từng luật: `rule`, `status`, `detail` theo thứ tự R1 → R2 → R4 → R3 → R5 → R6 → R7 → R8 |
|
|
199
|
+
| `final_note` | Ghi chú cuối |
|
|
200
|
+
| `engine_version` | Phiên bản thư viện |
|
|
201
|
+
| `input` | Đầu vào sau chuẩn hoá (giá trị engine thực sự dùng) |
|
|
202
|
+
| `errors` | Chỉ có khi `status = INPUT_ERROR` |
|
|
203
|
+
|
|
204
|
+
Ví dụ rút gọn với đầu vào `{"gas_name": "methane", "operating_pressure_kpag": 8, "service_location": "End-of-line", "requested_dn": 50}`:
|
|
205
|
+
|
|
206
|
+
```json
|
|
207
|
+
{
|
|
208
|
+
"status": "PRELIMINARY",
|
|
209
|
+
"decision": "REVIEW_REQUIRED",
|
|
210
|
+
"gas_group": "IIA1",
|
|
211
|
+
"device_type": "DEFLAGRATION",
|
|
212
|
+
"primary_candidate": {"series": "IFRF", "dn": 50, "pressure_kpag": 50.0, "certified": false,
|
|
213
|
+
"model_code": "IFRF-50-BB-{IIA1:chưa xác nhận}-P50", "...": "..."},
|
|
214
|
+
"candidates": ["... 20 ứng viên ..."],
|
|
215
|
+
"warnings": ["Kết quả là TIỀN CHỌN; kỹ thuật KANEKO phải xác nhận model trước khi báo giá.", "..."],
|
|
216
|
+
"steps": [{"rule": "R1", "status": "PASS", "detail": "Nhóm khí IIA1."}, "..."],
|
|
217
|
+
"final_note": "Chỉ là tiền chọn. Không dùng để đặt hàng/báo giá trước khi kỹ thuật KANEKO xác nhận."
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## App demo Streamlit
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
pip install -e ".[app]"
|
|
225
|
+
streamlit run app.py
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## Test
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
pip install -e ".[dev]"
|
|
232
|
+
pytest
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## Cấu trúc thư mục
|
|
236
|
+
|
|
237
|
+
- `src/kaneko_fa_selector/__init__.py`: API công khai `select`, `select_json`, `load_config`
|
|
238
|
+
- `src/kaneko_fa_selector/engine.py`: luật R1–R8 và các bảng tra (nguồn sự thật của logic)
|
|
239
|
+
- `src/kaneko_fa_selector/inputs.py`: chuẩn hoá / kiểm tra đầu vào, `SelectorInputError`
|
|
240
|
+
- `src/kaneko_fa_selector/__main__.py`: CLI
|
|
241
|
+
- `src/kaneko_fa_selector/rules/kaneko_fa_rules.yaml`: cấu hình tham chiếu (đi kèm package)
|
|
242
|
+
- `src/selector.py`: shim tương thích cho code cũ `from selector import ...`
|
|
243
|
+
- `app.py`: demo Streamlit
|
|
244
|
+
- `tests/`: test thư viện, CLI và app demo
|
|
245
|
+
- `pyproject.toml`: metadata và cấu hình đóng gói; `requirements.txt`: cài editable kèm Streamlit cho demo
|
|
246
|
+
- `build_dist.ps1`: build wheel + sdist vào `dist/` (thư mục `dist/` được `.gitignore` bỏ qua)
|
|
247
|
+
- `source_rule_engine.docx`, `docs_flowchart.png`, `van_relation.md`: tài liệu nguồn và sơ đồ dòng sản phẩm
|
|
248
|
+
|
|
249
|
+
## Đã triển khai từ tài liệu nguồn
|
|
250
|
+
|
|
251
|
+
- R1: nhóm khí, tra theo tên hoặc chọn tay; chất lạ và acetylene chuyển kỹ thuật
|
|
252
|
+
- R2: loại thiết bị theo end-of-line, L/D (ngưỡng 30 cho IIC, 50 cho nhóm khác) và điều kiện ống; mặc định bảo thủ DETONATION
|
|
253
|
+
- R4: nhánh IBExU (`yes` chỉ bản chứng nhận, `no` chỉ bản thường, `unknown` cả hai, ưu tiên bản thường)
|
|
254
|
+
- R3: lọc dòng sản phẩm theo bảng rating áp suất trong nguồn
|
|
255
|
+
- R5: báo rõ chưa có hệ số / điểm đường cong; không bịa ΔP
|
|
256
|
+
- R6: chọn ứng viên theo DN khách → DN nhỏ nhất → bản thường trước → rating thấp hơn
|
|
257
|
+
- R7: gợi ý nâng cấp khi kết quả là DEFLAGRATION
|
|
258
|
+
- R8: ghép mã model `{series}-{dn}-BB-{chữ nhóm}-P{rating}[-EX]` kèm cảnh báo
|
|
259
|
+
|
|
260
|
+
## Lưu ý khi đọc logic
|
|
261
|
+
|
|
262
|
+
- File YAML chỉ để tham chiếu / hiển thị. Các bảng tra thực sự nằm trong `engine.py`; sửa YAML không đổi kết quả.
|
|
263
|
+
- Loại thiết bị ở R2 (DEFLAGRATION / DETONATION) chưa được dùng để lọc dòng sản phẩm ở R3; engine xét mọi dòng trong `families`.
|
|
264
|
+
- Bước quy đổi cột biểu đồ A/B/C (`gas_column`) có trong code để tham chiếu nhưng `run_engine` chưa gọi.
|
|
265
|
+
- R7 chỉ là lát cắt của danh sách ứng viên (DN ≥ model chính), không tra bảng model Detonation riêng.
|
|
266
|
+
- Khi có `requested_dn`, mọi mã model đều mang DN đó; cột `dn` trong ứng viên mới là DN catalog thật.
|
|
267
|
+
|
|
268
|
+
## Cần bổ sung để dùng thật
|
|
269
|
+
|
|
270
|
+
1. Bảng đầy đủ 215 chất (EN/JP/MESG).
|
|
271
|
+
2. Đường cong lưu lượng KANEKO đã số hoá và/hoặc hệ số `(a, b)` được phê duyệt cho mọi tổ hợp, kèm khoảng Q hợp lệ.
|
|
272
|
+
3. Catalog DN / áp suất / model và ma trận chứng nhận chính xác.
|
|
273
|
+
4. Kỹ thuật KANEKO rà soát chính thức và bộ test case được chủ sở hữu phê duyệt.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "kaneko-fa-selector"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "KANEKO flame arrester preselection rule engine (R1-R8): JSON in, JSON out"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
dependencies = ["PyYAML>=6.0"]
|
|
12
|
+
authors = [{ email = "stkengaposa832@gmail.com" }]
|
|
13
|
+
keywords = ["kaneko", "flame arrester", "rule engine", "preselection"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 3 - Alpha",
|
|
16
|
+
"Intended Audience :: Manufacturing",
|
|
17
|
+
"Topic :: Scientific/Engineering",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
20
|
+
"Programming Language :: Python :: 3.10",
|
|
21
|
+
"Programming Language :: Python :: 3.11",
|
|
22
|
+
"Programming Language :: Python :: 3.12",
|
|
23
|
+
"Programming Language :: Python :: 3.13",
|
|
24
|
+
"Operating System :: OS Independent",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[project.optional-dependencies]
|
|
28
|
+
app = ["streamlit>=1.35"]
|
|
29
|
+
dev = ["pytest>=8.0", "build>=1.0", "twine>=5.0"]
|
|
30
|
+
|
|
31
|
+
[project.scripts]
|
|
32
|
+
kaneko-fa-selector = "kaneko_fa_selector.__main__:main"
|
|
33
|
+
|
|
34
|
+
[tool.setuptools]
|
|
35
|
+
package-dir = {"" = "src"}
|
|
36
|
+
|
|
37
|
+
[tool.setuptools.packages.find]
|
|
38
|
+
where = ["src"]
|
|
39
|
+
|
|
40
|
+
[tool.setuptools.package-data]
|
|
41
|
+
kaneko_fa_selector = ["rules/*.yaml"]
|
|
42
|
+
|
|
43
|
+
[tool.setuptools.dynamic]
|
|
44
|
+
version = {attr = "kaneko_fa_selector.__version__"}
|
|
45
|
+
|
|
46
|
+
[tool.pytest.ini_options]
|
|
47
|
+
testpaths = ["tests"]
|