test
This commit is contained in:
parent
043386268b
commit
e3860e2490
|
@ -2,27 +2,14 @@ import os
|
|||
from pydantic_settings import BaseSettings
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# Load .env file from the backend directory (one level up from core)
|
||||
# BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
# load_dotenv(os.path.join(BASE_DIR, '..', '.env')) # Adjust path if needed
|
||||
|
||||
# Or simply let pydantic-settings handle it by default if .env is in the root execution dir
|
||||
load_dotenv()
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
DATABASE_URL: str = "sqlite:///./default.db" # Default value if not in .env
|
||||
# Настройки JWT удалены
|
||||
# SECRET_KEY: str = "default_secret"
|
||||
# ALGORITHM: str = "HS256"
|
||||
# ACCESS_TOKEN_EXPIRE_MINUTES: int = 30
|
||||
DATABASE_URL: str = "sqlite:///./default.db"
|
||||
|
||||
class Config:
|
||||
env_file = ".env"
|
||||
env_file_encoding = 'utf-8'
|
||||
# If your .env file is not in the root directory where you run uvicorn,
|
||||
# you might need to specify the path explicitly:
|
||||
# env_file = '../.env' # Example if running from inside 'app' dir
|
||||
|
||||
|
||||
settings = Settings()
|
|
@ -2,17 +2,14 @@ from sqlalchemy import create_engine
|
|||
from sqlalchemy.orm import sessionmaker
|
||||
from app.core.config import settings
|
||||
|
||||
# Create SQLAlchemy engine
|
||||
engine = create_engine(
|
||||
settings.DATABASE_URL,
|
||||
# Required for SQLite to prevent issues with FastAPI's async nature
|
||||
|
||||
connect_args={"check_same_thread": False} if "sqlite" in settings.DATABASE_URL else {}
|
||||
)
|
||||
|
||||
# Create a session factory
|
||||
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||
|
||||
# Dependency to get DB session (we'll use this in routers)
|
||||
def get_db():
|
||||
db = SessionLocal()
|
||||
try:
|
||||
|
|
|
@ -2,7 +2,7 @@ import asyncio
|
|||
import random
|
||||
from typing import Dict, Any
|
||||
|
||||
# Делаем функцию асинхронной
|
||||
|
||||
async def solve_cutting_problem(input_params: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
Асинхронная заглушка для имитации сложного расчета раскройки стекла.
|
||||
|
@ -10,26 +10,23 @@ async def solve_cutting_problem(input_params: Dict[str, Any]) -> Dict[str, Any]:
|
|||
"""
|
||||
print(f"Received input for async fuzzy solver: {input_params}")
|
||||
|
||||
# Имитация времени расчета с использованием asyncio.sleep
|
||||
delay = random.uniform(0.5, 2.0)
|
||||
print(f"Simulating calculation for {delay:.2f} seconds...")
|
||||
await asyncio.sleep(delay) # Используем await asyncio.sleep вместо time.sleep
|
||||
|
||||
# Пример выходных данных (остается таким же)
|
||||
await asyncio.sleep(delay)
|
||||
|
||||
output_data = {
|
||||
"layout": [
|
||||
{"piece_id": 1, "x": 10, "y": 10, "width": 500, "height": 300},
|
||||
{"piece_id": 2, "x": 520, "y": 10, "width": 400, "height": 300},
|
||||
# ... другие детали раскроя ...
|
||||
|
||||
],
|
||||
"waste_percentage": round(random.uniform(5.0, 15.0), 2),
|
||||
"number_of_cuts": random.randint(5, 20),
|
||||
"processing_time_ms": int(delay * 1000) # Используем задержку как время обработки
|
||||
"processing_time_ms": int(delay * 1000)
|
||||
}
|
||||
|
||||
# Можно добавить логику на основе input_params, если нужно для тестов
|
||||
if input_params.get("optimize_for") == "speed":
|
||||
output_data["number_of_cuts"] = random.randint(15, 25) # Больше резов - быстрее?
|
||||
output_data["number_of_cuts"] = random.randint(15, 25)
|
||||
|
||||
print(f"Async fuzzy solver generated output: {output_data}")
|
||||
return output_data
|
|
@ -1,37 +1,25 @@
|
|||
from fastapi import FastAPI
|
||||
from fastapi.middleware.cors import CORSMiddleware # Импортируем middleware
|
||||
from app.routers import calculation # Импортируем роутер
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from app.routers import calculation
|
||||
|
||||
app = FastAPI(title="Glass Cutting Optimization API")
|
||||
|
||||
# --- Настройка CORS ---
|
||||
# Список разрешенных источников (origins)
|
||||
# Для разработки можно разрешить все или указать адрес вашего React-приложения
|
||||
origins = [
|
||||
"http://localhost", # Если React запускается на http://localhost:port
|
||||
"http://localhost:3000", # Стандартный порт для create-react-app
|
||||
"http://localhost:5173", # Стандартный порт для Vite/React
|
||||
# "http://127.0.0.1:5173", # Можно добавить и IP-адрес
|
||||
# "*" # Разрешить все источники (будьте осторожны в production)
|
||||
"http://localhost",
|
||||
"http://localhost:3000",
|
||||
"http://localhost:5173",
|
||||
]
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=origins, # Указываем разрешенные источники
|
||||
allow_credentials=True, # Разрешаем куки (если потребуются в будущем)
|
||||
allow_methods=["*"], # Разрешаем все методы (GET, POST, PUT, etc.)
|
||||
allow_headers=["*"], # Разрешаем все заголовки
|
||||
allow_origins=origins,
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
# --- Конец настройки CORS ---
|
||||
|
||||
|
||||
# Подключаем роутер расчетов
|
||||
app.include_router(calculation.router)
|
||||
|
||||
@app.get("/")
|
||||
async def read_root():
|
||||
return {"message": "Welcome to the Glass Cutting Optimization API"}
|
||||
|
||||
# Убедимся, что здесь нет подключения auth роутера
|
||||
# from .routers import calculation # Позже подключим calculation
|
||||
# app.include_router(calculation.router)
|
||||
return {"message": "Welcome to the Glass Cutting Optimization API"}
|
|
@ -2,7 +2,5 @@ from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
|
|||
from sqlalchemy import Integer
|
||||
from typing import Annotated
|
||||
|
||||
# Define a base class using SQLAlchemy 2.0 style
|
||||
class Base(DeclarativeBase):
|
||||
# Define a primary key type annotation for convenience
|
||||
pass
|
|
@ -8,7 +8,6 @@ from typing import Dict, Any
|
|||
class Calculation(Base):
|
||||
__tablename__ = "calculations"
|
||||
|
||||
#
|
||||
id: Mapped[int] = mapped_column(primary_key=True, index=True)
|
||||
input_params: Mapped[Dict[str, Any]] = mapped_column(JSON, nullable=False)
|
||||
output_results: Mapped[Dict[str, Any] | None] = mapped_column(JSON, nullable=True)
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
from sqlalchemy import Column, Integer, String, JSON, Float, DateTime
|
||||
from sqlalchemy.sql import func
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
|
||||
Base = declarative_base()
|
||||
|
||||
class Calculation(Base):
|
||||
__tablename__ = "calculations"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
input_params = Column(JSON)
|
||||
output_results = Column(JSON)
|
||||
timestamp = Column(DateTime(timezone=True), server_default=func.now())
|
||||
model_name = Column(String, nullable=True)
|
||||
objective_score = Column(Float, nullable=True)
|
||||
# Удалите эти строки, если они есть:
|
||||
# user_id = Column(Integer, ForeignKey("users.id"))
|
||||
# user = relationship("User", back_populates="calculations")
|
||||
|
||||
# Можно вообще удалить класс User, если он больше не нужен
|
|
@ -7,8 +7,8 @@ from app.services import calculation_service as service
|
|||
from app.db.session import get_db
|
||||
|
||||
router = APIRouter(
|
||||
prefix="/calculation", # Общий префикс для эндпоинтов этого роутера
|
||||
tags=["Calculations"], # Тег для группировки в документации Swagger
|
||||
prefix="/calculation",
|
||||
tags=["Calculations"],
|
||||
)
|
||||
|
||||
@router.post("/", response_model=CalculationRead, status_code=status.HTTP_201_CREATED)
|
||||
|
@ -45,8 +45,6 @@ async def read_calculation(
|
|||
)
|
||||
return db_calc
|
||||
|
||||
# Определяем эндпоинт для истории до эндпоинта с ID,
|
||||
# чтобы FastAPI не принял "history" за ID
|
||||
@router.get("/history/", response_model=List[CalculationRead])
|
||||
async def read_calculation_history(
|
||||
skip: int = 0,
|
||||
|
|
|
@ -2,34 +2,22 @@ from pydantic import BaseModel, ConfigDict
|
|||
from datetime import datetime
|
||||
from typing import Optional, Dict, Any
|
||||
|
||||
# --- Базовая схема ---
|
||||
# Общие поля для расчета
|
||||
class CalculationBase(BaseModel):
|
||||
input_params: Dict[str, Any]
|
||||
model_name: Optional[str] = None # Модель может быть выбрана сервером
|
||||
model_name: Optional[str] = None
|
||||
|
||||
# --- Схема для создания (запуска) расчета ---
|
||||
# Данные, которые пользователь отправляет для запуска
|
||||
class CalculationCreate(CalculationBase):
|
||||
pass # Пока совпадает с Base, но может быть расширена
|
||||
pass
|
||||
|
||||
# --- Схема для чтения ---
|
||||
# Полная информация о расчете, возвращаемая API
|
||||
class CalculationRead(CalculationBase):
|
||||
id: int
|
||||
output_results: Optional[Dict[str, Any]] = None
|
||||
timestamp: datetime
|
||||
objective_score: Optional[float] = None
|
||||
|
||||
# Включаем режим ORM
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
# В Pydantic v1 было:
|
||||
# class Config:
|
||||
# orm_mode = True
|
||||
|
||||
|
||||
# --- Опционально: Схема для обновления (если результаты добавляются позже) ---
|
||||
class CalculationUpdate(BaseModel):
|
||||
output_results: Optional[Dict[str, Any]] = None
|
||||
objective_score: Optional[float] = None
|
||||
model_name: Optional[str] = None # Если модель определяется по результату
|
||||
model_name: Optional[str] = None
|
|
@ -6,6 +6,4 @@ class Token(BaseModel):
|
|||
token_type: str
|
||||
|
||||
class TokenData(BaseModel):
|
||||
username: Optional[str] = None
|
||||
# Можно использовать id пользователя, если удобнее
|
||||
# user_id: Optional[int] = None
|
||||
username: Optional[str] = None
|
|
@ -3,25 +3,19 @@ from typing import List, Optional, Dict, Any
|
|||
|
||||
from app.models.calculation import Calculation
|
||||
from app.schemas.calculation import CalculationCreate, CalculationUpdate
|
||||
from app.fuzzy_solver import solve_cutting_problem # Импортируем асинхронную заглушку
|
||||
from app.fuzzy_solver import solve_cutting_problem
|
||||
|
||||
# Делаем функцию создания асинхронной
|
||||
async def create_calculation(db: Session, calc_in: CalculationCreate) -> Calculation:
|
||||
"""
|
||||
Асинхронно создает запись о расчете, вызывает заглушку и сохраняет результат.
|
||||
"""
|
||||
# 1. Вызываем асинхронную заглушку расчета
|
||||
print("Calling async solver...")
|
||||
output_results = await solve_cutting_problem(calc_in.input_params)
|
||||
print("Async solver finished.")
|
||||
|
||||
# 2. Определяем другие параметры (логика остается)
|
||||
objective_score = output_results.get("waste_percentage")
|
||||
model_name = calc_in.model_name or "default_fuzzy_model_v1"
|
||||
|
||||
# 3. Создаем объект модели SQLAlchemy
|
||||
# Операции с БД остаются синхронными в этом примере
|
||||
# Для полной асинхронности потребовался бы async-драйвер и AsyncSession
|
||||
print("Creating DB object...")
|
||||
db_calc = Calculation(
|
||||
input_params=calc_in.input_params,
|
||||
|
@ -30,7 +24,6 @@ async def create_calculation(db: Session, calc_in: CalculationCreate) -> Calcula
|
|||
model_name=model_name
|
||||
)
|
||||
|
||||
# 4. Сохраняем в базу данных (синхронные операции)
|
||||
print("Adding to DB session...")
|
||||
db.add(db_calc)
|
||||
print("Committing DB session...")
|
||||
|
@ -40,8 +33,6 @@ async def create_calculation(db: Session, calc_in: CalculationCreate) -> Calcula
|
|||
print("Calculation created and saved.")
|
||||
return db_calc
|
||||
|
||||
# Функции чтения можно оставить синхронными, т.к. они быстрые
|
||||
# и используют синхронную сессию
|
||||
def get_calculation_by_id(db: Session, calc_id: int) -> Optional[Calculation]:
|
||||
"""
|
||||
Получает расчет по его ID.
|
||||
|
@ -53,16 +44,3 @@ def get_calculations(db: Session, skip: int = 0, limit: int = 100) -> List[Calcu
|
|||
Получает список всех расчетов с пагинацией.
|
||||
"""
|
||||
return db.query(Calculation).offset(skip).limit(limit).all()
|
||||
|
||||
# Опционально: Функция для обновления расчета (если нужно)
|
||||
# def update_calculation(db: Session, calc_id: int, calc_update: CalculationUpdate) -> Optional[Calculation]:
|
||||
# db_calc = get_calculation_by_id(db, calc_id)
|
||||
# if not db_calc:
|
||||
# return None
|
||||
# update_data = calc_update.model_dump(exclude_unset=True) # Pydantic v2
|
||||
# # update_data = calc_update.dict(exclude_unset=True) # Pydantic v1
|
||||
# for key, value in update_data.items():
|
||||
# setattr(db_calc, key, value)
|
||||
# db.commit()
|
||||
# db.refresh(db_calc)
|
||||
# return db_calc
|
Loading…
Reference in New Issue