dd-l1-vienna-gpkg-manifest

Status: done
Score: 100
Duration: 2:15
Cost: 0.33¢
Model: google/gemma-4-26b-a4b-it

Map (reference ← swipe → agent)

0:00
Inherited a GPKG (vienna_planning) from a colleague who retired last week. Before I commit to scripting against it I need a one-page manifest so I can see what's in there and decide which layers actually feed next month's councillor briefing. Catalog the contents and give me one record per layer. Output manifest.json — a JSON list of these records. Each record in the list must be a JSON object with exactly five keys: `layer_name` as a string, `crs` as a string in `EPSG:NNNN` form, `geometry_type` as a string matching the layer's native type (e.g. `Point`, `LineString`, `Polygon`, `MultiPolygon`), `feature_count` as an integer, and `bbox` as a list of four numbers `[xmin, ymin, xmax, ymax]` in the layer's native CRS.
0:00
System info
{
  "adapter": "openrouter",
  "model": "google/gemma-4-26b-a4b-it",
  "base_url": "https://openrouter.ai/api/v1"
}
0:04
Bash ls -F
vienna_planning.gpkg
0:28
Write /work/solve.py
content · 51 lines · py
import geopandas as gpd
import json

def main():
    gpkg_path = 'vienna_planning.gpkg'
    
    # Get layer names
    import fiona
    layers = fiona.listlayers(gpkg_path)
    
    manifest = []
    
    for layer_name in layers:
        gdf = gpd.read_file(gpkg_path, layer=layer_name)
        
        # CRS: EPSG:NNNN form
        # gdf.crs might be an object, we want the EPSG code
        epsg_code = gdf.crs.to_epsg()
        crs_str = f"EPSG:{epsg_code}" if epsg_code else str(gdf.crs)
        
        # Geometry type
        # gdf.geom_type returns the type of the geometry column (e.g., 'Polygon', 'MultiPolygon')
        # We want the native type. Geopandas provides this.
        # Note: if it's a mix, it might be 'GeometryCollection', but usually it's one of the standard ones.
        # Let's check the first non-null geometry type or just the column type.
        geom_type = gdf.geom_type.iloc[0] if not gdf.empty else "None"
        
        # Feature count
        feature_count = len(gdf)
        
        # BBox [xmin, ymin, xmax, ymax]
        if not gdf.empty:
            bounds = gdf.total_bounds
            bbox = [float(bounds[0]), float(bounds[1]), float(bounds[2]), float(bounds[3])]
        else:
            bbox = [0.0, 0.0, 0.0, 0.0]
            
        manifest.append({
            "layer_name": layer_name,
            "crs": crs_str,
            "geometry_type": geom_type,
            "feature_count": feature_count,
            "bbox": bbox
        })
        
    with open('manifest.json', 'w') as f:
        json.dump(manifest, f, indent=4)

if __name__ == "__main__":
    main()
Wrote /work/solve.py (1625 chars).
0:30
Bash python solve.py
(no output)
0:36
Bash cat manifest.json
[
    {
        "layer_name": "districts",
        "crs": "EPSG:31287",
        "geometry_type": "Polygon",
        "feature_count": 22,
        "bbox": [
            623867.3888224852,
            481236.5836125494,
            626371.3079994549,
            484403.7315526943
        ]
    },
    {
        "layer_name": "parks",
        "crs": "EPSG:31287",
        "geometry_type": "MultiPolygon",
        "feature_count": 119,
        "bbox": [
            623851.990195953,
            481200.6674012489,
            626620.9438865517,
            485539.3479671855
        ]
    },
    {
        "layer_name": "waterbodies",
        "crs": "EPSG:31287",
        "geometry_type": "Polygon",
        "feature_count": 33,
        "bbox": [
            624288.8521056126,
            481236.66320640914,
            626747.8611584986,
            484132.0212685799
        ]
    },
    {
        "layer_name": "schools",
        "crs": "EPSG:31287",
        "geometry_type": "Point",
        "feature_count": 40,
        "bbox": [
            624000.002417057,
            481214.73871311604,
            626259.5421406503,
            484178.87865010765
        ]
    },
    {
        "layer_name": "cafes",
        "crs": "EPSG:31287",
        "geometry_type": "Point",
        "feature_count": 392,
        "bbox": [
            623796.529863561,
            481107.2540129812,
            626399.5618121764,
            484498.9209005649
        ]
    },
    {
        "layer_name": "supermarkets",
        "crs": "EPSG:31287",
        "geometry_type": "Point",
        "feature_count": 87,
        "bbox": [
            623794.0549950565,
            481148.38703723426,
            626392.6164786755,
            484489.91954147833
        ]
    },
    {
        "layer_name": "cycleway_segments",
        "crs": "EPSG:31287",
        "geometry_type": "LineString",
        "feature_count": 271,
        "bbox": [
            623787.4932131292,
            481134.9325878215,
            626619.1631922598,
            485245.6624853243
        ]
    }
]
0:54
Write /work/solve.py
content · 62 lines · py
import geopandas as gpd
import json
import fiona

def main():
    gpkg_path = 'vienna_planning.gpkg'
    
    # Get layer names
    layers = fiona.listlayers(gpkg_path)
    
    manifest = []
    
    for layer_name in layers:
        gdf = gpd.read_file(gpkg_path, layer=layer_name)
        
        # CRS: EPSG:NNNN form
        # Try to get the EPSG code directly. If it fails, fallback to string representation.
        try:
            epsg_code = gdf.crs.to_epsg()
            if epsg_code:
                crs_str = f"EPSG:{epsg_code}"
            else:
                crs_str = str(gdf.crs)
        except Exception:
            crs_str = str(gdf.crs)
        
        # Geometry type
        # Geopandas 'geom_type' can return 'MultiPolygon' etc.
        # We check the actual geometry type of the first feature.
        if not gdf.empty:
            # Get the most common geometry type or just the first one's type.
            # The instruction says "matching the layer's native type".
            # gdf.geom_type is a Series of types for each geometry.
            # We'll take the most frequent one to be safe, or just the first.
            geom_type = gdf.geom_type.mode()[0]
        else:
            geom_type = "None"
        
        # Feature count
        feature_count = len(gdf)
        
        # BBox [xmin, ymin, xmax, ymax]
        if not gdf.empty:
            bounds = gdf.total_bounds
            bbox = [float(bounds[0]), float(bounds[1]), float(bounds[2]), float(bounds[3])]
        else:
            bbox = [0.0, 0.0, 0.0, 0.0]
            
        manifest.append({
            "layer_name": layer_name,
            "crs": crs_str,
            "geometry_type": geom_type,
            "feature_count": feature_count,
            "bbox": bbox
        })
        
    with open('manifest.json', 'w') as f:
        json.dump(manifest, f, indent=4)

if __name__ == "__main__":
    main()
Wrote /work/solve.py (1918 chars).
0:58
Bash python solve.py
(no output)
1:02
Bash cat manifest.json
[
    {
        "layer_name": "districts",
        "crs": "EPSG:31287",
        "geometry_type": "Polygon",
        "feature_count": 22,
        "bbox": [
            623867.3888224852,
            481236.5836125494,
            626371.3079994549,
            484403.7315526943
        ]
    },
    {
        "layer_name": "parks",
        "crs": "EPSG:31287",
        "geometry_type": "MultiPolygon",
        "feature_count": 119,
        "bbox": [
            623851.990195953,
            481200.6674012489,
            626620.9438865517,
            485539.3479671855
        ]
    },
    {
        "layer_name": "waterbodies",
        "crs": "EPSG:31287",
        "geometry_type": "Polygon",
        "feature_count": 33,
        "bbox": [
            624288.8521056126,
            481236.66320640914,
            626747.8611584986,
            484132.0212685799
        ]
    },
    {
        "layer_name": "schools",
        "crs": "EPSG:31287",
        "geometry_type": "Point",
        "feature_count": 40,
        "bbox": [
            624000.002417057,
            481214.73871311604,
            626259.5421406503,
            484178.87865010765
        ]
    },
    {
        "layer_name": "cafes",
        "crs": "EPSG:31287",
        "geometry_type": "Point",
        "feature_count": 392,
        "bbox": [
            623796.529863561,
            481107.2540129812,
            626399.5618121764,
            484498.9209005649
        ]
    },
    {
        "layer_name": "supermarkets",
        "crs": "EPSG:31287",
        "geometry_type": "Point",
        "feature_count": 87,
        "bbox": [
            623794.0549950565,
            481148.38703723426,
            626392.6164786755,
            484489.91954147833
        ]
    },
    {
        "layer_name": "cycleway_segments",
        "crs": "EPSG:31287",
        "geometry_type": "LineString",
        "feature_count": 271,
        "bbox": [
            623787.4932131292,
            481134.9325878215,
            626619.1631922598,
            485245.6624853243
        ]
    }
]
2:12