Files
aiform_dev/backend/app/services/s3_service.py
AI Assistant d2777aeabf feat: Step2 переделан + улучшен Debug Panel с полными S3 URL
Step2Details (по скриншоту):
 Индикатор ' Полис найден' вверху
 Select с типами событий из erv_ticket:
   - Задержка авиарейса (более 3 часов)
   - Отмена авиарейса
   - Пропуск стыковочного рейса
   - Посадка на запасной аэродром
   - Задержка отправки поезда
   - Отмена поезда
   - Задержка/отмена парома/круизного судна

 Дата наступления страхового случая (DatePicker)
 Номер рейса/поезда/парома
 Загрузка подтверждающих документов:
   - Посадочный талон, билет, справка и т.д.
   - До 10 файлов по 15MB
   - HEIC, PDF, фото

Debug Panel улучшения:
 Полные S3 URL (не обрезанные)
 Кнопка '🔗 Открыть в новой вкладке'
 word-break: break-all для длинных URL
 Показывает все файлы из массива
 Для каждого файла:
   - Filename
   - File ID (UUID)
   - Size (KB)
   - Полный S3 URL (кликабельный)

Теперь в Debug видно КУДА загрузилось:
https://s3.twcstorage.ru/f9825c87-.../policies/20251024_213045_abc123_file.jpg

Можно кликнуть и посмотреть глазами! 👀
2025-10-25 09:27:56 +03:00

106 lines
3.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
S3 Service - Загрузка файлов в S3 (Timeweb Cloud Storage)
"""
import boto3
from botocore.client import Config
from typing import Optional
import logging
from datetime import datetime
import uuid
from ..config import settings
logger = logging.getLogger(__name__)
class S3Service:
"""Сервис для работы с S3 хранилищем"""
def __init__(self):
self.client = None
self.bucket = settings.s3_bucket
def connect(self):
"""Подключение к S3"""
try:
self.client = boto3.client(
's3',
endpoint_url=settings.s3_endpoint,
aws_access_key_id=settings.s3_access_key,
aws_secret_access_key=settings.s3_secret_key,
config=Config(signature_version='s3v4'),
region_name=settings.s3_region
)
logger.info(f"✅ S3 connected: {settings.s3_endpoint}/{settings.s3_bucket}")
except Exception as e:
logger.error(f"❌ S3 connection error: {e}")
raise
async def upload_file(
self,
file_content: bytes,
filename: str,
content_type: str = 'application/octet-stream',
folder: str = 'uploads'
) -> Optional[str]:
"""
Загрузить файл в S3
Args:
file_content: Содержимое файла в bytes
filename: Имя файла
content_type: MIME тип
folder: Папка в bucket
Returns:
URL файла в S3 или None при ошибке
"""
if not self.client:
self.connect()
try:
# Генерируем уникальное имя файла
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
unique_id = str(uuid.uuid4())[:8]
safe_filename = f"{folder}/{timestamp}_{unique_id}_{filename}"
# Загружаем файл
self.client.put_object(
Bucket=self.bucket,
Key=safe_filename,
Body=file_content,
ContentType=content_type
)
# Генерируем URL
file_url = f"{settings.s3_endpoint}/{self.bucket}/{safe_filename}"
logger.info(f"✅ File uploaded to S3: {safe_filename}")
return file_url
except Exception as e:
logger.error(f"❌ S3 upload error: {e}")
return None
async def delete_file(self, file_key: str) -> bool:
"""Удалить файл из S3"""
if not self.client:
self.connect()
try:
self.client.delete_object(
Bucket=self.bucket,
Key=file_key
)
logger.info(f"✅ File deleted from S3: {file_key}")
return True
except Exception as e:
logger.error(f"❌ S3 delete error: {e}")
return False
# Глобальный экземпляр
s3_service = S3Service()