yan-istart_IStart-Note-AI-P.../main.js
2026-04-25 15:40:45 +08:00

322 lines
12 KiB
JavaScript

/*
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
if you want to view the source, please visit the github repository of this plugin
*/
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/main.ts
var main_exports = {};
__export(main_exports, {
default: () => DeepSeekPlugin
});
module.exports = __toCommonJS(main_exports);
var import_obsidian4 = require("obsidian");
// src/types.ts
var DEFAULT_SETTINGS = {
apiKey: "",
baseUrl: "https://api.deepseek.com",
model: "deepseek-chat",
savePath: "Knowledge/Q&A",
autoOpenGraph: false
};
// src/DeepSeekClient.ts
var SYSTEM_PROMPT = `\u4F60\u662F\u4E00\u4E2A\u77E5\u8BC6\u56FE\u8C31\u6784\u5EFA\u52A9\u624B\u3002\u7528\u6237\u4F1A\u5411\u4F60\u63D0\u95EE\uFF0C\u4F60\u9700\u8981\uFF1A
1. \u7ED9\u51FA\u6E05\u6670\u7684\u56DE\u7B54
2. \u63D0\u53D6\u5173\u952E\u6982\u5FF5\uFF083-7\u4E2A\uFF09
3. \u8BC6\u522B\u6982\u5FF5\u95F4\u7684\u5173\u7CFB\uFF08\u9650\u4E8E\uFF1A\u5F71\u54CD\u3001\u5C5E\u4E8E\u3001\u5BFC\u81F4\u3001\u4F9D\u8D56\u3001\u5BF9\u7ACB\uFF09
4. \u751F\u6210\u76F8\u5173\u6807\u7B7E\uFF082-5\u4E2A\uFF09
\u4E25\u683C\u6309\u7167\u4EE5\u4E0B JSON \u683C\u5F0F\u8FD4\u56DE\uFF0C\u4E0D\u8981\u6709\u4EFB\u4F55\u5176\u4ED6\u5185\u5BB9\uFF1A
{
"answer": "\u8BE6\u7EC6\u56DE\u7B54",
"concepts": ["\u6982\u5FF5A", "\u6982\u5FF5B"],
"relations": [
{ "from": "\u6982\u5FF5A", "relation": "\u5F71\u54CD", "to": "\u6982\u5FF5B" }
],
"tags": ["\u6807\u7B7E1", "\u6807\u7B7E2"]
}`;
var DeepSeekClient = class {
constructor(settings) {
this.settings = settings;
}
async ask(question) {
var _a, _b, _c;
if (!this.settings.apiKey) {
throw new Error("\u8BF7\u5148\u5728\u63D2\u4EF6\u8BBE\u7F6E\u4E2D\u914D\u7F6E DeepSeek API Key");
}
const response = await fetch(`${this.settings.baseUrl}/v1/chat/completions`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${this.settings.apiKey}`
},
body: JSON.stringify({
model: this.settings.model,
messages: [
{ role: "system", content: SYSTEM_PROMPT },
{ role: "user", content: question }
],
temperature: 0.7
})
});
if (!response.ok) {
const err = await response.text();
throw new Error(`DeepSeek API \u9519\u8BEF: ${response.status} - ${err}`);
}
const data = await response.json();
const content = (_c = (_b = (_a = data.choices) == null ? void 0 : _a[0]) == null ? void 0 : _b.message) == null ? void 0 : _c.content;
if (!content) {
throw new Error("DeepSeek \u8FD4\u56DE\u5185\u5BB9\u4E3A\u7A7A");
}
return this.parseResponse(content);
}
parseResponse(content) {
const jsonMatch = content.match(/```(?:json)?\s*([\s\S]*?)```/) || content.match(/(\{[\s\S]*\})/);
const jsonStr = jsonMatch ? jsonMatch[1] : content;
try {
const parsed = JSON.parse(jsonStr.trim());
return {
answer: parsed.answer || "",
concepts: Array.isArray(parsed.concepts) ? parsed.concepts : [],
relations: Array.isArray(parsed.relations) ? parsed.relations : [],
tags: Array.isArray(parsed.tags) ? parsed.tags : []
};
} catch (e) {
return {
answer: content,
concepts: [],
relations: [],
tags: []
};
}
}
};
// src/VaultWriter.ts
var import_obsidian = require("obsidian");
var VaultWriter = class {
constructor(app, settings) {
this.app = app;
this.settings = settings;
}
async writeQANote(question, response) {
const date = new Date().toISOString().slice(0, 10);
const safeTitle = this.sanitizeFilename(question).slice(0, 50);
const filename = `${date}-${safeTitle}.md`;
const folderPath = (0, import_obsidian.normalizePath)(this.settings.savePath);
const filePath = (0, import_obsidian.normalizePath)(`${folderPath}/${filename}`);
await this.ensureFolder(folderPath);
const content = this.buildNoteContent(question, response);
const file = await this.app.vault.create(filePath, content);
for (const concept of response.concepts) {
await this.ensureConceptNote(concept);
}
return file;
}
buildNoteContent(question, response) {
const conceptLinks = response.concepts.map((c) => `- [[${c}]]`).join("\n");
const relationLines = response.relations.map((r) => `- [[${r.from}]] -${r.relation}-> [[${r.to}]]`).join("\n");
const tagLine = response.tags.map((t) => `#${t.replace(/\s+/g, "_")}`).join(" ");
return `# ${question}
## Question
${question}
## Answer
${response.answer}
## Concepts
${conceptLinks || "- \u6682\u65E0"}
## Relations
${relationLines || "- \u6682\u65E0"}
## Tags
${tagLine || "\u6682\u65E0\u6807\u7B7E"}
`;
}
async ensureConceptNote(concept) {
const folderPath = (0, import_obsidian.normalizePath)("Knowledge/Concepts");
const filePath = (0, import_obsidian.normalizePath)(`${folderPath}/${concept}.md`);
await this.ensureFolder(folderPath);
const exists = this.app.vault.getAbstractFileByPath(filePath);
if (!exists) {
await this.app.vault.create(
filePath,
`# ${concept}
## \u5B9A\u4E49
## \u5173\u8054
## \u6765\u6E90
`
);
}
}
async ensureFolder(path) {
const exists = this.app.vault.getAbstractFileByPath(path);
if (!exists) {
await this.app.vault.createFolder(path);
}
}
sanitizeFilename(name) {
return name.replace(/[\\/:*?"<>|#\[\]]/g, "-").trim();
}
};
// src/QuestionModal.ts
var import_obsidian2 = require("obsidian");
var QuestionModal = class extends import_obsidian2.Modal {
constructor(app, onSubmit) {
super(app);
this.question = "";
this.onSubmit = onSubmit;
}
onOpen() {
const { contentEl } = this;
contentEl.createEl("h2", { text: "\u5411 DeepSeek \u63D0\u95EE" });
const textArea = contentEl.createEl("textarea", {
attr: {
placeholder: "\u8F93\u5165\u4F60\u7684\u95EE\u9898...",
rows: "4",
style: "width:100%; resize:vertical; padding:8px; font-size:14px;"
}
});
textArea.addEventListener("input", () => {
this.question = textArea.value;
});
textArea.addEventListener("keydown", (e) => {
if ((e.ctrlKey || e.metaKey) && e.key === "Enter") {
this.submit();
}
});
new import_obsidian2.Setting(contentEl).addButton(
(btn) => btn.setButtonText("\u63D0\u95EE (Ctrl+Enter)").setCta().onClick(() => this.submit())
).addButton(
(btn) => btn.setButtonText("\u53D6\u6D88").onClick(() => this.close())
);
setTimeout(() => textArea.focus(), 50);
}
submit() {
const q = this.question.trim();
if (!q)
return;
this.close();
this.onSubmit(q);
}
onClose() {
this.contentEl.empty();
}
};
// src/SettingsTab.ts
var import_obsidian3 = require("obsidian");
var DeepSeekSettingsTab = class extends import_obsidian3.PluginSettingTab {
constructor(app, plugin) {
super(app, plugin);
this.plugin = plugin;
}
display() {
const { containerEl } = this;
containerEl.empty();
containerEl.createEl("h2", { text: "DeepSeek Knowledge Graph \u8BBE\u7F6E" });
new import_obsidian3.Setting(containerEl).setName("API Key").setDesc("DeepSeek API Key\uFF08\u5728 platform.deepseek.com \u83B7\u53D6\uFF09").addText(
(text) => text.setPlaceholder("sk-...").setValue(this.plugin.settings.apiKey).onChange(async (value) => {
this.plugin.settings.apiKey = value.trim();
await this.plugin.saveSettings();
})
);
new import_obsidian3.Setting(containerEl).setName("Base URL").setDesc("API \u5730\u5740\uFF0C\u9ED8\u8BA4 https://api.deepseek.com").addText(
(text) => text.setPlaceholder("https://api.deepseek.com").setValue(this.plugin.settings.baseUrl).onChange(async (value) => {
this.plugin.settings.baseUrl = value.trim() || "https://api.deepseek.com";
await this.plugin.saveSettings();
})
);
new import_obsidian3.Setting(containerEl).setName("\u6A21\u578B").setDesc("\u9009\u62E9\u4F7F\u7528\u7684 DeepSeek \u6A21\u578B").addDropdown(
(drop) => drop.addOption("deepseek-chat", "deepseek-chat\uFF08\u63A8\u8350\uFF09").addOption("deepseek-reasoner", "deepseek-reasoner\uFF08\u6DF1\u5EA6\u63A8\u7406\uFF09").setValue(this.plugin.settings.model).onChange(async (value) => {
this.plugin.settings.model = value;
await this.plugin.saveSettings();
})
);
new import_obsidian3.Setting(containerEl).setName("\u7B14\u8BB0\u4FDD\u5B58\u8DEF\u5F84").setDesc("Q&A \u7B14\u8BB0\u5B58\u50A8\u76EE\u5F55\uFF08\u76F8\u5BF9\u4E8E Vault \u6839\u76EE\u5F55\uFF09").addText(
(text) => text.setPlaceholder("Knowledge/Q&A").setValue(this.plugin.settings.savePath).onChange(async (value) => {
this.plugin.settings.savePath = value.trim() || "Knowledge/Q&A";
await this.plugin.saveSettings();
})
);
new import_obsidian3.Setting(containerEl).setName("\u81EA\u52A8\u6253\u5F00 Graph View").setDesc("\u751F\u6210\u7B14\u8BB0\u540E\u81EA\u52A8\u6253\u5F00\u56FE\u8C31\u89C6\u56FE").addToggle(
(toggle) => toggle.setValue(this.plugin.settings.autoOpenGraph).onChange(async (value) => {
this.plugin.settings.autoOpenGraph = value;
await this.plugin.saveSettings();
})
);
}
};
// src/main.ts
var DeepSeekPlugin = class extends import_obsidian4.Plugin {
async onload() {
await this.loadSettings();
this.addRibbonIcon("brain", "DeepSeek \u63D0\u95EE", () => {
this.openQuestionModal();
});
this.addCommand({
id: "ask-deepseek",
name: "\u5411 DeepSeek \u63D0\u95EE\u5E76\u751F\u6210\u77E5\u8BC6\u7B14\u8BB0",
hotkeys: [{ modifiers: ["Mod", "Shift"], key: "d" }],
callback: () => this.openQuestionModal()
});
this.addSettingTab(new DeepSeekSettingsTab(this.app, this));
}
openQuestionModal() {
new QuestionModal(this.app, (question) => {
this.processQuestion(question);
}).open();
}
async processQuestion(question) {
const notice = new import_obsidian4.Notice("\u23F3 DeepSeek \u601D\u8003\u4E2D...", 0);
try {
const client = new DeepSeekClient(this.settings);
const response = await client.ask(question);
const writer = new VaultWriter(this.app, this.settings);
const file = await writer.writeQANote(question, response);
notice.hide();
new import_obsidian4.Notice(`\u2705 \u7B14\u8BB0\u5DF2\u751F\u6210\uFF1A${file.name}`);
const leaf = this.app.workspace.getLeaf(false);
await leaf.openFile(file);
if (this.settings.autoOpenGraph) {
this.app.commands.executeCommandById("graph:open");
}
} catch (err) {
notice.hide();
new import_obsidian4.Notice(`\u274C \u9519\u8BEF\uFF1A${err.message}`);
console.error("[DeepSeek Plugin]", err);
}
}
async loadSettings() {
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
}
async saveSettings() {
await this.saveData(this.settings);
}
};