mirror of
https://github.com/snailyp/gemini-balance.git
synced 2026-09-05 07:26:39 +08:00
新增自定义日志模块,替换全局logging实现;优化日志输出格式与颜色支持
This commit is contained in:
Vendored
+2
-1
@@ -15,7 +15,8 @@
|
|||||||
"--host",
|
"--host",
|
||||||
"127.0.0.1",
|
"127.0.0.1",
|
||||||
"--port",
|
"--port",
|
||||||
"8000"
|
"8000",
|
||||||
|
"--no-access-log"
|
||||||
],
|
],
|
||||||
"jinja": true
|
"jinja": true
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -17,4 +17,4 @@ ENV MODEL_SEARCH='["gemini-2.0-flash-exp"]'
|
|||||||
EXPOSE 8000
|
EXPOSE 8000
|
||||||
|
|
||||||
# Run the application
|
# Run the application
|
||||||
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
|
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--no-access-log"]
|
||||||
|
|||||||
+2
-3
@@ -1,6 +1,5 @@
|
|||||||
from http.client import HTTPException
|
from http.client import HTTPException
|
||||||
from fastapi import APIRouter, Depends, Header
|
from fastapi import APIRouter, Depends, Header
|
||||||
import logging
|
|
||||||
from fastapi.responses import StreamingResponse
|
from fastapi.responses import StreamingResponse
|
||||||
|
|
||||||
from app.core.security import SecurityService
|
from app.core.security import SecurityService
|
||||||
@@ -10,9 +9,10 @@ from app.services.chat_service import ChatService
|
|||||||
from app.services.embedding_service import EmbeddingService
|
from app.services.embedding_service import EmbeddingService
|
||||||
from app.schemas.request_model import ChatRequest, EmbeddingRequest
|
from app.schemas.request_model import ChatRequest, EmbeddingRequest
|
||||||
from app.core.config import settings
|
from app.core.config import settings
|
||||||
|
from app.core.logger import get_api_logger
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
logger = logging.getLogger(__name__)
|
logger = get_api_logger()
|
||||||
|
|
||||||
# 初始化服务
|
# 初始化服务
|
||||||
security_service = SecurityService(settings.ALLOWED_TOKENS)
|
security_service = SecurityService(settings.ALLOWED_TOKENS)
|
||||||
@@ -59,7 +59,6 @@ async def chat_completion(
|
|||||||
tools=request.tools,
|
tools=request.tools,
|
||||||
tool_choice=request.tool_choice,
|
tool_choice=request.tool_choice,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# 处理流式响应
|
# 处理流式响应
|
||||||
if request.stream:
|
if request.stream:
|
||||||
|
|||||||
@@ -0,0 +1,105 @@
|
|||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
from typing import Dict, Optional
|
||||||
|
import platform
|
||||||
|
|
||||||
|
# ANSI转义序列颜色代码
|
||||||
|
COLORS = {
|
||||||
|
'DEBUG': '\033[34m', # 蓝色
|
||||||
|
'INFO': '\033[32m', # 绿色
|
||||||
|
'WARNING': '\033[33m', # 黄色
|
||||||
|
'ERROR': '\033[31m', # 红色
|
||||||
|
'CRITICAL': '\033[1;31m' # 红色加粗
|
||||||
|
}
|
||||||
|
|
||||||
|
# Windows系统启用ANSI支持
|
||||||
|
if platform.system() == 'Windows':
|
||||||
|
import ctypes
|
||||||
|
kernel32 = ctypes.windll.kernel32
|
||||||
|
kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7)
|
||||||
|
|
||||||
|
|
||||||
|
class ColoredFormatter(logging.Formatter):
|
||||||
|
"""
|
||||||
|
自定义的日志格式化器,添加颜色支持
|
||||||
|
"""
|
||||||
|
def format(self, record):
|
||||||
|
# 获取对应级别的颜色代码
|
||||||
|
color = COLORS.get(record.levelname, '')
|
||||||
|
# 添加颜色代码和重置代码
|
||||||
|
record.levelname = f"{color}{record.levelname}\033[0m"
|
||||||
|
return super().format(record)
|
||||||
|
|
||||||
|
# 日志格式
|
||||||
|
FORMATTER = ColoredFormatter(
|
||||||
|
"%(asctime)s - %(name)s - %(levelname)s - [%(filename)s:%(lineno)d] - %(message)s"
|
||||||
|
)
|
||||||
|
|
||||||
|
# 日志级别映射
|
||||||
|
LOG_LEVELS = {
|
||||||
|
"debug": logging.DEBUG,
|
||||||
|
"info": logging.INFO,
|
||||||
|
"warning": logging.WARNING,
|
||||||
|
"error": logging.ERROR,
|
||||||
|
"critical": logging.CRITICAL,
|
||||||
|
}
|
||||||
|
|
||||||
|
class Logger:
|
||||||
|
_loggers: Dict[str, logging.Logger] = {}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def setup_logger(
|
||||||
|
name: str,
|
||||||
|
level: str = "info",
|
||||||
|
) -> logging.Logger:
|
||||||
|
"""
|
||||||
|
设置并获取logger
|
||||||
|
:param name: logger名称
|
||||||
|
:param level: 日志级别
|
||||||
|
:return: logger实例
|
||||||
|
"""
|
||||||
|
if name in Logger._loggers:
|
||||||
|
return Logger._loggers[name]
|
||||||
|
|
||||||
|
logger = logging.getLogger(name)
|
||||||
|
logger.setLevel(LOG_LEVELS.get(level.lower(), logging.INFO))
|
||||||
|
logger.propagate = False
|
||||||
|
|
||||||
|
# 添加控制台输出
|
||||||
|
console_handler = logging.StreamHandler(sys.stdout)
|
||||||
|
console_handler.setFormatter(FORMATTER)
|
||||||
|
logger.addHandler(console_handler)
|
||||||
|
|
||||||
|
Logger._loggers[name] = logger
|
||||||
|
return logger
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_logger(name: str) -> Optional[logging.Logger]:
|
||||||
|
"""
|
||||||
|
获取已存在的logger
|
||||||
|
:param name: logger名称
|
||||||
|
:return: logger实例或None
|
||||||
|
"""
|
||||||
|
return Logger._loggers.get(name)
|
||||||
|
|
||||||
|
# 预定义的loggers
|
||||||
|
def get_api_logger():
|
||||||
|
return Logger.setup_logger("api")
|
||||||
|
|
||||||
|
def get_chat_logger():
|
||||||
|
return Logger.setup_logger("chat")
|
||||||
|
|
||||||
|
def get_model_logger():
|
||||||
|
return Logger.setup_logger("model")
|
||||||
|
|
||||||
|
def get_security_logger():
|
||||||
|
return Logger.setup_logger("security")
|
||||||
|
|
||||||
|
def get_key_manager_logger():
|
||||||
|
return Logger.setup_logger("key_manager")
|
||||||
|
|
||||||
|
def get_main_logger():
|
||||||
|
return Logger.setup_logger("main")
|
||||||
|
|
||||||
|
def get_embeddings_logger():
|
||||||
|
return Logger.setup_logger("embeddings")
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
from fastapi import HTTPException, Header
|
from fastapi import HTTPException, Header
|
||||||
import logging
|
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
from app.core.logger import get_security_logger
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = get_security_logger()
|
||||||
|
|
||||||
|
|
||||||
class SecurityService:
|
class SecurityService:
|
||||||
|
|||||||
+2
-5
@@ -1,15 +1,12 @@
|
|||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
import logging
|
from app.core.logger import get_main_logger
|
||||||
|
|
||||||
from app.api.routes import router
|
from app.api.routes import router
|
||||||
import uvicorn
|
import uvicorn
|
||||||
|
|
||||||
# 配置日志
|
# 配置日志
|
||||||
logging.basicConfig(
|
logger = get_main_logger()
|
||||||
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
|
|
||||||
)
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
app = FastAPI()
|
app = FastAPI()
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ import httpx
|
|||||||
import json
|
import json
|
||||||
import time
|
import time
|
||||||
import uuid
|
import uuid
|
||||||
import logging
|
|
||||||
from typing import Dict, Any, Optional, AsyncGenerator, Union
|
from typing import Dict, Any, Optional, AsyncGenerator, Union
|
||||||
import openai
|
import openai
|
||||||
from app.core.config import settings
|
from app.core.config import settings
|
||||||
|
from app.core.logger import get_chat_logger
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = get_chat_logger()
|
||||||
|
|
||||||
|
|
||||||
class ChatService:
|
class ChatService:
|
||||||
@@ -170,6 +170,9 @@ class ChatService:
|
|||||||
gemini_model = model
|
gemini_model = model
|
||||||
gemini_messages = self.convert_messages_to_gemini_format(messages)
|
gemini_messages = self.convert_messages_to_gemini_format(messages)
|
||||||
|
|
||||||
|
if not stream:
|
||||||
|
# 非流式模式下,移除代码执行工具
|
||||||
|
tools.remove({"code_execution": {}})
|
||||||
payload = {
|
payload = {
|
||||||
"contents": gemini_messages,
|
"contents": gemini_messages,
|
||||||
"generationConfig": {"temperature": temperature},
|
"generationConfig": {"temperature": temperature},
|
||||||
@@ -241,7 +244,9 @@ class ChatService:
|
|||||||
url = f"https://generativelanguage.googleapis.com/v1beta/models/{gemini_model}:generateContent?key={api_key}"
|
url = f"https://generativelanguage.googleapis.com/v1beta/models/{gemini_model}:generateContent?key={api_key}"
|
||||||
response = await client.post(url, json=payload)
|
response = await client.post(url, json=payload)
|
||||||
if response.status_code != 200:
|
if response.status_code != 200:
|
||||||
raise Exception(f"API error: {response.status_code}")
|
error_text = response.text
|
||||||
|
error_code = response.status_code
|
||||||
|
raise Exception(f"API调用错误 - 状态码: {error_code}, 响应内容: {error_text}")
|
||||||
gemini_response = response.json()
|
gemini_response = response.json()
|
||||||
return self.convert_gemini_response_to_openai(gemini_response, model, finish_reason="stop")
|
return self.convert_gemini_response_to_openai(gemini_response, model, finish_reason="stop")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -287,10 +292,10 @@ class ChatService:
|
|||||||
language = code_data.get("language", "").lower()
|
language = code_data.get("language", "").lower()
|
||||||
code = code_data.get("code", "").strip()
|
code = code_data.get("code", "").strip()
|
||||||
|
|
||||||
return f"""\n```{language}\n{code}\n```\n"""
|
return f"""\n【代码执行】\n```{language}\n{code}\n```\n"""
|
||||||
|
|
||||||
def format_execution_result(self, result_data: dict) -> str:
|
def format_execution_result(self, result_data: dict) -> str:
|
||||||
"""格式化执行结果输出"""
|
"""格式化执行结果输出"""
|
||||||
outcome = result_data.get("outcome", "")
|
outcome = result_data.get("outcome", "")
|
||||||
output = result_data.get("output", "").strip()
|
output = result_data.get("output", "").strip()
|
||||||
return f"""\n【执行结果】\noutcome: {outcome}\noutput: {output}\n"""
|
return f"""\n【执行结果】\noutcome: {outcome}\noutput:\n```{output}```\n"""
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import logging
|
|
||||||
import openai
|
import openai
|
||||||
from typing import Union, List, Dict, Any
|
from typing import Union, List, Dict, Any
|
||||||
|
from app.core.logger import get_embeddings_logger
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = get_embeddings_logger()
|
||||||
|
|
||||||
|
|
||||||
class EmbeddingService:
|
class EmbeddingService:
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
from itertools import cycle
|
from itertools import cycle
|
||||||
import logging
|
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
from app.core.logger import get_key_manager_logger
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = get_key_manager_logger()
|
||||||
|
|
||||||
|
|
||||||
class KeyManager:
|
class KeyManager:
|
||||||
@@ -42,7 +42,7 @@ class KeyManager:
|
|||||||
|
|
||||||
current_key = await self.get_next_key()
|
current_key = await self.get_next_key()
|
||||||
if current_key == initial_key:
|
if current_key == initial_key:
|
||||||
await self.reset_failure_counts()
|
# await self.reset_failure_counts() 取消重置
|
||||||
return current_key
|
return current_key
|
||||||
|
|
||||||
async def handle_api_failure(self, api_key: str) -> str:
|
async def handle_api_failure(self, api_key: str) -> str:
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import requests
|
import requests
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from typing import Optional, Dict, Any
|
from typing import Optional, Dict, Any
|
||||||
import logging
|
from app.core.logger import get_model_logger
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = get_model_logger()
|
||||||
|
|
||||||
|
|
||||||
class ModelService:
|
class ModelService:
|
||||||
|
|||||||
Reference in New Issue
Block a user