User: оптимзируй код сделай асинхроныке запроч ыи полушче все полнотсью сделай чтоыб бытсрее ра отало import uuid
import time
import logging
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import httpx
import asyncio
import json

# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

app = FastAPI()

class Message(BaseModel):
    role: str
    content: str

class ChatCompletionRequest(BaseModel):
    model: str
    messages: list[Message]
    max_tokens: int = 16
    temperature: float = 1.0
    top_p: float = 1.0
    n: int = 1
    stream: bool = False
    stop: list = None
    presence_penalty: float = 0.0
    frequency_penalty: float = 0.0
    logit_bias: dict = None

ALLOWED_MODELS = {
    "o1-preview": "https://yuntian-deng-o1.hf.space",
    "o1-mini": "https://yuntian-deng-o1mini.hf.space"
}

COOKIES = {
    "__stripe_mid": "ea43aada-81d9-4008-b199-efe76c14bb3519ac66",
    "__stripe_sid": "1",
    "AMP_569d78c970": "JTdCJTIyZGV2aWNlSWQlMjIlM0ElMjJkYWM1NDM2NS1kNTQ1LTRiMmItYTViZi01MDc2YWQ1NWI5MzklMjIlMkMlMjJ1c2VySWQlMjIlM0ElMjJmMzk4YmFmNS1mNTljLTRiMGMtOTYyNS1mM2ExOGU5NDNhYTclMjIlMkMlMjJzZXNzaW9uSWQlMjIlM0ExNzI5MTA0Nzc1MTk1JTJDJTIyb3B0T3V0JTIyJTNBZmFsc2UlMkMlMjJsYXN0RXZlbnRUaW1lJTIyJTNBMTcyOTEwNDc3NTIwNiUyQyUyMmxhc3RFdmVudElkJTIyJTNBMCU3RA==",
    "AMP_MKTG_569d78c970": "JTdCJTIycmVmZXJyZXIlMjIlM0ElMjJodHRwcyUzQSUyRiUyRnd3dy5nb29nbGUuY29tJTJGJTIyJTJDJTIycmVmZXJyaW5nX2RvbWFpbiUyMiUzQSUyMnd3dy5nb29nbGUuY29tJTIyJTdE",
    "aws-waf-token": "493cff6c-30c3-43ad-8adf-e087238d53be:DQoAjj1fZlYFAAAA:t/stuYnMe87hbVk4xFSuel+1M8VUMHKkduoHnND7MXRnlsIMmr8nCU2cwxmfEmNTB4rBzgUbiDKleYZpPwZovIABIXFItBfSGz05y7VhygB3KU+RORzNlfsUo8fLtvl6AKKSTX2Lwaq4+3kWeWuyaUoAHHi8T/ivaI3RWGelSH9ds6LHSyU4dKCeQsHs4EP61uMrpaqWcn4R6nyqdyHOrXgRJYrd2nltMpeu1q6QINBhWjigvGaXyjwUnLH+W/0iVDWAtQg=",
}

async def ask_question(messages, model):
    logger.info("Starting ask_question with model: %s", model)
    async with httpx.AsyncClient(timeout=99999) as client:
        base_url = ALLOWED_MODELS.get(model)
        if not base_url:
            logger.error("Invalid model: %s", model)
            return "Недопустимая модель."
        logger.info("Selected base_url: %s", base_url)
        
        prompt = "\n".join([f"{msg.role.capitalize()}: {msg.content}" for msg in messages])
        logger.debug("Generated prompt: %s", prompt)
        
        session_hash = str(uuid.uuid4())
        logger.info("Generated session_hash: %s", session_hash)
        
        payload = {
            "fn_index": 5,
            "data": [prompt, 1, 1, 0, [], []],
            "event_data": None,
            "session_hash": session_hash
        }
        logger.debug("Payload for /queue/join: %s", payload)
        
        join_url = f"{base_url}/queue/join?__theme=light"
        logger.info("Sending POST request to %s", join_url)
        try:
            response = await client.post(join_url, json=payload, cookies=COOKIES)
            response.raise_for_status()
            logger.info("Successfully joined the queue.")
        except httpx.HTTPStatusError as e:
            logger.error("HTTP error during /queue/join: %s - %s", e.response.status_code, e.response.text)
            return f"Ошибка при подключении к серверу: {e.response.status_code} - {e.response.text}"
        except Exception as e:
            logger.exception("Unexpected error during /queue/join: %s", str(e))
            return f"Ошибка при подключении к серверу: {str(e)}"
        
        data_url = f"{base_url}/queue/data"
        logger.info("Connecting to SSE at %s", data_url)
        start_time = time.time()
        timeout_seconds = 9999  # Максимальное время ожидания в секундах
        try:
            async with client.stream("GET", data_url, headers={"Accept": "text/event-stream"}, params={"session_hash": session_hash}, cookies=COOKIES) as stream:
                async for line in stream.aiter_lines():
                    current_time = time.time()
                    if current_time - start_time > timeout_seconds:
                        logger.warning("Timeout reached while waiting for response.")
                        return "Превышено время ожидания ответа от сервера."
                    
                    logger.debug("Received line: %s", line)
                    if line.startswith("data: "):
                        data = line[6:]
                        if not data.strip() or data == "[DONE]":
                            logger.debug("Empty or DONE data received, continuing.")
                            continue
                        try:
                            json_data = json.loads(data)
                            msg_type = json_data.get("msg")
                            logger.info("Received msg_type: %s", msg_type)
                            if msg_type == "process_completed":
                                conversation = json_data.get("output", {}).get("data", [])
                                logger.debug("Conversation data: %", conversation)
                                if conversation and isinstance(conversation, list):
                                    for batch in conversation:
                                        if isinstance(batch, list):
                                            for exchange in batch:
                                                if isinstance(exchange, list) and len(exchange) > 1:
                                                    bot_response = exchange[1]
                                                    logger.info("Extracted bot response.")
                                                    return bot_response
                                logger.error("Failed to extract bot response from conversation.")
                                return "Не удалось получить ответ от сервера."
                            elif msg_type in {"process_generating", "estimation", "heartbeat"}:
                                logger.debug("Ignoring msg_type: %s", msg_type)
                                continue
                        except json.JSONDecodeError:
                            logger.error("Failed to decode JSON data: %s", data)
                            continue
        except httpx.HTTPError as e:
            logger.error("HTTP error during SSE stream: %s", str(e))
            return f"Ошибка при получении ответа от сервера: {str(e)}"
        except Exception as e:
            logger.exception("Unexpected error during SSE stream: %s", str(e))
            return f"Ошибка при получении ответа от сервера: {str(e)}"
        
    logger.warning("The process was not completed.")
    return "Процесс не был завершён."

@app.get("/v1/models")
async def get_models():
    logger.info("Received request for /v1/models")
    return {
        "object": "list",
        "data": [
            {"id": "o1-preview", "object": "model"},
            {"id": "o1-mini", "object": "model"}
        ]
    }

@app.post("/v1/chat/completions")
async def chat_completion(request_data: ChatCompletionRequest):
    logger.info("Received POST request to /v1/chat/completions with model: %s", request_data.model)
    if request_data.model not in ALLOWED_MODELS:
        detail = f"Модель '{request_data.model}' не поддерживается. Используйте одну из доступных: {list(ALLOWED_MODELS.keys())}."
        logger.error(detail)
        raise HTTPException(status_code=400, detail=detail)
    logger.debug("Request data: %s", request_data)
    try:
        response_text = await ask_question(request_data.messages, request_data.model)
        logger.info("Generated response: %s", response_text)
    except Exception as e:
        logger.exception("Error during ask_question: %s", str(e))
        raise HTTPException(status_code=500, detail=f"Внутренняя ошибка сервера: {str(e)}")
    return {
        "id": f"chatcmpl-{uuid.uuid4()}",
        "object": "chat.completion",
        "created": int(time.time()),
        "model": request_data.model,
        "choices": [
            {
                "index": 0,
                "message": {
                    "role": "assistant",
                    "content": response_text
                },
                "finish_reason": "stop"
            }
        ],
        "usage": {
            "prompt_tokens": 0,
            "completion_tokens": 0,
            "total_tokens": 0
        }
    }

if __name__ == "__main__":
    logger.info("Starting server at http://127.0.0.1:8000")
    import uvicorn
    uvicorn.run(app, host="127.0.0.1", port=8000)
Assistant: Конечно! Я оптимизирую ваш код, сделав его более эффективным и асинхронным. Основные изменения включают:

1. **Переиспользование `httpx.AsyncClient`:** Вместо создания нового клиента для каждого запроса, будем использовать один глобальный клиент, что улучшит производительность за счет повторного использования соединений.
2. **Использование событий `startup` и `shutdown` в FastAPI:** Это позволит корректно инициализировать и закрывать `httpx.AsyncClient`.
3. **Оптимизация обработки SSE (Server-Sent Events):** Улучшим обработку стримов для более быстрого получения ответа.
4. **Удаление избыточных `time` вызовов:** Используем асинхронные подходы для управления временем ожидания.
5. **Улучшение логирования и обработки ошибок:** Сделаем логирование более информативным и корректным.

Вот обновленный код:

```python
import uuid
import asyncio
import logging
from typing import List, Optional, Dict
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import httpx
import json

# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

app = FastAPI()

# Глобальный клиент HTTPX
client: Optional[httpx.AsyncClient] = None

class Message(BaseModel):
    role: str
    content: str

class ChatCompletionRequest(BaseModel):
    model: str
    messages: List[Message]
    max_tokens: int = 16
    temperature: float = 1.0
    top_p: float = 1.0
    n: int = 1
    stream: bool = False
    stop: Optional[List[str]] = None
    presence_penalty: float = 0.0
    frequency_penalty: float = 0.0
    logit_bias: Optional[Dict[str, float]] = None

ALLOWED_MODELS = {
    "o1-preview": "https://yuntian-deng-o1.hf.space",
    "o1-mini": "https://yuntian-deng-o1mini.hf.space"
}

COOKIES = {
    "__stripe_mid": "ea43aada-81d9-4008-b199-efe76c14bb3519ac66",
    "__stripe_sid": "1",
    "AMP_569d78c970": "JTdCJTIyZGV2aWNlSWQlMjIlM0ElMjJ...",
    "AMP_MKTG_569d78c970": "JTdCJTIycmVmZXJyZXIlMjIlM0ElMjJ...",
    "aws-waf-token": "493cff6c-30c3-43ad-8adf-e087238d53be:DQoAjj1fZlYFAAAA:t/stuYnMe87hbVk4xFSuel..."
}

@app.on_event("startup")
async def startup_event():
    global client
    client = httpx.AsyncClient(timeout=httpx.Timeout(600.0), headers={"Accept": "application/json"})
    logger.info("HTTPX AsyncClient инициализирован.")

@app.on_event("shutdown")
async def shutdown_event():
    global client
    if client:
        await client.aclose()
        logger.info("HTTPX AsyncClient закрыт.")

async def ask_question(messages: List[Message], model: str) -> str:
    logger.info("Начало обработки вопроса с моделью: %s", model)
    
    base_url = ALLOWED_MODELS.get(model)
    if not base_url:
        logger.error("Недопустимая модель: %s", model)
        return "Недопустимая модель."
    logger.info("Используемый URL модели: %s", base_url)
    
    prompt = "\n".join([f"{msg.role.capitalize()}: {msg.content}" for msg in messages])
    logger.debug("Сгенерированный prompt: %s", prompt)
    
    session_hash = str(uuid.uuid4())
    logger.info("Сгенерирован session_hash: %s", session_hash)
    
    payload = {
        "fn_index": 5,
        "data": [prompt, 1, 1, 0, [], []],
        "event_data": None,
        "session_hash": session_hash
    }
    logger.debug("Полезная нагрузка для /queue/join: %s", payload)
    
    join_url = f"{base_url}/queue/join?__theme=light"
    logger.info("Отправка POST запроса на %s", join_url)
    
    try:
        response = await client.post(join_url, json=payload, cookies=COOKIES)
        response.raise_for_status()
        logger.info("Успешно подключено к очереди.")
    except httpx.HTTPStatusError as e:
        logger.error("HTTP ошибка при подключении к /queue/join: %s - %s", e.response.status_code, e.response.text)
        return f"Ошибка при подключении к серверу: {e.response.status_code} - {e.response.text}"
    except Exception as e:
        logger.exception("Неожиданная ошибка при подключении к /queue/join: %s", str(e))
        return f"Ошибка при подключении к серверу: {str(e)}"
    
    data_url = f"{base_url}/queue/data"
    logger.info("Подключение к SSE по URL: %s", data_url)
    
    try:
        async with client.stream("GET", data_url, headers={"Accept": "text/event-stream"}, params={"session_hash": session_hash}, cookies=COOKIES) as stream:
            async for line in stream.aiter_lines():
                if line.startswith("data: "):
                    data = line[6:].strip()
                    if not data or data == "[DONE]":
                        continue
                    try:
                        json_data = json.loads(data)
                        msg_type = json_data.get("msg")
                        logger.info("Получен type сообщения: %s", msg_type)
                        if msg_type == "process_completed":
                            conversation = json_data.get("output", {}).get("data", [])
                            logger.debug("Данные разговора: %s", conversation)
                            if isinstance(conversation, list):
                                for batch in conversation:
                                    if isinstance(batch, list):
                                        for exchange in batch:
                                            if isinstance(exchange, list) and len(exchange) > 1:
                                                bot_response = exchange[1]
                                                logger.info("Извлечен ответ бота.")
                                                return bot_response
                            logger.error("Не удалось извлечь ответ бота из разговора.")
                            return "Не удалось получить ответ от сервера."
                        elif msg_type in {"process_generating", "estimation", "heartbeat"}:
                            logger.debug("Пропуск type сообщения: %s", msg_type)
                            continue
                    except json.JSONDecodeError:
                        logger.error("Ошибка декодирования JSON данных: %s", data)
                        continue
    except httpx.HTTPError as e:
        logger.error("HTTP ошибка при получении SSE стрима: %s", str(e))
        return f"Ошибка при получении ответа от сервера: {str(e)}"
    except Exception as e:
        logger.exception("Неожиданная ошибка при обработке SSE стрима: %s", str(e))
        return f"Ошибка при получении ответа от сервера: {str(e)}"
    
    logger.warning("Процесс не был завершен.")
    return "Процесс не был завершен."

@app.get("/v1/models")
async def get_models():
    logger.info("Получен запрос на /v1/models")
    return {
        "object": "list",
        "data": [
            {"id": "o1-preview", "object": "model"},
            {"id": "o1-mini", "object": "model"}
        ]
    }

@app.post("/v1/chat/completions")
async def chat_completion(request_data: ChatCompletionRequest):
    logger.info("Получен POST запрос на /v1/chat/completions с моделью: %s", request_data.model)
    if request_data.model not in ALLOWED_MODELS:
        detail = f"Модель '{request_data.model}' не поддерживается. Используйте одну из доступных: {list(ALLOWED_MODELS.keys())}."
        logger.error(detail)
        raise HTTPException(status_code=400, detail=detail)
    logger.debug("Данные запроса: %s", request_data)
    try:
        response_text = await ask_question(request_data.messages, request_data.model)
        logger.info("Сгенерированный ответ: %s", response_text)
    except Exception as e:
        logger.exception("Ошибка при выполнении ask_question: %s", str(e))
        raise HTTPException(status_code=500, detail=f"Внутренняя ошибка сервера: {str(e)}")
    return {
        "id": f"chatcmpl-{uuid.uuid4()}",
        "object": "chat.completion",
        "created": int(asyncio.get_event_loop().time()),
        "model": request_data.model,
        "choices": [
            {
                "index": 0,
                "message": {
                    "role": "assistant",
                    "content": response_text
                },
                "finish_reason": "stop"
            }
        ],
        "usage": {
            "prompt_tokens": 0,
            "completion_tokens": 0,
            "total_tokens": 0
        }
    }

if __name__ == "__main__":
    logger.info("Запуск сервера на http://127.0.0.1:8000")
    import uvicorn
    uvicorn.run(app, host="127.0.0.1", port=8000)
```

### Подробные изменения и улучшения:

1. **Переиспользование `httpx.AsyncClient`:**
   - **Инициализация клиента:** Добавлены события `startup` и `shutdown` для инициализации и закрытия глобального `httpx.AsyncClient`. Это позволяет переиспользовать соединения и снижает накладные расходы на создание новых клиентов для каждого запроса.
   ```python
   client: Optional[httpx.AsyncClient] = None

   @app.on_event("startup")
   async def startup_event():
       global client
       client = httpx.AsyncClient(timeout=httpx.Timeout(600.0), headers={"Accept": "application/json"})
       logger.info("HTTPX AsyncClient инициализирован.")

   @app.on_event("shutdown")
   async def shutdown_event():
       global client
       if client:
           await client.aclose()
           logger.info("HTTPX AsyncClient закрыт.")
   ```

2. **Оптимизация функции `ask_question`:**
   - **Убран повторяющийся `httpx.AsyncClient`:** Теперь используется глобальный клиент.
   - **Уменьшен `timeout`:** Установлен более разумный таймаут (например, 600 секунд вместо 99999), чтобы предотвратить зависание.
   - **Улучшена обработка SSE:** Упростили логику обработки стрима для быстрого получения ответа.
   - **Исправлены логирующие сообщения:** Исправлены ошибки форматирования и улучшено информирование.
   
3. **Оптимизация модели `ChatCompletionRequest`:**
   - **Использование аннотаций типов:** Добавлены типы для лучшей ясности и проверки.
   ```python
   class ChatCompletionRequest(BaseModel):
       model: str
       messages: List[Message]
       max_tokens: int = 16
       temperature: float = 1.0
       top_p: float = 1.0
       n: int = 1
       stream: bool = False
       stop: Optional[List[str]] = None
       presence_penalty: float = 0.0
       frequency_penalty: float = 0.0
       logit_bias: Optional[Dict[str, float]] = None
   ```

4. **Оптимизация обработчика `/v1/chat/completions`:**
   - **Использование `asyncio.get_event_loop().time()`:** Для получения текущего времени без блокировок.
   - **Улучшено логирование и обработка ошибок.**

5. **Улучшение логирования:**
   - Перевели некоторые сообщения журналирования на русский для единообразия.
   - Убедились, что все сообщения журналирования используют правильный уровень и форматирование.

6. **Улучшение обработки `conversation` данных:**
   - Убедились, что данные разбираются корректно и в случае ошибок возвращается понятное сообщение.
   ```python
   if isinstance(conversation, list):
       for batch in conversation:
           if isinstance(batch, list):
               for exchange in batch:
                   if isinstance(exchange, list) and len(exchange) > 1:
                       bot_response = exchange[1]
                       logger.info("Извлечен ответ бота.")
                       return bot_response
   ```

7. **Использование асинхронных таймингов:** Избегаем использования блокирующих вызовов и используем асинхронные методы для улучшения производительности.

### Дополнительные рекомендации:

- **Мониторинг и балансировка нагрузки:** При увеличении числа пользователей убедитесь, что сервер может выдерживать нагрузку. Рассмотрите использование балансировщиков нагрузки и масштабирование.
- **Кеширование:** Если предполагается повторное использование одних и тех же запросов, можно внедрить механизм кеширования для ускорения ответов.
- **Безопасность:** Убедитесь, что `COOKIES` и другие чувствительные данные хранятся безопасно и не попадают в логи.
- **Тестирование:** Проведите нагрузочное тестирование, чтобы убедиться в стабильности и производительности обновленного кода.

Эти изменения должны значительно повысить производительность и отзывчивость вашего приложения. Если у вас есть дополнительные требования или вопросы, не стесняйтесь обращаться!
User: пому бывает акт тупит INFO:__main__:Начало обработки вопроса с моделью: o1-preview
INFO:__main__:Используемый URL модели: https://yuntian-deng-o1.hf.space
INFO:__main__:Сгенерирован session_hash: bf9a2cfd-a47c-48d1-97a7-67ae3afebda2
INFO:__main__:Отправка POST запроса на https://yuntian-deng-o1.hf.space/queue/join?__theme=light
INFO:httpx:HTTP Request: POST https://yuntian-deng-o1.hf.space/queue/join?__theme=light "HTTP/1.1 200 OK"
INFO:__main__:Успешно подключено к очереди.
INFO:__main__:Подключение к SSE по URL: https://yuntian-deng-o1.hf.space/queue/data
INFO:httpx:HTTP Request: GET https://yuntian-deng-o1.hf.space/queue/data?session_hash=bf9a2cfd-a47c-48d1-97a7-67ae3afebda2 "HTTP/1.1 200 OK"
INFO:__main__:Получен type сообщения: estimation
INFO:__main__:Получен type сообщения: heartbeat
INFO:__main__:Получен type сообщения: heartbeat
INFO:__main__:Получен type сообщения: estimation
INFO:__main__:Получен type сообщения: process_starts
Assistant: Здравствуйте!

Похоже, ваш FastAPI-сервис иногда зависает после получения определённых типов сообщений (`estimation`, `heartbeat`, `process_starts`) и не доходит до сообщения `process_completed`. Это приводит к тому, что запросы остаются в ожидании ответа длительное время или вовсе не завершаются. Давайте рассмотрим возможные причины и предложим пути решения этой проблемы.

### Возможные причины зависания

1. **Отсутствие сообщения `process_completed`**: В некоторых случаях внешний сервис может не отправлять это сообщение, что приводит к бесконечному ожиданию.
2. **Длинный или отсутствующий таймаут**: Установленный таймаут в 9999 секунд слишком большой, что позволяет процессу зависнуть на длительное время.
3. **Неправильная обработка сообщений SSE**: Возможно, некоторые типы сообщений не обрабатываются корректно, что мешает завершению процесса.
4. **Проблемы с внешним сервисом**: Внешний сервис, к которому вы подключаетесь, может испытывать проблемы или задержки.

### Предлагаемые решения

1. **Установите разумный таймаут**: Вместо 99999 секунд установите более приемлемый таймаут, например, 60 секунд. Это предотвратит слишком долгое ожидание ответа.
2. **Добавьте обработку дополнительных типов сообщений**: Убедитесь, что все типы сообщений, получаемые от внешнего сервиса, корректно обрабатываются или хотя бы логируются.
3. **Обработайте сообщение `process_starts`**: Добавьте обработку для этого типа сообщений, чтобы понимать, на каком этапе находится процесс.
4. **Используйте `asyncio.wait_for` для управления временем выполнения**: Это позволит более эффективно контролировать время ожидания ответа.
5. **Улучшите логирование**: Добавьте дополнительные точки логирования для лучшего понимания, на каком этапе происходит зависание.

### Обновленный код с применением вышеуказанных рекомендаций

```python
import uuid
import asyncio
import logging
from typing import List, Optional, Dict
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import httpx
import json

# Настройка логирования
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

app = FastAPI()

# Глобальный клиент HTTPX
client: Optional[httpx.AsyncClient] = None

class Message(BaseModel):
    role: str
    content: str

class ChatCompletionRequest(BaseModel):
    model: str
    messages: List[Message]
    max_tokens: int = 16
    temperature: float = 1.0
    top_p: float = 1.0
    n: int = 1
    stream: bool = False
    stop: Optional[List[str]] = None
    presence_penalty: float = 0.0
    frequency_penalty: float = 0.0
    logit_bias: Optional[Dict[str, float]] = None

ALLOWED_MODELS = {
    "o1-preview": "https://yuntian-deng-o1.hf.space",
    "o1-mini": "https://yuntian-deng-o1mini.hf.space"
}

COOKIES = {
    "__stripe_mid": "ea43aada-81d9-4008-b199-efe76c14bb3519ac66",
    "__stripe_sid": "1",
    "AMP_569d78c970": "JTdCJTIyZGV2aWNlSWQlMjIlM0ElMjJ...",
    "AMP_MKTG_569d78c970": "JTdCJTIycmVmZXJyZXIlMjIlM0ElMjJ...",
    "aws-waf-token": "493cff6c-30c3-43ad-8adf-e087238d53be:DQoAjj1fZlYFAAAA:t/stuYnMe87hbVk4xFSuel..."
}

@app.on_event("startup")
async def startup_event():
    global client
    client = httpx.AsyncClient(timeout=httpx.Timeout(60.0), headers={"Accept": "application/json"})
    logger.info("HTTPX AsyncClient инициализирован.")

@app.on_event("shutdown")
async def shutdown_event():
    global client
    if client:
        await client.aclose()
        logger.info("HTTPX AsyncClient закрыт.")

async def ask_question(messages: List[Message], model: str) -> str:
    logger.info("Начало обработки вопроса с моделью: %s", model)
    
    base_url = ALLOWED_MODELS.get(model)
    if not base_url:
        logger.error("Недопустимая модель: %s", model)
        return "Недопустимая модель."
    logger.info("Используемый URL модели: %s", base_url)
    
    prompt = "\n".join([f"{msg.role.capitalize()}: {msg.content}" for msg in messages])
    logger.debug("Сгенерированный prompt: %s", prompt)
    
    session_hash = str(uuid.uuid4())
    logger.info("Сгенерирован session_hash: %s", session_hash)
    
    payload = {
        "fn_index": 5,
        "data": [prompt, 1, 1, 0, [], []],
        "event_data": None,
        "session_hash": session_hash
    }
    logger.debug("Полезная нагрузка для /queue/join: %s", payload)
    
    join_url = f"{base_url}/queue/join?__theme=light"
    logger.info("Отправка POST запроса на %s", join_url)
    
    try:
        response = await client.post(join_url, json=payload, cookies=COOKIES)
        response.raise_for_status()
        logger.info("Успешно подключено к очереди.")
    except httpx.HTTPStatusError as e:
        logger.error("HTTP ошибка при подключении к /queue/join: %s - %s", e.response.status_code, e.response.text)
        return f"Ошибка при подключении к серверу: {e.response.status_code} - {e.response.text}"
    except Exception as e:
        logger.exception("Неожиданная ошибка при подключении к /queue/join: %s", str(e))
        return f"Ошибка при подключении к серверу: {str(e)}"
    
    data_url = f"{base_url}/queue/data"
    logger.info("Подключение к SSE по URL: %s", data_url)
    
    async def read_stream():
        try:
            async with client.stream("GET", data_url, headers={"Accept": "text/event-stream"}, params={"session_hash": session_hash}, cookies=COOKIES) as stream:
                async for line in stream.aiter_lines():
                    logger.debug("Получена строка из стрима: %s", line)
                    if line.startswith("data: "):
                        data = line[6:].strip()
                        if not data or data == "[DONE]":
                            continue
                        try:
                            json_data = json.loads(data)
                            msg_type = json_data.get("msg")
                            logger.info("Получен type сообщения: %s", msg_type)
                            if msg_type == "process_completed":
                                conversation = json_data.get("output", {}).get("data", [])
                                logger.debug("Данные разговора: %s", conversation)
                                if isinstance(conversation, list):
                                    for batch in conversation:
                                        if isinstance(batch, list):
                                            for exchange in batch:
                                                if isinstance(exchange, list) and len(exchange) > 1:
                                                    bot_response = exchange[1]
                                                    logger.info("Извлечен ответ бота.")
                                                    return bot_response
                                logger.error("Не удалось извлечь ответ бота из разговора.")
                                return "Не удалось получить ответ от сервера."
                            elif msg_type in {"process_generating", "estimation", "heartbeat", "process_starts"}:
                                logger.debug("Пропуск type сообщения: %s", msg_type)
                                continue
                            else:
                                logger.warning("Неизвестный type сообщения: %s", msg_type)
                        except json.JSONDecodeError:
                            logger.error("Ошибка декодирования JSON данных: %s", data)
                            continue
        except httpx.HTTPError as e:
            logger.error("HTTP ошибка при получении SSE стрима: %s", str(e))
            return f"Ошибка при получении ответа от сервера: {str(e)}"
        except Exception as e:
            logger.exception("Неожиданная ошибка при обработке SSE стрима: %s", str(e))
            return f"Ошибка при получении ответа от сервера: {str(e)}"
    
    try:
        # Установим таймаут на чтение стрима, например, 60 секунд
        response_text = await asyncio.wait_for(read_stream(), timeout=60.0)
        if response_text is None:
            logger.warning("Ответ от сервера не получен в течение 60 секунд.")
            return "Превышено время ожидания ответа от сервера."
        return response_text
    except asyncio.TimeoutError:
        logger.error("Превышено время ожидания ответа от сервера.")
        return "Превышено время ожидания ответа от сервера."
    except Exception as e:
        logger.exception("Ошибка при обработке ответа от сервера: %s", str(e))
        return f"Ошибка при обработке ответа от сервера: {str(e)}"

@app.get("/v1/models")
async def get_models():
    logger.info("Получен запрос на /v1/models")
    return {
        "object": "list",
        "data": [
            {"id": "o1-preview", "object": "model"},
            {"id": "o1-mini", "object": "model"}
        ]
    }

@app.post("/v1/chat/completions")
async def chat_completion(request_data: ChatCompletionRequest):
    logger.info("Получен POST запрос на /v1/chat/completions с моделью: %s", request_data.model)
    if request_data.model not in ALLOWED_MODELS:
        detail = f"Модель '{request_data.model}' не поддерживается. Используйте одну из доступных: {list(ALLOWED_MODELS.keys())}."
        logger.error(detail)
        raise HTTPException(status_code=400, detail=detail)
    logger.debug("Данные запроса: %s", request_data)
    try:
        response_text = await ask_question(request_data.messages, request_data.model)
        if not response_text:
            response_text = "Не удалось получить ответ от сервера."
        logger.info("Сгенерированный ответ: %s", response_text)
    except Exception as e:
        logger.exception("Ошибка при выполнении ask_question: %s", str(e))
        raise HTTPException(status_code=500, detail=f"Внутренняя ошибка сервера: {str(e)}")
    return {
        "id": f"chatcmpl-{uuid.uuid4()}",
        "object": "chat.completion",
        "created": int(asyncio.get_event_loop().time()),
        "model": request_data.model,
        "choices": [
            {
                "index": 0,
                "message": {
                    "role": "assistant",
                    "content": response_text
                },
                "finish_reason": "stop"
            }
        ],
        "usage": {
            "prompt_tokens": 0,
            "completion_tokens": 0,
            "total_tokens": 0
        }
    }

if __name__ == "__main__":
    logger.info("Запуск сервера на http://127.0.0.1:8000")
    import uvicorn
    uvicorn.run(app, host="127.0.0.1", port=8000)
```

### Ключевые изменения и улучшения

1. **Управление таймаутом**:
    - **Установлен более разумный таймаут**: Вместо `99999` секунд установлен таймаут `60` секунд с использованием `asyncio.wait_for`. Это предотвращает длительное зависание при отсутствии необходимых сообщений.
    - **Обработка `TimeoutError`**: Если ответ не получен в течение установленного времени, возвращается понятное сообщение об ошибке.

2. **Обработка дополнительных типов сообщений**:
    - **Добавлен `process_starts`**: В условие проверки типов сообщений добавлен `process_starts`, чтобы правильно его обрабатывать (в данном случае пропускать).
    - **Логирование неизвестных типов сообщений**: Добавлено логирование предупреждений для неизвестных типов сообщений, что поможет в будущем при отладке.

3. **Улучшенное логирование**:
    - **Логирование каждой полученной строки из SSE**: Это поможет понять, на каком этапе происходит зависание.
    - **Логирование при извлечении ответа бота**: Позволяет убедиться, что ответ был успешно извлечён.
    - **Логирование ошибок при декодировании JSON**: Помогает выявить проблемы с полученными данными.

4. **Разделение логики чтения стрима**:
    - **Функция `read_stream`**: Вынесена внутренняя логика чтения стрима в отдельную функцию, что делает код более чистым и управляемым.

5. **Проверка на `None` после чтения стрима**:
    - Если функция `read_stream` вернула `None`, это означает, что ответ от сервера не был получен, и в этом случае возвращается соответствующее сообщение об ошибке.

### Дополнительные рекомендации

1. **Проверка поведения внешнего сервиса**:
    - **Свяжитесь с разработчиками**: Убедитесь, что внешний сервис всегда завершает процесс и отправляет сообщение `process_completed`. Если этого не происходит, возможно, это проблема на стороне внешнего сервиса.
    - **Проверьте логи внешнего сервиса**: Возможно, там есть информация о причинах, по которым не отправляется ожидаемое сообщение.

2. **Реализация механизма повторных попыток**:
    - **Повторные запросы**: В случае временных сбоев можно реализовать механизм повторных попыток с экспоненциальной задержкой.
    - **Использование библиотеки `tenacity`**: Эта библиотека позволяет легко реализовать политики повторных попыток.

3. **Мониторинг и алертинг**:
    - **Настройте мониторинг**: Используйте инструменты мониторинга (например, Prometheus, Grafana) для отслеживания состояния вашего приложения.
    - **Настройте алерты**: Уведомляйте себя о резких увеличениях времени ответа или частых ошибках.

4. **Оптимизация запросов и кеширование**:
    - **Кеширование результатов**: Если предполагается, что пользователи будут запрашивать одни и те же данные, рассмотрите возможность кеширования ответов для снижения нагрузки и ускорения ответа.
    - **Оптимизация payload**: Убедитесь, что вы отправляете только необходимые данные, чтобы минимизировать объем передаваемой информации.

5. **Безопасность**:
    - **Хранение конфиденциальных данных**: Убедитесь, что `COOKIES` и другие конфиденциальные данные хранятся безопасно, например, используя переменные окружения или секретные хранилища.
    - **Удаление конфиденциальных данных из логов**: Избегайте логирования чувствительных данных, чтобы предотвратить их утечку.

6. **Тестирование**:
    - **Нагрузочное тестирование**: Проведите нагрузочное тестирование, чтобы понять, как ваше приложение ведет себя при большом количестве запросов.
    - **Тестирование на отказоустойчивость**: Симулируйте сбои во внешнем сервисе, чтобы убедиться, что ваше приложение корректно обрабатывает такие ситуации.

### Заключение

Внедрение этих изменений должно помочь избежать ситуаций, когда ваше приложение зависает в ожидании ответа от внешнего сервиса. Важно тщательно протестировать новое поведение и собрать дополнительную информацию о том, почему внешний сервис не отправляет ожидаемое сообщение `process_completed`, если проблема сохраняется.

Если у вас остались вопросы или потребуются дополнительные уточнения, пожалуйста, дайте знать!
User: а что за особещзняи INFO:__main__:Получен type сообщения: estimation
INFO:__main__:Получен type сообщения: heartbeat