-
Notifications
You must be signed in to change notification settings - Fork 19
added multi-llm support #90
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -21,6 +21,8 @@ const Settings = () => { | |||||||||||||||||||||||||||||||||||||||||||
| const [isApiKeyVisible, setIsApiKeyVisible] = useState(false); | ||||||||||||||||||||||||||||||||||||||||||||
| const [isSaving, setIsSaving] = useState(false); | ||||||||||||||||||||||||||||||||||||||||||||
| const [lastSaved, setLastSaved] = useState<Date | null>(null); | ||||||||||||||||||||||||||||||||||||||||||||
| const [isBaseUrlVisible, setIsBaseUrlVisible] = useState(false); | ||||||||||||||||||||||||||||||||||||||||||||
| const [isModelIdVisible, setIsModelIdVisible] = useState(false); | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| const fetchUserSettings = async () => { | ||||||||||||||||||||||||||||||||||||||||||||
| if (!user) throw new Error('No user found'); | ||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -123,6 +125,8 @@ const Settings = () => { | |||||||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||||||||
| // API Settings | ||||||||||||||||||||||||||||||||||||||||||||
| apiKey: (document.getElementById('apiKey') as HTMLInputElement)?.value, | ||||||||||||||||||||||||||||||||||||||||||||
| apiBaseUrl: (document.getElementById('apiBaseUrl') as HTMLInputElement)?.value, | ||||||||||||||||||||||||||||||||||||||||||||
| modelId: (document.getElementById('modelId') as HTMLInputElement)?.value, | ||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| // Validations (same as before) | ||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -357,11 +361,11 @@ const Settings = () => { | |||||||||||||||||||||||||||||||||||||||||||
| <KeyIcon className="w-5 h-5 mr-2" style={{ color: '#8b5cf6' }} /> | ||||||||||||||||||||||||||||||||||||||||||||
| <h2 className="text-lg font-medium text-[#ffffff]">API Settings</h2> | ||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| <div className="space-y-5"> | ||||||||||||||||||||||||||||||||||||||||||||
| <div className="space-y-2"> | ||||||||||||||||||||||||||||||||||||||||||||
| <label className="block text-sm font-medium text-[#B0B7C3]"> | ||||||||||||||||||||||||||||||||||||||||||||
| OpenAI API Key | ||||||||||||||||||||||||||||||||||||||||||||
| API Key | ||||||||||||||||||||||||||||||||||||||||||||
| </label> | ||||||||||||||||||||||||||||||||||||||||||||
| <div className="relative"> | ||||||||||||||||||||||||||||||||||||||||||||
| <div className="absolute inset-0 rounded-lg bg-gradient-to-r from-[rgba(6,182,212,0.1)] to-[rgba(59,130,246,0.1)]" /> | ||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -387,7 +391,61 @@ const Settings = () => { | |||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||
| <p className="text-xs text-[#8A94A6]"> | ||||||||||||||||||||||||||||||||||||||||||||
| Enter your OpenAI API key to enable AI-based features. | ||||||||||||||||||||||||||||||||||||||||||||
| Enter your API key to enable AI-based features. | ||||||||||||||||||||||||||||||||||||||||||||
| </p> | ||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| <div className="space-y-2"> | ||||||||||||||||||||||||||||||||||||||||||||
| <label className="block text-sm font-medium text-[#B0B7C3]"> | ||||||||||||||||||||||||||||||||||||||||||||
| Base URL | ||||||||||||||||||||||||||||||||||||||||||||
| </label> | ||||||||||||||||||||||||||||||||||||||||||||
| <div className="relative group"> | ||||||||||||||||||||||||||||||||||||||||||||
| <input | ||||||||||||||||||||||||||||||||||||||||||||
| type={isBaseUrlVisible ? "text" : "password"} | ||||||||||||||||||||||||||||||||||||||||||||
| id="apiBaseUrl" | ||||||||||||||||||||||||||||||||||||||||||||
| defaultValue={data.apiBaseUrl} | ||||||||||||||||||||||||||||||||||||||||||||
| placeholder="https://api.openai.com/v1" | ||||||||||||||||||||||||||||||||||||||||||||
| className="w-full px-3 py-2 bg-[#2A303C] border border-[#3A4150]/70 rounded-md shadow-sm outline-none focus:outline-none focus:border-[#06b6d4]/70 focus:ring-1 focus:ring-[#3b82f6]/50 transition-all duration-200 text-primary h-11" | ||||||||||||||||||||||||||||||||||||||||||||
| style={{ outline: 'none' }} | ||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||
| <button | ||||||||||||||||||||||||||||||||||||||||||||
| type="button" | ||||||||||||||||||||||||||||||||||||||||||||
| onClick={() => setIsBaseUrlVisible(!isBaseUrlVisible)} | ||||||||||||||||||||||||||||||||||||||||||||
| className="absolute right-3 top-1/2 -translate-y-1/2 text-[#8A94A6] hover:text-[#ffffff] transition-colors" | ||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||
| {isBaseUrlVisible ? 'Hide' : 'Show'} | ||||||||||||||||||||||||||||||||||||||||||||
| </button> | ||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+404
to
+417
|
||||||||||||||||||||||||||||||||||||||||||||
| type={isBaseUrlVisible ? "text" : "password"} | |
| id="apiBaseUrl" | |
| defaultValue={data.apiBaseUrl} | |
| placeholder="https://api.openai.com/v1" | |
| className="w-full px-3 py-2 bg-[#2A303C] border border-[#3A4150]/70 rounded-md shadow-sm outline-none focus:outline-none focus:border-[#06b6d4]/70 focus:ring-1 focus:ring-[#3b82f6]/50 transition-all duration-200 text-primary h-11" | |
| style={{ outline: 'none' }} | |
| /> | |
| <button | |
| type="button" | |
| onClick={() => setIsBaseUrlVisible(!isBaseUrlVisible)} | |
| className="absolute right-3 top-1/2 -translate-y-1/2 text-[#8A94A6] hover:text-[#ffffff] transition-colors" | |
| > | |
| {isBaseUrlVisible ? 'Hide' : 'Show'} | |
| </button> | |
| type="text" | |
| id="apiBaseUrl" | |
| defaultValue={data.apiBaseUrl} | |
| placeholder="https://api.openai.com/v1" | |
| className="w-full px-3 py-2 bg-[#2A303C] border border-[#3A4150]/70 rounded-md shadow-sm outline-none focus:outline-none focus:border-[#06b6d4]/70 focus:ring-1 focus:ring-[#3b82f6]/50 transition-all duration-200 text-primary h-11" | |
| style={{ outline: 'none' }} | |
| /> |
Copilot
AI
Apr 5, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Model ID field is rendered as type="password", but model identifiers aren’t sensitive. This makes it harder to review/edit the value and can interfere with autofill/password managers. Consider switching this input to type="text" and dropping the hide/show toggle.
| type={isModelIdVisible ? "text" : "password"} | |
| id="modelId" | |
| defaultValue={data.modelId} | |
| placeholder="gpt-4o" | |
| className="w-full px-3 py-2 bg-[#2A303C] border border-[#3A4150]/70 rounded-md shadow-sm outline-none focus:outline-none focus:border-[#06b6d4]/70 focus:ring-1 focus:ring-[#3b82f6]/50 transition-all duration-200 text-primary h-11" | |
| style={{ outline: 'none' }} | |
| /> | |
| <button | |
| type="button" | |
| onClick={() => setIsModelIdVisible(!isModelIdVisible)} | |
| className="absolute right-3 top-1/2 -translate-y-1/2 text-[#8A94A6] hover:text-[#ffffff] transition-colors" | |
| > | |
| {isModelIdVisible ? 'Hide' : 'Show'} | |
| </button> | |
| type="text" | |
| id="modelId" | |
| defaultValue={data.modelId} | |
| placeholder="gpt-4o" | |
| className="w-full px-3 py-2 bg-[#2A303C] border border-[#3A4150]/70 rounded-md shadow-sm outline-none focus:outline-none focus:border-[#06b6d4]/70 focus:ring-1 focus:ring-[#3b82f6]/50 transition-all duration-200 text-primary h-11" | |
| style={{ outline: 'none' }} | |
| /> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,10 +2,11 @@ import { NextApiRequest, NextApiResponse } from 'next'; | |
| import OpenAI from 'openai'; | ||
|
|
||
| export default async (req: NextApiRequest, res: NextApiResponse) => { | ||
| const { question, solution, userSolution, userMessage, apiKey, mode = "chat" } = req.body; | ||
| const { question, solution, userSolution, userMessage, apiKey, baseUrl, modelId, mode = "chat" } = req.body; | ||
|
|
||
| const openai = new OpenAI({ | ||
| apiKey: apiKey, | ||
| baseURL: baseUrl || "https://api.openai.com/v1", | ||
| }); | ||
|
Comment on lines
+5
to
10
|
||
|
|
||
| let messages: any = []; | ||
|
|
@@ -45,9 +46,9 @@ export default async (req: NextApiRequest, res: NextApiResponse) => { | |
| } | ||
|
|
||
| const completion = await openai.chat.completions.create({ | ||
| model: "gpt-4o", | ||
| model: modelId || "gpt-4o", | ||
| messages, | ||
| max_tokens: 1500, | ||
| max_tokens: 1500, | ||
| }); | ||
|
|
||
| if (completion.choices && completion.choices.length > 0) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Prisma schema adds
apiBaseUrlandmodelId, but there’s no corresponding migration checked in underprisma/migrations. If the project relies on migrations (it looks like it does), this will cause schema drift / deploy failures. Please generate and commit a migration for these new columns.