diff --git a/pages/ai.html b/pages/ai.html
new file mode 100644
index 0000000..84790ea
--- /dev/null
+++ b/pages/ai.html
@@ -0,0 +1,25 @@
+id: ai
+title: AI
+date_created: 2024-08-08
+date_last_updated: 2024-08-08
+description: How I use AI.
+---
+
AI
+
+ Common page I am seeing start to show up is an AI page explaining how creators use AI in their writing.
+ Along with some general thoughts on the topic.
+ Especially these days it seems like a useful page to have so here goes.
+
+
+ I don't use AI in my research, coding, or in any of my writing.
+ I am not against AI in principle, just this incarnation of it with LLMs.
+ The way that the models were created, trained on so many people's work without permission.
+ The massive amount of computation and therefore energy, water, etc. that they use.
+
+
+ That is why I don't use them in general.
+ I could see in the future if these issues were addressed.
+ If we had fairly trained models that were unbelievably more efficient and economical to run.
+ I may use them for work, but I don't see them ever touching this website or personal projects.
+ I do these things for the joy of doing them, and I don't want to give up any of that process.
+
diff --git a/src/database/link.rs b/src/database/link.rs
new file mode 100644
index 0000000..b257c66
--- /dev/null
+++ b/src/database/link.rs
@@ -0,0 +1,89 @@
+use crate::database::PsqlData;
+use futures_util::TryStreamExt;
+use serde::{Deserialize, Serialize};
+use sqlx::{self, postgres::PgPool};
+use std::error::Error;
+use time::Date;
+
+#[derive(Debug, Serialize, Deserialize, PartialEq, PartialOrd, Clone, sqlx::Type)]
+#[sqlx(type_name = "link_type", rename_all = "lowercase")]
+pub enum LinkType {
+ ARTICLE,
+ BLOG,
+}
+
+#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, sqlx::FromRow)]
+pub struct Link {
+ pub id: i32,
+ pub url: String,
+ pub description: Option,
+ pub title: Option,
+ pub author: String,
+ pub link_type: LinkType,
+ pub date_added: Date,
+}
+
+impl PsqlData for Link {
+ async fn read_all(pool: &PgPool) -> Result>, Box> {
+ let mut results = sqlx::query_as!(Link, "SELECT id,url,title,author,date_added,link_type AS \"link_type!: LinkType\",description FROM links;")
+ .fetch(pool);
+
+ let mut output = Vec::>::new();
+
+ while let Some(result) = results.try_next().await? {
+ output.push(Box::new(result));
+ }
+
+ Ok(output)
+ }
+
+ async fn read(pool: &PgPool, id: i32) -> Result, Box> {
+ let result = sqlx::query_as!(
+ Link,
+ "SELECT id,url,title,author,date_added,link_type AS \"link_type!: LinkType\",description FROM links WHERE id = $1",
+ id
+ )
+ .fetch_one(pool)
+ .await?;
+
+ Ok(Box::new(result))
+ }
+
+ async fn insert(&self, pool: &PgPool) -> Result<(), Box> {
+ sqlx::query!(
+ "INSERT INTO links (url, title, author, date_added, link_type, description) VALUES ($1, $2, $3, $4, $5, $6) RETURNING id,url,title,author,date_added,link_type AS \"link_type!: LinkType\", description",
+ self.url,
+ self.title,
+ self.author,
+ self.date_added,
+ self.link_type.clone() as LinkType,
+ self.description,
+ )
+ .fetch_one(pool)
+ .await?;
+
+ Ok(())
+ }
+
+ async fn update(&self, pool: &PgPool) -> Result<(), Box> {
+ sqlx::query!(
+ "UPDATE links SET url=$1, title=$2, author=$3, date_added=$4, link_type=$5, description=$6 WHERE id=$7",
+ self.url,
+ self.title,
+ self.author,
+ self.date_added,
+ self.link_type.clone() as LinkType,
+ self.description,
+ self.id,
+ )
+ .execute(pool)
+ .await?;
+
+ Ok(())
+ }
+
+ async fn delete(&self, pool: &PgPool) -> Result<(), Box> {
+ let id = &self.id;
+ crate::psql_delete!(id, pool, "links")
+ }
+}
diff --git a/src/database/mod.rs b/src/database/mod.rs
index 450c483..e90d0c8 100644
--- a/src/database/mod.rs
+++ b/src/database/mod.rs
@@ -9,6 +9,7 @@ use std::{
pub mod article;
pub mod page;
+pub mod link;
pub async fn establish_connection() -> Result> {
let db_url = match env::var("DATABASE_URL") {
diff --git a/src/html/root.rs b/src/html/root.rs
index ac2437f..c29b912 100644
--- a/src/html/root.rs
+++ b/src/html/root.rs
@@ -26,6 +26,7 @@ pub fn get_router(pool: PgPool) -> Router {
.route("/about", get(about))
.route("/contact", get(contact))
.route("/uses", get(uses))
+ .route("/ai", get(ai))
.route(
"/robots.txt",
get(|| async { Redirect::permanent("/assets/robots.txt") }),
@@ -52,3 +53,7 @@ async fn contact(state: Extension) -> Result) -> Result {
get_page(&state.db, "uses").await
}
+
+async fn ai(state: Extension) -> Result {
+ get_page(&state.db, "ai").await
+}