chore: clear lint and sync admin story views
This commit is contained in:
@@ -6,7 +6,9 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from app.core.admin_auth import admin_guard
|
||||
from app.db.admin_models import Provider
|
||||
from app.db.database import get_db
|
||||
from app.services.adapters.registry import AdapterRegistry
|
||||
from app.services.cost_tracker import cost_tracker
|
||||
from app.services.provider_router import DEFAULT_PROVIDERS
|
||||
from app.services.secret_service import SecretService
|
||||
|
||||
router = APIRouter(dependencies=[Depends(admin_guard)])
|
||||
@@ -54,11 +56,6 @@ class ProviderResponse(BaseModel):
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
from app.services.adapters.registry import AdapterRegistry
|
||||
from app.services.provider_router import DEFAULT_PROVIDERS
|
||||
|
||||
|
||||
@router.get("/providers/adapters")
|
||||
async def list_available_adapters():
|
||||
"""获取所有可用的适配器类型 (定义的类)。"""
|
||||
|
||||
@@ -266,13 +266,18 @@ async def get_profile_timeline(
|
||||
if not obt_at:
|
||||
obt_at = u.updated_at.isoformat()
|
||||
|
||||
events.append(TimelineEvent(
|
||||
date=obt_at,
|
||||
type="achievement",
|
||||
title=f"获得成就:{ach.get('type')}",
|
||||
description=ach.get('description'),
|
||||
metadata={"universe_id": u.id, "source_story_id": ach.get("source_story_id")}
|
||||
))
|
||||
events.append(
|
||||
TimelineEvent(
|
||||
date=obt_at,
|
||||
type="achievement",
|
||||
title=f"获得成就:{ach.get('type')}",
|
||||
description=ach.get("description"),
|
||||
metadata={
|
||||
"universe_id": u.id,
|
||||
"source_story_id": ach.get("source_story_id"),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
# Sort by date desc
|
||||
events.sort(key=lambda x: x.date, reverse=True)
|
||||
|
||||
@@ -45,7 +45,11 @@ class ReadingEventResponse(BaseModel):
|
||||
from_attributes = True
|
||||
|
||||
|
||||
@router.post("/reading-events", response_model=ReadingEventResponse, status_code=status.HTTP_201_CREATED)
|
||||
@router.post(
|
||||
"/reading-events",
|
||||
response_model=ReadingEventResponse,
|
||||
status_code=status.HTTP_201_CREATED,
|
||||
)
|
||||
async def create_reading_event(
|
||||
payload: ReadingEventCreate,
|
||||
user: User = Depends(require_user),
|
||||
|
||||
@@ -29,7 +29,10 @@ class Provider(Base):
|
||||
weight: Mapped[int] = mapped_column(Integer, default=1)
|
||||
priority: Mapped[int] = mapped_column(Integer, default=0)
|
||||
enabled: Mapped[bool] = mapped_column(Boolean, default=True)
|
||||
config_json: Mapped[dict | None] = mapped_column(JSON, nullable=True) # 存储额外配置(speed, vol, etc)
|
||||
config_json: Mapped[dict | None] = mapped_column(
|
||||
JSON,
|
||||
nullable=True,
|
||||
) # 存储额外配置(speed, vol, etc)
|
||||
config_ref: Mapped[str] = mapped_column(String(100), nullable=True) # 环境变量 key 名称(回退)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=datetime.utcnow)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
"""图像生成适配器。"""# Image adapters
|
||||
from app.services.adapters.image import cqtai as _image_cqtai_adapter # noqa: F401
|
||||
from app.services.adapters.image import antigravity as _image_antigravity_adapter # noqa: F401
|
||||
"""图像生成适配器。"""
|
||||
|
||||
from app.services.adapters.image import antigravity as _image_antigravity_adapter # noqa: F401
|
||||
from app.services.adapters.image import cqtai as _image_cqtai_adapter # noqa: F401
|
||||
|
||||
@@ -4,11 +4,9 @@
|
||||
支持 gemini-3-pro-image 等模型。
|
||||
"""
|
||||
|
||||
import base64
|
||||
import time
|
||||
from typing import Any
|
||||
|
||||
from openai import AsyncOpenAI
|
||||
import time
|
||||
|
||||
from openai import AsyncOpenAI
|
||||
from tenacity import (
|
||||
retry,
|
||||
retry_if_exception_type,
|
||||
@@ -105,13 +103,13 @@ class AntigravityImageAdapter(BaseAdapter[str]):
|
||||
return image_url
|
||||
|
||||
async def health_check(self) -> bool:
|
||||
"""检查 Antigravity API 是否可用。"""
|
||||
try:
|
||||
# 简单测试连通性
|
||||
response = await self.client.chat.completions.create(
|
||||
model=self.config.model or DEFAULT_MODEL,
|
||||
messages=[{"role": "user", "content": "test"}],
|
||||
max_tokens=1,
|
||||
"""检查 Antigravity API 是否可用。"""
|
||||
try:
|
||||
# 简单测试连通性
|
||||
await self.client.chat.completions.create(
|
||||
model=self.config.model or DEFAULT_MODEL,
|
||||
messages=[{"role": "user", "content": "test"}],
|
||||
max_tokens=1,
|
||||
)
|
||||
return True
|
||||
except Exception as e:
|
||||
|
||||
@@ -98,10 +98,14 @@ async def build_enhanced_memory_context(
|
||||
p_desc = f"{protagonist.get('name', '主角')} ({protagonist.get('personality', '')})"
|
||||
context_parts.append(f"主角设定:{p_desc}")
|
||||
|
||||
# 常驻角色
|
||||
if universe.recurring_characters:
|
||||
chars = [f"{c.get('name')} ({c.get('type')})" for c in universe.recurring_characters if isinstance(c, dict)]
|
||||
context_parts.append(f"已知伙伴:{'、'.join(chars)}")
|
||||
# 常驻角色
|
||||
if universe.recurring_characters:
|
||||
chars = [
|
||||
f"{c.get('name')} ({c.get('type')})"
|
||||
for c in universe.recurring_characters
|
||||
if isinstance(c, dict)
|
||||
]
|
||||
context_parts.append(f"已知伙伴:{'、'.join(chars)}")
|
||||
|
||||
# 成就
|
||||
if universe.achievements:
|
||||
|
||||
@@ -17,9 +17,10 @@ logger = get_logger(__name__)
|
||||
ProviderType = Literal["text", "image", "tts", "storybook"]
|
||||
|
||||
|
||||
class CachedProvider(BaseModel):
|
||||
"""Serializable provider configuration matching DB model fields."""
|
||||
id: str
|
||||
class CachedProvider(BaseModel):
|
||||
"""Serializable provider configuration matching DB model fields."""
|
||||
|
||||
id: str
|
||||
name: str
|
||||
type: str
|
||||
adapter: str
|
||||
@@ -43,28 +44,30 @@ CACHE_KEY = "dreamweaver:providers:config"
|
||||
async def reload_providers(db: AsyncSession) -> dict[ProviderType, list[CachedProvider]]:
|
||||
"""Reload providers from DB and update Redis cache."""
|
||||
try:
|
||||
result = await db.execute(select(Provider).where(Provider.enabled == True)) # noqa: E712
|
||||
providers = result.scalars().all()
|
||||
|
||||
# Convert to Pydantic models
|
||||
cached_list = []
|
||||
for p in providers:
|
||||
cached_list.append(CachedProvider(
|
||||
id=p.id,
|
||||
name=p.name,
|
||||
type=p.type,
|
||||
adapter=p.adapter,
|
||||
model=p.model,
|
||||
api_base=p.api_base,
|
||||
api_key=p.api_key,
|
||||
timeout_ms=p.timeout_ms,
|
||||
max_retries=p.max_retries,
|
||||
weight=p.weight,
|
||||
priority=p.priority,
|
||||
enabled=p.enabled,
|
||||
config_json=p.config_json,
|
||||
config_ref=p.config_ref
|
||||
))
|
||||
result = await db.execute(select(Provider).where(Provider.enabled == True)) # noqa: E712
|
||||
providers = result.scalars().all()
|
||||
|
||||
# Convert to Pydantic models
|
||||
cached_list = []
|
||||
for p in providers:
|
||||
cached_list.append(
|
||||
CachedProvider(
|
||||
id=p.id,
|
||||
name=p.name,
|
||||
type=p.type,
|
||||
adapter=p.adapter,
|
||||
model=p.model,
|
||||
api_base=p.api_base,
|
||||
api_key=p.api_key,
|
||||
timeout_ms=p.timeout_ms,
|
||||
max_retries=p.max_retries,
|
||||
weight=p.weight,
|
||||
priority=p.priority,
|
||||
enabled=p.enabled,
|
||||
config_json=p.config_json,
|
||||
config_ref=p.config_ref,
|
||||
)
|
||||
)
|
||||
|
||||
# Group by type
|
||||
grouped: dict[str, list[CachedProvider]] = defaultdict(list)
|
||||
@@ -77,19 +80,19 @@ async def reload_providers(db: AsyncSession) -> dict[ProviderType, list[CachedPr
|
||||
|
||||
# Update Redis
|
||||
redis = await get_redis()
|
||||
# Serialize entire dict structure
|
||||
# Pydantic -> dict -> json
|
||||
json_data = {k: [p.model_dump() for p in v] for k, v in grouped.items()}
|
||||
await redis.set(CACHE_KEY, json.dumps(json_data))
|
||||
|
||||
# Update local cache
|
||||
_local_cache.clear()
|
||||
_local_cache.update(grouped)
|
||||
return grouped
|
||||
|
||||
except Exception as e:
|
||||
logger.error("failed_to_reload_providers", error=str(e))
|
||||
raise
|
||||
# Serialize entire dict structure
|
||||
# Pydantic -> dict -> json
|
||||
json_data = {k: [p.model_dump() for p in v] for k, v in grouped.items()}
|
||||
await redis.set(CACHE_KEY, json.dumps(json_data))
|
||||
|
||||
# Update local cache
|
||||
_local_cache.clear()
|
||||
_local_cache.update(grouped)
|
||||
return grouped
|
||||
|
||||
except Exception as e:
|
||||
logger.error("failed_to_reload_providers", error=str(e))
|
||||
raise
|
||||
|
||||
|
||||
async def get_providers(provider_type: ProviderType) -> list[CachedProvider]:
|
||||
@@ -102,8 +105,8 @@ async def get_providers(provider_type: ProviderType) -> list[CachedProvider]:
|
||||
if provider_type in raw_dict:
|
||||
return [CachedProvider(**item) for item in raw_dict[provider_type]]
|
||||
return []
|
||||
except Exception as e:
|
||||
logger.warning("redis_cache_read_failed", error=str(e))
|
||||
|
||||
# Fallback to local memory
|
||||
return _local_cache.get(provider_type, [])
|
||||
except Exception as e:
|
||||
logger.warning("redis_cache_read_failed", error=str(e))
|
||||
|
||||
# Fallback to local memory
|
||||
return _local_cache.get(provider_type, [])
|
||||
|
||||
Reference in New Issue
Block a user