初始化提交

This commit is contained in:
2025-12-14 15:40:49 +08:00
commit 410b2f068d
72 changed files with 10460 additions and 0 deletions

View File

@@ -0,0 +1,16 @@
# DeepSeek 模型配置
import os
# 价格配置 (CNY per 1M tokens)
TOKEN_PRICE_INPUT = 400.0 / 1000000 # 4元 / 1M tokens
TOKEN_PRICE_OUTPUT = 1600.0 / 1000000 # 16元 / 1M tokens
# 最低余额要求
MIN_BALANCE = 0.01
# API 配置 (优先从环境变量获取)
def get_config():
return {
'api_url': os.getenv('DEEPSEEK_API_URL', 'https://api.deepseek.com'),
'api_key': os.getenv('DEEPSEEK_API_KEY')
}

View File

@@ -0,0 +1,54 @@
from ..base import ModelService
from .config import TOKEN_PRICE_INPUT, TOKEN_PRICE_OUTPUT, MIN_BALANCE, get_config
from typing import Dict, Any, Tuple, Generator, Union
import json
import logging
logger = logging.getLogger(__name__)
class DeepSeekService(ModelService):
def get_api_config(self) -> Tuple[str, str]:
config = get_config()
return config['api_url'], config['api_key']
def check_balance(self, balance: float) -> Tuple[bool, float, str]:
if balance < MIN_BALANCE:
return False, MIN_BALANCE, f'余额不足。当前余额: {balance}, 需要至少: {MIN_BALANCE}'
return True, 0.0, ""
def calculate_cost(self, usage: Dict[str, Any] = None, stream: bool = False) -> float:
if not usage:
return 0.0
prompt_tokens = usage.get('prompt_tokens', 0)
completion_tokens = usage.get('completion_tokens', 0)
cost = (prompt_tokens * TOKEN_PRICE_INPUT) + (completion_tokens * TOKEN_PRICE_OUTPUT)
return cost
def prepare_payload(self, data: Dict[str, Any]) -> Dict[str, Any]:
payload = {k: v for k, v in data.items() if k not in ['user']}
# 强制 DeepSeek 返回 usage
if data.get('stream', False):
if 'stream_options' not in payload:
payload['stream_options'] = {"include_usage": True}
return payload
def handle_response(self, response, stream: bool) -> Union[Dict[str, Any], Generator]:
# Response handling is mostly done in the route handler for stream/json split
# but we can provide helper methods to parse usage
pass
@staticmethod
def parse_stream_usage(chunk_text: str) -> Dict[str, Any]:
"""解析流式响应中的 usage"""
try:
for line in chunk_text.split('\n'):
if line.startswith('data: ') and line != 'data: [DONE]':
json_str = line[6:]
data_obj = json.loads(json_str)
if 'usage' in data_obj and data_obj['usage']:
return data_obj['usage']
except Exception:
pass
return None

View File

@@ -0,0 +1,12 @@
# Nano Banana 模型配置
import os
# 价格配置 (CNY per call)
IMAGE_GENERATION_PRICE = float(os.getenv('IMAGE_GENERATION_PRICE', 0.15))
# API 配置 (优先从环境变量获取)
def get_config():
return {
'api_url': os.getenv('NANO_BANANA_API_URL', 'https://api.nanobanana.com/v1'),
'api_key': os.getenv('NANO_BANANA_API_KEY')
}

View File

@@ -0,0 +1,26 @@
from ..base import ModelService
from .config import IMAGE_GENERATION_PRICE, get_config
from typing import Dict, Any, Tuple, Generator, Union
import logging
logger = logging.getLogger(__name__)
class NanoBananaService(ModelService):
def get_api_config(self) -> Tuple[str, str]:
config = get_config()
return config['api_url'], config['api_key']
def check_balance(self, balance: float) -> Tuple[bool, float, str]:
if balance < IMAGE_GENERATION_PRICE:
return False, IMAGE_GENERATION_PRICE, f'余额不足。当前余额: {balance}, 需要: {IMAGE_GENERATION_PRICE}'
return True, IMAGE_GENERATION_PRICE, ""
def calculate_cost(self, usage: Dict[str, Any] = None, stream: bool = False) -> float:
# 固定按次计费
return IMAGE_GENERATION_PRICE
def prepare_payload(self, data: Dict[str, Any]) -> Dict[str, Any]:
return {k: v for k, v in data.items() if k not in ['user']}
def handle_response(self, response, stream: bool) -> Union[Dict[str, Any], Generator]:
pass

View File

@@ -0,0 +1,10 @@
from .DeepSeek.service import DeepSeekService
from .NanoBanana.service import NanoBananaService
def get_model_service(model_name: str):
"""根据模型名称获取对应的服务实例"""
if model_name.startswith('deepseek-'):
return DeepSeekService()
else:
# 默认使用 Nano Banana 服务 (包括文生图等)
return NanoBananaService()

View File

@@ -0,0 +1,33 @@
from abc import ABC, abstractmethod
from typing import Dict, Any, Generator, Union, Tuple
import requests
class ModelService(ABC):
"""大模型服务基类"""
@abstractmethod
def get_api_config(self) -> Tuple[str, str]:
"""获取 API URL 和 Key"""
pass
@abstractmethod
def calculate_cost(self, usage: Dict[str, Any] = None, stream: bool = False) -> float:
"""计算费用"""
pass
@abstractmethod
def check_balance(self, balance: float) -> Tuple[bool, float, str]:
"""检查余额是否充足
Returns: (is_sufficient, estimated_cost, error_message)
"""
pass
@abstractmethod
def prepare_payload(self, data: Dict[str, Any]) -> Dict[str, Any]:
"""准备请求载荷"""
pass
@abstractmethod
def handle_response(self, response: requests.Response, stream: bool) -> Union[Dict[str, Any], Generator]:
"""处理响应"""
pass