| 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 |
|
|
| |
| 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" |
| ) |
|
|
| |
| class CoordinateRequest(BaseModel): |
| latitude: float |
| longitude: float |
|
|
| |
| class DataResponse(BaseModel): |
| values: str |
| status: str = "success" |
|
|
| |
| solid_data_app = None |
|
|
| |
| @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") |
|
|
| |
| @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: |
| |
| df_data = solid_data_app.get_data(request.longitude, request.latitude) |
| |
| |
| 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') |
|
|
| |
| cols_to_normalize = [ |
| 'SlopesCl1', 'SlopesCl2', 'SlopesCl3', 'SlopesCl4', |
| 'SlopesCl5', 'SlopesCl6', 'SlopesCl7', 'SlopesCl8', |
| 'AspectClN', 'AspectClE', 'AspectClS', 'AspectClW', 'AspectClU' |
| ] |
|
|
| |
| mask = df_data['name'].isin(cols_to_normalize) |
| values = df_data.loc[mask, 'value'] |
|
|
| |
| 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 |
| |
| 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)}") |
|
|
| |
| @app.get("/health") |
| async def health_check(): |
| return {"status": "ok"} |
|
|
| |
| @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)}") |
|
|
| |
| if __name__ == "__main__": |
| port = int(os.environ.get("PORT", 7860)) |
| uvicorn.run("app:app", host="0.0.0.0", port=port, reload=True) |