Skip to content

Dev - #33

Merged
Voronapxl merged 19 commits into
mainfrom
dev
Jul 24, 2026
Merged

Dev#33
Voronapxl merged 19 commits into
mainfrom
dev

Conversation

@Voronapxl

Copy link
Copy Markdown
Collaborator

No description provided.

Voronapxl and others added 19 commits July 14, 2026 19:09
…pi id

building_pzz_check assumed a numeric functional_zone_type_id keyed to the
built-in fz→pzz mapping. A real ПЗЗ layer carries letter indices («Ж-1», «П-1»)
and text names instead, so build_zone_gdf silently dropped every zone (int("Ж-1")
fails) and all buildings came back "нет пересечения с ПЗЗ" — a quiet wrong result.

Add a second zone backend, mirroring the regular pzz_check zone side:
- load_pzz_label_mapping reads the letter-index label schema
  (pzz_zone_llm_labels_template.json), keyed by a normalised index.
- normalise_zone_code folds trivial spelling drift (Ж-1 ≈ ж1 ≈ Ж–1) while the
  user's verbatim code is preserved for display (zone_code_display).
- build_zone_gdf gains a numeric flag; join_objects_to_zones preserves the key
  type (int for urban_api, str for ПЗЗ indices).
- The runner auto-picks the backend from the zone code values, falls back to the
  built-in template when no descriptions file is uploaded (not required), and
  collects zone codes absent from the mapping (uncovered_zones) plus a
  used_default_mapping flag for the chat answer.

Numeric urban_api flow is unchanged (verdicts identical on the 843-zone sample).
Adds building_pzz_zone_suggest_threshold setting (used by the upcoming confirm flow).
…d flow

Builds on the letter-index backend: when a real ПЗЗ is checked against the
built-in template (no user descriptions), be honest about it and help close the
gap, instead of silently emitting no_zone_metadata for unmapped zones.

Before the task runs, review_building_zones decides:
- proceed — numeric urban_api zones, the user's own descriptions, or the template
  already covers every zone. Template/overlay-based runs prepend an approximate-
  classification disclaimer (build_disclaimer) listing any still-uncovered zones.
- suggest_upload — many zone indices absent from the template (≥ threshold):
  stream a terminal message asking to upload proper descriptions (no task run).
- confirm — a few absent: one batched LLM call suggests the nearest template zone
  per uncovered code (by name), streamed for the user to confirm and re-submit via
  confirmed_zone_map. build_confirmed_overlay turns confirmations into an overlay
  labels file fed back as the descriptions upload, so «СХ-3» resolves against the
  confirmed template zone's ВРИ.

The zone-review logic, disclaimer, overlay and LLM prompt/parse are pure and unit-
tested (tests/test_building_zone_review.py); the SSE endpoint is thin glue over
them. Also:
- classifier accepts a letter-index label list (not just the fz dict) for the
  building descriptions upload;
- building auto-detect now also picks the zone-name column (powers suggestions);
- new confirmed_zone_map form param + zone_review_generator SSE event
  (status zone_review_required, mirroring detection_failed);
- zone_codes_are_numeric / zone_code_display_map moved to _deterministic_pzz so
  the endpoint and runner share them.
The auto/chat/stream flow opens the LLM client for column detection and, in
building_pzz_check, for the zone-suggestion step. Both caught only OllamaChatError,
so an unreachable model host raised httpx.ConnectError straight through → HTTP 500.

- detect_columns_for_file: catch httpx.HTTPError too; unresolved targets fall back
  to heuristic-only ("not found") instead of failing the whole request.
- _run_building_pzz_auto zone-suggest: on LLM failure, degrade to the
  "upload your descriptions" (suggest_upload) response naming the uncovered zones,
  instead of 500.

Surfaced while testing the two-phase flow against a stack whose LLM host was
temporarily unreachable.
…e examples

- frontend-api-guide.md (section H): letter-index vs numeric zone backends, the
  zone_review SSE event (confirm / suggest_upload), confirmed_zone_map, the
  approximate-classification disclaimer, threshold, per-zone flow + Scenario 5.
- input-files-examples.md (new): worked examples of every input file across all
  endpoints — parcels, buildings, zones (numeric/letter), descriptions (both
  schemas), VRI classifier, confirmed_zone_map, and request examples per endpoint.
Add POST /pzz/zone-descriptions/convert: read a tidy zone-description table (one row per zone/VRI/permission) and fold it into the pzz_check label schema, so users can supply PZZ descriptions as spreadsheets.

- table_reader: CSV (encoding + delimiter sniff) and XLSX (openpyxl).

- convert_zone_table: group by zone, split by permission, dedupe VRI.

- detect_columns: LLM-first table column detection (heuristic_first flag) so arbitrary headers map by values, with a heuristic offline backstop.

- input-files-examples.md: document the table contract and the endpoint.
Resolve human-written building type/service names to the catalogue by embedding similarity (vectorizer) when they match neither an id nor an alias, before the LLM enum-pick fallback; below-threshold names go to manual review, flagged in the resolution basis.

Add embeddings_client, vectorizer_url and building_semantic_* settings. Deterministic id/alias matches never reach the embedder; if it is unreachable the flow degrades to the LLM, then manual review.
Ground the building_pzz_check chat answer with a building-specific system prompt (objects/buildings/services, not parcels). Thread an optional system_prompt_path through the answer generator; parcel modes keep the default prompt.
Key the answer grounding by the result file's Russian attribute names (Kod_podobrannogo_VRI, Podobrannyj_VRI, Verdikt_PZZ...) instead of English field names, and instruct the model to name the attribute when citing its value and to take the VRI code and name strictly from the provided data.
…xt building types

- frontend-api-guide.md: new POST /pzz/zone-descriptions/convert section (request, response, frontend flow) and updated building_pzz_check resolution to the id/alias/embedder/LLM/manual ladder.

- input-files-examples.md: buildings (S2) note that type/service can be free human text, resolved by the embedder with a basis flag.
Format staged Python with Black on every commit via a pre-commit hook (Black runs in pre-commit's isolated env, so no reliance on the active venv). line-length 88 matches the codebase (vast majority of lines already fit).

Setup per clone: pip install -r requirements-dev.txt && pre-commit install.
Mechanical reformat only (Black 26.5.1, line-length 88); no logic changes. Vendored pipeline_modules/ is excluded via [tool.black] extend-exclude. See .git-blame-ignore-revs to keep git blame clean.
Add .git-blame-ignore-revs pointing at the style commit so line authorship survives the reformat. Enable locally: git config blame.ignoreRevsFile .git-blame-ignore-revs (GitHub uses it automatically).
In building_pzz_check, a pzz_descriptions_file with a .csv/.xlsx name is converted to the label JSON up front (read_table + LLM column detect + convert_zone_table), so the frontend can drop a spreadsheet without a separate /convert call. What was recognised (zones/VRI + warnings) is prepended to the leading narrative chunk; an unresolvable required column yields a terminal detection_failed. JSON descriptions pass through unchanged. /convert stays for verify-before-run.
…hat/stream

Note that pzz_descriptions_file accepts a table directly (converted inline, recognised columns announced in the leading chunk), and when to use that vs the /convert preview.
…zz_check

Symmetry with the building descriptions flow: pzz_descriptions_file (building) and pzz_zone_vri_labels_file (pzz_check) are the same labels slot (task field pzz_zone_vri_labels_path, same default template). So a .csv/.xlsx labels file for pzz_check is now converted to the label JSON up front too, via the shared _convert_descriptions_if_table helper, with the recognised columns announced in the leading narrative chunk and a terminal detection_failed on an unresolvable required column.
…before definition

The inline-conversion note now lists which table columns were matched to which role (код зоны — «Zone», тип разрешения — «Code», …) and spells out «правила землепользования и застройки» / «виды разрешённого использования» in full, since this leading narrative precedes the model's «ВРИ — …; ПЗЗ — …» definition line. Same for the table read/convert error messages and the converter's ВРИ warnings.
… name

The result attribute «Название фактической зоны нахождения кадастра» (and the answer's per-zone breakdown) now resolves the zone name as: description zone_name → zones-layer name column → code. So when the uploaded zones layer names its zones but the descriptions don't, a reader sees «Зона жилой застройки» instead of «Ж-1». Numeric backends keep the existing nickname.
@Voronapxl
Voronapxl merged commit 346fb0c into main Jul 24, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant