修复动作提示缓存缺失降级
角色资产工作流解析在 OSS 缓存未配置时返回默认提示词 补充无 OSS 缓存的 workflow 路由回归测试 同步后端契约文档说明
This commit is contained in:
@@ -60,7 +60,7 @@ npm run check:server-rs-ddd
|
||||
- 平台基础能力:`/api/llm/*`、`/api/speech/volcengine/*`,只保留通用 LLM 和语音代理。
|
||||
- 资产基础能力:`/api/assets/direct-upload-tickets`、`/api/assets/sts-upload-credentials`、`/api/assets/objects/*`、`/api/assets/read-*`,负责直传、确认、绑定和读取。
|
||||
- 外部 OpenAPI:`/api/external/v1/openapi.json`、`/api/external/v1/assets/direct-upload-tickets`、`/api/external/v1/assets/objects/confirm`、`/api/external/v1/assets/read-url`、`/api/external/v1/editor/*`,使用 Bearer API Key 鉴权;API Key 管理仍在登录态 `/api/profile/api-keys`,不进入外部 OpenAPI JSON。
|
||||
- 创作 / 游玩支撑能力:`/api/creation-entry/config`、`/api/ai/tasks*`、`/api/runtime/chat/*`、`/api/runtime/settings`、`/api/runtime/save/snapshot`、`/api/profile/browse-history`、`/api/profile/save-archives*`、`/api/profile/play-stats`、`/api/assets/history`、`/api/assets/character-visual/*`、`/api/assets/character-animation/*`、`/api/assets/character-workflow-cache*`、`/api/assets/hyper3d/*`、`/api/runtime/custom-world/asset-studio/*`、`/api/editor/projects*`。
|
||||
- 创作 / 游玩支撑能力:`/api/creation-entry/config`、`/api/ai/tasks*`、`/api/runtime/chat/*`、`/api/runtime/settings`、`/api/runtime/save/snapshot`、`/api/profile/browse-history`、`/api/profile/save-archives*`、`/api/profile/play-stats`、`/api/assets/history`、`/api/assets/character-visual/*`、`/api/assets/character-animation/*`、`/api/assets/character-workflow-cache*`、`/api/assets/hyper3d/*`、`/api/runtime/custom-world/asset-studio/*`、`/api/editor/projects*`。`/api/runtime/custom-world/asset-studio/*` 解析默认角色形象 / 动作提示词时可以在 OSS 缓存不可用或未配置时按无缓存返回默认提示;保存 workflow 缓存和真实素材读写仍必须要求 OSS 正常可用。
|
||||
- 后台入口配置:`/admin/api/creation-entry/config`、`/admin/api/creation-entry/config/banners` 和 `/admin/api/creation-entry/config/interactions`。
|
||||
- 自定义世界 / RPG:`/api/runtime/custom-world*`、`/api/story/*`、`/api/runtime/chat/*`。
|
||||
- 拼图:`/api/runtime/puzzle/*`。
|
||||
|
||||
@@ -690,6 +690,45 @@ mod tests {
|
||||
assert_eq!(body["error"]["details"]["creationTypeId"], "rpg");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn role_asset_workflow_returns_default_prompts_without_oss_cache() {
|
||||
let app = build_router(AppState::new(AppConfig::default()).expect("state should build"));
|
||||
|
||||
let response = app
|
||||
.oneshot(
|
||||
Request::builder()
|
||||
.method("POST")
|
||||
.uri("/api/runtime/custom-world/asset-studio/role/hero-01/workflow")
|
||||
.header("content-type", "application/json")
|
||||
.body(Body::from(
|
||||
serde_json::json!({
|
||||
"role": {
|
||||
"id": "hero-01",
|
||||
"name": "沈砺",
|
||||
"title": "灰炬向导",
|
||||
"role": "边路同行者",
|
||||
"actionDescription": "持灯快步穿过灰烬街巷"
|
||||
}
|
||||
})
|
||||
.to_string(),
|
||||
))
|
||||
.expect("workflow request should build"),
|
||||
)
|
||||
.await
|
||||
.expect("workflow request should succeed");
|
||||
|
||||
assert_eq!(response.status(), StatusCode::OK);
|
||||
let body = read_json_response(response).await;
|
||||
assert_eq!(body["ok"], Value::Bool(true));
|
||||
assert_eq!(body["cache"], Value::Null);
|
||||
assert!(
|
||||
body["workflow"]["animationPromptText"]
|
||||
.as_str()
|
||||
.unwrap_or_default()
|
||||
.contains("持灯快步穿过灰烬街巷")
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn healthz_returns_standard_envelope_when_requested() {
|
||||
let app = build_router(AppState::new(AppConfig::default()).expect("state should build"));
|
||||
|
||||
@@ -1124,9 +1124,13 @@ pub async fn resolve_role_asset_workflow(
|
||||
})?;
|
||||
|
||||
let cache_scope_id = trim_optional_text(payload.cache_scope_id.as_deref());
|
||||
let cache = load_workflow_cache(&state, character_id.as_str(), cache_scope_id.as_deref())
|
||||
let cache = match load_workflow_cache(&state, character_id.as_str(), cache_scope_id.as_deref())
|
||||
.await
|
||||
.map_err(|error| character_animation_error_response(&request_context, error))?;
|
||||
{
|
||||
Ok(cache) => cache,
|
||||
Err(error) if is_missing_oss_config_error(&error) => None,
|
||||
Err(error) => return Err(character_animation_error_response(&request_context, error)),
|
||||
};
|
||||
let workflow = build_role_asset_workflow(payload.role, cache.as_ref());
|
||||
|
||||
Ok(json_success_body(
|
||||
@@ -4133,6 +4137,14 @@ fn require_oss_client(state: &AppState) -> Result<&platform_oss::OssClient, AppE
|
||||
})
|
||||
}
|
||||
|
||||
fn is_missing_oss_config_error(error: &AppError) -> bool {
|
||||
error.status_code() == StatusCode::SERVICE_UNAVAILABLE
|
||||
&& error.details().is_some_and(|details| {
|
||||
details.get("provider").and_then(Value::as_str) == Some("aliyun-oss")
|
||||
&& details.get("reason").and_then(Value::as_str) == Some("OSS 未完成环境变量配置")
|
||||
})
|
||||
}
|
||||
|
||||
fn normalize_required_text(value: &str, fallback: &str) -> String {
|
||||
let normalized = value
|
||||
.trim()
|
||||
|
||||
Reference in New Issue
Block a user