fix: main & yml

This commit is contained in:
KofK 2025-02-15 13:52:05 +03:00
parent 2eafc574b6
commit 3928cbcd61
6 changed files with 141 additions and 76 deletions

17
.gitignore vendored
View File

@ -2,3 +2,20 @@
/__pycache__ /__pycache__
/myenv /myenv
imageboard.db imageboard.db
**/node_modules
**/venv
**/.git
**/.github
**/logs
**/dist
**/build
*.log
*.md
.DS_Store
.env
**/__pycache__
*.sqlite3
*.pyc
*.pyo
*.pyd
.Python

View File

@ -1,9 +1,22 @@
# Dockerfile # Используем официальный образ Python
FROM python:3.9-slim FROM python:3.9-slim
ENV PYTHONUNBUFFERED 1 # Устанавливаем системные зависимости
RUN apt-get update && \
apt-get install -y --no-install-recommends gcc python3-dev && \
rm -rf /var/lib/apt/lists/*
RUN apt-get update && apt-get install -y --no-install-recommends \ # Рабочая директория
gcc \ WORKDIR /app
python3-dev \
&& rm -rf /var/lib/apt/lists/* # Сначала копируем только зависимости
COPY requirements.txt .
# Устанавливаем зависимости с кэшированием
RUN pip install --no-cache-dir -r requirements.txt
# Копируем остальные файлы
COPY . .
# Команда для запуска (замените на вашу)
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

View File

@ -1,4 +1,4 @@
version: '3.8' version: "3.8"
services: services:
qdrant: qdrant:
@ -10,38 +10,24 @@ services:
volumes: volumes:
- qdrant_data:/qdrant/storage - qdrant_data:/qdrant/storage
restart: unless-stopped restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "--fail", "http://qdrant:6333"]
interval: 30s
timeout: 10s
retries: 3
app: backend:
build: . build:
context: .
dockerfile: Dockerfile
container_name: backend container_name: backend
ports: ports:
- "8000:8000" - "8000:8000"
volumes: restart: unless-stopped
- .:/app
working_dir: /app
depends_on:
qdrant:
condition: service_healthy
command: sh -c "pip install -r requirements.txt && uvicorn main:app --host 0.0.0.0 --port 8000 --reload"
frontend: futa-clone:
build: build:
context: . context: ./futa-clone
dockerfile: ./futa-clone/Dockerfile.frontend dockerfile: Dockerfile
container_name: frontend container_name: futa-clone
ports: ports:
- "3000:3000" - "3000:3000"
volumes: restart: unless-stopped
- ./futa-clone:/app
working_dir: /app
depends_on:
- qdrant
command: sh -c "npm install && npm run start"
volumes: volumes:
qdrant_data: qdrant_data:

18
futa-clone/Dockerfile Normal file
View File

@ -0,0 +1,18 @@
# Используем официальный Node.js образ (на примере версии 16 на базе Alpine)
FROM node:20-alpine
# Устанавливаем рабочую директорию внутри контейнера
WORKDIR /app
# Копируем файлы зависимостей и устанавливаем их
COPY package*.json ./
RUN npm install
# Копируем исходный код приложения
COPY . .
# Если требуется, можно указать порт (например, 3000)
EXPOSE 3000
# Запускаем приложение
CMD ["npm", "run", "start"]

View File

@ -1,4 +0,0 @@
# Dockerfile.frontend
FROM node:18-alpine
RUN apk add --no-cache git

113
main.py
View File

@ -10,6 +10,7 @@ import requests
from qdrant_client import QdrantClient from qdrant_client import QdrantClient
from qdrant_client.http import models from qdrant_client.http import models
from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.cors import CORSMiddleware
import time # Добавлен импорт модуля time
# Database setup # Database setup
from sqlalchemy import create_engine, Column, String, DateTime, Text from sqlalchemy import create_engine, Column, String, DateTime, Text
@ -26,78 +27,112 @@ import logging
from qdrant_client.http.models import VectorParams, Distance from qdrant_client.http.models import VectorParams, Distance
# Настройка базового логирования (например, вывод в консоль) # Настройка базового логирования
logging.basicConfig( logging.basicConfig(
level=logging.INFO, # Можно изменить уровень, например, на DEBUG level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(name)s - %(message)s" format="%(asctime)s [%(levelname)s] %(name)s - %(message)s"
) )
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# Задайте имя коллекции # Конфигурация
COLLECTION_NAME = "posts" COLLECTION_NAME = "posts"
# Определите размер вектора. Этот размер должен соответствовать длине объединённого эмбеддинга текста и изображения. VECTOR_SIZE = 1280
VECTOR_SIZE = 1280 # Пример: поменяйте на актуальное значение для вашего случая
# Configuration
DATABASE_URL = "sqlite:///./imageboard.db" DATABASE_URL = "sqlite:///./imageboard.db"
QDRANT_URL = "http://localhost:6333" QDRANT_URL = "http://localhost:6333"
OLLAMA_URL = "http://localhost:11434" OLLAMA_URL = "http://localhost:11434"
EMBEDDING_MODEL = "nomic-embed-text" # Локальная модель через Ollama EMBEDDING_MODEL = "nomic-embed-text"
IMAGE_MODEL = "openai/clip-vit-base-patch32" # Локальная CLIP модель IMAGE_MODEL = "openai/clip-vit-base-patch32"
IMAGE_SIZE = (224, 224) IMAGE_SIZE = (224, 224)
UPLOAD_DIR = "uploads" UPLOAD_DIR = "uploads"
os.makedirs(UPLOAD_DIR, exist_ok=True) os.makedirs(UPLOAD_DIR, exist_ok=True)
# Initialize components # Инициализация компонентов
Base = declarative_base() Base = declarative_base()
engine = create_engine(DATABASE_URL) engine = create_engine(DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
#Base.metadata.drop_all(bind=engine) # Удаляет все таблицы # Инициализация CLIP
#Base.metadata.create_all(bind=engine) # Создаёт таблицы заново
# Инициализация CLIP для изображений
clip_model = CLIPModel.from_pretrained(IMAGE_MODEL) clip_model = CLIPModel.from_pretrained(IMAGE_MODEL)
clip_processor = CLIPProcessor.from_pretrained(IMAGE_MODEL) clip_processor = CLIPProcessor.from_pretrained(IMAGE_MODEL)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu") device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
clip_model = clip_model.to(device) clip_model = clip_model.to(device)
# Qdrant клиент # Функция для создания QdrantClient с повторными попытками
qdrant_client = QdrantClient(QDRANT_URL) def create_qdrant_client():
max_attempts = 5
attempt = 0
while attempt < max_attempts:
try:
client = QdrantClient(QDRANT_URL)
# Проверка подключения
client.get_collections()
logger.info("Успешное подключение к Qdrant")
return client
except Exception as e:
logger.warning(f"Попытка {attempt+1} подключения к Qdrant не удалась: {str(e)}")
attempt += 1
time.sleep(2)
raise RuntimeError(f"Не удалось подключиться к Qdrant после {max_attempts} попыток")
# Инициализация клиента Qdrant
try:
qdrant_client = create_qdrant_client()
except Exception as e:
logger.error(f"Ошибка инициализации Qdrant: {str(e)}")
raise
# Функция проверки и создания коллекции
def ensure_collection_exists(): def ensure_collection_exists():
try: max_attempts = 5
# Попытка получить коллекцию. Если коллекция не существует, Qdrant выбросит исключение. attempt = 0
qdrant_client.get_collection(collection_name=COLLECTION_NAME) while attempt < max_attempts:
logger.info("Коллекция '%s' существует.", COLLECTION_NAME) try:
except Exception as e: # Проверка существования коллекции
logger.info("Коллекция '%s' не найдена. Создаём коллекцию...", COLLECTION_NAME) qdrant_client.get_collection(collection_name=COLLECTION_NAME)
qdrant_client.create_collection( logger.info(f"Коллекция '{COLLECTION_NAME}' существует")
collection_name=COLLECTION_NAME, return
vectors_config=VectorParams( except Exception as e:
size=VECTOR_SIZE, if "not found" in str(e).lower():
distance=Distance.COSINE # Или другой подходящий тип расстояния logger.info(f"Создание коллекции '{COLLECTION_NAME}'...")
) try:
) qdrant_client.create_collection(
logger.info("Коллекция '%s' создана.", COLLECTION_NAME) collection_name=COLLECTION_NAME,
vectors_config=VectorParams(
size=VECTOR_SIZE,
distance=Distance.COSINE
)
)
logger.info(f"Коллекция '{COLLECTION_NAME}' создана")
return
except Exception as create_error:
logger.error(f"Ошибка создания: {str(create_error)}")
else:
logger.error(f"Ошибка подключения: {str(e)}")
# Вызываем функцию при инициализации приложения, например, в начале main.py attempt += 1
ensure_collection_exists() time.sleep(2)
raise RuntimeError(f"Не удалось инициализировать коллекцию после {max_attempts} попыток")
# Вызов функции проверки коллекции
try:
ensure_collection_exists()
except Exception as e:
logger.error(f"Ошибка инициализации коллекции: {str(e)}")
raise
# Инициализация FastAPI
app = FastAPI() app = FastAPI()
app.mount("/uploads", StaticFiles(directory=UPLOAD_DIR), name="uploads")
app.mount("/uploads", StaticFiles(directory=UPLOAD_DIR), name=UPLOAD_DIR)
app.add_middleware( app.add_middleware(
CORSMiddleware, CORSMiddleware,
allow_origins=["*"], # Разрешить все источники allow_origins=["*"],
allow_credentials=True, allow_credentials=True,
allow_methods=["*"], # Разрешить все методы allow_methods=["*"],
allow_headers=["*"], # Разрешить все заголовки allow_headers=["*"],
) )
# Database models # Модель базы данных
class Post(Base): class Post(Base):
__tablename__ = "posts" __tablename__ = "posts"
id = Column(String, primary_key=True, index=True) id = Column(String, primary_key=True, index=True)