Skip to content

Commit

Permalink
Merge pull request #23 from lolipopshock/allow-set-s2-api
Browse files Browse the repository at this point in the history
Allow setting s2 api in the app to avoid rate limits.
  • Loading branch information
lolipopshock committed Apr 20, 2024
2 parents 8e08d40 + c6ced27 commit f410487
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 10 deletions.
Binary file added .github/demo/settings.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

### Install from Obsidian Plugin Library

This plugin will be released upon the approval of the maintainers. See [this PR](https://github.com/obsidianmd/obsidian-releases/pull/2525).
This plugin is released on the Obsidian Plugin Library. You can install it directly from the Obsidian app [by searching `Scholar` in the community plugins](https://obsidian.md/plugins?search=scholar).

### Manual Installation

Expand All @@ -26,6 +26,15 @@ This plugin will be released upon the approval of the maintainers. See [this PR]
3. Download the three files `manifest.json`, `styles.css`, and `main.js` from the [latest release](https://github.com/lolipopshock/obsidian-scholar/releases/latest), and put the files in the `.obsidian/plugins/scholar` folder you just created.
4. Open Obsidian and in `settings > community plugins`, find `Scholar` and enable the plugin. Be sure to change the `Scholar` settings properly before use.

## Documentation

### Settings

![Settings](.github/demo/settings.png)

- **Adding an SemanticScholar API Key**
Sometimes you might experience rate limiting when querying papers from SemanticScholar. To avoid this, you can add your own SemanticScholar API key in the settings. You can obtain the API Key [here](https://www.semanticscholar.org/product/api#api-key).

## Motivation and Acknowledgement

The goal of *Obsidian Scholar* is to create a smooth experience that spans from paper reading, note taking, and reflection and synthesis.
Expand Down
3 changes: 3 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ export const SETTING_TEMPLATE_NAME = "Note Template";
export const SETTING_TEMPLATE_DESC = "If set, we will use you own template for the paper note.";
export const SETTING_TEMPLATE_FOLDER_DEFAULT = "template";

export const SETTING_S2API_NAME = "Semantic Scholar API Key";
export const SETTING_S2API_DESC = "Provide an Semantic Scholar API key can help you avoid rate limits when calling the API. You can obtain an API key from https://api.semanticscholar.org/.";

// NOTICES
export const NOTICE_RETRIEVING_ARXIV = "Retrieving paper information from arXiv API.";
export const NOTICE_RETRIEVING_S2 = "Retrieving paper information from Semantic Scholar API.";
Expand Down
8 changes: 6 additions & 2 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ class paperSearchModal extends SuggestModal<PaperSearchModelResult> {
async searchSemanticScholar(query: string) {
let searchResult: StructuredPaperData[] = [];
try {
searchResult = await searchSemanticScholar(query);
searchResult = await searchSemanticScholar(query, this.settings.s2apikey);
} catch (error) {
new Notice("Errors when downloading papers from Semanticscholar");
console.error(error);
Expand Down Expand Up @@ -1011,7 +1011,11 @@ class createNoteFromUrlModal extends Modal {
paperFetchFunction = fetchArxivPaperDataFromUrl;
} else {
new Notice(NOTICE_RETRIEVING_S2);
paperFetchFunction = fetchSemanticScholarPaperDataFromUrl;
paperFetchFunction = (url: string) =>
fetchSemanticScholarPaperDataFromUrl(
url,
this.settings.s2apikey
);
}
paperFetchFunction(url)
.then(async (paperData: StructuredPaperData) => {
Expand Down
20 changes: 13 additions & 7 deletions src/paperData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
SEMANTIC_SCHOLAR_SEARCH_API,
SEMANTIC_SCHOLAR_REFERENCE_SEARCH_FIELDS,
} from "./constants";
import { request } from "obsidian";
import { request, RequestUrlParam } from "obsidian";
import { trimString } from "./utility";
import { backOff } from "exponential-backoff";
import { Notice } from "obsidian";
Expand All @@ -33,12 +33,16 @@ function getIdentifierFromUrl(url: string): string {
return url.split("/").slice(-1)[0];
}

async function makeRequestWithRetry(url: string): Promise<any> {
async function makeRequestWithRetry(url: string, apiKey?: string): Promise<any> {
const makeRequest = async () => {
const response = await request(url);
const requestOptions: RequestUrlParam = {
url: url,
headers: apiKey && apiKey !== "" ? {'x-api-key': apiKey} : {},
};
const response = await request(requestOptions);
return response;
};

return backOff(makeRequest, {
startingDelay: 1000, // b/c the default is 1000ms according to the semanticscholar API
numOfAttempts: 5,
Expand Down Expand Up @@ -168,6 +172,7 @@ function parseS2paperData(json: any) {

export async function fetchSemanticScholarPaperDataFromUrl(
url: string,
apiKey?: string,
maxRetryCount = 3,
retryDelay = 2000,
): Promise<StructuredPaperData> {
Expand All @@ -184,7 +189,7 @@ export async function fetchSemanticScholarPaperDataFromUrl(
throw new Error("Invalid url: " + url);
}

let s2Data = await makeRequestWithRetry(SEMANTIC_SCHOLAR_API + s2Id + "?" + SEMANTIC_SCHOLAR_FIELDS);
let s2Data = await makeRequestWithRetry(SEMANTIC_SCHOLAR_API + s2Id + "?" + SEMANTIC_SCHOLAR_FIELDS, apiKey);

let json = JSON.parse(s2Data);

Expand All @@ -195,7 +200,8 @@ export async function fetchSemanticScholarPaperDataFromUrl(
}

export async function searchSemanticScholar(
query: string
query: string,
apiKey?: string
): Promise<StructuredPaperData[]> {
let requestUrl =
SEMANTIC_SCHOLAR_SEARCH_API +
Expand All @@ -205,7 +211,7 @@ export async function searchSemanticScholar(

// console.log(requestUrl);

let s2Data = await makeRequestWithRetry(requestUrl);
let s2Data = await makeRequestWithRetry(requestUrl, apiKey);
// console.log(s2Data);

let json = JSON.parse(s2Data);
Expand Down
21 changes: 21 additions & 0 deletions src/settingsTab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import {
SETTING_FRONTMATTER_ADD_ALIASES_DESC,
SETTING_FRONTMATTER_ADD_ANNOTATION_NAME,
SETTING_FRONTMATTER_ADD_ANNOTATION_DESC,
SETTING_S2API_NAME,
SETTING_S2API_DESC,
NOTICE_NOT_BIB_FILE,
NOTICE_NO_BIB_FILE_SELECTED,
} from "./constants";
Expand All @@ -38,6 +40,7 @@ export interface ObsidianScholarPluginSettings {
bibTexFileLocation: string;
noteAddFrontmatterAliases: boolean;
noteAddFrontmatterAnnotation: boolean;
s2apikey: string;
}

export const DEFAULT_SETTINGS: ObsidianScholarPluginSettings = {
Expand All @@ -50,6 +53,7 @@ export const DEFAULT_SETTINGS: ObsidianScholarPluginSettings = {
bibTexFileLocation: "",
noteAddFrontmatterAliases: false,
noteAddFrontmatterAnnotation: false,
s2apikey: "",
};

// Settings Tab
Expand Down Expand Up @@ -252,5 +256,22 @@ export class ObsidianScholarSettingTab extends PluginSettingTab {
await this.plugin.saveSettings();
})
);
new Setting(containerEl)
.setName(SETTING_S2API_NAME)
.setDesc(SETTING_S2API_DESC)
.addText((text) =>
text
.setPlaceholder("API key")
.setValue(this.plugin.settings.s2apikey || "")
.onChange(async (value) => {
// Check if it is a valid API key
if (!value || value.length !== 40) {
new Notice("Please enter a valid API key");
return;
}
this.plugin.settings.s2apikey = value;
await this.plugin.saveSettings();
})
);
}
}

0 comments on commit f410487

Please sign in to comment.