Skip to content

Commit

Permalink
work in progress
Browse files Browse the repository at this point in the history
  • Loading branch information
benjaminshafii committed Apr 21, 2024
1 parent 083de0e commit fc8b53d
Show file tree
Hide file tree
Showing 8 changed files with 243 additions and 57 deletions.
90 changes: 90 additions & 0 deletions app/app/api/files/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
const generateConfig = (document: string, filePaths: string, model: string) => {
console.log("generateConfig", filePaths);
const config = {
"gpt-3.5-turbo": {
url: "https://api.openai.com/v1/chat/completions",
messages: [
{
role: "system",
content:
"Always answer with the full path of the most appropriate file from the provided list. If none of the files are suitable, answer with 'None'.",
},
{
role: "user",
content: `Given the document: "${document}", which of the following files best matches the user's request? Available files: ${filePaths}`,
},
],
},
"dolphin-mistral": {
url: "http://localhost:11434/v1/chat/completions",
messages: [
{
role: "assistant",
content: `Always answer full filename. Example Answer: "folder/subfolder/file.md"`,
},
{
role: "user",
content: `
document: "${document}",
files: "${filePaths}",
identify the most relevant file. If none are suitable, respond with 'None'.`,
},
],
},
llama3: {
url: "http://localhost:11434/v1/chat/completions",
messages: [
{
role: "user",
content: `Based on the document: "${document}", identify the most relevant file. If none are suitable, respond with 'None'.`,
},
],
},
};
return config[model];
};

export async function POST(request: Request) {
console.log("received post on files route");
try {
const apiKey = process.env.OPENAI_API_KEY || "";
const useOllama = process.env.USE_OLLAMA === "true";
const requestBody = await request.json();
const model = useOllama ? "dolphin-mistral" : "gpt-3.5-turbo";

const config = generateConfig(
requestBody.document,
requestBody.filePaths.join(", "),
model
);

const data = {
model,
messages: [...config.messages],
};

console.log("file data", data);
const response = await fetch(config.url, {
method: "POST",
body: JSON.stringify(data),
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${apiKey}`,
},
});

const result = await response.json();
console.log("magic", result.choices[0].message.content);
return new Response(JSON.stringify(result), {
status: 200,
headers: { "Content-Type": "application/json" },
});
} catch (error) {
console.error(error);
return new Response(JSON.stringify({ message: "Error" }), {
status: 500,
headers: { "Content-Type": "application/json" },
});
}
}
96 changes: 96 additions & 0 deletions app/app/api/folders/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
const generateConfig = (document: string, folders: string[], model) => {
const config = {
"gpt-3.5-turbo": {
url: "https://api.openai.com/v1/chat/completions",
messages: [
{
role: "system",
content:
"Always answer with the name of the most appropriate folder from the provided list. If none of the folders are suitable, answer with 'None'.",
},
{
role: "user",
content: `Given the text "${document}", which of the following folders would be the most appropriate location for the file? Available folders: ${folders}`,
},
],
},
"dolphin-mistral": {
url: "http://localhost:11434/v1/chat/completions",
messages: [
{
role: "system",
content:
"Always answer with the name of the most appropriate folder from the provided list. If none of the folders are suitable, answer with 'None'.",
},
{
role: "user",
content: `Given the text "${document}", which of the following folders would be the most appropriate location for the file? Available folders: ${folders}`,
},
],
},
llama3: {
url: "http://localhost:11434/v1/chat/completions",
messages: [
{
role: "system",
content:
"Always answer with the name of the most appropriate folder from the provided list. If none of the folders are suitable, answer with 'None'.",
},
{
role: "user",
content: `Given the text "${document}", which of the following folders would be the most appropriate location for the file? Available folders: ${folders}`,
},
],
},
};
return config[model];
};

export async function POST(request: Request) {
console.log("received post on folders route");
try {
const apiKey = process.env.OPENAI_API_KEY || "";
const useOllama = process.env.USE_OLLAMA === "true";
const requestBody = await request.json();
const model = useOllama ? "dolphin-mistral" : "gpt-3.5-turbo";

const config = generateConfig(
requestBody.document,
requestBody.folders.join(", "),
model
);

const data = {
model,
messages: [...config.messages],
};

console.log("folder data", data);
const response = await fetch(config.url, {
method: "POST",
body: JSON.stringify(data),
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${apiKey}`,
},
});
if (response.status === 401) {
return new Response(JSON.stringify({ message: "Invalid API key" }), {
status: 401,
headers: { "Content-Type": "application/json" },
});
}
const result = await response.json();
console.log("result from folders", result);
return new Response(JSON.stringify(result), {
status: 200,
headers: { "Content-Type": "application/json" },
});
} catch (error) {
console.error(error);
return new Response(JSON.stringify({ message: "Error" }), {
status: 500,
headers: { "Content-Type": "application/json" },
});
}
}
3 changes: 2 additions & 1 deletion app/app/api/tags/route.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const generateConfig = (document: string, tags: string, model) => {
console.log("getto tags", tags);
const config = {
"gpt-3.5-turbo": {
url: "https://api.openai.com/v1/chat/completions",
Expand All @@ -23,7 +24,7 @@ const generateConfig = (document: string, tags: string, model) => {
{
role: "system",
content:
"Always answer with a list of tag names from the provided list. If none of the tags are relevant, answer with an empty list.",
"Always answer with a list of top 5 tag names from the provided list. If none of the tags are relevant, answer with an empty list.",
},
{
role: "user",
Expand Down
9 changes: 1 addition & 8 deletions src/AssistantView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,22 +28,15 @@ export class AssistantView extends ItemView {
return "pencil";
}
suggestLinks = async (file: TFile, content: string) => {
return;
const links = await this.plugin.getMostSimilarFileByName(content, file);
this.similarLinkBox.empty();
const links = await this.plugin.getMostSimilarFileByName(content, file);

const child = this.similarLinkBox.createEl("a", { text: links.basename });
child.onclick = () => {
this.app.workspace.openLinkText(links.path, "", true);
};
this.similarLinkBox.appendChild(child);
};
// private createLoadingIndicator(): HTMLElement {
// const loading = document.createElement("div");
// loading.textContent = "Loading...";
// loading.style.display = "none"; // Hidden by default
// return loading;
// }

suggestTags = async (file: TFile, content: string) => {
const tags = await this.plugin.getSimilarTags(content, file.basename);
Expand Down
67 changes: 24 additions & 43 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
TAbstractFile,
moment,
WorkspaceLeaf,
getLinkpath,
} from "obsidian";
import useName from "./modules/name";
import useVision from "./modules/vision";
Expand All @@ -15,7 +14,9 @@ import useText from "./modules/text";
import { logMessage, formatToSafeName } from "../utils";
import { FileOrganizerSettingTab } from "./FileOrganizerSettingTab";
import { ASSISTANT_VIEW_TYPE, AssistantView } from "./AssistantView";
import fetchTags, { getMostSimilarTags } from "./modules/tags";
import fetchTags from "./modules/tags";
import predictFolder from "./modules/folder";
import predictMostSimilarFile from "./modules/file";
class FileOrganizerSettings {
API_KEY = "";
useLogs = true;
Expand Down Expand Up @@ -364,28 +365,15 @@ export default class FileOrganizer extends Plugin {
// Extract the most similar tags from the response

logMessage("mostSimilarTags", mostSimilarTags);

// sample1 mostSimilarTags "[#dao, #communityfirst, #questions, #research, #integration, #blockchain]"
// sample2 mostSimilarTags string "#blockchain #crypto #tokenops #smart-contracts #startup"
// normalize string to array of tags [dao, communityfirst, questions, research, integration, blockchain]
const normalizedTags = mostSimilarTags
.replace(/,/g, " ")
.split(" ")
// repalce all comas with empty string
.map((tag: string) => tag.replace(",", ""))
// add # to the beginning of the tag if it's not there
.map((tag: string) => (tag.startsWith("#") ? tag : `#${tag}`))
.map((tag: string) => tag.trim())
// also filter out tags that are already in the file
.filter((tag: string) => !content.includes(tag))
// this should probie replaced by this.app.fileManager.processFrontMatter
.filter(async (tag: string) => {
// Check for tag in front matter
const frontMatterRegex = new RegExp(
`^tags:\\s*\\[.*?${tag.slice(1)}.*?\\]`,
"m"
);
// Check for tag inline
const inlineTagRegex = new RegExp(`\\s${tag}(\\s|$)`);
return !frontMatterRegex.test(content) && !inlineTagRegex.test(content);
});
.replace(/^\[|\]$/g, "")
.split(/[\s,]+/)
.map((tag) => tag.replace(/^#/, ""))
.map((tag) => tag.replace(/['"]+/g, ""))
.filter((tag) => tag !== "");

logMessage("normalizedTags", normalizedTags);
return normalizedTags;
Expand Down Expand Up @@ -421,20 +409,13 @@ export default class FileOrganizer extends Plugin {
logMessage("uniqueFolders", uniqueFolders);

// Get the most similar folder based on the content and file name
const mostSimilarFolder = await useText(
`Given the text content "${content}" (and if the file name "${
file.basename
}"), which of the following folders would be the most appropriate location for the file? Available folders: ${uniqueFolders.join(
", "
)}`,
"Please respond with the name of the most appropriate folder from the provided list. If none of the folders are suitable, respond with 'None'.",
{
baseUrl: this.settings.useCustomServer
? this.settings.customServerUrl
: this.settings.defaultServerUrl,
apiKey: this.settings.API_KEY,
}
);

const mostSimilarFolder = await predictFolder(content, uniqueFolders, {
baseUrl: this.settings.useCustomServer
? this.settings.customServerUrl
: this.settings.defaultServerUrl,
apiKey: this.settings.API_KEY,
});
logMessage("mostSimilarFolder", mostSimilarFolder);
new Notice(`Most similar folder: ${mostSimilarFolder}`, 3000);

Expand All @@ -460,7 +441,9 @@ export default class FileOrganizer extends Plugin {
await this.appendToFrontMatter(file, "tags", tag);
return;
}
await this.app.vault.append(file, `\n${tag}`);
// add # in front of tag if it doesn't exist
const sanitizedTag = tag.startsWith("#") ? tag : `#${tag}`;
await this.app.vault.append(file, `\n${sanitizedTag}`);
}

async appendSimilarTags(content: string, file: TFile) {
Expand Down Expand Up @@ -495,11 +478,9 @@ export default class FileOrganizer extends Plugin {
.map((file) => file.path);

// Get the most similar file based on the content
const mostSimilarFile = await useText(
`Given the request of the user to append it in a certain file in "${content}", which of the following files would match the user request the most? Available files: ${allMarkdownFilePaths.join(
","
)}`,
"Please only respond with the full path of the most appropriate file from the provided list.",
const mostSimilarFile = await predictMostSimilarFile(
content,
allMarkdownFilePaths,
{
baseUrl: this.settings.useCustomServer
? this.settings.customServerUrl
Expand Down
Empty file removed src/modules/classify.ts
Empty file.
29 changes: 29 additions & 0 deletions src/modules/file.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { requestUrl } from "obsidian";
import { logMessage } from "../../utils";

async function predictMostSimilarFile(
content: string,
allMarkdownFilePaths: string[],
{ baseUrl, apiKey }
) {
const endpoint = "api/files";
const url = `${baseUrl}/${endpoint}`;

const response = await requestUrl({
url: url,
method: "POST",
body: JSON.stringify({
document: content,
filePaths: allMarkdownFilePaths,
}),
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${apiKey}`,
},
});
const result = await response.json;
logMessage(`Most similar file path: ${result.choices[0].message.content}`);
return result.choices[0].message.content.trim();
}

export default predictMostSimilarFile;
6 changes: 1 addition & 5 deletions src/modules/folder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,13 @@ async function predictFolder(
folders: string[],
{ baseUrl, apiKey }
) {
const data = {
document: content,
folders: folders,
};
const endpoint = "api/folders";
const url = `${baseUrl}/${endpoint}`;

const response = await requestUrl({
url: url,
method: "POST",
body: JSON.stringify(data),
body: JSON.stringify({ document: content, folders: folders }),
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${apiKey}`,
Expand Down

0 comments on commit fc8b53d

Please sign in to comment.