Изменения:
-добавлены нетворки в докер композ -исправлен рутинг (баг пайчарма) -запросы к ии агентам не проходят из-за ссл сертификата (пробовали отключить, но пока не выходит, нужно доделать)
This commit is contained in:
5
.idea/misc.xml
generated
5
.idea/misc.xml
generated
@@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_22" project-jdk-name="openjdk-23" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
<component name="Black">
|
||||
<option name="sdkName" value="Python 3.14 (New-planet-api)" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.14 (New-planet-api)" project-jdk-type="Python SDK" />
|
||||
</project>
|
||||
7
.idea/new-planet-backend.iml
generated
7
.idea/new-planet-backend.iml
generated
@@ -2,8 +2,11 @@
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/new-planet-backend" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/venv" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Python 3.14 (New-planet-api)" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -1,21 +1,27 @@
|
||||
# Database
|
||||
|
||||
GIGACHAT_CLIENT_ID=019966f4-1c5c-7382-9006-b84419fbe5d1
|
||||
GIGACHAT_CLIENT_SECRET=MDE5OTY2ZjQtMWM1Yy03MzgyLTkwMDYtYjg0NDE5ZmJlNWQxOjJjODBmOWE2LWU4YWMtNDE4YS1iOGVkLWE4NTE0YzVkNDAwNw==
|
||||
GIGACHAT_AUTH_URL=https://ngw.devices.sberbank.ru:9443/api/v2/oauth
|
||||
GIGACHAT_BASE_URL=https://gigachat.devices.sberbank.ru/api/v1
|
||||
GIGACHAT_MODEL_CHAT=GigaChat-2-Lite
|
||||
GIGACHAT_MODEL_SCHEDULE=GigaChat-2-Pro
|
||||
|
||||
# Security
|
||||
SECRET_KEY=3db8542397edddbd6162ad823157e36f8d47232aa646725d4799266229ba7aa4
|
||||
|
||||
# Database
|
||||
POSTGRES_USER=postgres
|
||||
POSTGRES_PASSWORD=postgres
|
||||
POSTGRES_DB=newplanet
|
||||
POSTGRES_HOST=localhost
|
||||
POSTGRES_PORT=5432
|
||||
DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5432/newplanet
|
||||
|
||||
# Redis
|
||||
REDIS_HOST=localhost
|
||||
REDIS_PORT=6379
|
||||
REDIS_DB=0
|
||||
REDIS_URL=redis://localhost:6379
|
||||
|
||||
# Security
|
||||
SECRET_KEY=jwt-secret-key
|
||||
|
||||
# Storage (MinIO/S3)
|
||||
# Storage
|
||||
STORAGE_ENDPOINT=localhost:9000
|
||||
STORAGE_ACCESS_KEY=minioadmin
|
||||
STORAGE_SECRET_KEY=minioadmin
|
||||
@@ -23,6 +29,3 @@ STORAGE_BUCKET=new-planet-images
|
||||
STORAGE_USE_SSL=false
|
||||
STORAGE_REGION=us-east-1
|
||||
|
||||
# GigaChat API
|
||||
GIGACHAT_CLIENT_ID=gigachat-client-id
|
||||
GIGACHAT_CLIENT_SECRET="gigachat-token-here"
|
||||
|
||||
@@ -23,12 +23,13 @@ Backend API для мобильного приложения **Новая Пла
|
||||
### Установка
|
||||
|
||||
1. Клонируйте репозиторий
|
||||
2. Установите зависимости:
|
||||
2. Установить окружение ("python -m venv venv")
|
||||
3. Установите зависимости:
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
3. Настройте `.env`:
|
||||
4. Настройте `.env`:
|
||||
```bash
|
||||
cp .env.example .env
|
||||
#В целом вам нужно поменять GIGACHAT API секцию, JWT Secret key сгенерить, просто в поисковике генератор на 256 байт сделаете JWT
|
||||
@@ -36,7 +37,7 @@ cp .env.example .env
|
||||
# Отредактируйте .env с вашими настройками
|
||||
```
|
||||
|
||||
4. Запустите инфраструктуру (Docker):
|
||||
5. Запустите инфраструктуру (Docker):
|
||||
```bash
|
||||
docker-compose -f docker/docker-compose.yml up -d
|
||||
# или используйте вариант ниже,но лучше вариант выше для избежания непредвиденного
|
||||
@@ -44,12 +45,12 @@ docker-compose -f docker/docker-compose.yml up -d
|
||||
docker-compose up
|
||||
```
|
||||
|
||||
5. Примените миграции:
|
||||
6. Примените миграции:
|
||||
```bash
|
||||
alembic upgrade head
|
||||
```
|
||||
|
||||
6. Запустите сервер:
|
||||
7. Запустите сервер:
|
||||
```bash
|
||||
uvicorn app.main:app --reload
|
||||
# если не запустилось, проверяйте есть ли .venv(установлено ли окружение для питона), также попробуйте в венве uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
|
||||
|
||||
@@ -7,7 +7,7 @@ from app.crud import user as crud_user
|
||||
from app.services.auth_service import auth_service
|
||||
from app.models.user import User
|
||||
|
||||
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="api/v1/auth/login")
|
||||
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/login")
|
||||
|
||||
|
||||
async def get_current_user(
|
||||
|
||||
@@ -3,9 +3,27 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from app.db.session import get_db
|
||||
from app.api.deps import get_current_active_user
|
||||
from app.models.user import User
|
||||
from app.schemas.ai import ChatRequest, ChatResponse, ScheduleGenerateRequest, ScheduleGenerateResponse
|
||||
from app.models.ai_conversation import AIConversation
|
||||
from app.schemas.ai import (
|
||||
ChatRequest,
|
||||
ChatResponse,
|
||||
ScheduleGenerateRequest,
|
||||
ScheduleGenerateResponse,
|
||||
ConversationHistory,
|
||||
ConversationListItem,
|
||||
ScheduleUpdateRequest,
|
||||
ScheduleUpdateResponse,
|
||||
RecommendationRequest,
|
||||
RecommendationResponse,
|
||||
)
|
||||
from app.services.chat_service import chat_service
|
||||
from app.services.schedule_generator import schedule_generator
|
||||
from app.services.cache_service import cache_service
|
||||
from app.services.gigachat_service import gigachat_service
|
||||
from app.crud import schedule as crud_schedule, task as crud_task
|
||||
from app.schemas.task import TaskCreate
|
||||
from app.schemas.schedule import ScheduleUpdate
|
||||
from app.core.config import settings
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@@ -30,7 +48,6 @@ async def chat_with_ai(
|
||||
detail=f"Chat error: {str(e)}"
|
||||
)
|
||||
|
||||
|
||||
@router.post("/schedule/generate", response_model=ScheduleGenerateResponse)
|
||||
async def generate_schedule_ai(
|
||||
request: ScheduleGenerateRequest,
|
||||
@@ -58,3 +75,4 @@ async def generate_schedule_ai(
|
||||
detail=f"Failed to generate schedule: {str(e)}"
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -10,15 +10,15 @@ class Settings(BaseSettings):
|
||||
DEBUG: bool = False
|
||||
|
||||
# Security
|
||||
SECRET_KEY: str
|
||||
SECRET_KEY: str = "3db8542397edddbd6162ad823157e36f8d47232aa646725d4799266229ba7aa4"
|
||||
ALGORITHM: str = "HS256"
|
||||
ACCESS_TOKEN_EXPIRE_MINUTES: int = 30
|
||||
REFRESH_TOKEN_EXPIRE_DAYS: int = 7
|
||||
|
||||
# Database
|
||||
POSTGRES_USER: str
|
||||
POSTGRES_PASSWORD: str
|
||||
POSTGRES_DB: str
|
||||
POSTGRES_USER: str = "postgres"
|
||||
POSTGRES_PASSWORD: str = "postgres"
|
||||
POSTGRES_DB: str = "newplanet"
|
||||
POSTGRES_HOST: str = "localhost"
|
||||
POSTGRES_PORT: int = 5432
|
||||
DATABASE_URL: Optional[str] = None
|
||||
@@ -43,15 +43,15 @@ class Settings(BaseSettings):
|
||||
|
||||
# Storage (MinIO/S3)
|
||||
STORAGE_ENDPOINT: str = "localhost:9000"
|
||||
STORAGE_ACCESS_KEY: str
|
||||
STORAGE_SECRET_KEY: str
|
||||
STORAGE_ACCESS_KEY: str = "minioadmin"
|
||||
STORAGE_SECRET_KEY: str = "minioadmin"
|
||||
STORAGE_BUCKET: str = "new-planet-images"
|
||||
STORAGE_USE_SSL: bool = False
|
||||
STORAGE_REGION: str = "us-east-1"
|
||||
|
||||
# GigaChat
|
||||
GIGACHAT_CLIENT_ID: str
|
||||
GIGACHAT_CLIENT_SECRET: str
|
||||
GIGACHAT_CLIENT_ID: str = "019966f4-1c5c-7382-9006-b84419fbe5d1"
|
||||
GIGACHAT_CLIENT_SECRET: str = "MDE5OTY2ZjQtMWM1Yy03MzgyLTkwMDYtYjg0NDE5ZmJlNWQxOjJjODBmOWE2LWU4YWMtNDE4YS1iOGVkLWE4NTE0YzVkNDAwNw=="
|
||||
GIGACHAT_AUTH_URL: str = "https://ngw.devices.sberbank.ru:9443/api/v2/oauth"
|
||||
GIGACHAT_BASE_URL: str = "https://gigachat.devices.sberbank.ru/api/v1"
|
||||
GIGACHAT_MODEL_CHAT: str = "GigaChat-2-Lite"
|
||||
|
||||
@@ -2,7 +2,7 @@ from datetime import datetime, timedelta
|
||||
from typing import Optional, Dict, Any
|
||||
from jose import JWTError, jwt
|
||||
import bcrypt
|
||||
from app.core.config import settings
|
||||
from config import settings
|
||||
|
||||
|
||||
def verify_password(plain_password: str, hashed_password: str) -> bool:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.orm import declarative_base
|
||||
from sqlalchemy import Column, DateTime, func, String
|
||||
import uuid
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from app.db.base import Base
|
||||
from app.db.session import engine
|
||||
from base import Base
|
||||
from session import engine
|
||||
from app.models import user, schedule, task, reward, ai_conversation
|
||||
|
||||
|
||||
|
||||
@@ -3,8 +3,7 @@ from app.core.config import settings
|
||||
|
||||
engine = create_async_engine(
|
||||
settings.database_url,
|
||||
echo=settings.DEBUG,
|
||||
future=True
|
||||
echo=settings.DEBUG
|
||||
)
|
||||
|
||||
AsyncSessionLocal = async_sessionmaker(
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# Добавляем корневую директорию проекта в PYTHONPATH при прямом запуске
|
||||
# Это нужно, чтобы Python мог найти модуль 'app'
|
||||
# Проверяем, запускается ли файл напрямую, проверяя имя скрипта
|
||||
if sys.argv and len(sys.argv) > 0:
|
||||
script_path = Path(sys.argv[0]).resolve()
|
||||
current_file = Path(__file__).resolve()
|
||||
# Если скрипт запускается напрямую (не через модуль)
|
||||
if script_path == current_file or script_path.name == current_file.name:
|
||||
project_root = current_file.parent.parent # new-planet-backend
|
||||
if str(project_root) not in sys.path:
|
||||
sys.path.insert(0, str(project_root))
|
||||
|
||||
from fastapi import FastAPI, Request
|
||||
from fastapi.exceptions import RequestValidationError
|
||||
from starlette.exceptions import HTTPException as StarletteHTTPException
|
||||
@@ -73,7 +88,7 @@ if __name__ == "__main__":
|
||||
import uvicorn
|
||||
uvicorn.run(
|
||||
"app.main:app",
|
||||
host="0.0.0.0",
|
||||
host="127.0.0.1",
|
||||
port=8000,
|
||||
reload=settings.DEBUG
|
||||
)
|
||||
|
||||
@@ -38,3 +38,41 @@ class ConversationHistory(BaseModel):
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class ConversationListItem(BaseModel):
|
||||
"""Элемент списка разговоров"""
|
||||
conversation_id: str
|
||||
last_message: Optional[str] = None
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
message_count: int = 0
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class ScheduleUpdateRequest(BaseModel):
|
||||
"""Запрос на обновление расписания через ИИ"""
|
||||
user_request: str = Field(..., min_length=1, max_length=1000, description="Описание желаемых изменений")
|
||||
|
||||
|
||||
class ScheduleUpdateResponse(BaseModel):
|
||||
"""Ответ после обновления расписания"""
|
||||
schedule_id: str
|
||||
title: str
|
||||
tasks: List[Dict[str, Any]]
|
||||
tokens_used: Optional[int] = None
|
||||
|
||||
|
||||
class RecommendationRequest(BaseModel):
|
||||
"""Запрос на получение рекомендаций"""
|
||||
preferences: List[str] = Field(default_factory=list, description="Предпочтения пользователя")
|
||||
category: Optional[str] = Field(None, description="Категория заданий")
|
||||
completed_tasks: Optional[List[str]] = Field(default_factory=list, description="Уже выполненные задания")
|
||||
top_k: int = Field(5, ge=1, le=20, description="Количество рекомендаций")
|
||||
|
||||
|
||||
class RecommendationResponse(BaseModel):
|
||||
"""Ответ с рекомендациями"""
|
||||
recommendations: List[Dict[str, Any]]
|
||||
total: int
|
||||
@@ -1,11 +1,17 @@
|
||||
import os
|
||||
|
||||
import aiohttp
|
||||
import ssl
|
||||
import base64
|
||||
import uuid
|
||||
import time
|
||||
from urllib.parse import urlencode
|
||||
from typing import Optional, List, Dict, Any
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from app.core.config import settings
|
||||
|
||||
load_dotenv()
|
||||
|
||||
class GigaChatService:
|
||||
def __init__(self):
|
||||
@@ -19,8 +25,19 @@ class GigaChatService:
|
||||
if time.time() < (self.token_expires_at - 60):
|
||||
return self.access_token
|
||||
|
||||
credentials = f"{settings.GIGACHAT_CLIENT_ID}:{settings.GIGACHAT_CLIENT_SECRET}"
|
||||
encoded_credentials = base64.b64encode(credentials.encode()).decode()
|
||||
# Проверяем наличие credentials
|
||||
client_id = os.getenv("GIGACHAT_CLIENT_ID")
|
||||
client_secret = os.getenv("GIGACHAT_CLIENT_SECRET")
|
||||
|
||||
if not client_id or not client_secret:
|
||||
raise Exception(
|
||||
"GigaChat credentials not configured. "
|
||||
"Please set GIGACHAT_CLIENT_ID and GIGACHAT_CLIENT_SECRET in .env file"
|
||||
)
|
||||
|
||||
# Формируем credentials и кодируем в Base64 с явным указанием UTF-8
|
||||
credentials = f"{client_id}:{client_secret}".strip().encode('utf-8') # Обрезаем лишние символы
|
||||
encoded_credentials = base64.b64encode(credentials).decode('utf-8')
|
||||
|
||||
headers = {
|
||||
"Authorization": f"Basic {encoded_credentials}",
|
||||
@@ -29,31 +46,61 @@ class GigaChatService:
|
||||
"RqUID": str(uuid.uuid4())
|
||||
}
|
||||
|
||||
data = {"scope": "GIGACHAT_API_PERS"}
|
||||
# Правильно кодируем данные формы (как в рабочем примере)
|
||||
form_data = {
|
||||
"grant_type": "client_credentials",
|
||||
"scope": "GIGACHAT_API_PERS"
|
||||
}
|
||||
|
||||
# Создаем SSL контекст без проверки сертификата (только для разработки!)
|
||||
ssl_context = ssl.create_default_context()
|
||||
ssl_context.check_hostname = False
|
||||
ssl_context.verify_mode = ssl.CERT_NONE
|
||||
|
||||
connector = aiohttp.TCPConnector(ssl=ssl_context)
|
||||
# Отключаем проверку SSL (только для разработки!)
|
||||
# Используем ssl=False для полного отключения проверки сертификата
|
||||
connector = aiohttp.TCPConnector(ssl=False)
|
||||
async with aiohttp.ClientSession(connector=connector) as session:
|
||||
async with session.post(
|
||||
settings.GIGACHAT_AUTH_URL,
|
||||
os.getenv("GIGACHAT_BASE_URL"),
|
||||
headers=headers,
|
||||
data=data
|
||||
data=form_data
|
||||
) as response:
|
||||
if response.status != 200:
|
||||
raise Exception(f"Failed to get token: {response.status}")
|
||||
# Получаем детали ошибки из ответа
|
||||
try:
|
||||
error_body = await response.text()
|
||||
# Пытаемся распарсить как JSON, если не получается - возвращаем текст
|
||||
try:
|
||||
error_json = await response.json()
|
||||
error_detail = error_json.get("error_description") or error_json.get("error") or str(error_json)
|
||||
except:
|
||||
error_detail = error_body
|
||||
except:
|
||||
error_detail = "No error details available"
|
||||
|
||||
raise Exception(
|
||||
f"Failed to get token: HTTP {response.status}. "
|
||||
f"Error details: {error_detail}. "
|
||||
f"Check your GIGACHAT_CLIENT_ID and GIGACHAT_CLIENT_SECRET_2 in .env file"
|
||||
)
|
||||
|
||||
result = await response.json()
|
||||
self.access_token = result.get("access_token")
|
||||
expires_in = result.get("expires_at", 1800)
|
||||
# expires_at может быть timestamp или количество секунд
|
||||
if expires_in > 1000000000: # Это timestamp
|
||||
self.token_expires_at = expires_in
|
||||
else: # Это количество секунд
|
||||
if not self.access_token:
|
||||
raise Exception(f"Token not found in response: {result}")
|
||||
|
||||
# Обрабатываем время истечения токена (может быть expires_at или expires_in)
|
||||
expires_at = result.get("expires_at")
|
||||
expires_in = result.get("expires_in")
|
||||
|
||||
if expires_at:
|
||||
# expires_at может быть timestamp или количество секунд
|
||||
if expires_at > 1000000000: # Это timestamp
|
||||
self.token_expires_at = expires_at
|
||||
else: # Это количество секунд
|
||||
self.token_expires_at = time.time() + expires_at
|
||||
elif expires_in:
|
||||
# expires_in - это всегда количество секунд до истечения
|
||||
self.token_expires_at = time.time() + expires_in
|
||||
else:
|
||||
# По умолчанию 30 минут (1800 секунд)
|
||||
self.token_expires_at = time.time() + 1800
|
||||
|
||||
return self.access_token
|
||||
|
||||
@@ -65,7 +112,7 @@ class GigaChatService:
|
||||
) -> Dict[str, Any]:
|
||||
"""Отправить сообщение в GigaChat"""
|
||||
token = await self._get_token()
|
||||
model = model or settings.GIGACHAT_MODEL_CHAT
|
||||
model = model or settings.GIGACHAT_MODEL_CHAT or "GigaChat"
|
||||
|
||||
messages = context or []
|
||||
messages.append({"role": "user", "content": message})
|
||||
@@ -82,12 +129,9 @@ class GigaChatService:
|
||||
"max_tokens": 2000
|
||||
}
|
||||
|
||||
# Создаем SSL контекст без проверки сертификата (только для разработки!)
|
||||
ssl_context = ssl.create_default_context()
|
||||
ssl_context.check_hostname = False
|
||||
ssl_context.verify_mode = ssl.CERT_NONE
|
||||
|
||||
connector = aiohttp.TCPConnector(ssl=ssl_context)
|
||||
# Отключаем проверку SSL (только для разработки!)
|
||||
# Используем ssl=False для полного отключения проверки сертификата
|
||||
connector = aiohttp.TCPConnector(ssl=False)
|
||||
async with aiohttp.ClientSession(connector=connector) as session:
|
||||
async with session.post(
|
||||
f"{settings.GIGACHAT_BASE_URL}/chat/completions",
|
||||
|
||||
@@ -17,6 +17,8 @@ services:
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
networks:
|
||||
- new-planet-network
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
@@ -30,6 +32,8 @@ services:
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
networks:
|
||||
- new-planet-network
|
||||
|
||||
minio:
|
||||
image: minio/minio:latest
|
||||
@@ -48,9 +52,15 @@ services:
|
||||
interval: 30s
|
||||
timeout: 20s
|
||||
retries: 3
|
||||
networks:
|
||||
- new-planet-network
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
redis_data:
|
||||
minio_data:
|
||||
|
||||
networks:
|
||||
new-planet-network:
|
||||
driver: bridge
|
||||
|
||||
|
||||
@@ -1341,3 +1341,242 @@ WHERE users.id = $1::UUID]
|
||||
2025-12-18 13:49:33 - root - INFO - Shutting down...
|
||||
2025-12-18 13:49:38 - root - INFO - Starting up...
|
||||
2025-12-18 13:51:42 - root - INFO - Shutting down...
|
||||
2025-12-18 18:44:49 - root - INFO - Starting up...
|
||||
2025-12-18 19:39:26 - root - INFO - Starting up...
|
||||
2025-12-18 19:40:16 - app.middleware.error_handler - ERROR - Unhandled exception: Error 111 connecting to localhost:6379. Connection refused.
|
||||
+ Exception Group Traceback (most recent call last):
|
||||
| File "/usr/local/lib/python3.11/site-packages/starlette/_utils.py", line 79, in collapse_excgroups
|
||||
| yield
|
||||
| File "/usr/local/lib/python3.11/site-packages/starlette/middleware/base.py", line 192, in __call__
|
||||
| async with anyio.create_task_group() as task_group:
|
||||
| File "/usr/local/lib/python3.11/site-packages/anyio/_backends/_asyncio.py", line 783, in __aexit__
|
||||
| raise BaseExceptionGroup(
|
||||
| ExceptionGroup: unhandled errors in a TaskGroup (1 sub-exception)
|
||||
+-+---------------- 1 ----------------
|
||||
| Traceback (most recent call last):
|
||||
| File "/usr/local/lib/python3.11/site-packages/starlette/middleware/errors.py", line 164, in __call__
|
||||
| await self.app(scope, receive, _send)
|
||||
| File "/usr/local/lib/python3.11/site-packages/starlette/middleware/base.py", line 191, in __call__
|
||||
| with recv_stream, send_stream, collapse_excgroups():
|
||||
| File "/usr/local/lib/python3.11/contextlib.py", line 158, in __exit__
|
||||
| self.gen.throw(typ, value, traceback)
|
||||
| File "/usr/local/lib/python3.11/site-packages/starlette/_utils.py", line 85, in collapse_excgroups
|
||||
| raise exc
|
||||
| File "/usr/local/lib/python3.11/site-packages/starlette/middleware/base.py", line 193, in __call__
|
||||
| response = await self.dispatch_func(request, call_next)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| File "/app/app/middleware/rate_limiter.py", line 20, in dispatch
|
||||
| current_requests = await cache_service.get(cache_key)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| File "/app/app/services/cache_service.py", line 28, in get
|
||||
| return await self.redis_client.get(key)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| File "/usr/local/lib/python3.11/site-packages/redis/asyncio/client.py", line 720, in execute_command
|
||||
| conn = self.connection or await pool.get_connection()
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| File "/usr/local/lib/python3.11/site-packages/redis/asyncio/connection.py", line 1198, in get_connection
|
||||
| await self.ensure_connection(connection)
|
||||
| File "/usr/local/lib/python3.11/site-packages/redis/asyncio/connection.py", line 1231, in ensure_connection
|
||||
| await connection.connect()
|
||||
| File "/usr/local/lib/python3.11/site-packages/redis/asyncio/connection.py", line 298, in connect
|
||||
| await self.connect_check_health(check_health=True)
|
||||
| File "/usr/local/lib/python3.11/site-packages/redis/asyncio/connection.py", line 317, in connect_check_health
|
||||
| raise ConnectionError(self._error_message(e))
|
||||
| redis.exceptions.ConnectionError: Error 111 connecting to localhost:6379. Connection refused.
|
||||
+------------------------------------
|
||||
|
||||
During handling of the above exception, another exception occurred:
|
||||
|
||||
Traceback (most recent call last):
|
||||
File "/usr/local/lib/python3.11/site-packages/starlette/middleware/errors.py", line 164, in __call__
|
||||
await self.app(scope, receive, _send)
|
||||
File "/usr/local/lib/python3.11/site-packages/starlette/middleware/base.py", line 191, in __call__
|
||||
with recv_stream, send_stream, collapse_excgroups():
|
||||
File "/usr/local/lib/python3.11/contextlib.py", line 158, in __exit__
|
||||
self.gen.throw(typ, value, traceback)
|
||||
File "/usr/local/lib/python3.11/site-packages/starlette/_utils.py", line 85, in collapse_excgroups
|
||||
raise exc
|
||||
File "/usr/local/lib/python3.11/site-packages/starlette/middleware/base.py", line 193, in __call__
|
||||
response = await self.dispatch_func(request, call_next)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/app/app/middleware/rate_limiter.py", line 20, in dispatch
|
||||
current_requests = await cache_service.get(cache_key)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/app/app/services/cache_service.py", line 28, in get
|
||||
return await self.redis_client.get(key)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/usr/local/lib/python3.11/site-packages/redis/asyncio/client.py", line 720, in execute_command
|
||||
conn = self.connection or await pool.get_connection()
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/usr/local/lib/python3.11/site-packages/redis/asyncio/connection.py", line 1198, in get_connection
|
||||
await self.ensure_connection(connection)
|
||||
File "/usr/local/lib/python3.11/site-packages/redis/asyncio/connection.py", line 1231, in ensure_connection
|
||||
await connection.connect()
|
||||
File "/usr/local/lib/python3.11/site-packages/redis/asyncio/connection.py", line 298, in connect
|
||||
await self.connect_check_health(check_health=True)
|
||||
File "/usr/local/lib/python3.11/site-packages/redis/asyncio/connection.py", line 317, in connect_check_health
|
||||
raise ConnectionError(self._error_message(e))
|
||||
redis.exceptions.ConnectionError: Error 111 connecting to localhost:6379. Connection refused.
|
||||
2025-12-18 19:40:16 - app.middleware.error_handler - ERROR - Unhandled exception: Error 111 connecting to localhost:6379. Connection refused.
|
||||
+ Exception Group Traceback (most recent call last):
|
||||
| File "/usr/local/lib/python3.11/site-packages/starlette/_utils.py", line 79, in collapse_excgroups
|
||||
| yield
|
||||
| File "/usr/local/lib/python3.11/site-packages/starlette/middleware/base.py", line 192, in __call__
|
||||
| async with anyio.create_task_group() as task_group:
|
||||
| File "/usr/local/lib/python3.11/site-packages/anyio/_backends/_asyncio.py", line 783, in __aexit__
|
||||
| raise BaseExceptionGroup(
|
||||
| ExceptionGroup: unhandled errors in a TaskGroup (1 sub-exception)
|
||||
+-+---------------- 1 ----------------
|
||||
| Traceback (most recent call last):
|
||||
| File "/usr/local/lib/python3.11/site-packages/starlette/middleware/errors.py", line 164, in __call__
|
||||
| await self.app(scope, receive, _send)
|
||||
| File "/usr/local/lib/python3.11/site-packages/starlette/middleware/base.py", line 191, in __call__
|
||||
| with recv_stream, send_stream, collapse_excgroups():
|
||||
| File "/usr/local/lib/python3.11/contextlib.py", line 158, in __exit__
|
||||
| self.gen.throw(typ, value, traceback)
|
||||
| File "/usr/local/lib/python3.11/site-packages/starlette/_utils.py", line 85, in collapse_excgroups
|
||||
| raise exc
|
||||
| File "/usr/local/lib/python3.11/site-packages/starlette/middleware/base.py", line 193, in __call__
|
||||
| response = await self.dispatch_func(request, call_next)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| File "/app/app/middleware/rate_limiter.py", line 20, in dispatch
|
||||
| current_requests = await cache_service.get(cache_key)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| File "/app/app/services/cache_service.py", line 28, in get
|
||||
| return await self.redis_client.get(key)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| File "/usr/local/lib/python3.11/site-packages/redis/asyncio/client.py", line 720, in execute_command
|
||||
| conn = self.connection or await pool.get_connection()
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| File "/usr/local/lib/python3.11/site-packages/redis/asyncio/connection.py", line 1198, in get_connection
|
||||
| await self.ensure_connection(connection)
|
||||
| File "/usr/local/lib/python3.11/site-packages/redis/asyncio/connection.py", line 1231, in ensure_connection
|
||||
| await connection.connect()
|
||||
| File "/usr/local/lib/python3.11/site-packages/redis/asyncio/connection.py", line 298, in connect
|
||||
| await self.connect_check_health(check_health=True)
|
||||
| File "/usr/local/lib/python3.11/site-packages/redis/asyncio/connection.py", line 317, in connect_check_health
|
||||
| raise ConnectionError(self._error_message(e))
|
||||
| redis.exceptions.ConnectionError: Error 111 connecting to localhost:6379. Connection refused.
|
||||
+------------------------------------
|
||||
|
||||
During handling of the above exception, another exception occurred:
|
||||
|
||||
Traceback (most recent call last):
|
||||
File "/usr/local/lib/python3.11/site-packages/starlette/middleware/errors.py", line 164, in __call__
|
||||
await self.app(scope, receive, _send)
|
||||
File "/usr/local/lib/python3.11/site-packages/starlette/middleware/base.py", line 191, in __call__
|
||||
with recv_stream, send_stream, collapse_excgroups():
|
||||
File "/usr/local/lib/python3.11/contextlib.py", line 158, in __exit__
|
||||
self.gen.throw(typ, value, traceback)
|
||||
File "/usr/local/lib/python3.11/site-packages/starlette/_utils.py", line 85, in collapse_excgroups
|
||||
raise exc
|
||||
File "/usr/local/lib/python3.11/site-packages/starlette/middleware/base.py", line 193, in __call__
|
||||
response = await self.dispatch_func(request, call_next)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/app/app/middleware/rate_limiter.py", line 20, in dispatch
|
||||
current_requests = await cache_service.get(cache_key)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/app/app/services/cache_service.py", line 28, in get
|
||||
return await self.redis_client.get(key)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/usr/local/lib/python3.11/site-packages/redis/asyncio/client.py", line 720, in execute_command
|
||||
conn = self.connection or await pool.get_connection()
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/usr/local/lib/python3.11/site-packages/redis/asyncio/connection.py", line 1198, in get_connection
|
||||
await self.ensure_connection(connection)
|
||||
File "/usr/local/lib/python3.11/site-packages/redis/asyncio/connection.py", line 1231, in ensure_connection
|
||||
await connection.connect()
|
||||
File "/usr/local/lib/python3.11/site-packages/redis/asyncio/connection.py", line 298, in connect
|
||||
await self.connect_check_health(check_health=True)
|
||||
File "/usr/local/lib/python3.11/site-packages/redis/asyncio/connection.py", line 317, in connect_check_health
|
||||
raise ConnectionError(self._error_message(e))
|
||||
redis.exceptions.ConnectionError: Error 111 connecting to localhost:6379. Connection refused.
|
||||
2025-12-18 19:40:16 - app.middleware.error_handler - ERROR - Unhandled exception: Error 111 connecting to localhost:6379. Connection refused.
|
||||
+ Exception Group Traceback (most recent call last):
|
||||
| File "/usr/local/lib/python3.11/site-packages/starlette/_utils.py", line 79, in collapse_excgroups
|
||||
| yield
|
||||
| File "/usr/local/lib/python3.11/site-packages/starlette/middleware/base.py", line 192, in __call__
|
||||
| async with anyio.create_task_group() as task_group:
|
||||
| File "/usr/local/lib/python3.11/site-packages/anyio/_backends/_asyncio.py", line 783, in __aexit__
|
||||
| raise BaseExceptionGroup(
|
||||
| ExceptionGroup: unhandled errors in a TaskGroup (1 sub-exception)
|
||||
+-+---------------- 1 ----------------
|
||||
| Traceback (most recent call last):
|
||||
| File "/usr/local/lib/python3.11/site-packages/starlette/middleware/errors.py", line 164, in __call__
|
||||
| await self.app(scope, receive, _send)
|
||||
| File "/usr/local/lib/python3.11/site-packages/starlette/middleware/base.py", line 191, in __call__
|
||||
| with recv_stream, send_stream, collapse_excgroups():
|
||||
| File "/usr/local/lib/python3.11/contextlib.py", line 158, in __exit__
|
||||
| self.gen.throw(typ, value, traceback)
|
||||
| File "/usr/local/lib/python3.11/site-packages/starlette/_utils.py", line 85, in collapse_excgroups
|
||||
| raise exc
|
||||
| File "/usr/local/lib/python3.11/site-packages/starlette/middleware/base.py", line 193, in __call__
|
||||
| response = await self.dispatch_func(request, call_next)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| File "/app/app/middleware/rate_limiter.py", line 20, in dispatch
|
||||
| current_requests = await cache_service.get(cache_key)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| File "/app/app/services/cache_service.py", line 28, in get
|
||||
| return await self.redis_client.get(key)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| File "/usr/local/lib/python3.11/site-packages/redis/asyncio/client.py", line 720, in execute_command
|
||||
| conn = self.connection or await pool.get_connection()
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| File "/usr/local/lib/python3.11/site-packages/redis/asyncio/connection.py", line 1198, in get_connection
|
||||
| await self.ensure_connection(connection)
|
||||
| File "/usr/local/lib/python3.11/site-packages/redis/asyncio/connection.py", line 1231, in ensure_connection
|
||||
| await connection.connect()
|
||||
| File "/usr/local/lib/python3.11/site-packages/redis/asyncio/connection.py", line 298, in connect
|
||||
| await self.connect_check_health(check_health=True)
|
||||
| File "/usr/local/lib/python3.11/site-packages/redis/asyncio/connection.py", line 317, in connect_check_health
|
||||
| raise ConnectionError(self._error_message(e))
|
||||
| redis.exceptions.ConnectionError: Error 111 connecting to localhost:6379. Connection refused.
|
||||
+------------------------------------
|
||||
|
||||
During handling of the above exception, another exception occurred:
|
||||
|
||||
Traceback (most recent call last):
|
||||
File "/usr/local/lib/python3.11/site-packages/starlette/middleware/errors.py", line 164, in __call__
|
||||
await self.app(scope, receive, _send)
|
||||
File "/usr/local/lib/python3.11/site-packages/starlette/middleware/base.py", line 191, in __call__
|
||||
with recv_stream, send_stream, collapse_excgroups():
|
||||
File "/usr/local/lib/python3.11/contextlib.py", line 158, in __exit__
|
||||
self.gen.throw(typ, value, traceback)
|
||||
File "/usr/local/lib/python3.11/site-packages/starlette/_utils.py", line 85, in collapse_excgroups
|
||||
raise exc
|
||||
File "/usr/local/lib/python3.11/site-packages/starlette/middleware/base.py", line 193, in __call__
|
||||
response = await self.dispatch_func(request, call_next)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/app/app/middleware/rate_limiter.py", line 20, in dispatch
|
||||
current_requests = await cache_service.get(cache_key)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/app/app/services/cache_service.py", line 28, in get
|
||||
return await self.redis_client.get(key)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/usr/local/lib/python3.11/site-packages/redis/asyncio/client.py", line 720, in execute_command
|
||||
conn = self.connection or await pool.get_connection()
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/usr/local/lib/python3.11/site-packages/redis/asyncio/connection.py", line 1198, in get_connection
|
||||
await self.ensure_connection(connection)
|
||||
File "/usr/local/lib/python3.11/site-packages/redis/asyncio/connection.py", line 1231, in ensure_connection
|
||||
await connection.connect()
|
||||
File "/usr/local/lib/python3.11/site-packages/redis/asyncio/connection.py", line 298, in connect
|
||||
await self.connect_check_health(check_health=True)
|
||||
File "/usr/local/lib/python3.11/site-packages/redis/asyncio/connection.py", line 317, in connect_check_health
|
||||
raise ConnectionError(self._error_message(e))
|
||||
redis.exceptions.ConnectionError: Error 111 connecting to localhost:6379. Connection refused.
|
||||
2025-12-18 22:55:17 - root - INFO - Starting up...
|
||||
2025-12-18 22:55:17 - root - INFO - Starting up...
|
||||
2025-12-18 22:56:56 - root - INFO - Starting up...
|
||||
2025-12-18 22:56:56 - root - INFO - Shutting down...
|
||||
2025-12-18 22:59:02 - root - INFO - Starting up...
|
||||
2025-12-18 22:59:02 - root - INFO - Shutting down...
|
||||
2025-12-18 22:59:53 - root - INFO - Starting up...
|
||||
2025-12-18 22:59:53 - root - INFO - Starting up...
|
||||
2025-12-18 22:59:53 - root - INFO - Shutting down...
|
||||
2025-12-18 22:59:53 - root - INFO - Shutting down...
|
||||
2025-12-18 20:00:09 - root - INFO - Shutting down...
|
||||
2025-12-18 23:00:15 - root - INFO - Starting up...
|
||||
2025-12-18 23:00:15 - root - INFO - Starting up...
|
||||
2025-12-18 23:00:15 - root - INFO - Shutting down...
|
||||
2025-12-18 23:00:15 - root - INFO - Shutting down...
|
||||
|
||||
Reference in New Issue
Block a user