name-generator/src/main.rs
2024-12-29 21:12:39 +01:00

108 lines
3.2 KiB
Rust

use std::{collections::HashMap, str::from_utf8};
use actix_web::{get, web, App, HttpResponse, HttpServer};
use rand::seq::SliceRandom;
use rust_embed::Embed;
use serde::{Deserialize, Serialize};
static ARTICLE: &str = "<article>";
#[derive(Embed)]
#[folder = "dictionaries/"]
struct Dictionaries;
#[derive(Debug, Serialize, Deserialize)]
struct NameGenQuery {
dictionaries: Vec<String>,
gender: String,
qty: Option<u8>,
}
#[get("/")]
async fn index(query: web::Json<NameGenQuery>) -> HttpResponse {
// Load the dictionaries into memory
let mut dictionaries = HashMap::new();
for filename in Dictionaries::iter() {
if let Some(file) = Dictionaries::get(&filename) {
let data = from_utf8(file.data.as_ref()).unwrap();
dictionaries.insert(filename.to_string(), serde_json::from_str::<Vec<String>>(data).unwrap());
}
}
let qty = query.0.qty.unwrap_or(10).min(50).max(1);
let gender = match query.0.gender.as_str() {
"m" => "masculins",
"f" => "feminins",
_ => "masculins",
};
// Limit to 10 parts max
let mut chosen_dicts = query.0.dictionaries;
chosen_dicts.truncate(10);
let mut names = vec![];
for _ in 0..qty {
let mut parts = vec![];
for dict in chosen_dicts.iter() {
let filename = match dict.as_str() {
"adjectif" | "commun" | "ppasse" | "ppresent" | "prenom" => {
Some(format!("{dict}s_{gender}.json"))
}
"patronyme" => Some(format!("{dict}s.json")),
"article" => Some(ARTICLE.to_string()),
"virgule" => Some(",".to_string()),
_ => None,
};
if let Some(filename) = filename {
if let Some(data) = dictionaries.get(&filename) {
let item = data.choose(&mut rand::thread_rng()).unwrap();
parts.push(item.to_string())
} else {
parts.push(filename)
}
}
}
// Replace the <article> with le/la/l'
let mut to_replace = vec![];
for (i, item) in parts.iter().enumerate() {
if item == ARTICLE {
// Check the next word
if let Some(next) = parts.get(i + 1) {
if next
.starts_with(|c| vec!['a', 'e', 'i', 'o', 'u', 'é', 'è', 'ê', 'h'].contains(&c))
{
to_replace.push((i, "l'"));
} else {
to_replace.push((i, (if gender == "masculins" { "le" } else { "la" })))
}
}
}
}
for item in to_replace.iter() {
parts[item.0] = item.1.to_string();
}
let joined = parts
.join(" ")
// Remove space after "l'"
.replace("l' ", "l'")
// Remove space before comma
.replace(" ,", ",");
names.push(joined);
}
HttpResponse::Ok().json(names)
}
#[actix_web::main] // or #[tokio::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| App::new().service(index))
.bind(("127.0.0.1", 8080))?
.run()
.await
}