init commit, input data parsing logic and page
commit
a60d49ae92
|
|
@ -0,0 +1,189 @@
|
|||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# pipenv
|
||||
Pipfile.lock
|
||||
|
||||
# poetry
|
||||
poetry.lock
|
||||
|
||||
# pdm
|
||||
.pdm.toml
|
||||
|
||||
# PEP 582
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
# IDE - VSCode
|
||||
.vscode/
|
||||
*.code-workspace
|
||||
|
||||
# IDE - PyCharm
|
||||
.idea/
|
||||
*.iml
|
||||
*.iws
|
||||
*.ipr
|
||||
|
||||
# IDE - Sublime Text
|
||||
*.sublime-project
|
||||
*.sublime-workspace
|
||||
|
||||
# IDE - Vim
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
# OS generated files
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
desktop.ini
|
||||
|
||||
# Project specific
|
||||
*.db
|
||||
*.sqlite
|
||||
*.sqlite3
|
||||
logs/
|
||||
temp/
|
||||
tmp/
|
||||
cache/
|
||||
|
||||
# FastAPI
|
||||
.fastapi_cache/
|
||||
|
||||
# Security - API keys should never be committed
|
||||
.env
|
||||
.env.local
|
||||
.env.*.local
|
||||
secrets.json
|
||||
config.json
|
||||
|
||||
# Backup files
|
||||
*.bak
|
||||
*.backup
|
||||
*.old
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
# 부동산 자연어 검색 시스템
|
||||
|
||||
FastAPI와 OpenAI를 활용한 부동산 자연어 검색 웹 애플리케이션
|
||||
|
||||
## 기능
|
||||
|
||||
- 자연어로 부동산 조건 입력
|
||||
- OpenAI API를 통한 자동 정보 추출
|
||||
- 가격, 위치, 면적, 방 수, 거래 유형 파싱
|
||||
|
||||
## 설치
|
||||
|
||||
```bash
|
||||
cd C:\o2o\RealEstateSearch
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
## 설정
|
||||
|
||||
1. `.env` 파일에 OpenAI API 키 설정:
|
||||
```
|
||||
OPENAI_API_KEY=your-actual-api-key
|
||||
```
|
||||
|
||||
## 실행
|
||||
|
||||
```bash
|
||||
cd C:\o2o\RealEstateSearch\backend
|
||||
python main.py
|
||||
```
|
||||
|
||||
브라우저에서 http://localhost:20001 접속
|
||||
|
||||
## 입력 예시
|
||||
- "강남역 근처 전세 2억 이하 투룸"
|
||||
- "서초동 30평대 아파트 매매 10억 이하"
|
||||
- "판교 방 3개 월세 100/50"
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
import os
|
||||
from fastapi import FastAPI, HTTPException
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from fastapi.responses import FileResponse
|
||||
from dotenv import load_dotenv
|
||||
import uvicorn
|
||||
|
||||
from models import RealEstateQuery, ParsedRealEstate
|
||||
from openai_parser import OpenAIParser
|
||||
|
||||
load_dotenv()
|
||||
|
||||
app = FastAPI(title="부동산 검색 API")
|
||||
|
||||
# CORS 설정
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["*"],
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
# OpenAI 파서 초기화
|
||||
try:
|
||||
parser = OpenAIParser()
|
||||
except ValueError as e:
|
||||
print(f"Warning: {e}")
|
||||
parser = None
|
||||
|
||||
@app.get("/")
|
||||
async def serve_index():
|
||||
"""메인 페이지 제공"""
|
||||
return FileResponse("../frontend/index.html")
|
||||
|
||||
@app.post("/api/parse", response_model=ParsedRealEstate)
|
||||
async def parse_real_estate(query: RealEstateQuery):
|
||||
"""자연어 입력을 파싱하여 부동산 정보 추출"""
|
||||
if not parser:
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail="OpenAI API key not configured. Please set OPENAI_API_KEY in .env file"
|
||||
)
|
||||
|
||||
try:
|
||||
result = await parser.parse_real_estate_query(query.text)
|
||||
print(result)
|
||||
return result
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
# 정적 파일 서빙 (CSS, JS)
|
||||
app.mount("/static", StaticFiles(directory="../frontend"), name="static")
|
||||
|
||||
if __name__ == "__main__":
|
||||
host = os.getenv("HOST", "0.0.0.0")
|
||||
port = int(os.getenv("PORT", 20001))
|
||||
|
||||
print(f"Starting server at http://localhost:{port}")
|
||||
uvicorn.run(app, host=host, port=port, reload=True)
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
from pydantic import BaseModel
|
||||
from typing import Optional
|
||||
|
||||
class RealEstateQuery(BaseModel):
|
||||
"""부동산 검색 쿼리 모델"""
|
||||
text: str
|
||||
|
||||
class ParsedRealEstate(BaseModel):
|
||||
"""파싱된 부동산 정보 모델"""
|
||||
price: Optional[str] = None
|
||||
location: Optional[str] = None
|
||||
area: Optional[str] = None
|
||||
rooms: Optional[str] = None
|
||||
transaction_type: Optional[str] = None # 전세, 월세, 매매
|
||||
raw_text: str
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
import os
|
||||
import json
|
||||
from openai import OpenAI
|
||||
from dotenv import load_dotenv
|
||||
from models import ParsedRealEstate
|
||||
|
||||
load_dotenv()
|
||||
|
||||
class OpenAIParser:
|
||||
"""OpenAI를 이용한 부동산 정보 파싱"""
|
||||
|
||||
def __init__(self):
|
||||
api_key = os.getenv("OPENAI_API_KEY")
|
||||
if not api_key or api_key == "your-api-key-here":
|
||||
raise ValueError("OpenAI API key not configured in .env file")
|
||||
self.client = OpenAI(api_key=api_key)
|
||||
|
||||
async def parse_real_estate_query(self, text: str) -> ParsedRealEstate:
|
||||
"""자연어 텍스트에서 부동산 정보 추출"""
|
||||
|
||||
system_prompt = """
|
||||
당신은 부동산 정보를 추출하는 전문가입니다.
|
||||
사용자의 자연어 입력에서 다음 정보를 추출하세요.
|
||||
단위는 붙여서 표기하세요. :
|
||||
1. price: 가격 (전세금, 월세, 매매가 등) (string)
|
||||
2. location: 위치 (지역명, 동, 구 등) (string)
|
||||
3. area: 면적 (평수, 제곱미터) (string)
|
||||
4. rooms: 방 개수 (string)
|
||||
5. transaction_type: 거래 유형 (전세, 월세, 매매) (string)
|
||||
|
||||
JSON 형식으로만 응답하세요.
|
||||
정보가 없는 항목은 null로 표시하세요.
|
||||
"""
|
||||
|
||||
try:
|
||||
response = self.client.chat.completions.create(
|
||||
model="gpt-3.5-turbo",
|
||||
messages=[
|
||||
{"role": "system", "content": system_prompt},
|
||||
{"role": "user", "content": text}
|
||||
],
|
||||
temperature=0.1,
|
||||
response_format={"type": "json_object"}
|
||||
)
|
||||
|
||||
result = json.loads(response.choices[0].message.content)
|
||||
print(result)
|
||||
|
||||
return ParsedRealEstate(
|
||||
price=result.get("price"),
|
||||
location=result.get("location"),
|
||||
area=result.get("area"),
|
||||
rooms=result.get("rooms"),
|
||||
transaction_type=result.get("transaction_type"),
|
||||
raw_text=text
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
# 에러 발생 시 기본값 반환
|
||||
return ParsedRealEstate(
|
||||
raw_text=text,
|
||||
price=None,
|
||||
location=None,
|
||||
area=None,
|
||||
rooms=None,
|
||||
transaction_type=None
|
||||
)
|
||||
|
|
@ -0,0 +1,428 @@
|
|||
# 부동산 정보 검색 API 가이드
|
||||
|
||||
## 1. 공공데이터 API (국토교통부)
|
||||
|
||||
### 1.1 아파트 매매 실거래가 API
|
||||
- **서비스명**: 국토교통부_아파트 매매 실거래가 자료
|
||||
- **제공기관**: 국토교통부
|
||||
- **URL**: https://www.data.go.kr/data/15126469/openapi.do
|
||||
- **Base URL**: `apis.data.go.kr/1613000/RTMSDataSvcAptTrade`
|
||||
- **엔드포인트**: `/getRTMSDataSvcAptTrade`
|
||||
- **데이터 형식**: XML
|
||||
- **트래픽 제한**: 개발계정 10,000/일
|
||||
|
||||
#### 주요 파라미터
|
||||
- `serviceKey`: 공공데이터포털에서 발급받은 인증키
|
||||
- `LAWD_CD`: 법정동 코드 5자리 (예: 서울 종로구 11110)
|
||||
- `DEAL_YMD`: 계약년월 6자리 (예: 202501)
|
||||
|
||||
### 1.2 아파트 전월세 실거래가 API
|
||||
- **서비스명**: 국토교통부_아파트 전월세 실거래가 자료
|
||||
- **제공기관**: 국토교통부
|
||||
- **URL**: https://www.data.go.kr/data/15126474/openapi.do
|
||||
- **Base URL**: `apis.data.go.kr/1613000/RTMSDataSvcAptRent`
|
||||
- **엔드포인트**: `/getRTMSDataSvcAptRent`
|
||||
- **데이터 형식**: XML
|
||||
- **트래픽 제한**: 개발계정 10,000/일
|
||||
|
||||
#### 주요 파라미터
|
||||
- `serviceKey`: 공공데이터포털에서 발급받은 인증키
|
||||
- `LAWD_CD`: 법정동 코드
|
||||
- `DEAL_YMD`: 계약년월
|
||||
|
||||
### 1.3 연립/다세대 주택 실거래가 API
|
||||
- **서비스명**: 국토교통부_연립다세대 매매/전월세 실거래가 자료
|
||||
- **제공기관**: 국토교통부
|
||||
- **URL**:
|
||||
- 매매: https://www.data.go.kr/data/15126467/openapi.do
|
||||
- 전월세: https://www.data.go.kr/data/15126473/openapi.do
|
||||
- **Base URL**:
|
||||
- 매매: `apis.data.go.kr/1613000/RTMSDataSvcSHTrade`
|
||||
- 전월세: `apis.data.go.kr/1613000/RTMSDataSvcSHRent`
|
||||
- **엔드포인트**:
|
||||
- 매매: `/getRTMSDataSvcSHTrade`
|
||||
- 전월세: `/getRTMSDataSvcSHRent`
|
||||
- **데이터 형식**: XML
|
||||
- **트래픽 제한**: 개발계정 10,000/일
|
||||
|
||||
### 1.4 오피스텔 실거래가 API
|
||||
- **서비스명**: 국토교통부_오피스텔 매매/전월세 실거래가 자료
|
||||
- **제공기관**: 국토교통부
|
||||
- **URL**:
|
||||
- 매매: https://www.data.go.kr/data/15126464/openapi.do
|
||||
- 전월세: https://www.data.go.kr/data/15126475/openapi.do
|
||||
- **Base URL**:
|
||||
- 매매: `apis.data.go.kr/1613000/RTMSDataSvcOffiTrade`
|
||||
- 전월세: `apis.data.go.kr/1613000/RTMSDataSvcOffiRent`
|
||||
- **엔드포인트**:
|
||||
- 매매: `/getRTMSDataSvcOffiTrade`
|
||||
- 전월세: `/getRTMSDataSvcOffiRent`
|
||||
- **데이터 형식**: XML
|
||||
- **트래픽 제한**: 개발계정 10,000/일
|
||||
|
||||
### 1.5 단독/다가구 주택 실거래가 API
|
||||
- **서비스명**: 국토교통부_단독다가구 매매/전월세 실거래가 자료
|
||||
- **제공기관**: 국토교통부
|
||||
- **URL**:
|
||||
- 매매: https://www.data.go.kr/data/15126465/openapi.do
|
||||
- 전월세: https://www.data.go.kr/data/15126472/openapi.do
|
||||
- **Base URL**:
|
||||
- 매매: `apis.data.go.kr/1613000/RTMSDataSvcSHHouseTrade`
|
||||
- 전월세: `apis.data.go.kr/1613000/RTMSDataSvcSHHouseRent`
|
||||
- **엔드포인트**:
|
||||
- 매매: `/getRTMSDataSvcSHHouseTrade`
|
||||
- 전월세: `/getRTMSDataSvcSHHouseRent`
|
||||
- **데이터 형식**: XML
|
||||
- **트래픽 제한**: 개발계정 10,000/일
|
||||
|
||||
### 1.6 토지 실거래가 API
|
||||
- **서비스명**: 국토교통부_토지 매매 실거래가 자료
|
||||
- **제공기관**: 국토교통부
|
||||
- **URL**: https://www.data.go.kr/data/15126466/openapi.do
|
||||
- **Base URL**: `apis.data.go.kr/1613000/RTMSDataSvcLandTrade`
|
||||
- **엔드포인트**: `/getRTMSDataSvcLandTrade`
|
||||
- **데이터 형식**: XML
|
||||
- **트래픽 제한**: 개발계정 10,000/일
|
||||
|
||||
### 1.7 상업/업무용 부동산 실거래가 API
|
||||
- **서비스명**: 국토교통부_상업업무용 부동산 매매 실거래가 자료
|
||||
- **제공기관**: 국토교통부
|
||||
- **URL**: https://www.data.go.kr/data/15126463/openapi.do
|
||||
- **Base URL**: `apis.data.go.kr/1613000/RTMSDataSvcNrgTrade`
|
||||
- **엔드포인트**: `/getRTMSDataSvcNrgTrade`
|
||||
- **데이터 형식**: XML
|
||||
- **트래픽 제한**: 개발계정 10,000/일
|
||||
|
||||
## 2. 한국부동산원 API
|
||||
|
||||
### 2.1 부동산 통계 조회 서비스
|
||||
- **서비스명**: 한국부동산원_부동산통계 조회 서비스
|
||||
- **제공기관**: 한국부동산원
|
||||
- **URL**: https://www.data.go.kr/data/15134761/openapi.do
|
||||
- **Base URL**: https://www.reb.or.kr/r-one/portal/openapi
|
||||
- **주요 통계**:
|
||||
- 주택가격동향조사
|
||||
- 지가변동률
|
||||
- 상업용부동산 임대동향
|
||||
- 오피스텔 가격동향
|
||||
- 공동주택 실거래가격지수
|
||||
|
||||
### 2.2 아파트 단지 정보 API
|
||||
- **서비스명**: 한국부동산원_전국 아파트단지 정보
|
||||
- **특징**: 전국 아파트 단지의 기본 정보 및 동 정보 제공
|
||||
- **데이터**: 단지명, 주소, 세대수, 준공년월 등
|
||||
|
||||
## 3. LH 한국토지주택공사 API
|
||||
|
||||
### 3.1 공공임대주택 단지정보 조회 서비스
|
||||
- **서비스명**: 한국토지주택공사_공공임대주택 단지정보 조회 서비스
|
||||
- **URL**: https://www.data.go.kr/data/15058476/openapi.do
|
||||
- **Base URL**: `apis.data.go.kr/B552555/lhPublicRentalHousingComplexInquireSvc`
|
||||
- **엔드포인트**: `/getPublicRentalHousingComplexList`
|
||||
- **특징**: LH에서 관리하는 공공임대주택 정보 제공
|
||||
- **데이터 형식**: XML/JSON
|
||||
|
||||
### 3.2 임대주택단지 조회 서비스
|
||||
- **서비스명**: 한국토지주택공사_임대주택단지 조회 서비스
|
||||
- **URL**: https://www.data.go.kr/data/15059475/openapi.do
|
||||
- **Base URL**: `apis.data.go.kr/B552555/lhLeaseholdBuldListService`
|
||||
- **엔드포인트**: `/lhLeaseholdBuldList`
|
||||
- **데이터**: 임대유형, 임대료, 위치 정보 등
|
||||
- **데이터 형식**: XML/JSON
|
||||
|
||||
### 3.3 분양/임대 공고문 조회 서비스
|
||||
- **서비스명**: 한국토지주택공사_분양임대공고문 조회 서비스
|
||||
- **URL**: https://www.data.go.kr/data/15058530/openapi.do
|
||||
- **Base URL**: `apis.data.go.kr/B552555/lhLeaseNoticeInfo`
|
||||
- **엔드포인트**: `/lhLeaseNoticeInfo`
|
||||
- **특징**: LH 분양/임대 공고 정보 실시간 제공
|
||||
- **데이터 형식**: XML/JSON
|
||||
|
||||
## 4. 지자체 부동산 API
|
||||
|
||||
### 4.1 서울시 부동산 API
|
||||
- **제공기관**: 서울특별시
|
||||
- **플랫폼**: 서울 열린데이터광장 (data.seoul.go.kr)
|
||||
- **주요 API**:
|
||||
- 서울시 부동산 실거래가 정보
|
||||
- 서울시 전월세가 정보
|
||||
- 서울시 부동산 중개업소 정보
|
||||
|
||||
### 4.2 경기도 부동산 API
|
||||
- **제공기관**: 경기도
|
||||
- **플랫폼**: 경기데이터드림 (data.gg.go.kr)
|
||||
- **주요 API**:
|
||||
- 경기도 임대주택 현황
|
||||
- 경기도 부동산 중개업소 현황
|
||||
|
||||
### 4.3 SH 서울주택도시공사 API
|
||||
- **제공기관**: 서울주택도시공사
|
||||
- **URL**: https://www.i-sh.co.kr
|
||||
- **주요 데이터**:
|
||||
- SH 임대주택 정보
|
||||
- SH 분양 정보
|
||||
- 상가 및 공장 정보
|
||||
|
||||
## 5. 주택금융 관련 API
|
||||
|
||||
### 5.1 주택도시보증공사 (HUG) API
|
||||
- **제공기관**: 주택도시보증공사
|
||||
- **URL**: https://www.khug.or.kr
|
||||
- **Base URL**: `openapi.khug.or.kr`
|
||||
- **주요 API**:
|
||||
- 전세보증금 보증 정보: `/api/guarantee/deposit`
|
||||
- 분양보증 정보: `/api/guarantee/sale`
|
||||
- 주택금융 통계: `/api/statistics/housing`
|
||||
|
||||
### 5.2 마이홈포털 API
|
||||
- **서비스명**: 국토교통부_마이홈포털 공공임대주택 단지정보 조회 서비스
|
||||
- **URL**: https://www.data.go.kr/data/15110581/openapi.do
|
||||
- **Base URL**: `apis.data.go.kr/1613000/MyHomeService`
|
||||
- **엔드포인트**: `/getPublicRentalHousingInfo`
|
||||
- **특징**: 전국 공공임대주택 통합 정보 제공
|
||||
- **데이터 형식**: XML/JSON
|
||||
|
||||
## 6. Python을 이용한 API 호출 예제
|
||||
|
||||
### 6.1 공공데이터 API 호출 예제
|
||||
```python
|
||||
import requests
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
def get_apartment_trade_data(service_key, lawd_cd, deal_ymd):
|
||||
"""
|
||||
아파트 매매 실거래가 데이터 조회
|
||||
"""
|
||||
base_url = "http://apis.data.go.kr/1613000/RTMSDataSvcAptTrade/getRTMSDataSvcAptTrade"
|
||||
|
||||
params = {
|
||||
'serviceKey': service_key,
|
||||
'LAWD_CD': lawd_cd,
|
||||
'DEAL_YMD': deal_ymd,
|
||||
'pageNo': 1,
|
||||
'numOfRows': 100
|
||||
}
|
||||
|
||||
response = requests.get(base_url, params=params)
|
||||
|
||||
if response.status_code == 200:
|
||||
# XML 파싱
|
||||
root = ET.fromstring(response.content)
|
||||
items = root.findall('.//item')
|
||||
|
||||
results = []
|
||||
for item in items:
|
||||
data = {
|
||||
'아파트명': item.findtext('아파트'),
|
||||
'전용면적': item.findtext('전용면적'),
|
||||
'거래금액': item.findtext('거래금액'),
|
||||
'거래년': item.findtext('년'),
|
||||
'거래월': item.findtext('월'),
|
||||
'거래일': item.findtext('일'),
|
||||
'층': item.findtext('층'),
|
||||
'건축년도': item.findtext('건축년도'),
|
||||
'도로명': item.findtext('도로명'),
|
||||
'법정동': item.findtext('법정동')
|
||||
}
|
||||
results.append(data)
|
||||
|
||||
return results
|
||||
else:
|
||||
return None
|
||||
```
|
||||
|
||||
### 6.2 오피스텔 전월세 데이터 조회 예제
|
||||
```python
|
||||
def get_officetel_rent_data(service_key, lawd_cd, deal_ymd):
|
||||
"""
|
||||
오피스텔 전월세 실거래가 데이터 조회
|
||||
"""
|
||||
base_url = "http://apis.data.go.kr/1613000/RTMSDataSvcOffiRent/getRTMSDataSvcOffiRent"
|
||||
|
||||
params = {
|
||||
'serviceKey': service_key,
|
||||
'LAWD_CD': lawd_cd,
|
||||
'DEAL_YMD': deal_ymd,
|
||||
'pageNo': 1,
|
||||
'numOfRows': 100
|
||||
}
|
||||
|
||||
response = requests.get(base_url, params=params)
|
||||
|
||||
if response.status_code == 200:
|
||||
root = ET.fromstring(response.content)
|
||||
items = root.findall('.//item')
|
||||
|
||||
results = []
|
||||
for item in items:
|
||||
data = {
|
||||
'단지명': item.findtext('단지'),
|
||||
'전용면적': item.findtext('전용면적'),
|
||||
'보증금': item.findtext('보증금액'),
|
||||
'월세': item.findtext('월세금액'),
|
||||
'층': item.findtext('층'),
|
||||
'건축년도': item.findtext('건축년도'),
|
||||
'법정동': item.findtext('법정동')
|
||||
}
|
||||
results.append(data)
|
||||
|
||||
return results
|
||||
else:
|
||||
return None
|
||||
```
|
||||
|
||||
### 6.3 통합 API 호출 클래스 예제
|
||||
```python
|
||||
class RealEstateAPI:
|
||||
"""
|
||||
국토교통부 부동산 실거래가 통합 API 클래스
|
||||
"""
|
||||
|
||||
BASE_URL = "http://apis.data.go.kr/1613000"
|
||||
|
||||
ENDPOINTS = {
|
||||
'apt_trade': '/RTMSDataSvcAptTrade/getRTMSDataSvcAptTrade',
|
||||
'apt_rent': '/RTMSDataSvcAptRent/getRTMSDataSvcAptRent',
|
||||
'sh_trade': '/RTMSDataSvcSHTrade/getRTMSDataSvcSHTrade',
|
||||
'sh_rent': '/RTMSDataSvcSHRent/getRTMSDataSvcSHRent',
|
||||
'offi_trade': '/RTMSDataSvcOffiTrade/getRTMSDataSvcOffiTrade',
|
||||
'offi_rent': '/RTMSDataSvcOffiRent/getRTMSDataSvcOffiRent',
|
||||
'house_trade': '/RTMSDataSvcSHHouseTrade/getRTMSDataSvcSHHouseTrade',
|
||||
'house_rent': '/RTMSDataSvcSHHouseRent/getRTMSDataSvcSHHouseRent',
|
||||
'land': '/RTMSDataSvcLandTrade/getRTMSDataSvcLandTrade',
|
||||
'business': '/RTMSDataSvcNrgTrade/getRTMSDataSvcNrgTrade'
|
||||
}
|
||||
|
||||
def __init__(self, service_key):
|
||||
self.service_key = service_key
|
||||
|
||||
def get_data(self, api_type, lawd_cd, deal_ymd, page=1, rows=100):
|
||||
"""
|
||||
통합 데이터 조회 메서드
|
||||
|
||||
:param api_type: API 타입 (apt_trade, apt_rent, sh_trade 등)
|
||||
:param lawd_cd: 법정동 코드 5자리
|
||||
:param deal_ymd: 거래년월 6자리
|
||||
:param page: 페이지 번호
|
||||
:param rows: 한 페이지당 행 수
|
||||
"""
|
||||
if api_type not in self.ENDPOINTS:
|
||||
raise ValueError(f"Invalid API type: {api_type}")
|
||||
|
||||
url = self.BASE_URL + self.ENDPOINTS[api_type]
|
||||
params = {
|
||||
'serviceKey': self.service_key,
|
||||
'LAWD_CD': lawd_cd,
|
||||
'DEAL_YMD': deal_ymd,
|
||||
'pageNo': page,
|
||||
'numOfRows': rows
|
||||
}
|
||||
|
||||
response = requests.get(url, params=params)
|
||||
if response.status_code == 200:
|
||||
return self._parse_xml(response.content)
|
||||
else:
|
||||
return None
|
||||
|
||||
def _parse_xml(self, xml_content):
|
||||
"""XML 파싱 헬퍼 메서드"""
|
||||
root = ET.fromstring(xml_content)
|
||||
items = root.findall('.//item')
|
||||
return [self._extract_item_data(item) for item in items]
|
||||
|
||||
def _extract_item_data(self, item):
|
||||
"""아이템 데이터 추출"""
|
||||
# XML 엘리먼트에서 모든 데이터 추출
|
||||
data = {}
|
||||
for child in item:
|
||||
data[child.tag] = child.text
|
||||
return data
|
||||
```
|
||||
|
||||
## 7. 민간 부동산 API
|
||||
|
||||
### 7.1 네이버 부동산
|
||||
- **특징**: 공식 API 미제공, 웹 크롤링으로 데이터 수집
|
||||
- **주의사항**: robots.txt 확인 및 과도한 요청 자제
|
||||
- **대안**: Selenium을 이용한 동적 페이지 크롤링
|
||||
|
||||
### 7.2 직방 API (비공식)
|
||||
- **특징**: 내부 API 엔드포인트 활용 가능
|
||||
- **주의사항**: 공식 지원 없음, 변경 가능성 있음
|
||||
- **주요 엔드포인트**:
|
||||
- 지역 검색: `https://apis.zigbang.com/v2/search`
|
||||
- 매물 리스트: `https://apis.zigbang.com/v2/items`
|
||||
- 매물 상세: `https://apis.zigbang.com/v2/items/{item_id}`
|
||||
- 단지 정보: `https://apis.zigbang.com/v2/complex/{complex_id}`
|
||||
|
||||
### 7.3 호갱노노
|
||||
- **특징**: 아파트 실거래가 정보 특화
|
||||
- **URL**: https://hogangnono.com
|
||||
- **데이터**: 실거래가, 시세 차트, 단지 정보
|
||||
- **주의사항**: 웹 크롤링 필요
|
||||
|
||||
### 7.4 부동산114
|
||||
- **특징**: 종합 부동산 정보 제공
|
||||
- **URL**: https://www.r114.com
|
||||
- **데이터**: 시세, 실거래가, 분양 정보
|
||||
- **주의사항**: 회원가입 필요한 경우 있음
|
||||
|
||||
### 7.5 KB부동산
|
||||
- **특징**: KB국민은행 제공 부동산 데이터
|
||||
- **URL**: https://data.kbland.kr
|
||||
- **데이터**: 주택가격동향, 시세, 통계
|
||||
- **주의사항**: 일부 데이터는 유료
|
||||
|
||||
## 8. API 활용 시 주의사항
|
||||
|
||||
1. **인증키 관리**: 환경변수나 별도 설정 파일로 관리
|
||||
2. **트래픽 제한**: 일일 호출 제한 확인
|
||||
3. **데이터 갱신 주기**: 실시간이 아닌 일정 주기로 갱신됨
|
||||
4. **에러 처리**: 네트워크 오류, 서비스 점검 대응
|
||||
5. **법적 제약**: 개인정보보호법 준수
|
||||
|
||||
## 9. 추천 활용 방법
|
||||
|
||||
1. **캐싱 구현**: 동일 요청 반복 방지
|
||||
2. **배치 처리**: 대량 데이터는 야간 배치로 처리
|
||||
3. **데이터베이스 저장**: 조회한 데이터 로컬 DB 저장
|
||||
4. **모니터링**: API 응답 시간 및 에러율 모니터링
|
||||
|
||||
## 10. API 종류별 요약 테이블
|
||||
|
||||
| 구분 | API 제공처 | 데이터 종류 | 비용 | 인증 필요 |
|
||||
|------|------------|-------------|------|-----------|
|
||||
| 국토교통부 | 공공데이터포털 | 아파트/오피스텔/연립/단독 실거래가 | 무료 | O |
|
||||
| 한국부동산원 | 한국부동산원 | 부동산 통계, 가격지수 | 무료 | O |
|
||||
| LH공사 | 공공데이터포털 | 공공임대주택 정보 | 무료 | O |
|
||||
| SH공사 | SH/서울시 | 서울시 임대주택 정보 | 무료 | O |
|
||||
| 지자체 | 각 지자체 | 지역별 부동산 정보 | 무료 | O |
|
||||
| 네이버 | 네이버 | 매물, 시세 정보 | - | X |
|
||||
| 직방 | 직방 | 원룸/오피스텔 매물 | - | X |
|
||||
| 호갱노노 | 호갱노노 | 아파트 실거래가 | 무료 | X |
|
||||
| 부동산114 | 부동산114 | 종합 부동산 정보 | 일부유료 | △ |
|
||||
| KB부동산 | KB국민은행 | 부동산 통계/시세 | 일부유료 | △ |
|
||||
|
||||
## 11. API 엔드포인트 빠른 참조
|
||||
|
||||
### 국토교통부 실거래가 API 엔드포인트 목록
|
||||
|
||||
| 부동산 종류 | 거래 유형 | Base URL | 엔드포인트 |
|
||||
|------------|-----------|----------|------------|
|
||||
| 아파트 | 매매 | apis.data.go.kr/1613000/RTMSDataSvcAptTrade | /getRTMSDataSvcAptTrade |
|
||||
| 아파트 | 전월세 | apis.data.go.kr/1613000/RTMSDataSvcAptRent | /getRTMSDataSvcAptRent |
|
||||
| 연립/다세대 | 매매 | apis.data.go.kr/1613000/RTMSDataSvcSHTrade | /getRTMSDataSvcSHTrade |
|
||||
| 연립/다세대 | 전월세 | apis.data.go.kr/1613000/RTMSDataSvcSHRent | /getRTMSDataSvcSHRent |
|
||||
| 오피스텔 | 매매 | apis.data.go.kr/1613000/RTMSDataSvcOffiTrade | /getRTMSDataSvcOffiTrade |
|
||||
| 오피스텔 | 전월세 | apis.data.go.kr/1613000/RTMSDataSvcOffiRent | /getRTMSDataSvcOffiRent |
|
||||
| 단독/다가구 | 매매 | apis.data.go.kr/1613000/RTMSDataSvcSHHouseTrade | /getRTMSDataSvcSHHouseTrade |
|
||||
| 단독/다가구 | 전월세 | apis.data.go.kr/1613000/RTMSDataSvcSHHouseRent | /getRTMSDataSvcSHHouseRent |
|
||||
| 토지 | 매매 | apis.data.go.kr/1613000/RTMSDataSvcLandTrade | /getRTMSDataSvcLandTrade |
|
||||
| 상업/업무용 | 매매 | apis.data.go.kr/1613000/RTMSDataSvcNrgTrade | /getRTMSDataSvcNrgTrade |
|
||||
|
||||
### 공통 파라미터
|
||||
- `serviceKey`: 공공데이터포털 인증키 (필수)
|
||||
- `LAWD_CD`: 법정동 코드 5자리 (필수)
|
||||
- `DEAL_YMD`: 거래년월 6자리 (필수)
|
||||
- `pageNo`: 페이지 번호 (선택, 기본값: 1)
|
||||
- `numOfRows`: 한 페이지 결과 수 (선택, 기본값: 10)
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
[2025-08-19 10:55:09] 모든 부동산 API 엔드포인트 상세 정보 추가
|
||||
- 국토교통부 실거래가 API 엔드포인트 조사
|
||||
- 아파트 매매/전월세 API 엔드포인트 확인
|
||||
- 연립/다세대 매매/전월세 API 엔드포인트 추가
|
||||
- 오피스텔 매매/전월세 API 엔드포인트 추가
|
||||
- 단독/다가구 매매/전월세 API 엔드포인트 추가
|
||||
- 토지 매매 API 엔드포인트 추가
|
||||
- 상업/업무용 부동산 매매 API 엔드포인트 추가
|
||||
- docs/api_guide.md 대폭 업데이트
|
||||
- 모든 API의 Base URL 및 정확한 엔드포인트 경로 명시
|
||||
- LH 공사 API 3종 엔드포인트 추가
|
||||
- 마이홈포털 API 엔드포인트 추가
|
||||
- 직방 API 추가 엔드포인트 (매물 상세, 단지 정보)
|
||||
- 통합 API 호출 클래스(RealEstateAPI) 예제 코드 추가
|
||||
- API 엔드포인트 빠른 참조 테이블 작성
|
||||
- 공통 파라미터 설명 추가
|
||||
- 웹 브라우저를 통한 공공데이터포털 직접 확인
|
||||
- docs/project_plan.md 업데이트 (API 엔드포인트 추가 완료)
|
||||
|
||||
[2025-08-19 10:29:10] 추가 부동산 API 조사 및 문서 업데이트
|
||||
- 광범위한 부동산 API 웹 검색 수행
|
||||
- 국토교통부 전체 부동산 실거래가 API 조사
|
||||
- 한국부동산원 Open API 목록 확인
|
||||
- LH 한국토지주택공사 API 조사
|
||||
- 지자체별 부동산 API 정보 수집
|
||||
- docs/api_guide.md 대폭 확장
|
||||
- 연립/다세대, 오피스텔, 단독/다가구, 토지, 상업용 부동산 API 추가
|
||||
- 한국부동산원 부동산 통계 API 섹션 추가
|
||||
- LH 공공임대주택 관련 API 3종 추가
|
||||
- SH 서울주택도시공사 및 지자체 API 정보 추가
|
||||
- 주택금융 관련 API (HUG, 마이홈포털) 추가
|
||||
- 민간 부동산 서비스 확장 (호갱노노, 부동산114, KB부동산)
|
||||
- 오피스텔 전월세 API 호출 예제 코드 추가
|
||||
- API 종류별 요약 테이블 작성
|
||||
- docs/project_plan.md 업데이트 (추가 API 조사 완료 표시)
|
||||
|
||||
[2025-08-19 10:14:28] 부동산 정보 검색 API 가이드 문서 작성
|
||||
- 공공데이터포털 API 조사
|
||||
- 국토교통부 아파트 매매 실거래가 API 정보 확인
|
||||
- 국토교통부 아파트 전월세 실거래가 API 정보 확인
|
||||
- docs/api_guide.md 파일 생성 및 작성
|
||||
- 공공데이터 API (국토교통부) 섹션
|
||||
- Python API 호출 예제 코드
|
||||
- 민간 부동산 API 정보 (네이버, 직방)
|
||||
- API 활용 시 주의사항
|
||||
- 추천 활용 방법
|
||||
- docs/project_plan.md 업데이트 (API 가이드 문서 추가)
|
||||
- 웹 검색 및 브라우저를 통한 실제 API 정보 수집
|
||||
|
||||
[2025-08-19 11:29:38] .gitignore 파일 생성 작업 완료
|
||||
- Python 환경용 .gitignore 파일 생성
|
||||
- 포함 내용:
|
||||
- Python 컴파일 파일 (__pycache__, *.pyc 등)
|
||||
- 가상환경 (venv, env 등)
|
||||
- IDE 설정 파일 (VSCode, PyCharm, Sublime Text, Vim)
|
||||
- OS 생성 파일 (DS_Store, Thumbs.db 등)
|
||||
- 환경 변수 파일 (.env, .env.local 등)
|
||||
- 테스트 및 커버리지 파일
|
||||
- 로그 및 임시 파일
|
||||
- FastAPI 캐시
|
||||
- 백업 파일
|
||||
- 특히 .env 파일이 Git에 커밋되지 않도록 설정
|
||||
|
||||
[2025-08-19 11:28:27] .gitignore 파일 생성 작업 시작
|
||||
- Python 환경용 .gitignore 파일 생성
|
||||
|
||||
[2025-08-19 11:23:57] 불필요한 파일 정리 작업 완료
|
||||
- src/app.py 삭제 (Chainlit 메인 앱)
|
||||
- src/search_engine.py 삭제 (Chainlit 검색 엔진)
|
||||
- src 폴더 삭제
|
||||
- 최종 프로젝트 구조 정리 완료
|
||||
- FastAPI 기반 부동산 검색 시스템만 유지
|
||||
|
||||
[2025-08-19 11:22:54] 불필요한 파일 정리 작업 시작
|
||||
- Chainlit 관련 파일 삭제 예정
|
||||
- src 폴더 및 내부 파일 삭제 예정
|
||||
|
||||
[2025-08-19 11:20:14] FastAPI 및 OpenAI 기반 부동산 검색 웹사이트 개발 완료
|
||||
- backend 폴더 생성
|
||||
- frontend 폴더 생성
|
||||
- requirements.txt 업데이트 (FastAPI, uvicorn, openai, python-dotenv 등)
|
||||
- .env 파일 생성 (OpenAI API 키 설정 템플릿)
|
||||
- backend/models.py: Pydantic 데이터 모델 정의
|
||||
- RealEstateQuery: 사용자 입력 모델
|
||||
- ParsedRealEstate: 파싱 결과 모델
|
||||
- backend/openai_parser.py: OpenAI API 파싱 로직
|
||||
- GPT-3.5-turbo 모델 사용
|
||||
- JSON 응답 포맷으로 구조화된 데이터 추출
|
||||
- backend/main.py: FastAPI 서버
|
||||
- CORS 설정
|
||||
- /api/parse 엔드포인트
|
||||
- 정적 파일 서빙
|
||||
- 포트 20001에서 실행
|
||||
- frontend/index.html: 메인 페이지
|
||||
- 자연어 입력 텍스트 영역
|
||||
- 예시 제공
|
||||
- 결과 표시 섹션
|
||||
- frontend/style.css: 스타일시트
|
||||
- 그라디언트 배경
|
||||
- 반응형 디자인
|
||||
- 로딩 애니메이션
|
||||
- frontend/script.js: 클라이언트 로직
|
||||
- API 호출
|
||||
- 결과 파싱 및 표시
|
||||
- Enter 키 지원
|
||||
- README.md 업데이트
|
||||
- 기존 src 폴더의 Chainlit 파일들 유지 (app.py, search_engine.py)
|
||||
|
||||
[2025-08-19 11:14:44] FastAPI 및 OpenAI 기반 부동산 검색 웹사이트 개발 시작
|
||||
- Chainlit에서 FastAPI로 전환 결정
|
||||
- OpenAI API를 활용한 자연어 처리 구현 예정
|
||||
- 입력: 자연어 텍스트
|
||||
- 출력: 가격, 위치, 면적, 방 수, 거래 유형
|
||||
|
||||
[2025-08-19 09:54:26] Chainlit 부동산 검색 프로그램 개발 완료
|
||||
- 프로젝트 폴더 구조 생성 (C:\o2o\RealEstateSearch)
|
||||
- docs/project_plan.md 작성
|
||||
- requirements.txt 작성 (chainlit, requests, beautifulsoup4, selenium, pandas)
|
||||
- src/app.py 작성 - Chainlit 메인 애플리케이션
|
||||
- 사용자 입력 파싱 기능 (전세금, 방 개수, 지역명)
|
||||
- 검색 파라미터 관리
|
||||
- 검색 결과 포맷팅 및 표시
|
||||
- src/search_engine.py 작성 - 부동산 검색 엔진
|
||||
- RealEstateSearchEngine 클래스
|
||||
- 샘플 데이터 반환 (실제 API 연동 준비)
|
||||
- README.md 작성 (설치 및 실행 방법)
|
||||
- 모든 작업 완료
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
# 부동산 검색 프로젝트 계획
|
||||
|
||||
## 프로젝트 개요
|
||||
- **목적**: FastAPI와 OpenAI를 이용한 부동산 검색 웹사이트
|
||||
- **주요 기능**: 자연어 입력을 받아 OpenAI로 파싱 후 부동산 정보 추출
|
||||
|
||||
## 기술 스택
|
||||
- **Backend**: Python, FastAPI, OpenAI API
|
||||
- **Frontend**: HTML, CSS, JavaScript
|
||||
- **NLP**: OpenAI GPT API
|
||||
|
||||
## 폴더 구조
|
||||
```
|
||||
C:\o2o\RealEstateSearch\
|
||||
├── docs/
|
||||
│ ├── project_plan.md
|
||||
│ └── project_logs.txt
|
||||
├── backend/
|
||||
│ ├── main.py (FastAPI 서버)
|
||||
│ ├── openai_parser.py (OpenAI 파싱 로직)
|
||||
│ └── models.py (데이터 모델)
|
||||
├── frontend/
|
||||
│ ├── index.html
|
||||
│ ├── style.css
|
||||
│ └── script.js
|
||||
├── requirements.txt
|
||||
├── .env (API 키 저장)
|
||||
├── .gitignore (Git 제외 파일)
|
||||
└── README.md
|
||||
```
|
||||
|
||||
## 작업 단계
|
||||
- [x] 프로젝트 폴더 구조 생성
|
||||
- [x] 프로젝트 계획서 작성
|
||||
- [x] FastAPI 백엔드 개발
|
||||
- [x] OpenAI 파싱 로직 구현
|
||||
- [x] 프론트엔드 개발
|
||||
- [x] README.md 업데이트
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>부동산 검색 - 자연어 분석</title>
|
||||
<link rel="stylesheet" href="/static/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<header>
|
||||
<h1>🏠 부동산 자연어 검색</h1>
|
||||
<p>원하시는 부동산 조건을 자유롭게 입력해주세요</p>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<div class="search-section">
|
||||
<textarea id="searchInput" placeholder="예: 강남역 근처 전세 2억 이하 투룸 찾아줘
|
||||
서초동 30평대 아파트 매매 10억 이하
|
||||
방 3개짜리 월세 100/50 이하 판교"></textarea>
|
||||
<button id="searchBtn" onclick="parseQuery()">분석하기</button>
|
||||
</div>
|
||||
|
||||
<div class="examples">
|
||||
<h3>입력 예시:</h3>
|
||||
<div class="example-chips">
|
||||
<span class="chip" onclick="setExample(this)">강남 전세 3억 방 2개</span>
|
||||
<span class="chip" onclick="setExample(this)">판교 30평 아파트 매매</span>
|
||||
<span class="chip" onclick="setExample(this)">서초동 월세 200/100</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="resultSection" class="result-section" style="display: none;">
|
||||
<h2>📊 분석 결과</h2>
|
||||
<div id="resultContent"></div>
|
||||
</div>
|
||||
|
||||
<div id="loadingSection" class="loading" style="display: none;">
|
||||
<div class="spinner"></div>
|
||||
<p>AI가 분석 중입니다...</p>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
<script src="/static/script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
// 예시 텍스트 설정
|
||||
function setExample(element) {
|
||||
document.getElementById('searchInput').value = element.textContent;
|
||||
}
|
||||
|
||||
// 쿼리 파싱 및 분석
|
||||
async function parseQuery() {
|
||||
const input = document.getElementById('searchInput').value.trim();
|
||||
|
||||
if (!input) {
|
||||
alert('검색할 내용을 입력해주세요!');
|
||||
return;
|
||||
}
|
||||
|
||||
// UI 상태 변경
|
||||
document.getElementById('loadingSection').style.display = 'block';
|
||||
document.getElementById('resultSection').style.display = 'none';
|
||||
document.getElementById('searchBtn').disabled = true;
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/parse', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ text: input })
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('서버 오류가 발생했습니다.');
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
displayResults(data);
|
||||
|
||||
} catch (error) {
|
||||
alert('오류: ' + error.message);
|
||||
console.error('Error:', error);
|
||||
} finally {
|
||||
document.getElementById('loadingSection').style.display = 'none';
|
||||
document.getElementById('searchBtn').disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 결과 표시
|
||||
function displayResults(data) {
|
||||
const resultContent = document.getElementById('resultContent');
|
||||
|
||||
let html = '';
|
||||
|
||||
if (data.transaction_type) {
|
||||
html += `<div class="result-item">
|
||||
<strong>거래 유형:</strong> ${data.transaction_type}
|
||||
</div>`;
|
||||
}
|
||||
|
||||
if (data.price) {
|
||||
html += `<div class="result-item">
|
||||
<strong>가격:</strong> ${data.price}
|
||||
</div>`;
|
||||
}
|
||||
|
||||
if (data.location) {
|
||||
html += `<div class="result-item">
|
||||
<strong>위치:</strong> ${data.location}
|
||||
</div>`;
|
||||
}
|
||||
|
||||
if (data.area) {
|
||||
html += `<div class="result-item">
|
||||
<strong>면적:</strong> ${data.area}
|
||||
</div>`;
|
||||
}
|
||||
|
||||
if (data.rooms) {
|
||||
html += `<div class="result-item">
|
||||
<strong>방 개수:</strong> ${data.rooms}
|
||||
</div>`;
|
||||
}
|
||||
|
||||
if (!html) {
|
||||
html = '<p>추출된 정보가 없습니다. 더 구체적으로 입력해주세요.</p>';
|
||||
}
|
||||
|
||||
resultContent.innerHTML = html;
|
||||
document.getElementById('resultSection').style.display = 'block';
|
||||
}
|
||||
|
||||
// Enter 키로 검색
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
document.getElementById('searchInput').addEventListener('keypress', function(e) {
|
||||
if (e.key === 'Enter' && !e.shiftKey) {
|
||||
e.preventDefault();
|
||||
parseQuery();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,152 @@
|
|||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 90%;
|
||||
max-width: 800px;
|
||||
background: white;
|
||||
border-radius: 20px;
|
||||
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
|
||||
padding: 40px;
|
||||
}
|
||||
|
||||
header {
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
header h1 {
|
||||
color: #333;
|
||||
font-size: 2.5em;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
header p {
|
||||
color: #666;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.search-section {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
#searchInput {
|
||||
width: 100%;
|
||||
min-height: 120px;
|
||||
padding: 15px;
|
||||
font-size: 16px;
|
||||
border: 2px solid #e0e0e0;
|
||||
border-radius: 10px;
|
||||
resize: vertical;
|
||||
font-family: inherit;
|
||||
transition: border-color 0.3s;
|
||||
}
|
||||
|
||||
#searchInput:focus {
|
||||
outline: none;
|
||||
border-color: #667eea;
|
||||
}
|
||||
|
||||
#searchBtn {
|
||||
width: 100%;
|
||||
padding: 15px;
|
||||
margin-top: 15px;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 10px;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
|
||||
#searchBtn:hover {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.examples {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.examples h3 {
|
||||
color: #555;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.example-chips {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.chip {
|
||||
background: #f0f0f0;
|
||||
padding: 8px 16px;
|
||||
border-radius: 20px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.chip:hover {
|
||||
background: #667eea;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.result-section {
|
||||
background: #f8f9fa;
|
||||
padding: 25px;
|
||||
border-radius: 15px;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.result-section h2 {
|
||||
color: #333;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.result-item {
|
||||
background: white;
|
||||
padding: 15px;
|
||||
border-radius: 10px;
|
||||
margin-bottom: 15px;
|
||||
border-left: 4px solid #667eea;
|
||||
}
|
||||
|
||||
.result-item strong {
|
||||
color: #667eea;
|
||||
display: inline-block;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.loading {
|
||||
text-align: center;
|
||||
padding: 40px;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border: 5px solid #f3f3f3;
|
||||
border-top: 5px solid #667eea;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
margin: 0 auto 20px;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
fastapi
|
||||
uvicorn[standard]
|
||||
openai
|
||||
python-dotenv
|
||||
Loading…
Reference in New Issue