Feat: Add Configurable Timeout, internal Project ID fields, and patch model testing payload
This commit is contained in:
@@ -1 +1,19 @@
|
|||||||
# TODO
|
# MoodleGPT TODO List
|
||||||
|
|
||||||
|
Based on the open GitHub issues, the following features and improvements are planned:
|
||||||
|
|
||||||
|
## Configuration & Settings
|
||||||
|
|
||||||
|
- [x] **Configurable Request Timeout** (#70): Add a setting to manually configure the API request timeout, preventing hangups on deeply nested or slow LLM requests.
|
||||||
|
- [x] **OpenAI Project ID Support** (#55): Add a field under Advanced Settings to provide an OpenAI `project_id`, enabling compatibility with organizational level API keys.
|
||||||
|
- [ ] **Toggleable Visual Indications** (#71): Add an option to completely disable the cursor hijack and loading animations to prevent unwanted visual behaviors during strictly proctored quizzes.
|
||||||
|
- [ ] **Custom LMS Hostname Whitelisting** (#71): Implement internal configuration logic that seamlessly whitelists custom university domains (e.g., `*.oes.kz`) to ensure extension logic runs on rebranded Moodle portals.
|
||||||
|
|
||||||
|
## Context & Advanced AI Integration
|
||||||
|
|
||||||
|
- [ ] **Document Context Injection** (#39, #42): Allow users to upload or attach PDFs/lecture notes to be embedded in the AI's prompt resolution context to strictly enforce the correct syllabus answers.
|
||||||
|
- [ ] **ChatGPT Assistant Integrations** (#37): Implement support for routing requests to customized pre-trained ChatGPT Assistants using specific Assistant IDs instead of relying entirely on standard ChatCompletion routes.
|
||||||
|
|
||||||
|
## Cross-Platform
|
||||||
|
|
||||||
|
- [ ] **Firefox Port** (#50): Migrate and package the Chrome extension codebase for native Firefox compatibility, adapting to standard `browser.*` APIs.
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -60,10 +60,18 @@
|
|||||||
<label for="baseURL" class="textLabel">Base URL:</label>
|
<label for="baseURL" class="textLabel">Base URL:</label>
|
||||||
<input id="baseURL" type="text" />
|
<input id="baseURL" type="text" />
|
||||||
</div>
|
</div>
|
||||||
|
<div class="line center">
|
||||||
|
<label for="projectId" class="textLabel">Project ID:</label>
|
||||||
|
<input id="projectId" type="text" placeholder="proj_..." />
|
||||||
|
</div>
|
||||||
<div class="line center">
|
<div class="line center">
|
||||||
<label for="maxTokens" class="textLabel">Max Tokens:</label>
|
<label for="maxTokens" class="textLabel">Max Tokens:</label>
|
||||||
<input id="maxTokens" type="number" />
|
<input id="maxTokens" type="number" />
|
||||||
</div>
|
</div>
|
||||||
|
<div class="line center">
|
||||||
|
<label for="timeoutValue" class="textLabel">Timeout (s):</label>
|
||||||
|
<input id="timeoutValue" type="number" placeholder="20" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- SWITCH SETTINGS MODE -->
|
<!-- SWITCH SETTINGS MODE -->
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,78 @@
|
|||||||
|
[HELP] Add host and desactivate the cursor indication #71
|
||||||
|
Help Request
|
||||||
|
|
||||||
|
Issue Summary
|
||||||
|
Host name change due to private proctoring system integration and unwanted visual behavior in tests.
|
||||||
|
|
||||||
|
Describe the problem
|
||||||
|
Hello!
|
||||||
|
Our university is integrating a private proctoring system, and because of this, the host name is changing — it now ends with .oes.kz.
|
||||||
|
How can we properly add or register this new host in the LMS so that everything continues to work correctly?
|
||||||
|
|
||||||
|
Additionally, we’d like to remove the visual behavior when hovering over a test question. Currently, when you hover, the cursor changes, and when you click, a loading animation appears. Is there a way to disable this effect?
|
||||||
|
|
||||||
|
Environment
|
||||||
|
• Operating System: Windows 10
|
||||||
|
• Browser: Google Chrome
|
||||||
|
• Version: [e.g. 130.0.6723.70]
|
||||||
|
• Platform: LMS
|
||||||
|
|
||||||
|
[FEATURE] Add "Request timeout" configuration option #70
|
||||||
|
Help Request
|
||||||
|
|
||||||
|
Issue Summary
|
||||||
|
|
||||||
|
[Request was abort.]
|
||||||
|
|
||||||
|
Describe the problem
|
||||||
|
|
||||||
|
[I have no idea what happen maybe request is take too long time.it happen after using gpt 5 mode which not heppen on gpt4 before. can we have timeout setting feature so we can manually set it]
|
||||||
|
|
||||||
|
Environment
|
||||||
|
|
||||||
|
Operating System: [W11]
|
||||||
|
Browser: [Chrome]
|
||||||
|
Version: [1.1.5]
|
||||||
|
Any other relevant information
|
||||||
|
|
||||||
|
Additional Information
|
||||||
|
|
||||||
|
[Any additional information that may be helpful in diagnosing the issue.]
|
||||||
|
|
||||||
|
[FEATURE] Add Project ID under Advanced Settings #55
|
||||||
|
Add Project ID under Advanced Settings
|
||||||
|
|
||||||
|
To use organization API keys it is required to provide the project id in the request. I never used openai APIs before and I was getting 401 - Incorrect API key provided.
|
||||||
|
|
||||||
|
I fixed changing this line in MoodleGPT.js :
|
||||||
|
|
||||||
|
project: s = Be("OPENAI_PROJECT_ID") ?? <my-project-id>
|
||||||
|
|
||||||
|
and then loading the extension manually.
|
||||||
|
|
||||||
|
It would be very nice to add an optional project id under the advanced settings section.
|
||||||
|
|
||||||
|
[FEATURE] Firefox port? #50
|
||||||
|
Feature Request
|
||||||
|
|
||||||
|
Description of the Feature
|
||||||
|
Would be really good if the extension was available for Firefox too.
|
||||||
|
|
||||||
|
Additional Information
|
||||||
|
It wouldn't require too much code modification, since Firefox supports chrome. APIs natively too.
|
||||||
|
|
||||||
|
[FEATURE] Preprompt for test with existing documents #42
|
||||||
|
Hello, could there be an option to maybe choose a chatgpt chat you have made already or do I need to make a separate API and enter the files in there maybe?
|
||||||
|
|
||||||
|
TLDR: I have specific exams for what correct answers only come from there. For this I would usually make a chatgpt chat that had all the documents pre uploaded in there. But if I want to use the plugin, it takes new chats. Any way to work this in or do I need to generate a specific API for this?
|
||||||
|
|
||||||
|
[FEATURE] Add a document with the extension #39
|
||||||
|
Hello, quick question: is it possible to provide my PDF of lecture notes in advance, to prepare and optimise ChatGPT’s answers to the multiple-choice questions?
|
||||||
|
For example, for my ‘Strategic Communication’ exam, I provide my PDF of about 30 pages of notes, so that the answers are faithful to what we covered in class.
|
||||||
|
Thanks and have a good day
|
||||||
|
Leo
|
||||||
|
|
||||||
|
[FEATURE] ChatGPT Assistants #37
|
||||||
|
Feature Request
|
||||||
|
|
||||||
|
It would be really helpful if ChatGPT's assistants would also be supported in the extension. It should be only an option to select and use assistants which you have made for a specific topic to give more exact results.
|
||||||
@@ -18,7 +18,7 @@ async function getChatGPTResponse(
|
|||||||
question: string
|
question: string
|
||||||
): Promise<GPTAnswer> {
|
): Promise<GPTAnswer> {
|
||||||
const controller = new AbortController();
|
const controller = new AbortController();
|
||||||
const timeoutControler = setTimeout(() => controller.abort(), 20 * 1000);
|
const timeoutControler = setTimeout(() => controller.abort(), (config.timeoutValue || 20) * 1000);
|
||||||
|
|
||||||
// Get the content to send to chatgpt
|
// Get the content to send to chatgpt
|
||||||
// Including the instructions to the AI, the images as base64 if needed, the question and the past conversation if history is set to true
|
// Including the instructions to the AI, the images as base64 if needed, the question and the past conversation if history is set to true
|
||||||
@@ -27,6 +27,7 @@ async function getChatGPTResponse(
|
|||||||
const client = new OpenAI({
|
const client = new OpenAI({
|
||||||
apiKey: config.apiKey,
|
apiKey: config.apiKey,
|
||||||
baseURL: config.baseURL,
|
baseURL: config.baseURL,
|
||||||
|
project: config.projectId,
|
||||||
dangerouslyAllowBrowser: true
|
dangerouslyAllowBrowser: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,9 @@ type Config = {
|
|||||||
includeImages?: boolean;
|
includeImages?: boolean;
|
||||||
mode?: 'autocomplete' | 'question-to-answer' | 'clipboard';
|
mode?: 'autocomplete' | 'question-to-answer' | 'clipboard';
|
||||||
baseURL?: string;
|
baseURL?: string;
|
||||||
|
projectId?: string;
|
||||||
maxTokens?: number;
|
maxTokens?: number;
|
||||||
|
timeoutValue?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Config;
|
export default Config;
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ const inputModel: HTMLInputElement = document.querySelector('#model')!;
|
|||||||
const modelsList: HTMLElement = document.querySelector('#models')!;
|
const modelsList: HTMLElement = document.querySelector('#models')!;
|
||||||
const imagesIntegrationLine: HTMLInputElement = document.querySelector('#includeImages-line')!;
|
const imagesIntegrationLine: HTMLInputElement = document.querySelector('#includeImages-line')!;
|
||||||
const baseURLSelector: HTMLInputElement = document.querySelector('#baseURL')!;
|
const baseURLSelector: HTMLInputElement = document.querySelector('#baseURL')!;
|
||||||
|
const projectIdSelector: HTMLInputElement = document.querySelector('#projectId')!;
|
||||||
|
const maxTokensSelector: HTMLInputElement = document.querySelector('#maxTokens')!;
|
||||||
/**
|
/**
|
||||||
* Check if the gpt version is at least 4 to show the option 'Include images'
|
* Check if the gpt version is at least 4 to show the option 'Include images'
|
||||||
*/
|
*/
|
||||||
@@ -24,6 +26,7 @@ inputModel.addEventListener('input', checkCanIncludeImages);
|
|||||||
export async function populateDatalistWithGptVersions() {
|
export async function populateDatalistWithGptVersions() {
|
||||||
const apiKey = apiKeySelector.value?.trim();
|
const apiKey = apiKeySelector.value?.trim();
|
||||||
const baseURL = baseURLSelector.value?.trim();
|
const baseURL = baseURLSelector.value?.trim();
|
||||||
|
const projectId = projectIdSelector.value?.trim();
|
||||||
|
|
||||||
if (!apiKey) return;
|
if (!apiKey) return;
|
||||||
|
|
||||||
@@ -33,6 +36,7 @@ export async function populateDatalistWithGptVersions() {
|
|||||||
const client = new OpenAI({
|
const client = new OpenAI({
|
||||||
apiKey,
|
apiKey,
|
||||||
baseURL,
|
baseURL,
|
||||||
|
project: projectId,
|
||||||
dangerouslyAllowBrowser: true
|
dangerouslyAllowBrowser: true
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -66,13 +70,21 @@ export async function checkModel() {
|
|||||||
const model = inputModel.value?.trim();
|
const model = inputModel.value?.trim();
|
||||||
const apiKey = apiKeySelector.value?.trim();
|
const apiKey = apiKeySelector.value?.trim();
|
||||||
const baseURL = baseURLSelector.value?.trim();
|
const baseURL = baseURLSelector.value?.trim();
|
||||||
|
const projectId = projectIdSelector.value?.trim();
|
||||||
|
const maxTokens = maxTokensSelector.value ? parseInt(maxTokensSelector.value) : undefined;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
showMessage({ msg: 'Checking GPT version...', isInfinite: true, isError: false });
|
showMessage({ msg: 'Checking GPT version...', isInfinite: true, isError: false });
|
||||||
const client = new OpenAI({ apiKey, baseURL, dangerouslyAllowBrowser: true });
|
const client = new OpenAI({
|
||||||
|
apiKey,
|
||||||
|
baseURL,
|
||||||
|
project: projectId,
|
||||||
|
dangerouslyAllowBrowser: true
|
||||||
|
});
|
||||||
await client.chat.completions.create({
|
await client.chat.completions.create({
|
||||||
model,
|
model,
|
||||||
messages: [{ role: 'user', content: 'reply just pong' }]
|
messages: [{ role: 'user', content: 'reply just pong' }],
|
||||||
|
max_completion_tokens: maxTokens || 2000
|
||||||
});
|
});
|
||||||
showMessage({ msg: 'The model is valid!' });
|
showMessage({ msg: 'The model is valid!' });
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
|
|||||||
+5
-3
@@ -9,12 +9,12 @@ import { showMessage } from './utils';
|
|||||||
const saveBtn = document.querySelector('.save')!;
|
const saveBtn = document.querySelector('.save')!;
|
||||||
|
|
||||||
// inputs id
|
// inputs id
|
||||||
const inputsText = ['apiKey', 'code', 'model', 'baseURL', 'maxTokens'];
|
const inputsText = ['apiKey', 'code', 'model', 'baseURL', 'maxTokens', 'projectId', 'timeoutValue'];
|
||||||
|
|
||||||
// Save the configuration
|
// Save the configuration
|
||||||
saveBtn.addEventListener('click', function () {
|
saveBtn.addEventListener('click', function () {
|
||||||
const [apiKey, code, model, baseURL, maxTokens] = inputsText.map(selector =>
|
const [apiKey, code, model, baseURL, maxTokens, projectId, timeoutValue] = inputsText.map(
|
||||||
(document.querySelector('#' + selector) as HTMLInputElement).value.trim()
|
selector => (document.querySelector('#' + selector) as HTMLInputElement).value.trim()
|
||||||
);
|
);
|
||||||
const [logs, title, cursor, typing, mouseover, infinite, timeout, history, includeImages] =
|
const [logs, title, cursor, typing, mouseover, infinite, timeout, history, includeImages] =
|
||||||
inputsCheckbox.map(selector => {
|
inputsCheckbox.map(selector => {
|
||||||
@@ -42,6 +42,8 @@ saveBtn.addEventListener('click', function () {
|
|||||||
model,
|
model,
|
||||||
baseURL,
|
baseURL,
|
||||||
maxTokens: maxTokens ? parseInt(maxTokens) : undefined,
|
maxTokens: maxTokens ? parseInt(maxTokens) : undefined,
|
||||||
|
projectId,
|
||||||
|
timeoutValue: timeoutValue ? parseInt(timeoutValue) : undefined,
|
||||||
logs,
|
logs,
|
||||||
title,
|
title,
|
||||||
cursor,
|
cursor,
|
||||||
|
|||||||
Reference in New Issue
Block a user