✅ What's Working: Plugin loads successfully in Obsidian Settings are being saved correctly to disk Qdrant server is accessible and responding Ollama is set up with the embedding model UUID generation fixed for Qdrant compatibility ❌ Main Issue: Plugin is using default localhost:6333 URL instead of your saved https://vectors.biohazardvfx.com URL This is a settings initialization timing problem 🎯 Next Step: Fix the IndexingOrchestrator to use the loaded settings instead of defaults This is likely a simple fix - the orchestrator needs to reference this.settings that were loaded from data.json Progress: ~95% complete - just need to fix this one settings issue and then test the full indexing + search workflow!
221 lines
6.1 KiB
TypeScript
221 lines
6.1 KiB
TypeScript
import { App, Notice, Plugin, TFile } from 'obsidian';
|
|
import { PluginSettings, IndexingProgress } from './src/types';
|
|
import { DEFAULT_SETTINGS, validateSettings } from './src/settings';
|
|
import { IndexingOrchestrator } from './src/indexing/orchestrator';
|
|
import { SearchModal } from './src/search/searchModal';
|
|
import { QdrantSettingsTab } from './src/ui/settingsTab';
|
|
|
|
export default class QdrantPlugin extends Plugin {
|
|
settings: PluginSettings;
|
|
private indexingOrchestrator: IndexingOrchestrator | null = null;
|
|
private statusBarItem: HTMLElement | null = null;
|
|
|
|
async onload() {
|
|
console.log('Qdrant Semantic Search plugin loading...');
|
|
|
|
try {
|
|
await this.loadSettings();
|
|
console.log('Settings loaded successfully');
|
|
|
|
// Validate settings
|
|
const errors = validateSettings(this.settings);
|
|
if (errors.length > 0) {
|
|
console.warn('Settings validation warnings:', errors);
|
|
new Notice('Qdrant: Please configure settings. Settings validation warnings: ' + errors.join(', '));
|
|
}
|
|
|
|
// Add status bar item first
|
|
this.setupStatusBar();
|
|
console.log('Status bar added');
|
|
|
|
// Add commands
|
|
this.addCommands();
|
|
console.log('Commands registered');
|
|
|
|
// Add settings tab
|
|
this.addSettingTab(new QdrantSettingsTab(this.app, this));
|
|
console.log('Settings tab added');
|
|
|
|
// Initialize indexing orchestrator (non-blocking)
|
|
this.initializeOrchestrator();
|
|
|
|
console.log('Qdrant Semantic Search plugin loaded successfully');
|
|
new Notice('Qdrant Semantic Search loaded! Configure settings before indexing.');
|
|
} catch (error) {
|
|
console.error('Failed to load Qdrant plugin:', error);
|
|
new Notice('Failed to load Qdrant plugin: ' + (error as Error).message);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
private async initializeOrchestrator() {
|
|
try {
|
|
console.log('Initializing indexing orchestrator...');
|
|
this.indexingOrchestrator = new IndexingOrchestrator(this.app, this.settings);
|
|
await this.indexingOrchestrator.initialize();
|
|
|
|
// Set up progress tracking
|
|
this.setupProgressTracking();
|
|
|
|
console.log('Indexing orchestrator initialized successfully');
|
|
this.updateStatusBar('Ready');
|
|
} catch (error) {
|
|
console.error('Failed to initialize indexing orchestrator:', error);
|
|
console.error('Stack trace:', (error as Error).stack);
|
|
new Notice('Qdrant: Indexing system not ready. Please check settings and connection.');
|
|
this.updateStatusBar('Not configured');
|
|
}
|
|
}
|
|
|
|
onunload() {
|
|
// Shutdown indexing orchestrator
|
|
if (this.indexingOrchestrator) {
|
|
this.indexingOrchestrator.shutdown();
|
|
}
|
|
}
|
|
|
|
async loadSettings() {
|
|
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
|
|
}
|
|
|
|
async saveSettings() {
|
|
await this.saveData(this.settings);
|
|
}
|
|
|
|
private setupStatusBar() {
|
|
this.statusBarItem = this.addStatusBarItem();
|
|
this.updateStatusBar('Ready');
|
|
}
|
|
|
|
private addCommands() {
|
|
// Semantic search command
|
|
this.addCommand({
|
|
id: 'semantic-search',
|
|
name: 'Semantic search',
|
|
callback: () => {
|
|
if (!this.indexingOrchestrator?.isReady()) {
|
|
new Notice('Indexing system not ready. Please check your settings.');
|
|
return;
|
|
}
|
|
new SearchModal(this.app, this.settings).open();
|
|
}
|
|
});
|
|
|
|
// Index current file command
|
|
this.addCommand({
|
|
id: 'index-current-file',
|
|
name: 'Index current file',
|
|
checkCallback: (checking: boolean) => {
|
|
const activeFile = this.app.workspace.getActiveFile();
|
|
if (activeFile instanceof TFile) {
|
|
if (!checking) {
|
|
this.indexFile(activeFile);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
});
|
|
|
|
// Full reindex command
|
|
this.addCommand({
|
|
id: 'full-reindex',
|
|
name: 'Full reindex vault',
|
|
callback: () => {
|
|
this.indexFullVault();
|
|
}
|
|
});
|
|
|
|
// Clear index command
|
|
this.addCommand({
|
|
id: 'clear-index',
|
|
name: 'Clear index',
|
|
callback: () => {
|
|
this.clearIndex();
|
|
}
|
|
});
|
|
|
|
// Open graph view command
|
|
if (this.settings.enableGraphView) {
|
|
this.addCommand({
|
|
id: 'open-graph-view',
|
|
name: 'Open graph view',
|
|
callback: () => {
|
|
// TODO: Implement graph view
|
|
new Notice('Graph view not yet implemented');
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
private setupProgressTracking() {
|
|
if (!this.indexingOrchestrator) return;
|
|
|
|
this.indexingOrchestrator.setProgressCallback((progress: IndexingProgress) => {
|
|
this.updateStatusBar(progress);
|
|
});
|
|
|
|
this.indexingOrchestrator.setErrorCallback((error: string) => {
|
|
new Notice('Indexing error: ' + error);
|
|
});
|
|
}
|
|
|
|
private updateStatusBar(progress: IndexingProgress | string) {
|
|
if (!this.statusBarItem) return;
|
|
|
|
if (typeof progress === 'string') {
|
|
this.statusBarItem.setText(`Qdrant: ${progress}`);
|
|
return;
|
|
}
|
|
|
|
if (progress.isRunning) {
|
|
const percentage = progress.totalFiles > 0
|
|
? Math.round((progress.processedFiles / progress.totalFiles) * 100)
|
|
: 0;
|
|
this.statusBarItem.setText(`Qdrant: Indexing ${percentage}% (${progress.processedFiles}/${progress.totalFiles})`);
|
|
} else {
|
|
this.statusBarItem.setText('Qdrant: Ready');
|
|
}
|
|
}
|
|
|
|
// Public methods for settings tab
|
|
async testQdrantConnection(): Promise<boolean> {
|
|
if (!this.indexingOrchestrator) return false;
|
|
const connections = await this.indexingOrchestrator.testConnections();
|
|
return connections.qdrant;
|
|
}
|
|
|
|
async testOllamaConnection(): Promise<boolean> {
|
|
if (!this.indexingOrchestrator) return false;
|
|
const connections = await this.indexingOrchestrator.testConnections();
|
|
return connections.embedding;
|
|
}
|
|
|
|
async indexFullVault(): Promise<void> {
|
|
if (!this.indexingOrchestrator?.isReady()) {
|
|
throw new Error('Indexing system not ready');
|
|
}
|
|
await this.indexingOrchestrator.indexFullVault();
|
|
}
|
|
|
|
async indexFile(file: TFile): Promise<void> {
|
|
if (!this.indexingOrchestrator?.isReady()) {
|
|
throw new Error('Indexing system not ready');
|
|
}
|
|
await this.indexingOrchestrator.indexFile(file);
|
|
}
|
|
|
|
async clearIndex(): Promise<void> {
|
|
if (!this.indexingOrchestrator?.isReady()) {
|
|
throw new Error('Indexing system not ready');
|
|
}
|
|
await this.indexingOrchestrator.clearIndex();
|
|
}
|
|
|
|
async getIndexStats(): Promise<any> {
|
|
if (!this.indexingOrchestrator?.isReady()) {
|
|
throw new Error('Indexing system not ready');
|
|
}
|
|
return await this.indexingOrchestrator.getIndexStats();
|
|
}
|
|
} |