Skip to main content

KDM (K-water Data Model) SDK for water resource data access

Project description

KDM SDK

Python 3.10+ License: MIT Tests Beta

๐Ÿš€ ๋ฒ ํƒ€ ์˜คํ”ˆ - K-water Data Model (KDM) ๋ฐ์ดํ„ฐ๋ฅผ ์‰ฝ๊ฒŒ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋Š” Python SDK์ž…๋‹ˆ๋‹ค.

K-water Data Model (KDM)์€ water.or.kr/kdm ๊ธฐ๋ฐ˜์˜ ์ˆ˜์ž์› ๋ฐ์ดํ„ฐ ์„œ๋น„์Šค์ž…๋‹ˆ๋‹ค. ์ด SDK๋ฅผ ํ†ตํ•ด ๋Œ ์ˆ˜๋ฌธ ๋ฐ์ดํ„ฐ, ํ•˜์ฒœ ์ˆ˜์œ„, ๊ฐ•์šฐ๋Ÿ‰ ๋“ฑ์˜ ์ˆ˜์ž์› ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ„ํŽธํ•˜๊ฒŒ ์กฐํšŒํ•˜๊ณ  ๋ถ„์„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

English Documentation

์ฃผ์š” ๊ธฐ๋Šฅ

  • ์ง๊ด€์ ์ธ Query API - ๋ฉ”์„œ๋“œ ์ฒด์ด๋‹์œผ๋กœ ๊ฐ„๋‹จํ•œ ์ฟผ๋ฆฌ ์ž‘์„ฑ
  • ๋ฐฐ์น˜ ์ฟผ๋ฆฌ - ์—ฌ๋Ÿฌ ์‹œ์„ค์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ‘๋ ฌ๋กœ ์กฐํšŒํ•˜์—ฌ ์„ฑ๋Šฅ ํ–ฅ์ƒ
  • ์ƒํ•˜๋ฅ˜ ์—ฐ๊ด€ ๋ถ„์„ - ๋Œ ๋ฐฉ๋ฅ˜๋Ÿ‰๊ณผ ํ•˜๋ฅ˜ ์ˆ˜์œ„์˜ ์ƒ๊ด€๊ด€๊ณ„ ๋ถ„์„
  • ๐Ÿ†• ๊ด€์ธก์†Œ ์ž๋™ ํƒ์ƒ‰ - ๋Œ์˜ ์ƒํ•˜๋ฅ˜ ๊ด€์ธก์†Œ ์ž๋™ ๊ฒ€์ƒ‰ (Basin ๋งค์นญ + ์ง€๋ฆฌ ๊ธฐ๋ฐ˜ ๊ฒ€์ƒ‰)
  • ๐Ÿ†• ์›๋ณธ ์‹œ์„ค์ฝ”๋“œ ์ œ๊ณต - K-water, ํ™˜๊ฒฝ๋ถ€ ๋“ฑ ์›์ฒœ ๊ธฐ๊ด€์˜ ์‹œ์„ค์ฝ”๋“œ๋กœ ์™ธ๋ถ€ ์‹œ์Šคํ…œ ์—ฐ๋™
  • ํ…œํ”Œ๋ฆฟ ์‹œ์Šคํ…œ - YAML ๋˜๋Š” Python์œผ๋กœ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ฟผ๋ฆฌ ํ…œํ”Œ๋ฆฟ ์ž‘์„ฑ
  • pandas ํ†ตํ•ฉ - ์กฐํšŒ ๊ฒฐ๊ณผ๋ฅผ DataFrame์œผ๋กœ ์ฆ‰์‹œ ๋ณ€ํ™˜
  • ๊ฐ„ํŽธํ•œ ๋‚ด๋ณด๋‚ด๊ธฐ - Excel, CSV, Parquet, JSON์œผ๋กœ ํ•œ ์ค„์— ์ €์žฅ
  • ์ž๋™ ํด๋ฐฑ - ์‹œ๊ฐ„ ๋‹จ์œ„ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์œผ๋ฉด ์ž๋™์œผ๋กœ ์ผ/์›” ๋‹จ์œ„ ์กฐํšŒ
  • ๋น„๋™๊ธฐ ์ง€์› - async/await ํŒจํ„ด์œผ๋กœ ํšจ์œจ์ ์ธ ๋ฐ์ดํ„ฐ ์กฐํšŒ
  • ํƒ€์ž… ํžŒํŠธ - ์ „์ฒด ์ฝ”๋“œ์— ํƒ€์ž… ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ IDE ์ง€์› ๊ฐ•ํ™”

SDK์˜ ์—ญํ• 

โœ… SDK๊ฐ€ ํ•˜๋Š” ์ผ

  • ๋ฐ์ดํ„ฐ ์กฐํšŒ: KDM ์ˆ˜์ž์› ๋ฐ์ดํ„ฐ๋ฅผ ์‰ฝ๊ฒŒ ์กฐํšŒ
  • ๋ฐ์ดํ„ฐ ๋ณ€ํ™˜: pandas DataFrame์œผ๋กœ ์ž๋™ ๋ณ€ํ™˜
  • ๋ฐ์ดํ„ฐ ์ €์žฅ: Excel, CSV, Parquet, JSON์œผ๋กœ ํ•œ๊ธ€ ์ธ์ฝ”๋”ฉ ์ง€์›ํ•˜์—ฌ ์ €์žฅ

โŒ SDK๊ฐ€ ํ•˜์ง€ ์•Š๋Š” ์ผ

  • ์‹œ๊ฐํ™”: matplotlib, seaborn, plotly ๋“ฑ ์‚ฌ์šฉ
  • ํ†ต๊ณ„ ๋ถ„์„: pandas, scipy, numpy ๋“ฑ ์‚ฌ์šฉ
  • ๋ฐ์ดํ„ฐ ์ •์ œ: pandas ๋ฉ”์„œ๋“œ ์‚ฌ์šฉ

์ฒ ํ•™: ์ด SDK๋Š” KDM ๋ฐ์ดํ„ฐ๋ฅผ pandas๋กœ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ๊นŒ์ง€๋งŒ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค. ๊ทธ ์ดํ›„๋Š” ์—ฌ๋Ÿฌ๋ถ„์˜ ๋ฐ์ดํ„ฐ ๋ถ„์„ ๋Šฅ๋ ฅ์„ ํ™œ์šฉํ•˜์„ธ์š”!

examples/analyst_reference.py์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜จ ํ›„ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ถ„์„ ์˜ˆ์ œ๋ฅผ ํ™•์ธํ•˜์„ธ์š”.

์„ค์น˜

# PyPI์—์„œ ์„ค์น˜ (๊ถŒ์žฅ) โญ
pip install kdm-sdk

# ๋ฐ์ดํ„ฐ ๋ถ„์„๊ฐ€์šฉ (๋ถ„์„ ๋„๊ตฌ ํฌํ•จ)
pip install kdm-sdk[analyst]

# ๊ฐœ๋ฐœ์ž์šฉ (๊ฐœ๋ฐœ ๋„๊ตฌ ํฌํ•จ)
pip install kdm-sdk[dev]

# ๋˜๋Š” GitHub์—์„œ ์ตœ์‹  ๋ฒ„์ „ ์„ค์น˜
pip install git+https://github.com/kwatermywater/kdm-sdk.git

[analyst] ์˜ต์…˜์—๋Š” ๋‹ค์Œ์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค: pandas, jupyter, matplotlib, seaborn, plotly, openpyxl, pyarrow, scipy, statsmodels

์š”๊ตฌ์‚ฌํ•ญ

  • Python 3.10 ์ด์ƒ
  • KDM MCP Server (์šด์˜ ์„œ๋ฒ„: http://203.237.1.4:8080)
  • pandas 2.0+

์ฒ˜์Œ ์‚ฌ์šฉํ•˜์‹œ๋‚˜์š”?

๐Ÿ“š ๋ฐ์ดํ„ฐ ๊ฐ€์ด๋“œ ๋ฐ”๋กœ๊ฐ€๊ธฐ - ์ˆ˜์ž์› ๋ฐ์ดํ„ฐ๊ฐ€ ์ฒ˜์Œ์ด์‹  ๋ถ„๋“ค์„ ์œ„ํ•œ ์นœ์ ˆํ•œ ์„ค๋ช…์„œ

๊ฐ€์ด๋“œ ๋‚ด์šฉ:

  • ์‹œ์„ค ์œ ํ˜• (๋Œ, ์ˆ˜์œ„๊ด€์ธก์†Œ, ์šฐ๋Ÿ‰๊ด€์ธก์†Œ ๋“ฑ)
  • ์‹œ๊ฐ„ ๋‹จ์œ„ (์‹œ๊ฐ„๋ณ„, ์ผ๋ณ„, ์›”๋ณ„) ๋ฐ ์กฐํšŒ ๊ธฐ๊ฐ„ ๐Ÿ“…
  • ์ธก์ • ํ•ญ๋ชฉ (์ €์ˆ˜์œจ, ์œ ์ž…๋Ÿ‰, ๋ฐฉ๋ฅ˜๋Ÿ‰ ๋“ฑ) ๐Ÿ“Š
  • ์‹œ์„ค ๊ฒ€์ƒ‰ ๋ฐฉ๋ฒ•
  • ์šฉ์–ด ์„ค๋ช… (์ €์ˆ˜์œ„, CMS, TOC ๋“ฑ)
  • ์ดˆ๋ณด์ž์šฉ ์˜ˆ์ œ

๋น ๋ฅธ ํŒ:

# ๐Ÿ’ก ์–ด๋–ค ๋Œ์ด ์žˆ๋Š”์ง€ ๋ชจ๋ฅผ ๋•Œ
results = await client.search_facilities(query="๋Œ", limit=10)

# ๐Ÿ’ก ์ธก์ • ํ•ญ๋ชฉ์ด ๋ญ๊ฐ€ ์žˆ๋Š”์ง€ ๋ชจ๋ฅผ ๋•Œ
items = await client.list_measurements(site_name="์†Œ์–‘๊ฐ•๋Œ")

# ๐Ÿ’ก ์‹œ๊ฐ„ ๋‹จ์œ„๋ฅผ ๋ชจ๋ฅผ ๋•Œ (์ž๋™ ์„ ํƒ)
result = await KDMQuery().site("์†Œ์–‘๊ฐ•๋Œ").measurements(["์ €์ˆ˜์œจ"]) \
    .days(7).time_key("auto").execute()

๋น ๋ฅธ ์‹œ์ž‘

๊ธฐ๋ณธ ์ฟผ๋ฆฌ (Fluent API)

import asyncio
from kdm_sdk import KDMQuery

async def main():
    # ๋Œ ์ €์ˆ˜์œจ ๋ฐ์ดํ„ฐ ์กฐํšŒ
    result = await KDMQuery() \
        .site("์†Œ์–‘๊ฐ•๋Œ", facility_type="dam") \
        .measurements(["์ €์ˆ˜์œจ", "์œ ์ž…๋Ÿ‰"]) \
        .days(7) \
        .execute()

    # pandas DataFrame์œผ๋กœ ๋ณ€ํ™˜
    df = result.to_dataframe()
    print(df.head())

asyncio.run(main())

๋ฐฐ์น˜ ์ฟผ๋ฆฌ (์—ฌ๋Ÿฌ ์‹œ์„ค ๋™์‹œ ์กฐํšŒ)

from kdm_sdk import KDMQuery

async def batch_query():
    query = KDMQuery()

    # ์—ฌ๋Ÿฌ ๋Œ ์ถ”๊ฐ€
    for dam in ["์†Œ์–‘๊ฐ•๋Œ", "์ถฉ์ฃผ๋Œ", "ํŒ”๋‹น๋Œ"]:
        query.site(dam, facility_type="dam") \
             .measurements(["์ €์ˆ˜์œจ"]) \
             .days(7) \
             .add()

    # ๋ณ‘๋ ฌ ์‹คํ–‰
    results = await query.execute_batch(parallel=True)

    # ๋‹จ์ผ DataFrame์œผ๋กœ ํ†ตํ•ฉ
    combined_df = results.aggregate()
    print(combined_df.groupby("site_name")["์ €์ˆ˜์œจ"].mean())

asyncio.run(batch_query())

์ƒํ•˜๋ฅ˜ ์ƒ๊ด€๊ด€๊ณ„ ๋ถ„์„

from kdm_sdk import FacilityPair

async def correlation_analysis():
    # ๋Œ ๋ฐฉ๋ฅ˜๊ฐ€ ํ•˜๋ฅ˜ ์ˆ˜์œ„์— ๋ฏธ์น˜๋Š” ์˜ํ–ฅ ๋ถ„์„
    from kdm_sdk import KDMClient
    import pandas as pd

    async with KDMClient() as client:
        # ์ƒ๋ฅ˜ ๋ฐ์ดํ„ฐ ์กฐํšŒ (๋Œ)
        upstream_result = await client.get_water_data(
            site_name="์†Œ์–‘๊ฐ•๋Œ",
            facility_type="dam",
            measurement_items=["๋ฐฉ๋ฅ˜๋Ÿ‰"],
            days=30,
            time_key="h_1"
        )

        # ํ•˜๋ฅ˜ ๋ฐ์ดํ„ฐ ์กฐํšŒ (์ˆ˜์œ„๊ด€์ธก์†Œ)
        downstream_result = await client.get_water_data(
            site_name="์ถ˜์ฒœ์‹œ(์ถ˜์ฒœ๋Œํ•˜๋ฅ˜)",
            facility_type="water_level",
            measurement_items=["์ˆ˜์œ„"],
            days=30,
            time_key="h_1"
        )

        # DataFrame ๋ณ€ํ™˜
        def to_df(data):
            records = []
            for item in data:
                record = {"datetime": item.get("datetime")}
                if "values" in item:
                    for key, val in item["values"].items():
                        record[key] = val.get("value")
                records.append(record)
            df = pd.DataFrame(records)
            if "datetime" in df.columns:
                df["datetime"] = pd.to_datetime(df["datetime"])
                df.set_index("datetime", inplace=True)
            return df

        upstream_df = to_df(upstream_result.get("data", []))
        downstream_df = to_df(downstream_result.get("data", []))

        # FacilityPair ์ƒ์„ฑ
        pair = FacilityPair(
            upstream_name="์†Œ์–‘๊ฐ•๋Œ",
            downstream_name="์ถ˜์ฒœ์‹œ(์ถ˜์ฒœ๋Œํ•˜๋ฅ˜)",
            upstream_type="dam",
            downstream_type="water_level",
            upstream_data=upstream_df,
            downstream_data=downstream_df
        )

        # ์ตœ์  ์‹œ๊ฐ„์ฐจ ์ฐพ๊ธฐ
        correlation = pair.find_optimal_lag(max_lag_hours=12)
        print(f"์ตœ์  ์‹œ๊ฐ„์ฐจ: {correlation.lag_hours:.1f}์‹œ๊ฐ„")
        print(f"์ƒ๊ด€๊ณ„์ˆ˜: {correlation.correlation:.3f}")

asyncio.run(correlation_analysis())

ํ…œํ”Œ๋ฆฟ ๊ธฐ๋ฐ˜ ์ฟผ๋ฆฌ

from kdm_sdk.templates import TemplateBuilder

async def template_query():
    # ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ํ…œํ”Œ๋ฆฟ ์ƒ์„ฑ
    template = TemplateBuilder("์ฃผ๊ฐ„ ๋Œ ๋ชจ๋‹ˆํ„ฐ๋ง") \
        .site("์†Œ์–‘๊ฐ•๋Œ", facility_type="dam") \
        .measurements(["์ €์ˆ˜์œจ", "์œ ์ž…๋Ÿ‰", "๋ฐฉ๋ฅ˜๋Ÿ‰"]) \
        .days(7) \
        .time_key("h_1") \
        .build()

    # ํ…œํ”Œ๋ฆฟ ์‹คํ–‰
    result = await template.execute()
    df = result.to_dataframe()

    # ํ…œํ”Œ๋ฆฟ ์ €์žฅํ•˜์—ฌ ์žฌ์‚ฌ์šฉ
    template.save_yaml("templates/weekly_monitoring.yaml")

asyncio.run(template_query())

๊ด€์ธก์†Œ ์ž๋™ ํƒ์ƒ‰ (์‹ ๊ทœ ๊ธฐ๋Šฅ)

from kdm_sdk import KDMClient

async def find_stations():
    async with KDMClient() as client:
        # ๋Œ์˜ ํ•˜๋ฅ˜ ์ˆ˜์œ„๊ด€์ธก์†Œ ์ž๋™ ๊ฒ€์ƒ‰
        result = await client.find_related_stations(
            dam_name="์†Œ์–‘๊ฐ•๋Œ",
            direction="downstream",
            station_type="water_level"
        )

        # ๋Œ ์ •๋ณด (์›๋ณธ ์‹œ์„ค์ฝ”๋“œ ํฌํ•จ)
        dam = result['dam']
        print(f"๋Œ: {dam['site_name']}")
        print(f"์›๋ณธ์ฝ”๋“œ: {dam['original_facility_code']}")  # K-water ์ฝ”๋“œ

        # ๊ด€๋ จ ๊ด€์ธก์†Œ ๋ชฉ๋ก
        for station in result['stations']:
            print(f"- {station['site_name']}: {station['original_facility_code']}")
            print(f"  ๋งค์นญ๋ฐฉ์‹: {station['match_type']}")  # basin or geographic
            print(f"  ๊ฑฐ๋ฆฌ: {station['distance_km']:.1f} km")

asyncio.run(find_stations())

โœ… v0.2.2 ๊ฐœ์„ ์‚ฌํ•ญ: ๋ฌผํ๋ฆ„ ๋„คํŠธ์›Œํฌ ๊ทธ๋ž˜ํ”„ ๊ธฐ๋ฐ˜ ๊ฒ€์ƒ‰์œผ๋กœ ์ •ํ™•๋„ ๋Œ€ํญ ํ–ฅ์ƒ

  • ํ•˜๋ฅ˜(downstream) ๊ฒ€์ƒ‰: โœ… ์†Œ์–‘๊ฐ•๋Œ 10๊ฐœ, ํŒ”๋‹น๋Œ 10๊ฐœ (์ด์ „ 3๊ฐœ, 1๊ฐœ)
  • ์ƒ๋ฅ˜(upstream) ๊ฒ€์ƒ‰: โš ๏ธ MCP ์„œ๋ฒ„ ์—…๋ฐ์ดํŠธ ๋Œ€๊ธฐ ์ค‘ (ํ˜„์žฌ legacy fallback ์‚ฌ์šฉ)
  • match_type: "network" ํ•„๋“œ๋กœ ๊ฒฐ๊ณผ ์ถœ์ฒ˜ ํ™•์ธ ๊ฐ€๋Šฅ

๋ฌธ์„œ

ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ

kdm-sdk/
โ”œโ”€โ”€ src/
โ”‚   โ””โ”€โ”€ kdm_sdk/
โ”‚       โ”œโ”€โ”€ __init__.py           # ํŒจํ‚ค์ง€ exports
โ”‚       โ”œโ”€โ”€ client.py             # MCP ํด๋ผ์ด์–ธํŠธ
โ”‚       โ”œโ”€โ”€ query.py              # Fluent query API
โ”‚       โ”œโ”€โ”€ results.py            # ๊ฒฐ๊ณผ ๋ž˜ํผ
โ”‚       โ”œโ”€โ”€ facilities.py         # FacilityPair
โ”‚       โ””โ”€โ”€ templates/            # ํ…œํ”Œ๋ฆฟ ์‹œ์Šคํ…œ
โ”‚           โ”œโ”€โ”€ builder.py        # TemplateBuilder
โ”‚           โ”œโ”€โ”€ base.py           # Template ๊ธฐ๋ณธ ํด๋ž˜์Šค
โ”‚           โ””โ”€โ”€ loaders.py        # YAML/Python ๋กœ๋”
โ”œโ”€โ”€ tests/                        # ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ
โ”œโ”€โ”€ examples/                     # ์‚ฌ์šฉ ์˜ˆ์ œ
โ”‚   โ”œโ”€โ”€ basic_usage.py           # KDMClient ์˜ˆ์ œ
โ”‚   โ”œโ”€โ”€ query_usage.py           # Query API ์˜ˆ์ œ
โ”‚   โ”œโ”€โ”€ facility_pair_usage.py   # FacilityPair ์˜ˆ์ œ
โ”‚   โ””โ”€โ”€ templates/               # ํ…œํ”Œ๋ฆฟ ์˜ˆ์ œ
โ”œโ”€โ”€ docs/                         # ๋ฌธ์„œ
โ””โ”€โ”€ README.md                     # ์ด ํŒŒ์ผ

์˜ˆ์ œ

examples/ ๋””๋ ‰ํ† ๋ฆฌ์—์„œ ์ „์ฒด ์˜ˆ์ œ๋ฅผ ํ™•์ธํ•˜์„ธ์š”:

ํ…Œ์ŠคํŠธ

# ์ „์ฒด ํ…Œ์ŠคํŠธ ์‹คํ–‰
pytest

# ํŠน์ • ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ ์‹คํ–‰
pytest tests/test_query.py -v

# ์ปค๋ฒ„๋ฆฌ์ง€ ์ธก์ •
pytest --cov=kdm_sdk --cov-report=html

# ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋งŒ ์‹คํ–‰
pytest -m unit

# ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ ์‹คํ–‰ (MCP ์„œ๋ฒ„ ํ•„์š”)
pytest -m integration

์ฃผ์š” ์‚ฌ์šฉ ์‚ฌ๋ก€

1. ์—ฌ๋Ÿฌ ๋Œ ๋ชจ๋‹ˆํ„ฐ๋ง

query = KDMQuery()
for dam in ["์†Œ์–‘๊ฐ•๋Œ", "์ถฉ์ฃผ๋Œ", "ํŒ”๋‹น๋Œ", "๋Œ€์ฒญ๋Œ"]:
    query.site(dam).measurements(["์ €์ˆ˜์œจ"]).days(30).add()

results = await query.execute_batch(parallel=True)
df = results.aggregate()

2. ์ „๋…„ ๋Œ€๋น„ ๋น„๊ต

result = await KDMQuery() \
    .site("์žฅํฅ๋Œ") \
    .measurements(["์ €์ˆ˜์œจ"]) \
    .date_range("2024-06-01", "2024-06-30") \
    .compare_with_previous_year() \
    .execute()

3. ํ•˜๋ฅ˜ ์ˆ˜์œ„ ์˜ˆ์ธก

from kdm_sdk import KDMClient, FacilityPair
import pandas as pd

async with KDMClient() as client:
    # ์ƒ๋ฅ˜ ๋ฐ์ดํ„ฐ (๋Œ)
    upstream_result = await client.get_water_data(
        site_name="์†Œ์–‘๊ฐ•๋Œ",
        facility_type="dam",
        measurement_items=["๋ฐฉ๋ฅ˜๋Ÿ‰"],
        days=365,
        time_key="h_1"
    )

    # ํ•˜๋ฅ˜ ๋ฐ์ดํ„ฐ (๋Œ)
    downstream_result = await client.get_water_data(
        site_name="์˜์•”๋Œ",
        facility_type="dam",
        measurement_items=["์ˆ˜์œ„"],
        days=365,
        time_key="h_1"
    )

    # DataFrame ๋ณ€ํ™˜
    def to_df(data):
        records = []
        for item in data:
            record = {"datetime": item.get("datetime")}
            if "values" in item:
                for key, val in item["values"].items():
                    record[key] = val.get("value")
            records.append(record)
        df = pd.DataFrame(records)
        if "datetime" in df.columns:
            df["datetime"] = pd.to_datetime(df["datetime"])
            df.set_index("datetime", inplace=True)
        return df

    upstream_df = to_df(upstream_result.get("data", []))
    downstream_df = to_df(downstream_result.get("data", []))

    # FacilityPair ์ƒ์„ฑ
    pair = FacilityPair(
        upstream_name="์†Œ์–‘๊ฐ•๋Œ",
        downstream_name="์˜์•”๋Œ",
        upstream_data=upstream_df,
        downstream_data=downstream_df
    )

    # ์‹œ๊ฐ„์ฐจ๋ฅผ ๊ณ ๋ คํ•˜์—ฌ DataFrame ์ƒ์„ฑ (๋ฌผ์ด ์ด๋™ํ•˜๋Š”๋ฐ 5.5์‹œ๊ฐ„ ์†Œ์š”)
    df = pair.to_dataframe(lag_hours=5.5)

    # ๋จธ์‹ ๋Ÿฌ๋‹ ๋ชจ๋ธ ํ•™์Šต์— ์‚ฌ์šฉ
    X = df[["์†Œ์–‘๊ฐ•๋Œ_๋ฐฉ๋ฅ˜๋Ÿ‰"]]
    y = df["์˜์•”๋Œ_์ˆ˜์œ„"]

๊ฐœ๋ฐœ

ํ…Œ์ŠคํŠธ ์ฃผ๋„ ๊ฐœ๋ฐœ (TDD)

์ด ํ”„๋กœ์ ํŠธ๋Š” TDD ๋ฐฉ๋ฒ•๋ก ์œผ๋กœ ๊ฐœ๋ฐœ๋˜์—ˆ์Šต๋‹ˆ๋‹ค:

  1. Red - ์‹คํŒจํ•˜๋Š” ํ…Œ์ŠคํŠธ ๋จผ์ € ์ž‘์„ฑ
  2. Green - ํ…Œ์ŠคํŠธ๋ฅผ ํ†ต๊ณผํ•˜๋Š” ์ตœ์†Œํ•œ์˜ ์ฝ”๋“œ ๊ตฌํ˜„
  3. Refactor - ์ฝ”๋“œ ํ’ˆ์งˆ ๊ฐœ์„ 

ํ…Œ์ŠคํŠธ ์‹คํ–‰

# ๊ฐœ๋ฐœ ์˜์กด์„ฑ ์„ค์น˜
pip install -r requirements-dev.txt

# ํ…Œ์ŠคํŠธ ์‹คํ–‰
pytest -v

# ์ฝ”๋“œ ํฌ๋งทํŒ…
black src tests

# ํƒ€์ž… ์ฒดํฌ
mypy src

๊ธฐ์—ฌํ•˜๊ธฐ

๊ธฐ์—ฌ๋ฅผ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค! PR ์ œ์ถœ ์ „ ๋ชจ๋“  ํ…Œ์ŠคํŠธ๊ฐ€ ํ†ต๊ณผํ•˜๋Š”์ง€ ํ™•์ธํ•ด์ฃผ์„ธ์š”.

  1. ์ €์žฅ์†Œ ํฌํฌ
  2. ๊ธฐ๋Šฅ ๋ธŒ๋žœ์น˜ ์ƒ์„ฑ
  3. ์ƒˆ ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ํ…Œ์ŠคํŠธ ์ถ”๊ฐ€
  4. ๋ชจ๋“  ํ…Œ์ŠคํŠธ ํ†ต๊ณผ ํ™•์ธ: pytest
  5. ์ฝ”๋“œ ํฌ๋งทํŒ…: black src tests
  6. Pull Request ์ œ์ถœ

๋ผ์ด์„ ์Šค

MIT License - ์ž์„ธํ•œ ๋‚ด์šฉ์€ LICENSE ํŒŒ์ผ์„ ์ฐธ์กฐํ•˜์„ธ์š”.

์ง€์›

๋ฌธ์˜์‚ฌํ•ญ ๋ฐ ์ด์Šˆ:

  • ์ €์žฅ์†Œ์— ์ด์Šˆ ์ƒ์„ฑ
  • ๋ฐ์ดํ„ฐ ๊ฐ€์ด๋“œ๋Š” DATA_GUIDE.md ์ฐธ์กฐ
  • ์‚ฌ์šฉ ํŒจํ„ด์€ ์˜ˆ์ œ ํ™•์ธ

๋ณ€๊ฒฝ ์ด๋ ฅ

๋ฒ„์ „ ํžˆ์Šคํ† ๋ฆฌ๋Š” CHANGELOG.md๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

๊ฐ์‚ฌ์˜ ๊ธ€

  • K-water์˜ ํ•œ๊ตญ ๋Œ ๊ด€๋ฆฌ ์‹œ์Šคํ…œ์„ ์œ„ํ•ด ๊ฐœ๋ฐœ๋˜์—ˆ์Šต๋‹ˆ๋‹ค
  • ๋ฐ์ดํ„ฐ ์ ‘๊ทผ์„ ์œ„ํ•ด MCP (Model Context Protocol) ์‚ฌ์šฉ
  • ํ…Œ์ŠคํŠธ ์ฃผ๋„ ๊ฐœ๋ฐœ(TDD) ๋ฐฉ๋ฒ•๋ก ์œผ๋กœ ๊ฐœ๋ฐœ๋˜์—ˆ์Šต๋‹ˆ๋‹ค

๋ฒ ํƒ€ ์˜คํ”ˆ ์•ˆ๋‚ด

โš ๏ธ ํ˜„์žฌ ๋ฒ ํƒ€ ๋ฒ„์ „์ž…๋‹ˆ๋‹ค.

์ด SDK๋Š” ๋ฒ ํƒ€ ํ…Œ์ŠคํŠธ ๋‹จ๊ณ„์— ์žˆ์Šต๋‹ˆ๋‹ค. ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ ์‚ฌ์šฉํ•˜๊ธฐ ์ „์— ์ถฉ๋ถ„ํ•œ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•ด์ฃผ์„ธ์š”.

์•Œ๋ ค์ง„ ์ œํ•œ์‚ฌํ•ญ:

  • ์ผ๋ถ€ ์ธก์ • ํ•ญ๋ชฉ์€ ๋ฐ์ดํ„ฐ ๊ฐ€์šฉ์„ฑ์— ๋”ฐ๋ผ ์กฐํšŒ๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค
  • MCP ์„œ๋ฒ„ ์‘๋‹ต ์‹œ๊ฐ„์€ ๋„คํŠธ์›Œํฌ ์ƒํƒœ์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

ํ”ผ๋“œ๋ฐฑ:

  • GitHub Issues๋ฅผ ํ†ตํ•ด ๋ฒ„๊ทธ ๋ฆฌํฌํŠธ ๋ฐ ๊ธฐ๋Šฅ ์ œ์•ˆ์„ ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค
  • ๋ฒ ํƒ€ ํ…Œ์Šคํ„ฐ๋ถ„๋“ค์˜ ํ”ผ๋“œ๋ฐฑ์ด SDK ๊ฐœ์„ ์— ํฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค

๋ฌธ์˜: GitHub Issues ๋˜๋Š” K-water ๋‹ด๋‹น์ž์—๊ฒŒ ์—ฐ๋ฝํ•ด์ฃผ์„ธ์š”.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

kdm_sdk-0.2.2.tar.gz (89.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

kdm_sdk-0.2.2-py3-none-any.whl (33.4 kB view details)

Uploaded Python 3

File details

Details for the file kdm_sdk-0.2.2.tar.gz.

File metadata

  • Download URL: kdm_sdk-0.2.2.tar.gz
  • Upload date:
  • Size: 89.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.7

File hashes

Hashes for kdm_sdk-0.2.2.tar.gz
Algorithm Hash digest
SHA256 957dd1239867c491c6fb18cbcd9b73caf5641626517e6ada12d140f60c31adb9
MD5 6b99d0e063809e41d0eb40fa4523d2bf
BLAKE2b-256 d9d769cc532bceae3c77d52300b5f4b1c509ec052145185bc9883044c23d781b

See more details on using hashes here.

File details

Details for the file kdm_sdk-0.2.2-py3-none-any.whl.

File metadata

  • Download URL: kdm_sdk-0.2.2-py3-none-any.whl
  • Upload date:
  • Size: 33.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.7

File hashes

Hashes for kdm_sdk-0.2.2-py3-none-any.whl
Algorithm Hash digest
SHA256 25d030c01295a1c8caa67916d8822f368f8f6fba1bb16b5d48cf9f6d1a973f56
MD5 e9eff9c2ff89d0558571b01089561674
BLAKE2b-256 0309a417ea4e063e4246af8032bf4799f161de179b3debd23ebdb1795059fc03

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page