Merge pull request #4113 from InterestingDarknessII/google-dynamic-model Implement Google AI Studio model list dynamic fetching

88cd8bbbf3b46dc714babf4815312798f2398bc9

Cohee <18619528+Cohee1207@users.noreply.github.com>

Signed
3 files changed, +74 -1Ignore whitespace
public/index.html+1 -0
@@ -3236,6 +3236,7 @@
3236 <optgroup label="LearnLM">3236 <optgroup label="LearnLM">
3237 <option value="learnlm-2.0-flash-experimental">learnlm-2.0-flash-experimental</option>3237 <option value="learnlm-2.0-flash-experimental">learnlm-2.0-flash-experimental</option>
3238 </optgroup>3238 </optgroup>
3239 <optgroup id="google_other_models" label="Other"></optgroup>
3239 </select>3240 </select>
3240 </div>3241 </div>
3241 </form>3242 </form>
public/scripts/openai.js+30 -1
@@ -1912,6 +1912,36 @@ function saveModelList(data) {
19121912
1913 $('#model_pollinations_select').val(oai_settings.pollinations_model).trigger('change');1913 $('#model_pollinations_select').val(oai_settings.pollinations_model).trigger('change');
1914 }1914 }
1915
1916 if (oai_settings.chat_completion_source === chat_completion_sources.MAKERSUITE) {
1917 // Clear only the "Other" optgroup for dynamic models
1918 $('#google_other_models').empty();
1919
1920 // Get static model options that are already in the HTML
1921 const staticModels = [];
1922 $('#model_google_select option').each(function() {
1923 staticModels.push($(this).val());
1924 });
1925
1926 // Add dynamic models to the "Other" group
1927 model_list.forEach((model) => {
1928 // Only add if not already in static list
1929 if (!staticModels.includes(model.id)) {
1930 $('#google_other_models').append(
1931 $('<option>', {
1932 value: model.id,
1933 text: model.id,
1934 }));
1935 }
1936 });
1937
1938 const selectedModel = model_list.find(model => model.id === oai_settings.google_model);
1939 if (model_list.length > 0 && (!selectedModel || !oai_settings.google_model)) {
1940 oai_settings.google_model = model_list[0].id;
1941 }
1942
1943 $('#model_google_select').val(oai_settings.google_model).trigger('change');
1944 }
1915}1945}
19161946
1917function appendOpenRouterOptions(model_list, groupModels = false, sort = false) {1947function appendOpenRouterOptions(model_list, groupModels = false, sort = false) {
@@ -3700,7 +3730,6 @@ async function getStatusOpen() {
3700 chat_completion_sources.SCALE,3730 chat_completion_sources.SCALE,
3701 chat_completion_sources.CLAUDE,3731 chat_completion_sources.CLAUDE,
3702 chat_completion_sources.AI21,3732 chat_completion_sources.AI21,
3703 chat_completion_sources.MAKERSUITE,
3704 chat_completion_sources.VERTEXAI,3733 chat_completion_sources.VERTEXAI,
3705 chat_completion_sources.PERPLEXITY,3734 chat_completion_sources.PERPLEXITY,
3706 chat_completion_sources.GROQ,3735 chat_completion_sources.GROQ,
src/endpoints/backends/chat-completions.js+43 -0
@@ -1092,6 +1092,49 @@ router.post('/status', async function (request, response_getstatus_openai) {
1092 api_url = 'https://text.pollinations.ai';1092 api_url = 'https://text.pollinations.ai';
1093 api_key_openai = 'NONE';1093 api_key_openai = 'NONE';
1094 headers = {};1094 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 const apiVersion = getConfigValue('gemini.apiVersion', 'v1beta');
1100 let models_url = `${api_url.origin}/${apiVersion}/models?key=${api_key_makersuite}`;
1101
1102 if (!api_key_makersuite && request.body.reverse_proxy) {
1103 models_url = `${api_url.origin}/${apiVersion}/models`; // For some special reverse proxy, we can't pass the API key
1104 } else if (!api_key_makersuite && !request.body.reverse_proxy) {
1105 console.warn('Google AI Studio API key is missing.');
1106 return response_getstatus_openai.status(400).send({ error: true });
1107 }
1108
1109 try {
1110 const response = await fetch(models_url, {
1111 method: 'GET',
1112 headers: {
1113 'Content-Type': 'application/json',
1114 },
1115 });
1116
1117 if (response.ok) {
1118 /** @type {any} */
1119 const data = await response.json();
1120 // Transform Google AI Studio models to OpenAI format
1121 const models = data.models
1122 ?.filter(model => model.supportedGenerationMethods?.includes('generateContent'))
1123 ?.map(model => ({
1124 id: model.name.replace('models/', ''),
1125 })) || [];
1126
1127 response_getstatus_openai.send({ data: models });
1128 console.info('Available Google AI Studio models:', models.map(m => m.id));
1129 return;
1130 } else {
1131 console.error('Google AI Studio models endpoint failed:', response.status, response.statusText);
1132 return response_getstatus_openai.send({ error: true, can_bypass: true, data: { data: [] } });
1133 }
1134 } catch (error) {
1135 console.error('Error fetching Google AI Studio models:', error);
1136 return response_getstatus_openai.send({ error: true, can_bypass: true, data: { data: [] } });
1137 }
1095 } else {1138 } else {
1096 console.warn('This chat completion source is not supported yet.');1139 console.warn('This chat completion source is not supported yet.');
1097 return response_getstatus_openai.status(400).send({ error: true });1140 return response_getstatus_openai.status(400).send({ error: true });