Implement Google AI Studio model list dynamic fetching

ff4a98a9399d349745e9abe10380735bd24fc89d

InterestingDarkness <computeridiot999@gmail.com>

3 files changed, +63 -48Ignore whitespace
public/index.html+1 -47
@@ -3189,53 +3189,7 @@
31893189 <div>
31903190 <h4 data-i18n="Google Model">Google Model</h4>
31913191 <select id="model_google_select">
3192- <optgroup label="Gemini 2.5">
3192+ <option value="" data-i18n="-- Connect to the API --">-- Connect to the API --</option>
3193- <option value="gemini-2.5-pro-preview-06-05">gemini-2.5-pro-preview-06-05</option>
3194- <option value="gemini-2.5-pro-preview-05-06">gemini-2.5-pro-preview-05-06</option>
3195- <option value="gemini-2.5-pro-preview-03-25">gemini-2.5-pro-preview-03-25</option>
3196- <option value="gemini-2.5-pro-exp-03-25">gemini-2.5-pro-exp-03-25</option>
3197- <option value="gemini-2.5-flash-preview-05-20">gemini-2.5-flash-preview-05-20</option>
3198- <option value="gemini-2.5-flash-preview-04-17">gemini-2.5-flash-preview-04-17</option>
3199- </optgroup>
3200- <optgroup label="Gemini 2.0">
3201- <option value="gemini-2.0-pro-exp-02-05">gemini-2.0-pro-exp-02-05 → 2.5-pro-exp-03-25</option>
3202- <option value="gemini-2.0-pro-exp">gemini-2.0-pro-exp → 2.5-pro-exp-03-25</option>
3203- <option value="gemini-exp-1206">gemini-exp-1206 → 2.5-pro-exp-03-25</option>
3204- <option value="gemini-2.0-flash-001">gemini-2.0-flash-001</option>
3205- <option value="gemini-2.0-flash-exp-image-generation">gemini-2.0-flash-exp-image-generation</option>
3206- <option value="gemini-2.0-flash-exp">gemini-2.0-flash-exp</option>
3207- <option value="gemini-2.0-flash">gemini-2.0-flash</option>
3208- <option value="gemini-2.0-flash-thinking-exp-01-21">gemini-2.0-flash-thinking-exp-01-21 → 2.5-flash-preview-04-17</option>
3209- <option value="gemini-2.0-flash-thinking-exp-1219">gemini-2.0-flash-thinking-exp-1219 → 2.5-flash-preview-04-17</option>
3210- <option value="gemini-2.0-flash-thinking-exp">gemini-2.0-flash-thinking-exp → 2.5-flash-preview-04-17</option>
3211- <option value="gemini-2.0-flash-lite-001">gemini-2.0-flash-lite-001</option>
3212- <option value="gemini-2.0-flash-lite-preview-02-05">gemini-2.0-flash-lite-preview-02-05</option>
3213- <option value="gemini-2.0-flash-lite-preview">gemini-2.0-flash-lite-preview</option>
3214- </optgroup>
3215- <optgroup label="Gemini 1.5">
3216- <option value="gemini-1.5-pro-latest">gemini-1.5-pro-latest</option>
3217- <option value="gemini-1.5-pro-002">gemini-1.5-pro-002</option>
3218- <option value="gemini-1.5-pro-001">gemini-1.5-pro-001</option>
3219- <option value="gemini-1.5-pro">gemini-1.5-pro</option>
3220- <option value="gemini-1.5-flash-latest">gemini-1.5-flash-latest</option>
3221- <option value="gemini-1.5-flash-002">gemini-1.5-flash-002</option>
3222- <option value="gemini-1.5-flash-001">gemini-1.5-flash-001</option>
3223- <option value="gemini-1.5-flash">gemini-1.5-flash</option>
3224- <option value="gemini-1.5-flash-8b-001">gemini-1.5-flash-8b-001</option>
3225- <option value="gemini-1.5-flash-8b-exp-0924">gemini-1.5-flash-8b-exp-0924</option>
3226- <option value="gemini-1.5-flash-8b-exp-0827">gemini-1.5-flash-8b-exp-0827</option>
3227- <option value="gemini-1.5-flash-8b">gemini-1.5-flash-8b</option>
3228- </optgroup>
3229- <optgroup label="Gemma">
3230- <option value="gemma-3n-e4b-it">gemma-3n-e4b-it</option>
3231- <option value="gemma-3-27b-it">gemma-3-27b-it</option>
3232- <option value="gemma-3-12b-it">gemma-3-12b-it</option>
3233- <option value="gemma-3-4b-it">gemma-3-4b-it</option>
3234- <option value="gemma-3-1b-it">gemma-3-1b-it</option>
3235- </optgroup>
3236- <optgroup label="LearnLM">
3237- <option value="learnlm-2.0-flash-experimental">learnlm-2.0-flash-experimental</option>
3238- </optgroup>
32393193 </select>
32403194 </div>
32413195 </form>
public/scripts/openai.js+18 -1
@@ -1912,6 +1912,24 @@ function saveModelList(data) {
19121912
19131913 $('#model_pollinations_select').val(oai_settings.pollinations_model).trigger('change');
19141914 }
1915+
1916+ if (oai_settings.chat_completion_source === chat_completion_sources.MAKERSUITE) {
1917+ $('#model_google_select').empty();
1918+ model_list.forEach((model) => {
1919+ $('#model_google_select').append(
1920+ $('<option>', {
1921+ value: model.id,
1922+ text: model.id,
1923+ }));
1924+ });
1925+
1926+ const selectedModel = model_list.find(model => model.id === oai_settings.google_model);
1927+ if (model_list.length > 0 && (!selectedModel || !oai_settings.google_model)) {
1928+ oai_settings.google_model = model_list[0].id;
1929+ }
1930+
1931+ $('#model_google_select').val(oai_settings.google_model).trigger('change');
1932+ }
19151933}
19161934
19171935function appendOpenRouterOptions(model_list, groupModels = false, sort = false) {
@@ -3700,7 +3718,6 @@ async function getStatusOpen() {
37003718 chat_completion_sources.SCALE,
37013719 chat_completion_sources.CLAUDE,
37023720 chat_completion_sources.AI21,
3703- chat_completion_sources.MAKERSUITE,
37043721 chat_completion_sources.VERTEXAI,
37053722 chat_completion_sources.PERPLEXITY,
37063723 chat_completion_sources.GROQ,
src/endpoints/backends/chat-completions.js+44 -0
@@ -1092,6 +1092,50 @@ router.post('/status', async function (request, response_getstatus_openai) {
10921092 api_url = 'https://text.pollinations.ai';
10931093 api_key_openai = 'NONE';
10941094 headers = {};
1095+ } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.MAKERSUITE) {
1096+ // For Google AI Studio, we need to get models from the API
1097+ const api_key_makersuite = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.MAKERSUITE);
1098+ const api_url = new URL(request.body.reverse_proxy || API_MAKERSUITE);
1099+ let models_url = `${api_url.origin}/v1beta/models?key=${api_key_makersuite}`;
1100+
1101+ if (!api_key_makersuite && request.body.reverse_proxy) {
1102+ models_url = `${api_url.origin}/v1beta/models`; // For some special reverse proxy, we can't pass the API key
1103+ } else if (!api_key_makersuite && !request.body.reverse_proxy) {
1104+ console.warn('Google AI Studio API key is missing.');
1105+ return response_getstatus_openai.status(400).send({ error: true });
1106+ }
1107+
1108+ try {
1109+ const response = await fetch(models_url, {
1110+ method: 'GET',
1111+ headers: {
1112+ 'Content-Type': 'application/json',
1113+ },
1114+ });
1115+
1116+ if (response.ok) {
1117+ const data = await response.json();
1118+ // Transform Google AI Studio models to OpenAI format
1119+ const models = data.models
1120+ ?.filter(model => model.supportedGenerationMethods?.includes('generateContent'))
1121+ ?.map(model => ({
1122+ id: model.name.replace('models/', ''),
1123+ object: 'model',
1124+ created: Date.now(),
1125+ owned_by: 'google',
1126+ })) || [];
1127+
1128+ response_getstatus_openai.send({ data: models });
1129+ console.info('Available Google AI Studio models:', models.map(m => m.id));
1130+ return;
1131+ } else {
1132+ console.error('Google AI Studio models endpoint failed:', response.status, response.statusText);
1133+ return response_getstatus_openai.send({ error: true, can_bypass: true, data: { data: [] } });
1134+ }
1135+ } catch (error) {
1136+ console.error('Error fetching Google AI Studio models:', error);
1137+ return response_getstatus_openai.send({ error: true, can_bypass: true, data: { data: [] } });
1138+ }
10951139 } else {
10961140 console.warn('This chat completion source is not supported yet.');
10971141 return response_getstatus_openai.status(400).send({ error: true });