Skip to content

Commit

Permalink
Streamline api, Introduce item re-indexing, and introduce intelligenc…
Browse files Browse the repository at this point in the history
…e module
  • Loading branch information
lucemans committed Dec 3, 2024
1 parent b01f7d2 commit 3f74cc5
Show file tree
Hide file tree
Showing 19 changed files with 380 additions and 116 deletions.
4 changes: 4 additions & 0 deletions engine/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,7 @@ DATABASE_URL=postgres://postgres:postgres@localhost:5432/property
# Meilisearch
MEILISEARCH_URL=http://localhost:7700
MEILISEARCH_MASTER_KEY=master

# Ollama
OLLAMA_URL=http://localhost
OLLAMA_PORT=11434
38 changes: 38 additions & 0 deletions engine/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions engine/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ dotenvy = "0.15.7"
hex = "0.4.3"
hmac = "0.12.1"
meilisearch-sdk = "0.27.1"
ollama-rs = "0.2.1"
openid = "0.14.0"
poem = { version = "3.0.4", git = "https://github.com/poem-web/poem", branch = "master" }
poem-openapi = { version = "5", git = "https://github.com/poem-web/poem", branch = "master", features = [
Expand Down
40 changes: 40 additions & 0 deletions engine/src/intelligence/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
use std::env;

use ollama_rs::Ollama;
use tracing::info;

pub struct Intelligence {
pub ollama: Ollama,
}

impl Intelligence {
pub async fn new(url: String, port: u16) -> Result<Self, anyhow::Error> {
let ollama = Ollama::new(url, port);

let models: Vec<String> = ollama
.list_local_models()
.await?
.iter()
.map(|m| m.name.clone())
.collect();

info!("Ollama models detected: {:?}", models);

Ok(Self {
ollama,
})
}

pub async fn guess() -> Result<Self, anyhow::Error> {
let url = env::var("OLLAMA_URL")
.map_err(|_| anyhow::anyhow!("OLLAMA_URL is not set"))?;
let port = env::var("OLLAMA_PORT")
.map_err(|_| anyhow::anyhow!("OLLAMA_PORT is not set"))?
.parse::<u16>()
.map_err(|_| anyhow::anyhow!("OLLAMA_PORT is not a valid u16"))?;

Self::new(url, port)
.await
.map_err(anyhow::Error::from)
}
}
1 change: 1 addition & 0 deletions engine/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ mod models;
mod routes;
mod state;
mod search;
mod intelligence;

#[async_std::main]
async fn main() {
Expand Down
6 changes: 6 additions & 0 deletions engine/src/models/item/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ impl Item {
.await
}

pub async fn get_all(db: &Database) -> Result<Vec<Item>, sqlx::Error> {
query_as!(Item, "SELECT * FROM items")
.fetch_all(&db.pool)
.await
}

pub async fn get_by_owner_id(
database: &Database,
owner_id: i32
Expand Down
28 changes: 22 additions & 6 deletions engine/src/models/item/search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,31 @@ pub struct SearchableItem {
pub owner_id: Option<i32>,
pub location_id: Option<i32>,
// TODO: add more location info
pub fields: Vec<SearchableItemField>,
pub fields: Option<Vec<SearchableItemField>>,
pub created_at: Option<DateTime<Utc>>,
pub updated_at: Option<DateTime<Utc>>,

#[serde(rename = "_vectors")]
pub vectors: Option<SearchableItemVectors>,
}

#[derive(Debug, Clone, Serialize, Deserialize, Object)]
pub struct SearchableItemVectors {
pub ollama: SearchableItemVectorsOllama,
}

#[derive(Debug, Clone, Serialize, Deserialize, Object)]
pub struct SearchableItemVectorsOllama {
pub regenerate: bool,
}

impl Item {
pub async fn into_search(&self, db: &Database) -> Result<SearchableItem, sqlx::Error> {
let fields = ItemField::get_by_item_id(db, &self.item_id)
.await?
.iter()
.map(|field| field.into())
.collect();
let fields = Some(ItemField::get_by_item_id(db, &self.item_id)
.await?
.iter()
.map(|field| field.into())
.collect());

Ok(SearchableItem {
item_id: self.item_id.clone(),
Expand All @@ -35,6 +48,9 @@ impl Item {
fields,
created_at: self.created_at,
updated_at: self.updated_at,
vectors: Some(SearchableItemVectors {
ollama: SearchableItemVectorsOllama { regenerate: true },
}),
})
}
}
Expand Down
21 changes: 17 additions & 4 deletions engine/src/models/media.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use chrono::{DateTime, Utc};
use poem_openapi::Object;
use serde::{Deserialize, Serialize};
use sqlx::{query_as, FromRow};
use sqlx::{query, query_as, FromRow};

use crate::database::Database;

#[derive(FromRow, Object, Debug, Clone, Serialize, Deserialize)]
#[derive(FromRow, Object, Debug, Clone, Serialize, Deserialize, Default)]
pub struct Media {
pub media_id: i32,
pub description: Option<String>,
Expand Down Expand Up @@ -33,9 +33,22 @@ impl Media {
.await
}

pub async fn get_by_id(db: &Database, media_id: i32) -> Result<Media, sqlx::Error> {
pub async fn get_by_id(db: &Database, media_id: i32) -> Result<Option<Media>, sqlx::Error> {
query_as!(Media, "SELECT * FROM media WHERE media_id = $1", media_id)
.fetch_one(&db.pool)
.fetch_optional(&db.pool)
.await
}

pub async fn get_all(db: &Database) -> Result<Vec<Media>, sqlx::Error> {
query_as!(Media, "SELECT * FROM media")
.fetch_all(&db.pool)
.await
}

pub async fn delete(self, db: &Database) -> Result<(), sqlx::Error> {
query!("DELETE FROM media WHERE media_id = $1", self.media_id)
.execute(&db.pool)
.await
.map(|_| ())
}
}
4 changes: 2 additions & 2 deletions engine/src/routes/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize};

use crate::{auth::middleware::AuthToken, state::AppState};

pub struct ApiInstance;
pub struct InstanceApi;

#[derive(Serialize, Deserialize, Enum)]
pub enum IdCasingPreference {
Expand All @@ -32,7 +32,7 @@ impl Default for InstanceSettings {
}

#[OpenApi]
impl ApiInstance {
impl InstanceApi {
#[oai(path = "/instance/settings", method = "get")]
pub async fn settings(
&self,
Expand Down
4 changes: 2 additions & 2 deletions engine/src/routes/me.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ use crate::{
state::AppState,
};

pub struct ApiMe;
pub struct MeApi;

#[OpenApi]
impl ApiMe {
impl MeApi {
#[oai(path = "/me", method = "get")]
pub async fn me(&self, state: Data<&Arc<AppState>>, token: AuthToken) -> Json<User> {
match token {
Expand Down
101 changes: 101 additions & 0 deletions engine/src/routes/media/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
use std::sync::Arc;

use poem::{
web::{Data, Path},
Result,
};
use poem_openapi::{payload::Json, Object, OpenApi};
use reqwest::StatusCode;
use serde::{Deserialize, Serialize};

use crate::{
auth::middleware::AuthToken,
models::media::Media,
state::AppState,
};

pub struct MediaApi;

#[derive(Deserialize, Debug, Serialize, Object)]
pub struct MediaIdResponse {
media_id: String,
}

#[derive(Deserialize, Debug, Serialize, Object)]
pub struct CreateMediaRequest {
name: Option<String>,
kind: Option<String>,
}

#[OpenApi]
impl MediaApi {
#[oai(path = "/media/:media_id", method = "get")]
async fn get_media(
&self,
state: Data<&Arc<AppState>>,
auth: AuthToken,
media_id: Path<i32>,
) -> Result<Json<Media>> {
Media::get_by_id(&state.database, media_id.0)
.await
.or(Err(poem::Error::from_status(
StatusCode::INTERNAL_SERVER_ERROR,
)))?
.ok_or(poem::Error::from_status(StatusCode::NOT_FOUND))
.map(|x| Json(x))
}

#[oai(path = "/media/:media_id", method = "delete")]
async fn delete_media(
&self,
auth: AuthToken,
state: Data<&Arc<AppState>>,
media_id: Path<i32>,
) -> Result<()> {
Media::get_by_id(&state.database, media_id.0)
.await
.unwrap()
.unwrap()
.delete(&state.database)
.await
.unwrap();

Ok(())
}

#[oai(path = "/media", method = "get")]
async fn get_all_media(
&self,
auth: AuthToken,
state: Data<&Arc<AppState>>,
) -> Result<Json<Vec<Media>>> {
match auth.ok() {
Some(user) => Ok(Json(
Media::get_all(&state.database)
.await
.unwrap(),
)),
None => Err(StatusCode::UNAUTHORIZED.into()),
}
}

// #[oai(path = "/media", method = "post")]
// async fn create_media(
// &self,
// auth: AuthToken,
// state: Data<&Arc<AppState>>,
// request: Query<CreateMediaRequest>,
// ) -> Json<Media> {
// Json(
// Media {
// ..Default::default()
// }
// .insert(&state.database)
// .await
// .unwrap()
// .index_search(&state.search, &state.database)
// .await
// .unwrap(),
// )
// }
}
Loading

0 comments on commit 3f74cc5

Please sign in to comment.