diff --git a/app/components/chat/WebSearch.client.tsx b/app/components/chat/WebSearch.client.tsx index da37d014..f0d7ed54 100644 --- a/app/components/chat/WebSearch.client.tsx +++ b/app/components/chat/WebSearch.client.tsx @@ -27,11 +27,13 @@ export const WebSearch = ({ onSearchResult, disabled = false }: WebSearchProps) const [isSearching, setIsSearching] = useState(false); const formatSearchResult = (data: WebSearchResponse['data']) => { - if (!data) return ''; + if (!data) { + return ''; + } let result = `# Web Search Results from ${data.sourceUrl}\n\n`; result += `## ${data.title}\n\n`; - + if (data.description) { result += `**Description:** ${data.description}\n\n`; } @@ -40,14 +42,14 @@ export const WebSearch = ({ onSearchResult, disabled = false }: WebSearchProps) if (data.codeBlocks.length > 0) { result += `## Code Examples\n\n`; - data.codeBlocks.forEach((block, index) => { + data.codeBlocks.forEach((block, _index) => { result += `\`\`\`\n${block}\n\`\`\`\n\n`; }); } if (data.relevantLinks.length > 0) { result += `## Relevant Links\n\n`; - data.relevantLinks.forEach(link => { + data.relevantLinks.forEach((link) => { result += `- [${link.text}](${link.url})\n`; }); } @@ -56,12 +58,15 @@ export const WebSearch = ({ onSearchResult, disabled = false }: WebSearchProps) }; const handleWebSearch = async () => { - if (disabled) return; + if (disabled) { + return; + } try { setIsSearching(true); + const url = window.prompt('Enter URL to search:'); - + if (!url) { setIsSearching(false); return; @@ -75,7 +80,7 @@ export const WebSearch = ({ onSearchResult, disabled = false }: WebSearchProps) body: formData, }); - const data = await response.json() as WebSearchResponse; + const data = (await response.json()) as WebSearchResponse; if (!response.ok) { throw new Error(data.error || 'Failed to perform web search'); @@ -110,4 +115,4 @@ export const WebSearch = ({ onSearchResult, disabled = false }: WebSearchProps) )} ); -}; \ No newline at end of file +}; diff --git a/app/routes/api-web-search.ts b/app/routes/api-web-search.ts index 86468537..b7670909 100644 --- a/app/routes/api-web-search.ts +++ b/app/routes/api-web-search.ts @@ -13,10 +13,11 @@ export async function action({ request }: ActionFunctionArgs) { // Add proper headers to handle CORS and content type const response = await fetch(url, { headers: { - 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36', - 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', + 'User-Agent': + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36', + Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'Accept-Language': 'en-US,en;q=0.5', - } + }, }); if (!response.ok) { @@ -24,12 +25,13 @@ export async function action({ request }: ActionFunctionArgs) { } const contentType = response.headers.get('content-type'); + if (!contentType?.includes('text/html')) { throw new Error('URL must point to an HTML page'); } const html = await response.text(); - + // Extract title const titleMatch = html.match(/
]*>[\s\S]*?<\/pre>|]*>[\s\S]*?<\/code>/gi) || [];
- const formattedCodeBlocks = codeBlocks.map(block => {
+ const formattedCodeBlocks = codeBlocks.map((block) => {
return block
.replace(/<[^>]+>/g, '')
.replace(/</g, '<')
@@ -59,12 +61,13 @@ export async function action({ request }: ActionFunctionArgs) {
// Extract links
const links = html.match(/]*href="([^"]*)"[^>]*>([^<]*)<\/a>/gi) || [];
- const formattedLinks = links.map(link => {
+ const formattedLinks = links.map((link) => {
const hrefMatch = link.match(/href="([^"]*)"/i);
const textMatch = link.match(/>([^<]*)
- link.url &&
- !link.url.startsWith('#') &&
- !link.url.startsWith('javascript:') &&
- link.text.trim()
+ relevantLinks: formattedLinks.filter(
+ (link) => link.url && !link.url.startsWith('#') && !link.url.startsWith('javascript:') && link.text.trim(),
),
- sourceUrl: url
+ sourceUrl: url,
};
return json({
success: true,
- data: structuredContent
+ data: structuredContent,
});
} catch (error) {
console.error('Web search error:', error);
- return json(
- { error: error instanceof Error ? error.message : 'Unknown error occurred' },
- { status: 500 }
- );
+ return json({ error: error instanceof Error ? error.message : 'Unknown error occurred' }, { status: 500 });
}
-}
\ No newline at end of file
+}
diff --git a/app/routes/api/web-search.ts b/app/routes/api/web-search.ts
index 7ce502c6..febbc92b 100644
--- a/app/routes/api/web-search.ts
+++ b/app/routes/api/web-search.ts
@@ -11,38 +11,37 @@ export async function action({ request }: ActionFunctionArgs) {
}
const response = await fetch(url);
+
if (!response.ok) {
throw new Error(`Failed to fetch URL: ${response.status} ${response.statusText}`);
}
const html = await response.text();
-
+
// Basic HTML parsing to extract title and content
const titleMatch = html.match(/]*>([^<]+)<\/title>/i);
const title = titleMatch ? titleMatch[1].trim() : 'No title found';
-
+
// Extract content by removing script and style tags, then getting text content
- const content = html
- .replace(/