Skip to content

Commit 1bcb051

Browse files
committed
fix: webSearch clickable text + reference links
1 parent c50f3ae commit 1bcb051

File tree

2 files changed

+50
-10
lines changed

2 files changed

+50
-10
lines changed

apps/masterbots.ai/components/routes/chat/chat-clickable-text.tsx

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,38 @@ export function ClickableText({
5353
if (Array.isArray(extractedContent)) {
5454
return extractedContent.map((content, index) => {
5555
if (React.isValidElement(content)) {
56+
// Si es un strong, procesamos su contenido manteniendo el texto original
57+
if (content.type === 'strong') {
58+
const strongContent = extractTextFromReactNodeNormal(content.props.children)
59+
const { clickableText, restText } = parseClickableText(strongContent + ':')
60+
61+
if (clickableText.trim()) {
62+
return (
63+
<span
64+
key={`clickable-${index}`}
65+
className={cn(
66+
'cursor-pointer hover:underline',
67+
isListItem ? 'text-blue-500' : 'text-link'
68+
)}
69+
onClick={createClickHandler(clickableText)}
70+
role="button"
71+
tabIndex={0}
72+
>
73+
{strongContent}
74+
</span>
75+
)
76+
}
77+
return content
78+
}
5679
return content
5780
}
58-
81+
5982
const { clickableText, restText } = parseClickableText(String(content))
60-
83+
6184
if (!clickableText.trim()) {
6285
return content
6386
}
64-
87+
6588
return (
6689
<React.Fragment key={`clickable-${index}`}>
6790
{renderClickableContent(clickableText, restText)}

apps/masterbots.ai/lib/clickable-results.ts

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,18 @@ export interface ParsedText {
2424

2525
// ? It recursively extracts text from a ReactNode, preserving React elements and returning plain text for strings, numbers, and arrays.
2626
export function extractTextFromReactNodeWeb(node: ReactNode): ReactNode {
27-
// If it's a React element, preserve it entirely
27+
// Si es un elemento React válido
2828
if (React.isValidElement(node)) {
29+
// Si es un strong, preservamos su contenido original
30+
if (node.type === 'strong') {
31+
return {
32+
...node,
33+
props: {
34+
...node.props,
35+
children: extractTextFromReactNodeWeb(node.props.children)
36+
}
37+
}
38+
}
2939
return node
3040
}
3141

@@ -36,14 +46,14 @@ export function extractTextFromReactNodeWeb(node: ReactNode): ReactNode {
3646
}
3747
if (typeof node === 'object' && node !== null && 'props' in node) {
3848
const children = extractTextFromReactNodeWeb(node.props.children)
39-
// If children contains React elements, preserve them
4049
if (React.isValidElement(children) || Array.isArray(children)) {
4150
return children
4251
}
4352
return String(children)
4453
}
4554
return ''
4655
}
56+
4757
// ? Tthis does the following: extracts plain text from a ReactNode, ignoring React elements and returning concatenated strings from arrays
4858
export function extractTextFromReactNodeNormal(node: ReactNode): string {
4959
if (typeof node === 'string') return node
@@ -64,33 +74,39 @@ export function createUniquePattern(): RegExp {
6474
export const GENERAL_PATTERN = /(.*?)([:.,])(?:\s|$)/g
6575

6676
export function parseClickableText(fullText: string): ParsedText {
67-
// First handle URLs - they should remain as regular text
77+
// Si ya es una URL, no lo hacemos clickeable
6878
if (typeof fullText === 'string' && fullText.match(/https?:\/\/[^\s]+/)) {
6979
return {
7080
clickableText: '',
7181
restText: fullText
7282
}
7383
}
7484

75-
// Check for "Title: Description" pattern
85+
// Revisamos si es un texto con dos puntos
7686
const titlePattern = /^([^:]+?):\s*(.*)/
7787
const titleMatch = fullText.match(titlePattern)
88+
7889
if (titleMatch) {
7990
const title = titleMatch[1].trim()
80-
// Don't make the title clickable if it's just periods or empty
91+
// No hacemos clickeable si es solo puntos o está vacío
8192
if (!title || title.match(/^[.\s]+$/)) {
8293
return {
8394
clickableText: '',
8495
restText: fullText
8596
}
8697
}
98+
99+
// Si el título está dentro de un strong, lo extraemos
100+
const strongPattern = /<strong>(.*?)<\/strong>/
101+
const strongMatch = title.match(strongPattern)
102+
const finalTitle = strongMatch ? strongMatch[1] : title
103+
87104
return {
88-
clickableText: title,
105+
clickableText: finalTitle,
89106
restText: ':' + titleMatch[2]
90107
}
91108
}
92109

93-
// If no patterns match, return original text
94110
return {
95111
clickableText: '',
96112
restText: fullText
@@ -100,3 +116,4 @@ export function parseClickableText(fullText: string): ParsedText {
100116
export function cleanClickableText(text: string): string {
101117
return text.replace(/(:|\.|\,)\s*$/, '').trim()
102118
}
119+

0 commit comments

Comments
 (0)