feat: remove ai, uploader, and weebs modules
Remove all AI chat/gemini/image endpoints, ryzencdn uploader/file-serve endpoints, and weebs anime-info/manga-info/whatanime/waifu endpoints. 14 files changed, 1032 lines deleted. cargo check clean, all tests pass.
This commit is contained in:
@@ -1,103 +0,0 @@
|
||||
//! Axum handlers for AI endpoints (Pollinations).
|
||||
|
||||
use axum::body::Body;
|
||||
use axum::extract::Query;
|
||||
use axum::http::{header, StatusCode};
|
||||
use axum::response::Response;
|
||||
use axum::Json;
|
||||
use serde::Deserialize;
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::application::ai as use_cases;
|
||||
use crate::presentation::error::AppError;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct AiParams {
|
||||
pub text: Option<String>,
|
||||
pub prompt: Option<String>,
|
||||
pub model: Option<String>,
|
||||
pub image_url: Option<String>,
|
||||
pub url: Option<String>,
|
||||
pub width: Option<u32>,
|
||||
pub height: Option<u32>,
|
||||
}
|
||||
|
||||
/// GET /ai/chat?text=...&prompt=...&model=...
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/ai/chat",
|
||||
tag = "ai",
|
||||
operation_id = "ai_chat_handler",
|
||||
responses(
|
||||
(status = 200, description = "OK", body = serde_json::Value),
|
||||
(status = 400, description = "Bad Request"),
|
||||
(status = 502, description = "Upstream error"),
|
||||
)
|
||||
)]
|
||||
|
||||
pub async fn chat_handler(Query(params): Query<AiParams>) -> Result<Json<Value>, AppError> {
|
||||
let text = params
|
||||
.text
|
||||
.ok_or_else(|| AppError::BadRequest("Missing 'text' parameter".to_string()))?;
|
||||
let result = use_cases::chat(text, params.prompt.unwrap_or_default(), params.model).await?;
|
||||
Ok(Json(result))
|
||||
}
|
||||
|
||||
/// GET /ai/gemini?text=...&prompt=...&image_url=...
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/ai/gemini",
|
||||
tag = "ai",
|
||||
operation_id = "ai_gemini_handler",
|
||||
responses(
|
||||
(status = 200, description = "OK", body = serde_json::Value),
|
||||
(status = 400, description = "Bad Request"),
|
||||
(status = 502, description = "Upstream error"),
|
||||
)
|
||||
)]
|
||||
|
||||
pub async fn gemini_handler(Query(params): Query<AiParams>) -> Result<Json<Value>, AppError> {
|
||||
let text = params
|
||||
.text
|
||||
.ok_or_else(|| AppError::BadRequest("Missing 'text' parameter".to_string()))?;
|
||||
let result =
|
||||
use_cases::gemini(text, params.prompt.unwrap_or_default(), params.image_url).await?;
|
||||
Ok(Json(result))
|
||||
}
|
||||
|
||||
/// GET /ai/image?prompt=...&model=...&width=...&height=... — returns image bytes.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/ai/image",
|
||||
tag = "ai",
|
||||
operation_id = "ai_image_handler",
|
||||
responses(
|
||||
(status = 200, description = "OK", body = serde_json::Value),
|
||||
(status = 400, description = "Bad Request"),
|
||||
(status = 502, description = "Upstream error"),
|
||||
)
|
||||
)]
|
||||
|
||||
pub async fn image_handler(Query(params): Query<AiParams>) -> Result<Response<Body>, AppError> {
|
||||
let prompt = params
|
||||
.prompt
|
||||
.ok_or_else(|| AppError::BadRequest("Missing 'prompt' parameter".to_string()))?;
|
||||
let model = params.model.unwrap_or_else(|| "flux".to_string());
|
||||
let width = params.width.unwrap_or(1024);
|
||||
let height = params.height.unwrap_or(1024);
|
||||
|
||||
let bytes = use_cases::image(prompt, model, width, height).await?;
|
||||
// Pollinations flux returns JPEG by default.
|
||||
let mime = if bytes.starts_with(b"\xff\xd8\xff") {
|
||||
"image/jpeg"
|
||||
} else if bytes.starts_with(b"\x89PNG\r\n\x1a\n") {
|
||||
"image/png"
|
||||
} else {
|
||||
"application/octet-stream"
|
||||
};
|
||||
Response::builder()
|
||||
.status(StatusCode::OK)
|
||||
.header(header::CONTENT_TYPE, mime)
|
||||
.body(Body::from(bytes))
|
||||
.map_err(|e| AppError::Internal(format!("build response: {e}")))
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
pub mod ai;
|
||||
pub mod anime;
|
||||
pub mod anime2;
|
||||
pub mod downloader;
|
||||
@@ -10,5 +9,3 @@ pub mod proxy;
|
||||
pub mod search;
|
||||
pub mod stalk;
|
||||
pub mod tools;
|
||||
pub mod uploader;
|
||||
pub mod weebs;
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
//! Axum handlers for the uploader.
|
||||
//!
|
||||
//! POST /uploader/ryzencdn — multipart file upload, saved to local disk.
|
||||
//! GET /uploader/file/:name — serve an uploaded file.
|
||||
|
||||
use axum::body::Body;
|
||||
use axum::extract::{Multipart, Path};
|
||||
use axum::http::{header, StatusCode};
|
||||
use axum::response::Response;
|
||||
use axum::Json;
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::application::uploader as use_cases;
|
||||
use crate::presentation::error::AppError;
|
||||
|
||||
/// POST /uploader/ryzencdn — accept a multipart file upload.
|
||||
#[utoipa::path(
|
||||
post,
|
||||
path = "/uploader/ryzencdn",
|
||||
tag = "uploader",
|
||||
operation_id = "uploader_ryzencdn_handler",
|
||||
responses(
|
||||
(status = 200, description = "OK", body = serde_json::Value),
|
||||
(status = 400, description = "Bad Request"),
|
||||
(status = 502, description = "Upstream error"),
|
||||
)
|
||||
)]
|
||||
|
||||
pub async fn ryzencdn_handler(mut multipart: Multipart) -> Result<Json<Value>, AppError> {
|
||||
// Read the first file field.
|
||||
let mut file_name = String::from("");
|
||||
let mut data: Vec<u8> = Vec::new();
|
||||
|
||||
while let Some(field) = multipart
|
||||
.next_field()
|
||||
.await
|
||||
.map_err(|e| AppError::BadRequest(format!("multipart: {e}")))?
|
||||
{
|
||||
let name = field.name().unwrap_or("file").to_string();
|
||||
if name == "file" {
|
||||
file_name = field.file_name().unwrap_or("").to_string();
|
||||
let content = field
|
||||
.bytes()
|
||||
.await
|
||||
.map_err(|e| AppError::BadRequest(format!("bytes: {e}")))?;
|
||||
data = content.to_vec();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if data.is_empty() {
|
||||
return Err(AppError::BadRequest(
|
||||
"No file field named 'file' in multipart body".into(),
|
||||
));
|
||||
}
|
||||
|
||||
let result = use_cases::upload(&data, &file_name)?;
|
||||
Ok(Json(result))
|
||||
}
|
||||
|
||||
/// GET /uploader/file/:name — serve an uploaded file.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/uploader/file/:name",
|
||||
tag = "uploader",
|
||||
operation_id = "uploader_serve_file_handler",
|
||||
responses(
|
||||
(status = 200, description = "OK", body = serde_json::Value),
|
||||
(status = 400, description = "Bad Request"),
|
||||
(status = 502, description = "Upstream error"),
|
||||
)
|
||||
)]
|
||||
|
||||
pub async fn serve_file_handler(Path(name): Path<String>) -> Result<Response<Body>, AppError> {
|
||||
let (bytes, mime) = use_cases::serve(&name)?;
|
||||
Response::builder()
|
||||
.status(StatusCode::OK)
|
||||
.header(header::CONTENT_TYPE, mime)
|
||||
.header(header::CACHE_CONTROL, "public, max-age=86400")
|
||||
.body(Body::from(bytes))
|
||||
.map_err(|e| AppError::Internal(format!("build response: {e}")))
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
//! Axum handlers for weebs endpoints.
|
||||
//!
|
||||
//! Ported from Shirokami-API `scraper/weebs/*.js`.
|
||||
|
||||
use axum::extract::Query;
|
||||
use axum::http::StatusCode;
|
||||
use axum::Json;
|
||||
use serde::Deserialize;
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::application::weebs as use_cases;
|
||||
use crate::presentation::error::AppError;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct WeebsParams {
|
||||
pub query: Option<String>,
|
||||
pub q: Option<String>,
|
||||
pub url: Option<String>,
|
||||
pub tag: Option<String>,
|
||||
}
|
||||
|
||||
fn require(v: Option<&String>, name: &str) -> Result<String, AppError> {
|
||||
v.cloned()
|
||||
.ok_or_else(|| AppError::BadRequest(format!("Missing '{}' parameter", name)))
|
||||
}
|
||||
|
||||
/// GET /weebs/anime-info?query=naruto
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/weebs/anime-info",
|
||||
tag = "weebs",
|
||||
operation_id = "weebs_anime_info_handler",
|
||||
responses(
|
||||
(status = 200, description = "OK", body = serde_json::Value),
|
||||
(status = 400, description = "Bad Request"),
|
||||
(status = 502, description = "Upstream error"),
|
||||
)
|
||||
)]
|
||||
|
||||
pub async fn anime_info_handler(
|
||||
Query(p): Query<WeebsParams>,
|
||||
) -> Result<(StatusCode, Json<Value>), AppError> {
|
||||
let query = require(p.query.as_ref().or(p.q.as_ref()), "query")?;
|
||||
Ok((StatusCode::OK, Json(use_cases::anime_info(&query).await?)))
|
||||
}
|
||||
|
||||
/// GET /weebs/manga-info?query=one%20piece
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/weebs/manga-info",
|
||||
tag = "weebs",
|
||||
operation_id = "weebs_manga_info_handler",
|
||||
responses(
|
||||
(status = 200, description = "OK", body = serde_json::Value),
|
||||
(status = 400, description = "Bad Request"),
|
||||
(status = 502, description = "Upstream error"),
|
||||
)
|
||||
)]
|
||||
|
||||
pub async fn manga_info_handler(
|
||||
Query(p): Query<WeebsParams>,
|
||||
) -> Result<(StatusCode, Json<Value>), AppError> {
|
||||
let query = require(p.query.as_ref().or(p.q.as_ref()), "query")?;
|
||||
Ok((StatusCode::OK, Json(use_cases::manga_info(&query).await?)))
|
||||
}
|
||||
|
||||
/// GET /weebs/whatanime?url=<image-url>
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/weebs/whatanime",
|
||||
tag = "weebs",
|
||||
operation_id = "weebs_whatanime_handler",
|
||||
responses(
|
||||
(status = 200, description = "OK", body = serde_json::Value),
|
||||
(status = 400, description = "Bad Request"),
|
||||
(status = 502, description = "Upstream error"),
|
||||
)
|
||||
)]
|
||||
|
||||
pub async fn whatanime_handler(
|
||||
Query(p): Query<WeebsParams>,
|
||||
) -> Result<(StatusCode, Json<Value>), AppError> {
|
||||
let url = require(p.url.as_ref(), "url")?;
|
||||
Ok((StatusCode::OK, Json(use_cases::whatanime(&url).await?)))
|
||||
}
|
||||
|
||||
/// GET /weebs/sfw-waifu?tag=waifu
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/weebs/sfw-waifu",
|
||||
tag = "weebs",
|
||||
operation_id = "weebs_sfw_waifu_handler",
|
||||
responses(
|
||||
(status = 200, description = "OK", body = serde_json::Value),
|
||||
(status = 400, description = "Bad Request"),
|
||||
(status = 502, description = "Upstream error"),
|
||||
)
|
||||
)]
|
||||
|
||||
pub async fn sfw_waifu_handler(
|
||||
Query(p): Query<WeebsParams>,
|
||||
) -> Result<(StatusCode, Json<Value>), AppError> {
|
||||
let tag = require(p.tag.as_ref(), "tag")?;
|
||||
Ok((StatusCode::OK, Json(use_cases::sfw_waifu(&tag).await?)))
|
||||
}
|
||||
|
||||
/// GET /weebs/nsfw-waifu?tag=waifu
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/weebs/nsfw-waifu",
|
||||
tag = "weebs",
|
||||
operation_id = "weebs_nsfw_waifu_handler",
|
||||
responses(
|
||||
(status = 200, description = "OK", body = serde_json::Value),
|
||||
(status = 400, description = "Bad Request"),
|
||||
(status = 502, description = "Upstream error"),
|
||||
)
|
||||
)]
|
||||
|
||||
pub async fn nsfw_waifu_handler(
|
||||
Query(p): Query<WeebsParams>,
|
||||
) -> Result<(StatusCode, Json<Value>), AppError> {
|
||||
let tag = require(p.tag.as_ref(), "tag")?;
|
||||
Ok((StatusCode::OK, Json(use_cases::nsfw_waifu(&tag).await?)))
|
||||
}
|
||||
@@ -306,27 +306,6 @@ pub fn build_router(app_state: Arc<AppState>) -> anyhow::Result<Router> {
|
||||
"/stalk/instagram",
|
||||
axum::routing::get(crate::presentation::handler::stalk::instagram_handler),
|
||||
)
|
||||
// Weebs routes
|
||||
.route(
|
||||
"/weebs/anime-info",
|
||||
axum::routing::get(crate::presentation::handler::weebs::anime_info_handler),
|
||||
)
|
||||
.route(
|
||||
"/weebs/manga-info",
|
||||
axum::routing::get(crate::presentation::handler::weebs::manga_info_handler),
|
||||
)
|
||||
.route(
|
||||
"/weebs/whatanime",
|
||||
axum::routing::get(crate::presentation::handler::weebs::whatanime_handler),
|
||||
)
|
||||
.route(
|
||||
"/weebs/sfw-waifu",
|
||||
axum::routing::get(crate::presentation::handler::weebs::sfw_waifu_handler),
|
||||
)
|
||||
.route(
|
||||
"/weebs/nsfw-waifu",
|
||||
axum::routing::get(crate::presentation::handler::weebs::nsfw_waifu_handler),
|
||||
)
|
||||
// Search routes
|
||||
.route(
|
||||
"/search/bmkg",
|
||||
@@ -382,28 +361,6 @@ pub fn build_router(app_state: Arc<AppState>) -> anyhow::Result<Router> {
|
||||
"/image/brat/animated",
|
||||
axum::routing::get(crate::presentation::handler::image::brat_animated_handler),
|
||||
)
|
||||
// Uploader routes
|
||||
.route(
|
||||
"/uploader/ryzencdn",
|
||||
axum::routing::post(crate::presentation::handler::uploader::ryzencdn_handler),
|
||||
)
|
||||
.route(
|
||||
"/uploader/file/{name}",
|
||||
axum::routing::get(crate::presentation::handler::uploader::serve_file_handler),
|
||||
)
|
||||
// AI routes
|
||||
.route(
|
||||
"/ai/chat",
|
||||
axum::routing::get(crate::presentation::handler::ai::chat_handler),
|
||||
)
|
||||
.route(
|
||||
"/ai/gemini",
|
||||
axum::routing::get(crate::presentation::handler::ai::gemini_handler),
|
||||
)
|
||||
.route(
|
||||
"/ai/image",
|
||||
axum::routing::get(crate::presentation::handler::ai::image_handler),
|
||||
)
|
||||
// Health
|
||||
.route(
|
||||
"/health",
|
||||
|
||||
Reference in New Issue
Block a user