1
0
Fork 0

fix: update related sources

This commit is contained in:
Dylan Tientcheu 2025-05-15 09:12:16 +02:00
parent 68b66aff77
commit a2146c5910
5 changed files with 182 additions and 35 deletions

View file

@ -12,8 +12,8 @@ function App(): JSX.Element {
indexName="beta-react"
appId="betaHAXPMHIMMC"
apiKey="8b00405cba281a7d800ccec393e9af24"
dataSourceId="crawler_rag_beta-react-rag"
promptId="crawler_rag_beta-react-rag"
dataSourceId="crawler-beta-react-rag"
promptId="crawler-betaHAXPMHIMMC-TDE"
insights={true}
/>
</div>

View file

@ -787,15 +787,14 @@ assistive tech users */
.DocSearch-AskAiScreen-Response-Container {
display: flex;
flex-direction: row;
gap: 16px;
flex-direction: column;
margin-bottom: 16px;
}
.DocSearch-AskAiScreen-Response {
display: flex;
flex-direction: column;
width: 70%;
width: 100%;
gap: 16px;
font-size: 0.8em;
margin-bottom: 8px;
@ -884,7 +883,15 @@ assistive tech users */
.DocSearch-AskAiScreen-RelatedSources {
display: flex;
flex-direction: column;
width: 30%;
width: 100%;
gap: 4px;
}
.DocSearch-AskAiScreen-RelatedSources-List {
display: flex;
flex-direction: row;
flex-wrap: wrap;
width: 100%;
gap: 4px;
}
@ -938,6 +945,12 @@ assistive tech users */
white-space: nowrap;
}
.DocSearch-AskAiScreen-ExchangesList {
gap: 24px;
display: flex;
flex-direction: column;
}
.DocSearch-AskAiScreen-RelatedSources-Item-Link:hover {
background: var(--docsearch-hit-highlight-color);
}
@ -1117,7 +1130,6 @@ assistive tech users */
.DocSearch-AskAiScreen-Response-Container {
flex-direction: column;
gap: 24px;
}
.DocSearch-AskAiScreen-Response {

View file

@ -0,0 +1,81 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var replace = require('@rollup/plugin-replace');
var pluginBabel = require('@rollup/plugin-babel');
var json = require('@rollup/plugin-json');
var resolve = require('@rollup/plugin-node-resolve');
var terser = require('@rollup/plugin-terser');
var rollupPluginDts = require('rollup-plugin-dts');
var filesize = require('rollup-plugin-filesize');
var child_process = require('child_process');
var pkg = require('./package.json');
const plugins = [
replace({
preventAssignment: true,
__DEV__: JSON.stringify(process.env.NODE_ENV === 'development'),
}),
json(),
resolve({
extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'],
browser: true,
}),
pluginBabel.babel({
babelHelpers: 'bundled',
exclude: 'node_modules/**',
extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'],
rootMode: 'upward',
}),
terser(),
filesize({
showMinifiedSize: false,
showGzippedSize: true,
}),
];
const typesConfig = {
input: 'dist/esm/types/index.d.ts',
output: [{ file: 'dist/esm/index.d.ts', format: 'es' }],
plugins: [rollupPluginDts.dts()],
};
function getBundleBanner(pkg) {
const lastCommitHash = child_process.execSync('git rev-parse --short HEAD').toString().trim();
const version = process.env.SHIPJS ? pkg.version : `${pkg.version} (UNRELEASED ${lastCommitHash})`;
const authors = '© Algolia, Inc. and contributors';
return `/*! ${pkg.name} ${version} | MIT License | ${authors} | ${pkg.homepage} */`;
}
var rollup_config = [
{
input: 'src/index.ts',
external: ['react', 'react-dom'],
output: [
{
globals: {
react: 'React',
'react-dom': 'ReactDOM',
},
file: 'dist/umd/index.js',
format: 'umd',
sourcemap: true,
name: pkg.name,
banner: getBundleBanner(pkg),
},
{ dir: 'dist/esm', format: 'es' },
],
plugins: [
...plugins,
replace({
preventAssignment: true,
'process.env.NODE_ENV': JSON.stringify('production'),
}),
],
},
typesConfig,
];
exports.default = rollup_config;

View file

@ -10,6 +10,7 @@ interface Message {
id: string;
role: 'assistant' | 'user';
content: string;
urls?: Array<{ url: string; title?: string }>;
context?: AskAiResponse['context'];
}
@ -77,7 +78,7 @@ function AskAiExchangeCard({
const isStreaming = isLastExchange && loadingStatus === 'streaming';
const showError = isLastExchange && loadingStatus === 'error' && error;
const showActions = !isLastExchange || (isLastExchange && loadingStatus === 'idle' && Boolean(assistantMessage));
const contextToDisplay = assistantMessage?.context || [];
const urlsToDisplay = assistantMessage?.urls || [];
return (
<div className="DocSearch-AskAiScreen-Response-Container">
@ -110,13 +111,20 @@ function AskAiExchangeCard({
</div>
{/* Sources for this exchange */}
<AskAiSourcesPanel
contextToDisplay={contextToDisplay}
loadingStatus={loadingStatus}
relatedSourcesText={translations.relatedSourcesText}
hasHadAssistantResponse={globalHasHadAssistantResponse}
isExchangeLoading={isLastExchange && (loadingStatus === 'loading' || loadingStatus === 'streaming')}
/>
{urlsToDisplay.length > 0 ||
(urlsToDisplay.length === 0 &&
loadingStatus === 'loading' &&
!globalHasHadAssistantResponse &&
isLastExchange &&
(loadingStatus === 'loading' || loadingStatus === 'streaming')) ? (
<AskAiSourcesPanel
urlsToDisplay={urlsToDisplay}
loadingStatus={loadingStatus}
relatedSourcesText={translations.relatedSourcesText}
hasHadAssistantResponse={globalHasHadAssistantResponse}
isExchangeLoading={isLastExchange && (loadingStatus === 'loading' || loadingStatus === 'streaming')}
/>
) : null}
</div>
);
}
@ -143,7 +151,7 @@ function AskAiScreenFooterActions({
}
interface AskAiSourcesPanelProps {
contextToDisplay: AskAiResponse['context'];
urlsToDisplay: Array<{ url: string; title?: string }>;
loadingStatus: LoadingStatus;
relatedSourcesText: string;
hasHadAssistantResponse: boolean;
@ -151,7 +159,7 @@ interface AskAiSourcesPanelProps {
}
function AskAiSourcesPanel({
contextToDisplay,
urlsToDisplay,
loadingStatus,
relatedSourcesText,
hasHadAssistantResponse,
@ -160,32 +168,36 @@ function AskAiSourcesPanel({
return (
<div className="DocSearch-AskAiScreen-RelatedSources">
<p className="DocSearch-AskAiScreen-RelatedSources-Title">{relatedSourcesText}</p>
{contextToDisplay.length > 0 &&
contextToDisplay.map((source) => (
<a
key={source.objectID}
href={source.url || source.objectID || '#'}
className="DocSearch-AskAiScreen-RelatedSources-Item-Link"
>
<RelatedSourceIcon />
<span>{source.title || source.url || source.objectID}</span>
</a>
))}
{contextToDisplay.length === 0 &&
<div className="DocSearch-AskAiScreen-RelatedSources-List">
{urlsToDisplay.length > 0 &&
urlsToDisplay.map((link) => (
<a
key={link.url}
href={link.url}
className="DocSearch-AskAiScreen-RelatedSources-Item-Link"
target="_blank"
rel="noopener noreferrer"
>
<RelatedSourceIcon />
<span>{link.title || link.url}</span>
</a>
))}
</div>
{urlsToDisplay.length === 0 &&
loadingStatus === 'loading' &&
!hasHadAssistantResponse &&
isExchangeLoading &&
// eslint-disable-next-line react/no-array-index-key
Array.from({ length: 3 }).map((_, index) => <SkeletonSource key={index} />)}
{contextToDisplay.length === 0 &&
{urlsToDisplay.length === 0 &&
(loadingStatus === 'idle' || loadingStatus === 'streaming') &&
hasHadAssistantResponse &&
!isExchangeLoading && (
<p className="DocSearch-AskAiScreen-RelatedSources-NoResults">No related sources for the latest answer.</p>
<p className="DocSearch-AskAiScreen-RelatedSources-NoResults">no related sources for the latest answer.</p>
)}
{contextToDisplay.length === 0 && loadingStatus === 'error' && (
<p className="DocSearch-AskAiScreen-RelatedSources-Error">Could not load related sources.</p>
{urlsToDisplay.length === 0 && loadingStatus === 'error' && (
<p className="DocSearch-AskAiScreen-RelatedSources-Error">could not load related sources.</p>
)}
</div>
);

View file

@ -11,6 +11,7 @@ interface Message {
role: 'assistant' | 'user';
content: string;
context?: AskAiResponse['context'];
urls?: Array<{ url: string; title?: string }>;
}
export interface AskAiState {
@ -96,7 +97,7 @@ export function useAskAi({ genAiClient, conversations }: UseAskAiParams): AskAiS
messages: [
...(prevState.conversationId ? prevState.messages : []), // keep history if we have a conversationId
{ id: userMessageId, role: 'user', content: query },
{ id: assistantMessageId, role: 'assistant', content: '', context: [] },
{ id: assistantMessageId, role: 'assistant', content: '', context: [], urls: [] },
],
loadingStatus: 'loading',
query,
@ -112,7 +113,14 @@ export function useAskAi({ genAiClient, conversations }: UseAskAiParams): AskAiS
setState((prevState) => ({
...prevState,
messages: prevState.messages.map((m) =>
m.id === assistantMessageId ? { ...m, content: chunk.response, context: chunk.context } : m,
m.id === assistantMessageId
? {
...m,
content: chunk.response,
context: chunk.context,
urls: extractLinksFromText(chunk.response),
}
: m,
),
loadingStatus: 'streaming',
}));
@ -215,3 +223,37 @@ export function useGenAiClient(
return genAiClient;
}
// utility to extract links (markdown and bare urls) from a string
function extractLinksFromText(text: string): Array<{ url: string; title?: string }> {
// match [title](url) and bare urls
const markdownLinkRegex = /\[([^\]]+)\]\((https?:\/\/[^\s)]+)\)/g;
const urlRegex = /https?:\/\/[^\s)]+/g;
const links: Array<{ url: string; title?: string }> = [];
const seen = new Set<string>();
// extract markdown links first
let match;
while ((match = markdownLinkRegex.exec(text)) !== null) {
let url = match[2];
const title = match[1];
// trim trailing punctuation
url = url.replace(/[).,;!?]+$/, '');
if (!seen.has(url)) {
links.push({ url, title });
seen.add(url);
}
}
// extract bare urls
while ((match = urlRegex.exec(text)) !== null) {
let url = match[0];
url = url.replace(/[).,;!?]+$/, '');
if (!seen.has(url)) {
links.push({ url });
seen.add(url);
}
}
return links;
}