Soil-Data / app.py
l1aF2027's picture
Update app.py
857cec1 verified
from fastapi import FastAPI, HTTPException
import uvicorn
from pydantic import BaseModel
from typing import List, Optional
import numpy as np
import os
from tqdm.auto import tqdm
import pandas as pd
from solid_data import SolidData
from retrieval_app import RetrievalSolidData
# Khởi tạo FastAPI app
app = FastAPI(
title="Solid Data API",
description="API để tra cứu dữ liệu dựa trên tọa độ latitude và longitude",
version="1.0.0"
)
# Model dữ liệu đầu vào
class CoordinateRequest(BaseModel):
latitude: float
longitude: float
# Model dữ liệu đầu ra
class DataResponse(BaseModel):
values: str
status: str = "success"
# Biến global để lưu đối tượng RetrievalSolidData
solid_data_app = None
# Hàm khởi tạo dữ liệu - sẽ được gọi khi server khởi động
@app.on_event("startup")
async def startup_event():
global solid_data_app
solid_data_path = os.environ.get("SOLID_DATA_PATH", "./solid_data")
print(f"Khởi tạo dữ liệu từ thư mục: {solid_data_path}")
solid_data_app = RetrievalSolidData(solid_data_path)
print("Khởi tạo dữ liệu hoàn tất")
# API endpoint để lấy dữ liệu dựa trên tọa độ
@app.post("/get_data", response_model=DataResponse)
async def get_data(request: CoordinateRequest):
global solid_data_app
if solid_data_app is None:
raise HTTPException(status_code=500, detail="Hệ thống dữ liệu chưa được khởi tạo")
try:
# Lấy dữ liệu từ RetrievalSolidData
df_data = solid_data_app.get_data(request.longitude, request.latitude)
# Sắp xếp dữ liệu theo thứ tự như yêu cầu
new_order = ['CULTIR', 'CULTRF', 'CULT', 'FOR', 'GRS', 'NVG', 'sq1', 'sq2', 'sq3', 'sq4', 'sq5', 'sq6', 'sq7', 'URB', 'WAT', 'AspectClE',
'AspectClN', 'AspectClS', 'AspectClU', 'AspectClW', 'Elevation', 'SlopesCl1', 'SlopesCl2', 'SlopesCl3', 'SlopesCl4', 'SlopesCl5',
'SlopesCl6', 'SlopesCl7', 'SlopesCl8', 'LandMask']
df_data['name'] = pd.Categorical(df_data['name'], categories=new_order, ordered=True)
df_data = df_data.sort_values('name').reset_index(drop=True)
df_data['value'] = pd.to_numeric(df_data['value'], errors='coerce')
# Các cột cần normalize
cols_to_normalize = [
'SlopesCl1', 'SlopesCl2', 'SlopesCl3', 'SlopesCl4',
'SlopesCl5', 'SlopesCl6', 'SlopesCl7', 'SlopesCl8',
'AspectClN', 'AspectClE', 'AspectClS', 'AspectClW', 'AspectClU'
]
# Lọc theo các cột cần normalize
mask = df_data['name'].isin(cols_to_normalize)
values = df_data.loc[mask, 'value']
# Thực hiện chuẩn hóa 0–1 nếu có dữ liệu hợp lệ
if not values.isnull().all():
min_val = 0
max_val = 10000
if max_val != min_val:
df_data.loc[mask, 'value'] = (values - min_val) / (max_val - min_val)
else:
df_data.loc[mask, 'value'] = 0.0
# Chuyển cột value thành một chuỗi dạng [x1, x2, ...]
values_list = df_data['value'].tolist()
values_str = str(values_list).replace("'", "")
return DataResponse(values=values_str)
except ValueError as e:
raise HTTPException(status_code=400, detail=f"Lỗi dữ liệu: {str(e)}")
except Exception as e:
raise HTTPException(status_code=500, detail=f"Lỗi hệ thống: {str(e)}")
# API endpoint để kiểm tra trạng thái
@app.get("/health")
async def health_check():
return {"status": "ok"}
# API endpoint để lấy thông tin về dữ liệu
@app.get("/data_info")
async def get_data_info():
global solid_data_app
if solid_data_app is None:
raise HTTPException(status_code=500, detail="Hệ thống dữ liệu chưa được khởi tạo")
try:
info_df = solid_data_app.get_data_info()
return {"data_info": info_df.to_dict(orient="records")}
except Exception as e:
raise HTTPException(status_code=500, detail=f"Lỗi hệ thống: {str(e)}")
# Chạy ứng dụng nếu file này được thực thi trực tiếp
if __name__ == "__main__":
port = int(os.environ.get("PORT", 7860)) # Hugging Face Spaces sử dụng cổng 7860
uvicorn.run("app:app", host="0.0.0.0", port=port, reload=True)