mirror of
https://github.com/benstuart0/on-this-day-i-obsidian.git
synced 2026-07-22 05:38:19 +00:00
Remove diet estimates command
This commit is contained in:
parent
1f0b6f0c1a
commit
63813648da
6 changed files with 1 additions and 223 deletions
|
|
@ -9,14 +9,11 @@ This plugin comes with two commands:
|
|||
Adds a custom tag at your cursor location which the generation command looks for and replaces if it is available. The tag can be changed in settings. A tag command and setting should be available for each generation command.
|
||||
### Generate Through The Years
|
||||
Uses AI to find Daily Notes from the same date as your current note in years past. Generates a brief summary of this date for each instance of it through the years and places it in your note.
|
||||
### Generate Diet Estimates
|
||||
Parse your daily journal for food-related lines, and create a `dietEstimates` code-block that estimates your daily calories and macros.
|
||||
## How to Use
|
||||
- Enable the plugin in the settings menu and update the plugin settings accordingly.
|
||||
- Open the command palette and search for On This Day I to see the commands.
|
||||
- If you want the output to be placed at a certain location in your note, add a placeholder (default is <!OTDI>, can be changed in settings). Run the `On This Day I: Add Placeholder at Cursor` command if you'd like to automatically add a placeholder to your note at cursor location.
|
||||
- Run the command `On This Day I: Generate Through The Years` to generate your yearly insights.
|
||||
- Run the command `On This Day I: Generate Diet Estimates` to generate a calorie and macro estimates code-block.
|
||||
### OpenAI
|
||||
- **This plugin makes a network call to the OpenAI API to generate the journal summaries.**
|
||||
- Must have OpenAI API key. See [platform.openai.com](https://platform.openai.com/). Add this key to plugin settings.
|
||||
|
|
@ -25,8 +22,6 @@ Parse your daily journal for food-related lines, and create a `dietEstimates` co
|
|||
- Must be run from a note with a valid Date format. Update the date format in settings to match your daily note format.
|
||||
- Daily notes must all follow the same date format (e.g, MMMM D, YYYY would be something like February 6, 2025)
|
||||
- There must be at least one other daily note from this day in a past year.
|
||||
### Diet Estimates Requirements
|
||||
- Meant to be run on a daily journal that includes information documenting what you have eaten in a day.
|
||||
## How to Install
|
||||
### From within Obsidian
|
||||
You can activate this plugin within Obsidian by doing the following:
|
||||
|
|
|
|||
146
main.ts
146
main.ts
|
|
@ -2,12 +2,11 @@ import { MarkdownView, Notice, Plugin, TFolder, Editor } from "obsidian";
|
|||
import OpenAI from "openai";
|
||||
import { OnThisDayPluginSettings, DEFAULT_SETTINGS } from "src/settings";
|
||||
import OnThisDaySettingTab from "src/OnThisDaySettingTab";
|
||||
import { sysPrompt, constructPrompt, constructDietPrompt } from "src/prompt";
|
||||
import { sysPrompt, constructPrompt } from "src/prompt";
|
||||
import { isValidDateString, parseDateFromString } from "src/dateUtils";
|
||||
import {
|
||||
getMarkdownFilesInFolder,
|
||||
buildOutputBlock,
|
||||
buildHealthOutputBlock,
|
||||
} from "src/markdownUtils";
|
||||
|
||||
export default class OnThisDayPlugin extends Plugin {
|
||||
|
|
@ -38,27 +37,6 @@ export default class OnThisDayPlugin extends Plugin {
|
|||
},
|
||||
});
|
||||
|
||||
// Conditions: placeholder must be defined in settings
|
||||
this.addCommand({
|
||||
id: "diet-estimates-placeholder",
|
||||
name: "Add diet estimates placeholder at cursor",
|
||||
editorCheckCallback: (
|
||||
checking: boolean,
|
||||
editor: Editor,
|
||||
view: MarkdownView
|
||||
) => {
|
||||
const placeholderIsEmpty =
|
||||
this.settings.dietEstimatePlaceholder.trim() === "";
|
||||
if (!placeholderIsEmpty) {
|
||||
if (!checking) {
|
||||
this.addDietEstimatesPlaceholder();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
});
|
||||
|
||||
// Conditions: date format, daily notes folder, output header, model version, and apiKey
|
||||
this.addCommand({
|
||||
id: "generate-date-summaries",
|
||||
|
|
@ -83,29 +61,6 @@ export default class OnThisDayPlugin extends Plugin {
|
|||
return false;
|
||||
},
|
||||
});
|
||||
|
||||
// Conditions: section header, model version, and apiKey
|
||||
this.addCommand({
|
||||
id: "diet-estimates",
|
||||
name: "Generate diet estimates",
|
||||
editorCheckCallback: (
|
||||
checking: boolean,
|
||||
editor: Editor,
|
||||
view: MarkdownView
|
||||
) => {
|
||||
if (
|
||||
this.settings.foodHeader.trim() != "" &&
|
||||
this.settings.model.trim() != "" &&
|
||||
this.settings.openaiApiKey.trim() != ""
|
||||
) {
|
||||
if (!checking) {
|
||||
this.generateDateSummaries();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async loadSettings() {
|
||||
|
|
@ -244,95 +199,6 @@ export default class OnThisDayPlugin extends Plugin {
|
|||
new Notice("On This Day summaries inserted.");
|
||||
}
|
||||
|
||||
async generateDietEstimates() {
|
||||
const activeFile = this.app.workspace.getActiveFile();
|
||||
if (!activeFile) {
|
||||
new Notice("No active file found.");
|
||||
return;
|
||||
}
|
||||
|
||||
const content = await this.app.vault.read(activeFile);
|
||||
|
||||
// Find the index of the designated header (compare trimmed lines).
|
||||
const lines = content.split("\n");
|
||||
const headerIndex = lines.findIndex(
|
||||
(line) => line.trim() === this.settings.foodHeader.trim()
|
||||
);
|
||||
|
||||
if (headerIndex === -1) {
|
||||
new Notice(
|
||||
"Food section not found using header: " +
|
||||
this.settings.foodHeader
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Collect all lines after the header until a new header is encountered.
|
||||
const foodSectionLines: string[] = [];
|
||||
for (let i = headerIndex + 1; i < lines.length; i++) {
|
||||
if (lines[i].trim().startsWith("#")) {
|
||||
break;
|
||||
}
|
||||
foodSectionLines.push(lines[i]);
|
||||
}
|
||||
|
||||
const foodInfo = foodSectionLines.join("\n").trim();
|
||||
|
||||
if (!foodInfo) {
|
||||
new Notice(
|
||||
"No food-related details found under the header: " +
|
||||
this.settings.foodHeader
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const prompt = constructDietPrompt(foodInfo);
|
||||
|
||||
const loadingNotice = new Notice(
|
||||
"Calculating diet estimates... Please wait.",
|
||||
0
|
||||
);
|
||||
|
||||
let responseJSON: Record<string, any>;
|
||||
try {
|
||||
responseJSON = await this.callOpenAI(prompt);
|
||||
} catch (error: any) {
|
||||
loadingNotice.hide();
|
||||
console.error("Diet estimates calculation failed:", error);
|
||||
new Notice("Diet estimates calculation failed: " + error.message);
|
||||
return;
|
||||
}
|
||||
|
||||
loadingNotice.hide();
|
||||
new Notice("Diet estimates calculated!");
|
||||
|
||||
const outputBlock = buildHealthOutputBlock(
|
||||
responseJSON.calories,
|
||||
responseJSON.protein,
|
||||
responseJSON.carbs,
|
||||
responseJSON.fats,
|
||||
responseJSON.est_deficit
|
||||
);
|
||||
|
||||
const activeView = this.app.workspace.getActiveViewOfType(MarkdownView);
|
||||
if (!activeView) {
|
||||
loadingNotice.hide();
|
||||
new Notice("No active editor found.");
|
||||
return;
|
||||
}
|
||||
const editor = (activeView as MarkdownView).editor;
|
||||
|
||||
// Insert the output block at a placeholder if available, else at cursor location
|
||||
const placeholder = this.settings.dietEstimatePlaceholder;
|
||||
if (content.includes(placeholder)) {
|
||||
const newContent = content.replace(placeholder, outputBlock);
|
||||
editor.setValue(newContent);
|
||||
} else {
|
||||
editor.replaceSelection(outputBlock);
|
||||
}
|
||||
new Notice("Diet estimates inserted into the note.");
|
||||
}
|
||||
|
||||
async callOpenAI(prompt: string): Promise<Record<string, string>> {
|
||||
const client = new OpenAI({
|
||||
apiKey: this.settings.openaiApiKey,
|
||||
|
|
@ -389,14 +255,4 @@ export default class OnThisDayPlugin extends Plugin {
|
|||
const editor = (activeView as MarkdownView).editor;
|
||||
editor.replaceSelection(this.settings.placeholder);
|
||||
}
|
||||
|
||||
addDietEstimatesPlaceholder() {
|
||||
const activeView = this.app.workspace.getActiveViewOfType(MarkdownView);
|
||||
if (!activeView) {
|
||||
new Notice("No active editor found.");
|
||||
return;
|
||||
}
|
||||
const editor = (activeView as MarkdownView).editor;
|
||||
editor.replaceSelection(this.settings.dietEstimatePlaceholder);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -190,39 +190,5 @@ export default class OnThisDaySettingTab extends PluginSettingTab {
|
|||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl).setName("Health estimates").setHeading();
|
||||
new Setting(containerEl)
|
||||
.setName("Health estimates placeholder tag")
|
||||
.setDesc(
|
||||
"The plugin will search for this text in your active file to replace with its return block. Otherwise outputs at cursor. Default <!OTDI diet>"
|
||||
)
|
||||
.addText((text) =>
|
||||
text
|
||||
.setPlaceholder("<!OTDI diet>")
|
||||
.setValue(
|
||||
this.plugin.settings.dietEstimatePlaceholder ||
|
||||
"<!OTDI diet>"
|
||||
)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.dietEstimatePlaceholder = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Food section header")
|
||||
.setDesc(
|
||||
"Enter the header that marks the food section in your daily note. Default is '### Food'."
|
||||
)
|
||||
.addText((text) =>
|
||||
text
|
||||
.setPlaceholder("### Food")
|
||||
.setValue(this.plugin.settings.foodHeader || "### Food")
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.foodHeader = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,20 +56,3 @@ export function buildOutputBlock(
|
|||
|
||||
return output;
|
||||
}
|
||||
|
||||
export function buildHealthOutputBlock(
|
||||
calories: string,
|
||||
protein: string,
|
||||
carbs: string,
|
||||
fats: string,
|
||||
deficit: string
|
||||
): string {
|
||||
const outputBlock =
|
||||
`\`\`\`dietEstimates
|
||||
calories: ${calories}
|
||||
protein: ${protein}
|
||||
carbs: ${carbs}
|
||||
fats: ${fats}
|
||||
\`\`\``;
|
||||
return outputBlock;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,20 +26,3 @@ export function constructPrompt(
|
|||
const numberOfSentencesAppendage = `Each year's summary should be approximately ${numberOfSentences} sentences`;
|
||||
return `${promptInstructions}\n\nData:\n${dataString}\n${numberOfSentencesAppendage}`;
|
||||
}
|
||||
|
||||
export function constructDietPrompt(foodInfo: string): string {
|
||||
const prompt = `You are a health assistant. Based on the following food details extracted from a daily journal,
|
||||
provide an estimated nutritional analysis.
|
||||
|
||||
Food Information:
|
||||
${foodInfo}
|
||||
|
||||
Provide the output in JSON format with the following keys:
|
||||
- calories: estimated total calories consumed,
|
||||
- protein: estimated grams of protein,
|
||||
- carbs: estimated grams of carbohydrates,
|
||||
- fats: estimated grams of fats,
|
||||
|
||||
Return only a JSON object with these keys, with no additional text. Include units in the JSON values.`;
|
||||
return prompt;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,9 +14,6 @@ export interface OnThisDayPluginSettings {
|
|||
throughTheYearsHeader: string;
|
||||
shouldOutputLinkToNotes: boolean;
|
||||
outputLengthSentences: number;
|
||||
// Health estimate settings
|
||||
dietEstimatePlaceholder: string;
|
||||
foodHeader: string;
|
||||
}
|
||||
|
||||
export const DEFAULT_SETTINGS: OnThisDayPluginSettings = {
|
||||
|
|
@ -30,6 +27,4 @@ export const DEFAULT_SETTINGS: OnThisDayPluginSettings = {
|
|||
throughTheYearsHeader: "On This Day",
|
||||
shouldOutputLinkToNotes: true,
|
||||
outputLengthSentences: 3,
|
||||
dietEstimatePlaceholder: "<!OTDI diet>",
|
||||
foodHeader: "### Food",
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue