diff --git a/src/gentrade_server/config.py b/src/gentrade_server/config.py deleted file mode 100644 index c1e3721..0000000 --- a/src/gentrade_server/config.py +++ /dev/null @@ -1,14 +0,0 @@ -""" -Configure -""" -from pydantic_settings import BaseSettings - -class Settings(BaseSettings): - """ - Settings - """ - OPENAI_API_KEY: str = "" - OPENAI_API_URL: str = "" - OPENAI_API_MODEL: str = "gpt-3.5-turbo" - -settings = Settings() diff --git a/src/gentrade_server/main.py b/src/gentrade_server/main.py index f322470..866af9a 100644 --- a/src/gentrade_server/main.py +++ b/src/gentrade_server/main.py @@ -9,10 +9,10 @@ from fastapi import FastAPI, Depends from fastapi.middleware.cors import CORSMiddleware -from .routers import secure, public, agent +from .routers import public, agent, admin from .auth import get_user from .util import check_server_time -from .config import settings +from .model import settings from .datahub import DataHub logging.basicConfig(level=logging.INFO, format='%(asctime)s %(message)s') @@ -51,14 +51,16 @@ def receive_signal(number, _): public.router, prefix="/api/v1/public" ) + app.include_router( - secure.router, - prefix="/api/v1/secure", + agent.router, + prefix="/api/v1/agent", dependencies=[Depends(get_user)] ) + app.include_router( - agent.router, - prefix="/api/v1/agent", + admin.router, + prefix="/api/v1/admin", dependencies=[Depends(get_user)] ) diff --git a/src/gentrade_server/model.py b/src/gentrade_server/model.py new file mode 100644 index 0000000..37d5dc3 --- /dev/null +++ b/src/gentrade_server/model.py @@ -0,0 +1,72 @@ +""" +Model +""" +from typing import List + +from pydantic import BaseModel, Field, field_validator +from pydantic_settings import BaseSettings, SettingsConfigDict + +class HealthCheck(BaseModel): + """ + Response model to validate and return when performing a health check. + """ + status: str = Field("OK") + +class Settings(BaseSettings): + """ + Settings + """ + model_config = SettingsConfigDict(enable_decoding=False) + + openai_api_key: str = "" + openai_api_url: str = "" + openai_api_model: str = "gpt-3.5-turbo" + + ntp_servers : List[str] = Field( + "ntp.ntsc.ac.cn,ntp.sjtu.edu.cn,cn.ntp.org.cn,cn.pool.ntp.org,ntp.aliyun.com", + description="The string list of NTP server splitted via comma") + + @field_validator('ntp_servers', mode='before') + @classmethod + def decode_ntp_servers(cls, v: str) -> List[str]: + """decode function override + + Args: + v (str): input string + + Returns: + List[str]: splitted list for all NTP servers + """ + return v.split(',') + +settings = Settings() + +class Market(BaseModel): + """ + Response model to validate and return when performing a health check. + """ + name: str = Field(...) + type: str = Field(...) + +class Asset(BaseModel): + """ + Asset Model_ + """ + name: str = Field(...) + type: str = Field(...) + market: str = Field(...) + quote: str = Field(...) + cik: int = Field(None, description="only for US stock") + symbol: str = Field(None, description="only for crypto") + base: str = Field(None, description="only for crypto") + +class OHLCV(BaseModel): + """ + OHLCV model + """ + time: int = Field(..., description="UTC timestamp in seconds") + open: float = Field(...) + high: float = Field(...) + low: float = Field(...) + close: float = Field(...) + vol: float = Field(...) diff --git a/src/gentrade_server/routers/admin.py b/src/gentrade_server/routers/admin.py new file mode 100644 index 0000000..6cdeeb7 --- /dev/null +++ b/src/gentrade_server/routers/admin.py @@ -0,0 +1,20 @@ +''' +Admin portal +''' +import logging + +from fastapi import APIRouter, Depends +from ..model import settings, Settings +from ..auth import get_user + +LOG = logging.getLogger(__name__) + +router = APIRouter() + +@router.get("/settings") +async def get_settings(user: dict = Depends(get_user)) -> Settings: + """ + Get server settings + """ + LOG.info(user) + return settings diff --git a/src/gentrade_server/routers/agent.py b/src/gentrade_server/routers/agent.py index 96216f4..d2a5988 100644 --- a/src/gentrade_server/routers/agent.py +++ b/src/gentrade_server/routers/agent.py @@ -5,15 +5,15 @@ from openai import OpenAI from fastapi import APIRouter, Depends from ..auth import get_user -from ..config import settings +from ..model import settings LOG = logging.getLogger(__name__) router = APIRouter() client = OpenAI( - api_key=settings.OPENAI_API_KEY, - base_url=settings.OPENAI_API_URL + api_key=settings.openai_api_key, + base_url=settings.openai_api_url ) @router.get("/") @@ -22,7 +22,7 @@ async def get_answer(prompt: str, user: dict = Depends(get_user)): Prompt to OpenAI and get answer """ completion = client.chat.completions.create( - model=settings.OPENAI_API_MODEL, + model=settings.openai_api_model, messages=[ {"role": "system", "content": "You are a Lu Ken's assistant for cryptocurrency market."}, diff --git a/src/gentrade_server/routers/public.py b/src/gentrade_server/routers/public.py index a7ef678..525a378 100644 --- a/src/gentrade_server/routers/public.py +++ b/src/gentrade_server/routers/public.py @@ -8,30 +8,15 @@ import datetime from dateutil.tz import tzlocal -from fastapi import APIRouter -from pydantic import BaseModel +from fastapi import APIRouter, HTTPException -from ..config import settings from ..datahub import DataHub +from ..model import HealthCheck, Market, Asset, OHLCV LOG = logging.getLogger(__name__) router = APIRouter() -@router.get("/") -async def get_testroute(): - """ - Test public interface - """ - return "OK" - -class HealthCheck(BaseModel): - """ - Response model to validate and return when performing a health check. - """ - - status: str = "OK" - @router.get("/health") async def get_health() -> HealthCheck: """ @@ -39,15 +24,6 @@ async def get_health() -> HealthCheck: """ return HealthCheck(status="OK") -@router.get("/settings") -async def get_settings(): - """ - Get server settings - """ - return { - 'ntp_server': settings.ntp_server - } - @router.get("/server_time") async def get_server_time(): """ @@ -63,8 +39,8 @@ async def get_server_time(): 'timestamp_server': int(curr_ts) } -@router.get("/markets/") -async def get_markets(): +@router.get("/markets") +async def get_markets() -> dict[str, Market]: """ Get markets """ @@ -76,36 +52,33 @@ async def get_markets(): } return retval -@router.get("/assets/") -async def get_assets(market_id:str=""): - """ - Get assets +@router.get("/markets/{market_id}/assets") +async def get_assets(market_id:str="b13a4902-ad9d-11ef-a239-00155d3ba217", + start:int=0, limit:int=1000) -> list[Asset]: + """Get assets array, The maximus lenth is 1000 + + Args: + market_id (str, optional): Market ID string. Defaults to + "b13a4902-ad9d-11ef-a239-00155d3ba217". + start (int, optional): Start index. Defaults to 0. + + Returns: + dict[str, Asset]: _description_ """ - ret = {} - markets = [] - if len(market_id) != 0 and market_id not in DataHub.inst().markets: - LOG.error("could not find the market %s", market_id) - return ret - if len(market_id) == 0: - for id_ in DataHub.inst().markets: - markets.append(id_) - else: - markets.append(market_id) - - for id_ in markets: - market_inst = DataHub.inst().markets[id_] - for asset in market_inst.assets.values(): - if market_inst.market_id == "b13a4902-ad9d-11ef-a239-00155d3ba217" and \ - asset.asset_type == "spot": - ret[asset.name] = asset.to_dict() - elif market_inst.market_id == "5784f1f5-d8f6-401d-8d24-f685a3812f2d" and \ - asset.asset_type == "stock": - ret[asset.name] = asset.to_dict() - return ret - -@router.get("/asset/fetch_ohlcv/") + markets = DataHub.inst().markets + + if market_id not in markets: + raise HTTPException(status_code=404, detail="Item not found") + + assets = list(markets[market_id].assets.values()) + + if start > len(assets) - 1: + raise HTTPException(status_code=404, detail="Item not found") + return [item.to_dict() for item in assets[start:min(start + limit, len(assets))]] + +@router.get("/asset/fetch_ohlcv") async def fetch_ohlcv(assetname:str='btc_usdt', interval="1d", - since:int=-1, to:int=-1,limit:int=300): + since:int=-1, to:int=-1,limit:int=300) -> list[OHLCV]: """fetch ohlcv Args: @@ -119,7 +92,7 @@ async def fetch_ohlcv(assetname:str='btc_usdt', interval="1d", _type_: _description_ """ retval = {} - LOG.info("fetch_ohlcv: %s", assetname) + LOG.info("fetch_ohlcv: %s, interval: %s", assetname, interval) asset = DataHub.inst().get_asset(assetname) if asset is not None: ret = asset.fetch_ohlcv(interval, since, to, limit) diff --git a/src/gentrade_server/routers/secure.py b/src/gentrade_server/routers/secure.py deleted file mode 100644 index d47347a..0000000 --- a/src/gentrade_server/routers/secure.py +++ /dev/null @@ -1,14 +0,0 @@ -""" -Secure API interface -""" -from fastapi import APIRouter, Depends -from ..auth import get_user - -router = APIRouter() - -@router.get("/") -async def get_testroute(user: dict = Depends(get_user)): - """ - Test secure interface - """ - return user