feat(comfy-cloud): /history 轮询翻译(status+jobs→history)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -47,12 +47,40 @@ async fn submit_prompt(
|
|||||||
Ok(Json(value))
|
Ok(Json(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn fetch_history(db: &sqlx::SqlitePool, prompt_id: &str) -> AppResult<Value> {
|
||||||
|
let (base_url, api_key) = resolve_comfy_cloud_site(db).await?;
|
||||||
|
let http = client();
|
||||||
|
let status_resp = http
|
||||||
|
.get(format!("{base_url}/api/job/{prompt_id}/status"))
|
||||||
|
.header("X-API-Key", &api_key)
|
||||||
|
.send().await
|
||||||
|
.map_err(|e| AppError::UpstreamError(e.to_string()))?;
|
||||||
|
if !status_resp.status().is_success() {
|
||||||
|
let st = status_resp.status();
|
||||||
|
let body = status_resp.text().await.unwrap_or_default();
|
||||||
|
return Err(AppError::UpstreamError(format!("Comfy Cloud status [{st}]: {body}")));
|
||||||
|
}
|
||||||
|
let status_json: Value = status_resp.json().await.map_err(|e| AppError::UpstreamError(e.to_string()))?;
|
||||||
|
let status = status_json.get("status").and_then(Value::as_str).unwrap_or("in_progress");
|
||||||
|
|
||||||
|
if status != "completed" {
|
||||||
|
return Ok(comfy_cloud_job_to_history(prompt_id, status, None));
|
||||||
|
}
|
||||||
|
let detail_resp = http
|
||||||
|
.get(format!("{base_url}/api/jobs/{prompt_id}"))
|
||||||
|
.header("X-API-Key", &api_key)
|
||||||
|
.send().await
|
||||||
|
.map_err(|e| AppError::UpstreamError(e.to_string()))?;
|
||||||
|
let detail_json: Value = detail_resp.json().await.map_err(|e| AppError::UpstreamError(e.to_string()))?;
|
||||||
|
let outputs = detail_json.get("outputs");
|
||||||
|
Ok(comfy_cloud_job_to_history(prompt_id, status, outputs))
|
||||||
|
}
|
||||||
|
|
||||||
async fn get_history(
|
async fn get_history(
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
Path(prompt_id): Path<String>,
|
Path(prompt_id): Path<String>,
|
||||||
) -> AppResult<Json<Value>> {
|
) -> AppResult<Json<Value>> {
|
||||||
let _ = (&state, &prompt_id);
|
Ok(Json(fetch_history(&state.db, &prompt_id).await?))
|
||||||
Ok(Json(serde_json::json!({})))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_view(
|
async fn get_view(
|
||||||
@@ -98,4 +126,25 @@ mod tests {
|
|||||||
let v: Value = resp.json().await.unwrap();
|
let v: Value = resp.json().await.unwrap();
|
||||||
assert_eq!(v["prompt_id"], "p1");
|
assert_eq!(v["prompt_id"], "p1");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn history_in_progress_then_completed() {
|
||||||
|
let server = MockServer::start().await;
|
||||||
|
Mock::given(method("GET"))
|
||||||
|
.and(path("/api/job/p1/status"))
|
||||||
|
.and(match_header("X-API-Key", "key-123"))
|
||||||
|
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({ "status": "completed" })))
|
||||||
|
.mount(&server).await;
|
||||||
|
Mock::given(method("GET"))
|
||||||
|
.and(path("/api/jobs/p1"))
|
||||||
|
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
|
||||||
|
"outputs": { "9": { "images": [{ "filename": "a.png", "subfolder": "", "type": "output" }] } }
|
||||||
|
})))
|
||||||
|
.mount(&server).await;
|
||||||
|
|
||||||
|
let pool = db_with_site(&server.uri()).await;
|
||||||
|
let history = fetch_history(&pool, "p1").await.unwrap();
|
||||||
|
assert_eq!(history["p1"]["status"]["completed"], true);
|
||||||
|
assert_eq!(history["p1"]["outputs"]["9"]["images"][0]["filename"], "a.png");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user