mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-02-12 11:01:38 +00:00
Added pipeline to retrieve information for .NET runtime to create Qdrant client
This commit is contained in:
parent
dec2c27997
commit
a79a2996fe
8
.github/workflows/build-and-release.yml
vendored
8
.github/workflows/build-and-release.yml
vendored
@ -174,7 +174,7 @@ jobs:
|
||||
pdfium_version=$(echo $pdfium_version | cut -d'.' -f3)
|
||||
|
||||
# Next line is the Qdrant version:
|
||||
qdrant_version=$(sed -n '12p' metadata.txt)
|
||||
qdrant_version="v$(sed -n '12p' metadata.txt)"
|
||||
|
||||
# Write the metadata to the environment:
|
||||
echo "APP_VERSION=${app_version}" >> $GITHUB_ENV
|
||||
@ -247,7 +247,7 @@ jobs:
|
||||
$pdfium_version = $pdfium_version.Split('.')[2]
|
||||
|
||||
# Next line is the necessary Qdrant version:
|
||||
$qdrant_version = $metadata[12]
|
||||
$qdrant_version = "v$metadata[12]"
|
||||
|
||||
# Write the metadata to the environment:
|
||||
Write-Output "APP_VERSION=${app_version}" >> $env:GITHUB_ENV
|
||||
@ -441,7 +441,7 @@ jobs:
|
||||
;;
|
||||
esac
|
||||
|
||||
QDRANT_URL="https://github.com/qdrant/qdrant/releases/download/${QDRANT_VERSON}/qdrant-{QDRANT_FILE}"
|
||||
QDRANT_URL="https://github.com/qdrant/qdrant/releases/download/v${QDRANT_VERSION}/qdrant-{QDRANT_FILE}"
|
||||
|
||||
echo "Download Qdrant $QDRANT_URL ..."
|
||||
TMP=$(mktemp -d)
|
||||
@ -485,7 +485,7 @@ jobs:
|
||||
}
|
||||
}
|
||||
|
||||
QDRANT_URL="https://github.com/qdrant/qdrant/releases/download/${QDRANT_VERSON}/qdrant-{QDRANT_FILE}"
|
||||
QDRANT_URL="https://github.com/qdrant/qdrant/releases/download/v${QDRANT_VERSION}/qdrant-{QDRANT_FILE}"
|
||||
Write-Host "Download $QDRANT_URL ..."
|
||||
|
||||
# Create a unique temporary directory (not just a file)
|
||||
|
||||
@ -32,7 +32,7 @@ Since November 2024: Work on RAG (integration of your data and files) has begun.
|
||||
- [x] ~~App: Implement dialog for checking & handling [pandoc](https://pandoc.org/) installation ([PR #393](https://github.com/MindWorkAI/AI-Studio/pull/393), [PR #487](https://github.com/MindWorkAI/AI-Studio/pull/487))~~
|
||||
- [ ] App: Implement external embedding providers
|
||||
- [ ] App: Implement the process to vectorize one local file using embeddings
|
||||
- [ ] Runtime: Integration of the vector database [LanceDB](https://github.com/lancedb/lancedb)
|
||||
- [ ] Runtime: Integration of the vector database [Qdrant](https://github.com/qdrant/qdrant)
|
||||
- [ ] App: Implement the continuous process of vectorizing data
|
||||
- [x] ~~App: Define a common retrieval context interface for the integration of RAG processes in chats (PR [#281](https://github.com/MindWorkAI/AI-Studio/pull/281), [#284](https://github.com/MindWorkAI/AI-Studio/pull/284), [#286](https://github.com/MindWorkAI/AI-Studio/pull/286), [#287](https://github.com/MindWorkAI/AI-Studio/pull/287))~~
|
||||
- [x] ~~App: Define a common augmentation interface for the integration of RAG processes in chats (PR [#288](https://github.com/MindWorkAI/AI-Studio/pull/288), [#289](https://github.com/MindWorkAI/AI-Studio/pull/289))~~
|
||||
|
||||
@ -88,11 +88,11 @@ public static class Qdrant
|
||||
|
||||
private static Database GetDatabasePath(RID rid) => rid switch
|
||||
{
|
||||
RID.LINUX_ARM64 => new("qdrant", "qdrant-aarch64-apple-darwin"),
|
||||
RID.LINUX_X64 => new("qdrant", "qdrant-x86_64-apple-darwin"),
|
||||
RID.OSX_ARM64 => new("qdrant", "qdrant-aarch64-apple-darwin"),
|
||||
RID.OSX_X64 => new("qdrant", "qdrant-x86_64-apple-darwin"),
|
||||
|
||||
RID.OSX_ARM64 => new("qdrant", "qdrant-aarch64-unknown-linux-gnu"),
|
||||
RID.OSX_X64 => new("qdrant", "qdrant-x86_64-unknown-linux-gnu"),
|
||||
RID.LINUX_ARM64 => new("qdrant", "qdrant-aarch64-unknown-linux-gnu"),
|
||||
RID.LINUX_X64 => new("qdrant", "qdrant-x86_64-unknown-linux-gnu"),
|
||||
|
||||
RID.WIN_X64 => new("qdrant.exe", "qdrant-x86_64-pc-windows-msvc.exe"),
|
||||
|
||||
@ -101,7 +101,7 @@ public static class Qdrant
|
||||
|
||||
private static string GetQdrantDownloadUrl(RID rid, string version)
|
||||
{
|
||||
var baseUrl = $"https://github.com/qdrant/qdrant/releases/download/{version}/qdrant-";
|
||||
var baseUrl = $"https://github.com/qdrant/qdrant/releases/download/v{version}/qdrant-";
|
||||
return rid switch
|
||||
{
|
||||
RID.LINUX_ARM64 => $"{baseUrl}aarch64-unknown-linux-musl.tar.gz",
|
||||
|
||||
@ -4462,6 +4462,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::ABOUT::T1282228996"] = "AI Studio runs with an
|
||||
-- This library is used to read PDF files. This is necessary, e.g., for using PDFs as a data source for a chat.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::ABOUT::T1388816916"] = "This library is used to read PDF files. This is necessary, e.g., for using PDFs as a data source for a chat."
|
||||
|
||||
-- Database version
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::ABOUT::T1420062548"] = "Database version"
|
||||
|
||||
-- This library is used to extend the MudBlazor library. It provides additional components that are not part of the MudBlazor library.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::ABOUT::T1421513382"] = "This library is used to extend the MudBlazor library. It provides additional components that are not part of the MudBlazor library."
|
||||
|
||||
@ -4501,6 +4504,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::ABOUT::T1924365263"] = "This library is used t
|
||||
-- We use Rocket to implement the runtime API. This is necessary because the runtime must be able to communicate with the user interface (IPC). Rocket is a great framework for implementing web APIs in Rust.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::ABOUT::T1943216839"] = "We use Rocket to implement the runtime API. This is necessary because the runtime must be able to communicate with the user interface (IPC). Rocket is a great framework for implementing web APIs in Rust."
|
||||
|
||||
-- Copies the following to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::ABOUT::T2029659664"] = "Copies the following to the clipboard"
|
||||
|
||||
-- Copies the server URL to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::ABOUT::T2037899437"] = "Copies the server URL to the clipboard"
|
||||
|
||||
@ -4567,9 +4573,6 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::ABOUT::T2777988282"] = "Code in the Rust langu
|
||||
-- Show Details
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::ABOUT::T27924674"] = "Show Details"
|
||||
|
||||
-- Used Qdrant version
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::ABOUT::T2799791022"] = "Used Qdrant version"
|
||||
|
||||
-- View our project roadmap and help shape AI Studio's future development.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::ABOUT::T2829971158"] = "View our project roadmap and help shape AI Studio's future development."
|
||||
|
||||
|
||||
@ -19,7 +19,29 @@
|
||||
<MudListItem T="string" Icon="@Icons.Material.Outlined.Build" Text="@this.VersionDotnetSdk"/>
|
||||
<MudListItem T="string" Icon="@Icons.Material.Outlined.Memory" Text="@this.VersionDotnetRuntime"/>
|
||||
<MudListItem T="string" Icon="@Icons.Material.Outlined.Build" Text="@this.VersionRust"/>
|
||||
<MudListItem T="string" Icon="@Icons.Material.Outlined.Storage" Text="@this.VersionQdrant"/>
|
||||
<MudListItem T="string" Icon="@Icons.Material.Outlined.Storage">
|
||||
<MudText Typo="Typo.body1">
|
||||
@this.VersionDatabase
|
||||
</MudText>
|
||||
<MudCollapse Expanded="@showDatabaseDetails">
|
||||
<MudText Typo="Typo.body1" Class="mt-2 mb-2">
|
||||
@foreach (var (Label, Value) in DatabaseClient.GetDisplayInfo())
|
||||
{
|
||||
<div style="display: flex; align-items: center; gap: 8px;">
|
||||
<MudIcon Icon="@Icons.Material.Filled.ArrowRightAlt"/>
|
||||
<span>@Label: @Value</span>
|
||||
<MudCopyClipboardButton TooltipMessage="@(T("Copies the following to the clipboard")+": "+Value)" StringContent=@Value/>
|
||||
</div>
|
||||
}
|
||||
</MudText>
|
||||
</MudCollapse>
|
||||
<MudButton StartIcon="@(this.showDatabaseDetails ? Icons.Material.Filled.ExpandLess : Icons.Material.Filled.ExpandMore)"
|
||||
Size="Size.Small"
|
||||
Variant="Variant.Text"
|
||||
OnClick="@this.ToggleDatabaseDetails">
|
||||
@(this.showDatabaseDetails ? T("Hide Details") : T("Show Details"))
|
||||
</MudButton>
|
||||
</MudListItem>
|
||||
<MudListItem T="string" Icon="@Icons.Material.Outlined.DocumentScanner" Text="@this.VersionPdfium"/>
|
||||
<MudListItem T="string" Icon="@Icons.Material.Outlined.Article" Text="@this.versionPandoc"/>
|
||||
<MudListItem T="string" Icon="@Icons.Material.Outlined.Widgets" Text="@MudBlazorVersion"/>
|
||||
|
||||
@ -2,6 +2,7 @@ using System.Reflection;
|
||||
|
||||
using AIStudio.Components;
|
||||
using AIStudio.Dialogs;
|
||||
using AIStudio.Tools.Databases;
|
||||
using AIStudio.Tools.Metadata;
|
||||
using AIStudio.Tools.PluginSystem;
|
||||
using AIStudio.Tools.Rust;
|
||||
@ -26,6 +27,9 @@ public partial class About : MSGComponentBase
|
||||
[Inject]
|
||||
private ISnackbar Snackbar { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
private DatabaseClient DatabaseClient { get; init; } = null!;
|
||||
|
||||
private static readonly Assembly ASSEMBLY = Assembly.GetExecutingAssembly();
|
||||
private static readonly MetaDataAttribute META_DATA = ASSEMBLY.GetCustomAttribute<MetaDataAttribute>()!;
|
||||
private static readonly MetaDataArchitectureAttribute META_DATA_ARCH = ASSEMBLY.GetCustomAttribute<MetaDataArchitectureAttribute>()!;
|
||||
@ -54,7 +58,7 @@ public partial class About : MSGComponentBase
|
||||
|
||||
private string VersionPdfium => $"{T("Used PDFium version")}: v{META_DATA_LIBRARIES.PdfiumVersion}";
|
||||
|
||||
private string VersionQdrant => $"{T("Used Qdrant version")}: {META_DATA_DATABASES.QdrantVersion}";
|
||||
private string VersionDatabase => $"{T("Database version")}: {this.DatabaseClient.Name} v{META_DATA_DATABASES.DatabaseVersion}";
|
||||
|
||||
private string versionPandoc = TB("Determine Pandoc version, please wait...");
|
||||
private PandocInstallation pandocInstallation;
|
||||
@ -63,6 +67,8 @@ public partial class About : MSGComponentBase
|
||||
|
||||
private bool showEnterpriseConfigDetails;
|
||||
|
||||
private bool showDatabaseDetails = false;
|
||||
|
||||
private IPluginMetadata? configPlug = PluginFactory.AvailablePlugins.FirstOrDefault(x => x.Type is PluginType.CONFIGURATION);
|
||||
|
||||
/// <summary>
|
||||
@ -173,6 +179,11 @@ public partial class About : MSGComponentBase
|
||||
{
|
||||
this.showEnterpriseConfigDetails = !this.showEnterpriseConfigDetails;
|
||||
}
|
||||
|
||||
private void ToggleDatabaseDetails()
|
||||
{
|
||||
this.showDatabaseDetails = !this.showDatabaseDetails;
|
||||
}
|
||||
|
||||
private async Task CopyStartupLogPath()
|
||||
{
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
using AIStudio.Agents;
|
||||
using AIStudio.Settings;
|
||||
using AIStudio.Tools.Databases;
|
||||
using AIStudio.Tools.Databases.Qdrant;
|
||||
using AIStudio.Tools.PluginSystem;
|
||||
using AIStudio.Tools.Rust;
|
||||
using AIStudio.Tools.Services;
|
||||
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
||||
@ -82,6 +85,24 @@ internal sealed class Program
|
||||
return;
|
||||
}
|
||||
|
||||
var qdrantInfo = await rust.GetQdrantInfo();
|
||||
if (qdrantInfo.Path == String.Empty)
|
||||
{
|
||||
Console.WriteLine("Error: Failed to get the Qdrant path from Rust.");
|
||||
return;
|
||||
}
|
||||
if (qdrantInfo.PortHttp == 0)
|
||||
{
|
||||
Console.WriteLine("Error: Failed to get the Qdrant HTTP port from Rust.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (qdrantInfo.PortGrpc == 0)
|
||||
{
|
||||
Console.WriteLine("Error: Failed to get the Qdrant gRPC port from Rust.");
|
||||
return;
|
||||
}
|
||||
|
||||
var builder = WebApplication.CreateBuilder();
|
||||
|
||||
builder.WebHost.ConfigureKestrel(kestrelServerOptions =>
|
||||
@ -133,6 +154,7 @@ internal sealed class Program
|
||||
builder.Services.AddHostedService<UpdateService>();
|
||||
builder.Services.AddHostedService<TemporaryChatService>();
|
||||
builder.Services.AddHostedService<EnterpriseEnvironmentService>();
|
||||
builder.Services.AddSingleton<DatabaseClient>(new QdrantClient("Qdrant", qdrantInfo.Path, qdrantInfo.PortHttp, qdrantInfo.PortGrpc));
|
||||
|
||||
// ReSharper disable AccessToDisposedClosure
|
||||
builder.Services.AddHostedService<RustService>(_ => rust);
|
||||
@ -215,6 +237,7 @@ internal sealed class Program
|
||||
await rust.AppIsReady();
|
||||
programLogger.LogInformation("The AI Studio server is ready.");
|
||||
|
||||
|
||||
TaskScheduler.UnobservedTaskException += (sender, taskArgs) =>
|
||||
{
|
||||
programLogger.LogError(taskArgs.Exception, $"Unobserved task exception by sender '{sender ?? "n/a"}'.");
|
||||
|
||||
@ -77,7 +77,6 @@ public record Profile(
|
||||
|
||||
public static bool TryParseProfileTable(int idx, LuaTable table, Guid configPluginId, out ConfigurationBaseObject template)
|
||||
{
|
||||
LOGGER.LogInformation($"\n Profile table parsing {idx}.\n");
|
||||
template = NO_PROFILE;
|
||||
if (!table.TryGetValue("Id", out var idValue) || !idValue.TryRead<string>(out var idText) || !Guid.TryParse(idText, out var id))
|
||||
{
|
||||
|
||||
71
app/MindWork AI Studio/Tools/Databases/DatabaseClient.cs
Normal file
71
app/MindWork AI Studio/Tools/Databases/DatabaseClient.cs
Normal file
@ -0,0 +1,71 @@
|
||||
namespace AIStudio.Tools.Databases;
|
||||
|
||||
public abstract class DatabaseClient
|
||||
{
|
||||
public string Name { get; }
|
||||
private string Path { get; }
|
||||
|
||||
public DatabaseClient(string name, string path)
|
||||
{
|
||||
this.Name = name;
|
||||
this.Path = path;
|
||||
}
|
||||
|
||||
public abstract IEnumerable<(string Label, string Value)> GetDisplayInfo();
|
||||
|
||||
public string GetStorageSize()
|
||||
{
|
||||
if (string.IsNullOrEmpty(this.Path))
|
||||
{
|
||||
Console.WriteLine($"Error: Database path '{this.Path}' cannot be null or empty.");
|
||||
return "0 B";
|
||||
}
|
||||
|
||||
if (!Directory.Exists(this.Path))
|
||||
{
|
||||
Console.WriteLine($"Error: Database path '{this.Path}' does not exist.");
|
||||
return "0 B";
|
||||
}
|
||||
long size = 0;
|
||||
var stack = new Stack<string>();
|
||||
stack.Push(this.Path);
|
||||
while (stack.Count > 0)
|
||||
{
|
||||
string directory = stack.Pop();
|
||||
try
|
||||
{
|
||||
var files = Directory.GetFiles(directory);
|
||||
size += files.Sum(file => new FileInfo(file).Length);
|
||||
var subDirectories = Directory.GetDirectories(directory);
|
||||
foreach (var subDirectory in subDirectories)
|
||||
{
|
||||
stack.Push(subDirectory);
|
||||
}
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
Console.WriteLine($"No access to {directory}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"An error encountered while processing {directory}: ");
|
||||
Console.WriteLine($"{ ex.Message}");
|
||||
}
|
||||
}
|
||||
return FormatBytes(size);
|
||||
}
|
||||
|
||||
public static string FormatBytes(long size)
|
||||
{
|
||||
string[] suffixes = { "B", "KB", "MB", "GB", "TB", "PB" };
|
||||
int suffixIndex = 0;
|
||||
|
||||
while (size >= 1024 && suffixIndex < suffixes.Length - 1)
|
||||
{
|
||||
size /= 1024;
|
||||
suffixIndex++;
|
||||
}
|
||||
|
||||
return $"{size:0##} {suffixes[suffixIndex]}";
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
namespace AIStudio.Tools.Databases.Qdrant;
|
||||
|
||||
public class QdrantClient(string name, string path, int httpPort, int grpcPort) : DatabaseClient(name, path)
|
||||
{
|
||||
private int HttpPort { get; } = httpPort;
|
||||
private int GrpcPort { get; } = grpcPort;
|
||||
private string IpAddress { get; } = "127.0.0.1";
|
||||
|
||||
public override IEnumerable<(string Label, string Value)> GetDisplayInfo()
|
||||
{
|
||||
yield return ("HTTP Port", this.HttpPort.ToString());
|
||||
yield return ("gRPC Port", this.GrpcPort.ToString());
|
||||
yield return ("Storage Size", $"{base.GetStorageSize()}");
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
namespace AIStudio.Tools.Metadata;
|
||||
|
||||
public class MetaDataDatabasesAttribute(string qdrantVersion) : Attribute
|
||||
public class MetaDataDatabasesAttribute(string databaseVersion) : Attribute
|
||||
{
|
||||
public string QdrantVersion => qdrantVersion;
|
||||
public string DatabaseVersion => databaseVersion;
|
||||
}
|
||||
13
app/MindWork AI Studio/Tools/Rust/QdrantInfo.cs
Normal file
13
app/MindWork AI Studio/Tools/Rust/QdrantInfo.cs
Normal file
@ -0,0 +1,13 @@
|
||||
namespace AIStudio.Tools.Rust;
|
||||
|
||||
/// <summary>
|
||||
/// The response of the Qdrant information request.
|
||||
/// </summary>
|
||||
/// <param name="portHTTP">The port number for HTTP communication with Qdrant.</param>
|
||||
/// <param name="portGRPC">The port number for gRPC communication with Qdrant</param>
|
||||
public record struct QdrantInfo
|
||||
{
|
||||
public string Path { get; init; }
|
||||
public int PortHttp { get; init; }
|
||||
public int PortGrpc { get; init; }
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
using AIStudio.Tools.Rust;
|
||||
|
||||
namespace AIStudio.Tools.Services;
|
||||
|
||||
public sealed partial class RustService
|
||||
{
|
||||
public async Task<QdrantInfo> GetQdrantInfo()
|
||||
{
|
||||
try
|
||||
{
|
||||
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(45));
|
||||
var response = await this.http.GetFromJsonAsync<QdrantInfo>("/system/qdrant/port", this.jsonRustSerializerOptions, cts.Token);
|
||||
return response;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
return new QdrantInfo
|
||||
{
|
||||
Path = string.Empty,
|
||||
PortHttp = 0,
|
||||
PortGrpc = 0,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1 +1,2 @@
|
||||
# v0.9.55, build 230 (2025-12-xx xx:xx UTC)
|
||||
Added functionality to download Qdrant and execute it as a background sidecar.
|
||||
@ -9,4 +9,4 @@
|
||||
009bb33d839, release
|
||||
osx-arm64
|
||||
137.0.7215.0
|
||||
v1.16.1
|
||||
1.16.1
|
||||
@ -235,15 +235,15 @@ service:
|
||||
max_workers: 0
|
||||
|
||||
# Host to bind the service on
|
||||
host: 0.0.0.0
|
||||
host: 127.0.0.1
|
||||
|
||||
# HTTP(S) port to bind the service on
|
||||
http_port: 6373
|
||||
# http_port: 6333
|
||||
|
||||
# gRPC port to bind the service on.
|
||||
# If `null` - gRPC is disabled. Default: null
|
||||
# Comment to disable gRPC:
|
||||
grpc_port: 6344
|
||||
# grpc_port: 6334
|
||||
|
||||
# Enable CORS headers in REST API.
|
||||
# If enabled, browsers would be allowed to query REST endpoints regardless of query origin.
|
||||
@ -326,7 +326,7 @@ cluster:
|
||||
|
||||
# Set to true to prevent service from sending usage statistics to the developers.
|
||||
# Read more: https://qdrant.tech/documentation/guides/telemetry
|
||||
telemetry_disabled: false
|
||||
telemetry_disabled: true
|
||||
|
||||
# TLS configuration.
|
||||
# Required if either service.enable_tls or cluster.p2p.enable_tls is true.
|
||||
|
||||
@ -38,7 +38,7 @@ async fn main() {
|
||||
info!(".. MudBlazor: v{mud_blazor_version}", mud_blazor_version = metadata.mud_blazor_version);
|
||||
info!(".. Tauri: v{tauri_version}", tauri_version = metadata.tauri_version);
|
||||
info!(".. PDFium: v{pdfium_version}", pdfium_version = metadata.pdfium_version);
|
||||
info!(".. Qdrant: {qdrant_version}", qdrant_version = metadata.qdrant_version);
|
||||
info!(".. Qdrant: v{qdrant_version}", qdrant_version = metadata.qdrant_version);
|
||||
|
||||
if is_dev() {
|
||||
warn!("Running in development mode.");
|
||||
|
||||
@ -4,8 +4,9 @@ use std::sync::{Arc, Mutex};
|
||||
use log::{debug, error, info, warn};
|
||||
use once_cell::sync::Lazy;
|
||||
use rocket::get;
|
||||
use rocket::serde::json::Json;
|
||||
use rocket::serde::Serialize;
|
||||
use tauri::api::process::{Command, CommandChild, CommandEvent};
|
||||
use tauri::Url;
|
||||
use crate::api_token::{APIToken};
|
||||
use crate::environment::DATA_DIRECTORY;
|
||||
|
||||
@ -14,16 +15,28 @@ use crate::environment::DATA_DIRECTORY;
|
||||
static QDRANT_SERVER: Lazy<Arc<Mutex<Option<CommandChild>>>> = Lazy::new(|| Arc::new(Mutex::new(None)));
|
||||
|
||||
// Qdrant server port (default is 6333 for HTTP and 6334 for gRPC)
|
||||
static QDRANT_SERVER_PORT: Lazy<u16> = Lazy::new(|| {
|
||||
static QDRANT_SERVER_PORT_HTTP: Lazy<u16> = Lazy::new(|| {
|
||||
crate::network::get_available_port().unwrap_or(6333)
|
||||
});
|
||||
});
|
||||
|
||||
static QDRANT_INITIALIZED: Lazy<Mutex<bool>> = Lazy::new(|| Mutex::new(false));
|
||||
static QDRANT_SERVER_PORT_GRPC: Lazy<u16> = Lazy::new(|| {
|
||||
crate::network::get_available_port().unwrap_or(6334)
|
||||
});
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct ProvideQdrantInfo {
|
||||
path: String,
|
||||
port_http: u16,
|
||||
port_grpc: u16,
|
||||
}
|
||||
|
||||
#[get("/system/qdrant/port")]
|
||||
pub fn qdrant_port(_token: APIToken) -> String {
|
||||
let qdrant_port = *QDRANT_SERVER_PORT;
|
||||
format!("{qdrant_port}")
|
||||
pub fn qdrant_port(_token: APIToken) -> Json<ProvideQdrantInfo> {
|
||||
return Json(ProvideQdrantInfo {
|
||||
path: Path::new(DATA_DIRECTORY.get().unwrap()).join("databases").join("qdrant").to_str().unwrap().to_string(),
|
||||
port_http: *QDRANT_SERVER_PORT_HTTP,
|
||||
port_grpc: *QDRANT_SERVER_PORT_GRPC,
|
||||
});
|
||||
}
|
||||
|
||||
/// Starts the Qdrant server in a separate process.
|
||||
@ -35,16 +48,14 @@ pub fn start_qdrant_server() {
|
||||
let snapshot_path = Path::new(base_path).join("databases").join("qdrant").join("snapshots").to_str().unwrap().to_string();
|
||||
let init_path = Path::new(base_path).join("databases").join("qdrant").join(".qdrant-initalized").to_str().unwrap().to_string();
|
||||
|
||||
println!("{}", storage_path);
|
||||
println!("{}", snapshot_path);
|
||||
println!("{}", init_path);
|
||||
|
||||
let qdrant_server_environment = HashMap::from_iter([
|
||||
(String::from("QDRANT__SERVICE__HTTP_PORT"), QDRANT_SERVER_PORT.to_string()),
|
||||
(String::from("QDRANT__SERVICE__HTTP_PORT"), QDRANT_SERVER_PORT_HTTP.to_string()),
|
||||
(String::from("QDRANT__SERVICE__GRPC_PORT"), QDRANT_SERVER_PORT_GRPC.to_string()),
|
||||
(String::from("QDRANT_INIT_FILE_PATH"), init_path),
|
||||
(String::from("QDRANT__STORAGE__STORAGE_PATH"), storage_path),
|
||||
(String::from("QDRANT__STORAGE__SNAPSHOTS_PATH"), snapshot_path),
|
||||
]);
|
||||
|
||||
let server_spawn_clone = QDRANT_SERVER.clone();
|
||||
tauri::async_runtime::spawn(async move {
|
||||
let (mut rx, child) = Command::new_sidecar("qdrant")
|
||||
@ -84,30 +95,6 @@ pub fn start_qdrant_server() {
|
||||
});
|
||||
}
|
||||
|
||||
/// This endpoint is called by the Qdrant server or frontend to signal that Qdrant is ready.
|
||||
#[get("/system/qdrant/ready")]
|
||||
pub async fn qdrant_ready(_token: APIToken) {
|
||||
{
|
||||
let mut initialized = QDRANT_INITIALIZED.lock().unwrap();
|
||||
if *initialized {
|
||||
warn!("Qdrant server was already initialized.");
|
||||
return;
|
||||
}
|
||||
info!("Qdrant server is ready.");
|
||||
*initialized = true;
|
||||
}
|
||||
|
||||
let qdrant_port = *QDRANT_SERVER_PORT;
|
||||
let _url = match Url::parse(format!("http://localhost:{qdrant_port}").as_str()) {
|
||||
Ok(url) => url,
|
||||
Err(msg) => {
|
||||
error!("Error while parsing Qdrant URL: {msg}");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/// Stops the Qdrant server process.
|
||||
pub fn stop_qdrant_server() {
|
||||
if let Some(server_process) = QDRANT_SERVER.lock().unwrap().take() {
|
||||
|
||||
@ -67,6 +67,7 @@ pub fn start_runtime_api() {
|
||||
.mount("/", routes![
|
||||
crate::dotnet::dotnet_port,
|
||||
crate::dotnet::dotnet_ready,
|
||||
crate::qdrant::qdrant_port,
|
||||
crate::clipboard::set_clipboard,
|
||||
crate::app_window::get_event_stream,
|
||||
crate::app_window::check_for_update,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user