Для чего нужна данная статья? :
Найти альтернативы реализации SSG, сочетающий AI-контент, анализ данных и обработку изображений с ML.
1. Создание блогов
- Zola: Поддерживает Markdown, имеет встроенные шаблоны и удобен для создания персональных блогов или небольших сайтов.
- Cobalt: Поддерживает Markdown и Liquid-шаблонов. Хорошо подходит для ведения блога.
2. Портфолио и персональные сайты
- Gutenberg (Zola): Подходит для создания портфолио или персональных сайтов с поддержкой различных типов контента.
- Copper: Для создания легковесных персональных сайтов.
3. Документация
- mdBook: Для создания книг и документации. Он поддерживает Markdown и имеет функции генерации структуры и навигации по книге.
- Yewprint: Инструмент на базе Yew для создания документации и стилей компонентов.
4. Корпоративные сайты
- Tera: Движок шаблонов, который часто используется вместе с Rust для генерации статических сайтов с более сложной логикой.
- Trillium: Может использоваться для генерации статического контента, особенно если требуется более сложная логика.
5. Одностраничные сайты (Landing Pages)
- Sycamore: Для создания одностраничных приложений с поддержкой серверного рендеринга, что позволяет использовать его как SSG.
- Percy: Для создания одностраничных сайтов.
6. Инструменты для генерации HTML из Markdown или других форматов
- miniserve: Для показа статического контента, который можно использовать вместе с генераторами статических сайтов.
- cargo-generate: Для генерации шаблонов и структур проектов, включая статические сайты.
Зачем Вам это уметь? :
Написать Static Site Generators (SSG) на Rust с высокой производительностью используя :
pulldown-cmark: Парсер Markdown.
tera: Шаблонизатор для HTML.
walkdir: Обходит директории для поиска файлов..
Создайте новый проект на Rust:
cargo new my_ssg
cd my_ssg
Добавьте необходимые зависимости в Cargo.toml:
[dependencies]
pulldown-cmark = "0.9"
tera = "1.12.0"
walkdir = "2.3.2"
Добавьте следующий код в src/main.rs:
use pulldown_cmark::{Parser, Options, html};
use tera::{Tera, Context};
use std::fs::{self, File};
use std::io::{self, Write};
use std::path::Path;
use walkdir::WalkDir;
fn main() -> io::Result<()> {
let tera = Tera::new("templates/**/*")?;
for entry in WalkDir::new("content") {
let entry = entry?;
if entry.path().extension().and_then(|e| e.to_str()) == Some("md") {
let markdown_input = fs::read_to_string(entry.path())?;
let html_output = markdown_to_html(&markdown_input);
let file_stem = entry.path().file_stem().unwrap().to_str().unwrap();
let mut context = Context::new();
context.insert("content", &html_output);
let rendered_html = tera.render("page.html", &context)?;
let output_path = format!("public/{}.html", file_stem);
let mut output_file = File::create(output_path)?;
output_file.write_all(rendered_html.as_bytes())?;
}
}
Ok(())
}
fn markdown_to_html(markdown_input: &str) ->
String {
let mut options = Options::empty();
options.insert(Options::ENABLE_STRIKETHROUGH);
let parser = Parser::new_ext(markdown_input, options);
let mut html_output = String::new();
html::push_html(&mut html_output, parser);
html_output
}
Создайте следующие директории и файлы:
mkdir content
mkdir templates
mkdir public
Пример контента в content/index.md:
# Welcome
This is Rust!
Пример шаблона в templates/page.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ title | default(value="My Site") }}</title>
</head>
<body>
{{ content | safe }}
</body>
</html>
Соберите и запустите проект:
После выполнения команды cargo run, откройте сгенерированный HTML файл (public/index.html) в браузере.
DeepSeek AI с Torch (tch-rs) для анализа текста и imageproc с ndarray для оптимизации изображений
use tch::{CModule, Tensor};
use image::{DynamicImage, GenericImageView, imageops::FilterType};
use std::fs;
use std::path::Path;
use reqwest::Client;
use serde_json::json;
use tokio::task;
use rayon::prelude::*;
// Генерация контента через DeepSeek AI
async fn generate_content(prompt: &str) -> String {
let client = Client::new();
let response = client.post("https://api.deepseek.com/generate")
.json(&json!({"prompt": prompt, "max_length": 500}))
.send().await.unwrap()
.text().await.unwrap();
response
}
// Анализ контента с использованием ML-модели (Torch)
fn analyze_content(model: &CModule, text: &str) -> Tensor {
let input_tensor = Tensor::of_slice(&text.bytes().map(|b| b as f32).collect::<Vec<f32>>());
model.forward_ts(&[input_tensor]).unwrap()
}
// Оптимизация изображения с многопоточностью
fn optimize_image(path: &str) -> DynamicImage {
let img = image::open(path).unwrap();
let (width, height) = img.dimensions();
img.resize_exact(width / 2, height / 2, FilterType::CatmullRom)
}
// Параллельная обработка изображений
fn process_images(input_dir: &str, output_dir: &str) {
let paths: Vec<_> = fs::read_dir(input_dir).unwrap()
.filter_map(Result::ok)
.map(|entry| entry.path())
.collect();
paths.par_iter().for_each(|path| {
if let Some(ext) = path.extension() {
if ext == "jpg" || ext == "png" {
let optimized = optimize_image(path.to_str().unwrap());
let output_path = Path::new(output_dir).join(path.file_name().unwrap());
optimized.save(output_path).unwrap();
}
}
});
}
// Генерация статической страницы с шаблонизацией
fn generate_page(title: &str, content: &str, category: &str) -> String {
format!(
"<html><head><title>{}</title></head><body><h1>{}</h1><p>{}</p></body></html>",
title, category, content
)
}
#[tokio::main]
async fn main() {
let model = CModule::load("content_model.pt").unwrap();
let prompt = "SEO-оптимизированный текст о Rust";
let content_task = task::spawn(async move { generate_content(prompt).await });
let content = content_task.await.unwrap();
let category = analyze_content(&model, &content);
let category_str = format!("Категория: {:.2}", category.double_value(&[]));
let html = generate_page("Rust Blog", &content, &category_str);
fs::write("output/index.html", html).unwrap();
process_images("input", "output");
}