various fixes

This commit is contained in:
Kevin
2026-03-23 13:21:07 +08:00
parent 9c2e0329ca
commit b9ecfd02a4
18 changed files with 393 additions and 277 deletions

View File

@@ -1,6 +1,10 @@
"""
统一配置:所有环境变量通过此模块的 Settings 单点读取。
业务代码只允许 import settings禁止散落 os.getenv() / load_dotenv()。
本地开发时由 api/development.sh 在启动前将 .env.development 复制为 .env若尚无 .env
Docker / 服务端由镜像与 compose 注入进程环境;此处仅固定读取工作目录下的 .env 作为默认值来源。
进程环境变量(容器 environment、export覆盖 .env 同名项。
"""
import secrets
@@ -54,10 +58,9 @@ class Settings(BaseSettings):
tencent_sms_template_id: str = ""
tencent_sms_template_param_count: int = 2
# ── Tencent ASR ──────────────────────────────────────────
# ── Tencent ASR / TTS共用 Secret与短信、COS 密钥独立)────────────────
tencent_secret_id: str = ""
tencent_secret_key: str = ""
tencent_asr_app_id: str = ""
# ── TTS (openai | tencent),与 ASR 独立:仅控制回复侧语音合成 ──
enable_tts: bool = True
@@ -94,15 +97,11 @@ class Settings(BaseSettings):
enable_test_subscription: int = 0
enable_test_plan: str = "" # "1" / "true" / "yes" 为 True
enable_docs: bool = True
migration_database_url: str = "" # 脚本迁移用,空则用 database_url
# ── Memoir Image ─────────────────────────────────────────
memoir_image_enabled: bool = False
memoir_image_max_per_chapter: int = 2
memoir_image_poll_interval: int = 3
memoir_image_max_attempts: int = 20
memoir_image_chars_per_extra: int = 1500
memoir_image_max_cap: int = 8
memoir_image_provider: str = "liblib"
memoir_image_style_default: str = "watercolor"
memoir_image_size_default: str = "1280x720"

View File

@@ -5,9 +5,6 @@ if TYPE_CHECKING:
from app.core.config import Settings
DEFAULT_LIBLIB_TEMPLATE_UUID = "5d7e67009b344550bc1aa6ccbfa1d7f4"
DEFAULT_MAX_IMAGES_PER_CHAPTER = 2
DEFAULT_CHARS_PER_EXTRA_IMAGE = 1500
DEFAULT_MAX_IMAGES_CAP = 8
DEFAULT_IMAGE_PROVIDER = "liblib"
DEFAULT_IMAGE_STYLE = "watercolor"
DEFAULT_IMAGE_SIZE = "1280x720"
@@ -18,9 +15,6 @@ DEFAULT_MAX_ATTEMPTS = 60
@dataclass(frozen=True)
class MemoirImageSettings:
enabled: bool = False
max_per_chapter: int = DEFAULT_MAX_IMAGES_PER_CHAPTER
chars_per_extra_image: int = DEFAULT_CHARS_PER_EXTRA_IMAGE
max_images_cap: int = DEFAULT_MAX_IMAGES_CAP
provider: str = DEFAULT_IMAGE_PROVIDER
default_style: str = DEFAULT_IMAGE_STYLE
default_size: str = DEFAULT_IMAGE_SIZE
@@ -33,9 +27,6 @@ class MemoirImageSettings:
s = settings
return cls(
enabled=bool(s.memoir_image_enabled),
max_per_chapter=s.memoir_image_max_per_chapter,
chars_per_extra_image=s.memoir_image_chars_per_extra,
max_images_cap=s.memoir_image_max_cap,
provider=s.memoir_image_provider or DEFAULT_IMAGE_PROVIDER,
default_style=s.memoir_image_style_default or DEFAULT_IMAGE_STYLE,
default_size=s.memoir_image_size_default or DEFAULT_IMAGE_SIZE,
@@ -49,15 +40,3 @@ class MemoirImageSettings:
from app.core.config import settings as _s
return cls.from_settings(_s)
def effective_max_images(self, content_length: int) -> int:
"""根据正文字数动态计算单章允许的最大图片数。"""
base_max = max(self.max_per_chapter, 0)
effective_cap = max(self.max_images_cap, base_max)
safe_length = max(content_length, 0)
extra = (
safe_length // self.chars_per_extra_image
if self.chars_per_extra_image > 0
else 0
)
return min(base_max + extra, effective_cap)

View File

@@ -181,34 +181,6 @@ def _memoir_image_from_asset(
)
def _select_placeholders_for_effective_max(
placeholders: list[dict],
existing_images: list[dict] | None,
effective_max: int,
) -> list[dict]:
existing_placeholders = {
item.get("placeholder")
for item in normalize_image_assets(existing_images)
if item.get("placeholder")
}
existing_count_in_content = sum(
1 for item in placeholders if item.get("placeholder") in existing_placeholders
)
remaining_new_slots = max(0, effective_max - existing_count_in_content)
selected: list[dict] = []
for item in placeholders:
if item.get("placeholder") in existing_placeholders:
selected.append(item)
continue
if remaining_new_slots <= 0:
continue
selected.append(item)
remaining_new_slots -= 1
return [{**item, "index": index} for index, item in enumerate(selected)]
def _coerce_state(model: MemoirState) -> MemoirStateSchema:
"""将数据库模型转换为 Schema"""
return MemoirStateSchema.model_validate(