Skip to content

Commit ba805bb

Browse files
authored
feat: implement search with ✨jAI (#202)
## Description <!-- Please add PR description (don't leave blank) - example: This PR [adds/removes/fixes/replaces] the [feature/bug/etc] --> This pull request introduces a new "Search with ✨jAI" feature to the word search experience; before this, whenever a word was searched and it didn't exist in the dictionary, we'd get a `No Result Found` feedback, but now we get this options replacing the no found with search for the word with ✨jAI. This feature enable us route to a page where the meaning to that word is generated on the fly using ✨jAI. ### Notable Changes **1. AI-powered word definitions and prompt improvements** - Added a new dedicated prompt template (`SEARCH_WORD`) in `jai-prompts.js` for generating structured, SEO-friendly definitions, and moved the original personality prompt to this file. (`apps/jai/lib/jai-prompts.js`, `apps/jai/lib/jai-prompt.js` removed, `apps/jai/index.js`, `apps/jai/README.md`) [[1]](diffhunk://#diff-815b78cdf6ccc854f55ec0c701767e3969f07ce877749fb919892873cdc28712R1-R74) [[2]](diffhunk://#diff-82c094682b612a0966e5684b3ad170b5814750d54ff6d0c8be39f8aa6d2f52ecL1-L36) [[3]](diffhunk://#diff-5439cc07d5881e2e44a6e29b3126ebe43820b54254eca7a57282cf3bca01b122L3-R6) [[4]](diffhunk://#diff-b9fdf9d9f9a7a0c8030ced20f610c30cf1ddddb9918ea834e387e3e6f5e8adf6L52-R65) - Updated documentation to describe the new AI-powered word definition feature and explain the structure and style of generated definitions. (`apps/jai/README.md`) [[1]](diffhunk://#diff-b9fdf9d9f9a7a0c8030ced20f610c30cf1ddddb9918ea834e387e3e6f5e8adf6R15) [[2]](diffhunk://#diff-b9fdf9d9f9a7a0c8030ced20f610c30cf1ddddb9918ea834e387e3e6f5e8adf6L52-R65) **2. New React UI components for ✨jAI integration** - Added `logo.jsx`, a reusable SVG React component for ✨jAI branding. (`apps/jai/components/logo.jsx`) - Added `word-search.jsx`, a React component for generating and displaying AI-powered word definitions, including error handling, loading states, and a trigger component for UI integration. (`apps/jai/components/word-search.jsx`) - Integrated the `JAIWordSearchTrigger` into the main search UI for easy access to AI-powered definitions. (`src/components/islands/search.jsx`) **3. Documentation and architecture updates** - Expanded the `README.md` to clarify the module structure, document new components, and explain the updated integration flow, including the new `/api/jai/search` endpoint. (`apps/jai/README.md`) [[1]](diffhunk://#diff-b9fdf9d9f9a7a0c8030ced20f610c30cf1ddddb9918ea834e387e3e6f5e8adf6R36-R40) [[2]](diffhunk://#diff-b9fdf9d9f9a7a0c8030ced20f610c30cf1ddddb9918ea834e387e3e6f5e8adf6R87-R108) [[3]](diffhunk://#diff-b9fdf9d9f9a7a0c8030ced20f610c30cf1ddddb9918ea834e387e3e6f5e8adf6L114-R159) **4. Model selection and configuration** - Changed the default OpenAI chat model to `gpt-4.1-mini` for both local development (`.env.example`) and documentation, and added detailed notes about model selection strategy for different ✨jAI features. (`.env.example`, `apps/jai/lib/model.js`, `apps/jai/README.md`) [[1]](diffhunk://#diff-a3046da0d15a27e89f2afe639b25748a7ad4d9290af3e7b1b6c1a5533c8f0a8cL16-R16) [[2]](diffhunk://#diff-f74c575d26128dd8394213eb0a7cdb8be7e0618fba3bfc1254ac1dbcf3c3942eR1-R29) [[3]](diffhunk://#diff-b9fdf9d9f9a7a0c8030ced20f610c30cf1ddddb9918ea834e387e3e6f5e8adf6R87-R108) **5. Minor cleanups** - Removed unused or problematic files from `.prettierignore` to reduce noise in formatting tools. (`.prettierignore`) These changes collectively enhance the user experience, developer clarity, and the overall flexibility of the `apps/jai` module for future features and scaling. ## Related Issue <!-- Please prefix the issue number with Fixes/Resolves - example: Fixes #123 or Resolves #123 --> Fixes jargonsdev/roadmap#8 ## Screenshots/Screencasts <!-- Please provide screenshots or video recording that demos your changes (especially if it's a visual change) --> [screen-capture (5).webm](https://github.com/user-attachments/assets/ff67fd8d-1d3f-4ab3-bbea-04588228dfb8) ### Search for word that a not technical term or not related to software, programming ec. fields <img width="1128" height="671" alt="image" src="https://github.com/user-attachments/assets/ab943964-ce0f-4ed8-a4fd-bdbf0cb5b16d" /> ## Notes to Reviewer <!-- Please state here if you added a new npm packages, or any extra information that can help reviewer better review you changes --> - Confirm presence of the ✨jAI related environmental variables for this to work in production
1 parent dc19203 commit ba805bb

File tree

16 files changed

+512
-83
lines changed

16 files changed

+512
-83
lines changed

.env.example

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ PUBLIC_PROJECT_REPO_BRANCH_REF="refs/heads/main"
1313

1414
# LLM and Embedding Model - Optional to run jAI locally - Get keys https://platform.openai.com
1515
OPENAI_API_KEY=sk-proj-*************************************
16-
OPENAI_CHAT_MODEL=gpt-4.1
16+
OPENAI_CHAT_MODEL=gpt-4.1-mini
1717
OPENAI_EMBEDDINGS_MODEL=text-embedding-3-small
1818

1919
# Vector Store - Optional to run jAI locally - Get Keys https://qdrant.tech

.prettierignore

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,6 @@ package-lock.json
3131
.DS_Store
3232
Thumbs.db
3333

34-
# SVG files with CDATA that cause parsing issues
35-
src/components/jargonsdev-logo.astro
36-
3734
# Files with parsing issues in inline scripts
3835
src/layouts/base.astro
3936

apps/jai/README.md

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
Unlike standalone AI applications, ✨jAI is deeply integrated into the jargons.dev ecosystem, powering features like:
1414

15+
- **AI-powered word definitions**: Generate instant definitions for technical terms not yet in the dictionary
1516
- Intelligent word explanations and follow-up conversations
1617
- Semantic search across the dictionary
1718
- Context-aware responses based on the curated dictionary content
@@ -31,9 +32,12 @@ The ✨jAI module is organized into focused utility files:
3132

3233
```
3334
apps/jai/
34-
├── index.js # Main exports and module interface
35+
├── index.js # Main exports and module interface
36+
├── components/ # React components for UI/feature integration
37+
│ ├── logo.jsx # jAI Logo
38+
│ └── word-search.jsx # jAI Word Search feature
3539
└── lib/
36-
├── jai-prompt.js # AI personality and prompt templates
40+
├── jai-prompts.js # AI personality and prompt templates
3741
├── model.js # OpenAI model configuration
3842
├── utils.js # Utility functions for message formatting
3943
└── vector-store.js # Qdrant vector store integration
@@ -49,14 +53,16 @@ Main module interface that exports all ✨jAI utilities:
4953
export { jAIPrompt, formatMessage, model, vectorStore };
5054
```
5155

52-
#### `lib/jai-prompt.js`
56+
#### `lib/jai-prompts.js`
5357

5458
Defines ✨jAI's personality and conversation templates. The AI assistant is designed to:
5559

5660
- Explain technical jargon clearly and concisely
5761
- Use relatable analogies and developer-friendly examples
5862
- Maintain a friendly, witty personality
5963
- Encourage follow-up questions and deeper exploration
64+
- Generate accurate, SEO-friendly definitions for technical terms
65+
- Provide structured responses optimized for dictionary content
6066

6167
#### `lib/model.js`
6268

@@ -78,14 +84,28 @@ Manages the Qdrant vector database integration:
7884

7985
Utility functions for message processing and formatting.
8086

87+
#### `components/logo.jsx`
88+
89+
SVG React component for the ✨jAI logo with customizable styling. Used throughout the application for branding and visual identity.
90+
91+
#### `components/word-search.jsx`
92+
93+
React component that powers the AI-driven word definition feature. Includes:
94+
95+
- **JAIWordSearch**: Main component for generating and displaying AI-powered word definitions
96+
- **JAIWordSearchTrigger**: UI trigger component for initiating word searches with ✨jAI
97+
- Streaming response handling for real-time definition generation
98+
- Error handling and loading states
99+
- Integration with the `/api/jai/search` endpoint
100+
81101
## Environment Variables
82102

83103
✨jAI requires the following environment variables:
84104

85105
```bash
86106
# OpenAI Configuration
87107
OPENAI_API_KEY=your_openai_api_key
88-
OPENAI_CHAT_MODEL=gpt-4-turbo-preview # or your preferred model
108+
OPENAI_CHAT_MODEL=gpt-4.1-mini # or your preferred model
89109
OPENAI_EMBEDDINGS_MODEL=text-embedding-3-small
90110

91111
# Qdrant Vector Database
@@ -111,22 +131,32 @@ This command processes all dictionary entries and creates embeddings for semanti
111131

112132
## Architecture Integration
113133

114-
✨jAI is designed as a utility module that integrates seamlessly with the main jargons.dev application. The module is consumed in two primary areas:
134+
✨jAI is designed as a utility module that integrates seamlessly with the main jargons.dev application. The module is consumed in three primary areas:
115135

116136
### 1. Vector Store Seeding (`dev/seed-vector-store.js`)
117137

118138
Uses the `vectorStore` utility to populate the database with dictionary content. The script fetches dictionary entries from the jargons.dev API, processes them into document chunks, and creates vector embeddings for semantic search capabilities.
119139

120-
### 2. API Endpoint (`src/pages/api/jai/follow-up-chat.js`)
140+
### 2. Word Search API (`src/pages/api/jai/search.js`)
141+
142+
Dedicated endpoint for AI-powered word definitions that:
143+
144+
- Uses the `SEARCH_WORD` prompt template for structured, dictionary-optimized responses
145+
- Streams AI-generated definitions in real-time
146+
- Provides fallback definitions for terms not yet in the dictionary
147+
- Powers the `/browse/with-jai` page and word search components
148+
149+
<!-- ### 3. Follow-up Chat API (`src/pages/api/jai/follow-up-chat.js`)
121150
122-
Imports all four core utilities (`jAIPrompt`, `model`, `formatMessage`, `vectorStore`) for real-time AI interactions. Powers the follow-up chat feature with semantic search for relevant context, conversation history management, and streaming AI response generation.
151+
Imports all four core utilities (`jAIPrompt`, `model`, `formatMessage`, `vectorStore`) for real-time AI interactions. Powers the follow-up chat feature with semantic search for relevant context, conversation history management, and streaming AI response generation. -->
123152

124153
### Integration Flow
125154

126155
1. **Data Preparation**: `seed-vector-store.js` populates the vector database with dictionary content
127-
2. **Runtime Processing**: API endpoints use ✨jAI utilities for semantic search and AI response generation
128-
3. **Real-time Interaction**: Streaming responses provide immediate feedback to users
129-
4. **Context Awareness**: Vector search ensures AI responses are grounded in dictionary content
156+
2. **Word Search Flow**: Users can search for undefined terms via `/browse/with-jai`, which uses the search API to generate instant definitions
157+
3. **Runtime Processing**: API endpoints use ✨jAI utilities for semantic search and AI response generation
158+
4. **Real-time Interaction**: Streaming responses provide immediate feedback to users
159+
5. **Context Awareness**: Vector search ensures AI responses are grounded in dictionary content
130160

131161
## Development
132162

apps/jai/components/logo.jsx

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
export default function JAILogo({ className }) {
2+
return (
3+
<svg
4+
className={className}
5+
xmlns="http://www.w3.org/2000/svg"
6+
viewBox="0 0 780 420"
7+
>
8+
<g>
9+
<g>
10+
<path
11+
className="fill-white"
12+
d="M208 65c11,-13 29,-20 47,-15 14,5 26,16 30,31l13 44c1,4 3,7 6,10 3,3 7,6 11,7l44 12c1,1 2,1 3,1 3,-1 7,-2 11,-2l18 0c0,-1 0,-2 0,-4l0 -8c0,-14 5,-27 15,-37 11,-12 27,-15 43,-15 16,0 31,3 42,15 6,5 10,12 13,19 5,-12 17,-20 30,-20l59 0c5,0 9,1 14,3 4,-2 9,-3 14,-3l124 0c18,0 33,15 33,34l0 30c0,19 -15,34 -33,34l-8 0 0 64 8 0c18,0 33,15 33,33l0 31c0,18 -15,33 -33,33l-93 0c-1,0 -3,0 -4,0 -1,0 -2,0 -3,0l-44 0c-16,0 -29,-10 -33,-25l-5 -21 -1 0 -6 21c-3,15 -16,25 -32,25l-24 0c-2,12 -8,24 -17,33 -15,16 -36,22 -57,22l-52 0c-18,0 -34,-15 -34,-33l0 -32c0,-18 16,-33 34,-33l21 0 0 -67 -22 0c-9,0 -17,-4 -24,-10l-34 10c-4,1 -8,3 -11,6 -3,3 -5,7 -6,11l-13 44c-7,23 -31,37 -55,30 -15,-4 -26,-15 -30,-30l0 -1c-6,10 -16,18 -28,20l-15 4c-2,1 -3,1 -4,2 -1,1 -2,2 -2,3 0,1 0,1 0,1l-4 16c-6,23 -30,38 -54,32 -16,-4 -28,-17 -32,-33l-4 -15c0,-2 -1,-3 -2,-4 -1,-1 -2,-1 -4,-2l-15 -4c-24,-6 -39,-30 -33,-54 4,-16 17,-28 33,-32l15 -4c2,0 3,-1 4,-2 1,-1 2,-2 2,-3 0,0 0,-1 0,-2l4 -14c4,-17 18,-30 34,-33 0,-1 1,-2 1,-3 1,-4 3,-7 4,-10 -7,-6 -12,-13 -15,-22l-4 -13 -14 -5c-23,-8 -36,-33 -28,-56 4,-13 15,-24 28,-28l14 -5 4 -13c8,-23 33,-36 56,-28 13,4 24,15 28,28l5 13 13 5c9,3 16,8 21,14zm-30 73l-4 2 -1 1c2,-1 3,-2 5,-3z"
13+
/>
14+
<g>
15+
<path
16+
id="sparkle.svg"
17+
className="fill-black"
18+
d="M117 43l-6 18c0,0 0,1 -1,1 -1,4 -3,6 -5,9 -3,3 -6,5 -9,6l-18 6c-4,1 -6,3 -7,7 -2,5 1,11 7,13l18 6c3,2 6,4 9,6 3,3 5,6 6,9l6 19c1,3 3,5 7,6 5,2 11,-1 13,-6l6 -19c2,-3 4,-6 6,-9 3,-2 6,-4 9,-6l19 -6c3,-1 5,-3 7,-7 1,-5 -2,-11 -7,-13l-19 -6c-3,-1 -6,-3 -9,-6 -2,-3 -4,-6 -6,-9l-6 -19c-1,-3 -3,-5 -7,-6 -5,-2 -11,1 -13,6z"
19+
/>
20+
<path
21+
id="sparkle.svg_0"
22+
className="fill-black"
23+
d="M93 229l-3 15c0,1 -1,1 -1,1 -2,7 -5,14 -10,19 -6,5 -12,9 -19,11l-16 4c-4,1 -7,4 -8,8 -2,5 2,11 8,13l16 4c7,2 13,5 19,11 5,5 9,11 10,19l4 15c1,4 4,7 8,8 6,2 12,-2 14,-7l4 -16 0 0 0 0c1,-8 5,-14 10,-19 5,-6 12,-9 19,-11l16 -4c4,-1 7,-4 8,-8 2,-6 -2,-12 -8,-13l-16 -4c-7,-2 -14,-6 -19,-11 -5,-5 -9,-12 -10,-19 0,0 0,0 0,0l-4 -16c-1,-4 -4,-7 -8,-8 -6,-1 -12,2 -14,8z"
24+
/>
25+
<path
26+
id="sparkle.svg_1"
27+
className="fill-black"
28+
d="M643 298l19 0 0 -131 -41 0 0 -30 124 0 0 30 -42 0 0 131 42 0 0 31 -93 0 -9 -31zm-80 -121l-2 0 -19 72 40 0 -19 -72zm38 152l-13 -46 -52 0 -12 46 -42 0 52 -192 59 0 52 192 -44 0zm-227 23l54 0 0 -133 -55 0 0 -32 96 0 0 156c0,12 -3,22 -11,29 -7,8 -18,12 -32,12l-52 0 0 -32zm75 -183c-9,0 -16,-2 -19,-6 -4,-4 -6,-8 -6,-14l0 -8c0,-5 2,-10 6,-13 3,-4 10,-6 19,-6 9,0 15,2 19,6 4,3 5,8 5,13l0 8c0,6 -1,10 -5,14 -4,4 -10,6 -19,6z"
29+
/>
30+
<path
31+
id="sparkle.svg_2"
32+
className="fill-black"
33+
d="M232 90l-12 43c0,1 0,1 0,1 -3,10 -8,18 -15,25 -7,7 -16,12 -26,15l-43 12c-4,1 -7,4 -8,8 -1,6 2,12 8,13l43 13c10,3 19,8 26,15 7,7 12,15 15,25l12 44c1,3 4,6 8,7 5,2 11,-1 13,-7l12 -44c3,-10 8,-18 15,-25 7,-7 16,-12 26,-15l43 -13c4,-1 7,-3 8,-7 1,-6 -2,-12 -8,-14l-43 -12c-10,-3 -19,-8 -26,-15 -7,-7 -12,-15 -15,-25l-12 -44c-1,-3 -4,-6 -8,-7 -5,-2 -11,1 -13,7z"
34+
/>
35+
</g>
36+
</g>
37+
</g>
38+
</svg>
39+
);
40+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/**
2+
* JAI Word Search Feature Components
3+
* @exports JAIWordSearch - Fetches and displays AI-generated word definitions with loading and error states
4+
* @exports JAIWordSearchTrigger - Link component to initiate a word search with jAI
5+
*/
6+
7+
import { useEffect, useState } from "react";
8+
import Markdown from "react-markdown";
9+
import { useChat } from "@ai-sdk/react";
10+
import JAILogo from "./logo.jsx";
11+
import { capitalizeText } from "../../../src/lib/utils/index.js";
12+
13+
/**
14+
* JAI Word Search Component
15+
* @param {Object} props
16+
* @param {string} props.word - The word to search
17+
* @returns {JSX.Element}
18+
*/
19+
export default function JAIWordSearch({ word }) {
20+
const [error, setError] = useState(null);
21+
22+
/**
23+
* Initialize useChat hook
24+
*/
25+
const { messages, status, append } = useChat({
26+
api: "/api/jai/search",
27+
onError: (e) => {
28+
setError(JSON.parse(e.message));
29+
console.error(e);
30+
},
31+
});
32+
33+
/**
34+
* Handle Asking jAI for the word definition
35+
*/
36+
useEffect(() => {
37+
append({
38+
role: "user",
39+
content: `define ${word}`,
40+
});
41+
}, [word]);
42+
43+
/**
44+
* Loading State
45+
*/
46+
if (status === "submitted" || (status === "ready" && messages.length === 0))
47+
return (
48+
<div className="space-y-4">
49+
<div className="h-6 w-full animate-pulse bg-gray-200 rounded-md" />
50+
<div className="h-6 w-3/4 animate-pulse bg-gray-200 rounded-md" />
51+
<div className="h-6 w-4/5 animate-pulse bg-gray-200 rounded-md" />
52+
<div className="h-6 w-3/5 animate-pulse bg-gray-200 rounded-md" />
53+
</div>
54+
);
55+
56+
/**
57+
* Error State
58+
*/
59+
if (error)
60+
return (
61+
<div className="rounded-md bg-red-50 p-4">
62+
<div className="flex items-center gap-2">
63+
<svg
64+
xmlns="http://www.w3.org/2000/svg"
65+
fill="none"
66+
viewBox="0 0 24 24"
67+
strokeWidth={1.5}
68+
stroke="currentColor"
69+
className="size-6 text-red-800"
70+
>
71+
<path
72+
strokeLinecap="round"
73+
strokeLinejoin="round"
74+
d="M12 9v3.75m9-.75a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9 3.75h.008v.008H12v-.008Z"
75+
/>
76+
</svg>
77+
<p className="font-medium text-red-800">
78+
An Error Occured while generating the definition for{" "}
79+
<span className="font-bold">{word}</span>.
80+
</p>
81+
</div>
82+
</div>
83+
);
84+
85+
return messages
86+
.filter((msg) => msg.role !== "user")
87+
.map((msg, index) => <Markdown key={index}>{msg.content}</Markdown>);
88+
}
89+
90+
/**
91+
* JAI Word Search Trigger Component
92+
* @param {Object} props
93+
* @param {string} props.word - The word to search
94+
* @param {number} props.cursor - The cursor position for keyboard navigation
95+
* @returns {JSX.Element}
96+
*/
97+
export const JAIWordSearchTrigger = ({ word, cursor }) => (
98+
<a
99+
href={`/browse/with-jai?word=${word}`}
100+
className={`${cursor === 0 && "bg-gray-100 _cursor"} relative flex items-center justify-between no-underline w-full p-2 md:p-4 hover:bg-gray-100`}
101+
>
102+
<span>{capitalizeText(word)}</span>
103+
<span className="absolute right-0 mr-2 md:mr-4 flex items-center gap-2">
104+
<span>Search with</span>
105+
<JAILogo className="w-11 md:w-14 drop-shadow-md" />
106+
</span>
107+
</a>
108+
);

apps/jai/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import model from "./lib/model.js";
22
import { formatMessage } from "./lib/utils.js";
3-
import { jAIPrompt } from "./lib/jai-prompt.js";
3+
import { jAIPrompts } from "./lib/jai-prompts.js";
44
import vectorStore from "./lib/vector-store.js";
55

6-
export { jAIPrompt, formatMessage, model, vectorStore };
6+
export { jAIPrompts, formatMessage, model, vectorStore };

apps/jai/lib/jai-prompt.js

Lines changed: 0 additions & 36 deletions
This file was deleted.

0 commit comments

Comments
 (0)