Skip to content

Commit

Permalink
Gliner setup works; checks work
Browse files Browse the repository at this point in the history
  • Loading branch information
brainless committed Jan 7, 2025
1 parent 9493205 commit d4f7e24
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 26 deletions.
2 changes: 1 addition & 1 deletion admin/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "admin",
"private": true,
"version": "0.0.0",
"version": "0.1.1",
"type": "module",
"scripts": {
"dev": "vite",
Expand Down
4 changes: 2 additions & 2 deletions admin/src/routes/settings/Setup.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Component } from "solid-js";
import Heading from "../../widgets/typography/Heading";
import PythonEnv from "../../widgets/settings/Python";
import Gliner from "../../widgets/settings/Gliner";
import MQTTBroker from "../../widgets/settings/MQTTBroker";
// import Ollama from "../../widgets/settings/Ollama";
import Markdown from "../../widgets/typography/Markdown";
Expand Down Expand Up @@ -29,7 +29,7 @@ const Setup: Component = () => {
{!!workspace.settings?.pathToStorageDir ? (
<>
<div class="mb-16" />
<PythonEnv />
<Gliner />

<div class="mb-16" />
<MQTTBroker />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import { Component, createResource } from "solid-js";
import Heading from "../../widgets/typography/Heading";
import Heading from "../typography/Heading";
import { useWorkspace } from "../../stores/Workspace";
import Markdown from "../typography/Markdown";
import Button from "../interactable/Button";
import { getPixlieAIAPIRoot } from "../../utils/api";
import { onMount } from "solid-js";

const help = `
Pixlie AI needs a Python environment to run some of the AI/ML tools.
Gliner is a Python library that we use to extract semantics from the data.
Pixlie AI needs a Python environment and Gliner installed on your computer.
`;

const PythonEnv: Component = () => {
const Gliner: Component = () => {
// We need a local Python virtual environment. We are our API if it can detect system Python and venv.
const [workspace, { fetchSettingsStatus }] = useWorkspace();
const [_settings, { refetch }] = createResource(async () => {
Expand All @@ -31,7 +32,7 @@ const PythonEnv: Component = () => {

return (
<>
<Heading size={3}>Python</Heading>
<Heading size={3}>Python and Gliner</Heading>
<Markdown text={help} />

<div class="mt-4">
Expand Down Expand Up @@ -86,7 +87,8 @@ const PythonEnv: Component = () => {
)}
{workspace.settingsStatus?.data.includes("GlinerNotSetup") && (
<>
We need GLiNER installed on this computer.{" "}
We can install Gliner on this computer, this will take a
while.{" "}
<Button label="Setup Gliner" onClick={handleSetupGliner} />
</>
)}
Expand All @@ -99,4 +101,4 @@ const PythonEnv: Component = () => {
);
};

export default PythonEnv;
export default Gliner;
2 changes: 1 addition & 1 deletion pixlieai_rs/Cargo.lock

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

6 changes: 4 additions & 2 deletions pixlieai_rs/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pixlieai"
version = "0.1.0"
version = "0.1.1"
edition = "2021"

[dependencies]
Expand Down Expand Up @@ -44,7 +44,9 @@ test-log = { version = "0.2.16", default-features = false, features = ["log"] }
thiserror = { version = "1.0.64", default-features = false }
tokio = { version = "1.41.0", default-features = false }
toml = { version = "0.8.19", default-features = false }
ts-rs = { version = "10.1.0", default-features = false, features = ["serde-compat"] }
ts-rs = { version = "10.1.0", default-features = false, features = [
"serde-compat",
] }
url = { version = "2.5.3", default-features = false }

[[bin]]
Expand Down
114 changes: 112 additions & 2 deletions pixlieai_rs/src/config/gliner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@ use crate::{
};
use bytes::Buf;
use flate2::read::GzDecoder;
use log::error;
use std::{fs::create_dir, path::PathBuf, process::Command, sync::mpsc};
use log::{debug, error, info};
use std::{
fs::{create_dir, exists, remove_dir_all, remove_file, File},
path::PathBuf,
process::Command,
sync::mpsc,
};
use tar::Archive;

pub fn get_path_to_gliner() -> PiResult<PathBuf> {
Expand Down Expand Up @@ -82,6 +87,66 @@ fn install_gliner_dependencies() -> PiResult<bool> {
.status()
{
Ok(status) => Ok(status.success()),
Err(err) => {
error!(
"Could not install Gliner dependencies at {}\nError: {}",
path_to_gliner.display(),
err
);
Err(err.into())
}
}
}

pub fn get_is_gliner_setup() -> PiResult<bool> {
// GLiNER is supported locally only
// We check if the virtual environment for GLiNER has been created
// The virtual environment is created in a gliner/.venv directory in the cli settings directory
let path_to_gliner = get_path_to_gliner()?;
let mut path_to_gliner_venv = path_to_gliner.clone();
path_to_gliner_venv.push(".venv");
let mut path_to_gliner_python = path_to_gliner_venv.clone();
path_to_gliner_python.push("bin");
path_to_gliner_python.push("python");
// Check if the virtual environment has been created
match exists(&path_to_gliner_venv) {
Ok(true) => {}
Ok(false) => {
return Ok(false);
}
Err(err) => {
error!(
"Error checking if Gliner virtual environment exists: {}",
err
);
return Err(err.into());
}
}
// Check if Gliner has been installed
match Command::new(path_to_gliner_python)
.arg("-m")
.arg("pip")
.arg("freeze")
.current_dir(path_to_gliner.to_str().unwrap())
.output()
{
Ok(output) => {
if output.status.success() {
debug!(
"Gliner pip freeze output: {}",
String::from_utf8_lossy(&output.stdout)
);
// Check if gliner is installed
let output = String::from_utf8_lossy(&output.stdout).to_string();
if output.contains("gliner") {
Ok(true)
} else {
Ok(false)
}
} else {
Ok(false)
}
}
Err(err) => {
error!("Error: {}", err);
Err(err.into())
Expand All @@ -90,9 +155,54 @@ fn install_gliner_dependencies() -> PiResult<bool> {
}

pub fn setup_gliner(tx: mpsc::Sender<PiEvent>) -> PiResult<()> {
// Touch a lock file when setting up Gliner
let path_to_gliner = get_path_to_gliner()?;
let mut path_to_gliner_venv = path_to_gliner.clone();
path_to_gliner_venv.push(".venv");
let mut path_to_gliner_setup_lock = path_to_gliner.clone();
path_to_gliner_setup_lock.push(".gliner_setup");
match File::create_new(&path_to_gliner_setup_lock) {
Ok(_) => match exists(&path_to_gliner_venv) {
Ok(true) => match remove_dir_all(&path_to_gliner_venv) {
Ok(_) => {}
Err(err) => {
error!(
"Could not delete existing Gliner's virtual environment at {}\nError: {}",
path_to_gliner_venv.display(),
err
);
return Err(err.into());
}
},
_ => {}
},
Err(err) => {
error!(
"Could not create Gliner setup lock file at {}, perhaps Gliner is being setup\nError: {}",
path_to_gliner_setup_lock.display(),
err
);
return Err(err.into());
}
}

create_venv_for_gliner()?;
download_gliner_code()?;
install_gliner_dependencies()?;

// Remove the lock file
match remove_file(&path_to_gliner_setup_lock) {
Ok(_) => {}
Err(err) => {
error!(
"Could not remove Gliner setup lock file at {}\nError: {}",
path_to_gliner_setup_lock.display(),
err
);
return Err(err.into());
}
}
info!("Gliner setup complete");
tx.send(PiEvent::FinishedSetupGliner).unwrap();
Ok(())
}
15 changes: 3 additions & 12 deletions pixlieai_rs/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use bytes::Buf;
use config::Config;
use dirs::config_dir;
use flate2::read::GzDecoder;
use gliner::get_path_to_gliner;
use gliner::get_is_gliner_setup;
use log::{debug, error};
use python::check_system_python;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -186,15 +186,6 @@ impl Settings {
}
}

pub fn get_is_gliner_available(&self) -> PiResult<bool> {
// GLiNER is supported locally only
// We check if the virtual environment for GLiNER has been created
// The virtual environment is created in a gliner/.venv directory in the cli settings directory
let mut path_to_gliner_venv = get_path_to_gliner()?;
path_to_gliner_venv.push(".venv");
Ok(path_to_gliner_venv.exists())
}

pub fn get_settings_status(&self) -> PiResult<SettingsStatus> {
let mut incomplete_reasons = Vec::new();
if self.path_to_storage_dir.is_none() {
Expand All @@ -209,7 +200,7 @@ impl Settings {
incomplete_reasons.push(SettingsIncompleteReason::PythonVenvNotAvailable);
} else if !python_status.pip {
incomplete_reasons.push(SettingsIncompleteReason::PythonPipNotAvailable);
} else if !self.get_is_gliner_available()? {
} else if !get_is_gliner_setup()? {
incomplete_reasons.push(SettingsIncompleteReason::GlinerNotSetup);
}
}
Expand All @@ -227,7 +218,7 @@ impl Settings {
}

pub fn get_entity_extraction_provider(&self) -> PiResult<EntityExtractionProvider> {
if let true = self.get_is_gliner_available()? {
if let true = get_is_gliner_setup()? {
return Ok(EntityExtractionProvider::Gliner);
} else if let Some(_) = self.ollama_hosts {
return Ok(EntityExtractionProvider::Ollama);
Expand Down

0 comments on commit d4f7e24

Please sign in to comment.