Files
nibbleai/src/proofreading/Proofreader.ts
T
olivier 9b7ec36828 Unify AI provider selection across all features
Every LLM-backed feature (Post-Processing, Proofreading, Title
Generation, Property Filler) now reads from one CHAT_PROVIDERS
registry instead of 5 hand-duplicated provider lists, so they always
offer the exact same providers in the exact same order.

- Add Groq as a 5th chat-completion provider (was transcription-only
  despite its OpenAI-compatible API and an already-collected key).
- Provider dropdowns disable options with no API key configured
  (shown as e.g. "Anthropic (no API key)") instead of silently
  failing at runtime when picked.
- Collapse 3 byte-for-byte duplicated resolveProvider() methods
  (Proofreader, TitleGenerator, PropertyFiller) plus AudioHandler's
  getPostProcessingApiKey() into one resolveChatProvider() helper
  (src/ProviderResolver.ts).
- Fix Custom provider: previously Proofreading/Title/Property silently
  reused Post-Processing's postProcessingUrl with no visible field to
  set it. Renamed to a shared customApiUrl field with its own UI
  (createCustomProviderFields), now exposed on every tab that offers
  Custom, plus rows on the API Keys tab. Migrates old data.json values
  automatically.
- Update README settings reference and getting-started sections to
  match.

No behavior change for existing single-provider setups; migration
handles the postProcessingUrl -> customApiUrl rename transparently.
2026-09-07 17:14:33 -04:00

65 lines
1.8 KiB
TypeScript

import { Editor, Notice } from "obsidian";
import { AIService } from "../AIService";
import { resolveChatProvider } from "../ProviderResolver";
import NibbleAI from "main";
export class Proofreader {
private plugin: NibbleAI;
constructor(plugin: NibbleAI) {
this.plugin = plugin;
}
async fixSelection(editor: Editor): Promise<void> {
const selection = editor.getSelection();
if (!selection || selection.trim().length === 0) {
new Notice("No text selected.");
return;
}
const config = resolveChatProvider(
this.plugin.settings,
this.plugin.settings.proofreadingProvider || "openrouter"
);
if (!config) {
new Notice(
"⚠️ No API key for selected provider. Check Settings \u2192 NibbleAI \u2192 API Keys."
);
return;
}
new Notice("🤖 Fixing punctuation and grammar...");
try {
const systemPrompt =
this.plugin.settings.proofreadingSystemPrompt ||
"You are a text proofreading tool. Fix punctuation and grammar in the text below. Return only the corrected text, nothing else.";
const corrected = await AIService.callChatCompletion(
selection,
systemPrompt,
{
apiKey: config.apiKey,
model: this.plugin.settings.proofreadingModel,
endpoint: config.endpoint,
provider: config.provider,
temperature: this.plugin.settings.proofreadingTemperature,
maxTokens: this.plugin.settings.proofreadingMaxTokens,
}
);
if (!corrected || corrected.trim().length === 0) {
new Notice("⚠️ AI returned empty result. No changes made.");
return;
}
editor.replaceSelection(corrected);
new Notice("✅ Punctuation and grammar fixed.");
} catch (error) {
console.error("Proofreading error:", error);
new Notice(
`❌ Fix failed: ${error instanceof Error ? error.message : String(error)}`
);
}
}
}