chore: checkpoint ai search comments and i18n foundation

This commit is contained in:
2026-03-28 17:17:31 +08:00
parent d18a709987
commit ec96d91548
71 changed files with 9494 additions and 423 deletions

View File

@@ -21,7 +21,9 @@ use tower_http::cors::{Any, CorsLayer};
#[allow(unused_imports)]
use crate::{
controllers, initializers,
models::_entities::{categories, comments, friend_links, posts, reviews, site_settings, tags, users},
models::_entities::{
ai_chunks, categories, comments, friend_links, posts, reviews, site_settings, tags, users,
},
tasks,
workers::downloader::DownloadWorker,
};
@@ -69,12 +71,19 @@ impl Hooks for App {
.add_route(controllers::post::routes())
.add_route(controllers::search::routes())
.add_route(controllers::site_settings::routes())
.add_route(controllers::ai::routes())
.add_route(controllers::auth::routes())
}
async fn after_routes(router: AxumRouter, _ctx: &AppContext) -> Result<AxumRouter> {
let cors = CorsLayer::new()
.allow_origin(Any)
.allow_methods([Method::GET, Method::POST, Method::PUT, Method::PATCH, Method::DELETE])
.allow_methods([
Method::GET,
Method::POST,
Method::PUT,
Method::PATCH,
Method::DELETE,
])
.allow_headers(Any);
Ok(router.layer(cors))
@@ -88,10 +97,6 @@ impl Hooks for App {
fn register_tasks(tasks: &mut Tasks) {
// tasks-inject (do not remove)
}
async fn truncate(ctx: &AppContext) -> Result<()> {
truncate_table(&ctx.db, users::Entity).await?;
Ok(())
}
async fn seed(ctx: &AppContext, base: &Path) -> Result<()> {
// Seed users - use loco's default seed which handles duplicates
let users_file = base.join("users.yaml");
@@ -275,44 +280,59 @@ impl Hooks for App {
let item = site_settings::ActiveModel {
id: Set(settings["id"].as_i64().unwrap_or(1) as i32),
site_name: Set(settings["site_name"].as_str().map(ToString::to_string)),
site_short_name: Set(
settings["site_short_name"].as_str().map(ToString::to_string),
),
site_short_name: Set(settings["site_short_name"]
.as_str()
.map(ToString::to_string)),
site_url: Set(settings["site_url"].as_str().map(ToString::to_string)),
site_title: Set(settings["site_title"].as_str().map(ToString::to_string)),
site_description: Set(
settings["site_description"].as_str().map(ToString::to_string),
),
site_description: Set(settings["site_description"]
.as_str()
.map(ToString::to_string)),
hero_title: Set(settings["hero_title"].as_str().map(ToString::to_string)),
hero_subtitle: Set(
settings["hero_subtitle"].as_str().map(ToString::to_string),
),
hero_subtitle: Set(settings["hero_subtitle"]
.as_str()
.map(ToString::to_string)),
owner_name: Set(settings["owner_name"].as_str().map(ToString::to_string)),
owner_title: Set(
settings["owner_title"].as_str().map(ToString::to_string),
),
owner_title: Set(settings["owner_title"].as_str().map(ToString::to_string)),
owner_bio: Set(settings["owner_bio"].as_str().map(ToString::to_string)),
owner_avatar_url: Set(
settings["owner_avatar_url"].as_str().and_then(|value| {
owner_avatar_url: Set(settings["owner_avatar_url"].as_str().and_then(
|value| {
let trimmed = value.trim();
if trimmed.is_empty() {
None
} else {
Some(trimmed.to_string())
}
}),
),
social_github: Set(
settings["social_github"].as_str().map(ToString::to_string),
),
social_twitter: Set(
settings["social_twitter"].as_str().map(ToString::to_string),
),
social_email: Set(
settings["social_email"].as_str().map(ToString::to_string),
),
},
)),
social_github: Set(settings["social_github"]
.as_str()
.map(ToString::to_string)),
social_twitter: Set(settings["social_twitter"]
.as_str()
.map(ToString::to_string)),
social_email: Set(settings["social_email"]
.as_str()
.map(ToString::to_string)),
location: Set(settings["location"].as_str().map(ToString::to_string)),
tech_stack: Set(tech_stack),
ai_enabled: Set(settings["ai_enabled"].as_bool()),
ai_provider: Set(settings["ai_provider"].as_str().map(ToString::to_string)),
ai_api_base: Set(settings["ai_api_base"].as_str().map(ToString::to_string)),
ai_api_key: Set(settings["ai_api_key"].as_str().map(ToString::to_string)),
ai_chat_model: Set(settings["ai_chat_model"]
.as_str()
.map(ToString::to_string)),
ai_embedding_model: Set(settings["ai_embedding_model"]
.as_str()
.map(ToString::to_string)),
ai_system_prompt: Set(settings["ai_system_prompt"]
.as_str()
.map(ToString::to_string)),
ai_top_k: Set(settings["ai_top_k"].as_i64().map(|value| value as i32)),
ai_chunk_size: Set(settings["ai_chunk_size"]
.as_i64()
.map(|value| value as i32)),
..Default::default()
};
let _ = item.insert(&ctx.db).await;
@@ -365,4 +385,10 @@ impl Hooks for App {
Ok(())
}
async fn truncate(ctx: &AppContext) -> Result<()> {
truncate_table(&ctx.db, ai_chunks::Entity).await?;
truncate_table(&ctx.db, users::Entity).await?;
Ok(())
}
}