use config file instead of argument options

This commit is contained in:
yggverse 2026-01-10 16:37:28 +02:00
parent ec0cca64f3
commit 3e94399ccb
15 changed files with 162 additions and 123 deletions

View file

@ -6,7 +6,7 @@ update = 900
[mysql] [mysql]
host = "localhost" host = "localhost"
port = 3306 port = 3306
user = "" username = ""
password = "" password = ""
database = "rssto" database = "rssto"

View file

@ -8,7 +8,7 @@ pub struct Mysql {
pub host: String, pub host: String,
pub password: String, pub password: String,
pub port: u16, pub port: u16,
pub user: String, pub username: String,
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]

View file

@ -30,7 +30,7 @@ fn main() -> Result<()> {
let db = mysql::Database::pool( let db = mysql::Database::pool(
&config.mysql.host, &config.mysql.host,
config.mysql.port, config.mysql.port,
&config.mysql.user, &config.mysql.username,
&config.mysql.password, &config.mysql.password,
&config.mysql.database, &config.mysql.database,
)?; )?;

View file

@ -15,3 +15,5 @@ clap = { version = "4.5.54", features = ["derive"] }
mysql = { package = "rssto-mysql", version = "0.1.0", path = "../mysql" } mysql = { package = "rssto-mysql", version = "0.1.0", path = "../mysql" }
rocket = "0.5.1" rocket = "0.5.1"
rocket_dyn_templates = { version = "0.2.0", features = ["tera"] } rocket_dyn_templates = { version = "0.2.0", features = ["tera"] }
serde = { version = "1.0.228", features = ["derive"] }
toml = "0.9.10"

View file

@ -7,8 +7,5 @@ Web server implementation based on the Rocket engine
``` ```
cd rssto/crates/rssto-http cd rssto/crates/rssto-http
cargo run -- --mysql-username {USER} \ cargo run -- -c /path/to/config.toml
--mysql-password {PASS} \
--mysql-database {NAME}
``` ```
* optionally, use `--provider-id {ID}` to filter content using post-processing results (e.g. generated by the `rssto-llm` crate)

33
crates/http/config.toml Normal file
View file

@ -0,0 +1,33 @@
title = "rssto"
#description = ""
# Replace image sources with local
# * if crawled with the `persist_images_selector` selector
local_images = true
format_time = "%d/%m/%Y %H:%M"
# Provider ID (`provider` table)
# * None for the original content
# provider_id = 1
# Default listing limit
list_limit = 20
# Bind server on given host
host = "127.0.0.1"
# Bind server on given port
port = 8000
#Configure instance in the debug mode
debug = true
# Database connection setup
# * see crates/mysql/database
[mysql]
host = "localhost"
port = 3306
username = ""
password = ""
database = "rssto"

View file

@ -0,0 +1,12 @@
use clap::Parser;
use std::path::PathBuf;
#[derive(Parser, Debug)]
#[command(version, about, long_about = None)]
pub struct Argument {
/// Path to config file
///
/// * see `config.toml`
#[arg(short, long)]
pub config: PathBuf,
}

View file

@ -1,53 +1,24 @@
use clap::Parser; use serde::Deserialize;
use std::net::{IpAddr, Ipv4Addr}; use std::net::IpAddr;
#[derive(Parser, Debug)] #[derive(Debug, Deserialize)]
#[command(version, about, long_about = None)] pub struct Mysql {
pub struct Config { pub database: String,
/// Server name pub host: String,
#[arg(long, default_value_t = String::from("rssto"))] pub password: String,
pub title: String,
/// Server description
#[arg(long)]
pub description: Option<String>,
/// Format timestamps (on the web view)
///
/// * tip: escape with `%%d/%%m/%%Y %%H:%%M` in the CLI/bash argument
#[arg(long, default_value_t = String::from("%d/%m/%Y %H:%M"))]
pub format_time: String,
/// Provider ID (`provider` table)
/// * None for the original content
#[arg(long, short)]
pub provider_id: Option<u64>,
/// Default listing limit
#[arg(long, default_value_t = 20)]
pub list_limit: usize,
/// Bind server on given host
#[arg(long, default_value_t = IpAddr::V4(Ipv4Addr::LOCALHOST))]
pub host: IpAddr,
/// Bind server on given port
#[arg(long, default_value_t = 8000)]
pub port: u16, pub port: u16,
pub username: String,
/// Configure instance in the debug mode }
#[arg(long, default_value_t = false)]
pub debug: bool, #[derive(Debug, Deserialize)]
pub struct Config {
// Database pub mysql: Mysql,
#[arg(long, default_value_t = String::from("localhost"))] pub title: String,
pub mysql_host: String, pub description: Option<String>,
#[arg(long, default_value_t = 3306)] pub format_time: String,
pub mysql_port: u16, pub provider_id: Option<u64>,
#[arg(long)] pub list_limit: usize,
pub mysql_username: String, pub host: IpAddr,
#[arg(long)] pub port: u16,
pub mysql_password: String, pub debug: bool,
#[arg(long)]
pub mysql_database: String,
} }

View file

@ -1,13 +1,13 @@
#[macro_use] #[macro_use]
extern crate rocket; extern crate rocket;
mod argument;
mod config; mod config;
mod feed; mod feed;
mod global; mod global;
mod meta; mod meta;
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use config::Config;
use feed::Feed; use feed::Feed;
use global::Global; use global::Global;
use meta::Meta; use meta::Meta;
@ -187,7 +187,9 @@ fn rss(
#[launch] #[launch]
fn rocket() -> _ { fn rocket() -> _ {
use clap::Parser; use clap::Parser;
let config = Config::parse(); let argument = argument::Argument::parse();
let config: config::Config =
toml::from_str(&std::fs::read_to_string(argument.config).unwrap()).unwrap();
rocket::build() rocket::build()
.attach(Template::fairing()) .attach(Template::fairing())
.configure(rocket::Config { .configure(rocket::Config {
@ -201,11 +203,11 @@ fn rocket() -> _ {
}) })
.manage( .manage(
Database::pool( Database::pool(
&config.mysql_host, &config.mysql.host,
config.mysql_port, config.mysql.port,
&config.mysql_username, &config.mysql.username,
&config.mysql_password, &config.mysql.password,
&config.mysql_database, &config.mysql.database,
) )
.unwrap(), .unwrap(),
) )

View file

@ -16,5 +16,7 @@ clap = { version = "4.5.54", features = ["derive"] }
lancor = "0.1.1" lancor = "0.1.1"
log = "0.4.29" log = "0.4.29"
mysql = { package = "rssto-mysql", version = "0.1.0", features = ["transaction"], path = "../mysql" } mysql = { package = "rssto-mysql", version = "0.1.0", features = ["transaction"], path = "../mysql" }
serde = { version = "1.0.228", features = ["derive"] }
tokio = { version = "1.0", features = ["full"] } tokio = { version = "1.0", features = ["full"] }
toml = "0.9.10"
tracing-subscriber = { version = "0.3.22", features = ["env-filter"] } tracing-subscriber = { version = "0.3.22", features = ["env-filter"] }

View file

@ -17,12 +17,6 @@ llama-server -hf ggml-org/gemma-3-1b-it-GGUF
``` ```
cd rssto/crates/rssto-llm cd rssto/crates/rssto-llm
cargo run -- --mysql-username {USER} \ cargo run -- -c /path/to/config.toml
--mysql-password {PASS} \
--mysql-database {NAME} \
--llm-host {HOST} \
--llm-port {PORT} \
--llm-model {MODEL} \
--llm-message {MESSAGE}
``` ```
* see `--help` to display all supported options * see `--help` to display all supported options

22
crates/llm/config.toml Normal file
View file

@ -0,0 +1,22 @@
# Rescan database for new subjects, in seconds
# * process once if not defined
# update = 900
# Database connection setup
# * see crates/mysql/database
[mysql]
host = "localhost"
port = 3306
username = ""
password = ""
database = "rssto"
# LLM connection setup
[llm]
scheme = "http"
host = "127.0.0.1"
port = 8080
# Model name
model = "ggml-org/gemma-3-1b-it-GGUF"
# Initial message for the `content` subject (e.g. `translate to...`)
message = "translate to english:"

View file

@ -1,37 +1,12 @@
use clap::Parser; use clap::Parser;
use std::path::PathBuf;
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
#[command(version, about, long_about = None)] #[command(version, about, long_about = None)]
pub struct Argument { pub struct Argument {
// LLM /// Path to config file
#[arg(long, default_value_t = String::from("http"))] ///
pub llm_scheme: String, /// * see `config.toml`
#[arg(long, default_value_t = String::from("localhost"))] #[arg(short, long)]
pub llm_host: String, pub config: PathBuf,
#[arg(long, default_value_t = 8080)]
pub llm_port: u16,
/// Model name (e.g. `INSAIT-Institute/MamayLM-Gemma-2-9B-IT-v0.1-GGUF` or `ggml-org/gemma-3-1b-it-GGUF`)
#[arg(long)]
pub llm_model: String,
/// Initial message for the `content` subject (e.g. `translate to...`)
#[arg(long)]
pub llm_message: String,
// Database
#[arg(long, default_value_t = String::from("localhost"))]
pub mysql_host: String,
#[arg(long, default_value_t = 3306)]
pub mysql_port: u16,
#[arg(long)]
pub mysql_username: String,
#[arg(long)]
pub mysql_password: String,
#[arg(long)]
pub mysql_database: String,
/// Loop update in seconds
/// * None to exit on complete
#[arg(long, short)]
pub update: Option<u64>,
} }

27
crates/llm/src/config.rs Normal file
View file

@ -0,0 +1,27 @@
use serde::Deserialize;
use std::net::IpAddr;
#[derive(Debug, Deserialize)]
pub struct Mysql {
pub database: String,
pub host: IpAddr,
pub password: String,
pub port: u16,
pub username: String,
}
#[derive(Debug, Deserialize)]
pub struct Llm {
pub scheme: String,
pub host: IpAddr,
pub port: u16,
pub model: String,
pub message: String,
}
#[derive(Debug, Deserialize)]
pub struct Config {
pub mysql: Mysql,
pub llm: Llm,
pub update: Option<u64>,
}

View file

@ -1,7 +1,7 @@
mod argument; mod argument;
mod config;
use anyhow::Result; use anyhow::Result;
use argument::Argument;
use mysql::Database; use mysql::Database;
#[tokio::main] #[tokio::main]
@ -27,34 +27,36 @@ async fn main() -> Result<()> {
.init() .init()
} }
let arg = Argument::parse(); let argument = argument::Argument::parse();
let config: config::Config = toml::from_str(&std::fs::read_to_string(argument.config)?)?;
let llm = LlamaCppClient::new(format!( let llm = LlamaCppClient::new(format!(
"{}://{}:{}", "{}://{}:{}",
arg.llm_scheme, arg.llm_host, arg.llm_port config.llm.scheme, config.llm.host, config.llm.port
))?; ))?;
let db = Database::pool( let db = Database::pool(
&arg.mysql_host, &config.mysql.host.to_string(),
arg.mysql_port, config.mysql.port,
&arg.mysql_username, &config.mysql.username,
&arg.mysql_password, &config.mysql.password,
&arg.mysql_database, &config.mysql.database,
)?; )?;
let provider_id = { let provider_id = {
let mut conn = db.connection()?; let mut conn = db.connection()?;
match conn.provider_id_by_name(&arg.llm_model)? { match conn.provider_id_by_name(&config.llm.model)? {
Some(provider_id) => { Some(provider_id) => {
debug!( debug!(
"Use existing DB provider #{} matches model name `{}`", "Use existing DB provider #{} matches model name `{}`",
provider_id, &arg.llm_model provider_id, &config.llm.model
); );
provider_id provider_id
} }
None => { None => {
let provider_id = conn.insert_provider(&arg.llm_model)?; let provider_id = conn.insert_provider(&config.llm.model)?;
info!( info!(
"Provider `{}` not found in database, created new one with ID `{provider_id}`", "Provider `{}` not found in database, created new one with ID `{provider_id}`",
&arg.llm_model &config.llm.model
); );
provider_id provider_id
} }
@ -71,15 +73,15 @@ async fn main() -> Result<()> {
source.content_id source.content_id
); );
let title = let title = llm
llm.chat_completion(ChatCompletionRequest::new(&arg.llm_model).message( .chat_completion(ChatCompletionRequest::new(&config.llm.model).message(
Message::user(format!("{}\n{}", arg.llm_message, source.title)), Message::user(format!("{}\n{}", config.llm.message, source.title)),
)) ))
.await?; .await?;
let description = let description = llm
llm.chat_completion(ChatCompletionRequest::new(&arg.llm_model).message( .chat_completion(ChatCompletionRequest::new(&config.llm.model).message(
Message::user(format!("{}\n{}", arg.llm_message, source.description)), Message::user(format!("{}\n{}", config.llm.message, source.description)),
)) ))
.await?; .await?;
@ -97,7 +99,7 @@ async fn main() -> Result<()> {
} }
tx.commit()?; tx.commit()?;
debug!("Queue completed"); debug!("Queue completed");
if let Some(update) = arg.update { if let Some(update) = config.update {
debug!("Wait {update} seconds to continue..."); debug!("Wait {update} seconds to continue...");
std::thread::sleep(std::time::Duration::from_secs(update)) std::thread::sleep(std::time::Duration::from_secs(update))
} else { } else {