Building LexiGem: An AI-Powered Dictionary App with Google Gemini and Flask
Learn how LexiGem turns the prototype shown in its Jupyter notebook into a web application that uses Google Gemini to generate detailed dictionary-style definitions in English and French. The app combines prompt engineering, the Gemini API, Flask, Markdown rendering, and a Bootstrap-based interface to create an interactive AI-powered lexicographer.
Building LexiGem: An AI-Powered Dictionary App with Google Gemini and Flask
LexiGem is a small web application that demonstrates how a generative AI model can be turned into a practical dictionary-style tool. Instead of relying on a traditional dictionary database, LexiGem sends a word to Google’s Gemini model and asks it to generate a structured lexical entry.
The project started with an experimentation notebook, which demonstrates the core idea: configure the Gemini API, select the gemini-1.5-flash model, provide a carefully designed prompt, and generate a complete entry for a word. The web application then takes that same concept and wraps it in a Flask interface so a user can enter a word and receive the generated result in their browser.
What Is LexiGem?
LexiGem is essentially an AI-powered lexicographer.
A traditional dictionary application usually retrieves information from a predefined database. LexiGem takes a different approach: it asks a large language model to construct the dictionary entry dynamically.
For example, a user can enter a word such as hello. The application sends that word to Gemini along with instructions explaining exactly what information the model should return.
The generated entry can contain:
- The word
- Part of speech
- IPA pronunciation
- A concise definition
- An expanded definition
- Synonyms
- Antonyms
- Example sentences
- Register and domain information
- Etymology
These requirements come directly from the project’s notebook and are carried over into the web application’s prompts.
From Notebook Experiment to Web Application
The project notebook is important because it shows the underlying experiment before the application was built.
The notebook begins by importing Google’s generative AI library:
import google.generativeai as genai
The Gemini API is then configured with an API key:
genai.configure(api_key="Your api key")
After that, the project creates a Gemini model using:
model = genai.GenerativeModel('gemini-1.5-flash')
The basic workflow is therefore straightforward:
User's word
↓
Prompt
↓
Gemini
↓
Dictionary-style response
The notebook tests this approach with the word Hello and prints the generated result.
The web application takes the same workflow and adds the missing pieces needed for an actual application: a user interface, HTTP request handling, language selection, environment-variable configuration, and HTML rendering.
The Core of the Application
The main application logic is located in app.py.
At the beginning of the file, the application imports the libraries it needs:
import os
import google.generativeai as genai
from flask import Flask, render_template, request
from dotenv import load_dotenv
import markdown
Each library has a specific role.
Flask provides the web framework.
google-generativeai provides access to Google’s Gemini API.
python-dotenv loads the API key from a .env file.
Markdown converts Gemini’s Markdown response into HTML so that it can be displayed properly in the browser.
Keeping the API Key Outside the Code
Rather than placing the Google API key directly into the Python source code, LexiGem loads it from the environment.
The application first executes:
load_dotenv()
Then it retrieves the key:
api_key = os.getenv("GOOGLE_API_KEY")
If the key is missing, the application raises an error instead of silently continuing.
After retrieving the key, it configures Gemini:
genai.configure(api_key=api_key)
model = genai.GenerativeModel('gemini-1.5-flash')
This approach keeps the secret configuration separate from the source code.
Prompt Engineering Is the Main Intelligence Layer
One of the most interesting parts of LexiGem is that much of its behavior is controlled by the prompt.
The English prompt tells Gemini to behave as an expert lexicographer and usage editor:
You are an expert lexicographer and usage editor.
The prompt then specifies the exact structure Gemini should follow.
For example, it requests:
1. Word
2. Part of speech
3. Pronunciation
4. Concise definition
5. Expanded definition
6. Common synonyms
7. Common antonyms
8. Example sentences
9. Typical register
10. Etymology
It also specifies constraints such as keeping example sentences short and returning the entire result in Markdown.
This is a good example of prompt engineering. Rather than simply asking:
Define the word "hello".
LexiGem provides Gemini with a schema describing the desired output.
That makes the response more predictable and useful for the application’s interface.
Supporting Two Languages
LexiGem contains two separate prompts: one in English and one in French.
The English prompt asks Gemini to create an English dictionary entry, while the French prompt gives equivalent instructions in French.
This means the application does not merely translate the interface. It changes the prompt sent to Gemini depending on the selected language.
The user interface therefore provides two choices:
English
Français
The selected language is submitted along with the word.
The get_definition() Function
The central processing function is:
def get_definition(word: str, language: str = 'en') -> str:
Its responsibility is simple: receive a word and a language, select the appropriate prompt, send it to Gemini, and convert the result into HTML.
First, it determines which prompt should be used:
if language == 'fr':
prompt_template = prompt_fr
else:
prompt_template = prompt_en
The user’s word is then inserted into the selected template:
prompt = prompt_template.format(word=word)
The prompt is finally sent to Gemini:
response = model.generate_content(prompt)
The model’s Markdown response is converted into HTML:
return markdown.markdown(response.text)
This conversion is important because Gemini is instructed to produce Markdown, while the web page needs HTML for browser rendering.
The complete pipeline is therefore:
Word + Language
↓
Select Prompt
↓
Insert Word
↓
Send Prompt to Gemini
↓
Receive Markdown
↓
Convert Markdown → HTML
↓
Display in Browser
How the Flask Route Works
The application uses a single route:
@app.route('/', methods=['GET', 'POST'])
def index():
The route accepts both GET and POST requests.
When the page is first opened, there is no result yet. The application initializes variables such as:
result_html = None
word_of_user = ""
selected_language = "en"
When the user submits the form, Flask reads the submitted values:
word_of_user = request.form.get('word', '').strip()
selected_language = request.form.get('language', 'en')
If a word was entered, the application calls:
result_html = get_definition(word_of_user, selected_language)
Finally, Flask sends the result to the HTML template:
return render_template(
'index.html',
result=result_html,
word=word_of_user,
selected_language=selected_language
)
The Frontend
The application’s interface is defined in index.html.
The page uses Bootstrap 5 for its layout and styling. The interface is intentionally simple: the user chooses a language, enters a word, and presses Define.
The form contains a language selector:
<input type="radio" name="language" value="en">
<input type="radio" name="language" value="fr">
It also contains the word input:
<input
type="text"
id="word"
name="word"
placeholder="e.g., serendipity"
required
>
The form submits its data to the / route using POST.
Displaying Gemini’s Result
After Gemini generates the dictionary entry, Flask passes the converted HTML to the template.
The template displays it with:
{{ result | safe }}
The result is placed inside a styled card under a heading such as:
Definition for "hello"
The page therefore creates a simple conversation between the user and the AI model:
Enter a word
↓
Choose English or French
↓
Click Define
↓
Flask receives the request
↓
Gemini generates the entry
↓
Markdown becomes HTML
↓
The definition appears on the page
A Small Loading-State Improvement
The frontend also contains a small JavaScript enhancement.
When the form is submitted, JavaScript hides the Define text, displays a loading spinner, and disables the button:
document.getElementById('define-form').addEventListener('submit', function() {
document.getElementById('button-text').classList.add('d-none');
document.getElementById('loading-spinner').classList.remove('d-none');
document.querySelector('button[type="submit"]').disabled = true;
});
This does not change the AI logic, but it improves the user experience by making it clear that the application is waiting for Gemini to respond.
The Project Structure
The repository keeps the application relatively small:
LexiGem/
├── .env
├── notebook.ipynb
├── lexigem-app/
│ ├── app.py
│ ├── requirements.txt
│ └── templates/
│ └── index.html
├── LICENSE
└── README.md
The application dependencies are also minimal:
Flask
google-generativeai
python-dotenv
Markdown
(GitHub)
Why This Project Is Interesting
LexiGem is a useful example of how a relatively small Python project can transform a generative AI experiment into an interactive application.
The notebook demonstrates the AI concept:
Prompt → Gemini → Dictionary Entry
The Flask application adds the software layer:
Browser → Flask → Prompt → Gemini → HTML → Browser
That distinction is important. Calling an AI model from a notebook is only one part of building an AI application. A usable product also needs input handling, configuration management, a frontend, error handling, and a way to present the generated output.
LexiGem combines all of those pieces without requiring a large codebase.
Conclusion
LexiGem demonstrates a practical pattern for building small generative AI applications with Python.
The original notebook establishes the idea by using Gemini with a carefully structured lexicography prompt. The Flask application then turns that experiment into a browser-based tool with English and French support, secure API-key configuration through environment variables, Markdown-to-HTML conversion, and a Bootstrap interface.
The project is therefore more than a dictionary interface. It is a compact demonstration of the complete path from prompt engineering to an actual AI-powered web application.
Written by
Benmalek Zohir
Founder, AI Engineer & Full Stack Developer
Benmalek Zohir is an AI Engineer, Full Stack Developer, and technology enthusiast focused on artificial intelligence, software development, and emerging technologies. He is the founder of SoftwareJournal.blog, where he shares practical insights, software discoveries, AI tools, and the latest developments in technology.