test24 / api /utils.py
Niansuh's picture
Update api/utils.py
e848ce6 verified
raw
history blame
9.25 kB
from datetime import datetime
from http.client import HTTPException
import json
from typing import Any, Dict, Optional
import uuid
import httpx
from api import validate
from api.config import MODEL_MAPPING, headers, AGENT_MODE, TRENDING_AGENT_MODE
from fastapi import Depends, HTTPException as FastAPIHTTPException
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
from api.config import APP_SECRET, BASE_URL
from api.models import ChatRequest
from api.logger import setup_logger
logger = setup_logger(__name__)
# Initialize HTTPBearer for security dependency
security = HTTPBearer()
def create_chat_completion_data(
content: str, model: str, timestamp: int, finish_reason: Optional[str] = None
) -> Dict[str, Any]:
"""
Create a dictionary representing a chat completion chunk.
Args:
content (str): The content of the message.
model (str): The model used for the chat.
timestamp (int): The timestamp of the creation.
finish_reason (Optional[str], optional): The reason for finishing. Defaults to None.
Returns:
Dict[str, Any]: A dictionary representing the chat completion chunk.
"""
return {
"id": f"chatcmpl-{uuid.uuid4()}",
"object": "chat.completion.chunk",
"created": timestamp,
"model": model,
"choices": [
{
"index": 0,
"delta": {"content": content, "role": "assistant"},
"finish_reason": finish_reason,
}
],
"usage": None,
}
def verify_app_secret(credentials: HTTPAuthorizationCredentials = Depends(security)):
"""
Verify the application secret from the HTTP authorization credentials.
Args:
credentials (HTTPAuthorizationCredentials, optional): The HTTP authorization credentials. Defaults to Depends(security).
Raises:
HTTPException: If the APP_SECRET does not match.
Returns:
str: The verified credentials.
"""
if credentials.credentials != APP_SECRET:
raise FastAPIHTTPException(status_code=403, detail="Invalid APP_SECRET")
return credentials.credentials
def message_to_dict(message):
"""
Convert a message object to a dictionary.
Args:
message: The message object to convert.
Returns:
Dict[str, Any]: The dictionary representation of the message.
"""
if isinstance(message.content, str):
return {"role": message.role, "content": message.content}
elif isinstance(message.content, list) and len(message.content) == 2:
return {
"role": message.role,
"content": message.content[0]["text"],
"data": {
"imageBase64": message.content[1]["image_url"]["url"],
"fileText": "",
"title": "snapshot",
},
}
else:
return {"role": message.role, "content": message.content}
async def process_streaming_response(request: ChatRequest):
"""
Process a streaming response from the chat API.
Args:
request (ChatRequest): The chat request containing all necessary information.
Yields:
str: The streaming data chunks formatted as server-sent events.
"""
agent_mode = AGENT_MODE.get(request.model, {})
trending_agent_mode = TRENDING_AGENT_MODE.get(request.model, {})
# Log reduced information
logger.info(
f"Streaming request for model: '{request.model}', "
f"agent mode: {agent_mode}, trending agent mode: {trending_agent_mode}"
)
json_data = {
"messages": [message_to_dict(msg) for msg in request.messages],
"previewToken": None,
"userId": None,
"codeModelMode": True,
"agentMode": agent_mode,
"trendingAgentMode": trending_agent_mode,
"isMicMode": False,
"userSystemPrompt": None,
"maxTokens": request.max_tokens,
"playgroundTopP": request.top_p,
"playgroundTemperature": request.temperature,
"isChromeExt": False,
"githubToken": None,
"clickedAnswer2": False,
"clickedAnswer3": False,
"clickedForceWebSearch": False,
"visitFromDelta": False,
"mobileClient": False,
"userSelectedModel": MODEL_MAPPING.get(request.model),
"validated": validate.getHid()
}
async with httpx.AsyncClient() as client:
try:
async with client.stream(
"POST",
f"{BASE_URL}/api/chat",
headers=headers,
json=json_data,
timeout=100,
) as response:
response.raise_for_status()
timestamp = int(datetime.now().timestamp())
async for line in response.aiter_lines():
if line:
content = line + "\n"
if "https://www.blackbox.ai" in content:
validate.getHid(True)
content = "Hid has been refreshed; feel free to restart the conversation.\n"
yield f"data: {json.dumps(create_chat_completion_data(content, request.model, timestamp))}\n\n"
break
# Remove the specific pattern without affecting markdown
content = content.replace("$@$v=undefined-rv1$@$", "")
yield f"data: {json.dumps(create_chat_completion_data(content, request.model, timestamp))}\n\n"
# Indicate the end of the stream
yield f"data: {json.dumps(create_chat_completion_data('', request.model, timestamp, 'stop'))}\n\n"
yield "data: [DONE]\n\n"
except httpx.HTTPStatusError as e:
logger.error(f"HTTP error occurred: {e}")
raise FastAPIHTTPException(status_code=e.response.status_code, detail=str(e))
except httpx.RequestError as e:
logger.error(f"Error occurred during request: {e}")
raise FastAPIHTTPException(status_code=500, detail=str(e))
async def process_non_streaming_response(request: ChatRequest):
"""
Process a non-streaming response from the chat API.
Args:
request (ChatRequest): The chat request containing all necessary information.
Returns:
Dict[str, Any]: The full response from the chat API formatted appropriately.
"""
agent_mode = AGENT_MODE.get(request.model, {})
trending_agent_mode = TRENDING_AGENT_MODE.get(request.model, {})
# Log reduced information
logger.info(
f"Non-streaming request for model: '{request.model}', "
f"agent mode: {agent_mode}, trending agent mode: {trending_agent_mode}"
)
json_data = {
"messages": [message_to_dict(msg) for msg in request.messages],
"previewToken": None,
"userId": None,
"codeModelMode": True,
"agentMode": agent_mode,
"trendingAgentMode": trending_agent_mode,
"isMicMode": False,
"userSystemPrompt": None,
"maxTokens": request.max_tokens,
"playgroundTopP": request.top_p,
"playgroundTemperature": request.temperature,
"isChromeExt": False,
"githubToken": None,
"clickedAnswer2": False,
"clickedAnswer3": False,
"clickedForceWebSearch": False,
"visitFromDelta": False,
"mobileClient": False,
"userSelectedModel": MODEL_MAPPING.get(request.model),
"validated": validate.getHid()
}
full_response = ""
async with httpx.AsyncClient() as client:
try:
async with client.stream(
method="POST",
url=f"{BASE_URL}/api/chat",
headers=headers,
json=json_data,
timeout=100,
) as response:
response.raise_for_status()
async for chunk in response.aiter_text():
full_response += chunk
if "https://www.blackbox.ai" in full_response:
validate.getHid(True)
full_response = "Hid has been refreshed; feel free to restart the conversation."
# Remove the specific pattern without affecting markdown
full_response = full_response.replace("$@$v=undefined-rv1$@$", "")
return {
"id": f"chatcmpl-{uuid.uuid4()}",
"object": "chat.completion",
"created": int(datetime.now().timestamp()),
"model": request.model,
"choices": [
{
"index": 0,
"message": {"role": "assistant", "content": full_response},
"finish_reason": "stop",
}
],
"usage": None,
}
except httpx.HTTPStatusError as e:
logger.error(f"HTTP error occurred: {e}")
raise FastAPIHTTPException(status_code=e.response.status_code, detail=str(e))
except httpx.RequestError as e:
logger.error(f"Error occurred during request: {e}")
raise FastAPIHTTPException(status_code=500, detail=str(e))