use fastgpt python sdk
This commit is contained in:
+20
-1
@@ -8,4 +8,23 @@ class Config:
|
||||
API_V1_STR = "/api/v1"
|
||||
SECRET_KEY = os.getenv("SECRET_KEY", "your-secret-key")
|
||||
DATABASE_URL = os.getenv("DATABASE_URL", "sqlite:///./test.db")
|
||||
DEBUG = os.getenv("DEBUG", "false").lower() in ("true", "1", "t")
|
||||
DEBUG = os.getenv("DEBUG", "false").lower() in ("true", "1", "t")
|
||||
|
||||
# FastGPT Configuration
|
||||
FASTGPT_API_KEY = os.getenv("ANALYSIS_AUTH_TOKEN")
|
||||
FASTGPT_BASE_URL = os.getenv("ANALYSIS_SERVICE_URL")
|
||||
FASTGPT_APP_ID = os.getenv("APP_ID")
|
||||
DELETE_SESSION_URL = os.getenv("DELETE_SESSION_URL")
|
||||
DELETE_CHAT_URL = os.getenv("DELETE_CHAT_URL")
|
||||
GET_CHAT_RECORDS_URL = os.getenv("GET_CHAT_RECORDS_URL")
|
||||
|
||||
@classmethod
|
||||
def validate(cls):
|
||||
"""Validate required configuration."""
|
||||
required = [
|
||||
("FASTGPT_API_KEY", cls.FASTGPT_API_KEY),
|
||||
("FASTGPT_APP_ID", cls.FASTGPT_APP_ID),
|
||||
]
|
||||
missing = [name for name, value in required if not value]
|
||||
if missing:
|
||||
raise ValueError(f"Missing required environment variables: {', '.join(missing)}")
|
||||
@@ -0,0 +1,39 @@
|
||||
"""FastGPT client dependency injection."""
|
||||
from contextlib import asynccontextmanager
|
||||
from fastapi import FastAPI
|
||||
from fastgpt_client import AsyncChatClient
|
||||
from .config import Config
|
||||
|
||||
# Global client instance
|
||||
_fastgpt_client: AsyncChatClient | None = None
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
"""Manage FastGPT client lifecycle."""
|
||||
global _fastgpt_client
|
||||
Config.validate()
|
||||
|
||||
# Initialize client
|
||||
_fastgpt_client = AsyncChatClient(
|
||||
api_key=Config.FASTGPT_API_KEY,
|
||||
base_url=Config.FASTGPT_BASE_URL,
|
||||
timeout=60.0,
|
||||
max_retries=3,
|
||||
retry_delay=1.0,
|
||||
enable_logging=Config.DEBUG,
|
||||
)
|
||||
await _fastgpt_client.__aenter__()
|
||||
|
||||
yield
|
||||
|
||||
# Cleanup
|
||||
if _fastgpt_client:
|
||||
await _fastgpt_client.__aexit__(None, None, None)
|
||||
|
||||
|
||||
def get_fastgpt_client() -> AsyncChatClient:
|
||||
"""Get the FastGPT client instance."""
|
||||
if _fastgpt_client is None:
|
||||
raise RuntimeError("FastGPT client not initialized")
|
||||
return _fastgpt_client
|
||||
@@ -0,0 +1,79 @@
|
||||
"""Loguru logging configuration."""
|
||||
import sys
|
||||
import logging
|
||||
import inspect
|
||||
from loguru import logger
|
||||
from pathlib import Path
|
||||
from .config import Config
|
||||
|
||||
# Remove default logger
|
||||
logger.remove()
|
||||
|
||||
# Add console handler with color
|
||||
logger.add(
|
||||
sys.stderr,
|
||||
format="<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>",
|
||||
level="DEBUG" if Config.DEBUG else "INFO",
|
||||
colorize=True,
|
||||
)
|
||||
|
||||
# Add file handler with rotation
|
||||
log_dir = Path("logs")
|
||||
log_dir.mkdir(exist_ok=True)
|
||||
|
||||
logger.add(
|
||||
log_dir / "server_{time:YYYY-MM-DD}.log",
|
||||
rotation="00:00", # Rotate at midnight
|
||||
retention="30 days", # Keep logs for 30 days
|
||||
compression="zip", # Compress old logs
|
||||
format="{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <8} | {name}:{function}:{line} - {message}",
|
||||
level="DEBUG",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
# Add error file handler
|
||||
logger.add(
|
||||
log_dir / "error_{time:YYYY-MM-DD}.log",
|
||||
rotation="00:00",
|
||||
retention="90 days",
|
||||
compression="zip",
|
||||
format="{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <8} | {name}:{function}:{line} - {message}",
|
||||
level="ERROR",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
# Configure uvicorn logging to use loguru
|
||||
class InterceptHandler(logging.Handler):
|
||||
"""Intercept standard logging messages toward loguru."""
|
||||
|
||||
def emit(self, record: logging.LogRecord) -> None:
|
||||
# Get corresponding Loguru level if it exists
|
||||
try:
|
||||
level = logger.level(record.levelname).name
|
||||
except ValueError:
|
||||
level = str(record.levelno)
|
||||
|
||||
# Find caller from where originated the logged message
|
||||
frame, depth = inspect.currentframe(), 2
|
||||
while frame and frame.f_code.co_filename == logging.__file__:
|
||||
frame = frame.f_back
|
||||
depth += 1
|
||||
|
||||
logger.opt(depth=depth, exception=record.exc_info).log(level, record.getMessage())
|
||||
|
||||
|
||||
def setup_logging():
|
||||
"""Configure logging for the application."""
|
||||
# Intercept uvicorn and fastapi loggers
|
||||
logging.getLogger("uvicorn").handlers = [InterceptHandler()]
|
||||
logging.getLogger("uvicorn.access").handlers = [InterceptHandler()]
|
||||
logging.getLogger("fastapi").handlers = [InterceptHandler()]
|
||||
|
||||
# Set log levels
|
||||
logging.getLogger("uvicorn").setLevel(logging.INFO)
|
||||
logging.getLogger("uvicorn.access").setLevel(logging.INFO)
|
||||
logging.getLogger("fastapi").setLevel(logging.INFO)
|
||||
|
||||
# Intercept httpx logs if needed
|
||||
logging.getLogger("httpx").handlers = [InterceptHandler()]
|
||||
logging.getLogger("httpx").setLevel(logging.WARNING)
|
||||
Reference in New Issue
Block a user