refactor: modularize api server assets and handlers
This commit is contained in:
110
server-rs/crates/api-server/src/modules/admin.rs
Normal file
110
server-rs/crates/api-server/src/modules/admin.rs
Normal file
@@ -0,0 +1,110 @@
|
||||
use axum::{Router, middleware, routing::get};
|
||||
|
||||
use crate::{
|
||||
admin::{
|
||||
admin_debug_http, admin_get_creation_entry_config, admin_list_database_table_rows,
|
||||
admin_list_database_tables, admin_list_tracking_events, admin_login, admin_me,
|
||||
admin_overview, admin_upsert_creation_entry_config, require_admin_auth,
|
||||
},
|
||||
runtime_profile::{
|
||||
admin_disable_profile_redeem_code, admin_disable_profile_task_config,
|
||||
admin_list_profile_invite_codes, admin_list_profile_redeem_codes,
|
||||
admin_list_profile_task_configs, admin_upsert_profile_invite_code,
|
||||
admin_upsert_profile_redeem_code, admin_upsert_profile_task_config,
|
||||
},
|
||||
state::AppState,
|
||||
};
|
||||
|
||||
pub fn router(state: AppState) -> Router<AppState> {
|
||||
Router::new()
|
||||
.route("/admin/api/login", axum::routing::post(admin_login))
|
||||
.route(
|
||||
"/admin/api/me",
|
||||
get(admin_me).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_admin_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/admin/api/overview",
|
||||
get(admin_overview).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_admin_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/admin/api/debug/http",
|
||||
axum::routing::post(admin_debug_http).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_admin_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/admin/api/tracking/events",
|
||||
get(admin_list_tracking_events).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_admin_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/admin/api/database/tables",
|
||||
get(admin_list_database_tables).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_admin_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/admin/api/database/tables/{table_name}/rows",
|
||||
get(admin_list_database_table_rows).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_admin_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/admin/api/creation-entry/config",
|
||||
get(admin_get_creation_entry_config)
|
||||
.post(admin_upsert_creation_entry_config)
|
||||
.route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_admin_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/admin/api/profile/redeem-codes",
|
||||
get(admin_list_profile_redeem_codes)
|
||||
.post(admin_upsert_profile_redeem_code)
|
||||
.route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_admin_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/admin/api/profile/redeem-codes/disable",
|
||||
axum::routing::post(admin_disable_profile_redeem_code).route_layer(
|
||||
middleware::from_fn_with_state(state.clone(), require_admin_auth),
|
||||
),
|
||||
)
|
||||
.route(
|
||||
"/admin/api/profile/invite-codes",
|
||||
get(admin_list_profile_invite_codes)
|
||||
.post(admin_upsert_profile_invite_code)
|
||||
.route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_admin_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/admin/api/profile/tasks",
|
||||
get(admin_list_profile_task_configs)
|
||||
.post(admin_upsert_profile_task_config)
|
||||
.route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_admin_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/admin/api/profile/tasks/disable",
|
||||
axum::routing::post(admin_disable_profile_task_config)
|
||||
.route_layer(middleware::from_fn_with_state(state, require_admin_auth)),
|
||||
)
|
||||
}
|
||||
54
server-rs/crates/api-server/src/modules/assets.rs
Normal file
54
server-rs/crates/api-server/src/modules/assets.rs
Normal file
@@ -0,0 +1,54 @@
|
||||
use axum::{
|
||||
Router, middleware,
|
||||
routing::{get, post},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
assets::{
|
||||
bind_asset_object_to_entity, confirm_asset_object, create_direct_upload_ticket,
|
||||
create_sts_upload_credentials, get_asset_history, get_asset_read_bytes, get_asset_read_url,
|
||||
},
|
||||
auth::require_bearer_auth,
|
||||
state::AppState,
|
||||
};
|
||||
|
||||
pub fn router(state: AppState) -> Router<AppState> {
|
||||
Router::new()
|
||||
.route(
|
||||
"/api/assets/direct-upload-tickets",
|
||||
post(create_direct_upload_ticket).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/assets/sts-upload-credentials",
|
||||
post(create_sts_upload_credentials).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/assets/objects/confirm",
|
||||
post(confirm_asset_object).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/assets/objects/bind",
|
||||
post(bind_asset_object_to_entity).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route("/api/assets/read-url", get(get_asset_read_url))
|
||||
.route("/api/assets/read-bytes", get(get_asset_read_bytes))
|
||||
.route(
|
||||
"/api/assets/history",
|
||||
get(get_asset_history).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
}
|
||||
111
server-rs/crates/api-server/src/modules/auth.rs
Normal file
111
server-rs/crates/api-server/src/modules/auth.rs
Normal file
@@ -0,0 +1,111 @@
|
||||
use axum::{
|
||||
Router, middleware,
|
||||
routing::{get, post},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
auth::{attach_refresh_session_token, require_bearer_auth},
|
||||
auth_me::auth_me,
|
||||
auth_public_user::{get_public_user_by_code, get_public_user_by_id},
|
||||
auth_sessions::{auth_sessions, revoke_auth_session},
|
||||
login_options::auth_login_options,
|
||||
logout::logout,
|
||||
logout_all::logout_all,
|
||||
password_entry::password_entry,
|
||||
password_management::{change_password, reset_password},
|
||||
phone_auth::{phone_login, send_phone_code},
|
||||
refresh_session::refresh_session,
|
||||
state::AppState,
|
||||
wechat_auth::{
|
||||
bind_wechat_phone, handle_wechat_callback, login_wechat_mini_program, start_wechat_login,
|
||||
},
|
||||
};
|
||||
|
||||
pub fn router(state: AppState) -> Router<AppState> {
|
||||
Router::new()
|
||||
.route("/api/auth/login-options", get(auth_login_options))
|
||||
.route(
|
||||
"/api/auth/public-users/by-code/{code}",
|
||||
get(get_public_user_by_code),
|
||||
)
|
||||
.route(
|
||||
"/api/auth/public-users/by-id/{user_id}",
|
||||
get(get_public_user_by_id),
|
||||
)
|
||||
.route(
|
||||
"/api/auth/me",
|
||||
get(auth_me).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/auth/sessions",
|
||||
get(auth_sessions)
|
||||
.route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
attach_refresh_session_token,
|
||||
))
|
||||
.route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/auth/sessions/{session_id}/revoke",
|
||||
post(revoke_auth_session).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/auth/refresh",
|
||||
post(refresh_session).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
attach_refresh_session_token,
|
||||
)),
|
||||
)
|
||||
.route("/api/auth/phone/send-code", post(send_phone_code))
|
||||
.route("/api/auth/phone/login", post(phone_login))
|
||||
.route("/api/auth/wechat/start", get(start_wechat_login))
|
||||
.route("/api/auth/wechat/callback", get(handle_wechat_callback))
|
||||
.route(
|
||||
"/api/auth/wechat/miniprogram-login",
|
||||
post(login_wechat_mini_program),
|
||||
)
|
||||
.route(
|
||||
"/api/auth/wechat/bind-phone",
|
||||
post(bind_wechat_phone).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route("/api/auth/entry", post(password_entry))
|
||||
.route(
|
||||
"/api/auth/password/change",
|
||||
post(change_password).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route("/api/auth/password/reset", post(reset_password))
|
||||
.route(
|
||||
"/api/auth/logout",
|
||||
post(logout)
|
||||
.route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
attach_refresh_session_token,
|
||||
))
|
||||
.route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/auth/logout-all",
|
||||
post(logout_all).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
}
|
||||
119
server-rs/crates/api-server/src/modules/big_fish.rs
Normal file
119
server-rs/crates/api-server/src/modules/big_fish.rs
Normal file
@@ -0,0 +1,119 @@
|
||||
use axum::{
|
||||
Router, middleware,
|
||||
routing::{delete, get, post},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
auth::require_bearer_auth,
|
||||
big_fish::{
|
||||
create_big_fish_session, delete_big_fish_work, execute_big_fish_action, get_big_fish_run,
|
||||
get_big_fish_session, get_big_fish_works, list_big_fish_gallery,
|
||||
record_big_fish_gallery_like, record_big_fish_play, remix_big_fish_gallery_work,
|
||||
start_big_fish_run, stream_big_fish_message, submit_big_fish_input,
|
||||
submit_big_fish_message,
|
||||
},
|
||||
state::AppState,
|
||||
};
|
||||
|
||||
pub fn router(state: AppState) -> Router<AppState> {
|
||||
Router::new()
|
||||
.route(
|
||||
"/api/runtime/big-fish/agent/sessions",
|
||||
post(create_big_fish_session).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/big-fish/agent/sessions/{session_id}",
|
||||
get(get_big_fish_session).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/big-fish/agent/sessions/{session_id}/messages",
|
||||
post(submit_big_fish_message).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/big-fish/agent/sessions/{session_id}/messages/stream",
|
||||
post(stream_big_fish_message).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/big-fish/agent/sessions/{session_id}/actions",
|
||||
post(execute_big_fish_action).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/big-fish/works",
|
||||
get(get_big_fish_works).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route("/api/runtime/big-fish/gallery", get(list_big_fish_gallery))
|
||||
.route(
|
||||
"/api/runtime/big-fish/gallery/{session_id}/remix",
|
||||
post(remix_big_fish_gallery_work).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/big-fish/gallery/{session_id}/like",
|
||||
post(record_big_fish_gallery_like).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/big-fish/works/{session_id}",
|
||||
delete(delete_big_fish_work).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/big-fish/sessions/{session_id}/play",
|
||||
post(record_big_fish_play).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/big-fish/works/{session_id}/play",
|
||||
post(record_big_fish_play).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/big-fish/sessions/{session_id}/runs",
|
||||
post(start_big_fish_run).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/big-fish/runs/{run_id}",
|
||||
get(get_big_fish_run).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/big-fish/runs/{run_id}/input",
|
||||
post(submit_big_fish_input).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
}
|
||||
208
server-rs/crates/api-server/src/modules/custom_world.rs
Normal file
208
server-rs/crates/api-server/src/modules/custom_world.rs
Normal file
@@ -0,0 +1,208 @@
|
||||
use axum::{
|
||||
Router, middleware,
|
||||
routing::{get, post},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
auth::require_bearer_auth,
|
||||
custom_world::{
|
||||
create_custom_world_agent_session, delete_custom_world_agent_session,
|
||||
delete_custom_world_library_profile, execute_custom_world_agent_action,
|
||||
generate_custom_world_profile, get_custom_world_agent_card_detail,
|
||||
get_custom_world_agent_operation, get_custom_world_agent_result_view,
|
||||
get_custom_world_agent_session, get_custom_world_gallery_detail,
|
||||
get_custom_world_gallery_detail_by_code, get_custom_world_library,
|
||||
get_custom_world_library_detail, get_custom_world_works, list_custom_world_gallery,
|
||||
publish_custom_world_library_profile, put_custom_world_library_profile,
|
||||
record_custom_world_gallery_like, record_custom_world_gallery_play,
|
||||
remix_custom_world_gallery_profile, stream_custom_world_agent_message,
|
||||
submit_custom_world_agent_message, unpublish_custom_world_library_profile,
|
||||
},
|
||||
custom_world_ai::{
|
||||
generate_custom_world_cover_image, generate_custom_world_entity,
|
||||
generate_custom_world_opening_cg, generate_custom_world_scene_image,
|
||||
generate_custom_world_scene_npc, upload_custom_world_cover_image,
|
||||
},
|
||||
state::AppState,
|
||||
};
|
||||
|
||||
pub fn router(state: AppState) -> Router<AppState> {
|
||||
Router::new()
|
||||
.route(
|
||||
"/api/runtime/custom-world-library",
|
||||
get(get_custom_world_library).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/custom-world-library/{profile_id}",
|
||||
get(get_custom_world_library_detail)
|
||||
.put(put_custom_world_library_profile)
|
||||
.delete(delete_custom_world_library_profile)
|
||||
.route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/custom-world-library/{profile_id}/publish",
|
||||
post(publish_custom_world_library_profile).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/custom-world-library/{profile_id}/unpublish",
|
||||
post(unpublish_custom_world_library_profile).route_layer(
|
||||
middleware::from_fn_with_state(state.clone(), require_bearer_auth),
|
||||
),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/custom-world-gallery",
|
||||
get(list_custom_world_gallery),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/custom-world-gallery/{owner_user_id}/{profile_id}",
|
||||
get(get_custom_world_gallery_detail),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/custom-world-gallery/{owner_user_id}/{profile_id}/remix",
|
||||
post(remix_custom_world_gallery_profile).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/custom-world-gallery/{owner_user_id}/{profile_id}/play",
|
||||
post(record_custom_world_gallery_play).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/custom-world-gallery/{owner_user_id}/{profile_id}/like",
|
||||
post(record_custom_world_gallery_like).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/custom-world-gallery/by-code/{code}",
|
||||
get(get_custom_world_gallery_detail_by_code),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/custom-world/agent/sessions",
|
||||
post(create_custom_world_agent_session).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/custom-world/agent/sessions/{session_id}",
|
||||
get(get_custom_world_agent_session)
|
||||
.delete(delete_custom_world_agent_session)
|
||||
.route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/custom-world/agent/sessions/{session_id}/result-view",
|
||||
get(get_custom_world_agent_result_view).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/custom-world/works",
|
||||
get(get_custom_world_works).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/custom-world/agent/sessions/{session_id}/cards/{card_id}",
|
||||
get(get_custom_world_agent_card_detail).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/custom-world/agent/sessions/{session_id}/messages",
|
||||
post(submit_custom_world_agent_message).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/custom-world/agent/sessions/{session_id}/messages/stream",
|
||||
post(stream_custom_world_agent_message).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/custom-world/agent/sessions/{session_id}/actions",
|
||||
post(execute_custom_world_agent_action).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/custom-world/agent/sessions/{session_id}/operations/{operation_id}",
|
||||
get(get_custom_world_agent_operation).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/custom-world/profile",
|
||||
post(generate_custom_world_profile).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/custom-world/entity",
|
||||
post(generate_custom_world_entity).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/custom-world/scene-npc",
|
||||
post(generate_custom_world_scene_npc).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/custom-world/scene-image",
|
||||
post(generate_custom_world_scene_image).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/custom-world/cover-image",
|
||||
post(generate_custom_world_cover_image).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/custom-world/cover-upload",
|
||||
post(upload_custom_world_cover_image).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/custom-world/opening-cg",
|
||||
post(generate_custom_world_opening_cg).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
}
|
||||
7
server-rs/crates/api-server/src/modules/health.rs
Normal file
7
server-rs/crates/api-server/src/modules/health.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
use axum::{Router, routing::get};
|
||||
|
||||
use crate::{health::health_check, state::AppState};
|
||||
|
||||
pub fn router(_state: AppState) -> Router<AppState> {
|
||||
Router::new().route("/healthz", get(health_check))
|
||||
}
|
||||
27
server-rs/crates/api-server/src/modules/internal.rs
Normal file
27
server-rs/crates/api-server/src/modules/internal.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
use axum::{Router, middleware, routing::get};
|
||||
|
||||
use crate::{
|
||||
auth::{
|
||||
attach_refresh_session_token, inspect_auth_claims, inspect_refresh_session_cookie,
|
||||
require_bearer_auth,
|
||||
},
|
||||
state::AppState,
|
||||
};
|
||||
|
||||
pub fn router(state: AppState) -> Router<AppState> {
|
||||
Router::new()
|
||||
.route(
|
||||
"/_internal/auth/claims",
|
||||
get(inspect_auth_claims).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/_internal/auth/refresh-cookie",
|
||||
get(inspect_refresh_session_cookie).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
attach_refresh_session_token,
|
||||
)),
|
||||
)
|
||||
}
|
||||
173
server-rs/crates/api-server/src/modules/match3d.rs
Normal file
173
server-rs/crates/api-server/src/modules/match3d.rs
Normal file
@@ -0,0 +1,173 @@
|
||||
use axum::{
|
||||
Router, middleware,
|
||||
routing::{get, post, put},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
auth::require_bearer_auth,
|
||||
match3d::{
|
||||
click_match3d_item, compile_match3d_agent_draft, create_match3d_agent_session,
|
||||
delete_match3d_work, execute_match3d_agent_action, finish_match3d_time_up,
|
||||
generate_match3d_background_image_for_work, generate_match3d_cover_image,
|
||||
generate_match3d_item_assets_for_work, generate_match3d_work_tags,
|
||||
get_match3d_agent_session, get_match3d_run, get_match3d_work_detail, get_match3d_works,
|
||||
list_match3d_gallery, persist_match3d_generated_model, publish_match3d_work,
|
||||
put_match3d_audio_assets, put_match3d_work, restart_match3d_run, start_match3d_run,
|
||||
stop_match3d_run, stream_match3d_agent_message, submit_match3d_agent_message,
|
||||
},
|
||||
state::AppState,
|
||||
};
|
||||
|
||||
pub fn router(state: AppState) -> Router<AppState> {
|
||||
Router::new()
|
||||
.route(
|
||||
"/api/creation/match3d/sessions",
|
||||
post(create_match3d_agent_session).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/creation/match3d/sessions/{session_id}",
|
||||
get(get_match3d_agent_session).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/creation/match3d/sessions/{session_id}/messages",
|
||||
post(submit_match3d_agent_message).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/creation/match3d/sessions/{session_id}/messages/stream",
|
||||
post(stream_match3d_agent_message).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/creation/match3d/sessions/{session_id}/actions",
|
||||
post(execute_match3d_agent_action).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/creation/match3d/sessions/{session_id}/compile",
|
||||
post(compile_match3d_agent_draft).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/creation/match3d/works",
|
||||
get(get_match3d_works).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/creation/match3d/works/tags",
|
||||
post(generate_match3d_work_tags).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/creation/match3d/works/{profile_id}",
|
||||
get(get_match3d_work_detail)
|
||||
.patch(put_match3d_work)
|
||||
.put(put_match3d_work)
|
||||
.delete(delete_match3d_work)
|
||||
.route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/creation/match3d/works/{profile_id}/audio-assets",
|
||||
put(put_match3d_audio_assets).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/creation/match3d/works/{profile_id}/cover-image",
|
||||
post(generate_match3d_cover_image).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/creation/match3d/works/{profile_id}/background-image",
|
||||
post(generate_match3d_background_image_for_work).route_layer(
|
||||
middleware::from_fn_with_state(state.clone(), require_bearer_auth),
|
||||
),
|
||||
)
|
||||
.route(
|
||||
"/api/creation/match3d/works/{profile_id}/item-assets",
|
||||
post(generate_match3d_item_assets_for_work).route_layer(
|
||||
middleware::from_fn_with_state(state.clone(), require_bearer_auth),
|
||||
),
|
||||
)
|
||||
.route(
|
||||
"/api/creation/match3d/works/{profile_id}/generated-models",
|
||||
post(persist_match3d_generated_model).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/creation/match3d/works/{profile_id}/publish",
|
||||
post(publish_match3d_work).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route("/api/runtime/match3d/gallery", get(list_match3d_gallery))
|
||||
.route(
|
||||
"/api/runtime/match3d/works/{profile_id}/runs",
|
||||
post(start_match3d_run).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/match3d/runs/{run_id}",
|
||||
get(get_match3d_run).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/match3d/runs/{run_id}/click",
|
||||
post(click_match3d_item).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/match3d/runs/{run_id}/stop",
|
||||
post(stop_match3d_run).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/match3d/runs/{run_id}/restart",
|
||||
post(restart_match3d_run).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/match3d/runs/{run_id}/time-up",
|
||||
post(finish_match3d_time_up).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
}
|
||||
13
server-rs/crates/api-server/src/modules/mod.rs
Normal file
13
server-rs/crates/api-server/src/modules/mod.rs
Normal file
@@ -0,0 +1,13 @@
|
||||
pub mod admin;
|
||||
pub mod assets;
|
||||
pub mod auth;
|
||||
pub mod big_fish;
|
||||
pub mod custom_world;
|
||||
pub mod health;
|
||||
pub mod internal;
|
||||
pub mod match3d;
|
||||
pub mod platform;
|
||||
pub mod profile;
|
||||
pub mod puzzle;
|
||||
pub mod square_hole;
|
||||
pub mod story;
|
||||
293
server-rs/crates/api-server/src/modules/platform.rs
Normal file
293
server-rs/crates/api-server/src/modules/platform.rs
Normal file
@@ -0,0 +1,293 @@
|
||||
use axum::{
|
||||
Router,
|
||||
extract::DefaultBodyLimit,
|
||||
middleware,
|
||||
routing::{get, post},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
ai_tasks::{
|
||||
append_ai_text_chunk, attach_ai_result_reference, cancel_ai_task, complete_ai_stage,
|
||||
complete_ai_task, create_ai_task, fail_ai_task, start_ai_task, start_ai_task_stage,
|
||||
},
|
||||
auth::require_bearer_auth,
|
||||
character_animation_assets::{
|
||||
generate_character_animation, get_character_animation_job, get_character_workflow_cache,
|
||||
import_character_animation_video, list_character_animation_templates,
|
||||
publish_character_animation, put_role_asset_workflow, resolve_role_asset_workflow,
|
||||
save_character_workflow_cache,
|
||||
},
|
||||
character_visual_assets::{
|
||||
generate_character_visual, get_character_visual_job, publish_character_visual,
|
||||
},
|
||||
creation_agent_document_input::parse_creation_agent_document_input,
|
||||
creation_entry_config::get_creation_entry_config_handler,
|
||||
hyper3d_generation::{
|
||||
get_hyper3d_downloads, get_hyper3d_task_status, submit_hyper3d_image_to_model,
|
||||
submit_hyper3d_text_to_model,
|
||||
},
|
||||
llm::proxy_llm_chat_completions,
|
||||
runtime_chat::stream_runtime_npc_chat_turn,
|
||||
runtime_chat_plain::{
|
||||
generate_runtime_character_chat_suggestions, generate_runtime_character_chat_summary,
|
||||
stream_runtime_character_chat_reply, stream_runtime_npc_chat_dialogue,
|
||||
stream_runtime_npc_recruit_dialogue,
|
||||
},
|
||||
runtime_save::{delete_runtime_snapshot, get_runtime_snapshot, put_runtime_snapshot},
|
||||
runtime_settings::{get_runtime_settings, put_runtime_settings},
|
||||
state::AppState,
|
||||
volcengine_speech::{
|
||||
get_volcengine_speech_config, stream_volcengine_asr, stream_volcengine_tts_bidirection,
|
||||
stream_volcengine_tts_sse,
|
||||
},
|
||||
};
|
||||
|
||||
const HYPER3D_IMAGE_TO_MODEL_BODY_LIMIT_BYTES: usize = 56 * 1024 * 1024;
|
||||
|
||||
pub fn router(state: AppState) -> Router<AppState> {
|
||||
Router::new()
|
||||
.route(
|
||||
"/api/llm/chat/completions",
|
||||
post(proxy_llm_chat_completions).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/speech/volcengine/config",
|
||||
get(get_volcengine_speech_config).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/speech/volcengine/asr/stream",
|
||||
get(stream_volcengine_asr).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/speech/volcengine/tts/bidirection",
|
||||
get(stream_volcengine_tts_bidirection).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/speech/volcengine/tts/sse",
|
||||
post(stream_volcengine_tts_sse).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/chat/character/suggestions",
|
||||
post(generate_runtime_character_chat_suggestions).route_layer(
|
||||
middleware::from_fn_with_state(state.clone(), require_bearer_auth),
|
||||
),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/chat/character/summary",
|
||||
post(generate_runtime_character_chat_summary).route_layer(
|
||||
middleware::from_fn_with_state(state.clone(), require_bearer_auth),
|
||||
),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/chat/character/reply/stream",
|
||||
post(stream_runtime_character_chat_reply).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/chat/npc/dialogue/stream",
|
||||
post(stream_runtime_npc_chat_dialogue).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/chat/npc/turn/stream",
|
||||
post(stream_runtime_npc_chat_turn).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/chat/npc/recruit/stream",
|
||||
post(stream_runtime_npc_recruit_dialogue).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/creation-agent/document-inputs/parse",
|
||||
post(parse_creation_agent_document_input).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/ai/tasks",
|
||||
post(create_ai_task).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/ai/tasks/{task_id}/start",
|
||||
post(start_ai_task).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/ai/tasks/{task_id}/stages/{stage_kind}/start",
|
||||
post(start_ai_task_stage).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/ai/tasks/{task_id}/chunks",
|
||||
post(append_ai_text_chunk).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/ai/tasks/{task_id}/stages/{stage_kind}/complete",
|
||||
post(complete_ai_stage).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/ai/tasks/{task_id}/references",
|
||||
post(attach_ai_result_reference).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/ai/tasks/{task_id}/complete",
|
||||
post(complete_ai_task).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/ai/tasks/{task_id}/fail",
|
||||
post(fail_ai_task).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/ai/tasks/{task_id}/cancel",
|
||||
post(cancel_ai_task).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/assets/character-visual/generate",
|
||||
post(generate_character_visual),
|
||||
)
|
||||
.route(
|
||||
"/api/assets/character-visual/jobs/{task_id}",
|
||||
get(get_character_visual_job),
|
||||
)
|
||||
.route(
|
||||
"/api/assets/character-visual/publish",
|
||||
post(publish_character_visual),
|
||||
)
|
||||
.route(
|
||||
"/api/assets/character-animation/generate",
|
||||
post(generate_character_animation),
|
||||
)
|
||||
.route(
|
||||
"/api/assets/character-animation/jobs/{task_id}",
|
||||
get(get_character_animation_job),
|
||||
)
|
||||
.route(
|
||||
"/api/assets/character-animation/publish",
|
||||
post(publish_character_animation),
|
||||
)
|
||||
.route(
|
||||
"/api/assets/character-animation/import-video",
|
||||
post(import_character_animation_video),
|
||||
)
|
||||
.route(
|
||||
"/api/assets/character-animation/templates",
|
||||
get(list_character_animation_templates),
|
||||
)
|
||||
.route(
|
||||
"/api/assets/character-workflow-cache",
|
||||
post(save_character_workflow_cache),
|
||||
)
|
||||
.route(
|
||||
"/api/assets/character-workflow-cache/{character_id}",
|
||||
get(get_character_workflow_cache),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/custom-world/asset-studio/role/{character_id}/workflow",
|
||||
post(resolve_role_asset_workflow).put(put_role_asset_workflow),
|
||||
)
|
||||
.route(
|
||||
"/api/assets/hyper3d/text-to-model",
|
||||
post(submit_hyper3d_text_to_model).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/assets/hyper3d/image-to-model",
|
||||
post(submit_hyper3d_image_to_model)
|
||||
.layer(DefaultBodyLimit::max(
|
||||
HYPER3D_IMAGE_TO_MODEL_BODY_LIMIT_BYTES,
|
||||
))
|
||||
.route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/assets/hyper3d/status",
|
||||
post(get_hyper3d_task_status).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/assets/hyper3d/download",
|
||||
post(get_hyper3d_downloads).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/creation-entry/config",
|
||||
get(get_creation_entry_config_handler),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/settings",
|
||||
get(get_runtime_settings)
|
||||
.put(put_runtime_settings)
|
||||
.route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/save/snapshot",
|
||||
get(get_runtime_snapshot)
|
||||
.put(put_runtime_snapshot)
|
||||
.delete(delete_runtime_snapshot)
|
||||
.route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
}
|
||||
141
server-rs/crates/api-server/src/modules/profile.rs
Normal file
141
server-rs/crates/api-server/src/modules/profile.rs
Normal file
@@ -0,0 +1,141 @@
|
||||
use axum::{
|
||||
Router, middleware,
|
||||
routing::{get, patch, post},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
auth::require_bearer_auth,
|
||||
profile_identity::update_profile_identity,
|
||||
runtime_browse_history::{
|
||||
delete_runtime_browse_history, get_runtime_browse_history, post_runtime_browse_history,
|
||||
},
|
||||
runtime_profile::{
|
||||
claim_profile_task_reward, create_profile_recharge_order, get_profile_analytics_metric,
|
||||
get_profile_dashboard, get_profile_play_stats, get_profile_recharge_center,
|
||||
get_profile_referral_invite_center, get_profile_task_center, get_profile_wallet_ledger,
|
||||
redeem_profile_referral_invite_code, redeem_profile_reward_code, submit_profile_feedback,
|
||||
},
|
||||
runtime_save::{list_profile_save_archives, resume_profile_save_archive},
|
||||
state::AppState,
|
||||
};
|
||||
|
||||
pub fn router(state: AppState) -> Router<AppState> {
|
||||
Router::new()
|
||||
.route(
|
||||
"/api/profile/me",
|
||||
patch(update_profile_identity).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/profile/browse-history",
|
||||
get(get_runtime_browse_history)
|
||||
.post(post_runtime_browse_history)
|
||||
.delete(delete_runtime_browse_history)
|
||||
.route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/profile/dashboard",
|
||||
get(get_profile_dashboard).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/profile/wallet-ledger",
|
||||
get(get_profile_wallet_ledger).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/profile/recharge-center",
|
||||
get(get_profile_recharge_center).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/profile/recharge/orders",
|
||||
post(create_profile_recharge_order).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/profile/feedback",
|
||||
post(submit_profile_feedback)
|
||||
.layer(axum::extract::DefaultBodyLimit::max(6 * 1024 * 1024))
|
||||
.route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/profile/referrals/invite-center",
|
||||
get(get_profile_referral_invite_center).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/profile/referrals/redeem-code",
|
||||
post(redeem_profile_referral_invite_code).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/profile/redeem-codes/redeem",
|
||||
post(redeem_profile_reward_code).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/profile/analytics/metric",
|
||||
get(get_profile_analytics_metric).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/profile/tasks",
|
||||
get(get_profile_task_center).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/profile/tasks/{task_id}/claim",
|
||||
post(claim_profile_task_reward).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/profile/save-archives",
|
||||
get(list_profile_save_archives).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/profile/save-archives/{world_key}",
|
||||
post(resume_profile_save_archive).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/profile/play-stats",
|
||||
get(get_profile_play_stats).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
}
|
||||
184
server-rs/crates/api-server/src/modules/puzzle.rs
Normal file
184
server-rs/crates/api-server/src/modules/puzzle.rs
Normal file
@@ -0,0 +1,184 @@
|
||||
use axum::{
|
||||
Router,
|
||||
extract::DefaultBodyLimit,
|
||||
middleware,
|
||||
routing::{get, post},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
auth::require_bearer_auth,
|
||||
puzzle::{
|
||||
advance_puzzle_next_level, claim_puzzle_work_point_incentive, create_puzzle_agent_session,
|
||||
delete_puzzle_work, drag_puzzle_piece_or_group, execute_puzzle_agent_action,
|
||||
generate_puzzle_onboarding_work, get_puzzle_agent_session, get_puzzle_gallery_detail,
|
||||
get_puzzle_run, get_puzzle_work_detail, get_puzzle_works, list_puzzle_gallery,
|
||||
put_puzzle_work, record_puzzle_gallery_like, remix_puzzle_gallery_work,
|
||||
save_puzzle_onboarding_work, start_puzzle_run, stream_puzzle_agent_message,
|
||||
submit_puzzle_agent_message, submit_puzzle_leaderboard, swap_puzzle_pieces,
|
||||
update_puzzle_run_pause, use_puzzle_runtime_prop,
|
||||
},
|
||||
state::AppState,
|
||||
};
|
||||
|
||||
const PUZZLE_REFERENCE_IMAGE_BODY_LIMIT_BYTES: usize = 12 * 1024 * 1024;
|
||||
|
||||
pub fn router(state: AppState) -> Router<AppState> {
|
||||
Router::new()
|
||||
.route(
|
||||
"/api/runtime/puzzle/agent/sessions",
|
||||
post(create_puzzle_agent_session)
|
||||
// 中文注释:拼图表单会携带单张参考图 Data URL,需只给该写入入口放宽 body 上限。
|
||||
.layer(DefaultBodyLimit::max(
|
||||
PUZZLE_REFERENCE_IMAGE_BODY_LIMIT_BYTES,
|
||||
))
|
||||
.route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/puzzle/agent/sessions/{session_id}",
|
||||
get(get_puzzle_agent_session).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/puzzle/agent/sessions/{session_id}/messages",
|
||||
post(submit_puzzle_agent_message).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/puzzle/agent/sessions/{session_id}/messages/stream",
|
||||
post(stream_puzzle_agent_message).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/puzzle/agent/sessions/{session_id}/actions",
|
||||
post(execute_puzzle_agent_action)
|
||||
// 中文注释:生成草稿/重新出图会复用 referenceImageSrc,避免默认 2MB JSON limit 拦截。
|
||||
.layer(DefaultBodyLimit::max(
|
||||
PUZZLE_REFERENCE_IMAGE_BODY_LIMIT_BYTES,
|
||||
))
|
||||
.route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/puzzle/onboarding/generate",
|
||||
post(generate_puzzle_onboarding_work).layer(DefaultBodyLimit::max(
|
||||
PUZZLE_REFERENCE_IMAGE_BODY_LIMIT_BYTES,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/puzzle/onboarding/save",
|
||||
post(save_puzzle_onboarding_work).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/puzzle/works",
|
||||
get(get_puzzle_works).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/puzzle/works/{profile_id}",
|
||||
get(get_puzzle_work_detail)
|
||||
.put(put_puzzle_work)
|
||||
.delete(delete_puzzle_work)
|
||||
.route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/puzzle/works/{profile_id}/point-incentive/claim",
|
||||
post(claim_puzzle_work_point_incentive).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route("/api/runtime/puzzle/gallery", get(list_puzzle_gallery))
|
||||
.route(
|
||||
"/api/runtime/puzzle/gallery/{profile_id}",
|
||||
get(get_puzzle_gallery_detail),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/puzzle/gallery/{profile_id}/remix",
|
||||
post(remix_puzzle_gallery_work).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/puzzle/gallery/{profile_id}/like",
|
||||
post(record_puzzle_gallery_like).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/puzzle/runs",
|
||||
post(start_puzzle_run).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/puzzle/runs/{run_id}",
|
||||
get(get_puzzle_run).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/puzzle/runs/{run_id}/swap",
|
||||
post(swap_puzzle_pieces).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/puzzle/runs/{run_id}/drag",
|
||||
post(drag_puzzle_piece_or_group).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/puzzle/runs/{run_id}/next-level",
|
||||
post(advance_puzzle_next_level).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/puzzle/runs/{run_id}/pause",
|
||||
post(update_puzzle_run_pause).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/puzzle/runs/{run_id}/props",
|
||||
post(use_puzzle_runtime_prop).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/puzzle/runs/{run_id}/leaderboard",
|
||||
post(submit_puzzle_leaderboard).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
}
|
||||
142
server-rs/crates/api-server/src/modules/square_hole.rs
Normal file
142
server-rs/crates/api-server/src/modules/square_hole.rs
Normal file
@@ -0,0 +1,142 @@
|
||||
use axum::{
|
||||
Router, middleware,
|
||||
routing::{get, post},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
auth::require_bearer_auth,
|
||||
square_hole::{
|
||||
compile_square_hole_agent_draft, create_square_hole_agent_session, delete_square_hole_work,
|
||||
drop_square_hole_shape, execute_square_hole_agent_action, finish_square_hole_time_up,
|
||||
get_square_hole_agent_session, get_square_hole_run, get_square_hole_work_detail,
|
||||
get_square_hole_works, list_square_hole_gallery, publish_square_hole_work,
|
||||
put_square_hole_work, regenerate_square_hole_work_image, restart_square_hole_run,
|
||||
start_square_hole_run, stop_square_hole_run, stream_square_hole_agent_message,
|
||||
submit_square_hole_agent_message,
|
||||
},
|
||||
state::AppState,
|
||||
};
|
||||
|
||||
pub fn router(state: AppState) -> Router<AppState> {
|
||||
Router::new()
|
||||
.route(
|
||||
"/api/creation/square-hole/sessions",
|
||||
post(create_square_hole_agent_session).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/creation/square-hole/sessions/{session_id}",
|
||||
get(get_square_hole_agent_session).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/creation/square-hole/sessions/{session_id}/messages",
|
||||
post(submit_square_hole_agent_message).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/creation/square-hole/sessions/{session_id}/messages/stream",
|
||||
post(stream_square_hole_agent_message).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/creation/square-hole/sessions/{session_id}/actions",
|
||||
post(execute_square_hole_agent_action).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/creation/square-hole/sessions/{session_id}/compile",
|
||||
post(compile_square_hole_agent_draft).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/creation/square-hole/works",
|
||||
get(get_square_hole_works).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/creation/square-hole/works/{profile_id}",
|
||||
get(get_square_hole_work_detail)
|
||||
.patch(put_square_hole_work)
|
||||
.put(put_square_hole_work)
|
||||
.delete(delete_square_hole_work)
|
||||
.route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/creation/square-hole/works/{profile_id}/publish",
|
||||
post(publish_square_hole_work).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/creation/square-hole/works/{profile_id}/images/regenerate",
|
||||
post(regenerate_square_hole_work_image).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/square-hole/gallery",
|
||||
get(list_square_hole_gallery),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/square-hole/works/{profile_id}/runs",
|
||||
post(start_square_hole_run).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/square-hole/runs/{run_id}",
|
||||
get(get_square_hole_run).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/square-hole/runs/{run_id}/drop",
|
||||
post(drop_square_hole_shape).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/square-hole/runs/{run_id}/stop",
|
||||
post(stop_square_hole_run).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/square-hole/runs/{run_id}/restart",
|
||||
post(restart_square_hole_run).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/square-hole/runs/{run_id}/time-up",
|
||||
post(finish_square_hole_time_up).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
}
|
||||
154
server-rs/crates/api-server/src/modules/story.rs
Normal file
154
server-rs/crates/api-server/src/modules/story.rs
Normal file
@@ -0,0 +1,154 @@
|
||||
use axum::{
|
||||
Router,
|
||||
extract::DefaultBodyLimit,
|
||||
middleware,
|
||||
routing::{get, post},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
auth::require_bearer_auth,
|
||||
creative_agent::{
|
||||
cancel_creative_agent_session, confirm_creative_puzzle_template,
|
||||
create_creative_agent_session, get_creative_agent_session, stream_creative_agent_message,
|
||||
stream_creative_draft_edit,
|
||||
},
|
||||
state::AppState,
|
||||
story_battles::{
|
||||
create_story_battle, create_story_npc_battle, get_story_battle_state, resolve_story_battle,
|
||||
},
|
||||
story_sessions::{
|
||||
begin_story_runtime_session, begin_story_session, continue_story,
|
||||
get_story_runtime_projection, get_story_session_state, resolve_story_runtime_action,
|
||||
},
|
||||
};
|
||||
|
||||
const PUZZLE_REFERENCE_IMAGE_BODY_LIMIT_BYTES: usize = 12 * 1024 * 1024;
|
||||
|
||||
pub fn router(state: AppState) -> Router<AppState> {
|
||||
Router::new()
|
||||
.route(
|
||||
"/api/story/sessions",
|
||||
post(begin_story_session).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/story/sessions/runtime",
|
||||
post(begin_story_runtime_session).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/story/sessions/{story_session_id}/state",
|
||||
get(get_story_session_state).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/story/sessions/{story_session_id}/runtime-projection",
|
||||
get(get_story_runtime_projection).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/story/sessions/{story_session_id}/actions/resolve",
|
||||
post(resolve_story_runtime_action).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/story/sessions/continue",
|
||||
post(continue_story).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/story/battles",
|
||||
post(create_story_battle).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/story/battles/{battle_state_id}",
|
||||
get(get_story_battle_state).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/story/npc/battle",
|
||||
post(create_story_npc_battle).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/story/battles/resolve",
|
||||
post(resolve_story_battle).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/creative-agent/sessions",
|
||||
post(create_creative_agent_session)
|
||||
// 中文注释:创意 Agent 首轮允许携带参考图 URL/Data URL,沿用拼图参考图入口上限。
|
||||
.layer(DefaultBodyLimit::max(
|
||||
PUZZLE_REFERENCE_IMAGE_BODY_LIMIT_BYTES,
|
||||
))
|
||||
.route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/creative-agent/sessions/{session_id}",
|
||||
get(get_creative_agent_session).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/creative-agent/sessions/{session_id}/messages/stream",
|
||||
post(stream_creative_agent_message)
|
||||
// 中文注释:message stream 同样可能带图片素材,避免默认 JSON limit 过早拒绝。
|
||||
.layer(DefaultBodyLimit::max(
|
||||
PUZZLE_REFERENCE_IMAGE_BODY_LIMIT_BYTES,
|
||||
))
|
||||
.route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/creative-agent/sessions/{session_id}/confirm-template",
|
||||
post(confirm_creative_puzzle_template).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/creative-agent/sessions/{session_id}/draft-edits/stream",
|
||||
post(stream_creative_draft_edit)
|
||||
// 中文注释:草稿编辑会携带当前 puzzle draft JSON,保持和拼图草稿入口一致的 body 上限。
|
||||
.layer(DefaultBodyLimit::max(
|
||||
PUZZLE_REFERENCE_IMAGE_BODY_LIMIT_BYTES,
|
||||
))
|
||||
.route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/creative-agent/sessions/{session_id}/cancel",
|
||||
post(cancel_creative_agent_session)
|
||||
.route_layer(middleware::from_fn_with_state(state, require_bearer_auth)),
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user