From b8fade251bb5af4750c70ff7dc79607ca501fe7f Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Tue, 24 Dec 2024 17:15:17 +0530 Subject: [PATCH 01/86] (feat: searchResults): adding utility to preprocess markdown --- extensions/react-widget/src/utils/helper.ts | 191 ++++++++++++++++++-- 1 file changed, 180 insertions(+), 11 deletions(-) diff --git a/extensions/react-widget/src/utils/helper.ts b/extensions/react-widget/src/utils/helper.ts index d9aa19c3..511b39fc 100644 --- a/extensions/react-widget/src/utils/helper.ts +++ b/extensions/react-widget/src/utils/helper.ts @@ -27,22 +27,169 @@ export const getOS = () => { return 'other'; }; -export const preprocessSearchResultsToHTML = (text: string, keyword: string) => { - const md = new MarkdownIt(); - const htmlString = md.render(text); +interface MarkdownElement { + type: 'heading' | 'paragraph' | 'code' | 'list' | 'other'; + content: string; + level?: number; +} - // Container for processed HTML - const filteredResults = document.createElement("div"); - filteredResults.innerHTML = htmlString; +interface ParsedElement { + content: string; + tag: string; +} - if (!processNode(filteredResults, keyword.trim())) return null; +export const processMarkdownString = (markdown: string): ParsedElement[] => { + const result: ParsedElement[] = []; + const lines = markdown.trim().split('\n'); + + let isInCodeBlock = false; + let currentCodeBlock = ''; - return filteredResults.innerHTML.trim() ? filteredResults.outerHTML : null; + for (let i = 0; i < lines.length; i++) { + const trimmedLine = lines[i].trim(); + if (!trimmedLine) continue; + + if (trimmedLine.startsWith('```')) { + if (isInCodeBlock) { + if (currentCodeBlock.trim()) { + result.push({ + content: currentCodeBlock.trim(), + tag: 'code' + }); + } + currentCodeBlock = ''; + isInCodeBlock = false; + } else { + isInCodeBlock = true; + } + continue; + } + + if (isInCodeBlock) { + currentCodeBlock += trimmedLine + '\n'; + continue; + } + + const headingMatch = trimmedLine.match(/^(#{1,6})\s+(.+)$/); + if (headingMatch) { + result.push({ + content: headingMatch[2], + tag: 'heading' + }); + continue; + } + + const bulletMatch = trimmedLine.match(/^[-*]\s+(.+)$/); + if (bulletMatch) { + result.push({ + content: bulletMatch[1], + tag: 'bulletList' + }); + continue; + } + + const numberedMatch = trimmedLine.match(/^\d+\.\s+(.+)$/); + if (numberedMatch) { + result.push({ + content: numberedMatch[1], + tag: 'numberedList' + }); + continue; + } + + result.push({ + content: trimmedLine, + tag: 'text' + }); + } + + if (isInCodeBlock && currentCodeBlock.trim()) { + result.push({ + content: currentCodeBlock.trim(), + tag: 'code' + }); + } + + return result; }; +export const preprocessSearchResultsToHTML = (text: string, keyword: string): MarkdownElement[] | null => { + const md = new MarkdownIt(); + const tokens = md.parse(text, {}); + const results: MarkdownElement[] = []; + + for (let i = 0; i < tokens.length; i++) { + const token = tokens[i]; + + if (token.type.endsWith('_close') || !token.content) continue; + const content = token.content.toLowerCase(); + const keywordLower = keyword.trim().toLowerCase(); + + if (!content.includes(keywordLower)) continue; + + switch (token.type) { + case 'heading_open': + const level = parseInt(token.tag.charAt(1)); + const headingContent = tokens[i + 1].content; + results.push({ + type: 'heading', + content: headingContent, + level + }); + break; + + case 'paragraph_open': + const paragraphContent = tokens[i + 1].content; + results.push({ + type: 'paragraph', + content: paragraphContent + }); + break; + + case 'fence': + case 'code_block': + results.push({ + type: 'code', + content: token.content + }); + break; + + case 'bullet_list_open': + case 'ordered_list_open': + let listItems = []; + i++; + while (i < tokens.length && !tokens[i].type.includes('list_close')) { + if (tokens[i].type === 'list_item_open') { + i++; + if (tokens[i].content) { + listItems.push(tokens[i].content); + } + } + i++; + } + if (listItems.length > 0) { + results.push({ + type: 'list', + content: listItems.join('\n') + }); + } + break; + + default: + if (token.content) { + results.push({ + type: 'other', + content: token.content + }); + } + break; + } + } + + return results.length > 0 ? results : null; +}; -// Recursive function to process nodes const processNode = (node: Node, keyword: string): boolean => { const keywordRegex = new RegExp(`(${keyword})`, "gi"); @@ -57,7 +204,6 @@ const processNode = (node: Node, keyword: string): boolean => { const tempContainer = document.createElement("div"); tempContainer.innerHTML = highlightedHTML; - // Replace the text node with highlighted content while (tempContainer.firstChild) { node.parentNode?.insertBefore(tempContainer.firstChild, node); } @@ -84,4 +230,27 @@ const processNode = (node: Node, keyword: string): boolean => { } return false; -}; \ No newline at end of file +}; + +const markdownString = ` +# Title +This is a paragraph. + +## Subtitle +- Bullet item 1 +* Bullet item 2 +1. Numbered item 1 +2. Numbered item 2 + +\`\`\`javascript +const hello = "world"; +console.log(hello); +// This is a multi-line +// code block +\`\`\` + +Regular text after code block +`; + +const parsed = processMarkdownString(markdownString); +console.log(parsed); From 2420af3b6d3c4c98a75b3f624e204c9514cac7d5 Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Fri, 27 Dec 2024 16:19:33 +0530 Subject: [PATCH 02/86] (feat:Search) highlight keywords on searching --- extensions/react-widget/src/utils/helper.ts | 251 +++++++------------- 1 file changed, 84 insertions(+), 167 deletions(-) diff --git a/extensions/react-widget/src/utils/helper.ts b/extensions/react-widget/src/utils/helper.ts index 511b39fc..13d2bf7a 100644 --- a/extensions/react-widget/src/utils/helper.ts +++ b/extensions/react-widget/src/utils/helper.ts @@ -1,5 +1,3 @@ -import MarkdownIt from "markdown-it"; -import DOMPurify from "dompurify"; export const getOS = () => { const platform = window.navigator.platform; const userAgent = window.navigator.userAgent || window.navigator.vendor; @@ -27,211 +25,130 @@ export const getOS = () => { return 'other'; }; -interface MarkdownElement { - type: 'heading' | 'paragraph' | 'code' | 'list' | 'other'; - content: string; - level?: number; -} interface ParsedElement { content: string; tag: string; } -export const processMarkdownString = (markdown: string): ParsedElement[] => { - const result: ParsedElement[] = []; +export const processMarkdownString = (markdown: string, keyword?: string): ParsedElement[] => { const lines = markdown.trim().split('\n'); - + const keywordLower = keyword?.toLowerCase(); + + const escapeRegExp = (str: string) => str.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); + const escapedKeyword = keyword ? escapeRegExp(keyword) : ''; + const keywordRegex = keyword ? new RegExp(`(${escapedKeyword})`, 'gi') : null; + let isInCodeBlock = false; - let currentCodeBlock = ''; + let codeBlockContent: string[] = []; + let matchingLines: ParsedElement[] = []; + let firstLine: ParsedElement | null = null; for (let i = 0; i < lines.length; i++) { const trimmedLine = lines[i].trim(); if (!trimmedLine) continue; + // Handle code block start/end if (trimmedLine.startsWith('```')) { - if (isInCodeBlock) { - if (currentCodeBlock.trim()) { - result.push({ - content: currentCodeBlock.trim(), - tag: 'code' - }); - } - currentCodeBlock = ''; - isInCodeBlock = false; - } else { + if (!isInCodeBlock) { + // Start of code block isInCodeBlock = true; + codeBlockContent = []; + } else { + // End of code block - process the collected content + isInCodeBlock = false; + const codeContent = codeBlockContent.join('\n'); + const parsedElement: ParsedElement = { + content: codeContent, + tag: 'code' + }; + + if (!firstLine) { + firstLine = parsedElement; + } + + if (keywordLower && codeContent.toLowerCase().includes(keywordLower)) { + parsedElement.content = parsedElement.content.replace(keywordRegex!, '$1'); + matchingLines.push(parsedElement); + } } continue; } + // Collect code block content if (isInCodeBlock) { - currentCodeBlock += trimmedLine + '\n'; + codeBlockContent.push(trimmedLine); continue; } + let parsedElement: ParsedElement | null = null; + const headingMatch = trimmedLine.match(/^(#{1,6})\s+(.+)$/); - if (headingMatch) { - result.push({ - content: headingMatch[2], - tag: 'heading' - }); - continue; - } - const bulletMatch = trimmedLine.match(/^[-*]\s+(.+)$/); - if (bulletMatch) { - result.push({ - content: bulletMatch[1], - tag: 'bulletList' - }); - continue; - } - const numberedMatch = trimmedLine.match(/^\d+\.\s+(.+)$/); - if (numberedMatch) { - result.push({ - content: numberedMatch[1], + + let content = trimmedLine; + + if (headingMatch) { + content = headingMatch[2]; + parsedElement = { + content: content, + tag: 'heading' + }; + } else if (bulletMatch) { + content = bulletMatch[1]; + parsedElement = { + content: content, + tag: 'bulletList' + }; + } else if (numberedMatch) { + content = numberedMatch[1]; + parsedElement = { + content: content, tag: 'numberedList' - }); - continue; + }; + } else { + parsedElement = { + content: content, + tag: 'text' + }; } - result.push({ - content: trimmedLine, - tag: 'text' - }); + if (!firstLine) { + firstLine = parsedElement; + } + + if (keywordLower && parsedElement.content.toLowerCase().includes(keywordLower)) { + parsedElement.content = parsedElement.content.replace(keywordRegex!, '$1'); + matchingLines.push(parsedElement); + } } - if (isInCodeBlock && currentCodeBlock.trim()) { - result.push({ - content: currentCodeBlock.trim(), + if (isInCodeBlock && codeBlockContent.length > 0) { + const codeContent = codeBlockContent.join('\n'); + const parsedElement: ParsedElement = { + content: codeContent, tag: 'code' - }); - } + }; - return result; -}; + if (!firstLine) { + firstLine = parsedElement; + } -export const preprocessSearchResultsToHTML = (text: string, keyword: string): MarkdownElement[] | null => { - const md = new MarkdownIt(); - const tokens = md.parse(text, {}); - const results: MarkdownElement[] = []; - - for (let i = 0; i < tokens.length; i++) { - const token = tokens[i]; - - if (token.type.endsWith('_close') || !token.content) continue; - - const content = token.content.toLowerCase(); - const keywordLower = keyword.trim().toLowerCase(); - - if (!content.includes(keywordLower)) continue; - - switch (token.type) { - case 'heading_open': - const level = parseInt(token.tag.charAt(1)); - const headingContent = tokens[i + 1].content; - results.push({ - type: 'heading', - content: headingContent, - level - }); - break; - - case 'paragraph_open': - const paragraphContent = tokens[i + 1].content; - results.push({ - type: 'paragraph', - content: paragraphContent - }); - break; - - case 'fence': - case 'code_block': - results.push({ - type: 'code', - content: token.content - }); - break; - - case 'bullet_list_open': - case 'ordered_list_open': - let listItems = []; - i++; - while (i < tokens.length && !tokens[i].type.includes('list_close')) { - if (tokens[i].type === 'list_item_open') { - i++; - if (tokens[i].content) { - listItems.push(tokens[i].content); - } - } - i++; - } - if (listItems.length > 0) { - results.push({ - type: 'list', - content: listItems.join('\n') - }); - } - break; - - default: - if (token.content) { - results.push({ - type: 'other', - content: token.content - }); - } - break; + if (keywordLower && codeContent.toLowerCase().includes(keywordLower)) { + parsedElement.content = parsedElement.content.replace(keywordRegex!, '$1'); + matchingLines.push(parsedElement); } } - return results.length > 0 ? results : null; -}; - -const processNode = (node: Node, keyword: string): boolean => { - - const keywordRegex = new RegExp(`(${keyword})`, "gi"); - if (node.nodeType === Node.TEXT_NODE) { - const textContent = node.textContent || ""; - - if (textContent.toLowerCase().includes(keyword.toLowerCase())) { - const highlightedHTML = textContent.replace( - keywordRegex, - `$1` - ); - const tempContainer = document.createElement("div"); - tempContainer.innerHTML = highlightedHTML; - - while (tempContainer.firstChild) { - node.parentNode?.insertBefore(tempContainer.firstChild, node); - } - node.parentNode?.removeChild(node); - - return true; - } - - return false; - } else if (node.nodeType === Node.ELEMENT_NODE) { - - const children = Array.from(node.childNodes); - let hasKeyword = false; - - children.forEach((child) => { - if (!processNode(child, keyword)) { - node.removeChild(child); - } else { - hasKeyword = true; - } - }); - - return hasKeyword; + if (keywordLower && matchingLines.length > 0) { + return matchingLines; } - return false; + return firstLine ? [firstLine] : []; }; + const markdownString = ` # Title This is a paragraph. @@ -252,5 +169,5 @@ console.log(hello); Regular text after code block `; -const parsed = processMarkdownString(markdownString); +const parsed = processMarkdownString(markdownString, 'world'); console.log(parsed); From 5ddf9bd7ecb36e3ca1cf39c3ecff69bd3fad482e Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Fri, 27 Dec 2024 17:40:04 +0530 Subject: [PATCH 03/86] (feat:search) handle blockquotes in markdown --- extensions/react-widget/src/utils/helper.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/extensions/react-widget/src/utils/helper.ts b/extensions/react-widget/src/utils/helper.ts index 13d2bf7a..ac257c91 100644 --- a/extensions/react-widget/src/utils/helper.ts +++ b/extensions/react-widget/src/utils/helper.ts @@ -86,6 +86,7 @@ export const processMarkdownString = (markdown: string, keyword?: string): Parse const headingMatch = trimmedLine.match(/^(#{1,6})\s+(.+)$/); const bulletMatch = trimmedLine.match(/^[-*]\s+(.+)$/); const numberedMatch = trimmedLine.match(/^\d+\.\s+(.+)$/); + const blockquoteMatch = trimmedLine.match(/^>+\s*(.+)$/); // Updated regex to handle multiple '>' symbols let content = trimmedLine; @@ -107,6 +108,12 @@ export const processMarkdownString = (markdown: string, keyword?: string): Parse content: content, tag: 'numberedList' }; + } else if (blockquoteMatch) { + content = blockquoteMatch[1]; + parsedElement = { + content: content, + tag: 'blockquote' + }; } else { parsedElement = { content: content, From e45648b389544fa59f24f65ea1d58efc58c35ef4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Dec 2024 20:17:15 +0000 Subject: [PATCH 04/86] build(deps): bump langsmith from 0.2.3 to 0.2.6 in /application Bumps [langsmith](https://github.com/langchain-ai/langsmith-sdk) from 0.2.3 to 0.2.6. - [Release notes](https://github.com/langchain-ai/langsmith-sdk/releases) - [Commits](https://github.com/langchain-ai/langsmith-sdk/compare/v0.2.3...v0.2.6) --- updated-dependencies: - dependency-name: langsmith dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- application/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/requirements.txt b/application/requirements.txt index 08990ab2..754fb271 100644 --- a/application/requirements.txt +++ b/application/requirements.txt @@ -33,7 +33,7 @@ langchain-community==0.3.13 langchain-core==0.3.28 langchain-openai==0.2.14 langchain-text-splitters==0.3.4 -langsmith==0.2.3 +langsmith==0.2.6 lazy-object-proxy==1.10.0 lxml==5.3.0 markupsafe==2.1.5 From e42fc97d03e88a31f676ad8daffc912b6210e7da Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Dec 2024 20:17:25 +0000 Subject: [PATCH 05/86] build(deps): bump celery from 5.3.6 to 5.4.0 in /application Bumps [celery](https://github.com/celery/celery) from 5.3.6 to 5.4.0. - [Release notes](https://github.com/celery/celery/releases) - [Changelog](https://github.com/celery/celery/blob/main/Changelog.rst) - [Commits](https://github.com/celery/celery/compare/v5.3.6...v5.4.0) --- updated-dependencies: - dependency-name: celery dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- application/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/requirements.txt b/application/requirements.txt index 08990ab2..41297624 100644 --- a/application/requirements.txt +++ b/application/requirements.txt @@ -1,7 +1,7 @@ anthropic==0.40.0 boto3==1.34.153 beautifulsoup4==4.12.3 -celery==5.3.6 +celery==5.4.0 dataclasses-json==0.6.7 docx2txt==0.8 duckduckgo-search==6.3.0 From b4d77080e8a6f6c96aba6546bfc69f196c76286e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Dec 2024 20:22:47 +0000 Subject: [PATCH 06/86] build(deps): bump i18next-browser-languagedetector in /frontend Bumps [i18next-browser-languagedetector](https://github.com/i18next/i18next-browser-languageDetector) from 8.0.0 to 8.0.2. - [Changelog](https://github.com/i18next/i18next-browser-languageDetector/blob/master/CHANGELOG.md) - [Commits](https://github.com/i18next/i18next-browser-languageDetector/compare/v8.0.0...v8.0.2) --- updated-dependencies: - dependency-name: i18next-browser-languagedetector dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 9 ++++----- frontend/package.json | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 9a3dbf31..7ad503c4 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -11,7 +11,7 @@ "@reduxjs/toolkit": "^2.2.7", "chart.js": "^4.4.4", "i18next": "^24.2.0", - "i18next-browser-languagedetector": "^8.0.0", + "i18next-browser-languagedetector": "^8.0.2", "prop-types": "^15.8.1", "react": "^18.2.0", "react-chartjs-2": "^5.2.0", @@ -4956,10 +4956,9 @@ } }, "node_modules/i18next-browser-languagedetector": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.0.0.tgz", - "integrity": "sha512-zhXdJXTTCoG39QsrOCiOabnWj2jecouOqbchu3EfhtSHxIB5Uugnm9JaizenOy39h7ne3+fLikIjeW88+rgszw==", - "license": "MIT", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.0.2.tgz", + "integrity": "sha512-shBvPmnIyZeD2VU5jVGIOWP7u9qNG3Lj7mpaiPFpbJ3LVfHZJvVzKR4v1Cb91wAOFpNw442N+LGPzHOHsten2g==", "dependencies": { "@babel/runtime": "^7.23.2" } diff --git a/frontend/package.json b/frontend/package.json index ff98e94c..bb8ff171 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -22,7 +22,7 @@ "@reduxjs/toolkit": "^2.2.7", "chart.js": "^4.4.4", "i18next": "^24.2.0", - "i18next-browser-languagedetector": "^8.0.0", + "i18next-browser-languagedetector": "^8.0.2", "prop-types": "^15.8.1", "react": "^18.2.0", "react-chartjs-2": "^5.2.0", From 8724c12c11e081aba4976f683c81e7d4e071b72b Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Tue, 31 Dec 2024 15:30:24 +0530 Subject: [PATCH 07/86] (feat:search) new UI --- .../react-widget/src/components/SearchBar.tsx | 442 ++++++++++++------ extensions/react-widget/src/utils/helper.ts | 31 +- 2 files changed, 308 insertions(+), 165 deletions(-) diff --git a/extensions/react-widget/src/components/SearchBar.tsx b/extensions/react-widget/src/components/SearchBar.tsx index 42262e08..5982f6f6 100644 --- a/extensions/react-widget/src/components/SearchBar.tsx +++ b/extensions/react-widget/src/components/SearchBar.tsx @@ -1,11 +1,20 @@ -import React from 'react' -import styled, { ThemeProvider } from 'styled-components'; +import React, { useRef } from 'react'; +import styled, { ThemeProvider, createGlobalStyle } from 'styled-components'; import { WidgetCore } from './DocsGPTWidget'; import { SearchBarProps } from '@/types'; -import { getSearchResults } from '../requests/searchAPI' +import { getSearchResults } from '../requests/searchAPI'; import { Result } from '@/types'; import MarkdownIt from 'markdown-it'; -import { getOS, preprocessSearchResultsToHTML } from '../utils/helper' +import { getOS, processMarkdownString } from '../utils/helper'; +import DOMPurify from 'dompurify'; +import { + CodeIcon, + TextAlignLeftIcon, + HeadingIcon, + ReaderIcon, + ListBulletIcon, + QuoteIcon +} from '@radix-ui/react-icons'; const themes = { dark: { bg: '#000', @@ -33,12 +42,20 @@ const themes = { } } +const GlobalStyle = createGlobalStyle` + .highlight { + color:#007EE6; + } +`; + const Main = styled.div` - all:initial; - font-family: sans-serif; + all: initial; + * { + font-family: 'Geist', sans-serif; + } ` -const TextField = styled.input<{ inputWidth: string }>` - padding: 6px 6px; +const SearchButton = styled.button<{ inputWidth: string }>` + padding: 6px 6px; width: ${({ inputWidth }) => inputWidth}; border-radius: 8px; display: inline; @@ -50,14 +67,15 @@ const TextField = styled.input<{ inputWidth: string }>` -moz-appearance: none; appearance: none; transition: background-color 128ms linear; + text-align: left; &:focus { - outline: none; - box-shadow: - 0px 0px 0px 2px rgba(0, 109, 199), - 0px 0px 6px rgb(0, 90, 163), - 0px 2px 6px rgba(0, 0, 0, 0.1) ; - background-color: ${props => props.theme.primary.bg}; - } + outline: none; + box-shadow: + 0px 0px 0px 2px rgba(0, 109, 199), + 0px 0px 6px rgb(0, 90, 163), + 0px 2px 6px rgba(0, 0, 0, 0.1); + background-color: ${props => props.theme.primary.bg}; + } ` const Container = styled.div` @@ -65,51 +83,122 @@ const Container = styled.div` display: inline-block; ` const SearchResults = styled.div` - position: absolute; - display: block; + position: fixed; + display: flex; + flex-direction: column; background-color: ${props => props.theme.primary.bg}; - border: 1px solid rgba(0, 0, 0, .1); + border: 1px solid ${props => props.theme.secondary.text}; border-radius: 12px; padding: 8px; - width: 576px; - min-width: 96%; + width: 792px; + max-width: 90vw; + height: 70vh; z-index: 100; - height: 25vh; - overflow-y: auto; - top: 32px; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); color: ${props => props.theme.primary.text}; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.1); + backdrop-filter: blur(16px); + box-sizing: border-box; + + @media only screen and (max-width: 768px) { + height: 80vh; + width: 90vw; + } +`; + +const SearchResultsScroll = styled.div` + flex: 1; + overflow-y: auto; + overflow-x: hidden; scrollbar-color: lab(48.438 0 0 / 0.4) rgba(0, 0, 0, 0); scrollbar-gutter: stable; scrollbar-width: thin; - box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05), 0 2px 4px rgba(0, 0, 0, 0.1); - backdrop-filter: blur(16px); - @media only screen and (max-width: 768px) { - max-height: 100vh; - max-width: 80vw; - overflow: auto; + padding: 0 16px; +`; + +const ResultHeader = styled.div` + display: flex; + align-items: center; +`; + +const IconContainer = styled.div` + display: flex; + gap: 20px; + align-items: center; + margin-right: 20px; + position: relative; + + &::after { + content: ''; + position: absolute; + top: 24px; + bottom: 0; + left: 50%; + width: 1px; + background-color: ${props => props.theme.secondary.text}; } -` +`; + +const IconTitleWrapper = styled.div` + display: flex; + align-items: center; + gap: 8px; +`; + const Title = styled.h3` - font-size: 14px; + font-size: 17.32px; + font-weight: 400; color: ${props => props.theme.primary.text}; - opacity: 0.8; - padding-bottom: 6px; - font-weight: 600; - text-transform: uppercase; - border-bottom: 1px solid ${(props) => props.theme.secondary.text}; -` + margin: 0; +`; +const ContentWrapper = styled.div` + display: flex; + flex-direction: column; + gap: 8px; // Reduced from 1 +`; const Content = styled.div` - font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; + display: flex; + margin-left: 10px; + flex-direction: column; + gap: 8px; + padding: 4px 0 0px 20px; + font-size: 17.32px; + color: ${props => props.theme.primary.text}; + line-height: 1.6; + border-left: 2px solid #585858; ` +const ContentSegment = styled.div` + display: flex; + align-items: flex-start; + gap: 8px; + padding-right: 16px; +` +const TextContent = styled.div` + display: flex; + flex-direction: column; + gap: 16px; + flex: 1; + padding-top: 3px; +`; + const ResultWrapper = styled.div` - padding: 4px 8px 4px 8px; - border-radius: 8px; + display: flex; + align-items: flex-start; + width: 100%; + box-sizing: border-box; + padding: 12px 16px 0 16px; cursor: pointer; - &.contains-source:hover{ + margin-bottom: 8px; + background-color: ${props => props.theme.primary.bg}; + transition: background-color 0.2s; + + &.contains-source:hover { background-color: rgba(0, 92, 197, 0.15); ${Title} { - color: rgb(0, 126, 230); - } + color: rgb(0, 126, 230); + } } ` const Markdown = styled.div` @@ -200,19 +289,71 @@ const NoResults = styled.div` font-size: 1rem; color: #888; `; -const InfoButton = styled.button` - cursor: pointer; - padding: 10px 4px 10px 4px; - display: block; +const AskAIButton = styled.button` + display: flex; + align-items: center; + justify-content: flex-start; + gap: 12px; width: 100%; - color: inherit; + box-sizing: border-box; + height: 50px; + padding: 8px 24px; + border: none; border-radius: 6px; - background-color: ${(props) => props.theme.bg}; - text-align: center; + background-color: ${props => props.theme.secondary.bg}; + color: ${props => props.theme.bg === '#000' ? '#EDEDED' : props.theme.secondary.text}; + cursor: pointer; + transition: background-color 0.2s, box-shadow 0.2s; + font-size: 18px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + margin-bottom: 16px; + + &:hover { + opacity: 0.8; + } +` +const SearchHeader = styled.div` + display: flex; + align-items: center; + gap: 8px; + margin-bottom: 12px; + padding-bottom: 12px; + border-bottom: 1px solid ${props => props.theme.secondary.text}; +` + +const TextField = styled.input` + width: calc(100% - 32px); + margin: 0 16px; + padding: 12px 16px; + border: none; + background-color: transparent; + color: #EDEDED; + font-size: 22px; + font-weight: 400; + outline: none; + + &:focus { + border-color: none; + } +` + +const EscapeInstruction = styled.kbd` + display: flex; + align-items: center; + justify-content: center; + margin: 12px 16px 0; + padding: 4px 8px; + border-radius: 4px; + background-color: transparent; + border: 1px solid ${props => props.theme.secondary.text}; + color: ${props => props.theme.secondary.text}; font-size: 14px; - margin-bottom: 8px; - border:1px solid ${(props) => props.theme.secondary.text}; - + white-space: nowrap; + cursor: pointer; + width: fit-content; + &:hover { + background-color: rgba(255, 255, 255, 0.1); + } ` export const SearchBar = ({ apiKey = "74039c6d-bff7-44ce-ae55-2973cbf13837", @@ -226,47 +367,48 @@ export const SearchBar = ({ const [isWidgetOpen, setIsWidgetOpen] = React.useState(false); const inputRef = React.useRef(null); const containerRef = React.useRef(null); - const [isResultVisible, setIsResultVisible] = React.useState(true); + const [isResultVisible, setIsResultVisible] = React.useState(false); const [results, setResults] = React.useState([]); const debounceTimeout = React.useRef | null>(null); - const abortControllerRef = React.useRef(null) + const abortControllerRef = React.useRef(null); const browserOS = getOS(); - function isTouchDevice() { - return 'ontouchstart' in window; - } - const isTouch = isTouchDevice(); + const isTouch = 'ontouchstart' in window; + const md = new MarkdownIt(); + const getKeyboardInstruction = () => { - if (isResultVisible) return "Enter" - if (browserOS === 'mac') - return "⌘ K" - else - return "Ctrl K" - } + if (isResultVisible) return "Enter"; + return browserOS === 'mac' ? '⌘ + K' : 'Ctrl + K'; + }; + React.useEffect(() => { - const handleFocusSearch = (event: KeyboardEvent) => { + const handleClickOutside = (event: MouseEvent) => { + if (containerRef.current && !containerRef.current.contains(event.target as Node)) { + setIsResultVisible(false); + } + }; + + const handleKeyDown = (event: KeyboardEvent) => { if ( ((browserOS === 'win' || browserOS === 'linux') && event.ctrlKey && event.key === 'k') || (browserOS === 'mac' && event.metaKey && event.key === 'k') ) { event.preventDefault(); inputRef.current?.focus(); - } - } - const handleClickOutside = (event: MouseEvent) => { - if ( - containerRef.current && - !containerRef.current.contains(event.target as Node) - ) { + setIsResultVisible(true); + } else if (event.key === 'Escape') { setIsResultVisible(false); } }; + + document.addEventListener('mousedown', handleClickOutside); - document.addEventListener('keydown', handleFocusSearch); + document.addEventListener('keydown', handleKeyDown); return () => { - setIsResultVisible(true); document.removeEventListener('mousedown', handleClickOutside); + document.removeEventListener('keydown', handleKeyDown); }; - }, []) + }, []); + React.useEffect(() => { if (!input) { setResults([]); @@ -291,8 +433,6 @@ export const SearchBar = ({ }, 500); return () => { - console.log(results); - abortController.abort(); clearTimeout(debounceTimeout.current ?? undefined); }; @@ -304,73 +444,105 @@ export const SearchBar = ({ openWidget(); } }; + const openWidget = () => { setIsWidgetOpen(true); - setIsResultVisible(false) - } + setIsResultVisible(false); + }; + const handleClose = () => { setIsWidgetOpen(false); - } - const md = new MarkdownIt(); + }; + return (
+ - setIsResultVisible(true)} inputWidth={width} - onFocus={() => setIsResultVisible(true)} - ref={inputRef} - onSubmit={() => setIsWidgetOpen(true)} - onKeyDown={(e) => handleKeyDown(e)} - placeholder={placeholder} - value={input} - onChange={(e) => setInput(e.target.value)} - /> + > + Search here + { - input.length > 0 && isResultVisible && ( + isResultVisible && ( - - { - isTouch ? - "Ask the AI" : - <> - Press Enter to ask the AI - - } - - {!loading ? - (results.length > 0 ? - results.map((res, key) => { - const containsSource = res.source !== 'local'; - const filteredResults = preprocessSearchResultsToHTML(res.text,input) - if (filteredResults) - return ( - { - if (!containsSource) return; - window.open(res.source, '_blank', 'noopener, noreferrer') - }} - className={containsSource ? "contains-source" : ""}> - {res.title} - - - - - ) - else { - setResults((prevItems) => prevItems.filter((_, index) => index !== key)); - } - }) - : - No results - ) - : - - } + + setInput(e.target.value)} + onKeyDown={(e) => handleKeyDown(e)} + placeholder={placeholder} + autoFocus + /> + setIsResultVisible(false)}> + Esc + + + + DocsGPT + Ask the AI + + + {!loading ? ( + results.length > 0 ? ( + results.map((res, key) => { + const containsSource = res.source !== 'local'; + const processedResults = processMarkdownString(res.text, input); + if (processedResults) + return ( + { + if (!containsSource) return; + window.open(res.source, '_blank', 'noopener, noreferrer'); + }} + > +
+ + + + {res.title} + + + {processedResults.map((element, index) => ( + + + {element.tag === 'code' && } + {(element.tag === 'bulletList' || element.tag === 'numberedList') && } + {element.tag === 'text' && } + {element.tag === 'heading' && } + {element.tag === 'blockquote' && } + +
+ + ))} + + +
+ + ); + return null; + }) + ) : ( + No results found + ) + ) : ( + + )} + ) } @@ -402,4 +574,4 @@ export const SearchBar = ({
) -} \ No newline at end of file +} diff --git a/extensions/react-widget/src/utils/helper.ts b/extensions/react-widget/src/utils/helper.ts index ac257c91..9f92fdcb 100644 --- a/extensions/react-widget/src/utils/helper.ts +++ b/extensions/react-widget/src/utils/helper.ts @@ -25,7 +25,6 @@ export const getOS = () => { return 'other'; }; - interface ParsedElement { content: string; tag: string; @@ -48,14 +47,11 @@ export const processMarkdownString = (markdown: string, keyword?: string): Parse const trimmedLine = lines[i].trim(); if (!trimmedLine) continue; - // Handle code block start/end if (trimmedLine.startsWith('```')) { if (!isInCodeBlock) { - // Start of code block isInCodeBlock = true; codeBlockContent = []; } else { - // End of code block - process the collected content isInCodeBlock = false; const codeContent = codeBlockContent.join('\n'); const parsedElement: ParsedElement = { @@ -75,7 +71,6 @@ export const processMarkdownString = (markdown: string, keyword?: string): Parse continue; } - // Collect code block content if (isInCodeBlock) { codeBlockContent.push(trimmedLine); continue; @@ -86,7 +81,7 @@ export const processMarkdownString = (markdown: string, keyword?: string): Parse const headingMatch = trimmedLine.match(/^(#{1,6})\s+(.+)$/); const bulletMatch = trimmedLine.match(/^[-*]\s+(.+)$/); const numberedMatch = trimmedLine.match(/^\d+\.\s+(.+)$/); - const blockquoteMatch = trimmedLine.match(/^>+\s*(.+)$/); // Updated regex to handle multiple '>' symbols + const blockquoteMatch = trimmedLine.match(/^>+\s*(.+)$/); let content = trimmedLine; @@ -154,27 +149,3 @@ export const processMarkdownString = (markdown: string, keyword?: string): Parse return firstLine ? [firstLine] : []; }; - - -const markdownString = ` -# Title -This is a paragraph. - -## Subtitle -- Bullet item 1 -* Bullet item 2 -1. Numbered item 1 -2. Numbered item 2 - -\`\`\`javascript -const hello = "world"; -console.log(hello); -// This is a multi-line -// code block -\`\`\` - -Regular text after code block -`; - -const parsed = processMarkdownString(markdownString, 'world'); -console.log(parsed); From 598c7a5d76829b71dc24fdaa6500407a81b1d5eb Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Tue, 31 Dec 2024 16:25:44 +0530 Subject: [PATCH 08/86] (feat:search) load geist font --- .../react-widget/src/components/SearchBar.tsx | 40 ++++++------------- 1 file changed, 12 insertions(+), 28 deletions(-) diff --git a/extensions/react-widget/src/components/SearchBar.tsx b/extensions/react-widget/src/components/SearchBar.tsx index 5982f6f6..b887c17d 100644 --- a/extensions/react-widget/src/components/SearchBar.tsx +++ b/extensions/react-widget/src/components/SearchBar.tsx @@ -1,4 +1,4 @@ -import React, { useRef } from 'react'; +import React from 'react'; import styled, { ThemeProvider, createGlobalStyle } from 'styled-components'; import { WidgetCore } from './DocsGPTWidget'; import { SearchBarProps } from '@/types'; @@ -48,11 +48,16 @@ const GlobalStyle = createGlobalStyle` } `; +const loadGeistFont = () => { + const link = document.createElement('link'); + link.href = 'https://fonts.googleapis.com/css2?family=Geist:wght@100..900&display=swap'; // Replace with the actual CDN URL + link.rel = 'stylesheet'; + document.head.appendChild(link); +}; + const Main = styled.div` all: initial; - * { - font-family: 'Geist', sans-serif; - } + font-family: 'Geist', sans-serif; ` const SearchButton = styled.button<{ inputWidth: string }>` padding: 6px 6px; @@ -118,29 +123,6 @@ const SearchResultsScroll = styled.div` padding: 0 16px; `; -const ResultHeader = styled.div` - display: flex; - align-items: center; -`; - -const IconContainer = styled.div` - display: flex; - gap: 20px; - align-items: center; - margin-right: 20px; - position: relative; - - &::after { - content: ''; - position: absolute; - top: 24px; - bottom: 0; - left: 50%; - width: 1px; - background-color: ${props => props.theme.secondary.text}; - } -`; - const IconTitleWrapper = styled.div` display: flex; align-items: center; @@ -156,7 +138,7 @@ const Title = styled.h3` const ContentWrapper = styled.div` display: flex; flex-direction: column; - gap: 8px; // Reduced from 1 + gap: 8px; `; const Content = styled.div` display: flex; @@ -192,6 +174,7 @@ const ResultWrapper = styled.div` cursor: pointer; margin-bottom: 8px; background-color: ${props => props.theme.primary.bg}; + font-family: 'Geist',sans-serif; transition: background-color 0.2s; &.contains-source:hover { @@ -381,6 +364,7 @@ export const SearchBar = ({ }; React.useEffect(() => { + loadGeistFont() const handleClickOutside = (event: MouseEvent) => { if (containerRef.current && !containerRef.current.contains(event.target as Node)) { setIsResultVisible(false); From 2f33a46e89f76aa3e18807264ba87c006c1f4f53 Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Tue, 31 Dec 2024 17:33:06 +0530 Subject: [PATCH 09/86] (feat:search/UX) enhance function --- .../react-widget/src/components/SearchBar.tsx | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/extensions/react-widget/src/components/SearchBar.tsx b/extensions/react-widget/src/components/SearchBar.tsx index b887c17d..18ac88a8 100644 --- a/extensions/react-widget/src/components/SearchBar.tsx +++ b/extensions/react-widget/src/components/SearchBar.tsx @@ -50,7 +50,7 @@ const GlobalStyle = createGlobalStyle` const loadGeistFont = () => { const link = document.createElement('link'); - link.href = 'https://fonts.googleapis.com/css2?family=Geist:wght@100..900&display=swap'; // Replace with the actual CDN URL + link.href = 'https://fonts.googleapis.com/css2?family=Geist:wght@100..900&display=swap'; link.rel = 'stylesheet'; document.head.appendChild(link); }; @@ -61,6 +61,7 @@ const Main = styled.div` ` const SearchButton = styled.button<{ inputWidth: string }>` padding: 6px 6px; + font-family: inherit; width: ${({ inputWidth }) => inputWidth}; border-radius: 8px; display: inline; @@ -93,11 +94,11 @@ const SearchResults = styled.div` flex-direction: column; background-color: ${props => props.theme.primary.bg}; border: 1px solid ${props => props.theme.secondary.text}; - border-radius: 12px; - padding: 8px; + border-radius: 15px; + padding: 8px 0px 8px 0px; width: 792px; max-width: 90vw; - height: 70vh; + height: 415px; z-index: 100; left: 50%; top: 50%; @@ -277,7 +278,8 @@ const AskAIButton = styled.button` align-items: center; justify-content: flex-start; gap: 12px; - width: 100%; + width: calc(100% - 32px); + margin: 0 16px 16px 16px; box-sizing: border-box; height: 50px; padding: 8px 24px; @@ -289,7 +291,6 @@ const AskAIButton = styled.button` transition: background-color 0.2s, box-shadow 0.2s; font-size: 18px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); - margin-bottom: 16px; &:hover { opacity: 0.8; @@ -331,6 +332,7 @@ const EscapeInstruction = styled.kbd` border: 1px solid ${props => props.theme.secondary.text}; color: ${props => props.theme.secondary.text}; font-size: 14px; + font-family: 'Geist', sans-serif; white-space: nowrap; cursor: pointer; width: fit-content; @@ -356,8 +358,7 @@ export const SearchBar = ({ const abortControllerRef = React.useRef(null); const browserOS = getOS(); const isTouch = 'ontouchstart' in window; - const md = new MarkdownIt(); - + const getKeyboardInstruction = () => { if (isResultVisible) return "Enter"; return browserOS === 'mac' ? '⌘ + K' : 'Ctrl + K'; @@ -436,6 +437,7 @@ export const SearchBar = ({ const handleClose = () => { setIsWidgetOpen(false); + setIsResultVisible(true); }; return ( From 0f611eb87bf038154afb20b31350027eecf23ae0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 31 Dec 2024 14:52:21 +0000 Subject: [PATCH 10/86] build(deps): bump redis from 5.0.1 to 5.2.1 in /application Bumps [redis](https://github.com/redis/redis-py) from 5.0.1 to 5.2.1. - [Release notes](https://github.com/redis/redis-py/releases) - [Changelog](https://github.com/redis/redis-py/blob/master/CHANGES) - [Commits](https://github.com/redis/redis-py/compare/v5.0.1...v5.2.1) --- updated-dependencies: - dependency-name: redis dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- application/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/requirements.txt b/application/requirements.txt index b7660c42..6a318338 100644 --- a/application/requirements.txt +++ b/application/requirements.txt @@ -68,7 +68,7 @@ python-dateutil==2.9.0.post0 python-dotenv==1.0.1 python-pptx==1.0.2 qdrant-client==1.11.0 -redis==5.0.1 +redis==5.2.1 referencing==0.30.2 regex==2024.9.11 requests==2.32.3 From 3daeab5186e41289656b5a5d71b86c38a526a62e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 31 Dec 2024 14:57:29 +0000 Subject: [PATCH 11/86] build(deps): bump tiktoken from 0.7.0 to 0.8.0 in /application Bumps [tiktoken](https://github.com/openai/tiktoken) from 0.7.0 to 0.8.0. - [Release notes](https://github.com/openai/tiktoken/releases) - [Changelog](https://github.com/openai/tiktoken/blob/main/CHANGELOG.md) - [Commits](https://github.com/openai/tiktoken/compare/0.7.0...0.8.0) --- updated-dependencies: - dependency-name: tiktoken dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- application/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/requirements.txt b/application/requirements.txt index 6a318338..7c9f8101 100644 --- a/application/requirements.txt +++ b/application/requirements.txt @@ -74,7 +74,7 @@ regex==2024.9.11 requests==2.32.3 retry==0.9.2 sentence-transformers==3.3.1 -tiktoken==0.7.0 +tiktoken==0.8.0 tokenizers==0.21.0 torch==2.4.1 tqdm==4.66.5 From efb018d2b068a88dd99b8b32bb08f106517294e4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 31 Dec 2024 14:58:26 +0000 Subject: [PATCH 12/86] build(deps): bump marshmallow from 3.22.0 to 3.23.2 in /application Bumps [marshmallow](https://github.com/marshmallow-code/marshmallow) from 3.22.0 to 3.23.2. - [Changelog](https://github.com/marshmallow-code/marshmallow/blob/dev/CHANGELOG.rst) - [Commits](https://github.com/marshmallow-code/marshmallow/compare/3.22.0...3.23.2) --- updated-dependencies: - dependency-name: marshmallow dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- application/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/requirements.txt b/application/requirements.txt index 7c9f8101..362fdd45 100644 --- a/application/requirements.txt +++ b/application/requirements.txt @@ -37,7 +37,7 @@ langsmith==0.2.6 lazy-object-proxy==1.10.0 lxml==5.3.0 markupsafe==2.1.5 -marshmallow==3.22.0 +marshmallow==3.23.2 mpmath==1.3.0 multidict==6.1.0 mypy-extensions==1.0.0 From 190f57171875bcbbc0f31ff8e9ceec5d5a733a37 Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Wed, 1 Jan 2025 15:14:03 +0530 Subject: [PATCH 13/86] (feat/search) exacting ui --- .../react-widget/src/components/SearchBar.tsx | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/extensions/react-widget/src/components/SearchBar.tsx b/extensions/react-widget/src/components/SearchBar.tsx index 18ac88a8..3a7f2ddd 100644 --- a/extensions/react-widget/src/components/SearchBar.tsx +++ b/extensions/react-widget/src/components/SearchBar.tsx @@ -93,7 +93,7 @@ const SearchResults = styled.div` display: flex; flex-direction: column; background-color: ${props => props.theme.primary.bg}; - border: 1px solid ${props => props.theme.secondary.text}; + border: 1px solid ${props => props.theme.secondary.bg}; border-radius: 15px; padding: 8px 0px 8px 0px; width: 792px; @@ -128,6 +128,10 @@ const IconTitleWrapper = styled.div` display: flex; align-items: center; gap: 8px; + + .element-icon{ + margin: 4px; + } `; const Title = styled.h3` @@ -143,10 +147,10 @@ const ContentWrapper = styled.div` `; const Content = styled.div` display: flex; - margin-left: 10px; + margin-left: 8px; flex-direction: column; gap: 8px; - padding: 4px 0 0px 20px; + padding: 4px 0px 0px 12px; font-size: 17.32px; color: ${props => props.theme.primary.text}; line-height: 1.6; @@ -158,13 +162,6 @@ const ContentSegment = styled.div` gap: 8px; padding-right: 16px; ` -const TextContent = styled.div` - display: flex; - flex-direction: column; - gap: 16px; - flex: 1; - padding-top: 3px; -`; const ResultWrapper = styled.div` display: flex; @@ -173,7 +170,6 @@ const ResultWrapper = styled.div` box-sizing: border-box; padding: 12px 16px 0 16px; cursor: pointer; - margin-bottom: 8px; background-color: ${props => props.theme.primary.bg}; font-family: 'Geist',sans-serif; transition: background-color 0.2s; @@ -302,7 +298,7 @@ const SearchHeader = styled.div` gap: 8px; margin-bottom: 12px; padding-bottom: 12px; - border-bottom: 1px solid ${props => props.theme.secondary.text}; + border-bottom: 1px solid ${props => props.theme.secondary.bg}; ` const TextField = styled.input` From 33a28a64ec5a2aae91a173c648c99273ed274898 Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Thu, 2 Jan 2025 01:33:49 +0530 Subject: [PATCH 14/86] (fix:ui/mobile) button squashed --- frontend/src/conversation/SharedConversation.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/conversation/SharedConversation.tsx b/frontend/src/conversation/SharedConversation.tsx index 5ab1d639..c6f73351 100644 --- a/frontend/src/conversation/SharedConversation.tsx +++ b/frontend/src/conversation/SharedConversation.tsx @@ -236,7 +236,7 @@ export const SharedConversation = () => { -
+
{apiKey ? (
{ ) : ( From 0751debff7ad82c83d0f64bd9c00e72a15c83fc8 Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Thu, 2 Jan 2025 02:31:29 +0530 Subject: [PATCH 15/86] (feat:nav) add enter/esc to rename in tile --- frontend/src/conversation/ConversationTile.tsx | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/frontend/src/conversation/ConversationTile.tsx b/frontend/src/conversation/ConversationTile.tsx index dd3e6e1d..c29b9d71 100644 --- a/frontend/src/conversation/ConversationTile.tsx +++ b/frontend/src/conversation/ConversationTile.tsx @@ -115,6 +115,19 @@ export default function ConversationTile({ setConversationsName(conversation.name); setIsEdit(false); } + + const handleRenameKeyDown = (e: React.KeyboardEvent) => { + e.stopPropagation(); + if (e.key === 'Enter') { + handleSaveConversation({ + id: conversation.id, + name: conversationName, + }); + } else if (e.key === 'Escape') { + onClear(); + } + }; + return ( <>
setConversationsName(e.target.value)} + onKeyDown={handleRenameKeyDown} /> ) : (

@@ -239,7 +253,7 @@ export default function ConversationTile({ > Edit Date: Thu, 2 Jan 2025 13:32:25 +0530 Subject: [PATCH 16/86] (fix: sources) inconcistent capitalisation --- application/api/user/routes.py | 2 +- frontend/src/locale/ru.json | 274 ++++++++++++++++----------------- 2 files changed, 138 insertions(+), 138 deletions(-) diff --git a/application/api/user/routes.py b/application/api/user/routes.py index fa0ff382..6b000816 100644 --- a/application/api/user/routes.py +++ b/application/api/user/routes.py @@ -538,7 +538,7 @@ class CombinedJson(Resource): user = "local" data = [ { - "name": "default", + "name": "Default", "date": "default", "model": settings.EMBEDDINGS_NAME, "location": "remote", diff --git a/frontend/src/locale/ru.json b/frontend/src/locale/ru.json index d23092a1..defbf94a 100644 --- a/frontend/src/locale/ru.json +++ b/frontend/src/locale/ru.json @@ -1,142 +1,142 @@ { - "language": "Русский", - "chat": "Чат", - "chats": "Чаты", - "newChat": "Новый чат", - "myPlan": "Мой план", - "about": "О", - "inputPlaceholder": "Введите свое сообщение здесь...", - "tagline": "DocsGPT использует GenAI, пожалуйста, проверьте важную информацию, используя источники.", - "sourceDocs": "Источник", - "none": "Нет", - "cancel": "Отмена", - "demo": [ - { - "header": "Узнайте о DocsGPT", - "query": "Что такое DocsGPT?" - }, - { - "header": "Обобщить документацию", - "query": "Обобщить текущий контекст" - }, - { - "header": "Написать код", - "query": "Написать код для запроса API к /api/answer" - }, - { - "header": "Помощь в обучении", - "query": "Написать потенциальные вопросы для контекста" - } - ], - "settings": { - "label": "Настройки", - "general": { - "label": "Общие", - "selectTheme": "Выбрать тему", - "light": "Светлая", - "dark": "Темная", - "selectLanguage": "Выбрать язык", - "chunks": "Обработанные фрагменты на запрос", - "prompt": "Активная подсказка", - "deleteAllLabel": "Удалить все беседы", - "deleteAllBtn": "Удалить все", - "addNew": "Добавить новый", - "convHistory": "История разговоров", - "none": "Нет", - "low": "Низкий", - "medium": "Средний", - "high": "Высокий", - "unlimited": "Без ограничений", - "default": "по умолчанию" - }, - "documents": { - "label": "Документы", - "name": "Название документа", - "date": "Дата вектора", - "type": "Тип", - "tokenUsage": "Использование токена", - "noData": "Нет существующих документов" - }, - "apiKeys": { - "label": "Чат-боты", - "name": "Название", - "key": "Ключ API", - "sourceDoc": "Исходный документ", - "createNew": "Создать новый", - "noData": "Нет существующих чат-ботов" - }, - "analytics": { - "label": "Analytics" - }, - "logs": { - "label": "Журналы" - } + "language": "Русский", + "chat": "Чат", + "chats": "Чаты", + "newChat": "Новый чат", + "myPlan": "Мой план", + "about": "О", + "inputPlaceholder": "Введите свое сообщение здесь...", + "tagline": "DocsGPT использует GenAI, пожалуйста, проверьте важную информацию, используя источники.", + "sourceDocs": "Источник", + "none": "Нет", + "cancel": "Отмена", + "demo": [ + { + "header": "Узнайте о DocsGPT", + "query": "Что такое DocsGPT?" }, - "modals": { - "uploadDoc": { - "label": "Загрузить новую документацию", - "select": "Выберите способ загрузки документа в DocsGPT", - "file": "Загрузить с устройства", - "back": "Назад", - "wait": "Пожалуйста, подождите ...", - "remote": "Собрать с веб-сайта", - "start": "Начать чат", - "name": "Имя", - "choose": "Выбрать файлы", - "info": "Загрузите .pdf, .txt, .rst, .csv, .xlsx, .docx, .md, .zip с ограничением до 25 МБ", - "uploadedFiles": "Загруженные файлы", - "cancel": "Отмена", - "train": "Обучение", - "link": "Ссылка", - "urlLink": "URL-ссылка", - "repoUrl": "URL-адрес репозитория", - "reddit": { - "id": "ID клиента", - "secret": "Секрет клиента", - "agent": "Агент пользователя", - "searchQueries": "Поисковые запросы", - "numberOfPosts": "Количество сообщений" - }, - "drag": { - "title": "Загрузите исходный файл", - "description": "Перетащите сюда свой файл, чтобы добавить его в качестве источника." - } - }, - "createAPIKey": { - "label": "Создать новый ключ API", - "apiKeyName": "Имя ключа API", - "chunks": "Обработано фрагментов на запрос", - "prompt": "Выбрать активный запрос", - "sourceDoc": "Исходный документ", - "create": "Создать" - }, - "saveKey": { - "note": "Пожалуйста, сохраните свой ключ", - "disclaimer": "Это единственный раз, когда будет показан ваш ключ.", - "copy": "Копировать", - "copied": "Скопировано", - "confirm": "Я сохранил ключ" - }, - "deleteConv": { - "confirm": "Вы уверены, что хотите удалить все разговоры?", - "delete": "Удалить" - }, - "shareConv": { - "label": "Создать публичную страницу для общего доступа", - "note": "Исходный документ, личная информация и дальнейший разговор останутся конфиденциальными", - "create": "Создать", - "option": "Разрешить пользователям запрашивать дальнейшие действия" - } + { + "header": "Обобщить документацию", + "query": "Обобщить текущий контекст" }, - "sharedConv": { - "subtitle": "Создано с помощью", - "button": "Начать работу с DocsGPT", - "meta": "DocsGPT использует GenAI, пожалуйста, проверьте важную информацию с помощью источников." + { + "header": "Написать код", + "query": "Написать код для запроса API к /api/answer" }, - "convTile": { - "share": "Поделиться", - "delete": "Удалить", - "rename": "Переименовать", - "deleteWarning": "Вы уверены, что хотите удалить этот разговор?" + { + "header": "Помощь в обучении", + "query": "Написать потенциальные вопросы для контекста" } -} \ No newline at end of file + ], + "settings": { + "label": "Настройки", + "general": { + "label": "Общие", + "selectTheme": "Выбрать тему", + "light": "Светлая", + "dark": "Темная", + "selectLanguage": "Выбрать язык", + "chunks": "Обработанные фрагменты на запрос", + "prompt": "Активная подсказка", + "deleteAllLabel": "Удалить все беседы", + "deleteAllBtn": "Удалить все", + "addNew": "Добавить новый", + "convHistory": "История разговоров", + "none": "Нет", + "low": "Низкий", + "medium": "Средний", + "high": "Высокий", + "unlimited": "Без ограничений", + "default": "по умолчанию" + }, + "documents": { + "label": "Документы", + "name": "Название документа", + "date": "Дата вектора", + "type": "Тип", + "tokenUsage": "Использование токена", + "noData": "Нет существующих документов" + }, + "apiKeys": { + "label": "Чат-боты", + "name": "Название", + "key": "Ключ API", + "sourceDoc": "Исходный документ", + "createNew": "Создать новый", + "noData": "Нет существующих чат-ботов" + }, + "analytics": { + "label": "Analytics" + }, + "logs": { + "label": "Журналы" + } + }, + "modals": { + "uploadDoc": { + "label": "Загрузить новую документацию", + "select": "Выберите способ загрузки документа в DocsGPT", + "file": "Загрузить с устройства", + "back": "Назад", + "wait": "Пожалуйста, подождите ...", + "remote": "Собрать с веб-сайта", + "start": "Начать чат", + "name": "Имя", + "choose": "Выбрать файлы", + "info": "Загрузите .pdf, .txt, .rst, .csv, .xlsx, .docx, .md, .zip с ограничением до 25 МБ", + "uploadedFiles": "Загруженные файлы", + "cancel": "Отмена", + "train": "Обучение", + "link": "Ссылка", + "urlLink": "URL-ссылка", + "repoUrl": "URL-адрес репозитория", + "reddit": { + "id": "ID клиента", + "secret": "Секрет клиента", + "agent": "Агент пользователя", + "searchQueries": "Поисковые запросы", + "numberOfPosts": "Количество сообщений" + }, + "drag": { + "title": "Загрузите исходный файл", + "description": "Перетащите сюда свой файл, чтобы добавить его в качестве источника." + } + }, + "createAPIKey": { + "label": "Создать новый ключ API", + "apiKeyName": "Имя ключа API", + "chunks": "Обработано фрагментов на запрос", + "prompt": "Выбрать активный запрос", + "sourceDoc": "Исходный документ", + "create": "Создать" + }, + "saveKey": { + "note": "Пожалуйста, сохраните свой ключ", + "disclaimer": "Это единственный раз, когда будет показан ваш ключ.", + "copy": "Копировать", + "copied": "Скопировано", + "confirm": "Я сохранил ключ" + }, + "deleteConv": { + "confirm": "Вы уверены, что хотите удалить все разговоры?", + "delete": "Удалить" + }, + "shareConv": { + "label": "Создать публичную страницу для общего доступа", + "note": "Исходный документ, личная информация и дальнейший разговор останутся конфиденциальными", + "create": "Создать", + "option": "Разрешить пользователям запрашивать дальнейшие действия" + } + }, + "sharedConv": { + "subtitle": "Создано с помощью", + "button": "Начать работу с DocsGPT", + "meta": "DocsGPT использует GenAI, пожалуйста, проверьте важную информацию с помощью источников." + }, + "convTile": { + "share": "Поделиться", + "delete": "Удалить", + "rename": "Переименовать", + "deleteWarning": "Вы уверены, что хотите удалить этот разговор?" + } +} From 8b206b087c782aac7c944e9dedfb7ee74a0e554b Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Thu, 2 Jan 2025 19:36:07 +0530 Subject: [PATCH 17/86] (feat:search) adding buttonTextt prop, minor ui --- .../react-widget/src/components/SearchBar.tsx | 55 ++++++++----------- extensions/react-widget/src/types/index.ts | 7 ++- 2 files changed, 28 insertions(+), 34 deletions(-) diff --git a/extensions/react-widget/src/components/SearchBar.tsx b/extensions/react-widget/src/components/SearchBar.tsx index 3a7f2ddd..a9e43972 100644 --- a/extensions/react-widget/src/components/SearchBar.tsx +++ b/extensions/react-widget/src/components/SearchBar.tsx @@ -18,7 +18,7 @@ import { const themes = { dark: { bg: '#000', - text: '#fff', + text: '#EDEDED', primary: { text: "#FAFAFA", bg: '#111111' @@ -30,7 +30,7 @@ const themes = { }, light: { bg: '#fff', - text: '#000', + text: '#171717', primary: { text: "#222327", bg: "#fff" @@ -65,7 +65,7 @@ const SearchButton = styled.button<{ inputWidth: string }>` width: ${({ inputWidth }) => inputWidth}; border-radius: 8px; display: inline; - color: ${props => props.theme.primary.text}; + color: ${props => props.theme.secondary.text}; outline: none; border: none; background-color: ${props => props.theme.secondary.bg}; @@ -74,14 +74,6 @@ const SearchButton = styled.button<{ inputWidth: string }>` appearance: none; transition: background-color 128ms linear; text-align: left; - &:focus { - outline: none; - box-shadow: - 0px 0px 0px 2px rgba(0, 109, 199), - 0px 0px 6px rgb(0, 90, 163), - 0px 2px 6px rgba(0, 0, 0, 0.1); - background-color: ${props => props.theme.primary.bg}; - } ` const Container = styled.div` @@ -98,7 +90,7 @@ const SearchResults = styled.div` padding: 8px 0px 8px 0px; width: 792px; max-width: 90vw; - height: 415px; + height: 396px; z-index: 100; left: 50%; top: 50%; @@ -118,9 +110,9 @@ const SearchResultsScroll = styled.div` flex: 1; overflow-y: auto; overflow-x: hidden; - scrollbar-color: lab(48.438 0 0 / 0.4) rgba(0, 0, 0, 0); scrollbar-gutter: stable; scrollbar-width: thin; + scrollbar-color: #383838 transparent; padding: 0 16px; `; @@ -135,7 +127,7 @@ const IconTitleWrapper = styled.div` `; const Title = styled.h3` - font-size: 17.32px; + font-size: 15px; font-weight: 400; color: ${props => props.theme.primary.text}; margin: 0; @@ -151,7 +143,7 @@ const Content = styled.div` flex-direction: column; gap: 8px; padding: 4px 0px 0px 12px; - font-size: 17.32px; + font-size: 15px; color: ${props => props.theme.primary.text}; line-height: 1.6; border-left: 2px solid #585858; @@ -182,13 +174,13 @@ const ResultWrapper = styled.div` } ` const Markdown = styled.div` -line-height:20px; -font-size: 12px; +line-height:18px; +font-size: 11px; white-space: pre-wrap; pre { padding: 8px; width: 90%; - font-size: 12px; + font-size: 11px; border-radius: 6px; overflow-x: auto; background-color: #1B1C1F; @@ -196,7 +188,7 @@ white-space: pre-wrap; } h1,h2 { - font-size: 16px; + font-size: 14px; font-weight: 600; color: ${(props) => props.theme.text}; opacity: 0.8; @@ -204,20 +196,20 @@ white-space: pre-wrap; h3 { - font-size: 14px; + font-size: 12px; } p { margin: 0px; line-height: 1.35rem; - font-size: 12px; + font-size: 11px; } code:not(pre code) { border-radius: 6px; padding: 2px 2px; margin: 2px; - font-size: 10px; + font-size: 9px; display: inline; background-color: #646464; color: #fff ; @@ -266,7 +258,7 @@ const Loader = styled.div` const NoResults = styled.div` margin-top: 2rem; text-align: center; - font-size: 1rem; + font-size: 14px; color: #888; `; const AskAIButton = styled.button` @@ -282,10 +274,10 @@ const AskAIButton = styled.button` border: none; border-radius: 6px; background-color: ${props => props.theme.secondary.bg}; - color: ${props => props.theme.bg === '#000' ? '#EDEDED' : props.theme.secondary.text}; + color: ${props => props.theme.text}; cursor: pointer; transition: background-color 0.2s, box-shadow 0.2s; - font-size: 18px; + font-size: 16px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); &:hover { @@ -307,8 +299,8 @@ const TextField = styled.input` padding: 12px 16px; border: none; background-color: transparent; - color: #EDEDED; - font-size: 22px; + color: ${props => props.theme.text}; + font-size: 20px; font-weight: 400; outline: none; @@ -326,8 +318,8 @@ const EscapeInstruction = styled.kbd` border-radius: 4px; background-color: transparent; border: 1px solid ${props => props.theme.secondary.text}; - color: ${props => props.theme.secondary.text}; - font-size: 14px; + color: ${props => props.theme.text}; + font-size: 12px; font-family: 'Geist', sans-serif; white-space: nowrap; cursor: pointer; @@ -341,7 +333,8 @@ export const SearchBar = ({ apiHost = "https://gptcloud.arc53.com", theme = "dark", placeholder = "Search or Ask AI...", - width = "256px" + width = "256px", + buttonText = "Search here" }: SearchBarProps) => { const [input, setInput] = React.useState(""); const [loading, setLoading] = React.useState(false); @@ -445,7 +438,7 @@ export const SearchBar = ({ onClick={() => setIsResultVisible(true)} inputWidth={width} > - Search here + {buttonText} { isResultVisible && ( diff --git a/extensions/react-widget/src/types/index.ts b/extensions/react-widget/src/types/index.ts index cea9e43a..5438cec7 100644 --- a/extensions/react-widget/src/types/index.ts +++ b/extensions/react-widget/src/types/index.ts @@ -44,9 +44,10 @@ export interface WidgetCoreProps extends WidgetProps { export interface SearchBarProps { apiHost?: string; apiKey?: string; - theme?:THEME; - placeholder?:string; - width?:string; + theme?: THEME; + placeholder?: string; + width?: string; + buttonText?: string; } export interface Result { From 411115523ee0bceba3cc731a154aab92820a9612 Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Fri, 3 Jan 2025 02:49:40 +0530 Subject: [PATCH 18/86] (fix:search) ui adjustments --- .../react-widget/src/components/SearchBar.tsx | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/extensions/react-widget/src/components/SearchBar.tsx b/extensions/react-widget/src/components/SearchBar.tsx index a9e43972..7ab9c0ce 100644 --- a/extensions/react-widget/src/components/SearchBar.tsx +++ b/extensions/react-widget/src/components/SearchBar.tsx @@ -74,6 +74,7 @@ const SearchButton = styled.button<{ inputWidth: string }>` appearance: none; transition: background-color 128ms linear; text-align: left; + cursor: pointer; ` const Container = styled.div` @@ -131,6 +132,10 @@ const Title = styled.h3` font-weight: 400; color: ${props => props.theme.primary.text}; margin: 0; + overflow-wrap: break-word; + white-space: normal; + overflow: hidden; + text-overflow: ellipsis; `; const ContentWrapper = styled.div` display: flex; @@ -147,12 +152,17 @@ const Content = styled.div` color: ${props => props.theme.primary.text}; line-height: 1.6; border-left: 2px solid #585858; + overflow: hidden; ` const ContentSegment = styled.div` display: flex; align-items: flex-start; gap: 8px; padding-right: 16px; + overflow-wrap: break-word; + white-space: normal; + overflow: hidden; + text-overflow: ellipsis; ` const ResultWrapper = styled.div` @@ -166,6 +176,13 @@ const ResultWrapper = styled.div` font-family: 'Geist',sans-serif; transition: background-color 0.2s; + word-wrap: break-word; + overflow-wrap: break-word; + word-break: break-word; + white-space: normal; + overflow: hidden; + text-overflow: ellipsis; + &.contains-source:hover { background-color: rgba(0, 92, 197, 0.15); ${Title} { @@ -303,7 +320,7 @@ const TextField = styled.input` font-size: 20px; font-weight: 400; outline: none; - + &:focus { border-color: none; } From 0031ca315981332a008460d114c5ef4fd79a8b41 Mon Sep 17 00:00:00 2001 From: Siddhant Rai Date: Fri, 3 Jan 2025 12:27:54 +0530 Subject: [PATCH 19/86] refactor: UI enhancement in tools --- application/api/user/routes.py | 43 ++++---- frontend/src/api/endpoints.ts | 1 + frontend/src/api/services/userService.ts | 2 + frontend/src/assets/no-files-dark.svg | 15 +++ frontend/src/assets/no-files.svg | 15 +++ frontend/src/modals/AddToolModal.tsx | 2 +- frontend/src/modals/ConfirmationModal.tsx | 8 +- frontend/src/modals/WrapperModal.tsx | 20 ++-- frontend/src/settings/ToolConfig.tsx | 32 ++++-- frontend/src/settings/Tools.tsx | 123 +++++++++++++--------- 10 files changed, 168 insertions(+), 93 deletions(-) create mode 100644 frontend/src/assets/no-files-dark.svg create mode 100644 frontend/src/assets/no-files.svg diff --git a/application/api/user/routes.py b/application/api/user/routes.py index f2d1be06..4bcbd719 100644 --- a/application/api/user/routes.py +++ b/application/api/user/routes.py @@ -185,8 +185,13 @@ class SubmitFeedback(Resource): ), "answer": fields.String(required=False, description="The AI answer"), "feedback": fields.String(required=True, description="User feedback"), - "question_index":fields.Integer(required=True, description="The question number in that particular conversation"), - "conversation_id":fields.String(required=True, description="id of the particular conversation"), + "question_index": fields.Integer( + required=True, + description="The question number in that particular conversation", + ), + "conversation_id": fields.String( + required=True, description="id of the particular conversation" + ), "api_key": fields.String(description="Optional API key"), }, ) @@ -196,21 +201,24 @@ class SubmitFeedback(Resource): ) def post(self): data = request.get_json() - required_fields = [ "feedback","conversation_id","question_index"] + required_fields = ["feedback", "conversation_id", "question_index"] missing_fields = check_required_fields(data, required_fields) if missing_fields: return missing_fields try: conversations_collection.update_one( - {"_id": ObjectId(data["conversation_id"]), f"queries.{data['question_index']}": {"$exists": True}}, - { - "$set": { - f"queries.{data['question_index']}.feedback": data["feedback"] - } - } - ) - + { + "_id": ObjectId(data["conversation_id"]), + f"queries.{data['question_index']}": {"$exists": True}, + }, + { + "$set": { + f"queries.{data['question_index']}.feedback": data["feedback"] + } + }, + ) + except Exception as err: return make_response(jsonify({"success": False, "error": str(err)}), 400) @@ -253,11 +261,9 @@ class DeleteOldIndexes(Resource): jsonify({"success": False, "message": "Missing required fields"}), 400 ) - doc = sources_collection.find_one( - {"_id": ObjectId(source_id), "user": "local"} - ) + doc = sources_collection.find_one({"_id": ObjectId(source_id), "user": "local"}) if not doc: - return make_response(jsonify({"status": "not found"}), 404) + return make_response(jsonify({"status": "not found"}), 404) try: if settings.VECTOR_STORE == "faiss": shutil.rmtree(os.path.join(current_dir, "indexes", str(doc["_id"]))) @@ -271,7 +277,7 @@ class DeleteOldIndexes(Resource): pass except Exception as err: return make_response(jsonify({"success": False, "error": str(err)}), 400) - + sources_collection.delete_one({"_id": ObjectId(source_id)}) return make_response(jsonify({"success": True}), 200) @@ -498,7 +504,9 @@ class PaginatedSources(Resource): total_documents = sources_collection.count_documents(query) total_pages = max(1, math.ceil(total_documents / rows_per_page)) - page = min(max(1, page), total_pages) # add this to make sure page inbound is within the range + page = min( + max(1, page), total_pages + ) # add this to make sure page inbound is within the range sort_order = 1 if sort_order == "asc" else -1 skip = (page - 1) * rows_per_page @@ -2098,4 +2106,3 @@ class DeleteTool(Resource): return {"success": False, "error": str(err)}, 400 return {"success": True}, 200 - \ No newline at end of file diff --git a/frontend/src/api/endpoints.ts b/frontend/src/api/endpoints.ts index 8a7f9ae2..66c334c1 100644 --- a/frontend/src/api/endpoints.ts +++ b/frontend/src/api/endpoints.ts @@ -23,6 +23,7 @@ const endpoints = { CREATE_TOOL: '/api/create_tool', UPDATE_TOOL_STATUS: '/api/update_tool_status', UPDATE_TOOL: '/api/update_tool', + DELETE_TOOL: '/api/delete_tool', }, CONVERSATION: { ANSWER: '/api/answer', diff --git a/frontend/src/api/services/userService.ts b/frontend/src/api/services/userService.ts index ab91a0a4..8a9b5858 100644 --- a/frontend/src/api/services/userService.ts +++ b/frontend/src/api/services/userService.ts @@ -45,6 +45,8 @@ const userService = { apiClient.post(endpoints.USER.UPDATE_TOOL_STATUS, data), updateTool: (data: any): Promise => apiClient.post(endpoints.USER.UPDATE_TOOL, data), + deleteTool: (data: any): Promise => + apiClient.post(endpoints.USER.DELETE_TOOL, data), }; export default userService; diff --git a/frontend/src/assets/no-files-dark.svg b/frontend/src/assets/no-files-dark.svg new file mode 100644 index 00000000..b1e28a0f --- /dev/null +++ b/frontend/src/assets/no-files-dark.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/no-files.svg b/frontend/src/assets/no-files.svg new file mode 100644 index 00000000..36510546 --- /dev/null +++ b/frontend/src/assets/no-files.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/frontend/src/modals/AddToolModal.tsx b/frontend/src/modals/AddToolModal.tsx index 330cf3bb..0763321d 100644 --- a/frontend/src/modals/AddToolModal.tsx +++ b/frontend/src/modals/AddToolModal.tsx @@ -84,7 +84,7 @@ export default function AddToolModal({

Select a tool to set up

-
+
{availableTools.map((tool, index) => (
); } - -export default ConfirmationModal; diff --git a/frontend/src/modals/WrapperModal.tsx b/frontend/src/modals/WrapperModal.tsx index f17e0a8a..da718a7a 100644 --- a/frontend/src/modals/WrapperModal.tsx +++ b/frontend/src/modals/WrapperModal.tsx @@ -1,12 +1,13 @@ import React, { useEffect, useRef } from 'react'; -import { WrapperModalProps } from './types'; -import Exit from '../assets/exit.svg'; -const WrapperModal: React.FC = ({ +import Exit from '../assets/exit.svg'; +import { WrapperModalProps } from './types'; + +export default function WrapperModal({ children, close, isPerformingTask, -}) => { +}: WrapperModalProps) { const modalRef = useRef(null); useEffect(() => { @@ -39,10 +40,13 @@ const WrapperModal: React.FC = ({
{!isPerformingTask && ( - )} @@ -50,6 +54,4 @@ const WrapperModal: React.FC = ({
); -}; - -export default WrapperModal; +} diff --git a/frontend/src/settings/ToolConfig.tsx b/frontend/src/settings/ToolConfig.tsx index 0de4dab9..cd5516fd 100644 --- a/frontend/src/settings/ToolConfig.tsx +++ b/frontend/src/settings/ToolConfig.tsx @@ -58,6 +58,12 @@ export default function ToolConfig({ handleGoBack(); }); }; + + const handleDelete = () => { + userService.deleteTool({ id: tool.id }).then(() => { + handleGoBack(); + }); + }; return (
@@ -83,7 +89,7 @@ export default function ToolConfig({ Authentication

)} -
+
{Object.keys(tool?.config).length !== 0 && (
@@ -98,12 +104,20 @@ export default function ToolConfig({ >
)} - +
+ + +
@@ -118,7 +132,7 @@ export default function ToolConfig({ key={actionIndex} className="w-full border border-silver dark:border-silver/40 rounded-xl" > -
+

{action.name}

@@ -146,7 +160,7 @@ export default function ToolConfig({
-
+
('INACTIVE'); @@ -86,62 +90,77 @@ export default function Tools() {
- {userTools - .filter((tool) => - tool.displayName - .toLowerCase() - .includes(searchTerm.toLowerCase()), - ) - .map((tool, index) => ( -
-
-
- - + +
+
+

+ {tool.displayName} +

+

+ {tool.description} +

+
-
-

- {tool.displayName} -

-

- {tool.description} -

+
+
-
- -
-
- ))} + )) + )}
Date: Fri, 3 Jan 2025 12:42:23 +0530 Subject: [PATCH 20/86] fix: extra padding in confirmation modal --- frontend/src/modals/ConfirmationModal.tsx | 2 +- frontend/src/modals/WrapperModal.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/modals/ConfirmationModal.tsx b/frontend/src/modals/ConfirmationModal.tsx index 61a25c63..1a2e22e2 100644 --- a/frontend/src/modals/ConfirmationModal.tsx +++ b/frontend/src/modals/ConfirmationModal.tsx @@ -31,7 +31,7 @@ export default function ConfirmationModal({ }} >
-
+

{message}

diff --git a/frontend/src/modals/WrapperModal.tsx b/frontend/src/modals/WrapperModal.tsx index da718a7a..18d0e48e 100644 --- a/frontend/src/modals/WrapperModal.tsx +++ b/frontend/src/modals/WrapperModal.tsx @@ -40,7 +40,7 @@ export default function WrapperModal({
{!isPerformingTask && (
{loading ? ( ) : ( -
+
@@ -270,7 +270,7 @@ const Documents: React.FC = ({ {document.type !== 'remote' && ( Delete { @@ -282,7 +282,7 @@ const Documents: React.FC = ({ {document.syncFrequency && (
{ handleManageSync(document, value); diff --git a/frontend/src/settings/General.tsx b/frontend/src/settings/General.tsx index 4868d252..227b0a6e 100644 --- a/frontend/src/settings/General.tsx +++ b/frontend/src/settings/General.tsx @@ -21,33 +21,15 @@ export default function General() { t, i18n: { changeLanguage, language }, } = useTranslation(); - const themes = ['Light', 'Dark']; + const themes = [t('settings.general.light'), t('settings.general.dark')]; const languageOptions = [ - { - label: 'English', - value: 'en', - }, - { - label: 'Spanish', - value: 'es', - }, - { - label: 'Japanese', - value: 'jp', - }, - { - label: 'Mandarin', - value: 'zh', - }, - { - label: 'Traditional Chinese', - value: 'zhTW', - }, - { - label: 'Russian', - value: 'ru', - }, + { label: 'English', value: 'en' }, + { label: 'Español', value: 'es' }, + { label: '日本語', value: 'jp' }, + { label: '普通话', value: 'zh' }, + { label: '繁體中文(臺灣)', value: 'zhTW' }, + { label: 'Русский', value: 'ru' }, ]; const chunks = ['0', '2', '4', '6', '8', '10']; const token_limits = new Map([ diff --git a/frontend/src/settings/Logs.tsx b/frontend/src/settings/Logs.tsx index 1e248d46..0f452e97 100644 --- a/frontend/src/settings/Logs.tsx +++ b/frontend/src/settings/Logs.tsx @@ -1,4 +1,5 @@ import React, { useState, useEffect, useRef, useCallback } from 'react'; +import { useTranslation } from 'react-i18next'; import userService from '../api/services/userService'; import ChevronRight from '../assets/chevron-right.svg'; @@ -8,6 +9,7 @@ import { APIKeyData, LogData } from './types'; import CoppyButton from '../components/CopyButton'; export default function Logs() { + const { t } = useTranslation(); const [chatbots, setChatbots] = useState([]); const [selectedChatbot, setSelectedChatbot] = useState(); const [logs, setLogs] = useState([]); @@ -66,7 +68,7 @@ export default function Logs() {

- Filter by chatbot + {t('settings.logs.filterByChatbot')}

{loadingChatbots ? ( @@ -78,9 +80,9 @@ export default function Logs() { label: chatbot.name, value: chatbot.id, })), - { label: 'None', value: '' }, + { label: t('settings.logs.none'), value: '' }, ]} - placeholder="Select chatbot" + placeholder={t('settings.logs.selectChatbotPlaceholder')} onSelect={(chatbot: { label: string; value: string }) => { setSelectedChatbot( chatbots.find((item) => item.id === chatbot.value), @@ -120,6 +122,7 @@ type LogsTableProps = { }; function LogsTable({ logs, setPage }: LogsTableProps) { + const { t } = useTranslation(); const observerRef = useRef(); const firstObserver = useCallback((node: HTMLDivElement) => { if (observerRef.current) { @@ -134,7 +137,7 @@ function LogsTable({ logs, setPage }: LogsTableProps) {

- API generated / chatbot conversations + {t('settings.logs.apiGeneratedConversations')}

Date: Sun, 5 Jan 2025 01:46:47 +0000 Subject: [PATCH 31/86] Update dependabot.yml --- .github/dependabot.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index dd0799c6..a41a1f3e 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -8,12 +8,12 @@ updates: - package-ecosystem: "pip" # See documentation for possible values directory: "/application" # Location of package manifests schedule: - interval: "weekly" + interval: "daily" - package-ecosystem: "npm" # See documentation for possible values directory: "/frontend" # Location of package manifests schedule: - interval: "weekly" + interval: "daily" - package-ecosystem: "github-actions" directory: "/" schedule: - interval: "weekly" + interval: "daily" From 90eb261da658bce45a23c1961672a1267f46b8bd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 5 Jan 2025 01:47:38 +0000 Subject: [PATCH 32/86] build(deps): bump transformers from 4.47.0 to 4.47.1 in /application Bumps [transformers](https://github.com/huggingface/transformers) from 4.47.0 to 4.47.1. - [Release notes](https://github.com/huggingface/transformers/releases) - [Commits](https://github.com/huggingface/transformers/compare/v4.47.0...v4.47.1) --- updated-dependencies: - dependency-name: transformers dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- application/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/requirements.txt b/application/requirements.txt index 362fdd45..24496040 100644 --- a/application/requirements.txt +++ b/application/requirements.txt @@ -78,7 +78,7 @@ tiktoken==0.8.0 tokenizers==0.21.0 torch==2.4.1 tqdm==4.66.5 -transformers==4.47.0 +transformers==4.47.1 typing-extensions==4.12.2 typing-inspect==0.9.0 tzdata==2024.2 From c873e4ef42f2c0c66c6f5aca7227001d6da7bdea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 5 Jan 2025 01:47:42 +0000 Subject: [PATCH 33/86] build(deps): bump markupsafe from 2.1.5 to 3.0.2 in /application Bumps [markupsafe](https://github.com/pallets/markupsafe) from 2.1.5 to 3.0.2. - [Release notes](https://github.com/pallets/markupsafe/releases) - [Changelog](https://github.com/pallets/markupsafe/blob/main/CHANGES.rst) - [Commits](https://github.com/pallets/markupsafe/compare/2.1.5...3.0.2) --- updated-dependencies: - dependency-name: markupsafe dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- application/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/requirements.txt b/application/requirements.txt index 362fdd45..f795cab7 100644 --- a/application/requirements.txt +++ b/application/requirements.txt @@ -36,7 +36,7 @@ langchain-text-splitters==0.3.4 langsmith==0.2.6 lazy-object-proxy==1.10.0 lxml==5.3.0 -markupsafe==2.1.5 +markupsafe==3.0.2 marshmallow==3.23.2 mpmath==1.3.0 multidict==6.1.0 From e1b6d6155889dadd31da46b45ac27d92a01d5324 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 5 Jan 2025 01:47:50 +0000 Subject: [PATCH 34/86] build(deps): bump regex from 2024.9.11 to 2024.11.6 in /application Bumps [regex](https://github.com/mrabarnett/mrab-regex) from 2024.9.11 to 2024.11.6. - [Changelog](https://github.com/mrabarnett/mrab-regex/blob/hg/changelog.txt) - [Commits](https://github.com/mrabarnett/mrab-regex/compare/2024.9.11...2024.11.6) --- updated-dependencies: - dependency-name: regex dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- application/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/requirements.txt b/application/requirements.txt index 362fdd45..79fecc1f 100644 --- a/application/requirements.txt +++ b/application/requirements.txt @@ -70,7 +70,7 @@ python-pptx==1.0.2 qdrant-client==1.11.0 redis==5.2.1 referencing==0.30.2 -regex==2024.9.11 +regex==2024.11.6 requests==2.32.3 retry==0.9.2 sentence-transformers==3.3.1 From 95ec541a3879387b9e476ff2c4bac6e2a640c2cb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 5 Jan 2025 01:48:13 +0000 Subject: [PATCH 35/86] build(deps): bump react-chartjs-2 from 5.2.0 to 5.3.0 in /frontend Bumps [react-chartjs-2](https://github.com/reactchartjs/react-chartjs-2) from 5.2.0 to 5.3.0. - [Release notes](https://github.com/reactchartjs/react-chartjs-2/releases) - [Changelog](https://github.com/reactchartjs/react-chartjs-2/blob/master/CHANGELOG.md) - [Commits](https://github.com/reactchartjs/react-chartjs-2/compare/v5.2.0...v5.3.0) --- updated-dependencies: - dependency-name: react-chartjs-2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 10 +++++----- frontend/package.json | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 28ce44eb..487a9880 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -14,7 +14,7 @@ "i18next-browser-languagedetector": "^8.0.2", "prop-types": "^15.8.1", "react": "^18.2.0", - "react-chartjs-2": "^5.2.0", + "react-chartjs-2": "^5.3.0", "react-copy-to-clipboard": "^5.1.0", "react-dom": "^18.3.1", "react-dropzone": "^14.3.5", @@ -7842,12 +7842,12 @@ } }, "node_modules/react-chartjs-2": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.2.0.tgz", - "integrity": "sha512-98iN5aguJyVSxp5U3CblRLH67J8gkfyGNbiK3c+l1QI/G4irHMPQw44aEPmjVag+YKTyQ260NcF82GTQ3bdscA==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.3.0.tgz", + "integrity": "sha512-UfZZFnDsERI3c3CZGxzvNJd02SHjaSJ8kgW1djn65H1KK8rehwTjyrRKOG3VTMG8wtHZ5rgAO5oTHtHi9GCCmw==", "peerDependencies": { "chart.js": "^4.1.1", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "node_modules/react-copy-to-clipboard": { diff --git a/frontend/package.json b/frontend/package.json index ec155cde..c105b703 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -25,7 +25,7 @@ "i18next-browser-languagedetector": "^8.0.2", "prop-types": "^15.8.1", "react": "^18.2.0", - "react-chartjs-2": "^5.2.0", + "react-chartjs-2": "^5.3.0", "react-copy-to-clipboard": "^5.1.0", "react-dom": "^18.3.1", "react-helmet": "^6.1.0", From c41877920af21a863754a26a0c046e4a8c16a947 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 5 Jan 2025 01:58:52 +0000 Subject: [PATCH 36/86] build(deps): bump jiter from 0.5.0 to 0.8.2 in /application Bumps [jiter](https://github.com/pydantic/jiter) from 0.5.0 to 0.8.2. - [Release notes](https://github.com/pydantic/jiter/releases) - [Commits](https://github.com/pydantic/jiter/compare/v0.5.0...v0.8.2) --- updated-dependencies: - dependency-name: jiter dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- application/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/requirements.txt b/application/requirements.txt index c7510c94..a9f17566 100644 --- a/application/requirements.txt +++ b/application/requirements.txt @@ -19,7 +19,7 @@ gunicorn==23.0.0 html2text==2024.2.26 javalang==0.13.0 jinja2==3.1.5 -jiter==0.5.0 +jiter==0.8.2 jmespath==1.0.1 joblib==1.4.2 jsonpatch==1.33 From bd5504461e35d7f8504588af3d283f44b60c3a2d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 5 Jan 2025 02:04:46 +0000 Subject: [PATCH 37/86] build(deps): bump langchain-core from 0.3.28 to 0.3.29 in /application Bumps [langchain-core](https://github.com/langchain-ai/langchain) from 0.3.28 to 0.3.29. - [Release notes](https://github.com/langchain-ai/langchain/releases) - [Commits](https://github.com/langchain-ai/langchain/compare/langchain-core==0.3.28...langchain-core==0.3.29) --- updated-dependencies: - dependency-name: langchain-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- application/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/requirements.txt b/application/requirements.txt index d4311430..fe0ab8e3 100644 --- a/application/requirements.txt +++ b/application/requirements.txt @@ -30,7 +30,7 @@ jsonschema-specifications==2023.7.1 kombu==5.4.2 langchain==0.3.13 langchain-community==0.3.13 -langchain-core==0.3.28 +langchain-core==0.3.29 langchain-openai==0.2.14 langchain-text-splitters==0.3.4 langsmith==0.2.6 From 0bbf1db434025ca9f9d0b36ee45009797513ff26 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Jan 2025 20:34:20 +0000 Subject: [PATCH 38/86] build(deps): bump langchain-community in /application Bumps [langchain-community](https://github.com/langchain-ai/langchain) from 0.3.13 to 0.3.14. - [Release notes](https://github.com/langchain-ai/langchain/releases) - [Commits](https://github.com/langchain-ai/langchain/compare/langchain-community==0.3.13...langchain-community==0.3.14) --- updated-dependencies: - dependency-name: langchain-community dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- application/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/requirements.txt b/application/requirements.txt index fe0ab8e3..be0814c2 100644 --- a/application/requirements.txt +++ b/application/requirements.txt @@ -29,7 +29,7 @@ jsonschema-spec==0.2.4 jsonschema-specifications==2023.7.1 kombu==5.4.2 langchain==0.3.13 -langchain-community==0.3.13 +langchain-community==0.3.14 langchain-core==0.3.29 langchain-openai==0.2.14 langchain-text-splitters==0.3.4 From 035f41b12c06661f02c2812cc333912c192186e1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Jan 2025 20:34:22 +0000 Subject: [PATCH 39/86] build(deps): bump primp from 0.6.3 to 0.9.3 in /application Bumps [primp](https://github.com/deedy5/primp) from 0.6.3 to 0.9.3. - [Release notes](https://github.com/deedy5/primp/releases) - [Commits](https://github.com/deedy5/primp/compare/v0.6.3...v0.9.3) --- updated-dependencies: - dependency-name: primp dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- application/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/requirements.txt b/application/requirements.txt index fe0ab8e3..7dd40cbf 100644 --- a/application/requirements.txt +++ b/application/requirements.txt @@ -55,7 +55,7 @@ pathable==0.4.3 pillow==10.4.0 portalocker==2.10.1 prance==23.6.21.0 -primp==0.6.3 +primp==0.9.3 prompt-toolkit==3.0.47 protobuf==5.28.2 py==1.11.0 From 9c30ff3024c193ba6e8a008378e102fb508276b3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Jan 2025 20:34:27 +0000 Subject: [PATCH 40/86] build(deps): bump torch from 2.4.1 to 2.5.1 in /application Bumps [torch](https://github.com/pytorch/pytorch) from 2.4.1 to 2.5.1. - [Release notes](https://github.com/pytorch/pytorch/releases) - [Changelog](https://github.com/pytorch/pytorch/blob/main/RELEASE.md) - [Commits](https://github.com/pytorch/pytorch/compare/v2.4.1...v2.5.1) --- updated-dependencies: - dependency-name: torch dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- application/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/requirements.txt b/application/requirements.txt index fe0ab8e3..62a960f1 100644 --- a/application/requirements.txt +++ b/application/requirements.txt @@ -76,7 +76,7 @@ retry==0.9.2 sentence-transformers==3.3.1 tiktoken==0.8.0 tokenizers==0.21.0 -torch==2.4.1 +torch==2.5.1 tqdm==4.66.5 transformers==4.47.1 typing-extensions==4.12.2 From 1e011879b11a0d860757f7b5be8a2e4aad54fb9a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Jan 2025 20:34:31 +0000 Subject: [PATCH 41/86] build(deps): bump networkx from 3.3 to 3.4.2 in /application Bumps [networkx](https://github.com/networkx/networkx) from 3.3 to 3.4.2. - [Release notes](https://github.com/networkx/networkx/releases) - [Commits](https://github.com/networkx/networkx/compare/networkx-3.3...networkx-3.4.2) --- updated-dependencies: - dependency-name: networkx dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- application/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/requirements.txt b/application/requirements.txt index fe0ab8e3..ac8139c4 100644 --- a/application/requirements.txt +++ b/application/requirements.txt @@ -41,7 +41,7 @@ marshmallow==3.23.2 mpmath==1.3.0 multidict==6.1.0 mypy-extensions==1.0.0 -networkx==3.3 +networkx==3.4.2 numpy==2.2.1 openai==1.58.1 openapi-schema-validator==0.6.2 From d5b73236dedfd6e3276a355ee50ca629b2ab3d8e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Jan 2025 20:34:39 +0000 Subject: [PATCH 42/86] build(deps): bump pymongo from 4.8.0 to 4.10.1 in /application Bumps [pymongo](https://github.com/mongodb/mongo-python-driver) from 4.8.0 to 4.10.1. - [Release notes](https://github.com/mongodb/mongo-python-driver/releases) - [Changelog](https://github.com/mongodb/mongo-python-driver/blob/master/doc/changelog.rst) - [Commits](https://github.com/mongodb/mongo-python-driver/compare/4.8.0...4.10.1) --- updated-dependencies: - dependency-name: pymongo dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- application/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/requirements.txt b/application/requirements.txt index fe0ab8e3..77450fea 100644 --- a/application/requirements.txt +++ b/application/requirements.txt @@ -62,7 +62,7 @@ py==1.11.0 pydantic==2.9.2 pydantic-core==2.23.4 pydantic-settings==2.4.0 -pymongo==4.8.0 +pymongo==4.10.1 pypdf2==3.0.1 python-dateutil==2.9.0.post0 python-dotenv==1.0.1 From 93e376ad2fbf10583b8d731e935f496f8c6c7dae Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 6 Jan 2025 23:33:34 +0000 Subject: [PATCH 43/86] fix: bump dependency --- application/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/requirements.txt b/application/requirements.txt index be0814c2..aaa74993 100644 --- a/application/requirements.txt +++ b/application/requirements.txt @@ -28,7 +28,7 @@ jsonschema==4.23.0 jsonschema-spec==0.2.4 jsonschema-specifications==2023.7.1 kombu==5.4.2 -langchain==0.3.13 +langchain==0.3.14 langchain-community==0.3.14 langchain-core==0.3.29 langchain-openai==0.2.14 From d1981967b24413bb775bf3950dc06d8021911ede Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Tue, 7 Jan 2025 20:28:59 +0530 Subject: [PATCH 44/86] (fix:locales) sync conversation --- .../src/conversation/ConversationBubble.tsx | 36 ++++++++++++------- frontend/src/locale/en.json | 16 +++++++++ frontend/src/locale/jp.json | 34 +++++++++++++++++- frontend/src/locale/zh-TW.json | 2 +- frontend/src/settings/index.tsx | 4 +-- 5 files changed, 75 insertions(+), 17 deletions(-) diff --git a/frontend/src/conversation/ConversationBubble.tsx b/frontend/src/conversation/ConversationBubble.tsx index d88b249e..e410b7c5 100644 --- a/frontend/src/conversation/ConversationBubble.tsx +++ b/frontend/src/conversation/ConversationBubble.tsx @@ -8,6 +8,7 @@ import { vscDarkPlus } from 'react-syntax-highlighter/dist/cjs/styles/prism'; import rehypeKatex from 'rehype-katex'; import remarkGfm from 'remark-gfm'; import remarkMath from 'remark-math'; +import { useTranslation } from 'react-i18next'; import DocsGPT3 from '../assets/cute_docsgpt3.svg'; import Dislike from '../assets/dislike.svg?react'; @@ -62,6 +63,7 @@ const ConversationBubble = forwardRef< }, ref, ) { + const { t } = useTranslation(); // const bubbleRef = useRef(null); const chunks = useSelector(selectChunks); const selectedDocs = useSelector(selectSelectedDocs); @@ -113,13 +115,13 @@ const ConversationBubble = forwardRef< {isEditClicked && (
{status === 'loading' ? ( + alt={t('loading')} + /> ) : (
- handleQuestionSubmission()} - src={isDarkTheme ? SendDark : Send} - > + aria-label={t('send')} + className="flex items-center justify-center" + > + {t('send')} +
)}
diff --git a/frontend/src/locale/en.json b/frontend/src/locale/en.json index 070deba6..9f9cbb21 100644 --- a/frontend/src/locale/en.json +++ b/frontend/src/locale/en.json @@ -166,6 +166,8 @@ "copied": "Copied", "speak": "Speak", "answer": "Answer", + "send": "Send message", + "loading": "Loading response", "edit": { "placeholder": "Type the updated query..." }, diff --git a/frontend/src/preferences/PromptsModal.tsx b/frontend/src/preferences/PromptsModal.tsx index 3aa8c54c..3a1f9bfa 100644 --- a/frontend/src/preferences/PromptsModal.tsx +++ b/frontend/src/preferences/PromptsModal.tsx @@ -29,8 +29,9 @@ function AddPrompt({ setNewPromptName(''); setNewPromptContent(''); }} + aria-label="Close add prompt modal" > - + Close modal

@@ -40,7 +41,11 @@ function AddPrompt({ Add your custom prompt and save it to DocsGPT

+
+
@@ -104,8 +114,9 @@ function EditPrompt({ onClick={() => { setModalState('INACTIVE'); }} + aria-label="Close edit prompt modal" > - + Close modal

@@ -115,13 +126,17 @@ function EditPrompt({ Edit your custom prompt and save it to DocsGPT

+ setEditPromptName(e.target.value)} - > + />
Prompt Name @@ -132,10 +147,15 @@ function EditPrompt({ Prompt Text
+
diff --git a/frontend/src/settings/APIKeys.tsx b/frontend/src/settings/APIKeys.tsx index 6775ba87..038e4bbb 100644 --- a/frontend/src/settings/APIKeys.tsx +++ b/frontend/src/settings/APIKeys.tsx @@ -115,12 +115,20 @@ export default function APIKeys() {
- - + - - + + @@ -146,7 +154,7 @@ export default function APIKeys() { diff --git a/frontend/src/settings/Logs.tsx b/frontend/src/settings/Logs.tsx index 0f452e97..f1ebfe72 100644 --- a/frontend/src/settings/Logs.tsx +++ b/frontend/src/settings/Logs.tsx @@ -67,9 +67,12 @@ export default function Logs() {
-

+

+ {loadingChatbots ? ( ) : ( diff --git a/frontend/src/settings/Tools.tsx b/frontend/src/settings/Tools.tsx index f58487a3..3dc31e35 100644 --- a/frontend/src/settings/Tools.tsx +++ b/frontend/src/settings/Tools.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { useTranslation } from 'react-i18next'; import userService from '../api/services/userService'; import CogwheelIcon from '../assets/cogwheel.svg'; @@ -18,6 +19,7 @@ export default function Tools() { React.useState('INACTIVE'); const [userTools, setUserTools] = React.useState([]); const [selectedTool, setSelectedTool] = React.useState(null); + const { t } = useTranslation(); const getUserTools = () => { userService @@ -70,12 +72,15 @@ export default function Tools() {
+ setSearchTerm(e.target.value)} /> @@ -86,7 +91,7 @@ export default function Tools() { setAddToolModalState('ACTIVE'); }} > - Add Tool + {t('settings.tools.addTool')}
@@ -98,10 +103,10 @@ export default function Tools() {
No tools found - No tools found + {t('settings.tools.noToolsFound')}
) : ( userTools @@ -119,15 +124,19 @@ export default function Tools() {
{`${tool.displayName} @@ -146,6 +155,11 @@ export default function Tools() { htmlFor={`toolToggle-${index}`} className="relative inline-block h-6 w-10 cursor-pointer rounded-full bg-gray-300 dark:bg-[#D2D5DA33]/20 transition [-webkit-tap-highlight-color:_transparent] has-[:checked]:bg-[#0C9D35CC] has-[:checked]:dark:bg-[#0C9D35CC]" > + + {t('settings.tools.toggleToolAria', { + toolName: tool.displayName, + })} +
Date: Mon, 13 Jan 2025 18:20:08 +0530 Subject: [PATCH 69/86] (fix/widget) centered the toolkit msg --- extensions/react-widget/publish.sh | 102 ++++++++++++------ .../react-widget/src/components/SearchBar.tsx | 10 +- 2 files changed, 80 insertions(+), 32 deletions(-) diff --git a/extensions/react-widget/publish.sh b/extensions/react-widget/publish.sh index c4545d85..129c4bcf 100755 --- a/extensions/react-widget/publish.sh +++ b/extensions/react-widget/publish.sh @@ -1,43 +1,85 @@ #!/bin/bash -## chmod +x publish.sh - to upgrade ownership set -e -cat package.json >> package_copy.json -cat package-lock.json >> package-lock_copy.json + +# Create backup of original files +cp package.json package_original.json +cp package-lock.json package-lock_original.json + +# Store the latest version after publishing +LATEST_VERSION="" + publish_package() { - PACKAGE_NAME=$1 - BUILD_COMMAND=$2 - # Update package name in package.json - jq --arg name "$PACKAGE_NAME" '.name=$name' package.json > temp.json && mv temp.json package.json + PACKAGE_NAME=$1 + BUILD_COMMAND=$2 + IS_REACT=$3 - # Remove 'target' key if the package name is 'docsgpt-react' - if [ "$PACKAGE_NAME" = "docsgpt-react" ]; then - jq 'del(.targets)' package.json > temp.json && mv temp.json package.json - fi + echo "Preparing to publish ${PACKAGE_NAME}..." + + # Restore original package.json state before each publish + cp package_original.json package.json + cp package-lock_original.json package-lock.json - if [ -d "dist" ]; then - echo "Deleting existing dist directory..." - rm -rf dist - fi + # Update package name in package.json + jq --arg name "$PACKAGE_NAME" '.name=$name' package.json > temp.json && mv temp.json package.json - npm version patch + # Handle targets based on package type + if [ "$IS_REACT" = "true" ]; then + echo "Removing targets for React library build..." + jq 'del(.targets)' package.json > temp.json && mv temp.json package.json + fi - npm run "$BUILD_COMMAND" + # Clean dist directory + if [ -d "dist" ]; then + echo "Cleaning dist directory..." + rm -rf dist + fi - # Publish to npm - npm publish - # Clean up - mv package_copy.json package.json - mv package-lock_copy.json package-lock.json - echo "Published ${PACKAGE_NAME}" + # update version and store it + LATEST_VERSION=$(npm version patch) + echo "New version: ${LATEST_VERSION}" + + # Build package + npm run "$BUILD_COMMAND" + + # Replace npm publish with npm pack for testing + npm publish + + echo "Successfully packaged ${PACKAGE_NAME}" + + # Log the bundle size + TARBALL="${PACKAGE_NAME}-${LATEST_VERSION#v}.tgz" + if [ -f "$TARBALL" ]; then + BUNDLE_SIZE=$(du -h "$TARBALL" | cut -f1) + echo "Bundle size for ${PACKAGE_NAME}: ${BUNDLE_SIZE}" + else + echo "Error: ${TARBALL} not found." + exit 1 + fi } -# Publish docsgpt package -publish_package "docsgpt" "build" +# First publish docsgpt (HTML bundle) +publish_package "docsgpt" "build" "false" -# Publish docsgpt-react package -publish_package "docsgpt-react" "build:react" +# Then publish docsgpt-react (React library) +publish_package "docsgpt-react" "build:react" "true" +# Restore original state but keep the updated version +cp package_original.json package.json +cp package-lock_original.json package-lock.json -rm -rf package_copy.json -rm -rf package-lock_copy.json -echo "---Process completed---" \ No newline at end of file +# Update the version in the final package.json +jq --arg version "${LATEST_VERSION#v}" '.version=$version' package.json > temp.json && mv temp.json package.json + +# Run npm install to update package-lock.json with the new version +npm install --package-lock-only + +# Cleanup backup files +rm -f package_original.json +rm -f package-lock_original.json +rm -f temp.json + +echo "---Process completed---" +echo "Final version in package.json: $(jq -r '.version' package.json)" +echo "Final version in package-lock.json: $(jq -r '.version' package-lock.json)" +echo "Generated test packages:" +ls *.tgz diff --git a/extensions/react-widget/src/components/SearchBar.tsx b/extensions/react-widget/src/components/SearchBar.tsx index c7344e43..c647991f 100644 --- a/extensions/react-widget/src/components/SearchBar.tsx +++ b/extensions/react-widget/src/components/SearchBar.tsx @@ -242,14 +242,20 @@ white-space: pre-wrap; const Toolkit = styled.kbd` position: absolute; right: 4px; - top: 4px; + top: 50%; + transform: translateY(-50%); background-color: ${(props) => props.theme.primary.bg}; color: ${(props) => props.theme.secondary.text}; font-weight: 600; font-size: 10px; - padding: 3px; + padding: 3px 6px; border: 1px solid ${(props) => props.theme.secondary.text}; border-radius: 4px; + display: flex; + align-items: center; + justify-content: center; + z-index: 1; + pointer-events: none; ` const Loader = styled.div` margin: 2rem auto; From 838525b452b3d766eee69c35595c309ce02241c0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Jan 2025 20:06:18 +0000 Subject: [PATCH 70/86] build(deps): bump tqdm from 4.66.5 to 4.67.1 in /application Bumps [tqdm](https://github.com/tqdm/tqdm) from 4.66.5 to 4.67.1. - [Release notes](https://github.com/tqdm/tqdm/releases) - [Commits](https://github.com/tqdm/tqdm/compare/v4.66.5...v4.67.1) --- updated-dependencies: - dependency-name: tqdm dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- application/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/requirements.txt b/application/requirements.txt index a54e0ddd..41d742eb 100644 --- a/application/requirements.txt +++ b/application/requirements.txt @@ -77,7 +77,7 @@ sentence-transformers==3.3.1 tiktoken==0.8.0 tokenizers==0.21.0 torch==2.5.1 -tqdm==4.66.5 +tqdm==4.67.1 transformers==4.47.1 typing-extensions==4.12.2 typing-inspect==0.9.0 From e0912f0cf0e4c49a88a264633e061c487758a943 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Jan 2025 20:06:20 +0000 Subject: [PATCH 71/86] build(deps): bump openapi3-parser from 1.1.18 to 1.1.19 in /application Bumps [openapi3-parser](https://github.com/manchenkoff/openapi3-parser) from 1.1.18 to 1.1.19. - [Release notes](https://github.com/manchenkoff/openapi3-parser/releases) - [Commits](https://github.com/manchenkoff/openapi3-parser/compare/v1.1.18...v1.1.19) --- updated-dependencies: - dependency-name: openapi3-parser dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- application/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/requirements.txt b/application/requirements.txt index a54e0ddd..5d6451cd 100644 --- a/application/requirements.txt +++ b/application/requirements.txt @@ -46,7 +46,7 @@ numpy==2.2.1 openai==1.59.5 openapi-schema-validator==0.6.2 openapi-spec-validator==0.6.0 -openapi3-parser==1.1.18 +openapi3-parser==1.1.19 orjson==3.10.14 packaging==24.1 pandas==2.2.3 From 1438fea76bd74f17ae94ddb47d8f75f8ec2e3231 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Jan 2025 20:06:27 +0000 Subject: [PATCH 72/86] build(deps): bump elastic-transport in /application Bumps [elastic-transport](https://github.com/elastic/elastic-transport-python) from 8.15.1 to 8.17.0. - [Release notes](https://github.com/elastic/elastic-transport-python/releases) - [Changelog](https://github.com/elastic/elastic-transport-python/blob/v8.17.0/CHANGELOG.md) - [Commits](https://github.com/elastic/elastic-transport-python/compare/v8.15.1...v8.17.0) --- updated-dependencies: - dependency-name: elastic-transport dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- application/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/requirements.txt b/application/requirements.txt index a54e0ddd..d750b9aa 100644 --- a/application/requirements.txt +++ b/application/requirements.txt @@ -6,7 +6,7 @@ dataclasses-json==0.6.7 docx2txt==0.8 duckduckgo-search==6.3.0 ebooklib==0.18 -elastic-transport==8.15.1 +elastic-transport==8.17.0 elasticsearch==8.17.0 escodegen==1.0.11 esprima==4.0.1 From 7369b02bf40bd4661ff41e19c53a1e113b012d72 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Jan 2025 20:06:32 +0000 Subject: [PATCH 73/86] build(deps): bump langsmith from 0.2.6 to 0.2.10 in /application Bumps [langsmith](https://github.com/langchain-ai/langsmith-sdk) from 0.2.6 to 0.2.10. - [Release notes](https://github.com/langchain-ai/langsmith-sdk/releases) - [Commits](https://github.com/langchain-ai/langsmith-sdk/compare/v0.2.6...v0.2.10) --- updated-dependencies: - dependency-name: langsmith dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- application/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/requirements.txt b/application/requirements.txt index a54e0ddd..499d6251 100644 --- a/application/requirements.txt +++ b/application/requirements.txt @@ -33,7 +33,7 @@ langchain-community==0.3.14 langchain-core==0.3.29 langchain-openai==0.3.0 langchain-text-splitters==0.3.5 -langsmith==0.2.6 +langsmith==0.2.10 lazy-object-proxy==1.10.0 lxml==5.3.0 markupsafe==3.0.2 From 5aea46c214cc584c300f947dfcdea13db1e87854 Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Tue, 14 Jan 2025 15:49:01 +0530 Subject: [PATCH 74/86] (feat:settings) locale lang for analytics and logs --- frontend/src/locale/en.json | 22 ++++++++++- frontend/src/settings/Analytics.tsx | 57 ++++++++++++++++++----------- frontend/src/settings/Logs.tsx | 14 ++++--- 3 files changed, 65 insertions(+), 28 deletions(-) diff --git a/frontend/src/locale/en.json b/frontend/src/locale/en.json index c6ae8023..7be4b568 100644 --- a/frontend/src/locale/en.json +++ b/frontend/src/locale/en.json @@ -69,10 +69,28 @@ "noData": "No existing Chatbots" }, "analytics": { - "label": "Analytics" + "label": "Analytics", + "filterByChatbot": "Filter by chatbot", + "selectChatbot": "Select chatbot", + "filterOptions": { + "hour": "Hour", + "last24Hours": "24 Hours", + "last7Days": "7 Days", + "last15Days": "15 Days", + "last30Days": "30 Days" + }, + "messages": "Messages", + "tokenUsage": "Token Usage", + "feedback": "Feedback", + "filterPlaceholder": "Filter", + "none": "None" }, "logs": { - "label": "Logs" + "label": "Logs", + "filterByChatbot": "Filter by chatbot", + "selectChatbot": "Select chatbot", + "none": "None", + "tableHeader": "API generated / chatbot conversations" }, "tools": { "label": "Tools" diff --git a/frontend/src/settings/Analytics.tsx b/frontend/src/settings/Analytics.tsx index 8baad361..8f3c45bb 100644 --- a/frontend/src/settings/Analytics.tsx +++ b/frontend/src/settings/Analytics.tsx @@ -1,4 +1,5 @@ import React, { useState, useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; import { BarElement, CategoryScale, @@ -28,15 +29,29 @@ ChartJS.register( Legend, ); -const filterOptions = [ - { label: 'Hour', value: 'last_hour' }, - { label: '24 Hours', value: 'last_24_hour' }, - { label: '7 Days', value: 'last_7_days' }, - { label: '15 Days', value: 'last_15_days' }, - { label: '30 Days', value: 'last_30_days' }, -]; - export default function Analytics() { + const { t } = useTranslation(); + + const filterOptions = [ + { label: t('settings.analytics.filterOptions.hour'), value: 'last_hour' }, + { + label: t('settings.analytics.filterOptions.last24Hours'), + value: 'last_24_hour', + }, + { + label: t('settings.analytics.filterOptions.last7Days'), + value: 'last_7_days', + }, + { + label: t('settings.analytics.filterOptions.last15Days'), + value: 'last_15_days', + }, + { + label: t('settings.analytics.filterOptions.last30Days'), + value: 'last_30_days', + }, + ]; + const [messagesData, setMessagesData] = useState

- Filter by chatbot + {t('settings.analytics.filterByChatbot')}

{ setSelectedChatbot( chatbots.find((item) => item.id === chatbot.value), @@ -199,12 +214,12 @@ export default function Analytics() {

- Messages + {t('settings.analytics.messages')}

- Token Usage + {t('settings.analytics.tokenUsage')}

- Feedback + {t('settings.analytics.feedback')}

item.positive, ), backgroundColor: '#7D54D1', }, { - label: 'Negative Feedback', + label: t('settings.analytics.negativeFeedback'), data: Object.values(feedbackData || {}).map( (item) => item.negative, ), diff --git a/frontend/src/settings/Logs.tsx b/frontend/src/settings/Logs.tsx index 1e248d46..df406122 100644 --- a/frontend/src/settings/Logs.tsx +++ b/frontend/src/settings/Logs.tsx @@ -1,4 +1,5 @@ import React, { useState, useEffect, useRef, useCallback } from 'react'; +import { useTranslation } from 'react-i18next'; import userService from '../api/services/userService'; import ChevronRight from '../assets/chevron-right.svg'; @@ -8,6 +9,7 @@ import { APIKeyData, LogData } from './types'; import CoppyButton from '../components/CopyButton'; export default function Logs() { + const { t } = useTranslation(); const [chatbots, setChatbots] = useState([]); const [selectedChatbot, setSelectedChatbot] = useState(); const [logs, setLogs] = useState([]); @@ -66,7 +68,7 @@ export default function Logs() {

- Filter by chatbot + {t('settings.logs.filterByChatbot')}

{loadingChatbots ? ( @@ -78,9 +80,9 @@ export default function Logs() { label: chatbot.name, value: chatbot.id, })), - { label: 'None', value: '' }, + { label: t('settings.logs.none'), value: '' }, ]} - placeholder="Select chatbot" + placeholder={t('settings.logs.selectChatbot')} onSelect={(chatbot: { label: string; value: string }) => { setSelectedChatbot( chatbots.find((item) => item.id === chatbot.value), @@ -120,6 +122,7 @@ type LogsTableProps = { }; function LogsTable({ logs, setPage }: LogsTableProps) { + const { t } = useTranslation(); const observerRef = useRef(); const firstObserver = useCallback((node: HTMLDivElement) => { if (observerRef.current) { @@ -134,7 +137,7 @@ function LogsTable({ logs, setPage }: LogsTableProps) {

- API generated / chatbot conversations + {t('settings.logs.tableHeader')}

chevron-right From cbcb717aee2e05ff37a49bbe08233e52da5d4324 Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Tue, 14 Jan 2025 16:52:35 +0530 Subject: [PATCH 75/86] (feat:locals) sync with en.json --- frontend/src/locale/es.json | 27 ++- frontend/src/locale/jp.json | 27 ++- frontend/src/locale/ru.json | 295 +++++++++++++++------------- frontend/src/locale/zh-TW.json | 29 ++- frontend/src/locale/zh.json | 27 ++- frontend/src/settings/Documents.tsx | 2 +- 6 files changed, 256 insertions(+), 151 deletions(-) diff --git a/frontend/src/locale/es.json b/frontend/src/locale/es.json index 79aa1b3b..d2c087db 100644 --- a/frontend/src/locale/es.json +++ b/frontend/src/locale/es.json @@ -69,10 +69,31 @@ "noData": "No hay chatbots existentes" }, "analytics": { - "label": "Analítica" + "label": "Analítica", + "filterByChatbot": "Filtrar por chatbot", + "selectChatbot": "Seleccionar chatbot", + "filterOptions": { + "hour": "Hora", + "last24Hours": "24 Horas", + "last7Days": "7 Días", + "last15Days": "15 Días", + "last30Days": "30 Días" + }, + "messages": "Mensajes", + "tokenUsage": "Uso de Tokens", + "feedback": "Retroalimentación", + "filterPlaceholder": "Filtrar", + "none": "Ninguno" }, "logs": { - "label": "Registros" + "label": "Registros", + "filterByChatbot": "Filtrar por chatbot", + "selectChatbot": "Seleccionar chatbot", + "none": "Ninguno", + "tableHeader": "Conversaciones generadas por API / chatbot" + }, + "tools": { + "label": "Herramientas" } }, "modals": { @@ -128,7 +149,7 @@ "label": "Crear una página pública para compartir", "note": "El documento original, la información personal y las conversaciones posteriores permanecerán privadas", "create": "Crear", - "option": "Permitir a los usuarios realizar más consultas." + "option": "Permitir a los usuarios realizar más consultas" } }, "sharedConv": { diff --git a/frontend/src/locale/jp.json b/frontend/src/locale/jp.json index 5f572ea4..71aa1e15 100644 --- a/frontend/src/locale/jp.json +++ b/frontend/src/locale/jp.json @@ -69,10 +69,31 @@ "noData": "既存のチャットボットはありません" }, "analytics": { - "label": "分析" + "label": "分析", + "filterByChatbot": "チャットボットでフィルター", + "selectChatbot": "チャットボットを選択", + "filterOptions": { + "hour": "時間", + "last24Hours": "24時間", + "last7Days": "7日間", + "last15Days": "15日間", + "last30Days": "30日間" + }, + "messages": "メッセージ", + "tokenUsage": "トークン使用量", + "feedback": "フィードバック", + "filterPlaceholder": "フィルター", + "none": "なし" }, "logs": { - "label": "ログ" + "label": "ログ", + "filterByChatbot": "チャットボットでフィルター", + "selectChatbot": "チャットボットを選択", + "none": "なし", + "tableHeader": "API生成/チャットボットの会話" + }, + "tools": { + "label": "ツール" } }, "modals": { @@ -86,7 +107,7 @@ "start": "チャットを開始する", "name": "名前", "choose": "ファイルを選択", - "info": ".pdf, .txt, .rst, .docx, .md, .json, .pptx, .zipファイルを25MBまでアップロードしてください", + "info": "25MBまでの.pdf, .txt, .rst, .csv, .xlsx, .docx, .md, .html, .epub, .json, .pptx, .zipファイルをアップロードしてください", "uploadedFiles": "アップロードされたファイル", "cancel": "キャンセル", "train": "トレーニング", diff --git a/frontend/src/locale/ru.json b/frontend/src/locale/ru.json index d23092a1..c5e3deb8 100644 --- a/frontend/src/locale/ru.json +++ b/frontend/src/locale/ru.json @@ -1,142 +1,163 @@ { - "language": "Русский", - "chat": "Чат", - "chats": "Чаты", - "newChat": "Новый чат", - "myPlan": "Мой план", - "about": "О", - "inputPlaceholder": "Введите свое сообщение здесь...", - "tagline": "DocsGPT использует GenAI, пожалуйста, проверьте важную информацию, используя источники.", - "sourceDocs": "Источник", - "none": "Нет", - "cancel": "Отмена", - "demo": [ - { - "header": "Узнайте о DocsGPT", - "query": "Что такое DocsGPT?" - }, - { - "header": "Обобщить документацию", - "query": "Обобщить текущий контекст" - }, - { - "header": "Написать код", - "query": "Написать код для запроса API к /api/answer" - }, - { - "header": "Помощь в обучении", - "query": "Написать потенциальные вопросы для контекста" - } - ], - "settings": { - "label": "Настройки", - "general": { - "label": "Общие", - "selectTheme": "Выбрать тему", - "light": "Светлая", - "dark": "Темная", - "selectLanguage": "Выбрать язык", - "chunks": "Обработанные фрагменты на запрос", - "prompt": "Активная подсказка", - "deleteAllLabel": "Удалить все беседы", - "deleteAllBtn": "Удалить все", - "addNew": "Добавить новый", - "convHistory": "История разговоров", - "none": "Нет", - "low": "Низкий", - "medium": "Средний", - "high": "Высокий", - "unlimited": "Без ограничений", - "default": "по умолчанию" - }, - "documents": { - "label": "Документы", - "name": "Название документа", - "date": "Дата вектора", - "type": "Тип", - "tokenUsage": "Использование токена", - "noData": "Нет существующих документов" - }, - "apiKeys": { - "label": "Чат-боты", - "name": "Название", - "key": "Ключ API", - "sourceDoc": "Исходный документ", - "createNew": "Создать новый", - "noData": "Нет существующих чат-ботов" - }, - "analytics": { - "label": "Analytics" - }, - "logs": { - "label": "Журналы" - } + "language": "Русский", + "chat": "Чат", + "chats": "Чаты", + "newChat": "Новый чат", + "myPlan": "Мой план", + "about": "О", + "inputPlaceholder": "Введите свое сообщение здесь...", + "tagline": "DocsGPT использует GenAI, пожалуйста, проверьте важную информацию, используя источники.", + "sourceDocs": "Источник", + "none": "Нет", + "cancel": "Отмена", + "demo": [ + { + "header": "Узнайте о DocsGPT", + "query": "Что такое DocsGPT?" }, - "modals": { - "uploadDoc": { - "label": "Загрузить новую документацию", - "select": "Выберите способ загрузки документа в DocsGPT", - "file": "Загрузить с устройства", - "back": "Назад", - "wait": "Пожалуйста, подождите ...", - "remote": "Собрать с веб-сайта", - "start": "Начать чат", - "name": "Имя", - "choose": "Выбрать файлы", - "info": "Загрузите .pdf, .txt, .rst, .csv, .xlsx, .docx, .md, .zip с ограничением до 25 МБ", - "uploadedFiles": "Загруженные файлы", - "cancel": "Отмена", - "train": "Обучение", - "link": "Ссылка", - "urlLink": "URL-ссылка", - "repoUrl": "URL-адрес репозитория", - "reddit": { - "id": "ID клиента", - "secret": "Секрет клиента", - "agent": "Агент пользователя", - "searchQueries": "Поисковые запросы", - "numberOfPosts": "Количество сообщений" - }, - "drag": { - "title": "Загрузите исходный файл", - "description": "Перетащите сюда свой файл, чтобы добавить его в качестве источника." - } - }, - "createAPIKey": { - "label": "Создать новый ключ API", - "apiKeyName": "Имя ключа API", - "chunks": "Обработано фрагментов на запрос", - "prompt": "Выбрать активный запрос", - "sourceDoc": "Исходный документ", - "create": "Создать" - }, - "saveKey": { - "note": "Пожалуйста, сохраните свой ключ", - "disclaimer": "Это единственный раз, когда будет показан ваш ключ.", - "copy": "Копировать", - "copied": "Скопировано", - "confirm": "Я сохранил ключ" - }, - "deleteConv": { - "confirm": "Вы уверены, что хотите удалить все разговоры?", - "delete": "Удалить" - }, - "shareConv": { - "label": "Создать публичную страницу для общего доступа", - "note": "Исходный документ, личная информация и дальнейший разговор останутся конфиденциальными", - "create": "Создать", - "option": "Разрешить пользователям запрашивать дальнейшие действия" - } + { + "header": "Обобщить документацию", + "query": "Обобщить текущий контекст" }, - "sharedConv": { - "subtitle": "Создано с помощью", - "button": "Начать работу с DocsGPT", - "meta": "DocsGPT использует GenAI, пожалуйста, проверьте важную информацию с помощью источников." + { + "header": "Написать код", + "query": "Написать код для запроса API к /api/answer" }, - "convTile": { - "share": "Поделиться", - "delete": "Удалить", - "rename": "Переименовать", - "deleteWarning": "Вы уверены, что хотите удалить этот разговор?" + { + "header": "Помощь в обучении", + "query": "Написать потенциальные вопросы для контекста" } -} \ No newline at end of file + ], + "settings": { + "label": "Настройки", + "general": { + "label": "Общие", + "selectTheme": "Выбрать тему", + "light": "Светлая", + "dark": "Темная", + "selectLanguage": "Выбрать язык", + "chunks": "Обработанные фрагменты на запрос", + "prompt": "Активная подсказка", + "deleteAllLabel": "Удалить все беседы", + "deleteAllBtn": "Удалить все", + "addNew": "Добавить новый", + "convHistory": "История разговоров", + "none": "Нет", + "low": "Низкий", + "medium": "Средний", + "high": "Высокий", + "unlimited": "Без ограничений", + "default": "по умолчанию" + }, + "documents": { + "label": "Документы", + "name": "Название документа", + "date": "Дата вектора", + "type": "Тип", + "tokenUsage": "Использование токена", + "noData": "Нет существующих документов" + }, + "apiKeys": { + "label": "Чат-боты", + "name": "Название", + "key": "Ключ API", + "sourceDoc": "Исходный документ", + "createNew": "Создать новый", + "noData": "Нет существующих чат-ботов" + }, + "analytics": { + "label": "Аналитика", + "filterByChatbot": "Фильтровать по чат-боту", + "selectChatbot": "Выбрать чат-бота", + "filterOptions": { + "hour": "Час", + "last24Hours": "24 часа", + "last7Days": "7 дней", + "last15Days": "15 дней", + "last30Days": "30 дней" + }, + "messages": "Сообщения", + "tokenUsage": "Использование токенов", + "feedback": "Обратная связь", + "filterPlaceholder": "Фильтр", + "none": "Нет" + }, + "logs": { + "label": "Журналы", + "filterByChatbot": "Фильтровать по чат-боту", + "selectChatbot": "Выбрать чат-бота", + "none": "Нет", + "tableHeader": "Сгенерированные API / разговоры с чат-ботом" + }, + "tools": { + "label": "Инструменты" + } + }, + "modals": { + "uploadDoc": { + "label": "Загрузить новую документацию", + "select": "Выберите способ загрузки документа в DocsGPT", + "file": "Загрузить с устройства", + "back": "Назад", + "wait": "Пожалуйста, подождите ...", + "remote": "Собрать с веб-сайта", + "start": "Начать чат", + "name": "Имя", + "choose": "Выбрать файлы", + "info": "Загрузите .pdf, .txt, .rst, .csv, .xlsx, .docx, .md, .html, .epub, .json, .pptx, .zip с ограничением до 25 МБ", + "uploadedFiles": "Загруженные файлы", + "cancel": "Отмена", + "train": "Обучение", + "link": "Ссылка", + "urlLink": "URL-ссылка", + "repoUrl": "URL-адрес репозитория", + "reddit": { + "id": "ID клиента", + "secret": "Секрет клиента", + "agent": "Агент пользователя", + "searchQueries": "Поисковые запросы", + "numberOfPosts": "Количество постов" + }, + "drag": { + "title": "Загрузить исходный файл", + "description": "Перетащите файл сюда, чтобы добавить его как источник" + } + }, + "createAPIKey": { + "label": "Создать новый ключ API", + "apiKeyName": "Название ключа API", + "chunks": "Обработанные фрагменты на запрос", + "prompt": "Выбрать активный запрос", + "sourceDoc": "Исходный документ", + "create": "Создать" + }, + "saveKey": { + "note": "Пожалуйста, сохраните свой ключ", + "disclaimer": "Это единственный раз, когда будет показан ваш ключ", + "copy": "Копировать", + "copied": "Скопировано", + "confirm": "Я сохранил ключ" + }, + "deleteConv": { + "confirm": "Вы уверены, что хотите удалить все разговоры?", + "delete": "Удалить" + }, + "shareConv": { + "label": "Создать публичную страницу для общего доступа", + "note": "Исходный документ, личная информация и дальнейший разговор останутся конфиденциальными", + "create": "Создать", + "option": "Разрешить пользователям делать дополнительные запросы" + } + }, + "sharedConv": { + "subtitle": "Создано с помощью", + "button": "Начать работу с DocsGPT", + "meta": "DocsGPT использует GenAI, пожалуйста, проверяйте важную информацию, используя источники" + }, + "convTile": { + "share": "Поделиться", + "delete": "Удалить", + "rename": "Переименовать", + "deleteWarning": "Вы уверены, что хотите удалить этот разговор?" + } +} diff --git a/frontend/src/locale/zh-TW.json b/frontend/src/locale/zh-TW.json index d5f633d2..5e97d883 100644 --- a/frontend/src/locale/zh-TW.json +++ b/frontend/src/locale/zh-TW.json @@ -10,8 +10,8 @@ "sourceDocs": "原始文件", "none": "無", "cancel": "取消", - "help": "聯繫支援", - "emailUs": "寄送電子郵件給我們", + "help": "幫助", + "emailUs": "給我們發電郵", "documentation": "文件", "demo": [ { @@ -67,10 +67,31 @@ "createNew": "新增" }, "analytics": { - "label": "分析" + "label": "分析", + "filterByChatbot": "按聊天機器人篩選", + "selectChatbot": "選擇聊天機器人", + "filterOptions": { + "hour": "小時", + "last24Hours": "24 小時", + "last7Days": "7 天", + "last15Days": "15 天", + "last30Days": "30 天" + }, + "messages": "訊息", + "tokenUsage": "Token 使用量", + "feedback": "回饋", + "filterPlaceholder": "篩選", + "none": "無" }, "logs": { - "label": "日誌" + "label": "日誌", + "filterByChatbot": "按聊天機器人篩選", + "selectChatbot": "選擇聊天機器人", + "none": "無", + "tableHeader": "API 生成 / 聊天機器人會話" + }, + "tools": { + "label": "工具" } }, "modals": { diff --git a/frontend/src/locale/zh.json b/frontend/src/locale/zh.json index 1a0d1f94..afa15f7b 100644 --- a/frontend/src/locale/zh.json +++ b/frontend/src/locale/zh.json @@ -10,7 +10,7 @@ "sourceDocs": "源", "none": "无", "cancel": "取消", - "help": "联系支持", + "help": "帮助", "emailUs": "给我们发邮件", "documentation": "文档", "demo": [ @@ -69,10 +69,31 @@ "noData": "没有现有的聊天机器人" }, "analytics": { - "label": "分析" + "label": "分析", + "filterByChatbot": "按聊天机器人筛选", + "selectChatbot": "选择聊天机器人", + "filterOptions": { + "hour": "小时", + "last24Hours": "24 小时", + "last7Days": "7 天", + "last15Days": "15 天", + "last30Days": "30 天" + }, + "messages": "消息", + "tokenUsage": "令牌使用", + "feedback": "反馈", + "filterPlaceholder": "筛选", + "none": "无" }, "logs": { - "label": "日志" + "label": "日志", + "filterByChatbot": "按聊天机器人筛选", + "selectChatbot": "选择聊天机器人", + "none": "无", + "tableHeader": "API 生成 / 聊天机器人会话" + }, + "tools": { + "label": "工具" } }, "modals": { diff --git a/frontend/src/settings/Documents.tsx b/frontend/src/settings/Documents.tsx index 8e68f226..52a63351 100644 --- a/frontend/src/settings/Documents.tsx +++ b/frontend/src/settings/Documents.tsx @@ -181,7 +181,7 @@ const Documents: React.FC = ({ {loading ? ( ) : ( -
+
{t('settings.apiKeys.name')} + + {t('settings.apiKeys.name')} + {t('settings.apiKeys.sourceDoc')} {t('settings.apiKeys.key')} + {t('settings.apiKeys.key')} +
Delete handleDeleteKey(element.id)} diff --git a/frontend/src/settings/Analytics.tsx b/frontend/src/settings/Analytics.tsx index 8baad361..ccb5ffcb 100644 --- a/frontend/src/settings/Analytics.tsx +++ b/frontend/src/settings/Analytics.tsx @@ -164,7 +164,7 @@ export default function Analytics() {
-

+

Filter by chatbot

diff --git a/frontend/src/settings/General.tsx b/frontend/src/settings/General.tsx index 227b0a6e..216ec1e0 100644 --- a/frontend/src/settings/General.tsx +++ b/frontend/src/settings/General.tsx @@ -81,9 +81,9 @@ export default function General() { return (
-

+

+
-

+

+ @@ -115,9 +115,9 @@ export default function General() { />
-

+

+
-

+

+ ({ value: value, @@ -163,16 +163,14 @@ export default function General() { />
-

+

+
diff --git a/frontend/src/settings/Prompts.tsx b/frontend/src/settings/Prompts.tsx index 6e1810e5..611b0b90 100644 --- a/frontend/src/settings/Prompts.tsx +++ b/frontend/src/settings/Prompts.tsx @@ -168,7 +168,7 @@ export default function Prompts({ />
- {' '} + {t('settings.documents.actions')}
From 9e6f970bc400bcec3d8ffb191c6d90927f982920 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Jan 2025 20:35:08 +0000 Subject: [PATCH 76/86] build(deps): bump flask from 3.0.3 to 3.1.0 in /application Bumps [flask](https://github.com/pallets/flask) from 3.0.3 to 3.1.0. - [Release notes](https://github.com/pallets/flask/releases) - [Changelog](https://github.com/pallets/flask/blob/main/CHANGES.rst) - [Commits](https://github.com/pallets/flask/compare/3.0.3...3.1.0) --- updated-dependencies: - dependency-name: flask dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- application/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/requirements.txt b/application/requirements.txt index df50d9d6..e2b3c129 100644 --- a/application/requirements.txt +++ b/application/requirements.txt @@ -11,7 +11,7 @@ elasticsearch==8.17.0 escodegen==1.0.11 esprima==4.0.1 esutils==1.0.1 -Flask==3.0.3 +Flask==3.1.0 faiss-cpu==1.9.0.post1 flask-restx==1.3.0 gTTS==2.5.4 From 850b79f459e8c722562bbce8474619f9ca224360 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Jan 2025 20:35:19 +0000 Subject: [PATCH 77/86] build(deps): bump transformers from 4.47.1 to 4.48.0 in /application Bumps [transformers](https://github.com/huggingface/transformers) from 4.47.1 to 4.48.0. - [Release notes](https://github.com/huggingface/transformers/releases) - [Commits](https://github.com/huggingface/transformers/compare/v4.47.1...v4.48.0) --- updated-dependencies: - dependency-name: transformers dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- application/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/requirements.txt b/application/requirements.txt index df50d9d6..5b1a1404 100644 --- a/application/requirements.txt +++ b/application/requirements.txt @@ -78,7 +78,7 @@ tiktoken==0.8.0 tokenizers==0.21.0 torch==2.5.1 tqdm==4.67.1 -transformers==4.47.1 +transformers==4.48.0 typing-extensions==4.12.2 typing-inspect==0.9.0 tzdata==2024.2 From 13fcbe3e74dad4b6f2b37bc093f022d941be9d0b Mon Sep 17 00:00:00 2001 From: Pavel Date: Wed, 15 Jan 2025 01:08:09 +0300 Subject: [PATCH 78/86] scraper with markdownify --- application/api/user/routes.py | 2 +- application/parser/remote/crawler_loader.py | 41 +++--- application/parser/remote/crawler_markdown.py | 139 ++++++++++++++++++ application/requirements.txt | 4 +- application/worker.py | 82 ++++++----- 5 files changed, 211 insertions(+), 57 deletions(-) create mode 100644 application/parser/remote/crawler_markdown.py diff --git a/application/api/user/routes.py b/application/api/user/routes.py index 4bcbd719..e516bb71 100644 --- a/application/api/user/routes.py +++ b/application/api/user/routes.py @@ -2105,4 +2105,4 @@ class DeleteTool(Resource): except Exception as err: return {"success": False, "error": str(err)}, 400 - return {"success": True}, 200 + return {"success": True}, 200 \ No newline at end of file diff --git a/application/parser/remote/crawler_loader.py b/application/parser/remote/crawler_loader.py index 76325ae6..c2da230b 100644 --- a/application/parser/remote/crawler_loader.py +++ b/application/parser/remote/crawler_loader.py @@ -2,16 +2,16 @@ import requests from urllib.parse import urlparse, urljoin from bs4 import BeautifulSoup from application.parser.remote.base import BaseRemote +from application.parser.schema.base import Document +from langchain_community.document_loaders import WebBaseLoader class CrawlerLoader(BaseRemote): def __init__(self, limit=10): - from langchain_community.document_loaders import WebBaseLoader self.loader = WebBaseLoader # Initialize the document loader self.limit = limit # Set the limit for the number of pages to scrape def load_data(self, inputs): url = inputs - # Check if the input is a list and if it is, use the first element if isinstance(url, list) and url: url = url[0] @@ -19,24 +19,29 @@ class CrawlerLoader(BaseRemote): if not urlparse(url).scheme: url = "http://" + url - visited_urls = set() # Keep track of URLs that have been visited - base_url = urlparse(url).scheme + "://" + urlparse(url).hostname # Extract the base URL - urls_to_visit = [url] # List of URLs to be visited, starting with the initial URL - loaded_content = [] # Store the loaded content from each URL + visited_urls = set() + base_url = urlparse(url).scheme + "://" + urlparse(url).hostname + urls_to_visit = [url] + loaded_content = [] - # Continue crawling until there are no more URLs to visit while urls_to_visit: - current_url = urls_to_visit.pop(0) # Get the next URL to visit - visited_urls.add(current_url) # Mark the URL as visited + current_url = urls_to_visit.pop(0) + visited_urls.add(current_url) - # Try to load and process the content from the current URL try: - response = requests.get(current_url) # Fetch the content of the current URL - response.raise_for_status() # Raise an exception for HTTP errors - loader = self.loader([current_url]) # Initialize the document loader for the current URL - loaded_content.extend(loader.load()) # Load the content and add it to the loaded_content list + response = requests.get(current_url) + response.raise_for_status() + loader = self.loader([current_url]) + docs = loader.load() + # Convert the loaded documents to your Document schema + for doc in docs: + loaded_content.append( + Document( + doc.page_content, + extra_info=doc.metadata + ) + ) except Exception as e: - # Print an error message if loading or processing fails and continue with the next URL print(f"Error processing URL {current_url}: {e}") continue @@ -45,15 +50,15 @@ class CrawlerLoader(BaseRemote): all_links = [ urljoin(current_url, a['href']) for a in soup.find_all('a', href=True) - if base_url in urljoin(current_url, a['href']) # Ensure links are from the same domain + if base_url in urljoin(current_url, a['href']) ] # Add new links to the list of URLs to visit if they haven't been visited yet urls_to_visit.extend([link for link in all_links if link not in visited_urls]) - urls_to_visit = list(set(urls_to_visit)) # Remove duplicate URLs + urls_to_visit = list(set(urls_to_visit)) # Stop crawling if the limit of pages to scrape is reached if self.limit is not None and len(visited_urls) >= self.limit: break - return loaded_content # Return the loaded content from all visited URLs + return loaded_content \ No newline at end of file diff --git a/application/parser/remote/crawler_markdown.py b/application/parser/remote/crawler_markdown.py new file mode 100644 index 00000000..3d199332 --- /dev/null +++ b/application/parser/remote/crawler_markdown.py @@ -0,0 +1,139 @@ +import requests +from urllib.parse import urlparse, urljoin +from bs4 import BeautifulSoup +from application.parser.remote.base import BaseRemote +import re +from markdownify import markdownify +from application.parser.schema.base import Document +import tldextract + +class CrawlerLoader(BaseRemote): + def __init__(self, limit=10, allow_subdomains=False): + """ + Given a URL crawl web pages up to `self.limit`, + convert HTML content to Markdown, and returning a list of Document objects. + + :param limit: The maximum number of pages to crawl. + :param allow_subdomains: If True, crawl pages on subdomains of the base domain. + """ + self.limit = limit + self.allow_subdomains = allow_subdomains + self.session = requests.Session() + + def load_data(self, inputs): + url = inputs + if isinstance(url, list) and url: + url = url[0] + + # Ensure the URL has a scheme (if not, default to http) + if not urlparse(url).scheme: + url = "http://" + url + + # Keep track of visited URLs to avoid revisiting the same page + visited_urls = set() + + # Determine the base domain for link filtering using tldextract + base_domain = self._get_base_domain(url) + urls_to_visit = {url} + documents = [] + + while urls_to_visit: + current_url = urls_to_visit.pop() + + # Skip if already visited + if current_url in visited_urls: + continue + visited_urls.add(current_url) + + # Fetch the page content + html_content = self._fetch_page(current_url) + if html_content is None: + continue + + # Convert the HTML to Markdown for cleaner text formatting + title, language, processed_markdown = self._process_html_to_markdown(html_content, current_url) + if processed_markdown: + # Create a Document for each visited page + documents.append( + Document( + processed_markdown, # content + None, # doc_id + None, # embedding + {"source": current_url, "title": title, "language": language} # extra_info + ) + ) + + # Extract links and filter them according to domain rules + new_links = self._extract_links(html_content, current_url) + filtered_links = self._filter_links(new_links, base_domain) + + # Add any new, not-yet-visited links to the queue + urls_to_visit.update(link for link in filtered_links if link not in visited_urls) + + # If we've reached the limit, stop crawling + if self.limit is not None and len(visited_urls) >= self.limit: + break + + return documents + + def _fetch_page(self, url): + try: + response = self.session.get(url, timeout=10) + response.raise_for_status() + return response.text + except requests.exceptions.RequestException as e: + print(f"Error fetching URL {url}: {e}") + return None + + def _process_html_to_markdown(self, html_content, current_url): + soup = BeautifulSoup(html_content, 'html.parser') + title_tag = soup.find('title') + title = title_tag.text.strip() if title_tag else "No Title" + + # Extract language + language_tag = soup.find('html') + language = language_tag.get('lang', 'en') if language_tag else "en" + + markdownified = markdownify(html_content, heading_style="ATX", newline_style="BACKSLASH") + # Reduce sequences of more than two newlines to exactly three + markdownified = re.sub(r'\n{3,}', '\n\n\n', markdownified) + return title, language, markdownified + + def _extract_links(self, html_content, current_url): + soup = BeautifulSoup(html_content, 'html.parser') + links = [] + for a in soup.find_all('a', href=True): + full_url = urljoin(current_url, a['href']) + links.append((full_url, a.text.strip())) + return links + + def _get_base_domain(self, url): + extracted = tldextract.extract(url) + # Reconstruct the domain as domain.suffix + base_domain = f"{extracted.domain}.{extracted.suffix}" + return base_domain + + def _filter_links(self, links, base_domain): + """ + Filter the extracted links to only include those that match the crawling criteria: + - If allow_subdomains is True, allow any link whose domain ends with the base_domain. + - If allow_subdomains is False, only allow exact matches of the base_domain. + """ + filtered = [] + for link, _ in links: + parsed_link = urlparse(link) + if not parsed_link.netloc: + continue + + extracted = tldextract.extract(parsed_link.netloc) + link_base = f"{extracted.domain}.{extracted.suffix}" + + if self.allow_subdomains: + # For subdomains: sub.example.com ends with example.com + if link_base == base_domain or link_base.endswith("." + base_domain): + filtered.append(link) + else: + # Exact domain match + if link_base == base_domain: + filtered.append(link) + return filtered \ No newline at end of file diff --git a/application/requirements.txt b/application/requirements.txt index ca8ba68f..7b756ed3 100644 --- a/application/requirements.txt +++ b/application/requirements.txt @@ -86,4 +86,6 @@ urllib3==2.3.0 vine==5.1.0 wcwidth==0.2.13 werkzeug==3.1.3 -yarl==1.18.3 \ No newline at end of file +yarl==1.18.3 +markdownify==0.14.1 +tldextract==5.1.3 \ No newline at end of file diff --git a/application/worker.py b/application/worker.py index f4f181e5..df0bbe7d 100755 --- a/application/worker.py +++ b/application/worker.py @@ -203,53 +203,61 @@ def remote_worker( sync_frequency="never", operation_mode="upload", doc_id=None, -): +): full_path = os.path.join(directory, user, name_job) - if not os.path.exists(full_path): os.makedirs(full_path) + self.update_state(state="PROGRESS", meta={"current": 1}) - logging.info( - f"Remote job: {full_path}", - extra={"user": user, "job": name_job, "source_data": source_data}, - ) + try: + logging.info("Initializing remote loader with type: %s", loader) + remote_loader = RemoteCreator.create_loader(loader) + raw_docs = remote_loader.load_data(source_data) - remote_loader = RemoteCreator.create_loader(loader) - raw_docs = remote_loader.load_data(source_data) + chunker = Chunker( + chunking_strategy="classic_chunk", + max_tokens=MAX_TOKENS, + min_tokens=MIN_TOKENS, + duplicate_headers=False + ) + docs = chunker.chunk(documents=raw_docs) + docs = [Document.to_langchain_format(raw_doc) for raw_doc in raw_docs] + tokens = count_tokens_docs(docs) + logging.info("Total tokens calculated: %d", tokens) - chunker = Chunker( - chunking_strategy="classic_chunk", - max_tokens=MAX_TOKENS, - min_tokens=MIN_TOKENS, - duplicate_headers=False - ) - docs = chunker.chunk(documents=raw_docs) + if operation_mode == "upload": + id = ObjectId() + embed_and_store_documents(docs, full_path, id, self) + elif operation_mode == "sync": + if not doc_id or not ObjectId.is_valid(doc_id): + logging.error("Invalid doc_id provided for sync operation: %s", doc_id) + raise ValueError("doc_id must be provided for sync operation.") + id = ObjectId(doc_id) + embed_and_store_documents(docs, full_path, id, self) - tokens = count_tokens_docs(docs) - if operation_mode == "upload": - id = ObjectId() - embed_and_store_documents(docs, full_path, id, self) - elif operation_mode == "sync": - if not doc_id or not ObjectId.is_valid(doc_id): - raise ValueError("doc_id must be provided for sync operation.") - id = ObjectId(doc_id) - embed_and_store_documents(docs, full_path, id, self) - self.update_state(state="PROGRESS", meta={"current": 100}) + self.update_state(state="PROGRESS", meta={"current": 100}) - file_data = { - "name": name_job, - "user": user, - "tokens": tokens, - "retriever": retriever, - "id": str(id), - "type": loader, - "remote_data": source_data, - "sync_frequency": sync_frequency, - } - upload_index(full_path, file_data) + file_data = { + "name": name_job, + "user": user, + "tokens": tokens, + "retriever": retriever, + "id": str(id), + "type": loader, + "remote_data": source_data, + "sync_frequency": sync_frequency, + } + upload_index(full_path, file_data) - shutil.rmtree(full_path) + except Exception as e: + logging.error("Error in remote_worker task: %s", str(e), exc_info=True) + raise + finally: + if os.path.exists(full_path): + shutil.rmtree(full_path) + + logging.info("remote_worker task completed successfully") return {"urls": source_data, "name_job": name_job, "user": user, "limited": False} def sync( From cab6305462db0aca429fa16fb4d66975b96c4d13 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 Jan 2025 20:59:45 +0000 Subject: [PATCH 79/86] build(deps): bump primp from 0.9.3 to 0.10.0 in /application Bumps [primp](https://github.com/deedy5/primp) from 0.9.3 to 0.10.0. - [Release notes](https://github.com/deedy5/primp/releases) - [Commits](https://github.com/deedy5/primp/compare/v0.9.3...v0.10.0) --- updated-dependencies: - dependency-name: primp dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- application/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/requirements.txt b/application/requirements.txt index 0ad92e27..3fc6d02d 100644 --- a/application/requirements.txt +++ b/application/requirements.txt @@ -55,7 +55,7 @@ pathable==0.4.4 pillow==11.1.0 portalocker==2.10.1 prance==23.6.21.0 -primp==0.9.3 +primp==0.10.0 prompt-toolkit==3.0.48 protobuf==5.29.3 py==1.11.0 From cc78ea7222cc6325508df6fce00e4b2b652bd1d2 Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Thu, 16 Jan 2025 18:24:27 +0530 Subject: [PATCH 80/86] (fix:locales) sync static text --- .../src/components/DocumentPagination.tsx | 16 ++- frontend/src/locale/en.json | 37 +++++- frontend/src/locale/es.json | 20 ++- frontend/src/locale/jp.json | 53 ++++++-- frontend/src/locale/ru.json | 96 +++++++++----- frontend/src/locale/zh-TW.json | 55 ++++++-- frontend/src/locale/zh.json | 37 +++++- frontend/src/modals/ConfigToolModal.tsx | 15 ++- .../src/modals/ShareConversationModal.tsx | 16 ++- frontend/src/preferences/PromptsModal.tsx | 39 +++--- frontend/src/settings/Analytics.tsx | 15 ++- frontend/src/settings/General.tsx | 17 ++- frontend/src/settings/Tools.tsx | 12 +- frontend/src/upload/Upload.tsx | 118 ++++++++---------- 14 files changed, 383 insertions(+), 163 deletions(-) diff --git a/frontend/src/components/DocumentPagination.tsx b/frontend/src/components/DocumentPagination.tsx index f02ef1c0..6958d051 100644 --- a/frontend/src/components/DocumentPagination.tsx +++ b/frontend/src/components/DocumentPagination.tsx @@ -1,4 +1,5 @@ import React, { useState } from 'react'; +import { useTranslation } from 'react-i18next'; import SingleArrowLeft from '../assets/single-left-arrow.svg'; import SingleArrowRight from '../assets/single-right-arrow.svg'; import DoubleArrowLeft from '../assets/double-arrow-left.svg'; @@ -19,6 +20,7 @@ const Pagination: React.FC = ({ onPageChange, onRowsPerPageChange, }) => { + const { t } = useTranslation(); const [isDropdownOpen, setIsDropdownOpen] = useState(false); const rowsPerPageOptions = [5, 10, 20, 50]; @@ -53,7 +55,9 @@ const Pagination: React.FC = ({
{/* Rows per page dropdown */}
- Rows per page: + + {t('pagination.rowsPerPage')}: +
@@ -108,7 +112,7 @@ const Pagination: React.FC = ({ > Previous page @@ -119,7 +123,7 @@ const Pagination: React.FC = ({ > Next page @@ -130,7 +134,7 @@ const Pagination: React.FC = ({ > Last page diff --git a/frontend/src/locale/en.json b/frontend/src/locale/en.json index 7be4b568..2f21445b 100644 --- a/frontend/src/locale/en.json +++ b/frontend/src/locale/en.json @@ -83,7 +83,9 @@ "tokenUsage": "Token Usage", "feedback": "Feedback", "filterPlaceholder": "Filter", - "none": "None" + "none": "None", + "positiveFeedback": "Positive Feedback", + "negativeFeedback": "Negative Feedback" }, "logs": { "label": "Logs", @@ -93,7 +95,12 @@ "tableHeader": "API generated / chatbot conversations" }, "tools": { - "label": "Tools" + "label": "Tools", + "searchPlaceholder": "Search...", + "addTool": "Add Tool", + "noToolsAlt": "No tools found", + "noToolsFound": "No tools found", + "selectToolSetup": "Select a tool to set up" } }, "modals": { @@ -150,6 +157,24 @@ "note": "Source document, personal information and further conversation will remain private", "create": "Create", "option": "Allow users to prompt further" + }, + "configTool": { + "title": "Tool Config", + "type": "Type", + "apiKeyLabel": "API Key / OAuth", + "apiKeyPlaceholder": "Enter API Key / OAuth", + "addButton": "Add Tool", + "closeButton": "Close" + }, + "prompts": { + "addPrompt": "Add Prompt", + "addDescription": "Add your custom prompt and save it to DocsGPT", + "editPrompt": "Edit Prompt", + "editDescription": "Edit your custom prompt and save it to DocsGPT", + "promptName": "Prompt Name", + "promptText": "Prompt Text", + "save": "Save", + "nameExists": "Name already exists" } }, "sharedConv": { @@ -162,5 +187,13 @@ "delete": "Delete", "rename": "Rename", "deleteWarning": "Are you sure you want to delete this conversation?" + }, + "pagination": { + "rowsPerPage": "Rows per page", + "pageOf": "Page {{currentPage}} of {{totalPages}}", + "firstPage": "First page", + "previousPage": "Previous page", + "nextPage": "Next page", + "lastPage": "Last page" } } diff --git a/frontend/src/locale/es.json b/frontend/src/locale/es.json index d2c087db..8d0a3273 100644 --- a/frontend/src/locale/es.json +++ b/frontend/src/locale/es.json @@ -83,7 +83,9 @@ "tokenUsage": "Uso de Tokens", "feedback": "Retroalimentación", "filterPlaceholder": "Filtrar", - "none": "Ninguno" + "none": "Ninguno", + "positiveFeedback": "Retroalimentación Positiva", + "negativeFeedback": "Retroalimentación Negativa" }, "logs": { "label": "Registros", @@ -150,6 +152,14 @@ "note": "El documento original, la información personal y las conversaciones posteriores permanecerán privadas", "create": "Crear", "option": "Permitir a los usuarios realizar más consultas" + }, + "configTool": { + "title": "Configuración de la Herramienta", + "type": "Tipo", + "apiKeyLabel": "Clave API / OAuth", + "apiKeyPlaceholder": "Ingrese la Clave API / OAuth", + "addButton": "Agregar Herramienta", + "closeButton": "Cerrar" } }, "sharedConv": { @@ -162,5 +172,13 @@ "delete": "Eliminar", "rename": "Renombrar", "deleteWarning": "¿Está seguro de que desea eliminar esta conversación?" + }, + "pagination": { + "rowsPerPage": "Filas por página", + "pageOf": "Página {{currentPage}} de {{totalPages}}", + "firstPage": "Primera página", + "previousPage": "Página anterior", + "nextPage": "Página siguiente", + "lastPage": "Última página" } } diff --git a/frontend/src/locale/jp.json b/frontend/src/locale/jp.json index 71aa1e15..e1e27503 100644 --- a/frontend/src/locale/jp.json +++ b/frontend/src/locale/jp.json @@ -58,15 +58,15 @@ "date": "ベクトル日付", "type": "タイプ", "tokenUsage": "トークン使用量", - "noData": "既存のドキュメントはありません" + "noData": "既存のドキュメントがありません" }, "apiKeys": { - "label": "チャットボット", + "label": "APIキー", "name": "名前", "key": "APIキー", "sourceDoc": "ソースドキュメント", "createNew": "新規作成", - "noData": "既存のチャットボットはありません" + "noData": "既存のAPIキーがありません" }, "analytics": { "label": "分析", @@ -74,26 +74,33 @@ "selectChatbot": "チャットボットを選択", "filterOptions": { "hour": "時間", - "last24Hours": "24時間", - "last7Days": "7日間", - "last15Days": "15日間", - "last30Days": "30日間" + "last24Hours": "過去24時間", + "last7Days": "過去7日間", + "last15Days": "過去15日間", + "last30Days": "過去30日間" }, "messages": "メッセージ", "tokenUsage": "トークン使用量", "feedback": "フィードバック", "filterPlaceholder": "フィルター", - "none": "なし" + "none": "なし", + "positiveFeedback": "肯定的なフィードバック", + "negativeFeedback": "否定的なフィードバック" }, "logs": { "label": "ログ", "filterByChatbot": "チャットボットでフィルター", "selectChatbot": "チャットボットを選択", "none": "なし", - "tableHeader": "API生成/チャットボットの会話" + "tableHeader": "API生成 / チャットボットの会話" }, "tools": { - "label": "ツール" + "label": "ツール", + "searchPlaceholder": "検索...", + "addTool": "ツールを追加", + "noToolsAlt": "ツールが見つかりません", + "noToolsFound": "ツールが見つかりません", + "selectToolSetup": "設定するツールを選択してください" } }, "modals": { @@ -150,6 +157,24 @@ "note": "ソースドキュメント、個人情報、および以降の会話は非公開のままになります", "create": "作成", "option": "ユーザーがより多くのクエリを実行できるようにします。" + }, + "configTool": { + "title": "ツール設定", + "type": "タイプ", + "apiKeyLabel": "APIキー / OAuth", + "apiKeyPlaceholder": "APIキー / OAuthを入力してください", + "addButton": "ツールを追加", + "closeButton": "閉じる" + }, + "prompts": { + "addPrompt": "プロンプトを追加", + "addDescription": "カスタムプロンプトを追加してDocsGPTに保存", + "editPrompt": "プロンプトを編集", + "editDescription": "カスタムプロンプトを編集してDocsGPTに保存", + "promptName": "プロンプト名", + "promptText": "プロンプトテキスト", + "save": "保存", + "nameExists": "名前が既に存在します" } }, "sharedConv": { @@ -162,5 +187,13 @@ "delete": "削除", "rename": "名前変更", "deleteWarning": "この会話を削除してもよろしいですか?" + }, + "pagination": { + "rowsPerPage": "1ページあたりの行数", + "pageOf": "ページ {{currentPage}} / {{totalPages}}", + "firstPage": "最初のページ", + "previousPage": "前のページ", + "nextPage": "次のページ", + "lastPage": "最後のページ" } } diff --git a/frontend/src/locale/ru.json b/frontend/src/locale/ru.json index c5e3deb8..f2eb2e87 100644 --- a/frontend/src/locale/ru.json +++ b/frontend/src/locale/ru.json @@ -10,6 +10,9 @@ "sourceDocs": "Источник", "none": "Нет", "cancel": "Отмена", + "help": "Помощь", + "emailUs": "Напишите нам", + "documentation": "Документация", "demo": [ { "header": "Узнайте о DocsGPT", @@ -34,7 +37,7 @@ "label": "Общие", "selectTheme": "Выбрать тему", "light": "Светлая", - "dark": "Темная", + "dark": "Тёмная", "selectLanguage": "Выбрать язык", "chunks": "Обработанные фрагменты на запрос", "prompt": "Активная подсказка", @@ -47,7 +50,7 @@ "medium": "Средний", "high": "Высокий", "unlimited": "Без ограничений", - "default": "по умолчанию" + "default": "По умолчанию" }, "documents": { "label": "Документы", @@ -58,12 +61,12 @@ "noData": "Нет существующих документов" }, "apiKeys": { - "label": "Чат-боты", + "label": "API ключи", "name": "Название", - "key": "Ключ API", - "sourceDoc": "Исходный документ", + "key": "API ключ", + "sourceDoc": "Источник документа", "createNew": "Создать новый", - "noData": "Нет существующих чат-ботов" + "noData": "Нет существующих API ключей" }, "analytics": { "label": "Аналитика", @@ -71,52 +74,59 @@ "selectChatbot": "Выбрать чат-бота", "filterOptions": { "hour": "Час", - "last24Hours": "24 часа", - "last7Days": "7 дней", - "last15Days": "15 дней", - "last30Days": "30 дней" + "last24Hours": "Последние 24 часа", + "last7Days": "Последние 7 дней", + "last15Days": "Последние 15 дней", + "last30Days": "Последние 30 дней" }, "messages": "Сообщения", - "tokenUsage": "Использование токенов", + "tokenUsage": "Использование токена", "feedback": "Обратная связь", "filterPlaceholder": "Фильтр", - "none": "Нет" + "none": "Нет", + "positiveFeedback": "Положительная обратная связь", + "negativeFeedback": "Отрицательная обратная связь" }, "logs": { "label": "Журналы", "filterByChatbot": "Фильтровать по чат-боту", "selectChatbot": "Выбрать чат-бота", "none": "Нет", - "tableHeader": "Сгенерированные API / разговоры с чат-ботом" + "tableHeader": "API сгенерировано / разговоры с чат-ботом" }, "tools": { - "label": "Инструменты" + "label": "Инструменты", + "searchPlaceholder": "Поиск...", + "addTool": "Добавить инструмент", + "noToolsAlt": "Инструменты не найдены", + "noToolsFound": "Инструменты не найдены", + "selectToolSetup": "Выберите инструмент для настройки" } }, "modals": { "uploadDoc": { - "label": "Загрузить новую документацию", + "label": "Загрузить новый документ", "select": "Выберите способ загрузки документа в DocsGPT", "file": "Загрузить с устройства", "back": "Назад", - "wait": "Пожалуйста, подождите ...", + "wait": "Пожалуйста, подождите...", "remote": "Собрать с веб-сайта", "start": "Начать чат", "name": "Имя", "choose": "Выбрать файлы", - "info": "Загрузите .pdf, .txt, .rst, .csv, .xlsx, .docx, .md, .html, .epub, .json, .pptx, .zip с ограничением до 25 МБ", + "info": "Пожалуйста, загрузите файлы .pdf, .txt, .rst, .csv, .xlsx, .docx, .md, .html, .epub, .json, .pptx, .zip размером до 25 МБ", "uploadedFiles": "Загруженные файлы", "cancel": "Отмена", "train": "Обучение", "link": "Ссылка", "urlLink": "URL-ссылка", - "repoUrl": "URL-адрес репозитория", + "repoUrl": "URL репозитория", "reddit": { "id": "ID клиента", "secret": "Секрет клиента", - "agent": "Агент пользователя", + "agent": "Пользовательский агент", "searchQueries": "Поисковые запросы", - "numberOfPosts": "Количество постов" + "numberOfPosts": "Количество сообщений" }, "drag": { "title": "Загрузить исходный файл", @@ -124,16 +134,16 @@ } }, "createAPIKey": { - "label": "Создать новый ключ API", - "apiKeyName": "Название ключа API", + "label": "Создать новый API ключ", + "apiKeyName": "Название API ключа", "chunks": "Обработанные фрагменты на запрос", - "prompt": "Выбрать активный запрос", - "sourceDoc": "Исходный документ", + "prompt": "Выбрать активную подсказку", + "sourceDoc": "Источник документа", "create": "Создать" }, "saveKey": { - "note": "Пожалуйста, сохраните свой ключ", - "disclaimer": "Это единственный раз, когда будет показан ваш ключ", + "note": "Пожалуйста, сохраните ваш ключ", + "disclaimer": "Ваш ключ будет показан только один раз.", "copy": "Копировать", "copied": "Скопировано", "confirm": "Я сохранил ключ" @@ -143,21 +153,47 @@ "delete": "Удалить" }, "shareConv": { - "label": "Создать публичную страницу для общего доступа", - "note": "Исходный документ, личная информация и дальнейший разговор останутся конфиденциальными", + "label": "Создать публичную страницу для совместного использования", + "note": "Исходный документ, личная информация и последующие разговоры останутся приватными", "create": "Создать", - "option": "Разрешить пользователям делать дополнительные запросы" + "option": "Позволить пользователям делать дополнительные запросы." + }, + "configTool": { + "title": "Настройка инструмента", + "type": "Тип", + "apiKeyLabel": "API ключ / OAuth", + "apiKeyPlaceholder": "Введите API ключ / OAuth", + "addButton": "Добавить инструмент", + "closeButton": "Закрыть" + }, + "prompts": { + "addPrompt": "Добавить подсказку", + "addDescription": "Добавить вашу пользовательскую подсказку и сохранить её в DocsGPT", + "editPrompt": "Редактировать подсказку", + "editDescription": "Редактировать вашу пользовательскую подсказку и сохранить её в DocsGPT", + "promptName": "Название подсказки", + "promptText": "Текст подсказки", + "save": "Сохранить", + "nameExists": "Название уже существует" } }, "sharedConv": { "subtitle": "Создано с помощью", "button": "Начать работу с DocsGPT", - "meta": "DocsGPT использует GenAI, пожалуйста, проверяйте важную информацию, используя источники" + "meta": "DocsGPT использует GenAI, пожалуйста, проверьте важную информацию, используя источники." }, "convTile": { "share": "Поделиться", "delete": "Удалить", "rename": "Переименовать", "deleteWarning": "Вы уверены, что хотите удалить этот разговор?" + }, + "pagination": { + "rowsPerPage": "Строк на странице", + "pageOf": "Страница {{currentPage}} из {{totalPages}}", + "firstPage": "Первая страница", + "previousPage": "Предыдущая страница", + "nextPage": "Следующая страница", + "lastPage": "Последняя страница" } } diff --git a/frontend/src/locale/zh-TW.json b/frontend/src/locale/zh-TW.json index 5e97d883..a2bba823 100644 --- a/frontend/src/locale/zh-TW.json +++ b/frontend/src/locale/zh-TW.json @@ -57,14 +57,16 @@ "name": "文件名稱", "date": "向量日期", "type": "類型", - "tokenUsage": "Token 使用量" + "tokenUsage": "Token 使用量", + "noData": "沒有現有的文件" }, "apiKeys": { - "label": "API 金鑰", + "label": "聊天機器人", "name": "名稱", "key": "API 金鑰", "sourceDoc": "來源文件", - "createNew": "新增" + "createNew": "新增", + "noData": "沒有現有的聊天機器人" }, "analytics": { "label": "分析", @@ -81,7 +83,9 @@ "tokenUsage": "Token 使用量", "feedback": "回饋", "filterPlaceholder": "篩選", - "none": "無" + "none": "無", + "positiveFeedback": "正向回饋", + "negativeFeedback": "負向回饋" }, "logs": { "label": "日誌", @@ -91,22 +95,32 @@ "tableHeader": "API 生成 / 聊天機器人會話" }, "tools": { - "label": "工具" + "label": "工具", + "searchPlaceholder": "搜尋...", + "addTool": "新增工具", + "noToolsAlt": "找不到工具", + "noToolsFound": "找不到工具", + "selectToolSetup": "選擇要設定的工具" } }, "modals": { "uploadDoc": { "label": "上傳新文件", + "select": "選擇如何將文件上傳到 DocsGPT", "file": "從檔案", "remote": "遠端", + "back": "返回", + "wait": "請稍候...", + "start": "開始對話", "name": "名稱", "choose": "選擇檔案", - "info": "請上傳 .pdf, .txt, .rst, .docx, .md, .json, .pptx, .zip 檔案,大小限制為 25MB", + "info": "請上傳 .pdf, .txt, .rst, .csv, .xlsx, .docx, .md, .html, .epub, .json, .pptx, .zip 檔案,大小限制為 25MB", "uploadedFiles": "已上傳的檔案", "cancel": "取消", "train": "訓練", "link": "連結", "urlLink": "URL 連結", + "repoUrl": "儲存庫 URL", "reddit": { "id": "用戶端 ID", "secret": "用戶端金鑰", @@ -141,7 +155,26 @@ "shareConv": { "label": "建立公開頁面以分享", "note": "來源文件、個人資訊和後續對話將保持私密", - "create": "建立" + "create": "建立", + "option": "允許使用者進行更多查詢" + }, + "configTool": { + "title": "工具設定", + "type": "類型", + "apiKeyLabel": "API 金鑰 / OAuth", + "apiKeyPlaceholder": "輸入 API 金鑰 / OAuth", + "addButton": "新增工具", + "closeButton": "關閉" + }, + "prompts": { + "addPrompt": "新增提示", + "addDescription": "新增自定義提示並儲存到 DocsGPT", + "editPrompt": "編輯提示", + "editDescription": "編輯自定義提示並儲存到 DocsGPT", + "promptName": "提示名稱", + "promptText": "提示文字", + "save": "儲存", + "nameExists": "名稱已存在" } }, "sharedConv": { @@ -154,5 +187,13 @@ "delete": "刪除", "rename": "重新命名", "deleteWarning": "您確定要刪除這個對話嗎?" + }, + "pagination": { + "rowsPerPage": "每頁行數", + "pageOf": "第 {{currentPage}} 頁,共 {{totalPages}} 頁", + "firstPage": "第一頁", + "previousPage": "上一頁", + "nextPage": "下一頁", + "lastPage": "最後一頁" } } diff --git a/frontend/src/locale/zh.json b/frontend/src/locale/zh.json index afa15f7b..0ca94fe2 100644 --- a/frontend/src/locale/zh.json +++ b/frontend/src/locale/zh.json @@ -83,7 +83,9 @@ "tokenUsage": "令牌使用", "feedback": "反馈", "filterPlaceholder": "筛选", - "none": "无" + "none": "无", + "positiveFeedback": "正向反馈", + "negativeFeedback": "负向反馈" }, "logs": { "label": "日志", @@ -93,7 +95,12 @@ "tableHeader": "API 生成 / 聊天机器人会话" }, "tools": { - "label": "工具" + "label": "工具", + "searchPlaceholder": "搜索...", + "addTool": "添加工具", + "noToolsAlt": "未找到工具", + "noToolsFound": "未找到工具", + "selectToolSetup": "选择要设置的工具" } }, "modals": { @@ -150,6 +157,24 @@ "note": "源文档、个人信息和后续对话将保持私密", "create": "创建", "option": "允许用户进行更多查询。" + }, + "configTool": { + "title": "工具配置", + "type": "类型", + "apiKeyLabel": "API 密钥 / OAuth", + "apiKeyPlaceholder": "输入 API 密钥 / OAuth", + "addButton": "添加工具", + "closeButton": "关闭" + }, + "prompts": { + "addPrompt": "添加提示", + "addDescription": "添加自定义提示并保存到 DocsGPT", + "editPrompt": "编辑提示", + "editDescription": "编辑自定义提示并保存到 DocsGPT", + "promptName": "提示名称", + "promptText": "提示文本", + "save": "保存", + "nameExists": "名称已存在" } }, "sharedConv": { @@ -162,5 +187,13 @@ "delete": "删除", "rename": "重命名", "deleteWarning": "您确定要删除此对话吗?" + }, + "pagination": { + "rowsPerPage": "每页行数", + "pageOf": "第 {{currentPage}} 页,共 {{totalPages}} 页", + "firstPage": "第一页", + "previousPage": "上一页", + "nextPage": "下一页", + "lastPage": "最后一页" } } diff --git a/frontend/src/modals/ConfigToolModal.tsx b/frontend/src/modals/ConfigToolModal.tsx index 96bb15be..4a8ca881 100644 --- a/frontend/src/modals/ConfigToolModal.tsx +++ b/frontend/src/modals/ConfigToolModal.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { useTranslation } from 'react-i18next'; import Exit from '../assets/exit.svg'; import Input from '../components/Input'; @@ -17,6 +18,7 @@ export default function ConfigToolModal({ tool: AvailableTool | null; getUserTools: () => void; }) { + const { t } = useTranslation(); const [authKey, setAuthKey] = React.useState(''); const handleAddTool = (tool: AvailableTool) => { @@ -52,21 +54,22 @@ export default function ConfigToolModal({

- Tool Config + {t('modals.configTool.title')}

- Type: {tool?.name} + {t('modals.configTool.type')}:{' '} + {tool?.name}

- API Key / Oauth + {t('modals.configTool.apiKeyLabel')} setAuthKey(e.target.value)} borderVariant="thin" - placeholder="Enter API Key / Oauth" + placeholder={t('modals.configTool.apiKeyPlaceholder')} >
@@ -76,7 +79,7 @@ export default function ConfigToolModal({ }} className="rounded-3xl bg-purple-30 px-5 py-2 text-sm text-white transition-all hover:bg-[#6F3FD1]" > - Add Tool + {t('modals.configTool.addButton')}
diff --git a/frontend/src/modals/ShareConversationModal.tsx b/frontend/src/modals/ShareConversationModal.tsx index 3f87839e..44156761 100644 --- a/frontend/src/modals/ShareConversationModal.tsx +++ b/frontend/src/modals/ShareConversationModal.tsx @@ -101,11 +101,17 @@ export const ShareConversationModal = ({ return (
-

{t('modals.shareConv.label')}

-

{t('modals.shareConv.note')}

+

+ {t('modals.shareConv.label')} +

+

+ {t('modals.shareConv.note')} +

- {t('modals.shareConv.option')} -