2025-10-24 12:02:17 +03:00
|
|
|
|
"""
|
2025-11-14 19:06:36 +03:00
|
|
|
|
Ticket Form Intake Platform - FastAPI Backend
|
2025-10-24 12:02:17 +03:00
|
|
|
|
"""
|
2025-11-19 18:46:48 +03:00
|
|
|
|
from fastapi import FastAPI, Request
|
2025-10-24 12:02:17 +03:00
|
|
|
|
from fastapi.middleware.cors import CORSMiddleware
|
2025-10-24 16:19:58 +03:00
|
|
|
|
from contextlib import asynccontextmanager
|
|
|
|
|
|
import logging
|
|
|
|
|
|
|
|
|
|
|
|
from .config import settings
|
|
|
|
|
|
from .services.database import db
|
|
|
|
|
|
from .services.redis_service import redis_service
|
|
|
|
|
|
from .services.rabbitmq_service import rabbitmq_service
|
2025-10-24 20:27:10 +03:00
|
|
|
|
from .services.policy_service import policy_service
|
2025-12-04 12:22:23 +03:00
|
|
|
|
from .services.crm_mysql_service import crm_mysql_service
|
2025-10-24 21:24:00 +03:00
|
|
|
|
from .services.s3_service import s3_service
|
2025-11-26 19:54:51 +03:00
|
|
|
|
from .api import sms, claims, policy, upload, draft, events, n8n_proxy, session, documents
|
2025-10-24 16:19:58 +03:00
|
|
|
|
|
|
|
|
|
|
# Настройка логирования
|
|
|
|
|
|
logging.basicConfig(
|
|
|
|
|
|
level=logging.INFO,
|
|
|
|
|
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
|
|
|
|
|
)
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@asynccontextmanager
|
|
|
|
|
|
async def lifespan(app: FastAPI):
|
|
|
|
|
|
"""
|
|
|
|
|
|
Lifecycle events: startup and shutdown
|
|
|
|
|
|
"""
|
|
|
|
|
|
# STARTUP
|
2025-11-14 19:06:36 +03:00
|
|
|
|
logger.info("🚀 Starting Ticket Form Intake Platform...")
|
2025-10-24 16:19:58 +03:00
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
# Подключаем PostgreSQL
|
|
|
|
|
|
await db.connect()
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.warning(f"⚠️ PostgreSQL not available: {e}")
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
# Подключаем Redis
|
|
|
|
|
|
await redis_service.connect()
|
2025-11-20 18:31:42 +03:00
|
|
|
|
# Инициализируем session API с Redis connection
|
|
|
|
|
|
session.init_redis(redis_service.client)
|
2025-10-24 16:19:58 +03:00
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.warning(f"⚠️ Redis not available: {e}")
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
# Подключаем RabbitMQ
|
|
|
|
|
|
await rabbitmq_service.connect()
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.warning(f"⚠️ RabbitMQ not available: {e}")
|
|
|
|
|
|
|
2025-10-24 20:54:57 +03:00
|
|
|
|
try:
|
|
|
|
|
|
# Подключаем MySQL (для проверки полисов)
|
|
|
|
|
|
await policy_service.connect()
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.warning(f"⚠️ MySQL Policy DB not available: {e}")
|
|
|
|
|
|
|
2025-12-04 12:22:23 +03:00
|
|
|
|
try:
|
|
|
|
|
|
# Подключаем MySQL CRM (vtiger)
|
|
|
|
|
|
await crm_mysql_service.connect()
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.warning(f"⚠️ MySQL CRM DB not available: {e}")
|
|
|
|
|
|
|
2025-10-24 21:24:00 +03:00
|
|
|
|
try:
|
|
|
|
|
|
# Подключаем S3 (для загрузки файлов)
|
|
|
|
|
|
s3_service.connect()
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.warning(f"⚠️ S3 storage not available: {e}")
|
|
|
|
|
|
|
2025-11-14 19:06:36 +03:00
|
|
|
|
logger.info("✅ Ticket Form Intake Platform started successfully!")
|
2025-10-24 16:19:58 +03:00
|
|
|
|
|
|
|
|
|
|
yield
|
|
|
|
|
|
|
|
|
|
|
|
# SHUTDOWN
|
2025-11-14 19:06:36 +03:00
|
|
|
|
logger.info("🛑 Shutting down Ticket Form Intake Platform...")
|
2025-10-24 16:19:58 +03:00
|
|
|
|
|
|
|
|
|
|
await db.disconnect()
|
|
|
|
|
|
await redis_service.disconnect()
|
|
|
|
|
|
await rabbitmq_service.disconnect()
|
2025-10-24 20:54:57 +03:00
|
|
|
|
await policy_service.close()
|
2025-12-04 12:22:23 +03:00
|
|
|
|
await crm_mysql_service.close()
|
2025-10-24 16:19:58 +03:00
|
|
|
|
|
2025-11-14 19:06:36 +03:00
|
|
|
|
logger.info("👋 Ticket Form Intake Platform stopped")
|
2025-10-24 16:19:58 +03:00
|
|
|
|
|
2025-10-24 12:02:17 +03:00
|
|
|
|
|
|
|
|
|
|
# Создаём FastAPI приложение
|
|
|
|
|
|
app = FastAPI(
|
2025-11-14 19:06:36 +03:00
|
|
|
|
title="Ticket Form Intake API",
|
|
|
|
|
|
description="API для обработки обращений Ticket Form",
|
2025-10-24 12:02:17 +03:00
|
|
|
|
version="1.0.0",
|
2025-10-24 16:19:58 +03:00
|
|
|
|
lifespan=lifespan
|
2025-10-24 12:02:17 +03:00
|
|
|
|
)
|
|
|
|
|
|
|
2025-10-24 16:19:58 +03:00
|
|
|
|
# CORS
|
2025-10-24 12:02:17 +03:00
|
|
|
|
app.add_middleware(
|
|
|
|
|
|
CORSMiddleware,
|
2025-10-24 16:19:58 +03:00
|
|
|
|
allow_origins=settings.cors_origins_list,
|
2025-10-24 12:02:17 +03:00
|
|
|
|
allow_credentials=True,
|
|
|
|
|
|
allow_methods=["*"],
|
|
|
|
|
|
allow_headers=["*"],
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2025-10-24 16:19:58 +03:00
|
|
|
|
# API Routes
|
|
|
|
|
|
app.include_router(sms.router)
|
|
|
|
|
|
app.include_router(claims.router)
|
2025-10-24 20:27:10 +03:00
|
|
|
|
app.include_router(policy.router)
|
|
|
|
|
|
app.include_router(upload.router)
|
2025-10-24 21:24:00 +03:00
|
|
|
|
app.include_router(draft.router)
|
2025-10-27 19:37:41 +03:00
|
|
|
|
app.include_router(events.router)
|
2025-10-29 16:49:03 +03:00
|
|
|
|
app.include_router(n8n_proxy.router) # 🔒 Безопасный proxy к n8n webhooks
|
2025-11-20 18:31:42 +03:00
|
|
|
|
app.include_router(session.router) # 🔑 Session management через Redis
|
2025-11-26 19:54:51 +03:00
|
|
|
|
app.include_router(documents.router) # 📄 Documents upload and processing
|
2025-10-24 12:02:17 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.get("/")
|
|
|
|
|
|
async def root():
|
|
|
|
|
|
"""Главная страница API"""
|
|
|
|
|
|
return {
|
2025-11-14 19:06:36 +03:00
|
|
|
|
"message": "🚀 Ticket Form Intake API",
|
2025-10-24 12:02:17 +03:00
|
|
|
|
"version": "1.0.0",
|
2025-10-24 16:19:58 +03:00
|
|
|
|
"status": "running",
|
2025-11-14 19:06:36 +03:00
|
|
|
|
"docs": f"{settings.backend_url}/docs"
|
2025-10-24 12:02:17 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.get("/health")
|
2025-10-24 16:19:58 +03:00
|
|
|
|
async def health():
|
|
|
|
|
|
"""Health check - проверка всех сервисов"""
|
2025-10-24 12:02:17 +03:00
|
|
|
|
health_status = {
|
2025-10-24 16:19:58 +03:00
|
|
|
|
"status": "ok",
|
|
|
|
|
|
"message": "API работает!",
|
|
|
|
|
|
"services": {}
|
2025-10-24 12:02:17 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Проверка PostgreSQL
|
|
|
|
|
|
try:
|
2025-10-24 16:19:58 +03:00
|
|
|
|
pg_healthy = await db.health_check()
|
|
|
|
|
|
health_status["services"]["postgresql"] = {
|
|
|
|
|
|
"status": "✅ healthy" if pg_healthy else "❌ unhealthy",
|
|
|
|
|
|
"connected": pg_healthy
|
|
|
|
|
|
}
|
|
|
|
|
|
except:
|
|
|
|
|
|
health_status["services"]["postgresql"] = {
|
|
|
|
|
|
"status": "❌ unavailable",
|
|
|
|
|
|
"connected": False
|
|
|
|
|
|
}
|
2025-10-24 12:02:17 +03:00
|
|
|
|
|
2025-10-24 16:19:58 +03:00
|
|
|
|
# Проверка Redis
|
2025-10-24 12:02:17 +03:00
|
|
|
|
try:
|
2025-10-24 16:19:58 +03:00
|
|
|
|
redis_healthy = await redis_service.health_check()
|
|
|
|
|
|
health_status["services"]["redis"] = {
|
|
|
|
|
|
"status": "✅ healthy" if redis_healthy else "❌ unhealthy",
|
|
|
|
|
|
"connected": redis_healthy
|
|
|
|
|
|
}
|
|
|
|
|
|
except:
|
|
|
|
|
|
health_status["services"]["redis"] = {
|
|
|
|
|
|
"status": "❌ unavailable",
|
|
|
|
|
|
"connected": False
|
|
|
|
|
|
}
|
2025-10-24 12:02:17 +03:00
|
|
|
|
|
2025-10-24 16:19:58 +03:00
|
|
|
|
# Проверка RabbitMQ
|
|
|
|
|
|
try:
|
|
|
|
|
|
rabbitmq_healthy = await rabbitmq_service.health_check()
|
|
|
|
|
|
health_status["services"]["rabbitmq"] = {
|
|
|
|
|
|
"status": "✅ healthy" if rabbitmq_healthy else "❌ unhealthy",
|
|
|
|
|
|
"connected": rabbitmq_healthy
|
2025-10-24 12:02:17 +03:00
|
|
|
|
}
|
2025-10-24 16:19:58 +03:00
|
|
|
|
except:
|
|
|
|
|
|
health_status["services"]["rabbitmq"] = {
|
|
|
|
|
|
"status": "❌ unavailable",
|
|
|
|
|
|
"connected": False
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Общий статус
|
|
|
|
|
|
all_healthy = all(
|
|
|
|
|
|
service.get("connected", False)
|
|
|
|
|
|
for service in health_status["services"].values()
|
2025-10-24 12:02:17 +03:00
|
|
|
|
)
|
2025-10-24 16:19:58 +03:00
|
|
|
|
|
|
|
|
|
|
if not all_healthy:
|
|
|
|
|
|
health_status["status"] = "degraded"
|
|
|
|
|
|
health_status["message"] = "⚠️ Некоторые сервисы недоступны"
|
|
|
|
|
|
|
|
|
|
|
|
return health_status
|
2025-10-24 12:02:17 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.get("/api/v1/test")
|
2025-10-24 16:19:58 +03:00
|
|
|
|
async def test():
|
2025-10-24 12:02:17 +03:00
|
|
|
|
"""Тестовый endpoint"""
|
|
|
|
|
|
return {
|
2025-10-24 16:19:58 +03:00
|
|
|
|
"success": True,
|
|
|
|
|
|
"message": "✅ Backend API работает!",
|
2025-10-24 12:02:17 +03:00
|
|
|
|
"services": {
|
2025-11-14 19:06:36 +03:00
|
|
|
|
"redis": f"{settings.redis_host}:{settings.redis_port}",
|
|
|
|
|
|
"postgres": f"{settings.postgres_host}:{settings.postgres_port}",
|
|
|
|
|
|
"ocr": settings.ocr_api_url,
|
|
|
|
|
|
"rabbitmq": f"{settings.rabbitmq_host}:{settings.rabbitmq_port}"
|
2025-10-24 12:02:17 +03:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-11-19 18:46:48 +03:00
|
|
|
|
@app.get("/api/v1/utils/client-ip")
|
|
|
|
|
|
async def get_client_ip(request: Request):
|
|
|
|
|
|
"""Возвращает IP-адрес клиента по HTTP-запросу"""
|
|
|
|
|
|
client_host = request.client.host if request.client else None
|
|
|
|
|
|
return {
|
|
|
|
|
|
"ip": client_host
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-10-24 12:02:17 +03:00
|
|
|
|
@app.get("/api/v1/info")
|
2025-10-24 16:19:58 +03:00
|
|
|
|
async def info():
|
2025-10-24 12:02:17 +03:00
|
|
|
|
"""Информация о платформе"""
|
|
|
|
|
|
return {
|
2025-11-14 19:06:36 +03:00
|
|
|
|
"platform": settings.app_name,
|
2025-10-24 12:02:17 +03:00
|
|
|
|
"version": "1.0.0",
|
|
|
|
|
|
"tech_stack": {
|
|
|
|
|
|
"backend": "Python FastAPI",
|
|
|
|
|
|
"frontend": "React TypeScript",
|
|
|
|
|
|
"database": "PostgreSQL + MySQL",
|
|
|
|
|
|
"cache": "Redis",
|
|
|
|
|
|
"queue": "RabbitMQ",
|
2025-10-24 16:19:58 +03:00
|
|
|
|
"storage": "S3 Timeweb"
|
|
|
|
|
|
},
|
|
|
|
|
|
"features": [
|
2025-11-14 19:06:36 +03:00
|
|
|
|
"OCR документов",
|
|
|
|
|
|
"AI автозаполнение",
|
|
|
|
|
|
"Проверка статуса выплат",
|
2025-10-24 16:19:58 +03:00
|
|
|
|
"СБП выплаты",
|
|
|
|
|
|
"Интеграция с CRM Vtiger"
|
|
|
|
|
|
]
|
2025-10-24 12:02:17 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
|
import uvicorn
|
2025-11-14 19:06:36 +03:00
|
|
|
|
uvicorn.run(app, host="0.0.0.0", port=8200)
|
2025-11-26 19:54:51 +03:00
|
|
|
|
|