Google Gemini (AI) API has free tier; Easily setup and ran tutorial article React app using API; Wrote 2nd Trial app with user choice for model
Last updated on 9 May 2025
Quick-Info
- Integrating basic query to and response from Gemini AI in a React app using free tier Gemini API is easy.
- Live site of 2nd version of related app I wrote with user choice for model: https://testgeminiapi.netlify.app/ . Public repo: https://github.com/ravisiyer/testGeminiAPI .
- Live site of 1st version of related app I created (based on below mentioned article): https://geminiapitrial.netlify.app/ . Public repo: https://github.com/ravisiyer/GeminiAPITrial . The README.md file has screenshots.
- Related to app 1st version: Tried out this article's code and got it working on localhost: How to Integrate Gemini API with React.js: A Step-by-Step Guide., https://dev.to/tahrim_bilal/how-to-integrate-gemini-api-with-reactjs-a-step-by-step-guide-341b . Had to run 'npm i react-scripts@latest' to get past digital envelope related errors on 'npm start'.
- Related to app 1st version: The app UI is quite decent (output of Gemini seems to be rendered as Markdown). Changed model (later) to gemini-2.0-flash . Note that 2.0 Flash is shown as default in official Google Gemini chat app.
- Related to app 1st and 2nd versions: For general questions, the Gemini API (without Grounding with Google Search) answers (with gemini-2.0-flash as model) seem to be okay. This includes questions like "Give me a useEffect example in React" where the API answers with example code and detailed explanation. But for some detailed questions, the quality of answers via the API (without Grounding with Google Search) with gemini-2.0-flash as model are sometimes poor as compared to answers with 2.0 Flash model in Google Gemini chat app for the same detailed questions. I have not yet tested with these detailed questions for Gemini API model gemini-2.0-flash with Grounding with Google Search.
- Had to use Grounding with Google Search to combine Gemini API model data with Google search results data. Note that gemini-2.0-flash API said, "My knowledge cutoff date is September 2021. This means I don't have information about events or developments that occurred after that point." On asking it, " https://gemini.google.com/app?hl=en-IN uses 2.0 flash but it has more updated data", gemini-2.0-flash API said, "Don't expect the Gemini API to automatically behave exactly like the Gemini web app. The API is designed for programmatic access to the core language model, while the web app is often a more polished, integrated, and potentially updated experience with real-time data access. You need to understand the limitations of the API and, if you need real-time data, implement your own mechanisms to provide that information to the model." So gemini-2.0-flash API used without Google search data tool is not good for getting info on current events. Even a question like who is the president of USA gave me a wrong answer of Joe Biden. But Gemini web app using Gemini 2.0 Flash model (which seems to be same model as that of gemini-2.0-flash API) gave me correct answer of Donald Trump. Looks like Gemini web app gets updated data from searching the web. After the Grounding with Google Search fix was added to Gemini API calling code in the test app, it now provides the correct answer of Donald Trump to the question: who is the president of USA?
- When using API, context of previous question is not remembered and so has to be provided along with the new question. In contrast, the Gemini web app remembers earlier context making it possible to have a conversation over multiple message interactions. As a specific example, "Who is president of USA" followed by "Tell me more about him" works with Gemini web app but does not work with Gemini API for what seems to be the same model - Gemini Flash 2.0.
- @google/genai library is the new library to be used. The older @google/generative-ai library is either already deprecated or expected to be deprecated 'soon'. 1st version app uses @google/generative-ai but 2nd version app uses @google/genai .
- @google/genai documentation for JavaScript is not great. Further the library seems incomplete as it does not have a list models function (which the older library @google/generative-ai seems to have). But there is a REST API which returns list of models (which is used by 2nd version app). However the information in this list is not enough. It does not have fields/properties for cut-off date, release date, whether it is available as free-tier and even whether it is deprecated or not. The description field sometimes has text saying a model is deprecated. For free-tier availability check, one has to try out the models. The error messages returned for models that are deprecated or not available in free tier are quite clear.
- Google Gemini API seems to have a decent free tier. As ChatGPT API does not have a free tier, Google Gemini API is superior to ChatGPT API in this aspect, which would be an imporant point for nonprofit NGOs. (IFIRC, ChatGPT API claims to have a 'free tier' but API calls fail with no quota or similar message and so it does not really have a 'free tier.)
- But as ChatGPT web app has a free tier and I am more comfortable chatting with it than Gemini web app, I used ChatGPT web app to resolve some issues I faced while developing 2nd version app! And sometimes when I used Google search for help on some issue, Google search AI (which probably uses Gemini) response was helpful. In other words, the 2nd version app using free tier Gemini AI API, was developed with some assistance, at times, from free tier ChatGPT web app and also Google Search AI! The detailed log below gives more info on these assists.
Detailed Log
In response to my sharing that ChatGPT API does not have a free tier, a friend had suggested Google's AI API. That prompted the activity covered by this post. Thanks to my friend for his suggestion.
Generated free API key at https://aistudio.google.com/app/apikey .
I first tried out code from this article: Integration of Gemini AI In React, https://medium.com/@codewithadurintiashok/integration-of-gemini-ai-in-react-8872025088de .
I had to run 'npm i react-scripts@latest' to fix some digital envelope related errors.
Then the program ran but Gemini gave an error that model is not found (code was using model: "gemini-pro").
https://ai.google.dev/gemini-api/docs/models lists currently available models
https://ai.google.dev/gemini-api/docs/pricing gives models and pricing
Gemini 1.5 Pro model seems to have free tier. Its name from https://ai.google.dev/gemini-api/docs/models : "gemini-1.5-pro"
Used "gemini-1.5-pro" as model in the app and the app worked with Gemini AI providing a response to my query/prompt which was shown by the app. However the app UI was very primitive and was rendering what seems to be Markdown response from Gemini API as plain text.
So I switched to this article's code (seems to be more sophisticated): How to Integrate Gemini API with React.js: A Step-by-Step Guide., https://dev.to/tahrim_bilal/how-to-integrate-gemini-api-with-reactjs-a-step-by-step-guide-341b Has a GitHub repo: https://github.com/Tahrim19/chatbot and a live site: https://chatbot-kappa-five.vercel.app/ (shows up page but fails to get response from Gemini; browser console shows "API key expired. Please renew the API key.").
Added key to .env file as instructed in article....
REACT_APP_GEMINI_API_KEY=YOUR-API-KEY
----
Ran: npm install react-markdown (and later, after I got an error) npm install react-icons
IFIRC, I ran 'npm i react-scripts@latest' to get past digital envelope related errors on 'npm start'
Changed model to gemini-1.5-pro in src\components\Model.jsx . Old code:
// const model = genAI.getGenerativeModel({ model: "gemini-1.5-flash" });
-----
The app worked on localhost and the UI is much, much better than the previous article app that I had tried.
I later changed model to gemini-2.0-flash (which is what is shown as default (2.0 Flash) in official Google Gemini chat app).
The quality of answers via the API with gemini-2.0-flash as model are sometimes poor as compared to answers with 2.0 Flash model in official Google Gemini chat app for the same detailed questions related to Bhagavan Sri Sathya Sai Baba (Did sathya sai baba travel out of india?)!
For general questions, the API answers seem to be okay.
Google Gemini API seems to have a decent free tier as I was able to do fair amount of test interactions and its usage info. page, Quotas tab (https://console.cloud.google.com/apis/api/generativelanguage.googleapis.com/quotas?project=xxxxx) showed that I had not exhausted my quota per day for the two models I tried.
There is small variation in the API code used in this app and what is shown in the docs now: https://ai.google.dev/api/generate-content#text_gen_text_only_prompt-JAVASCRIPT .
App code:
const { GoogleGenerativeAI } = require("@google/generative-ai");
const key = process.env.REACT_APP_GEMINI_API_KEY
const genAI = new GoogleGenerativeAI(key);
const modelName = process.env.REACT_APP_GEMINI_MODEL_NAME;
const model = genAI.getGenerativeModel({ model: modelName });
export const generateContent = async (prompt) => {
const result = await model.generateContent(prompt);
console.log(result.response.text());
return result.response.text; // return the response
}
Docs code:
// Make sure to include the following import:
// import {GoogleGenAI} from '@google/genai';
const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });
const response = await ai.models.generateContent({
model: "gemini-2.0-flash",
contents: "Write a story about a magic backpack.",
});
console.log(response.text);
====================
Perhaps the app code uses an older approach. But as the app code works and the variation is small, I don't want to change it as that will mean more time to test.
Put up the code as a public repo and later deployed it to netlify (links given at beginning of post).
======================
Given below is a log of additional notes as I first made some small enchancements to the small app (1st version app) followed by writing a 2nd version app which allows user to choose the model:
28 Apr. 2025
[To temporarily disable continuous deployment in Netlify:] From https://docs.netlify.com/configure-builds/stop-or-activate-builds/#stop-builds
"To stop builds for a site, go to Site configuration > Build & deploy > Continuous deployment > Build settings, select Configure, and then toggle Build status to Stopped builds."
How to prevent Netlify from treating warnings as errors because process.env.CI = true?, https://stackoverflow.com/questions/62415804/how-to-prevent-netlify-from-treating-warnings-as-errors-because-process-env-ci
Treating warnings as errors because process.env.CI = true.
Most CI servers set it automatically.
Failed to compile.
...
Once your deployment is failed, go to Deploys -> Deployment Settings.
There you will see Environment tab. Then click Environment Variables -> Edit Variables
Key: CI
Value: False
=================
I faced the above issue and the deploy failed. Then ...
In netlify, I created an env var. CI with value as false.
Then I went to failed deploy where I clicked a Retry drop down and chose something like clear cache and build.
That worked. The warning is reported in the build log but does not stop the build process and the site going live with the new build output.
===================
Complicated way to see console log for app running on Android mobile chrome: How to View the Google Chrome Console on Android, https://www.youtube.com/watch?v=RSgfFZTBY1Y , around 6 mins, Jan. 2025.
I am able to handle Shift + enter correctly on PC but on Android mobile I don't think it is providing a correct event for Shift key being depressed (or CAPS LOCK being on). Here's the code I used to test this out with the handler wired to onKeyDown prop of textarea:
const handleKeyPress = (e) => {
if (e.getModifierState('CapsLock')) {
setResponse([{ type: "system", message: "handleKeyPress: CapsLock is On." }]);
return
}
if (e.shiftKey) {
setResponse([{ type: "system", message: "handleKeyPress: Shift Key is On." }]);
return
}
if (!e.shiftKey && e.key === 'Enter') {
e.preventDefault();
handleSubmit();
}
};
------
https://www.npmjs.com/package/react-device-detect - Detect device, and render view according to the detected device type.
Am trying out above to detect if app is on mobile and if so then not triggering handleSubmit on Enter. In other words, on mobile user has to tap the Send button.
That worked!
===============
User questions are also interpreted as MarkDown by the program when it renders the user questions. So one newline is treated as one space. Two newlines result in one newline. Need to fix that code.
Changed manifest.json and package.json to new app name.
Created logos for program using Gemini: Create logo images of a Gemini AI API trial program of sizes 192x192 and 512x512
Convered png to ico using: https://cloudconvert.com/png-to-ico
Had to change title in index.html to change Chrome window title.
==============
30 Apr. 2025
CSS Units - What is the difference between vh/vw and %?, https://stackoverflow.com/questions/31039979/css-units-what-is-the-difference-between-vh-vw-and
Key point is % is relative to container element (e.g. div).
Also % seems to exclude scrollbar.
==============
Create React App (CRA) index.css does not have CSS reset. Using 100vh for body or some other element results in height slightly greater than window height. If 'overflow: hidden' is not specified, a vertical scrollbar appears.
To avoid that issue for a React app created with CRA and have body element (or perhaps some other element within body) take up full window height, following code in index.css works IFIRC:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body{
min-height: 100vh;
... // Other pre-existing code in index.css
}
----
Also see div-fitContentsToWindowHeight.html in ...VSCode\HTML-CSS-JSsamples-and-ravi-tests folder (on PC) which demonstrates this in plain HTML file.
However, in the Gemini API trial program, above approach causes an issue for ReactMarkdown component rendered HTML like p and ul elements. Their default margins are also reset (to 0) and so the resulting rendering is not so good.
The code below does not fix the basic issue of html and body height exceeding window height.
html, body {
margin: 0;
padding: 0;
box-sizing: border-box;
}
-----
I think it is best to revert to not using the CSS reset due to ReactMarkdown issue. Reverted
It seems OK on PC and mobile portrait mode. But on mobile landscape mode the input box is partially below the display and hence unusable. Also the PWA install on phone, IFIRC, showed a blank bottom rectangular area of different color from background color of rest of screen.
I think I should invest further time on these sort of styling issues only when I really need this functionality in a regular app as against a trial app.
To fix the newlines issue in user input rendering ... Based on: How to replace /n to linebreaks in react.js?, https://stackoverflow.com/questions/40418024/how-to-replace-n-to-linebreaks-in-react-js , I used the following code:
const escapedNewLineToLineBreakTag = (string) => {
const x = string.split('\n').map((item, index) => {
return (index === 0) ? item : [<br key={index} />, item]
})
console.log(x)
return x;
// return string.split('\n').map((item, index) => {
// return (index === 0) ? item : [<br key={index} />, item]
// })
}
...
{msg.type === "user" ? escapedNewLineToLineBreakTag(msg.message) : <ReactMarkdown>{msg.message}</ReactMarkdown>}
-----
The code worked but I don't know about React handling an array in above statement. Further an element of the array can be a plain string or another array having a br tag and a plain string. Chrome debugger console info. gave me this data. As of now, I don't want to dig deeper into how exactly this works and dig up related React docs for it. Maybe sometime later on ...
=============
Am trying out Gemini API for other stuff now. See info.txt of test-my-app for more. An extract from it dated 28 Apr. 2025 (slightly edited):
Now I have broken link in my-app folder (and its .git folder) to remote GH repo. I plan to try out some general stuff related to Gemini API.
I later renamed my-app to test-my-app to avoid confusion with the regular Gemini API trial project in what was previously my-app folder. Now I will be making commits to test-my-app but that is not linked to the remote Gemini API trial GitHub repo and is instead linked to another private remote repo I created for test-my-app folder: https://github.com/ravisiyer/testGeminiAPI.
------ end extract ------
https://ai.google.dev/api?lang=node uses @google/genai whereas the earlier trial used @google/generative-ai.
Switching to @google/genai in Trial.jsx component (which is what test-my-app uses (instead of Home component)). ... Done.
Commit: Migrated to current docs @google/genai from @google/generative-ai
I struggled to get a list of available models using @google/genai and have not yet succeeded.
https://ai.google.dev/api/models gives a python example which has:
client = genai.Client()
-----
When I tried equivalent in JS, IFIRC, I got an error that Client does not exist on the genAI object (my variable name was slightly different).
The shell example is (invokes a REST API):
curl https://generativelanguage.googleapis.com/v1beta/models?key=$GEMINI_API_KEY
That works on command line.
But I want to access it via the JS API: https://ai.google.dev/gemini-api/docs/libraries#javascript :
The new JavaScript/TypeScript library is currently in preview, which means it may not be feature complete and that we may need to introduce breaking changes.
However, we highly recommend you start using the new SDK over the previous, soon-to-be deprecated version, as long as you are comfortable with these caveats. We are actively working towards a GA (General Availability) release for this library.
---------
Ref. page for JS API: https://www.npmjs.com/package/@google/genai
JS samples GitHub repo folder: https://github.com/googleapis/js-genai/tree/main/sdk-samples . It has a lot of generate content examples and a get model info example but I could not locate an example for listing models.
I guess the list models is available in python and REST API but not yet available in new JS API. Hmm.
I had tried asking this of Gemini chat which turned out to be a waste of time, unless I made some mistake in understanding its responses (which I doubt). Here's a copy of the chat: https://docs.google.com/document/d/1Z3PFGVKeomdxjYIQNPzAiaQAhbHz0DMCB8zliSkyaHs/edit?usp=drive_link .
Essential parts of the chat :
I asked:
How to getting list of available models in gemini API using Javascript and @google/genai package
[Should have been get instead of getting]
Gemini responded with example code having "import { GoogleGenerativeAI } from '@google/generative-ai';".
On me saying that I want @google/genai package example, Gemini gave the following code:
import { GoogleGenerativeAI } from '@google/genai';
// Replace with your actual API key
const genAI = new GoogleGenerativeAI(process.env.API_KEY);
async function listAvailableModels() {
try {
const modelList = await genAI.listModels();
const models = modelList.models;
if (models && models.length > 0) {
console.log("Available Gemini API models:");
models.forEach(model => {
console.log(`- Name: ${model.name}`);
console.log(` Description: ${model.description}`);
console.log(` Input modalities: ${model.inputModalities.join(', ')}`);
console.log(` Output modalities: ${model.outputModalities.join(', ')}`);
console.log(` Supported generation methods: ${model.supportedGenerationMethods.join(', ')}`);
console.log("---");
});
} else {
console.log("No models found.");
}
} catch (error) {
console.error("Error listing models:", error);
}
}
listAvailableModels();
------
But when I tried above code, I got an error: Attempted import error: 'GoogleGenerativeAI' is not exported from '@google/genai' (imported as 'GoogleGenerativeAI').
I informed Gemini of the error but it was not able to give me a solution. It instead repeated what seems to be the same code in its response.
Then I gave up.
=============================
A learning from this effort is that Gemini AI JavaScript API in its current package: '@google/genai' seems to be incomplete. I could use the older version '@google/generative-ai' but the docs say that will be soon deprecated! The REST API may be the way to go but I wonder whether I will face such issues there too. It is quite disappointing to see that I am having to struggle to figure this out using Google Gemini documentation. It would have been great if the https://ai.google.dev/api/models page clearly had said that python API is ready for list models but that JS library API for @google/genai currently does not support list models. That would have saved me quite a bit of time and struggle.
....
The REST API for list models works:
async function listAvailableModels() {
const url = `https://generativelanguage.googleapis.com/v1beta/models?key=${key}`
console.log(`listAvailableModels url: ${url}`)
let data;
try {
const response = await fetch(url);
if (!response.ok) {
console.error(`HTTP error! status: ${response.status}`);
}
data = await response.json();
} catch (error) {
console.error("Fetching data failed:", error);
}
console.log("Available models:", data);
}
-------------------
Data in console:
Object
models
:
Array(49)
0
:
description
:
"A legacy text-only model optimized for chat conversations"
displayName
:
"PaLM 2 Chat (Legacy)"
inputTokenLimit
:
4096
name
:
"models/chat-bison-001"
outputTokenLimit
:
1024
supportedGenerationMethods
:
(2) ['generateMessage', 'countMessageTokens']
temperature
:
0.25
topK
:
40
topP
:
0.95
version
:
"001"
[[Prototype]]
:
Object
1
:
{name: 'models/text-bison-001', version: '001', displayName: 'PaLM 2 (Legacy)', description: 'A legacy model that understands text and generates text as an output', inputTokenLimit: 8196, …}
2
:
{name: 'models/embedding-gecko-001', version: '001', displayName: 'Embedding Gecko', description: 'Obtain a distributed representation of a text.', inputTokenLimit: 1024, …}
---snip---
===============
data.models[x].name should give the name (it has models/ at the beginning; that works with generateContent call). displayName is useful.
supportedGenerationMethods[] should have 'generateContent'.
supportedGenerationMethods.includes('generateContent')
==========
Explore using https://headlessui.com/react/listbox in Modal ... The hassle is that styling seems to be complicated. The examples use Tailwind CSS.
ListBox of PrimeReact seems to be more suitable for my current needs: https://primereact.org/listbox/
For the selections to be visible, I had to use a theme with:
import "primereact/resources/themes/lara-light-cyan/theme.css";
----
Once I figured out the above, I faced only minor issues which were easy to resolve. So I find this ListBox component to be very easy to use for my limited styling (without Tailwind) needs currently.
==============
Current approach for getting vertical scrollbar only for (trial) response involves:
a) overflow:hidden in body (else vertical scrollbar appears for whole page)
b) trial respons has overflow-y: auto and max-height: 60vh for mobile and 70vh above mobile (768).
I have HTML examples which use a different approach but there I have lot more control over all elements.
Here, in React app done with CRA there are elements like root element that do not have CSS associated with it.
But I think I should see I am managing this scrolling stuff in my blog app (based on DG tutorial) as that also IFIRC is a CRA created app.
Meanwhile above solution is quite OK. It breaks while typing in many line input but that's temporary and so OK, I guess.
A key aspect of the issue that appears if xxvh is not used for trial response element, is that the body and other elements seem to automatically expand their height based on content of trial response and if body height exceeds the screen size, as overflow is hidden in body, vertical scrollbar does not appear. trial response height also crosses screen height and its overflow-y: auto may not be resulting in vertical scroll as its parent element(s) are having enought height for its content even if that height is beyond screen height. Adding a xxvh at trial response does the trick.
However, calculating the right vh to set can be tricky as it is dependent on height of content above it which varies based on window width and lines of text in input! I googled to see if I could get some calc examples for this case but could not get suitable answers.
==========================
1 May 2025
ChatGPT answer to my question: In an html textarea element how can I have a default value with new lines
To set a default value with new lines in an HTML <textarea>, you simply include the value as the text between the opening and closing <textarea> tags. Use actual line breaks (\n or just press Enter) in the HTML code to insert new lines.
<textarea name="message" rows="5" cols="30">
This is line 1.
This is line 2.
This is line 3.
</textarea>
======================
That works. Only issue is that if there are tabs in the editor for these lines then these tabs result in unwanted spaces before the output text lines in the text area.
ChatGPT agreed and said:
The most straightforward fix is to avoid indenting the contents of <textarea>:
<textarea name="message" rows="5" cols="30">This is line 1.
This is line 2.
This is line 3.</textarea>
============
It also gave an alternative of: Remove Indentation with JavaScript
I don't want to get into that.
=================
Set scroll div height dynamically:
Did some trials with plain HTML and CSS, and came up with a solution that may work to set trial response height dynamically based on available area and such that all of its content is visible with scrolling (vertical scroll bar is fully visible and does not go off screen). The HTML & CSS solution involves the following:
1. Having a container div with CSS:
display: flex;
flex-direction: column;
max-height: 100vh;
2. 1st div in container does not have vertical scrollbar but can have textarea with its own vertical scrollbar. 1st div CSS:
flex-grow: 0;
3. 2nd div in container has content that, if required, can be vertically scrolled. This div's size is automatically changed such that it does not go off-screen. This is like what we have in trial response. 2nd div CSS:
flex-grow: 1;
overflow-y: auto;
----
To have Textarea element take up almost full width of window:
width: calc(100vw - 24px);
The padding for Textarea element's parent div is 20px. But using 'width: calc(100vw - 24px)' leaves a smaller vertical gap between textarea border on right and window border. 24px seems to be suitable with similar vertical gaps on both sides of textarea element. Note that 'box-sizing: border-box;' is applied globally. Probably the additional 4px is for associated border sizes.
The file demonstrating this is: div-fit2nddivToWinHtWflexgrow.html in ...\VSCode\HTML-CSS-JS\samples-and-ravi-tests\ on PC.
=========
The above "Set scroll div height dynamically" approach worked for trial response height. It also worked for height of list of models shown in a Modal (dialog).
=================
Seems like in React, setting input text HTML element's width to fit content may need JavaScript and measuring the text content width. But there is a 3rd party component that seems to do the job: react-input-autosize, https://www.npmjs.com/package/react-input-autosize . But that has a dependency conflict with React 19!!!
Google Search AI gave an interesting code example for: React 19 input text auto width :
import React, { useState, useEffect, useRef } from 'react';
function AutosizeInput() {
const [text, setText] = useState('');
const [inputWidth, setInputWidth] = useState('auto');
const inputRef = useRef(null);
const measureRef = useRef(null);
useEffect(() => {
if (!measureRef.current) return;
measureRef.current.textContent = text;
setInputWidth(measureRef.current.offsetWidth + 2); // Add some extra space
}, [text]);
return (
<div style={{ display: 'inline-block' }}>
<span
style={{
position: 'absolute',
whiteSpace: 'nowrap',
visibility: 'hidden',
font: getComputedStyle(inputRef.current).font,
}}
ref={measureRef}
>
{text}
</span>
<input
type="text"
value={text}
onChange={(e) => setText(e.target.value)}
style={{ width: inputWidth, minWidth: '10px' }}
ref={inputRef}
/>
</div>
);
}
export default AutosizeInput;
============
Let me try it in the trials project (test-my-app).
I got an error about: Failed to execute 'getComputedStyle' on 'Window' for this line:
font: getComputedStyle(inputRef.current).font,
----
Browsing for the error for React suggested checking for inputRef.current before invoking getComputedStyle. So I used the following code:
font: modelUsedInputRef.current ? getComputedStyle(modelUsedInputRef.current).font : null,
----
I don't know what value to use if modelUsedInputRef.current is undefined/null and so I just tried null. That seems to not trip up anything.
Now the code seems to work! The last character is not shown and needs scrolling. But that fix should be minor ... changed 2 to 8 in below line:
setModelUsedInputWidth(measureRef.current.offsetWidth + 8); // Add some extra space
----
Now last character is shown correctly.
That's nice! Plan to study the code and understand it for any future needs I may have for such functionality.
============================
============================
1st to 4th May 2025
1 May 2025
ChatGPT: To reduce the padding for list entries in a PrimeReact ListBox, you need to override the default CSS applied to each list item.
Each item in a ListBox is rendered using a class like .p-listbox-item. PrimeReact uses fairly padded defaults for accessibility and visual clarity, but you can customize it.
✅ Example CSS to reduce padding:
/* Target listbox items */
.p-listbox .p-listbox-list .p-listbox-item {
padding: 0.25rem 0.5rem; /* Adjust these values as needed */
line-height: 1.2; /* Optional: reduce line height */
}
Optional: reduce font size too
.p-listbox .p-listbox-list .p-listbox-item {
font-size: 0.85rem;
}
========================
I tried out the first of the above (excluding font-size setting) and it worked well.
=========
ChatGPT response to: Is there not a simple CSS class solution which applies padding if associated element is non empty?
.has-padding:not(:empty) {
padding: 1rem;
}
...
Explanation:
:empty matches elements with no child nodes (no text, no elements, no comments).
:not(:empty) does the opposite — it matches elements with content, including text or child elements.
...
<div class="has-padding">This has padding</div>
<div class="has-padding"></div> <!-- No padding applied -->
==== end response ======
I tried above approach and that worked to solve the problem of tiny filled rectangle of background color being shown when "Model selected:" associated value is empty. Now the tiny filled rectangle does not show if value is empty. Related CSS code I used is given below:
.model-select-value {
text-align: left;
/* padding: 2px; */
font-size: 16px;
background-color: #6431c1;
color: white;
/* border-radius: 5%; */
width: auto;
height: auto;
}
.model-select-value:not(:empty) {
padding: 2px;
}
==================
Have made lot of UI improvments to app. Also named it Gemini AI API 2nd Trial.
Some outstanding minor issues:
a) If list of models is not yet available and user opens List Models modal, user is shown 'No available options' in ListBox which may be standard message of PrimeReact ListBox. Ideally I should show a loading message. Or List Modals button itself should be disabled during loading of this list.
b) On Samsung phone, i) before sending message, the top part of screen is shown with different background color (off-white) from bottom part of screen (shown as white). ii) On receiving response which needs vertical scrolling, in portrait mode, the last two or so lines of the response cannot be viewed. But on switching to landscape mode, one can view them and then on switching back to portrait mode one can view them! On Chrome browser on PC in mobile mode, this issue is not there.
2nd May
--------
Fixed above b i) issue.
=============
Is there any way to see names of 'fields' in React multiple state with React DevTools when using 'useState' hooks, https://stackoverflow.com/questions/57659640/is-there-any-way-to-see-names-of-fields-in-react-multiple-state-with-react-dev :
(click) magic button in custom hooks card
-----
Fixed above a) issue
Put in workaround for b ii) issue, by using less than 100vh for < 768px width using media query.
=========
Small gap at bottom (below chat response) appears on using overflow-y: auto; in .trial-chat-response. Removing overflow-y: auto does not seem to affect scrollbars. Both horizontal and vertical scrollbars continue to appear when necessary but the background colour of the response (pink) is not shown on parts that are scrolled horizontally to the right! I think that's due to trial-chat-response div being limited to some width whereas contained ReactMarkdown component, at times, generates content that is wider. I am not getting into this issue as of now and opting to have overflow-y: auto in .trial-chat-response.
=============
Faced a rare issue of 'Generating response' message going away but no response being shown on screen.
Console.log showed undefined against what seems to be response.text.
That issue cropped up twice for the gemini 2.0 flash model but did not happen when I switched to another model.
When I retried with gemini 2.0 flash model, it worked.
An error was not raised.
Added code to test response.text and give suitable message if it is empty/undefined.
Asked gemini-2.0-flash through API:
what is the cutoff date for your data
It responded: My knowledge cutoff date is September 2021. This means I don't have information about events or developments that occurred after that point.
I then asked it: https://gemini.google.com/app?hl=en-IN uses 2.0 flash but it has more updated data. Accessing it through API does not give updated data for questions like who is USA president.
It gave a long response. Its concluding part is:
In Summary
Don't expect the Gemini API to automatically behave exactly like the Gemini web app. The API is designed for programmatic access to the core language model, while the web app is often a more polished, integrated, and potentially updated experience with real-time data access. You need to understand the limitations of the API and, if you need real-time data, implement your own mechanisms to provide that information to the model. Read the API documentation carefully for features related to external data sources.
===========
3rd May
Made some further improvements. Commits listed below:
Made loading available models a regular useEffect; improved UI ...
code cleanup; full/normal width toggle
Styled Full/normal width; Added new message will delete old message
Moved Models list code to new component: GeminiModelsList; Added filter in it
-------
If required, I can replace PrimeReact ListBox with DataTable, https://primereact.org/datatable/ where I can show additional columns like:
*) displayName which in some cases indicates whether it is deprecated or not.
*) description
*) temperature [From Google search: "In Large Language Models (LLMs), the "temperature" parameter controls the randomness or "creativity" of the generated text. Lower values result in more predictable and deterministic outputs, while higher values lead to more diverse and potentially creative, but also less coherent, responses"]
============
As a temporary fix kind-of thing, I tried appending displayName to the name of the model and show that in the ListBox. But that resulted in the entry wrapping down to next line if there was not enough room. I wanted it to scroll horizontally. I tried a lot of CSS stuff some of which is given below but I did not get the solution I wanted:
To various classes like .p-listbox, .p-listbox-item, .p-listbox-list, .p-listbox-header
overflow-x: auto !important;
white-space: nowrap;
---
'display: inline-block;' gave an unsatisfactory solution of horizontal scrollbar appearing on vertically scrolling to bottom of list.
Getting an HTML listbox which showed both vertical and horizontal scrollbar when content overflowed was easy using 'overflow-x: auto;' and 'white-space: nowarp;'. On PC, see div-listbox-hscroll.html in ...VSCode\HTML-CSS-JS\samples-and-ravi-tests
The hassle with figuring out how to get PrimeReact Listbox to behave like above plain HTML example is that lot of attributes are introduced by PrimeReact in the HTML it creates for the listbox. It is not worth investing time to study all that in detail. I did study it using Chrome Inspect to understand the HTML elements involved and also played around with some style settings for them in Chrome Inspect directly and in CSS file used by my app but without success.
So I am discarding this attempt related work.
------------
Got GitHub CoPilot (within VSCode) to review my files. Some of its suggestions were good and incorporated them. First time I am using CoPilot. Interestingly it shows GPT-4o as the (default) model. So through CoPilot's free tier plan, I can access ChatGPT-4o for code review and suggestions! Great!
====================
4 May 2025
Today, I had some great help from ChatGPT in adding a tooltip and then an info. icon button in each item in the Models PrimeReact ListBox.
I have given below key parts of that convo with some additional comments I am making now enclosed in [Ravi-comment-later: end Ravi-comment-later]:
==================================================
Me: how to use PrimeReact ListBox with tooltip
ChatGPT: ...
Option 1: Tooltip on the ListBox component
...
Option 2: Tooltip on individual items (custom template)
You can use itemTemplate to show a tooltip per item:
const itemTemplate = (option) => {
return (
<div title={`City code: ${option.code}`}>
{option.name}
</div>
);
};
// Inside ListBox component:
<ListBox
value={selectedCity}
options={cities}
onChange={(e) => setSelectedCity(e.value)}
optionLabel="name"
itemTemplate={itemTemplate}
/>
---
...
-----------------------------------------
Me: Above implmentation of ListBox tooltip per item works on web. But on Android mobile using Chrome, ListBox tooltip per item does not appear. I think it is related to hover event not getting triggered on Android mobile. Any solution?
ChatGPT: You're absolutely right — on Android mobile (and mobile browsers in general), tooltips based on hover (e.g., title attribute or PrimeReact's Tooltip) do not work reliably because hover events don't exist on touch devices.
...
Would you like me to prepare a reusable component that shows per-item info in a toast or popup for both mobile and desktop?
-----------------------------------------
Me: Yes please. with popup not toast.
ChatGPT: Great! Here's a reusable React component that uses PrimeReact's ListBox and shows a popup dialog (instead of a tooltip or toast) with item-specific info — fully compatible with both mobile and desktop.
...
import React, { useState } from 'react';
import { ListBox } from 'primereact/listbox';
import { Dialog } from 'primereact/dialog';
import { Button } from 'primereact/button';
const cities = [
{ name: 'New York', code: 'NY', info: 'New York is a major city in the USA.' },
{ name: 'Rome', code: 'RM', info: 'Rome is the capital of Italy.' },
{ name: 'London', code: 'LDN', info: 'London is the capital of the UK.' },
{ name: 'Istanbul', code: 'IST', info: 'Istanbul is a major city in Turkey.' },
{ name: 'Paris', code: 'PRS', info: 'Paris is the capital of France.' }
];
const ListBoxWithPopup = () => {
const [selectedCity, setSelectedCity] = useState(null);
const [dialogVisible, setDialogVisible] = useState(false);
const handleItemClick = (e) => {
setSelectedCity(e.value);
setDialogVisible(true);
};
const itemTemplate = (option) => (
<div className="flex justify-between items-center w-full">
<span>{option.name}</span>
<Button
icon="pi pi-info-circle"
className="p-button-text p-button-sm"
onClick={(e) => {
e.stopPropagation(); // prevent ListBox selection
setSelectedCity(option);
setDialogVisible(true);
}}
aria-label={`More info about ${option.name}`}
/>
</div>
);
return (
<div className="card">
<h5>Select a City</h5>
<ListBox
value={selectedCity}
options={cities}
onChange={handleItemClick}
optionLabel="name"
itemTemplate={itemTemplate}
style={{ width: '15rem' }}
/>
<Dialog
header={selectedCity?.name}
visible={dialogVisible}
onHide={() => setDialogVisible(false)}
modal
style={{ width: '80vw', maxWidth: '400px' }}
>
<p>{selectedCity?.info}</p>
</Dialog>
</div>
);
};
export default ListBoxWithPopup;
...
Dependencies (PrimeReact + PrimeIcons):
npm install primereact primeicons
...
And include PrimeReact styles in your main CSS:
js
import 'primereact/resources/themes/lara-light-blue/theme.css';
import 'primereact/resources/primereact.min.css';
import 'primeicons/primeicons.css';
[Ravi-comment-later: I tried the above with some variation appropriate for my code. There were some styling issues but the basic functionality was working though not exactly as I wanted it. So I made some further experimentation and changes. But I got stuck with uncertain click behaviour of the info. icon. I interacted again with ChatGPT about that.
end Ravi-comment-later]
-----------------------------------------
Me: As suggested by you, I added an icon button in PrimeReact ListBox through itemTemplate. Clicking on the icon once usually does not work. I have to click once, wait for some time, and then click again. Then it works. Does PrimeReact icon button when used in a ListBox have this issue?
ChatGPT: That behavior you're describing — where the icon button inside a ListBox item in PrimeReact only works on the second click — is not typical or intended, but it can happen due to one of the following common causes:
...
[Ravi-comment-later: Skipping some code it gave. end Ravi-comment-later]
-----------------------------------------
Me: My code seems to be similar in the main points. Here is my code that has the issue I described earlier:
const itemTemplate = (option) => (
<div className="flex justify-between items-center w-full">
<span className="span-listbox-item">{option.code}</span>
<Button
icon="pi pi-info-circle"
className="p-button-text p-button-sm"
onClick={(e) => {
console.log("Clicked on info icon for option: ", option);
e.stopPropagation(); // prevent ListBox selection
setSelectedModelName(option);
setDialogVisible(true);
}}
// aria-label={More info about ${option.name}}
/>
</div>
);
ChatGPT: Thanks for sharing your code — it looks clean and your use of e.stopPropagation() is exactly what should avoid the ListBox item selection interfering with the button click.
Given that the code appears correct, but you're still experiencing the issue where the first click doesn't trigger the dialog, here are some deeper causes and suggestions:
[Ravi-comment-later: Skipping its suggestions. end Ravi-comment-later]
-----------------------------------------
Me: I tried type="button". That did not solve the issue. Regarding the dialog visibility, I have a console.log statement in the onClick handler. That shows that at times the onClick handler is just not called.
ChatGPT:Thanks for that clarification — the fact that the console.log doesn’t run on the first click confirms the click event is being swallowed by something — most likely ListBox's internal selection logic, focus behavior, or DOM layout quirks.
Even though e.stopPropagation() is present, PrimeReact's ListBox may still interfere, especially if:
It captures the event during a different phase (e.g. capturing vs bubbling).
It uses a custom onClick or onMouseDown that resets focus/selection before your button receives the event.
✅ Reliable Fix: Use onMouseDown instead of onClick
Try replacing onClick with onMouseDown, like this:
<Button
type="button"
icon="pi pi-info-circle"
className="p-button-text p-button-sm"
onMouseDown={(e) => {
e.stopPropagation(); // Very important
console.log("Mouse down on info icon for option: ", option);
setSelectedModelName(option);
setDialogVisible(true);
}}
/>
-------
Why it works:
onMouseDown fires before ListBox's onClick or focus logic.
You can intercept the interaction earlier in the event cycle.
This avoids losing the event to ListBox's internal selection handling.
Optional: Style adjustment
If onMouseDown triggers the dialog too early or feels jumpy, you can combine it with preventDefault():
e.preventDefault();
e.stopPropagation();
-------
Let me know if this resolves the issue — it usually does when ListBox or similar components interfere with embedded buttons.
-----------------------------------------
[Ravi-comment-later: I tried the main code above skipping the optional style adjustment part. It fixed the issue. end Ravi-comment-later]
Me: Using onMouseDown code as given by you above, solved the issue. You are awesome!
ChatGPT: I'm really glad that solved it — that's great to hear! 🎉
Using onMouseDown is one of those subtle tricks that makes a big difference when dealing with complex components like ListBox that have their own internal event handling.
...
-----------------------------------------
===== end ChatGPT convo extracts =========
I am really impressed with how ChatGPT helped me, for free! I may have figured out this issue through Google Search and going through some links it provided but I would had to do the work of sifting through the articles for the info./solution I want. ChatGPT did it much more conveniently and in a conversational style. Note that PrimeReact documentation for ListBox does not give an example of using an info. or any other icon button in each ListBox entry which, on click, pops up a dialog. This is where ChatGPT coming up with the initial example code was of great help to me.
Made the repo associated with this 2nd Trial app: https://github.com/ravisiyer/testGeminiAPI public.
================
5th May 2025
For 2nd Trial project:
GitHub reported two issues:
Dependabot alerts #1
Inefficient Regular Expression Complexity in nth-check #1
Upgrade nth-check to fix 1 Dependabot alert in package-lock.json
Upgrade nth-check to version 2.0.1 or later. For example:
"dependencies": {
"nth-check": ">=2.0.1"
}
"devDependencies": {
"nth-check": ">=2.0.1"
}
...
Transitive dependency nth-check 1.0.2 is introduced via
react-scripts 5.0.1 ... nth-check 1.0.2
----------
Dependabot alerts #2
PostCSS line return parsing error #2
Upgrade postcss to fix 1 Dependabot alert in package-lock.json
Upgrade postcss to version 8.4.31 or later. For example:
"dependencies": {
"postcss": ">=8.4.31"
}
"devDependencies": {
"postcss": ">=8.4.31"
}
...
Transitive dependency postcss 7.0.39 is introduced via
react-scripts 5.0.1 ... postcss 7.0.39
==========
For 1st alert, ChatGPT session suggested:
Adding overrides in example package.json:
{
"name": "my-project",
"version": "1.0.0",
"description": "Example project with override for nth-check vulnerability",
"main": "index.js",
"scripts": {
"start": "node index.js",
"test": "echo \"No tests specified\" && exit 0"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"cheerio": "^1.0.0-rc.12"
},
"devDependencies": {},
"overrides": {
"nth-check": ">=2.0.1"
}
}
How to Use It
Save or update your package.json.
Run:
npm install
Verify that the override worked:
npm ls nth-check
You should see that nth-check is now at or above version 2.0.1.
---
I did the above. Output of 'npm ls nth-check' after above steps:
gemini-api-trial@0.1.0 C:\Users\ravi-user\CurrProjects\VSCode\React\GeminiAPITrial\testGeminiAPI
└─┬ react-scripts@5.0.1
├─┬ @svgr/webpack@5.5.0
│ └─┬ @svgr/plugin-svgo@5.5.0
│ └─┬ svgo@1.3.2
│ └─┬ css-select@2.1.0
│ └── nth-check@2.1.1 overridden
└─┬ html-webpack-plugin@5.6.3
└─┬ pretty-error@4.0.0
└─┬ renderkid@3.0.0
└─┬ css-select@4.3.0
└── nth-check@2.1.1 deduped
------
For the 2nd issue:
ChatGPT suggested:
"overrides": {
"nth-check": ">=2.0.1",
"postcss": ">=8.4.31"
}
---
Did the above. npm ls postcss gave long list of postcss entries with version as: postcss@8.5.3
=============
Netlify build failed with:
Module not found: Error: Can't resolve './Trial.css' in '/opt/build/repo/src/components'
----
I had renamed trial.css to Trial.css sometime back but I think git does not note it as a change.
Reverted to trial.css (and changed import statement in Trial.jsx to use trial.css). Pushed the changes to GitHub.
Checked about the issue with ChatGPT. Its response:
Yes — what you're seeing is a common and known issue with Git on case-insensitive filesystems, especially macOS and Windows by default. Here's what’s happening:
...
Renaming a file from trial.css → Trial.css does not register as a change because the filesystem treats those names as the same file. Git doesn’t see a change in the filename casing unless you force it to.
...
To get Git to properly detect and commit a case-only filename change:
Option 1: Two-step rename (safe and common fix)
git mv trial.css temp.css
git commit -m "Temp rename to trigger casing change"
git mv temp.css Trial.css
git commit -m "Rename trial.css to Trial.css"
---
This makes Git treat it as a real rename.
...
-----end ChatGPT response extracts ---
Got app successfully deployed on netlify at https://testgeminiapi.netlify.app/ .
======================
7th May 2025
Got the fix for combining Gemini API model data with Google search results data. Google itself has provided the relevant tool.... Grounding with Google Search | Gemini API | Google AI for Developers, https://ai.google.dev/gemini-api/docs/grounding?lang=javascript.
But this fix works to give current data but for Gemini 2.0 (and above). For earlier versions, specifying grounding results in error response!
How to know if the model is Gemini 2.0 or above? Don't have a proper answer but am using this code temporarily:
const isModel2p0OrLater = (model) => {
return model.startsWith("models/gemini-2."); // Not a perfect check but good enough for now.
}
Now my test app using Gemini API with default model of Gemini Flash 2.0, gives the right answer of Donald Trump for the question: Who is president of usa.
When I first encountered the issue I did search and AI chat for a solution but I was not pointed to this easy and perhaps recommended solution. Google Gemini API documentation and knowledge about it in Google search is not yet good enough, IMHO.
=================
Probably 7th May 2025
https://docs.netlify.com/site-deploys/overview/#branches-and-deploys - covers how to create production deploy from production branch and branch deploy from staging/development branch.
Trying out the above:
git checkout -b dev
On first push to remote, git push failed and had to use:
git push --set-upstream origin dev
---
Above succeeded.
Go to Site configuration > Build & deploy > Continuous Deployment > Branches and deploy contexts, and select Configure.
Select Let me add individual branches and enter the name of each branch you want to deploy. ...
----
Followed the above instructions.
But the dev branch deploy was not getting triggered (even with Trigger Deploy command being used).
Solution was to make a minor modification to a source file and then push to GitHub. That triggered Netlify dev branch deployment!
Dev branch app got deployed to: https://main--testgeminiapi.netlify.app/
https://testgeminiapi.netlify.app/ continues to work and corresponds to main (production) branch.
Great!
Perhaps I had noted this in the past but forgot about it. Earlier successful deploys of production branch are available as separate URLs. For example: https://6818c1d4b0982b00087e7041--testgeminiapi.netlify.app/ is the production branch version with deployment info:
May 5 at 7:19 PM, by ravisiyerravisiyer on GitHub
Production: main@68d1d4e
------
Above version does not implement Grounding with Google Search.
Whereas current version of https://testgeminiapi.netlify.app/ implements Grounding with Google Search (but without checkbox UI). Its deployment info (I had triggered a deploy manually):
Today at 4:31 PM
Production: main@HEAD
-----
For completeness sake, the dev branch deploy info:
Today at 4:35 PM, by ravisiyerravisiyer on GitHub
Branch Deploy: dev@9377425
----
=====
JS ref. page for generateContent
=========
If I use Grounding with Google Search (GGS) with gemini-1.5-flash, this is the error I get:
Failed to generate response. Error message received from Gemini: got status: 429 . {"error":{"code":429,"message":"You exceeded your current quota, please check your plan and billing details. For more information on this error, head to: https://ai.google.dev/gemini-api/docs/rate-limits.","status":"RESOURCE_EXHAUSTED","details":[{"@type":"type.googleapis.com/google.rpc.Help","links":[{"description":"Learn more about Gemini API quotas","url":"https://ai.google.dev/gemini-api/docs/rate-limits"}]}]}}
==========
If I don't use GGS for the above case, it works!
So the error message provided by gemini-1.5-flash if GGS is used, is misleading. Perhaps GGS was added only after 1.5 and so this misleading error message.
==============
I tried using debounce in the input text type field as follows (based on CoPilot/GPT-4o suggestion):
const debouncedSetModelUsed = debounce((value) => {
setModelUsed(value);
}, 300);
...
// onChange={(e) => setModelUsed(e.target.value)}
onChange={(e) => debouncedSetModelUsed(e.target.value)}
----
That resulted in cursor position being changed to end of input after typing in a character!
Google search AI explained the issue well:
Incorrect Cursor Position:
Problem: If the input value is not immediately updated with each keystroke due to debouncing, React might reset the cursor position to the end of the input field after the debounced function updates the state.
Solution: Ensure the input value is updated immediately with each keystroke, even if the processing or saving of the value is debounced. This keeps React's internal representation of the input consistent with what the user sees.
===========
I then asked CoPilot about it. I said: When I used your debounce suggestion, it resulted in cursor position being changed to end of input after typing in a character!
CoPilot response:
The issue you're experiencing is a common problem when using debounce with controlled inputs. The debounce function delays the state update (setModelUsed), but React re-renders the component immediately after every keystroke. Since the value of the input is tied to modelUsed, the input loses its cursor position and resets to the end.
To fix this, you can use a local state to manage the input value immediately and only update the debounced state (modelUsed) after the debounce delay. Here's how you can modify your code:
Updated Code:
const [localModelUsed, setLocalModelUsed] = useState(modelUsed);
const debouncedSetModelUsed = debounce((value) => {
setModelUsed(value);
}, 300);
const handleModelUsedChange = (e) => {
const value = e.target.value;
setLocalModelUsed(value); // Update local state immediately
debouncedSetModelUsed(value); // Update debounced state
};
----
Then, update the input element to use localModelUsed as its value:
<input
className="model-used-input"
type="text"
id="modelUsedInput"
value={localModelUsed} // Use local state here
onChange={handleModelUsedChange}
style={{ width: modelUsedInputWidth, minWidth: '10px' }}
ref={modelUsedInputRef}
/>
-----
Explanation:
localModelUsed State:
This state is updated immediately on every keystroke, ensuring the input value reflects the user's typing without delay.
Debounced setModelUsed:
The debouncedSetModelUsed function updates the modelUsed state after the debounce delay, ensuring that the expensive operations tied to modelUsed (e.g., re-renders or API calls) are not triggered too frequently.
Cursor Position:
Since localModelUsed is updated immediately and used as the value of the input, the cursor position remains intact.
This approach ensures smooth typing without resetting the cursor position while still debouncing the updates to the modelUsed state.
==== end CoPilot response ===============
I said: OK. I will try it. But why did you not give me the above solution right away instead of the first flawed solution. I have lost quite a bit of time figuring out the input cursor position problem.
CoPilot: I understand your frustration, and I apologize for the inconvenience caused. The initial solution I provided focused on implementing debouncing without fully considering the specific behavior of controlled inputs in React, which can lead to the cursor position issue. This oversight was my mistake.
The cursor issue is a well-known challenge when combining debouncing with controlled inputs, and I should have anticipated it and provided the more robust solution (using a local state) from the start. I'll strive to be more thorough in addressing such scenarios in the future.
Thank you for pointing this out, and I appreciate your patience. If you encounter any further issues, feel free to ask, and I'll do my best to assist you promptly.
==== end CoPilot response ===============
I said: That's nice and polite of you. Thank you.
CoPilot said: You're welcome! I'm glad you appreciated the response. If you have any further questions or need help with anything else, feel free to ask. Happy coding! 😊
==== end CoPilot response ===============
The debounce code now used is based on the above and is working fine. It needed one additional statement which is given below:
const closeModal = () => {
modelUsed !== localModelUsed && setLocalModelUsed(modelUsed);
setIsModalOpen(false);
};
--- end code ---
The above statement was needed to show selected model in main page after user changed the selected model in the List modal.
===============
8th May 2025
Fixed the issue of hasUserChangedGSS state variable reset to false in UseEffect, resulting in unwanted invocation of useEffect which tripped up the very code that needed the hasUserChangedGSS state variable, by changing hasUserChangedGSS to a ref (useRef) reference variable. Change to the current property of ref does not change ref itself and so even if the ref is added as a dependency to the useEffect, the useEffect does not get triggered on changing current property of ref (React seems to use shallow checking for detecting change in dependencies). Further, there is no warning from lint even if the ref is not mentioned in the dependency list. After fix, the code is as follows:
const hasUserChangedGSS = useRef(false);
...
useEffect(() => {
if (hasUserChangedGSS.current) {
hasUserChangedGSS.current = false;
} else {
setGroundingWithGS(isModel2p0OrLater(modelUsed));
}
}, [modelUsed, groundingWithGS]);
// }, [modelUsed, groundingWithGS, hasUserChangedGSS]);
...
<div className="GGS-container">
{/* <Checkbox inputId="GGS" onChange={e => {setGroundingWithGS(e.checked); setHasUserChangedGSS(true)}} */}
<Checkbox inputId="GGS" onChange={e => {setGroundingWithGS(e.checked); hasUserChangedGSS.current=true}}
checked={groundingWithGS}></Checkbox>
<label htmlFor="GGS" className="">Grounding with Google Search</label>
</div>
--- end code ---
======================
Added Confirm dialog for GSS being checked if model not >= Gemini 2.0
Merging dev branch to main:
git checkout main
git merge dev
git push
==================
A CSS only way to change button labels based on window width:
In CSS file:
.small-width {
display: block;
}
.medium-width {
display: none;
}
@media only screen and (min-width: 768px) {
.small-width {
display: none;
}
.medium-width {
display: block;
}
}
...
In JSX file:
<button className="btn set-selected-model-btn"
disabled={!selectedModel?.name || selectedModel.name === modelUsed}
onClick={()=>selectedModel?.name && setModelUsed(selectedModel?.name)}>
<span className="medium-width">Set selected model as model to use</span>
<span className="small-width">Use selected model</span>
</button>
----
Note that Window: matchMedia() method can also be used: https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia . Also window resize event can be used but that is more coding.
But I was looking for a CSS only simple solution. Above solution works OK.
There seems to be also some CSS ::before solution which seems to be straightforward but I have not used that much. In one of my Next.js and Tailwind CSS projects I recall some helper function to do this stuff but can't recall it and could not get it now with Google search.
==========
9th May 2025
Cleaned up code, added finishing touches, merged dev with main and pushed to GitHub. The production version deployed on netlify: https://testgeminiapi.netlify.app/ has got updated.
Comments
Post a Comment