├── .devcontainer ├── Dockerfile ├── devc-welcome.md ├── devcontainer.json ├── docker-compose-dev.yaml ├── docker-compose.override.yaml └── post-create-command.sh ├── .env-template ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ └── feature_request.yml ├── PULL_REQUEST_TEMPLATE.md ├── dependabot.yml ├── holopin.yml ├── labeler.yml └── workflows │ ├── bandit.yaml │ ├── ci.yml │ ├── cife.yml │ ├── docker-develop-build.yml │ ├── docker-develop-fe-build.yml │ ├── labeler.yml │ ├── lint.yml │ ├── pytest.yml │ └── sync_fork.yaml ├── .gitignore ├── .ruff.toml ├── .vscode ├── launch.json └── tasks.json ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── SECURITY.md ├── application ├── .env_sample ├── Dockerfile ├── __init__.py ├── agents │ ├── __init__.py │ ├── agent_creator.py │ ├── base.py │ ├── classic_agent.py │ ├── llm_handler.py │ ├── react_agent.py │ └── tools │ │ ├── api_tool.py │ │ ├── base.py │ │ ├── brave.py │ │ ├── cryptoprice.py │ │ ├── ntfy.py │ │ ├── postgres.py │ │ ├── read_webpage.py │ │ ├── telegram.py │ │ ├── tool_action_parser.py │ │ └── tool_manager.py ├── api │ ├── __init__.py │ ├── answer │ │ ├── __init__.py │ │ └── routes.py │ ├── internal │ │ ├── __init__.py │ │ └── routes.py │ └── user │ │ ├── __init__.py │ │ ├── routes.py │ │ └── tasks.py ├── app.py ├── auth.py ├── cache.py ├── celery_init.py ├── celeryconfig.py ├── core │ ├── __init__.py │ ├── logging_config.py │ ├── mongo_db.py │ └── settings.py ├── error.py ├── extensions.py ├── index.faiss ├── index.pkl ├── llm │ ├── __init__.py │ ├── anthropic.py │ ├── base.py │ ├── docsgpt_provider.py │ ├── google_ai.py │ ├── groq.py │ ├── huggingface.py │ ├── llama_cpp.py │ ├── llm_creator.py │ ├── novita.py │ ├── openai.py │ ├── premai.py │ └── sagemaker.py ├── logging.py ├── parser │ ├── __init__.py │ ├── chunking.py │ ├── embedding_pipeline.py │ ├── file │ │ ├── __init__.py │ │ ├── base.py │ │ ├── base_parser.py │ │ ├── bulk.py │ │ ├── docs_parser.py │ │ ├── epub_parser.py │ │ ├── html_parser.py │ │ ├── image_parser.py │ │ ├── json_parser.py │ │ ├── markdown_parser.py │ │ ├── openapi3_parser.py │ │ ├── pptx_parser.py │ │ ├── rst_parser.py │ │ └── tabular_parser.py │ ├── remote │ │ ├── base.py │ │ ├── crawler_loader.py │ │ ├── crawler_markdown.py │ │ ├── github_loader.py │ │ ├── reddit_loader.py │ │ ├── remote_creator.py │ │ ├── sitemap_loader.py │ │ ├── telegram.py │ │ └── web_loader.py │ └── schema │ │ ├── __init__.py │ │ ├── base.py │ │ └── schema.py ├── prompts │ ├── chat_combine_creative.txt │ ├── chat_combine_default.txt │ ├── chat_combine_strict.txt │ ├── chat_reduce_prompt.txt │ ├── react_final_prompt.txt │ └── react_planning_prompt.txt ├── requirements.txt ├── retriever │ ├── __init__.py │ ├── base.py │ ├── brave_search.py │ ├── classic_rag.py │ ├── duckduck_search.py │ └── retriever_creator.py ├── storage │ ├── base.py │ ├── local.py │ ├── s3.py │ └── storage_creator.py ├── tts │ ├── base.py │ ├── elevenlabs.py │ └── google_tts.py ├── usage.py ├── utils.py ├── vectorstore │ ├── __init__.py │ ├── base.py │ ├── document_class.py │ ├── elasticsearch.py │ ├── faiss.py │ ├── lancedb.py │ ├── milvus.py │ ├── mongodb.py │ ├── qdrant.py │ └── vector_creator.py ├── worker.py └── wsgi.py ├── codecov.yml ├── deployment ├── docker-compose-azure.yaml ├── docker-compose-dev.yaml ├── docker-compose-local.yaml ├── docker-compose.yaml ├── k8s │ ├── deployments │ │ ├── docsgpt-deploy.yaml │ │ ├── mongo-deploy.yaml │ │ ├── qdrant-deploy.yaml │ │ └── redis-deploy.yaml │ ├── docsgpt-secrets.yaml │ └── services │ │ ├── docsgpt-service.yaml │ │ ├── mongo-service.yaml │ │ ├── qdrant-service.yaml │ │ └── redis-service.yaml └── optional │ ├── docker-compose.optional.ollama-cpu.yaml │ └── docker-compose.optional.ollama-gpu.yaml ├── docs ├── README.md ├── components │ ├── DeploymentCards.jsx │ └── ToolCards.jsx ├── next.config.js ├── package-lock.json ├── package.json ├── pages │ ├── Agents │ │ ├── _meta.json │ │ └── basics.mdx │ ├── Deploying │ │ ├── Amazon-Lightsail.mdx │ │ ├── Development-Environment.mdx │ │ ├── Docker-Deploying.mdx │ │ ├── DocsGPT-Settings.mdx │ │ ├── Hosting-the-app.mdx │ │ ├── Kubernetes-Deploying.mdx │ │ ├── Railway.mdx │ │ └── _meta.json │ ├── Extensions │ │ ├── Chatwoot-extension.mdx │ │ ├── Chrome-extension.mdx │ │ ├── _meta.json │ │ ├── api-key-guide.mdx │ │ ├── chat-widget.mdx │ │ └── search-widget.mdx │ ├── Guides │ │ ├── Architecture.mdx │ │ ├── Customising-prompts.mdx │ │ ├── How-to-train-on-other-documentation.mdx │ │ ├── How-to-use-different-LLM.mdx │ │ ├── My-AI-answers-questions-using-external-knowledge.mdx │ │ └── _meta.json │ ├── Models │ │ ├── _meta.json │ │ ├── cloud-providers.mdx │ │ ├── embeddings.md │ │ └── local-inference.mdx │ ├── Tools │ │ ├── _meta.json │ │ ├── api-tool.mdx │ │ ├── basics.mdx │ │ └── creating-a-tool.mdx │ ├── _app.mdx │ ├── _meta.json │ ├── changelog.mdx │ ├── index.mdx │ └── quickstart.mdx ├── public │ ├── Railway-selection.png │ ├── civo.png │ ├── cute-docsgpt.png │ ├── digitalocean.png │ ├── docs.gif │ ├── favicons │ │ ├── apple-touch-icon.png │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ └── site.webmanifest │ ├── homevideo.gif │ ├── jwt-input.png │ ├── kamatera.png │ ├── lightsail.png │ ├── llms.gif │ ├── new-agent.png │ ├── prompts.gif │ ├── railway.png │ └── toolIcons │ │ ├── api-tool-example.png │ │ ├── tool_api_tool.svg │ │ ├── tool_brave.svg │ │ ├── tool_cryptoprice.svg │ │ ├── tool_ntfy.svg │ │ ├── tool_postgres.svg │ │ ├── tool_read_webpage.svg │ │ └── tool_telegram.svg └── theme.config.jsx ├── extensions ├── chatwoot │ ├── .env_sample │ ├── __init__.py │ └── app.py ├── chrome │ ├── _locales │ │ └── en │ │ │ └── messages.json │ ├── dist │ │ └── output.css │ ├── icons │ │ ├── icon128.png │ │ ├── icon16 2.png │ │ ├── icon16.png │ │ ├── icon19.png │ │ ├── icon24.png │ │ ├── icon256.png │ │ ├── icon32.png │ │ └── icon48.png │ ├── js │ │ └── jquery │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── bower.json │ │ │ ├── component.json │ │ │ ├── composer.json │ │ │ ├── jquery.js │ │ │ ├── jquery.min.js │ │ │ └── package.json │ ├── manifest.json │ ├── package-lock.json │ ├── package.json │ ├── popup.html │ ├── popup.js │ ├── src │ │ └── bg │ │ │ └── service-worker.js │ ├── styles.css │ └── tailwind.config.js ├── discord │ ├── __init__.py │ └── bot.py ├── react-widget │ ├── .gitignore │ ├── .parcelrc │ ├── README.md │ ├── custom.d.ts │ ├── package-lock.json │ ├── package.json │ ├── publish.sh │ ├── src │ │ ├── App.tsx │ │ ├── assets │ │ │ ├── dislike.svg │ │ │ └── like.svg │ │ ├── browser.tsx │ │ ├── components │ │ │ ├── DocsGPTWidget.tsx │ │ │ └── SearchBar.tsx │ │ ├── index.html │ │ ├── index.ts │ │ ├── main.tsx │ │ ├── requests │ │ │ ├── searchAPI.ts │ │ │ └── streamingApi.ts │ │ ├── types │ │ │ └── index.ts │ │ └── utils │ │ │ └── helper.ts │ └── tsconfig.json ├── slack-bot │ ├── .gitignore │ ├── Readme.md │ ├── app.py │ └── requirements.txt └── web-widget │ ├── README.md │ ├── dist │ ├── chat-widget.js │ └── output.css │ ├── index.html │ ├── package-lock.json │ ├── package.json │ ├── src │ ├── html │ │ └── widget.html │ ├── input.css │ └── js │ │ └── script.js │ └── tailwind.config.js ├── frontend ├── .env.development ├── .env.production ├── .eslintignore ├── .eslintrc.cjs ├── .husky │ └── pre-commit ├── .prettierignore ├── Dockerfile ├── index.html ├── package-lock.json ├── package.json ├── postcss.config.cjs ├── prettier.config.cjs ├── public │ ├── favicon.ico │ ├── fonts │ │ ├── IBMPlexMono-Medium.ttf │ │ └── Inter-Variable.ttf │ ├── lock-dark.svg │ ├── lock.svg │ ├── message-programming-dark.svg │ ├── message-programming.svg │ ├── message-text-dark.svg │ ├── message-text.svg │ ├── toolIcons │ │ ├── tool_api_tool.svg │ │ ├── tool_brave.svg │ │ ├── tool_cryptoprice.svg │ │ ├── tool_ntfy.svg │ │ ├── tool_postgres.svg │ │ ├── tool_read_webpage.svg │ │ └── tool_telegram.svg │ └── vite.svg ├── signal-desktop-keyring.gpg ├── src │ ├── App.tsx │ ├── Hero.tsx │ ├── Navigation.tsx │ ├── PageNotFound.tsx │ ├── agents │ │ ├── AgentCard.tsx │ │ ├── AgentLogs.tsx │ │ ├── AgentPreview.tsx │ │ ├── NewAgent.tsx │ │ ├── SharedAgent.tsx │ │ ├── index.tsx │ │ └── types │ │ │ └── index.ts │ ├── api │ │ ├── client.ts │ │ ├── endpoints.ts │ │ └── services │ │ │ ├── conversationService.ts │ │ │ └── userService.ts │ ├── assets │ │ ├── DragFileUpload.svg │ │ ├── Loading.svg │ │ ├── TwitterX.svg │ │ ├── add.svg │ │ ├── alert.svg │ │ ├── arrow-down.svg │ │ ├── arrow-left.svg │ │ ├── arrow-right.svg │ │ ├── arrow.svg │ │ ├── caret-sort.svg │ │ ├── checkMark2.svg │ │ ├── checkmark.svg │ │ ├── chevron-down.svg │ │ ├── chevron-right.svg │ │ ├── circle-check.svg │ │ ├── circle-x.svg │ │ ├── clip.svg │ │ ├── cloud.svg │ │ ├── cogwheel.svg │ │ ├── copy-linear.svg │ │ ├── copy.svg │ │ ├── cute_docsgpt3.svg │ │ ├── discord-dark.svg │ │ ├── discord.svg │ │ ├── dislike.svg │ │ ├── document.svg │ │ ├── documentation-dark.svg │ │ ├── documentation.svg │ │ ├── double-arrow-left.svg │ │ ├── double-arrow-right.svg │ │ ├── dropdown-arrow.svg │ │ ├── edit.svg │ │ ├── envelope-dark.svg │ │ ├── envelope.svg │ │ ├── exit.svg │ │ ├── expand.svg │ │ ├── eye-view.svg │ │ ├── file_upload.svg │ │ ├── github-dark.svg │ │ ├── github.svg │ │ ├── hamburger-dark.svg │ │ ├── hamburger.svg │ │ ├── info-dark.svg │ │ ├── info.svg │ │ ├── key.svg │ │ ├── like.svg │ │ ├── link-gray.svg │ │ ├── link.svg │ │ ├── message-dark.svg │ │ ├── message.svg │ │ ├── monitoring-purple.svg │ │ ├── monitoring-white.svg │ │ ├── monitoring.svg │ │ ├── no-files-dark.svg │ │ ├── no-files.svg │ │ ├── openNewChat.svg │ │ ├── paper_plane.svg │ │ ├── pin.svg │ │ ├── red-trash.svg │ │ ├── redirect.svg │ │ ├── robot.svg │ │ ├── science-spark-dark.svg │ │ ├── science-spark.svg │ │ ├── send.svg │ │ ├── send_dark.svg │ │ ├── settingGear-dark.svg │ │ ├── settingGear.svg │ │ ├── share.svg │ │ ├── single-left-arrow.svg │ │ ├── single-right-arrow.svg │ │ ├── source.svg │ │ ├── sources.svg │ │ ├── spark.svg │ │ ├── speaker.svg │ │ ├── spinner-dark.svg │ │ ├── spinner.svg │ │ ├── stopspeech.svg │ │ ├── sync.svg │ │ ├── three-dots.svg │ │ ├── tool.svg │ │ ├── trash.svg │ │ ├── unpin.svg │ │ ├── upload.svg │ │ ├── user.svg │ │ ├── website_collect.svg │ │ └── white-trash.svg │ ├── components │ │ ├── Accordion.tsx │ │ ├── ActionButtons.tsx │ │ ├── Avatar.tsx │ │ ├── ContextMenu.tsx │ │ ├── CopyButton.tsx │ │ ├── DocumentPagination.tsx │ │ ├── Dropdown.tsx │ │ ├── DropdownMenu.tsx │ │ ├── Help.tsx │ │ ├── Input.tsx │ │ ├── MermaidRenderer.tsx │ │ ├── MessageInput.tsx │ │ ├── MultiSelectPopup.tsx │ │ ├── RetryIcon.tsx │ │ ├── SettingsBar.tsx │ │ ├── ShareButton.tsx │ │ ├── Sidebar.tsx │ │ ├── SkeletonLoader.tsx │ │ ├── SourceDropdown.tsx │ │ ├── SourcesPopup.tsx │ │ ├── Spinner.tsx │ │ ├── TextToSpeechButton.tsx │ │ ├── ToggleSwitch.tsx │ │ ├── ToolsPopup.tsx │ │ └── types │ │ │ └── index.ts │ ├── conversation │ │ ├── Conversation.tsx │ │ ├── ConversationBubble.module.css │ │ ├── ConversationBubble.tsx │ │ ├── ConversationMessages.tsx │ │ ├── ConversationTile.tsx │ │ ├── SharedConversation.tsx │ │ ├── conversationHandlers.ts │ │ ├── conversationModels.ts │ │ ├── conversationSlice.ts │ │ ├── sharedConversationSlice.ts │ │ └── types │ │ │ └── index.ts │ ├── hooks │ │ ├── index.ts │ │ ├── useDefaultDocument.ts │ │ ├── usePromptManager.ts │ │ └── useTokenAuth.ts │ ├── index.css │ ├── locale │ │ ├── en.json │ │ ├── es.json │ │ ├── i18n.ts │ │ ├── jp.json │ │ ├── ru.json │ │ ├── zh-TW.json │ │ └── zh.json │ ├── main.tsx │ ├── modals │ │ ├── AddActionModal.tsx │ │ ├── AddToolModal.tsx │ │ ├── AgentDetailsModal.tsx │ │ ├── ChunkModal.tsx │ │ ├── ConfigToolModal.tsx │ │ ├── ConfirmationModal.tsx │ │ ├── CreateAPIKeyModal.tsx │ │ ├── DeleteConvModal.tsx │ │ ├── JWTModal.tsx │ │ ├── SaveAPIKeyModal.tsx │ │ ├── ShareConversationModal.tsx │ │ ├── WrapperModal.tsx │ │ └── types │ │ │ └── index.ts │ ├── models │ │ └── misc.ts │ ├── preferences │ │ ├── PromptsModal.tsx │ │ ├── preferenceApi.ts │ │ ├── preferenceSlice.ts │ │ └── types │ │ │ └── index.ts │ ├── settings │ │ ├── APIKeys.tsx │ │ ├── Analytics.tsx │ │ ├── Documents.tsx │ │ ├── General.tsx │ │ ├── Logs.tsx │ │ ├── Prompts.tsx │ │ ├── ToolConfig.tsx │ │ ├── Tools.tsx │ │ ├── Widgets.tsx │ │ ├── index.tsx │ │ └── types │ │ │ └── index.ts │ ├── store.ts │ ├── upload │ │ ├── Upload.tsx │ │ └── types │ │ │ └── ingestor.ts │ ├── utils │ │ ├── browserUtils.ts │ │ ├── chartUtils.ts │ │ ├── dateTimeUtils.ts │ │ ├── objectUtils.ts │ │ └── stringUtils.ts │ └── vite-env.d.ts ├── tailwind.config.cjs ├── tsconfig.json ├── tsconfig.node.json └── vite.config.ts ├── md-gen.py ├── scripts └── migrate_to_v1_vectorstore.py ├── setup.ps1 ├── setup.sh └── tests ├── llm ├── test_anthropic.py ├── test_openai.py └── test_sagemaker.py ├── test_app.py ├── test_cache.py ├── test_celery.py ├── test_error.py ├── test_openapi3.yaml └── test_openapi3parser.py /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.12-bookworm 2 | 3 | # Install Node.js 20.x 4 | RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \ 5 | && apt-get install -y nodejs \ 6 | && rm -rf /var/lib/apt/lists/* 7 | 8 | # Install global npm packages 9 | RUN npm install -g husky vite 10 | 11 | # Create and activate Python virtual environment 12 | RUN python -m venv /opt/venv 13 | ENV PATH="/opt/venv/bin:$PATH" 14 | 15 | WORKDIR /workspace -------------------------------------------------------------------------------- /.devcontainer/devc-welcome.md: -------------------------------------------------------------------------------- 1 | # Welcome to DocsGPT Devcontainer 2 | 3 | Welcome to the DocsGPT development environment! This guide will help you get started quickly. 4 | 5 | ## Starting Services 6 | 7 | To run DocsGPT, you need to start three main services: Flask (backend), Celery (task queue), and Vite (frontend). Here are the commands to start each service within the devcontainer: 8 | 9 | ### Vite (Frontend) 10 | 11 | ```bash 12 | cd frontend 13 | npm run dev -- --host 14 | ``` 15 | 16 | ### Flask (Backend) 17 | 18 | ```bash 19 | flask --app application/app.py run --host=0.0.0.0 --port=7091 20 | ``` 21 | 22 | ### Celery (Task Queue) 23 | 24 | ```bash 25 | celery -A application.app.celery worker -l INFO 26 | ``` 27 | 28 | ## Github Codespaces Instructions 29 | 30 | ### 1. Make Ports Public: 31 | 32 | Go to the "Ports" panel in Codespaces (usually located at the bottom of the VS Code window). 33 | 34 | For both port 5173 and 7091, right-click on the port and select "Make Public". 35 | 36 | ![CleanShot 2025-02-12 at 09 46 14@2x](https://github.com/user-attachments/assets/00a34b16-a7ef-47af-9648-87a7e3008475) 37 | 38 | 39 | ### 2. Update VITE_API_HOST: 40 | 41 | After making port 7091 public, copy the public URL provided by Codespaces for port 7091. 42 | 43 | Open the file frontend/.env.development. 44 | 45 | Find the line VITE_API_HOST=http://localhost:7091. 46 | 47 | Replace http://localhost:7091 with the public URL you copied from Codespaces. 48 | 49 | ![CleanShot 2025-02-12 at 09 46 56@2x](https://github.com/user-attachments/assets/c472242f-1079-4cd8-bc0b-2d78db22b94c) 50 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "DocsGPT Dev Container", 3 | "dockerComposeFile": ["docker-compose-dev.yaml", "docker-compose.override.yaml"], 4 | "service": "dev", 5 | "workspaceFolder": "/workspace", 6 | "postCreateCommand": ".devcontainer/post-create-command.sh", 7 | "forwardPorts": [7091, 5173, 6379, 27017], 8 | "customizations": { 9 | "vscode": { 10 | "extensions": [ 11 | "ms-python.python", 12 | "ms-toolsai.jupyter", 13 | "esbenp.prettier-vscode", 14 | "dbaeumer.vscode-eslint" 15 | ] 16 | }, 17 | "codespaces": { 18 | "openFiles": [ 19 | ".devcontainer/devc-welcome.md", 20 | "CONTRIBUTING.md" 21 | ] 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /.devcontainer/docker-compose-dev.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | 3 | redis: 4 | image: redis:6-alpine 5 | ports: 6 | - 6379:6379 7 | 8 | mongo: 9 | image: mongo:6 10 | ports: 11 | - 27017:27017 12 | volumes: 13 | - mongodb_data_container:/data/db 14 | 15 | 16 | 17 | volumes: 18 | mongodb_data_container: -------------------------------------------------------------------------------- /.devcontainer/docker-compose.override.yaml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | 3 | services: 4 | dev: 5 | build: 6 | context: . 7 | dockerfile: Dockerfile 8 | volumes: 9 | - ../:/workspace:cached 10 | command: sleep infinity 11 | depends_on: 12 | redis: 13 | condition: service_healthy 14 | mongo: 15 | condition: service_healthy 16 | environment: 17 | - CELERY_BROKER_URL=redis://redis:6379/0 18 | - CELERY_RESULT_BACKEND=redis://redis:6379/1 19 | - MONGO_URI=mongodb://mongo:27017/docsgpt 20 | - CACHE_REDIS_URL=redis://redis:6379/2 21 | networks: 22 | - default 23 | 24 | redis: 25 | healthcheck: 26 | test: ["CMD", "redis-cli", "ping"] 27 | interval: 5s 28 | timeout: 30s 29 | retries: 5 30 | 31 | mongo: 32 | healthcheck: 33 | test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"] 34 | interval: 5s 35 | timeout: 30s 36 | retries: 5 37 | 38 | networks: 39 | default: 40 | name: docsgpt-dev-network -------------------------------------------------------------------------------- /.devcontainer/post-create-command.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e # Exit immediately if a command exits with a non-zero status 4 | 5 | if [ ! -f frontend/.env.development ]; then 6 | cp -n .env-template frontend/.env.development || true # Assuming .env-template is in the root 7 | fi 8 | 9 | # Determine VITE_API_HOST based on environment 10 | if [ -n "$CODESPACES" ]; then 11 | # Running in Codespaces 12 | CODESPACE_NAME=$(echo "$CODESPACES" | cut -d'-' -f1) # Extract codespace name 13 | PUBLIC_API_HOST="https://${CODESPACE_NAME}-7091.${GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN}" 14 | echo "Setting VITE_API_HOST for Codespaces: $PUBLIC_API_HOST in frontend/.env.development" 15 | sed -i "s|VITE_API_HOST=.*|VITE_API_HOST=$PUBLIC_API_HOST|" frontend/.env.development 16 | else 17 | # Not running in Codespaces (local devcontainer) 18 | DEFAULT_API_HOST="http://localhost:7091" 19 | echo "Setting VITE_API_HOST for local dev: $DEFAULT_API_HOST in frontend/.env.development" 20 | sed -i "s|VITE_API_HOST=.*|VITE_API_HOST=$DEFAULT_API_HOST|" frontend/.env.development 21 | fi 22 | 23 | 24 | mkdir -p model 25 | if [ ! -d model/all-mpnet-base-v2 ]; then 26 | wget -q https://d3dg1063dc54p9.cloudfront.net/models/embeddings/mpnet-base-v2.zip -O model/mpnet-base-v2.zip 27 | unzip -q model/mpnet-base-v2.zip -d model 28 | rm model/mpnet-base-v2.zip 29 | fi 30 | pip install -r application/requirements.txt 31 | cd frontend 32 | npm install --include=dev -------------------------------------------------------------------------------- /.env-template: -------------------------------------------------------------------------------- 1 | API_KEY= 2 | LLM_NAME=docsgpt 3 | VITE_API_STREAMING=true 4 | 5 | #For Azure (you can delete it if you don't use Azure) 6 | OPENAI_API_BASE= 7 | OPENAI_API_VERSION= 8 | AZURE_DEPLOYMENT_NAME= 9 | AZURE_EMBEDDINGS_DEPLOYMENT_NAME= -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: arc53 4 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | - **What kind of change does this PR introduce?** (Bug fix, feature, docs update, ...) 2 | 3 | - **Why was this change needed?** (You can also link to an open issue here) 4 | 5 | - **Other information**: -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "pip" # See documentation for possible values 9 | directory: "/application" # Location of package manifests 10 | schedule: 11 | interval: "daily" 12 | - package-ecosystem: "npm" # See documentation for possible values 13 | directory: "/frontend" # Location of package manifests 14 | schedule: 15 | interval: "daily" 16 | - package-ecosystem: "github-actions" 17 | directory: "/" 18 | schedule: 19 | interval: "daily" 20 | -------------------------------------------------------------------------------- /.github/holopin.yml: -------------------------------------------------------------------------------- 1 | organization: docsgpt 2 | defaultSticker: cm1ulwkkl180570cl82rtzympu 3 | stickers: 4 | - id: cm1ulwkkl180570cl82rtzympu 5 | alias: contributor2024 6 | - id: cm1ureg8o130450cl8c1po6mil 7 | alias: api 8 | - id: cm1urhmag148240cl8yvqxkthx 9 | alias: lpc 10 | - id: cm1urlcpq622090cl2tvu4w71y 11 | alias: lexeu 12 | -------------------------------------------------------------------------------- /.github/labeler.yml: -------------------------------------------------------------------------------- 1 | repo: 2 | - changed-files: 3 | - any-glob-to-any-file: '*' 4 | 5 | github: 6 | - changed-files: 7 | - any-glob-to-any-file: '.github/**/*' 8 | 9 | application: 10 | - changed-files: 11 | - any-glob-to-any-file: 'application/**/*' 12 | 13 | docs: 14 | - changed-files: 15 | - any-glob-to-any-file: 'docs/**/*' 16 | 17 | extensions: 18 | - changed-files: 19 | - any-glob-to-any-file: 'extensions/**/*' 20 | 21 | frontend: 22 | - changed-files: 23 | - any-glob-to-any-file: 'frontend/**/*' 24 | 25 | scripts: 26 | - changed-files: 27 | - any-glob-to-any-file: 'scripts/**/*' 28 | 29 | tests: 30 | - changed-files: 31 | - any-glob-to-any-file: 'tests/**/*' 32 | -------------------------------------------------------------------------------- /.github/workflows/bandit.yaml: -------------------------------------------------------------------------------- 1 | name: Bandit Security Scan 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | types: [opened, synchronize, reopened] 9 | 10 | jobs: 11 | bandit_scan: 12 | if: ${{ github.repository == 'arc53/DocsGPT' }} 13 | runs-on: ubuntu-latest 14 | permissions: 15 | security-events: write 16 | actions: read 17 | contents: read 18 | 19 | steps: 20 | - name: Checkout code 21 | uses: actions/checkout@v4 22 | 23 | - name: Set up Python 24 | uses: actions/setup-python@v5 25 | with: 26 | python-version: '3.12' 27 | - name: Install dependencies 28 | run: | 29 | python -m pip install --upgrade pip 30 | pip install bandit # Bandit is needed for this action 31 | if [ -f application/requirements.txt ]; then pip install -r application/requirements.txt; fi 32 | 33 | - name: Run Bandit scan 34 | uses: PyCQA/bandit-action@v1 35 | with: 36 | severity: medium 37 | confidence: medium 38 | targets: application/ 39 | env: 40 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /.github/workflows/labeler.yml: -------------------------------------------------------------------------------- 1 | # https://github.com/actions/labeler 2 | name: Pull Request Labeler 3 | on: 4 | - pull_request_target 5 | jobs: 6 | triage: 7 | if: github.repository == 'arc53/DocsGPT' 8 | permissions: 9 | contents: read 10 | pull-requests: write 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/labeler@v5 14 | with: 15 | repo-token: "${{ secrets.GITHUB_TOKEN }}" 16 | sync-labels: true 17 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Python linting 2 | 3 | on: 4 | push: 5 | branches: 6 | - '*' 7 | pull_request: 8 | types: [ opened, synchronize ] 9 | 10 | jobs: 11 | ruff: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v4 15 | 16 | - name: Lint with Ruff 17 | uses: chartboost/ruff-action@v1 18 | -------------------------------------------------------------------------------- /.github/workflows/pytest.yml: -------------------------------------------------------------------------------- 1 | name: Run python tests with pytest 2 | on: [push, pull_request] 3 | jobs: 4 | pytest_and_coverage: 5 | name: Run tests and count coverage 6 | runs-on: ubuntu-latest 7 | strategy: 8 | matrix: 9 | python-version: ["3.12"] 10 | steps: 11 | - uses: actions/checkout@v4 12 | - name: Set up Python ${{ matrix.python-version }} 13 | uses: actions/setup-python@v5 14 | with: 15 | python-version: ${{ matrix.python-version }} 16 | - name: Install dependencies 17 | run: | 18 | python -m pip install --upgrade pip 19 | pip install pytest pytest-cov 20 | cd application 21 | if [ -f requirements.txt ]; then pip install -r requirements.txt; fi 22 | - name: Test with pytest and generate coverage report 23 | run: | 24 | python -m pytest --cov=application --cov-report=xml 25 | - name: Upload coverage reports to Codecov 26 | if: github.event_name == 'pull_request' && matrix.python-version == '3.12' 27 | uses: codecov/codecov-action@v5 28 | env: 29 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} 30 | 31 | -------------------------------------------------------------------------------- /.github/workflows/sync_fork.yaml: -------------------------------------------------------------------------------- 1 | name: Upstream Sync 2 | 3 | permissions: 4 | contents: write 5 | 6 | on: 7 | schedule: 8 | - cron: "0 0 * * *" # every hour 9 | workflow_dispatch: 10 | 11 | jobs: 12 | sync_latest_from_upstream: 13 | name: Sync latest commits from upstream repo 14 | runs-on: ubuntu-latest 15 | if: ${{ github.event.repository.fork }} 16 | 17 | steps: 18 | # Step 1: run a standard checkout action 19 | - name: Checkout target repo 20 | uses: actions/checkout@v4 21 | 22 | # Step 2: run the sync action 23 | - name: Sync upstream changes 24 | id: sync 25 | uses: aormsby/Fork-Sync-With-Upstream-action@v3.4 26 | with: 27 | # set your upstream repo and branch 28 | upstream_sync_repo: arc53/DocsGPT 29 | upstream_sync_branch: main 30 | target_sync_branch: main 31 | target_repo_token: ${{ secrets.GITHUB_TOKEN }} # automatically generated, no need to set 32 | 33 | # Set test_mode true to run tests instead of the true action!! 34 | test_mode: false 35 | 36 | - name: Sync check 37 | if: failure() 38 | run: | 39 | echo "::error::由于权限不足,导致同步失败(这是预期的行为),请前往仓库首页手动执行[Sync fork]。" 40 | echo "::error::Due to insufficient permissions, synchronization failed (as expected). Please go to the repository homepage and manually perform [Sync fork]." 41 | exit 1 -------------------------------------------------------------------------------- /.ruff.toml: -------------------------------------------------------------------------------- 1 | # Allow lines to be as long as 120 characters. 2 | line-length = 120 -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Docker Debug Frontend", 6 | "request": "launch", 7 | "type": "chrome", 8 | "preLaunchTask": "docker-compose: debug:frontend", 9 | "url": "http://127.0.0.1:5173", 10 | "webRoot": "${workspaceFolder}/frontend", 11 | "skipFiles": [ 12 | "/**" 13 | ] 14 | }, 15 | { 16 | "name": "Flask Debugger", 17 | "type": "debugpy", 18 | "request": "launch", 19 | "module": "flask", 20 | "env": { 21 | "FLASK_APP": "application/app.py", 22 | "PYTHONPATH": "${workspaceFolder}", 23 | "FLASK_ENV": "development", 24 | "FLASK_DEBUG": "1", 25 | "FLASK_RUN_PORT": "7091", 26 | "FLASK_RUN_HOST": "0.0.0.0" 27 | 28 | }, 29 | "args": [ 30 | "run", 31 | "--no-debugger" 32 | ], 33 | "cwd": "${workspaceFolder}", 34 | }, 35 | { 36 | "name": "Celery Debugger", 37 | "type": "debugpy", 38 | "request": "launch", 39 | "module": "celery", 40 | "env": { 41 | "PYTHONPATH": "${workspaceFolder}", 42 | }, 43 | "args": [ 44 | "-A", 45 | "application.app.celery", 46 | "worker", 47 | "-l", 48 | "INFO", 49 | "--pool=solo" 50 | ], 51 | "cwd": "${workspaceFolder}" 52 | } 53 | ] 54 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "type": "docker-compose", 6 | "label": "docker-compose: debug:frontend", 7 | "dockerCompose": { 8 | "up": { 9 | "detached": true, 10 | "services": [ 11 | "frontend" 12 | ], 13 | "build": true 14 | }, 15 | "files": [ 16 | "${workspaceFolder}/docker-compose.yaml" 17 | ] 18 | } 19 | } 20 | ] 21 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 arc53 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Supported Versions: 6 | 7 | Currently, we support security patches by committing changes and bumping the version published on Github. 8 | 9 | ## Reporting a Vulnerability 10 | 11 | Found a vulnerability? Please email us: 12 | 13 | security@arc53.com 14 | 15 | -------------------------------------------------------------------------------- /application/.env_sample: -------------------------------------------------------------------------------- 1 | API_KEY=your_api_key 2 | EMBEDDINGS_KEY=your_api_key 3 | API_URL=http://localhost:7091 4 | FLASK_APP=application/app.py 5 | FLASK_DEBUG=true 6 | 7 | #For OPENAI on Azure 8 | OPENAI_API_BASE= 9 | OPENAI_API_VERSION= 10 | AZURE_DEPLOYMENT_NAME= 11 | AZURE_EMBEDDINGS_DEPLOYMENT_NAME= -------------------------------------------------------------------------------- /application/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/application/__init__.py -------------------------------------------------------------------------------- /application/agents/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/application/agents/__init__.py -------------------------------------------------------------------------------- /application/agents/agent_creator.py: -------------------------------------------------------------------------------- 1 | from application.agents.classic_agent import ClassicAgent 2 | from application.agents.react_agent import ReActAgent 3 | 4 | 5 | class AgentCreator: 6 | agents = { 7 | "classic": ClassicAgent, 8 | "react": ReActAgent, 9 | } 10 | 11 | @classmethod 12 | def create_agent(cls, type, *args, **kwargs): 13 | agent_class = cls.agents.get(type.lower()) 14 | if not agent_class: 15 | raise ValueError(f"No agent class found for type {type}") 16 | return agent_class(*args, **kwargs) 17 | -------------------------------------------------------------------------------- /application/agents/tools/base.py: -------------------------------------------------------------------------------- 1 | from abc import ABC, abstractmethod 2 | 3 | 4 | class Tool(ABC): 5 | @abstractmethod 6 | def execute_action(self, action_name: str, **kwargs): 7 | pass 8 | 9 | @abstractmethod 10 | def get_actions_metadata(self): 11 | """ 12 | Returns a list of JSON objects describing the actions supported by the tool. 13 | """ 14 | pass 15 | 16 | @abstractmethod 17 | def get_config_requirements(self): 18 | """ 19 | Returns a dictionary describing the configuration requirements for the tool. 20 | """ 21 | pass 22 | -------------------------------------------------------------------------------- /application/agents/tools/tool_action_parser.py: -------------------------------------------------------------------------------- 1 | import json 2 | import logging 3 | 4 | logger = logging.getLogger(__name__) 5 | 6 | 7 | class ToolActionParser: 8 | def __init__(self, llm_type): 9 | self.llm_type = llm_type 10 | self.parsers = { 11 | "OpenAILLM": self._parse_openai_llm, 12 | "GoogleLLM": self._parse_google_llm, 13 | } 14 | 15 | def parse_args(self, call): 16 | parser = self.parsers.get(self.llm_type, self._parse_openai_llm) 17 | return parser(call) 18 | 19 | def _parse_openai_llm(self, call): 20 | if isinstance(call, dict): 21 | try: 22 | call_args = json.loads(call["function"]["arguments"]) 23 | tool_id = call["function"]["name"].split("_")[-1] 24 | action_name = call["function"]["name"].rsplit("_", 1)[0] 25 | except (KeyError, TypeError) as e: 26 | logger.error(f"Error parsing OpenAI LLM call: {e}") 27 | return None, None, None 28 | else: 29 | try: 30 | call_args = json.loads(call.function.arguments) 31 | tool_id = call.function.name.split("_")[-1] 32 | action_name = call.function.name.rsplit("_", 1)[0] 33 | except (AttributeError, TypeError) as e: 34 | logger.error(f"Error parsing OpenAI LLM call: {e}") 35 | return None, None, None 36 | return tool_id, action_name, call_args 37 | 38 | def _parse_google_llm(self, call): 39 | call_args = call.args 40 | tool_id = call.name.split("_")[-1] 41 | action_name = call.name.rsplit("_", 1)[0] 42 | return tool_id, action_name, call_args 43 | -------------------------------------------------------------------------------- /application/agents/tools/tool_manager.py: -------------------------------------------------------------------------------- 1 | import importlib 2 | import inspect 3 | import os 4 | import pkgutil 5 | 6 | from application.agents.tools.base import Tool 7 | 8 | 9 | class ToolManager: 10 | def __init__(self, config): 11 | self.config = config 12 | self.tools = {} 13 | self.load_tools() 14 | 15 | def load_tools(self): 16 | tools_dir = os.path.join(os.path.dirname(__file__)) 17 | for finder, name, ispkg in pkgutil.iter_modules([tools_dir]): 18 | if name == "base" or name.startswith("__"): 19 | continue 20 | module = importlib.import_module(f"application.agents.tools.{name}") 21 | for member_name, obj in inspect.getmembers(module, inspect.isclass): 22 | if issubclass(obj, Tool) and obj is not Tool: 23 | tool_config = self.config.get(name, {}) 24 | self.tools[name] = obj(tool_config) 25 | 26 | def load_tool(self, tool_name, tool_config): 27 | self.config[tool_name] = tool_config 28 | module = importlib.import_module(f"application.agents.tools.{tool_name}") 29 | for member_name, obj in inspect.getmembers(module, inspect.isclass): 30 | if issubclass(obj, Tool) and obj is not Tool: 31 | return obj(tool_config) 32 | 33 | def execute_action(self, tool_name, action_name, **kwargs): 34 | if tool_name not in self.tools: 35 | raise ValueError(f"Tool '{tool_name}' not loaded") 36 | return self.tools[tool_name].execute_action(action_name, **kwargs) 37 | 38 | def get_all_actions_metadata(self): 39 | metadata = [] 40 | for tool in self.tools.values(): 41 | metadata.extend(tool.get_actions_metadata()) 42 | return metadata 43 | -------------------------------------------------------------------------------- /application/api/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/application/api/__init__.py -------------------------------------------------------------------------------- /application/api/answer/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/application/api/answer/__init__.py -------------------------------------------------------------------------------- /application/api/internal/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/application/api/internal/__init__.py -------------------------------------------------------------------------------- /application/api/user/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/application/api/user/__init__.py -------------------------------------------------------------------------------- /application/api/user/tasks.py: -------------------------------------------------------------------------------- 1 | from datetime import timedelta 2 | 3 | from application.celery_init import celery 4 | from application.worker import ( 5 | agent_webhook_worker, 6 | attachment_worker, 7 | ingest_worker, 8 | remote_worker, 9 | sync_worker, 10 | ) 11 | 12 | 13 | @celery.task(bind=True) 14 | def ingest(self, directory, formats, name_job, filename, user): 15 | resp = ingest_worker(self, directory, formats, name_job, filename, user) 16 | return resp 17 | 18 | 19 | @celery.task(bind=True) 20 | def ingest_remote(self, source_data, job_name, user, loader): 21 | resp = remote_worker(self, source_data, job_name, user, loader) 22 | return resp 23 | 24 | 25 | @celery.task(bind=True) 26 | def schedule_syncs(self, frequency): 27 | resp = sync_worker(self, frequency) 28 | return resp 29 | 30 | 31 | @celery.task(bind=True) 32 | def store_attachment(self, file_info, user): 33 | resp = attachment_worker(self, file_info, user) 34 | return resp 35 | 36 | 37 | @celery.task(bind=True) 38 | def process_agent_webhook(self, agent_id, payload): 39 | resp = agent_webhook_worker(self, agent_id, payload) 40 | return resp 41 | 42 | 43 | @celery.on_after_configure.connect 44 | def setup_periodic_tasks(sender, **kwargs): 45 | sender.add_periodic_task( 46 | timedelta(days=1), 47 | schedule_syncs.s("daily"), 48 | ) 49 | sender.add_periodic_task( 50 | timedelta(weeks=1), 51 | schedule_syncs.s("weekly"), 52 | ) 53 | sender.add_periodic_task( 54 | timedelta(days=30), 55 | schedule_syncs.s("monthly"), 56 | ) 57 | -------------------------------------------------------------------------------- /application/auth.py: -------------------------------------------------------------------------------- 1 | from jose import jwt 2 | 3 | from application.core.settings import settings 4 | 5 | 6 | def handle_auth(request, data={}): 7 | if settings.AUTH_TYPE in ["simple_jwt", "session_jwt"]: 8 | jwt_token = request.headers.get("Authorization") 9 | if not jwt_token: 10 | return None 11 | 12 | jwt_token = jwt_token.replace("Bearer ", "") 13 | 14 | try: 15 | decoded_token = jwt.decode( 16 | jwt_token, 17 | settings.JWT_SECRET_KEY, 18 | algorithms=["HS256"], 19 | options={"verify_exp": False}, 20 | ) 21 | return decoded_token 22 | except Exception as e: 23 | return { 24 | "message": f"Authentication error: {str(e)}", 25 | "error": "invalid_token", 26 | } 27 | else: 28 | return {"sub": "local"} 29 | -------------------------------------------------------------------------------- /application/celery_init.py: -------------------------------------------------------------------------------- 1 | from celery import Celery 2 | from application.core.settings import settings 3 | from celery.signals import setup_logging 4 | 5 | 6 | def make_celery(app_name=__name__): 7 | celery = Celery( 8 | app_name, 9 | broker=settings.CELERY_BROKER_URL, 10 | backend=settings.CELERY_RESULT_BACKEND, 11 | ) 12 | celery.conf.update(settings) 13 | return celery 14 | 15 | 16 | @setup_logging.connect 17 | def config_loggers(*args, **kwargs): 18 | from application.core.logging_config import setup_logging 19 | 20 | setup_logging() 21 | 22 | 23 | celery = make_celery() 24 | -------------------------------------------------------------------------------- /application/celeryconfig.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | broker_url = os.getenv("CELERY_BROKER_URL") 4 | result_backend = os.getenv("CELERY_RESULT_BACKEND") 5 | 6 | task_serializer = 'json' 7 | result_serializer = 'json' 8 | accept_content = ['json'] 9 | -------------------------------------------------------------------------------- /application/core/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/application/core/__init__.py -------------------------------------------------------------------------------- /application/core/logging_config.py: -------------------------------------------------------------------------------- 1 | from logging.config import dictConfig 2 | 3 | def setup_logging(): 4 | dictConfig({ 5 | 'version': 1, 6 | 'formatters': { 7 | 'default': { 8 | 'format': '[%(asctime)s] %(levelname)s in %(module)s: %(message)s', 9 | } 10 | }, 11 | "handlers": { 12 | "console": { 13 | "class": "logging.StreamHandler", 14 | "stream": "ext://sys.stdout", 15 | "formatter": "default", 16 | } 17 | }, 18 | 'root': { 19 | 'level': 'INFO', 20 | 'handlers': ['console'], 21 | }, 22 | }) -------------------------------------------------------------------------------- /application/core/mongo_db.py: -------------------------------------------------------------------------------- 1 | from application.core.settings import settings 2 | from pymongo import MongoClient 3 | 4 | 5 | class MongoDB: 6 | _client = None 7 | 8 | @classmethod 9 | def get_client(cls): 10 | """ 11 | Get the MongoDB client instance, creating it if necessary. 12 | """ 13 | if cls._client is None: 14 | cls._client = MongoClient(settings.MONGO_URI) 15 | return cls._client 16 | 17 | @classmethod 18 | def close_client(cls): 19 | """ 20 | Close the MongoDB client connection. 21 | """ 22 | if cls._client is not None: 23 | cls._client.close() 24 | cls._client = None 25 | -------------------------------------------------------------------------------- /application/error.py: -------------------------------------------------------------------------------- 1 | from flask import jsonify 2 | from werkzeug.http import HTTP_STATUS_CODES 3 | 4 | 5 | def response_error(code_status, message=None): 6 | payload = {'error': HTTP_STATUS_CODES.get(code_status, "something went wrong")} 7 | if message: 8 | payload['message'] = message 9 | response = jsonify(payload) 10 | response.status_code = code_status 11 | return response 12 | 13 | 14 | def bad_request(status_code=400, message=''): 15 | return response_error(code_status=status_code, message=message) 16 | -------------------------------------------------------------------------------- /application/extensions.py: -------------------------------------------------------------------------------- 1 | from flask_restx import Api 2 | 3 | api = Api( 4 | version="1.0", 5 | title="DocsGPT API", 6 | description="API for DocsGPT", 7 | ) 8 | -------------------------------------------------------------------------------- /application/index.faiss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/application/index.faiss -------------------------------------------------------------------------------- /application/index.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/application/index.pkl -------------------------------------------------------------------------------- /application/llm/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/application/llm/__init__.py -------------------------------------------------------------------------------- /application/llm/groq.py: -------------------------------------------------------------------------------- 1 | from application.llm.base import BaseLLM 2 | from openai import OpenAI 3 | 4 | 5 | class GroqLLM(BaseLLM): 6 | def __init__(self, api_key=None, user_api_key=None, *args, **kwargs): 7 | super().__init__(*args, **kwargs) 8 | self.client = OpenAI(api_key=api_key, base_url="https://api.groq.com/openai/v1") 9 | self.api_key = api_key 10 | self.user_api_key = user_api_key 11 | 12 | def _raw_gen(self, baseself, model, messages, stream=False, tools=None, **kwargs): 13 | if tools: 14 | response = self.client.chat.completions.create( 15 | model=model, messages=messages, stream=stream, tools=tools, **kwargs 16 | ) 17 | return response.choices[0] 18 | else: 19 | response = self.client.chat.completions.create( 20 | model=model, messages=messages, stream=stream, **kwargs 21 | ) 22 | return response.choices[0].message.content 23 | 24 | def _raw_gen_stream( 25 | self, baseself, model, messages, stream=True, tools=None, **kwargs 26 | ): 27 | response = self.client.chat.completions.create( 28 | model=model, messages=messages, stream=stream, **kwargs 29 | ) 30 | for line in response: 31 | if line.choices[0].delta.content is not None: 32 | yield line.choices[0].delta.content 33 | -------------------------------------------------------------------------------- /application/llm/llm_creator.py: -------------------------------------------------------------------------------- 1 | from application.llm.groq import GroqLLM 2 | from application.llm.openai import OpenAILLM, AzureOpenAILLM 3 | from application.llm.sagemaker import SagemakerAPILLM 4 | from application.llm.huggingface import HuggingFaceLLM 5 | from application.llm.llama_cpp import LlamaCpp 6 | from application.llm.anthropic import AnthropicLLM 7 | from application.llm.docsgpt_provider import DocsGPTAPILLM 8 | from application.llm.premai import PremAILLM 9 | from application.llm.google_ai import GoogleLLM 10 | from application.llm.novita import NovitaLLM 11 | 12 | 13 | class LLMCreator: 14 | llms = { 15 | "openai": OpenAILLM, 16 | "azure_openai": AzureOpenAILLM, 17 | "sagemaker": SagemakerAPILLM, 18 | "huggingface": HuggingFaceLLM, 19 | "llama.cpp": LlamaCpp, 20 | "anthropic": AnthropicLLM, 21 | "docsgpt": DocsGPTAPILLM, 22 | "premai": PremAILLM, 23 | "groq": GroqLLM, 24 | "google": GoogleLLM, 25 | "novita": NovitaLLM, 26 | } 27 | 28 | @classmethod 29 | def create_llm(cls, type, api_key, user_api_key, decoded_token, *args, **kwargs): 30 | llm_class = cls.llms.get(type.lower()) 31 | if not llm_class: 32 | raise ValueError(f"No LLM class found for type {type}") 33 | return llm_class( 34 | api_key, user_api_key, decoded_token=decoded_token, *args, **kwargs 35 | ) 36 | -------------------------------------------------------------------------------- /application/llm/novita.py: -------------------------------------------------------------------------------- 1 | from application.llm.base import BaseLLM 2 | from openai import OpenAI 3 | 4 | 5 | class NovitaLLM(BaseLLM): 6 | def __init__(self, api_key=None, user_api_key=None, *args, **kwargs): 7 | super().__init__(*args, **kwargs) 8 | self.client = OpenAI(api_key=api_key, base_url="https://api.novita.ai/v3/openai") 9 | self.api_key = api_key 10 | self.user_api_key = user_api_key 11 | 12 | def _raw_gen(self, baseself, model, messages, stream=False, tools=None, **kwargs): 13 | if tools: 14 | response = self.client.chat.completions.create( 15 | model=model, messages=messages, stream=stream, tools=tools, **kwargs 16 | ) 17 | return response.choices[0] 18 | else: 19 | response = self.client.chat.completions.create( 20 | model=model, messages=messages, stream=stream, **kwargs 21 | ) 22 | return response.choices[0].message.content 23 | 24 | def _raw_gen_stream( 25 | self, baseself, model, messages, stream=True, tools=None, **kwargs 26 | ): 27 | response = self.client.chat.completions.create( 28 | model=model, messages=messages, stream=stream, **kwargs 29 | ) 30 | for line in response: 31 | if line.choices[0].delta.content is not None: 32 | yield line.choices[0].delta.content 33 | -------------------------------------------------------------------------------- /application/llm/premai.py: -------------------------------------------------------------------------------- 1 | from application.llm.base import BaseLLM 2 | from application.core.settings import settings 3 | 4 | 5 | class PremAILLM(BaseLLM): 6 | 7 | def __init__(self, api_key=None, user_api_key=None, *args, **kwargs): 8 | from premai import Prem 9 | 10 | super().__init__(*args, **kwargs) 11 | self.client = Prem(api_key=api_key) 12 | self.api_key = api_key 13 | self.user_api_key = user_api_key 14 | self.project_id = settings.PREMAI_PROJECT_ID 15 | 16 | def _raw_gen(self, baseself, model, messages, stream=False, **kwargs): 17 | response = self.client.chat.completions.create( 18 | model=model, 19 | project_id=self.project_id, 20 | messages=messages, 21 | stream=stream, 22 | **kwargs 23 | ) 24 | 25 | return response.choices[0].message["content"] 26 | 27 | def _raw_gen_stream(self, baseself, model, messages, stream=True, **kwargs): 28 | response = self.client.chat.completions.create( 29 | model=model, 30 | project_id=self.project_id, 31 | messages=messages, 32 | stream=stream, 33 | **kwargs 34 | ) 35 | 36 | for line in response: 37 | if line.choices[0].delta["content"] is not None: 38 | yield line.choices[0].delta["content"] 39 | -------------------------------------------------------------------------------- /application/parser/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /application/parser/file/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /application/parser/file/base.py: -------------------------------------------------------------------------------- 1 | """Base reader class.""" 2 | from abc import abstractmethod 3 | from typing import Any, List 4 | 5 | from langchain.docstore.document import Document as LCDocument 6 | from application.parser.schema.base import Document 7 | 8 | 9 | class BaseReader: 10 | """Utilities for loading data from a directory.""" 11 | 12 | @abstractmethod 13 | def load_data(self, *args: Any, **load_kwargs: Any) -> List[Document]: 14 | """Load data from the input directory.""" 15 | 16 | def load_langchain_documents(self, **load_kwargs: Any) -> List[LCDocument]: 17 | """Load data in LangChain document format.""" 18 | docs = self.load_data(**load_kwargs) 19 | return [d.to_langchain_format() for d in docs] 20 | -------------------------------------------------------------------------------- /application/parser/file/base_parser.py: -------------------------------------------------------------------------------- 1 | """Base parser and config class.""" 2 | 3 | from abc import abstractmethod 4 | from pathlib import Path 5 | from typing import Dict, List, Optional, Union 6 | 7 | 8 | class BaseParser: 9 | """Base class for all parsers.""" 10 | 11 | def __init__(self, parser_config: Optional[Dict] = None): 12 | """Init params.""" 13 | self._parser_config = parser_config 14 | 15 | def init_parser(self) -> None: 16 | """Init parser and store it.""" 17 | parser_config = self._init_parser() 18 | self._parser_config = parser_config 19 | 20 | @property 21 | def parser_config_set(self) -> bool: 22 | """Check if parser config is set.""" 23 | return self._parser_config is not None 24 | 25 | @property 26 | def parser_config(self) -> Dict: 27 | """Check if parser config is set.""" 28 | if self._parser_config is None: 29 | raise ValueError("Parser config not set.") 30 | return self._parser_config 31 | 32 | @abstractmethod 33 | def _init_parser(self) -> Dict: 34 | """Initialize the parser with the config.""" 35 | 36 | @abstractmethod 37 | def parse_file(self, file: Path, errors: str = "ignore") -> Union[str, List[str]]: 38 | """Parse file.""" 39 | -------------------------------------------------------------------------------- /application/parser/file/epub_parser.py: -------------------------------------------------------------------------------- 1 | """Epub parser. 2 | 3 | Contains parsers for epub files. 4 | """ 5 | 6 | from pathlib import Path 7 | from typing import Dict 8 | 9 | from application.parser.file.base_parser import BaseParser 10 | 11 | 12 | class EpubParser(BaseParser): 13 | """Epub Parser.""" 14 | 15 | def _init_parser(self) -> Dict: 16 | """Init parser.""" 17 | return {} 18 | 19 | def parse_file(self, file: Path, errors: str = "ignore") -> str: 20 | """Parse file.""" 21 | try: 22 | import ebooklib 23 | from ebooklib import epub 24 | except ImportError: 25 | raise ValueError("`EbookLib` is required to read Epub files.") 26 | try: 27 | import html2text 28 | except ImportError: 29 | raise ValueError("`html2text` is required to parse Epub files.") 30 | 31 | text_list = [] 32 | book = epub.read_epub(file, options={"ignore_ncx": True}) 33 | 34 | # Iterate through all chapters. 35 | for item in book.get_items(): 36 | # Chapters are typically located in epub documents items. 37 | if item.get_type() == ebooklib.ITEM_DOCUMENT: 38 | text_list.append( 39 | html2text.html2text(item.get_content().decode("utf-8")) 40 | ) 41 | 42 | text = "\n".join(text_list) 43 | return text 44 | -------------------------------------------------------------------------------- /application/parser/file/html_parser.py: -------------------------------------------------------------------------------- 1 | """HTML parser. 2 | 3 | Contains parser for html files. 4 | 5 | """ 6 | from pathlib import Path 7 | from typing import Dict, Union 8 | 9 | from application.parser.file.base_parser import BaseParser 10 | 11 | 12 | class HTMLParser(BaseParser): 13 | """HTML parser.""" 14 | 15 | def _init_parser(self) -> Dict: 16 | """Init parser.""" 17 | return {} 18 | 19 | def parse_file(self, file: Path, errors: str = "ignore") -> Union[str, list[str]]: 20 | from langchain_community.document_loaders import BSHTMLLoader 21 | 22 | loader = BSHTMLLoader(file) 23 | data = loader.load() 24 | return data 25 | -------------------------------------------------------------------------------- /application/parser/file/image_parser.py: -------------------------------------------------------------------------------- 1 | """Image parser. 2 | 3 | Contains parser for .png, .jpg, .jpeg files. 4 | 5 | """ 6 | from pathlib import Path 7 | import requests 8 | from typing import Dict, Union 9 | 10 | from application.parser.file.base_parser import BaseParser 11 | 12 | 13 | class ImageParser(BaseParser): 14 | """Image parser.""" 15 | 16 | def _init_parser(self) -> Dict: 17 | """Init parser.""" 18 | return {} 19 | 20 | def parse_file(self, file: Path, errors: str = "ignore") -> Union[str, list[str]]: 21 | doc2md_service = "https://llm.arc53.com/doc2md" 22 | # alternatively you can use local vision capable LLM 23 | with open(file, "rb") as file_loaded: 24 | files = {'file': file_loaded} 25 | response = requests.post(doc2md_service, files=files) 26 | data = response.json()["markdown"] 27 | return data 28 | -------------------------------------------------------------------------------- /application/parser/remote/base.py: -------------------------------------------------------------------------------- 1 | """Base reader class.""" 2 | from abc import abstractmethod 3 | from typing import Any, List 4 | 5 | from langchain.docstore.document import Document as LCDocument 6 | from application.parser.schema.base import Document 7 | 8 | 9 | class BaseRemote: 10 | """Utilities for loading data from a directory.""" 11 | 12 | @abstractmethod 13 | def load_data(self, *args: Any, **load_kwargs: Any) -> List[Document]: 14 | """Load data from the input directory.""" 15 | 16 | def load_langchain_documents(self, **load_kwargs: Any) -> List[LCDocument]: 17 | """Load data in LangChain document format.""" 18 | docs = self.load_data(**load_kwargs) 19 | return [d.to_langchain_format() for d in docs] 20 | -------------------------------------------------------------------------------- /application/parser/remote/reddit_loader.py: -------------------------------------------------------------------------------- 1 | from application.parser.remote.base import BaseRemote 2 | from langchain_community.document_loaders import RedditPostsLoader 3 | import json 4 | 5 | 6 | class RedditPostsLoaderRemote(BaseRemote): 7 | def load_data(self, inputs): 8 | try: 9 | data = json.loads(inputs) 10 | except json.JSONDecodeError as e: 11 | raise ValueError(f"Invalid JSON input: {e}") 12 | 13 | required_fields = ["client_id", "client_secret", "user_agent", "search_queries"] 14 | missing_fields = [field for field in required_fields if field not in data] 15 | if missing_fields: 16 | raise ValueError(f"Missing required fields: {', '.join(missing_fields)}") 17 | client_id = data.get("client_id") 18 | client_secret = data.get("client_secret") 19 | user_agent = data.get("user_agent") 20 | categories = data.get("categories", ["new", "hot"]) 21 | mode = data.get("mode", "subreddit") 22 | search_queries = data.get("search_queries") 23 | number_posts = data.get("number_posts", 10) 24 | self.loader = RedditPostsLoader( 25 | client_id=client_id, 26 | client_secret=client_secret, 27 | user_agent=user_agent, 28 | categories=categories, 29 | mode=mode, 30 | search_queries=search_queries, 31 | number_posts=number_posts, 32 | ) 33 | documents = self.loader.load() 34 | print(f"Loaded {len(documents)} documents from Reddit") 35 | return documents 36 | -------------------------------------------------------------------------------- /application/parser/remote/remote_creator.py: -------------------------------------------------------------------------------- 1 | from application.parser.remote.sitemap_loader import SitemapLoader 2 | from application.parser.remote.crawler_loader import CrawlerLoader 3 | from application.parser.remote.web_loader import WebLoader 4 | from application.parser.remote.reddit_loader import RedditPostsLoaderRemote 5 | from application.parser.remote.github_loader import GitHubLoader 6 | 7 | 8 | class RemoteCreator: 9 | loaders = { 10 | "url": WebLoader, 11 | "sitemap": SitemapLoader, 12 | "crawler": CrawlerLoader, 13 | "reddit": RedditPostsLoaderRemote, 14 | "github": GitHubLoader, 15 | } 16 | 17 | @classmethod 18 | def create_loader(cls, type, *args, **kwargs): 19 | loader_class = cls.loaders.get(type.lower()) 20 | if not loader_class: 21 | raise ValueError(f"No LLM class found for type {type}") 22 | return loader_class(*args, **kwargs) 23 | -------------------------------------------------------------------------------- /application/parser/remote/telegram.py: -------------------------------------------------------------------------------- 1 | from langchain.document_loader import TelegramChatApiLoader 2 | from application.parser.remote.base import BaseRemote 3 | 4 | class TelegramChatApiRemote(BaseRemote): 5 | def _init_parser(self, *args, **load_kwargs): 6 | self.loader = TelegramChatApiLoader(**load_kwargs) 7 | return {} 8 | 9 | def parse_file(self, *args, **load_kwargs): 10 | 11 | return -------------------------------------------------------------------------------- /application/parser/remote/web_loader.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from application.parser.remote.base import BaseRemote 3 | from application.parser.schema.base import Document 4 | from langchain_community.document_loaders import WebBaseLoader 5 | from urllib.parse import urlparse 6 | 7 | headers = { 8 | "User-Agent": "Mozilla/5.0", 9 | "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*" 10 | ";q=0.8", 11 | "Accept-Language": "en-US,en;q=0.5", 12 | "Referer": "https://www.google.com/", 13 | "DNT": "1", 14 | "Connection": "keep-alive", 15 | "Upgrade-Insecure-Requests": "1", 16 | } 17 | 18 | 19 | class WebLoader(BaseRemote): 20 | def __init__(self): 21 | self.loader = WebBaseLoader 22 | 23 | def load_data(self, inputs): 24 | urls = inputs 25 | if isinstance(urls, str): 26 | urls = [urls] 27 | documents = [] 28 | for url in urls: 29 | # Check if the URL scheme is provided, if not, assume http 30 | if not urlparse(url).scheme: 31 | url = "http://" + url 32 | try: 33 | loader = self.loader([url], header_template=headers) 34 | loaded_docs = loader.load() 35 | for doc in loaded_docs: 36 | documents.append( 37 | Document( 38 | doc.page_content, 39 | extra_info=doc.metadata, 40 | ) 41 | ) 42 | except Exception as e: 43 | logging.error(f"Error processing URL {url}: {e}", exc_info=True) 44 | continue 45 | return documents 46 | -------------------------------------------------------------------------------- /application/parser/schema/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /application/parser/schema/base.py: -------------------------------------------------------------------------------- 1 | """Base schema for readers.""" 2 | from dataclasses import dataclass 3 | 4 | from langchain.docstore.document import Document as LCDocument 5 | from application.parser.schema.schema import BaseDocument 6 | 7 | 8 | @dataclass 9 | class Document(BaseDocument): 10 | """Generic interface for a data document. 11 | 12 | This document connects to data sources. 13 | 14 | """ 15 | 16 | def __post_init__(self) -> None: 17 | """Post init.""" 18 | if self.text is None: 19 | raise ValueError("text field not set.") 20 | 21 | @classmethod 22 | def get_type(cls) -> str: 23 | """Get Document type.""" 24 | return "Document" 25 | 26 | def to_langchain_format(self) -> LCDocument: 27 | """Convert struct to LangChain document format.""" 28 | metadata = self.extra_info or {} 29 | return LCDocument(page_content=self.text, metadata=metadata) 30 | 31 | @classmethod 32 | def from_langchain_format(cls, doc: LCDocument) -> "Document": 33 | """Convert struct from LangChain document format.""" 34 | return cls(text=doc.page_content, extra_info=doc.metadata) 35 | -------------------------------------------------------------------------------- /application/prompts/chat_combine_creative.txt: -------------------------------------------------------------------------------- 1 | You are a helpful AI assistant, DocsGPT. You are proactive and helpful. Try to use tools, if they are available to you, 2 | be proactive and fill in missing information. 3 | Users can Upload documents for your context as attachments or sources via UI using the Conversation input box. 4 | If appropriate, your answers can include code examples, formatted as follows: 5 | ```(language) 6 | (code) 7 | ``` 8 | Users are also able to see charts and diagrams if you use them with valid mermaid syntax in your responses. 9 | Try to respond with mermaid charts if visualization helps with users queries. 10 | You effectively utilize chat history, ensuring relevant and tailored responses. 11 | Try to use additional provided context if it's available, otherwise use your knowledge and tool capabilities. 12 | Allow yourself to be very creative and use your imagination. 13 | ---------------- 14 | Possible additional context from uploaded sources: 15 | {summaries} -------------------------------------------------------------------------------- /application/prompts/chat_combine_default.txt: -------------------------------------------------------------------------------- 1 | You are a helpful AI assistant, DocsGPT. You are proactive and helpful. Try to use tools, if they are available to you, 2 | be proactive and fill in missing information. 3 | Users can Upload documents for your context as attachments or sources via UI using the Conversation input box. 4 | If appropriate, your answers can include code examples, formatted as follows: 5 | ```(language) 6 | (code) 7 | ``` 8 | Users are also able to see charts and diagrams if you use them with valid mermaid syntax in your responses. 9 | Try to respond with mermaid charts if visualization helps with users queries. 10 | You effectively utilize chat history, ensuring relevant and tailored responses. 11 | Try to use additional provided context if it's available, otherwise use your knowledge and tool capabilities. 12 | ---------------- 13 | Possible additional context from uploaded sources: 14 | {summaries} -------------------------------------------------------------------------------- /application/prompts/chat_combine_strict.txt: -------------------------------------------------------------------------------- 1 | You are a helpful AI assistant, DocsGPT. You are proactive and helpful. Try to use tools, if they are available to you, 2 | be proactive and fill in missing information. 3 | Users can Upload documents for your context as attachments or sources via UI using the Conversation input box. 4 | If appropriate, your answers can include code examples, formatted as follows: 5 | ```(language) 6 | (code) 7 | ``` 8 | Users are also able to see charts and diagrams if you use them with valid mermaid syntax in your responses. 9 | Try to respond with mermaid charts if visualization helps with users queries. 10 | You effectively utilize chat history, ensuring relevant and tailored responses. 11 | Use context provided below or use available tools tool capabilities to answer user queries. 12 | If you dont have enough information from the context or tools, answer "I don't know" or "I don't have enough information". 13 | Never make up information or provide false information! 14 | Allow yourself to be very creative and use your imagination. 15 | ---------------- 16 | Context from uploaded sources: 17 | {summaries} -------------------------------------------------------------------------------- /application/prompts/chat_reduce_prompt.txt: -------------------------------------------------------------------------------- 1 | Use the following pieces of context to help answer the users question. If its not relevant to the question, respond with "-" 2 | ---------------- 3 | {context} -------------------------------------------------------------------------------- /application/prompts/react_final_prompt.txt: -------------------------------------------------------------------------------- 1 | Query: {query} 2 | Observations: {observations} 3 | Now, using the insights from the observations, formulate a well-structured and precise final answer. -------------------------------------------------------------------------------- /application/prompts/react_planning_prompt.txt: -------------------------------------------------------------------------------- 1 | You are an AI assistant and talk like you're thinking out loud. Given the following query, outline a concise thought process that includes key steps and considerations necessary for effective analysis and response. Avoid pointwise formatting. The goal is to break down the query into manageable components without excessive detail, focusing on clarity and logical progression. 2 | 3 | Include the following elements in your thought and execution process: 4 | 1. Identify the main objective of the query. 5 | 2. Determine any relevant context or background information needed to understand the query. 6 | 3. List potential approaches or methods to address the query. 7 | 4. Highlight any critical factors or constraints that may influence the outcome. 8 | 5. Plan with available tools to help you with the analysis but dont execute them. Tools will be executed by another AI. 9 | 10 | Query: {query} 11 | Summaries: {summaries} 12 | Prompt: {prompt} 13 | Observations(potentially previous tool calls): {observations} 14 | -------------------------------------------------------------------------------- /application/retriever/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/application/retriever/__init__.py -------------------------------------------------------------------------------- /application/retriever/base.py: -------------------------------------------------------------------------------- 1 | from abc import ABC, abstractmethod 2 | 3 | 4 | class BaseRetriever(ABC): 5 | def __init__(self): 6 | pass 7 | 8 | @abstractmethod 9 | def gen(self, *args, **kwargs): 10 | pass 11 | 12 | @abstractmethod 13 | def search(self, *args, **kwargs): 14 | pass 15 | 16 | @abstractmethod 17 | def get_params(self): 18 | pass 19 | -------------------------------------------------------------------------------- /application/retriever/retriever_creator.py: -------------------------------------------------------------------------------- 1 | from application.retriever.classic_rag import ClassicRAG 2 | from application.retriever.duckduck_search import DuckDuckSearch 3 | from application.retriever.brave_search import BraveRetSearch 4 | 5 | 6 | 7 | class RetrieverCreator: 8 | retrievers = { 9 | 'classic': ClassicRAG, 10 | 'duckduck_search': DuckDuckSearch, 11 | 'brave_search': BraveRetSearch, 12 | 'default': ClassicRAG 13 | } 14 | 15 | @classmethod 16 | def create_retriever(cls, type, *args, **kwargs): 17 | retiever_class = cls.retrievers.get(type.lower()) 18 | if not retiever_class: 19 | raise ValueError(f"No retievers class found for type {type}") 20 | return retiever_class(*args, **kwargs) -------------------------------------------------------------------------------- /application/storage/storage_creator.py: -------------------------------------------------------------------------------- 1 | """Storage factory for creating different storage implementations.""" 2 | from typing import Dict, Type 3 | 4 | from application.storage.base import BaseStorage 5 | from application.storage.local import LocalStorage 6 | from application.storage.s3 import S3Storage 7 | from application.core.settings import settings 8 | 9 | 10 | class StorageCreator: 11 | storages: Dict[str, Type[BaseStorage]] = { 12 | "local": LocalStorage, 13 | "s3": S3Storage, 14 | } 15 | 16 | _instance = None 17 | 18 | @classmethod 19 | def get_storage(cls) -> BaseStorage: 20 | if cls._instance is None: 21 | storage_type = getattr(settings, "STORAGE_TYPE", "local") 22 | cls._instance = cls.create_storage(storage_type) 23 | 24 | return cls._instance 25 | 26 | @classmethod 27 | def create_storage(cls, type_name: str, *args, **kwargs) -> BaseStorage: 28 | storage_class = cls.storages.get(type_name.lower()) 29 | if not storage_class: 30 | raise ValueError(f"No storage implementation found for type {type_name}") 31 | 32 | return storage_class(*args, **kwargs) 33 | -------------------------------------------------------------------------------- /application/tts/base.py: -------------------------------------------------------------------------------- 1 | from abc import ABC, abstractmethod 2 | 3 | 4 | class BaseTTS(ABC): 5 | def __init__(self): 6 | pass 7 | 8 | @abstractmethod 9 | def text_to_speech(self, *args, **kwargs): 10 | pass -------------------------------------------------------------------------------- /application/tts/google_tts.py: -------------------------------------------------------------------------------- 1 | import io 2 | import base64 3 | from gtts import gTTS 4 | from application.tts.base import BaseTTS 5 | 6 | 7 | class GoogleTTS(BaseTTS): 8 | def __init__(self): 9 | pass 10 | 11 | 12 | def text_to_speech(self, text): 13 | lang = "en" 14 | audio_fp = io.BytesIO() 15 | tts = gTTS(text=text, lang=lang, slow=False) 16 | tts.write_to_fp(audio_fp) 17 | audio_fp.seek(0) 18 | audio_base64 = base64.b64encode(audio_fp.read()).decode("utf-8") 19 | return audio_base64, lang 20 | -------------------------------------------------------------------------------- /application/vectorstore/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/application/vectorstore/__init__.py -------------------------------------------------------------------------------- /application/vectorstore/document_class.py: -------------------------------------------------------------------------------- 1 | class Document(str): 2 | """Class for storing a piece of text and associated metadata.""" 3 | 4 | def __new__(cls, page_content: str, metadata: dict): 5 | instance = super().__new__(cls, page_content) 6 | instance.page_content = page_content 7 | instance.metadata = metadata 8 | return instance 9 | -------------------------------------------------------------------------------- /application/vectorstore/milvus.py: -------------------------------------------------------------------------------- 1 | from typing import List, Optional 2 | from uuid import uuid4 3 | 4 | 5 | from application.core.settings import settings 6 | from application.vectorstore.base import BaseVectorStore 7 | 8 | 9 | class MilvusStore(BaseVectorStore): 10 | def __init__(self, source_id: str = "", embeddings_key: str = "embeddings"): 11 | super().__init__() 12 | from langchain_milvus import Milvus 13 | 14 | connection_args = { 15 | "uri": settings.MILVUS_URI, 16 | "token": settings.MILVUS_TOKEN, 17 | } 18 | self._docsearch = Milvus( 19 | embedding_function=self._get_embeddings(settings.EMBEDDINGS_NAME, embeddings_key), 20 | collection_name=settings.MILVUS_COLLECTION_NAME, 21 | connection_args=connection_args, 22 | ) 23 | self._source_id = source_id 24 | 25 | def search(self, question, k=2, *args, **kwargs): 26 | expr = f"source_id == '{self._source_id}'" 27 | return self._docsearch.similarity_search(query=question, k=k, expr=expr, *args, **kwargs) 28 | 29 | def add_texts(self, texts: List[str], metadatas: Optional[List[dict]], *args, **kwargs): 30 | ids = [str(uuid4()) for _ in range(len(texts))] 31 | 32 | return self._docsearch.add_texts(texts=texts, metadatas=metadatas, ids=ids, *args, **kwargs) 33 | 34 | def save_local(self, *args, **kwargs): 35 | pass 36 | 37 | def delete_index(self, *args, **kwargs): 38 | pass 39 | -------------------------------------------------------------------------------- /application/vectorstore/vector_creator.py: -------------------------------------------------------------------------------- 1 | from application.vectorstore.faiss import FaissStore 2 | from application.vectorstore.elasticsearch import ElasticsearchStore 3 | from application.vectorstore.milvus import MilvusStore 4 | from application.vectorstore.mongodb import MongoDBVectorStore 5 | from application.vectorstore.qdrant import QdrantStore 6 | 7 | 8 | class VectorCreator: 9 | vectorstores = { 10 | "faiss": FaissStore, 11 | "elasticsearch": ElasticsearchStore, 12 | "mongodb": MongoDBVectorStore, 13 | "qdrant": QdrantStore, 14 | "milvus": MilvusStore, 15 | } 16 | 17 | @classmethod 18 | def create_vectorstore(cls, type, *args, **kwargs): 19 | vectorstore_class = cls.vectorstores.get(type.lower()) 20 | if not vectorstore_class: 21 | raise ValueError(f"No vectorstore class found for type {type}") 22 | return vectorstore_class(*args, **kwargs) 23 | -------------------------------------------------------------------------------- /application/wsgi.py: -------------------------------------------------------------------------------- 1 | from application.app import app 2 | from application.core.settings import settings 3 | 4 | if __name__ == "__main__": 5 | app.run(debug=settings.FLASK_DEBUG_MODE, port=7091) 6 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | ignore: 2 | - "*/tests/*" -------------------------------------------------------------------------------- /deployment/docker-compose-dev.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | 3 | redis: 4 | image: redis:6-alpine 5 | ports: 6 | - 6379:6379 7 | 8 | mongo: 9 | image: mongo:6 10 | ports: 11 | - 27017:27017 12 | volumes: 13 | - mongodb_data_container:/data/db 14 | 15 | 16 | 17 | volumes: 18 | mongodb_data_container: -------------------------------------------------------------------------------- /deployment/docker-compose-local.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | frontend: 3 | build: ../frontend 4 | volumes: 5 | - ../frontend/src:/app/src 6 | environment: 7 | - VITE_API_HOST=http://localhost:7091 8 | - VITE_API_STREAMING=$VITE_API_STREAMING 9 | - VITE_EMBEDDINGS_NAME=$EMBEDDINGS_NAME 10 | ports: 11 | - "5173:5173" 12 | 13 | redis: 14 | image: redis:6-alpine 15 | ports: 16 | - 6379:6379 17 | 18 | mongo: 19 | image: mongo:6 20 | ports: 21 | - 27017:27017 22 | volumes: 23 | - mongodb_data_container:/data/db 24 | 25 | volumes: 26 | mongodb_data_container: 27 | -------------------------------------------------------------------------------- /deployment/k8s/deployments/mongo-deploy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolumeClaim 3 | metadata: 4 | name: mongodb-pvc 5 | spec: 6 | accessModes: 7 | - ReadWriteOnce 8 | resources: 9 | requests: 10 | storage: 10Gi # Adjust size as needed 11 | 12 | --- 13 | 14 | apiVersion: apps/v1 15 | kind: Deployment 16 | metadata: 17 | name: mongodb 18 | spec: 19 | replicas: 1 20 | selector: 21 | matchLabels: 22 | app: mongodb 23 | template: 24 | metadata: 25 | labels: 26 | app: mongodb 27 | spec: 28 | containers: 29 | - name: mongodb 30 | image: mongo:latest 31 | ports: 32 | - containerPort: 27017 33 | resources: 34 | limits: 35 | memory: "1Gi" 36 | cpu: "0.5" 37 | requests: 38 | memory: "512Mi" 39 | cpu: "250m" 40 | volumeMounts: 41 | - name: mongodb-data 42 | mountPath: /data/db 43 | volumes: 44 | - name: mongodb-data 45 | persistentVolumeClaim: 46 | claimName: mongodb-pvc -------------------------------------------------------------------------------- /deployment/k8s/deployments/qdrant-deploy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolumeClaim 3 | metadata: 4 | name: qdrant-pvc 5 | spec: 6 | accessModes: 7 | - ReadWriteOnce 8 | resources: 9 | requests: 10 | storage: 10Gi 11 | 12 | --- 13 | 14 | apiVersion: apps/v1 15 | kind: Deployment 16 | metadata: 17 | name: qdrant 18 | spec: 19 | replicas: 1 20 | selector: 21 | matchLabels: 22 | app: qdrant 23 | template: 24 | metadata: 25 | labels: 26 | app: qdrant 27 | spec: 28 | containers: 29 | - name: qdrant 30 | image: qdrant/qdrant:latest 31 | ports: 32 | - containerPort: 6333 33 | resources: 34 | limits: 35 | memory: "2Gi" # Adjust based on your needs 36 | cpu: "1" # Adjust based on your needs 37 | requests: 38 | memory: "1Gi" # Adjust based on your needs 39 | cpu: "500m" # Adjust based on your needs 40 | volumeMounts: 41 | - name: qdrant-data 42 | mountPath: /qdrant/storage 43 | volumes: 44 | - name: qdrant-data 45 | persistentVolumeClaim: 46 | claimName: qdrant-pvc -------------------------------------------------------------------------------- /deployment/k8s/deployments/redis-deploy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: redis 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: redis 10 | template: 11 | metadata: 12 | labels: 13 | app: redis 14 | spec: 15 | containers: 16 | - name: redis 17 | image: redis:latest 18 | ports: 19 | - containerPort: 6379 20 | resources: 21 | limits: 22 | memory: "1Gi" 23 | cpu: "0.5" 24 | requests: 25 | memory: "512Mi" 26 | cpu: "250m" -------------------------------------------------------------------------------- /deployment/k8s/docsgpt-secrets.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: docsgpt-secrets 5 | type: Opaque 6 | data: 7 | LLM_NAME: ZG9jc2dwdA== 8 | INTERNAL_KEY: aW50ZXJuYWw= 9 | CELERY_BROKER_URL: cmVkaXM6Ly9yZWRpcy1zZXJ2aWNlOjYzNzkvMA== 10 | CELERY_RESULT_BACKEND: cmVkaXM6Ly9yZWRpcy1zZXJ2aWNlOjYzNzkvMA== 11 | QDRANT_URL: cmVkaXM6Ly9yZWRpcy1zZXJ2aWNlOjYzNzkvMA== 12 | QDRANT_PORT: NjM3OQ== 13 | MONGO_URI: bW9uZ29kYjovL21vbmdvZGItc2VydmljZToyNzAxNy9kb2NzZ3B0P3JldHJ5V3JpdGVzPXRydWUmdz1tYWpvcml0eQ== 14 | mongo-user: bW9uZ28tdXNlcg== 15 | mongo-password: bW9uZ28tcGFzc3dvcmQ= -------------------------------------------------------------------------------- /deployment/k8s/services/docsgpt-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: docsgpt-api-service 5 | spec: 6 | selector: 7 | app: docsgpt-api 8 | ports: 9 | - protocol: TCP 10 | port: 80 11 | targetPort: 7091 12 | type: LoadBalancer 13 | --- 14 | apiVersion: v1 15 | kind: Service 16 | metadata: 17 | name: docsgpt-frontend-service 18 | spec: 19 | selector: 20 | app: docsgpt-frontend 21 | ports: 22 | - protocol: TCP 23 | port: 80 24 | targetPort: 5173 25 | type: LoadBalancer -------------------------------------------------------------------------------- /deployment/k8s/services/mongo-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: mongodb-service 5 | spec: 6 | selector: 7 | app: mongodb 8 | ports: 9 | - protocol: TCP 10 | port: 27017 11 | targetPort: 27017 12 | type: ClusterIP -------------------------------------------------------------------------------- /deployment/k8s/services/qdrant-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: qdrant 5 | spec: 6 | selector: 7 | app: qdrant 8 | ports: 9 | - protocol: TCP 10 | port: 6333 11 | targetPort: 6333 12 | type: ClusterIP -------------------------------------------------------------------------------- /deployment/k8s/services/redis-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: redis-service 5 | spec: 6 | selector: 7 | app: redis 8 | ports: 9 | - protocol: TCP 10 | port: 6379 11 | targetPort: 6379 12 | type: ClusterIP -------------------------------------------------------------------------------- /deployment/optional/docker-compose.optional.ollama-cpu.yaml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | services: 3 | ollama: 4 | image: ollama/ollama 5 | ports: 6 | - "11434:11434" 7 | volumes: 8 | - ollama_data:/root/.ollama 9 | 10 | volumes: 11 | ollama_data: -------------------------------------------------------------------------------- /deployment/optional/docker-compose.optional.ollama-gpu.yaml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | services: 3 | ollama: 4 | image: ollama/ollama 5 | ports: 6 | - "11434:11434" 7 | volumes: 8 | - ollama_data:/root/.ollama 9 | deploy: 10 | resources: 11 | reservations: 12 | devices: 13 | - capabilities: [gpu] 14 | 15 | volumes: 16 | ollama_data: -------------------------------------------------------------------------------- /docs/next.config.js: -------------------------------------------------------------------------------- 1 | const withNextra = require('nextra')({ 2 | theme: 'nextra-theme-docs', 3 | themeConfig: './theme.config.jsx' 4 | }) 5 | 6 | module.exports = withNextra() 7 | 8 | // If you have other Next.js configurations, you can pass them as the parameter: 9 | // module.exports = withNextra({ /* other next.js config */ }) 10 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "dev": "next dev", 4 | "build": "next build", 5 | "start": "next start" 6 | }, 7 | "license": "MIT", 8 | "dependencies": { 9 | "@vercel/analytics": "^1.1.1", 10 | "docsgpt-react": "^0.5.1", 11 | "next": "^15.3.3", 12 | "nextra": "^2.13.2", 13 | "nextra-theme-docs": "^2.13.2", 14 | "react": "^18.2.0", 15 | "react-dom": "^18.2.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /docs/pages/Agents/_meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "basics": { 3 | "title": "🤖 Agent Basics", 4 | "href": "/Agents/basics" 5 | } 6 | } -------------------------------------------------------------------------------- /docs/pages/Deploying/Hosting-the-app.mdx: -------------------------------------------------------------------------------- 1 | import { DeploymentCards } from '../../components/DeploymentCards'; 2 | 3 | # Deployment Guides 4 | 5 | 34 | -------------------------------------------------------------------------------- /docs/pages/Deploying/_meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "DocsGPT-Settings": { 3 | "title": "⚙️ App Configuration", 4 | "href": "/Deploying/DocsGPT-Settings" 5 | }, 6 | "Docker-Deploying": { 7 | "title": "🛳️ Docker Setup", 8 | "href": "/Deploying/Docker-Deploying" 9 | }, 10 | "Development-Environment": { 11 | "title": "🛠️Development Environment", 12 | "href": "/Deploying/Development-Environment" 13 | }, 14 | "Kubernetes-Deploying": { 15 | "title": "☸️ Deploying on Kubernetes", 16 | "href": "/Deploying/Kubernetes-Deploying" 17 | }, 18 | "Hosting-the-app": { 19 | "title": "☁️ Hosting DocsGPT", 20 | "href": "/Deploying/Hosting-the-app" 21 | }, 22 | "Amazon-Lightsail": { 23 | "title": "Hosting DocsGPT on Amazon Lightsail", 24 | "href": "/Deploying/Amazon-Lightsail", 25 | "display": "hidden" 26 | }, 27 | "Railway": { 28 | "title": "Hosting DocsGPT on Railway", 29 | "href": "/Deploying/Railway", 30 | "display": "hidden" 31 | } 32 | } -------------------------------------------------------------------------------- /docs/pages/Extensions/Chrome-extension.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Add DocsGPT Chrome Extension to Your Browser 3 | description: Install the DocsGPT Chrome extension to access AI-powered document assistance directly from your browser for enhanced productivity. 4 | --- 5 | 6 | import {Steps} from 'nextra/components' 7 | import { Callout } from 'nextra/components' 8 | 9 | 10 | ## Chrome Extension Setup Guide 11 | 12 | To enhance your DocsGPT experience, you can install the DocsGPT Chrome extension. Here's how: 13 | 14 | ### Step 1 15 | 16 | 17 | 18 | In the DocsGPT GitHub repository, click on the **Code** button and select **Download ZIP**. 19 | ### Step 2 20 | Unzip the downloaded file to a location you can easily access. 21 | ### Step 3 22 | Open the Google Chrome browser and click on the three dots menu (upper right corner). 23 | ### Step 4 24 | Select **More Tools** and then **Extensions**. 25 | ### Step 5 26 | Turn on the **Developer mode** switch in the top right corner of the **Extensions page**. 27 | ### Step 6 28 | Click on the **Load unpacked** button. 29 | ### Step 7 30 | 7. Select the **Chrome** folder where the DocsGPT files have been unzipped (docsgpt-main > extensions > chrome). 31 | ### Step 8 32 | The extension should now be added to Google Chrome and can be managed on the Extensions page. 33 | ### Step 9 34 | To disable or remove the extension, simply turn off the toggle switch on the extension card or click the **Remove** button. 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /docs/pages/Extensions/_meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "api-key-guide": { 3 | "title": "🔑 Getting API key", 4 | "href": "/Extensions/api-key-guide" 5 | }, 6 | "chat-widget": { 7 | "title": "💬️ Chat Widget", 8 | "href": "/Extensions/chat-widget" 9 | }, 10 | "search-widget": { 11 | "title": "🔎 Search Widget", 12 | "href": "/Extensions/search-widget" 13 | }, 14 | "Chrome-extension": { 15 | "title": "🌐 Chrome Extension", 16 | "href": "/Extensions/Chrome-extension" 17 | }, 18 | "Chatwoot-extension": { 19 | "title": "🗣️ Chatwoot Extension", 20 | "href": "/Extensions/Chatwoot-extension" 21 | } 22 | } -------------------------------------------------------------------------------- /docs/pages/Guides/How-to-use-different-LLM.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 3 | description: 4 | --- 5 | 6 | import { Callout } from 'nextra/components' 7 | import Image from 'next/image' 8 | import { Steps } from 'nextra/components' 9 | 10 | # Setting Up Local Language Models for Your App 11 | 12 | Setting up local language models for your app can significantly enhance its capabilities, enabling it to understand and generate text in multiple languages without relying on external APIs. By integrating local language models, you can improve privacy, reduce latency, and ensure continuous functionality even in offline environments. Here's a comprehensive guide on how to set up local language models for your application: 13 | 14 | ## Steps: 15 | ### For cloud version LLM change: 16 | 17 | ### Step 1 18 | Visit the chat screen and you will be to see the default LLM selected. 19 | ### Step 2 20 | Click on it and you will get a drop down of various LLM's available to choose. 21 | ### Step 3 22 | Choose the LLM of your choice. 23 | 24 | 25 | 26 | 27 | 28 | 29 | ### Video Demo 30 | prompts 31 | 32 | ### For Open source llm change: 33 | 34 | ### Step 1 35 | For open source version please edit `LLM_NAME`, `MODEL_NAME` and others in the .env file. Refer to [⚙️ App Configuration](/Deploying/DocsGPT-Settings) for more information. 36 | ### Step 2 37 | Visit [☁️ Cloud Providers](/Models/cloud-providers) for the updated list of online models. Make sure you have the right API_KEY and correct LLM_NAME. 38 | For self-hosted please visit [🖥️ Local Inference](/Models/local-inference). 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /docs/pages/Guides/My-AI-answers-questions-using-external-knowledge.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 3 | description: 4 | --- 5 | 6 | # Avoiding hallucinations 7 | 8 | If your AI uses external knowledge and is not explicit enough, it is ok, because we try to make DocsGPT friendly. 9 | 10 | But if you want to adjust it, here is a simple way:- 11 | 12 | - Got to `application/prompts/chat_combine_prompt.txt` 13 | 14 | - And change it to 15 | 16 | 17 | ``` 18 | 19 | You are a DocsGPT, friendly and helpful AI assistant by Arc53 that provides help with documents. You give thorough answers with code examples, if possible. 20 | Write an answer for the question below based on the provided context. 21 | If the context provides insufficient information, reply "I cannot answer". 22 | You have access to chat history and can use it to help answer the question. 23 | ---------------- 24 | {summaries} 25 | 26 | ``` 27 | -------------------------------------------------------------------------------- /docs/pages/Guides/_meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "Customising-prompts": { 3 | "title": "️💻 Customising Prompts", 4 | "href": "/Guides/Customising-prompts" 5 | }, 6 | "How-to-train-on-other-documentation": { 7 | "title": "📥 Training on docs", 8 | "href": "/Guides/How-to-train-on-other-documentation" 9 | }, 10 | "How-to-use-different-LLM": { 11 | "title": "️🤖 How to use different LLM's", 12 | "href": "/Guides/How-to-use-different-LLM", 13 | "display": "hidden" 14 | }, 15 | "My-AI-answers-questions-using-external-knowledge": { 16 | "title": "💭️ Avoiding hallucinations", 17 | "href": "/Guides/My-AI-answers-questions-using-external-knowledge", 18 | "display": "hidden" 19 | }, 20 | "Architecture": { 21 | "title": "🏗️ Architecture", 22 | "href": "/Guides/Architecture" 23 | } 24 | } -------------------------------------------------------------------------------- /docs/pages/Models/_meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "cloud-providers": { 3 | "title": "☁️ Cloud Providers", 4 | "href": "/Models/cloud-providers" 5 | }, 6 | "local-inference": { 7 | "title": "🖥️ Local Inference", 8 | "href": "/Models/local-inference" 9 | }, 10 | "embeddings": { 11 | "title": "📝 Embeddings", 12 | "href": "/Models/embeddings" 13 | } 14 | } -------------------------------------------------------------------------------- /docs/pages/Tools/_meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "basics": { 3 | "title": "🔧 Tools Basics", 4 | "href": "/Tools/basics" 5 | }, 6 | "api-tool": { 7 | "title": "🗝️ API Tool", 8 | "href": "/Tools/api-tool" 9 | }, 10 | "creating-a-tool": { 11 | "title": "🛠️ Creating a Custom Tool", 12 | "href": "/Tools/creating-a-tool" 13 | } 14 | } -------------------------------------------------------------------------------- /docs/pages/_app.mdx: -------------------------------------------------------------------------------- 1 | import { DocsGPTWidget } from "docsgpt-react"; 2 | 3 | export default function MyApp({ Component, pageProps }) { 4 | return ( 5 | <> 6 | 7 | 8 | 9 | ) 10 | } 11 | -------------------------------------------------------------------------------- /docs/pages/_meta.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "index": "Home", 4 | "quickstart": "Quickstart", 5 | "Deploying": "Deploying", 6 | "Models": "Models", 7 | "Tools": "Tools", 8 | "Agents": "Agents", 9 | "Extensions": "Extensions", 10 | "https://gptcloud.arc53.com/": { 11 | "title": "API", 12 | "href": "https://gptcloud.arc53.com/", 13 | "newWindow": true 14 | }, 15 | "Guides": "Guides", 16 | "changelog": { 17 | "title": "Changelog", 18 | "display": "hidden" 19 | } 20 | } -------------------------------------------------------------------------------- /docs/pages/changelog.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Changelog' 3 | --- -------------------------------------------------------------------------------- /docs/public/Railway-selection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/docs/public/Railway-selection.png -------------------------------------------------------------------------------- /docs/public/civo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/docs/public/civo.png -------------------------------------------------------------------------------- /docs/public/cute-docsgpt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/docs/public/cute-docsgpt.png -------------------------------------------------------------------------------- /docs/public/digitalocean.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/docs/public/digitalocean.png -------------------------------------------------------------------------------- /docs/public/docs.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/docs/public/docs.gif -------------------------------------------------------------------------------- /docs/public/favicons/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/docs/public/favicons/apple-touch-icon.png -------------------------------------------------------------------------------- /docs/public/favicons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/docs/public/favicons/favicon-16x16.png -------------------------------------------------------------------------------- /docs/public/favicons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/docs/public/favicons/favicon-32x32.png -------------------------------------------------------------------------------- /docs/public/favicons/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "short_name": "", 4 | "icons": [ 5 | { 6 | "src": "/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#ffffff", 17 | "background_color": "#ffffff", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /docs/public/homevideo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/docs/public/homevideo.gif -------------------------------------------------------------------------------- /docs/public/jwt-input.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/docs/public/jwt-input.png -------------------------------------------------------------------------------- /docs/public/kamatera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/docs/public/kamatera.png -------------------------------------------------------------------------------- /docs/public/lightsail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/docs/public/lightsail.png -------------------------------------------------------------------------------- /docs/public/llms.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/docs/public/llms.gif -------------------------------------------------------------------------------- /docs/public/new-agent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/docs/public/new-agent.png -------------------------------------------------------------------------------- /docs/public/prompts.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/docs/public/prompts.gif -------------------------------------------------------------------------------- /docs/public/railway.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/docs/public/railway.png -------------------------------------------------------------------------------- /docs/public/toolIcons/api-tool-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/docs/public/toolIcons/api-tool-example.png -------------------------------------------------------------------------------- /docs/public/toolIcons/tool_api_tool.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /docs/public/toolIcons/tool_cryptoprice.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/public/toolIcons/tool_read_webpage.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/public/toolIcons/tool_telegram.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /extensions/chatwoot/.env_sample: -------------------------------------------------------------------------------- 1 | docsgpt_url= 2 | chatwoot_url= 3 | docsgpt_key= 4 | chatwoot_token=xxxxx 5 | account_id=(optional) 1 6 | assignee_id=(optional) 1 -------------------------------------------------------------------------------- /extensions/chatwoot/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/extensions/chatwoot/__init__.py -------------------------------------------------------------------------------- /extensions/chrome/icons/icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/extensions/chrome/icons/icon128.png -------------------------------------------------------------------------------- /extensions/chrome/icons/icon16 2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/extensions/chrome/icons/icon16 2.png -------------------------------------------------------------------------------- /extensions/chrome/icons/icon16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/extensions/chrome/icons/icon16.png -------------------------------------------------------------------------------- /extensions/chrome/icons/icon19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/extensions/chrome/icons/icon19.png -------------------------------------------------------------------------------- /extensions/chrome/icons/icon24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/extensions/chrome/icons/icon24.png -------------------------------------------------------------------------------- /extensions/chrome/icons/icon256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/extensions/chrome/icons/icon256.png -------------------------------------------------------------------------------- /extensions/chrome/icons/icon32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/extensions/chrome/icons/icon32.png -------------------------------------------------------------------------------- /extensions/chrome/icons/icon48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/extensions/chrome/icons/icon48.png -------------------------------------------------------------------------------- /extensions/chrome/js/jquery/.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | jquery-migrate.js 3 | jquery-migrate.min.js 4 | -------------------------------------------------------------------------------- /extensions/chrome/js/jquery/README.md: -------------------------------------------------------------------------------- 1 | jQuery Component 2 | ================ 3 | 4 | Shim repository for jQuery. 5 | -------------------------------------------------------------------------------- /extensions/chrome/js/jquery/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery", 3 | "version": "2.0.0", 4 | "description": "jQuery component", 5 | "keywords": [ 6 | "jquery", 7 | "component" 8 | ], 9 | "scripts": [ 10 | "jquery.js" 11 | ], 12 | "license": "MIT" 13 | } 14 | -------------------------------------------------------------------------------- /extensions/chrome/js/jquery/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery", 3 | "version": "2.0.0", 4 | "description": "jQuery component", 5 | "keywords": [ 6 | "jquery", 7 | "component" 8 | ], 9 | "scripts": [ 10 | "jquery.js" 11 | ], 12 | "license": "MIT", 13 | "gitHead": "46f8412bd1bb9b1b30b5b0eb88560e2d4196509c", 14 | "readme": "jQuery Component\n================\n\nShim repository for jQuery.\n", 15 | "readmeFilename": "README.md", 16 | "_id": "jquery@2.0.0", 17 | "repository": { 18 | "type": "git", 19 | "url": "git://github.com/components/jquery.git" 20 | } 21 | } -------------------------------------------------------------------------------- /extensions/chrome/js/jquery/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "components/jquery", 3 | "description": "jQuery JavaScript Library", 4 | "type": "component", 5 | "homepage": "http://jquery.com", 6 | "license": "MIT", 7 | "support": { 8 | "irc": "irc://irc.freenode.org/jquery", 9 | "issues": "http://bugs.jquery.com", 10 | "forum": "http://forum.jquery.com", 11 | "wiki": "http://docs.jquery.com/", 12 | "source": "https://github.com/jquery/jquery" 13 | }, 14 | "authors": [ 15 | { 16 | "name": "John Resig", 17 | "email": "jeresig@gmail.com" 18 | } 19 | ], 20 | "require": { 21 | "robloach/component-installer": "*" 22 | }, 23 | "extra": { 24 | "component": { 25 | "scripts": [ 26 | "jquery.js" 27 | ] 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /extensions/chrome/js/jquery/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "components-jquery", 3 | "version": "2.0.0", 4 | "description": "jQuery component", 5 | "keywords": ["jquery"], 6 | "main": "./jquery.js" 7 | } 8 | -------------------------------------------------------------------------------- /extensions/chrome/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "DocsGPT - Documentation AI butler", 3 | "version": "0.0.1", 4 | "manifest_version": 3, 5 | "description": "AI assistant for developers, that helps you answer your questions about the documentation you are reading.", 6 | "icons": { 7 | "16": "icons/icon16.png", 8 | "48": "icons/icon48.png", 9 | "128": "icons/icon128.png" 10 | }, 11 | "default_locale": "en", 12 | "background": { 13 | "service_worker": "src/bg/service-worker.js" 14 | }, 15 | "action": { 16 | "default_title": "DocsGPT - Documentation AI butler", 17 | "default_popup": "popup.html" 18 | }, 19 | "permissions": ["activeTab", "storage"], 20 | "host_permissions": [ 21 | "*://*/*" 22 | ], 23 | "content_scripts": [{ 24 | "js": ["popup.js"], 25 | "matches": ["https://github.com/*"] 26 | }] 27 | 28 | } 29 | -------------------------------------------------------------------------------- /extensions/chrome/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docsgpt-chrome-extension", 3 | "version": "0.0.1", 4 | "description": "DocsGPT - Documentation AI butler", 5 | "main": "popup.js", 6 | "author": "", 7 | "license": "MIT", 8 | "scripts": { 9 | "dev": "npx tailwindcss -i ./styles.css -o ./dist/output.css --watch" 10 | }, 11 | "keywords": [ 12 | "DocsGPT", 13 | "Documentation", 14 | "Chrome", 15 | "extension" 16 | ], 17 | "devDependencies": { 18 | "tailwindcss": "^3.2.4" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /extensions/chrome/src/bg/service-worker.js: -------------------------------------------------------------------------------- 1 | // This is the service worker script, which executes in its own context 2 | // when the extension is installed or refreshed (or when you access its console). 3 | // It would correspond to the background script in chrome extensions v2. 4 | 5 | console.log("This prints to the console of the service worker (background script)"); 6 | chrome.runtime.onMessage.addListener( 7 | function(request, sender, sendResponse) { 8 | if (request.msg === "sendMessage") { 9 | sendResponse({response: "Message received"}); 10 | } 11 | } 12 | ); -------------------------------------------------------------------------------- /extensions/chrome/styles.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | 6 | #chat-container { 7 | width: 500px; 8 | height: 450px; 9 | background-color: white; 10 | padding: 10px; 11 | overflow: auto; 12 | } 13 | 14 | 15 | 16 | .bg-gray-200 { 17 | background-color: #edf2f7; 18 | } 19 | 20 | .bg-gray-900 { 21 | background-color: #1a202c; 22 | } 23 | 24 | .rounded-lg { 25 | border-radius: 0.5rem; 26 | } 27 | 28 | .shadow { 29 | box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24); 30 | } 31 | 32 | .text-gray-700 { 33 | color: #4a5568; 34 | } 35 | 36 | .text-sm { 37 | font-size: 0.875rem; 38 | } 39 | 40 | .p-4 { 41 | padding: 1.5rem; 42 | } 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /extensions/chrome/tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | content: ["./src/**/*.{html,js}", "./*.{html,js,css}"], 3 | theme: { 4 | extend: {}, 5 | }, 6 | plugins: [], 7 | } -------------------------------------------------------------------------------- /extensions/discord/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/extensions/discord/__init__.py -------------------------------------------------------------------------------- /extensions/react-widget/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .parcel-cache -------------------------------------------------------------------------------- /extensions/react-widget/.parcelrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@parcel/config-default", 3 | "resolvers": ["@parcel/resolver-glob","..."], 4 | "transformers": { 5 | "*.svg": ["...", "@parcel/transformer-svg-react", "@parcel/transformer-typescript-tsc"] 6 | }, 7 | "validators": { 8 | "*.{ts,tsx}": ["@parcel/validator-typescript"] 9 | } 10 | } -------------------------------------------------------------------------------- /extensions/react-widget/custom.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.svg" { 2 | import * as React from "react"; 3 | 4 | const ReactComponent: React.FunctionComponent< 5 | React.SVGProps & { title?: string } 6 | >; 7 | 8 | export default ReactComponent; 9 | } -------------------------------------------------------------------------------- /extensions/react-widget/src/App.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import {DocsGPTWidget} from "./components/DocsGPTWidget" 3 | import {SearchBar} from "./components/SearchBar" 4 | export const App = () => { 5 | return ( 6 |
7 | 8 | 9 |
10 | ) 11 | } -------------------------------------------------------------------------------- /extensions/react-widget/src/assets/dislike.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /extensions/react-widget/src/assets/like.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /extensions/react-widget/src/browser.tsx: -------------------------------------------------------------------------------- 1 | //exports browser ready methods 2 | 3 | import { createRoot } from "react-dom/client"; 4 | 5 | import { DocsGPTWidget } from './components/DocsGPTWidget'; 6 | import { SearchBar } from './components/SearchBar'; 7 | import React from "react"; 8 | if (typeof window !== 'undefined') { 9 | const renderWidget = (elementId: string, props = {}) => { 10 | const root = createRoot(document.getElementById(elementId) as HTMLElement); 11 | root.render(); 12 | }; 13 | const renderSearchBar = (elementId: string, props = {}) => { 14 | const root = createRoot(document.getElementById(elementId) as HTMLElement); 15 | root.render(); 16 | }; 17 | (window as any).renderDocsGPTWidget = renderWidget; 18 | 19 | (window as any).renderSearchBar = renderSearchBar; 20 | } 21 | 22 | export { DocsGPTWidget, SearchBar }; 23 | -------------------------------------------------------------------------------- /extensions/react-widget/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | DocsGPT Widget 8 | 9 | 10 |
11 | 12 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /extensions/react-widget/src/index.ts: -------------------------------------------------------------------------------- 1 | //exports methods for React 2 | export {SearchBar} from "./components/SearchBar" 3 | export { DocsGPTWidget } from "./components/DocsGPTWidget"; 4 | -------------------------------------------------------------------------------- /extensions/react-widget/src/main.tsx: -------------------------------------------------------------------------------- 1 | 2 | //development 3 | import { createRoot } from "react-dom/client"; 4 | import { App } from "./App"; 5 | import React from "react"; 6 | const container = document.getElementById("app") as HTMLElement; 7 | const root = createRoot(container) 8 | root.render(); 9 | -------------------------------------------------------------------------------- /extensions/react-widget/src/requests/searchAPI.ts: -------------------------------------------------------------------------------- 1 | import { Result } from "@/types"; 2 | 3 | async function getSearchResults(question: string, apiKey: string, apiHost: string, signal: AbortSignal): Promise { 4 | 5 | const payload = { 6 | question, 7 | api_key: apiKey 8 | }; 9 | 10 | try { 11 | const response = await fetch(`${apiHost}/api/search`, { 12 | method: "POST", 13 | headers: { 14 | "Content-Type": "application/json", 15 | }, 16 | body: JSON.stringify(payload), 17 | signal: signal 18 | }); 19 | 20 | if (!response.ok) { 21 | throw new Error(`Error: ${response.status}`); 22 | } 23 | 24 | const data: Result[] = await response.json(); 25 | return data; 26 | 27 | } catch (error) { 28 | if (!(error instanceof DOMException && error.name == "AbortError")) { 29 | console.error("Failed to fetch documents:", error); 30 | } 31 | throw error; 32 | } 33 | } 34 | 35 | export { 36 | getSearchResults 37 | } -------------------------------------------------------------------------------- /extensions/react-widget/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export type MESSAGE_TYPE = 'QUESTION' | 'ANSWER' | 'ERROR'; 2 | 3 | export type Status = 'idle' | 'loading' | 'failed'; 4 | 5 | export type FEEDBACK = 'LIKE' | 'DISLIKE'; 6 | 7 | export type THEME = 'light' | 'dark'; 8 | 9 | export interface Query { 10 | prompt: string; 11 | response?: string; 12 | feedback?: FEEDBACK; 13 | error?: string; 14 | sources?: { title: string; text: string, source:string }[]; 15 | conversationId?: string | null; 16 | title?: string | null; 17 | } 18 | 19 | export interface WidgetProps { 20 | apiHost?: string; 21 | apiKey?: string; 22 | avatar?: string; 23 | title?: string; 24 | description?: string; 25 | heroTitle?: string; 26 | heroDescription?: string; 27 | size?: 'small' | 'medium' | 'large' | { 28 | custom: { 29 | width: string; 30 | height: string; 31 | maxWidth?: string; 32 | maxHeight?: string; 33 | }; 34 | }; 35 | theme?:THEME, 36 | buttonIcon?:string; 37 | buttonText?:string; 38 | buttonBg?:string; 39 | collectFeedback?:boolean; 40 | showSources?: boolean; 41 | defaultOpen?: boolean; 42 | } 43 | export interface WidgetCoreProps extends WidgetProps { 44 | widgetRef?:React.RefObject | null; 45 | handleClose?:React.MouseEventHandler | undefined; 46 | isOpen:boolean; 47 | prefilledQuery?: string; 48 | } 49 | 50 | export interface SearchBarProps { 51 | apiHost?: string; 52 | apiKey?: string; 53 | theme?: THEME; 54 | placeholder?: string; 55 | width?: string; 56 | buttonText?: string; 57 | } 58 | 59 | export interface Result { 60 | text:string; 61 | title:string; 62 | source:string; 63 | } 64 | -------------------------------------------------------------------------------- /extensions/react-widget/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "paths": { 5 | "@/*": ["src/*", "@/*"] 6 | }, 7 | "target": "ES2020", 8 | "useDefineForClassFields": true, 9 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 10 | "module": "ESNext", 11 | "skipLibCheck": true, 12 | 13 | /* Bundler mode */ 14 | "moduleResolution": "bundler", 15 | "allowImportingTsExtensions": true, 16 | "resolveJsonModule": true, 17 | "isolatedModules": true, 18 | "noEmit": true, 19 | "jsx": "react-jsx", 20 | 21 | /* Linting */ 22 | "strict": true, 23 | "noUnusedLocals": false, 24 | "noUnusedParameters": false, 25 | "noFallthroughCasesInSwitch": true, 26 | /* The "typeRoots" configuration specifies the locations where 27 | TypeScript looks for type definitions (.d.ts files) to 28 | include in the compilation process.*/ 29 | "typeRoots": ["./dist/index.d.ts", "node_modules/@types"] 30 | }, 31 | /* include /index.ts*/ 32 | "include": ["src/index.ts","custom.d.ts"], 33 | "exclude": ["node_modules"], 34 | } -------------------------------------------------------------------------------- /extensions/slack-bot/.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | .venv/ 3 | get-pip.py -------------------------------------------------------------------------------- /extensions/slack-bot/requirements.txt: -------------------------------------------------------------------------------- 1 | aiohttp>=3,<4 2 | certifi==2024.7.4 3 | h11==0.14.0 4 | httpcore==1.0.5 5 | httpx==0.27.0 6 | idna==3.7 7 | python-dotenv==1.0.1 8 | sniffio==1.3.1 9 | slack-bolt==1.21.0 10 | bson==0.5.10 11 | -------------------------------------------------------------------------------- /extensions/web-widget/README.md: -------------------------------------------------------------------------------- 1 | # Chat Widget 2 | 3 | A simple chat widget that can be easily integrated into any website. 4 | 5 | ## Installation 6 | 7 | 1. Host the `widget.html`, `styles.css`, and `script.js` files from the `src` folder on your own server or a Content Delivery Network (CDN). Make sure to note the URLs for these files. 8 | 9 | 2. Update the URLs in the `dist/chat-widget.js` file to match the locations of your hosted files: 10 | 11 | ```javascript 12 | fetch("https://your-server-or-cdn.com/path/to/widget.html"), 13 | fetch("https://your-server-or-cdn.com/path/to/styles.css"), 14 | fetch("https://your-server-or-cdn.com/path/to/script.js"), 15 | ``` 16 | 17 | 3. Host the `dist/chat-widget.js` file on your own server or a Content Delivery Network (CDN). Make sure to note the URL for this file. 18 | 19 | 20 | ##Integration 21 | 22 | To integrate the chat widget into a website, add the following script tag to the HTML file, replacing URL_TO_CHAT_WIDGET_JS with the actual URL of your hosted chat-widget.js file: 23 | ```javascript 24 | 25 | ``` -------------------------------------------------------------------------------- /extensions/web-widget/dist/chat-widget.js: -------------------------------------------------------------------------------- 1 | (async function () { 2 | // Fetch the HTML, CSS, and JavaScript from your server or CDN 3 | const [htmlRes, jsRes] = await Promise.all([ 4 | fetch("https://s3-eu-west-2.amazonaws.com/arc53data/widget.html"), 5 | // fetch("https://s3-eu-west-2.amazonaws.com/arc53data/tailwind.css"), 6 | fetch("https://s3-eu-west-2.amazonaws.com/arc53data/script.js"), 7 | ]); 8 | 9 | const html = await htmlRes.text(); 10 | //const css = await cssRes.text(); 11 | const js = await jsRes.text(); 12 | 13 | // create a new link element 14 | const link = document.createElement("link"); 15 | 16 | //set the rel, href, type, and integrity attributes 17 | link.rel = "stylesheet"; 18 | link.href = "https://cdn.tailwindcss.com/"; 19 | link.type = "text/css"; 20 | link.integrity = "sha384-PDOmVviaTm8N1W35y1NSmo80w6GPaGhbDuOBAF/5hRffaeGc6yOwIo1qAt4gqLGA%"; 21 | 22 | // get the document head and append the link element to it 23 | // document.head.appendChild(link); 24 | 25 | 26 | 27 | // Create a style element for the CSS 28 | // const style = document.createElement("style"); 29 | // style.innerHTML = css; 30 | // document.head.appendChild(style); 31 | 32 | // Create a container for the chat widget and inject the HTML 33 | const chatWidgetContainer = document.createElement("div"); 34 | chatWidgetContainer.innerHTML = html; 35 | document.body.appendChild(chatWidgetContainer); 36 | 37 | // Execute the JavaScript code 38 | const script = document.createElement("script"); 39 | script.innerHTML = js; 40 | document.body.appendChild(script); 41 | })(); 42 | -------------------------------------------------------------------------------- /extensions/web-widget/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Chat Widget Test 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /extensions/web-widget/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "web-widget", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "tailwindcss": "^3.3.1" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /extensions/web-widget/src/input.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; -------------------------------------------------------------------------------- /extensions/web-widget/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: ["./src/**/*.{html,js}"], 4 | theme: { 5 | extend: {}, 6 | }, 7 | plugins: [], 8 | } 9 | 10 | 11 | -------------------------------------------------------------------------------- /frontend/.env.development: -------------------------------------------------------------------------------- 1 | # Please put appropriate value 2 | VITE_BASE_URL=http://localhost:5173 3 | VITE_API_HOST=http://127.0.0.1:7091 4 | VITE_API_STREAMING=true -------------------------------------------------------------------------------- /frontend/.env.production: -------------------------------------------------------------------------------- 1 | VITE_API_HOST = https://gptcloud.arc53.com -------------------------------------------------------------------------------- /frontend/.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | prettier.config.cjs 4 | .eslintrc.cjs 5 | env.d.ts 6 | public/ 7 | assets/ 8 | vite-env.d.ts 9 | .prettierignore 10 | package-lock.json 11 | package.json 12 | postcss.config.cjs 13 | prettier.config.cjs 14 | tailwind.config.cjs 15 | tsconfig.json 16 | tsconfig.node.json 17 | vite.config.ts -------------------------------------------------------------------------------- /frontend/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: true, 4 | es2021: true, 5 | node: true, 6 | }, 7 | extends: [ 8 | 'eslint:recommended', 9 | 'plugin:@typescript-eslint/recommended', 10 | 'plugin:react/recommended', 11 | 'plugin:prettier/recommended', 12 | ], 13 | overrides: [], 14 | parser: '@typescript-eslint/parser', 15 | parserOptions: { 16 | ecmaVersion: 'latest', 17 | sourceType: 'module', 18 | }, 19 | plugins: ['react', 'unused-imports'], 20 | rules: { 21 | 'react/prop-types': 'off', 22 | 'unused-imports/no-unused-imports': 'error', 23 | 'react/react-in-jsx-scope': 'off', 24 | 'prettier/prettier': [ 25 | 'error', 26 | { 27 | endOfLine: 'auto', 28 | }, 29 | ], 30 | }, 31 | settings: { 32 | 'import/parsers': { 33 | '@typescript-eslint/parser': ['.ts', '.tsx'], 34 | }, 35 | react: { 36 | version: 'detect', 37 | }, 38 | 'import/resolver': { 39 | node: { 40 | paths: ['src'], 41 | extensions: ['.js', '.jsx', '.ts', '.tsx'], 42 | }, 43 | }, 44 | }, 45 | }; 46 | -------------------------------------------------------------------------------- /frontend/.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | # npm test 5 | cd frontend 6 | npx lint-staged -------------------------------------------------------------------------------- /frontend/.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | prettier.config.cjs 4 | .eslintrc.cjs 5 | env.d.ts 6 | public/ 7 | assets/ 8 | vite-env.d.ts 9 | .prettierignore 10 | package-lock.json 11 | package.json 12 | postcss.config.cjs 13 | prettier.config.cjs 14 | tailwind.config.cjs 15 | tsconfig.json 16 | tsconfig.node.json 17 | vite.config.ts -------------------------------------------------------------------------------- /frontend/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:20.6.1-bullseye-slim 2 | 3 | 4 | WORKDIR /app 5 | COPY package*.json ./ 6 | RUN npm install 7 | COPY . . 8 | 9 | EXPOSE 5173 10 | 11 | CMD [ "npm", "run", "dev", "--" , "--host"] 12 | -------------------------------------------------------------------------------- /frontend/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | DocsGPT 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /frontend/postcss.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /frontend/prettier.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | trailingComma: 'all', 3 | tabWidth: 2, 4 | semi: true, 5 | singleQuote: true, 6 | printWidth: 80, 7 | plugins: ['prettier-plugin-tailwindcss'], 8 | }; 9 | -------------------------------------------------------------------------------- /frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/frontend/public/favicon.ico -------------------------------------------------------------------------------- /frontend/public/fonts/IBMPlexMono-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/frontend/public/fonts/IBMPlexMono-Medium.ttf -------------------------------------------------------------------------------- /frontend/public/fonts/Inter-Variable.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/frontend/public/fonts/Inter-Variable.ttf -------------------------------------------------------------------------------- /frontend/public/lock-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /frontend/public/lock.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /frontend/public/message-programming-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /frontend/public/message-programming.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /frontend/public/message-text-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /frontend/public/message-text.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /frontend/public/toolIcons/tool_api_tool.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /frontend/public/toolIcons/tool_cryptoprice.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/public/toolIcons/tool_read_webpage.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/public/toolIcons/tool_telegram.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /frontend/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/signal-desktop-keyring.gpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arc53/DocsGPT/b47af9600f17f7bb19c87cbb87bb07d0bf044a7a/frontend/signal-desktop-keyring.gpg -------------------------------------------------------------------------------- /frontend/src/PageNotFound.tsx: -------------------------------------------------------------------------------- 1 | import { Link } from 'react-router-dom'; 2 | 3 | export default function PageNotFound() { 4 | return ( 5 |
6 |

7 |

404

8 |

The page you are looking for does not exist.

9 | 12 |

13 |
14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /frontend/src/agents/types/index.ts: -------------------------------------------------------------------------------- 1 | export type Agent = { 2 | id?: string; 3 | name: string; 4 | description: string; 5 | image: string; 6 | source: string; 7 | chunks: string; 8 | retriever: string; 9 | prompt_id: string; 10 | tools: string[]; 11 | agent_type: string; 12 | status: string; 13 | key?: string; 14 | incoming_webhook_token?: string; 15 | pinned?: boolean; 16 | shared?: boolean; 17 | shared_token?: string; 18 | shared_metadata?: any; 19 | created_at?: string; 20 | updated_at?: string; 21 | last_used_at?: string; 22 | }; 23 | -------------------------------------------------------------------------------- /frontend/src/assets/DragFileUpload.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /frontend/src/assets/Loading.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/TwitterX.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/add.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /frontend/src/assets/alert.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/arrow-down.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /frontend/src/assets/arrow-left.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/arrow-right.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/caret-sort.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/assets/checkMark2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /frontend/src/assets/checkmark.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/assets/chevron-down.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/assets/chevron-right.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/circle-check.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/assets/circle-x.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/assets/clip.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/cloud.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /frontend/src/assets/cogwheel.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/copy-linear.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /frontend/src/assets/copy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/dislike.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /frontend/src/assets/document.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/documentation-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /frontend/src/assets/documentation.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /frontend/src/assets/double-arrow-left.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /frontend/src/assets/double-arrow-right.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /frontend/src/assets/dropdown-arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/edit.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /frontend/src/assets/envelope-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/envelope.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/exit.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /frontend/src/assets/expand.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /frontend/src/assets/eye-view.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /frontend/src/assets/file_upload.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /frontend/src/assets/github.svg: -------------------------------------------------------------------------------- 1 | 2 | github 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /frontend/src/assets/hamburger-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/hamburger.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/info-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /frontend/src/assets/info.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/key.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/like.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /frontend/src/assets/link-gray.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/link.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/message-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /frontend/src/assets/message.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/openNewChat.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /frontend/src/assets/paper_plane.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/pin.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/assets/red-trash.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/redirect.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/send.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/send_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/single-left-arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /frontend/src/assets/single-right-arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /frontend/src/assets/source.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /frontend/src/assets/speaker.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /frontend/src/assets/spinner-dark.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/assets/spinner.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/assets/stopspeech.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /frontend/src/assets/sync.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/assets/three-dots.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/trash.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /frontend/src/assets/unpin.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/assets/upload.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/assets/website_collect.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /frontend/src/assets/white-trash.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/components/Avatar.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from 'react'; 2 | 3 | export default function Avatar({ 4 | avatar, 5 | size, 6 | className, 7 | }: { 8 | avatar: ReactNode; 9 | size?: 'SMALL' | 'MEDIUM' | 'LARGE'; 10 | className: string; 11 | }) { 12 | return
{avatar}
; 13 | } 14 | -------------------------------------------------------------------------------- /frontend/src/components/RetryIcon.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { SVGProps } from 'react'; 3 | const RetryIcon = (props: SVGProps) => ( 4 | 15 | 16 | 17 | ); 18 | export default RetryIcon; 19 | -------------------------------------------------------------------------------- /frontend/src/components/ShareButton.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | import ShareIcon from '../assets/share.svg'; 3 | import { ShareConversationModal } from '../modals/ShareConversationModal'; 4 | 5 | type ShareButtonProps = { 6 | conversationId: string; 7 | }; 8 | 9 | export default function ShareButton({ conversationId }: ShareButtonProps) { 10 | const [isShareModalOpen, setShareModalState] = useState(false); 11 | return ( 12 | <> 13 | 26 | {isShareModalOpen && ( 27 | { 29 | setShareModalState(false); 30 | }} 31 | conversationId={conversationId} 32 | /> 33 | )} 34 | 35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /frontend/src/components/Sidebar.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import Exit from '../assets/exit.svg'; 4 | 5 | type SidebarProps = { 6 | isOpen: boolean; 7 | toggleState: (arg0: boolean) => void; 8 | children: React.ReactNode; 9 | }; 10 | 11 | export default function Sidebar({ 12 | isOpen, 13 | toggleState, 14 | children, 15 | }: SidebarProps) { 16 | const sidebarRef = React.useRef(null); 17 | 18 | const handleClickOutside = (event: MouseEvent) => { 19 | if ( 20 | sidebarRef.current && 21 | !sidebarRef.current.contains(event.target as Node) 22 | ) { 23 | toggleState(false); 24 | } 25 | }; 26 | 27 | React.useEffect(() => { 28 | document.addEventListener('mousedown', handleClickOutside); 29 | return () => { 30 | document.removeEventListener('mousedown', handleClickOutside); 31 | }; 32 | }, []); 33 | return ( 34 |
35 |
40 |
41 | 47 |
48 |
49 | {children} 50 |
51 |
52 |
53 | ); 54 | } 55 | -------------------------------------------------------------------------------- /frontend/src/components/Spinner.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | type SpinnerProps = { 4 | size?: 'small' | 'medium' | 'large'; 5 | color?: string; 6 | }; 7 | 8 | export default function Spinner({ 9 | size = 'medium', 10 | color = 'grey', 11 | }: SpinnerProps) { 12 | const sizeMap = { 13 | small: '20px', 14 | medium: '30px', 15 | large: '40px', 16 | }; 17 | const spinnerSize = sizeMap[size]; 18 | 19 | const spinnerStyle = { 20 | width: spinnerSize, 21 | height: spinnerSize, 22 | aspectRatio: '1', 23 | borderRadius: '50%', 24 | background: ` 25 | radial-gradient(farthest-side, ${color} 94%, #0000) top/8px 8px no-repeat, 26 | conic-gradient(#0000 30%, ${color}) 27 | `, 28 | WebkitMask: 29 | 'radial-gradient(farthest-side, #0000 calc(100% - 8px), #000 0)', 30 | animation: 'l13 1s infinite linear', 31 | } as React.CSSProperties; 32 | 33 | const keyframesStyle = `@keyframes l13 { 34 | 100% { transform: rotate(1turn) } 35 | }`; 36 | 37 | return ( 38 | <> 39 | 40 |
41 | 42 | ); 43 | } 44 | -------------------------------------------------------------------------------- /frontend/src/components/types/index.ts: -------------------------------------------------------------------------------- 1 | export type InputProps = { 2 | type: 'text' | 'number'; 3 | value: string | string[] | number; 4 | colorVariant?: 'silver' | 'jet' | 'gray'; 5 | borderVariant?: 'thin' | 'thick'; 6 | textSize?: 'small' | 'medium'; 7 | isAutoFocused?: boolean; 8 | id?: string; 9 | maxLength?: number; 10 | name?: string; 11 | placeholder?: string; 12 | required?: boolean; 13 | className?: string; 14 | children?: React.ReactElement; 15 | labelBgClassName?: string; 16 | onChange: ( 17 | e: React.ChangeEvent, 18 | ) => void; 19 | onPaste?: ( 20 | e: React.ClipboardEvent, 21 | ) => void; 22 | onKeyDown?: ( 23 | e: React.KeyboardEvent, 24 | ) => void; 25 | }; 26 | 27 | export type MermaidRendererProps = { 28 | code: string; 29 | isLoading?: boolean; 30 | }; 31 | -------------------------------------------------------------------------------- /frontend/src/conversation/ConversationBubble.module.css: -------------------------------------------------------------------------------- 1 | .list p { 2 | display: inline; 3 | } 4 | 5 | .list li:not(:first-child) { 6 | margin-top: 1em; 7 | } 8 | 9 | .list li > .list { 10 | margin-top: 1em; 11 | } 12 | -------------------------------------------------------------------------------- /frontend/src/conversation/types/index.ts: -------------------------------------------------------------------------------- 1 | export type ToolCallsType = { 2 | tool_name: string; 3 | action_name: string; 4 | call_id: string; 5 | arguments: Record; 6 | result: Record; 7 | }; 8 | -------------------------------------------------------------------------------- /frontend/src/hooks/useDefaultDocument.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useDispatch, useSelector } from 'react-redux'; 3 | 4 | import { Doc } from '../models/misc'; 5 | import { getDocs } from '../preferences/preferenceApi'; 6 | import { 7 | selectSelectedDocs, 8 | selectToken, 9 | setSelectedDocs, 10 | setSourceDocs, 11 | } from '../preferences/preferenceSlice'; 12 | 13 | export default function useDefaultDocument() { 14 | const dispatch = useDispatch(); 15 | const token = useSelector(selectToken); 16 | const selectedDoc = useSelector(selectSelectedDocs); 17 | 18 | const fetchDocs = () => { 19 | getDocs(token).then((data) => { 20 | dispatch(setSourceDocs(data)); 21 | if (!selectedDoc) 22 | Array.isArray(data) && 23 | data?.forEach((doc: Doc) => { 24 | if (doc.model && doc.name === 'default') { 25 | dispatch(setSelectedDocs(doc)); 26 | } 27 | }); 28 | }); 29 | }; 30 | 31 | React.useEffect(() => { 32 | fetchDocs(); 33 | }, []); 34 | } 35 | -------------------------------------------------------------------------------- /frontend/src/locale/i18n.ts: -------------------------------------------------------------------------------- 1 | import i18n from 'i18next'; 2 | import { initReactI18next } from 'react-i18next'; 3 | import LanguageDetector from 'i18next-browser-languagedetector'; 4 | 5 | import en from './en.json'; //English 6 | import es from './es.json'; //Spanish 7 | import jp from './jp.json'; //Japanese 8 | import zh from './zh.json'; //Mandarin 9 | import zhTW from './zh-TW.json'; //Traditional Chinese 10 | import ru from './ru.json'; //Russian 11 | 12 | i18n 13 | .use(LanguageDetector) 14 | .use(initReactI18next) 15 | .init({ 16 | resources: { 17 | en: { 18 | translation: en, 19 | }, 20 | es: { 21 | translation: es, 22 | }, 23 | jp: { 24 | translation: jp, 25 | }, 26 | zh: { 27 | translation: zh, 28 | }, 29 | zhTW: { 30 | translation: zhTW, 31 | }, 32 | ru: { 33 | translation: ru, 34 | }, 35 | }, 36 | fallbackLng: 'en', 37 | detection: { 38 | order: ['localStorage', 'navigator'], 39 | caches: ['localStorage'], 40 | lookupLocalStorage: 'docsgpt-locale', 41 | }, 42 | }); 43 | 44 | i18n.changeLanguage(i18n.language); 45 | 46 | export default i18n; 47 | -------------------------------------------------------------------------------- /frontend/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import App from './App'; 4 | import { BrowserRouter } from 'react-router-dom'; 5 | import { Provider } from 'react-redux'; 6 | import store from './store'; 7 | import './index.css'; 8 | 9 | ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( 10 | 11 | 12 | 13 | 14 | 15 | 16 | , 17 | ); 18 | -------------------------------------------------------------------------------- /frontend/src/modals/DeleteConvModal.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useDispatch } from 'react-redux'; 3 | import { ActiveState } from '../models/misc'; 4 | import { useMediaQuery, useOutsideAlerter } from '../hooks'; 5 | import ConfirmationModal from './ConfirmationModal'; 6 | import { useTranslation } from 'react-i18next'; 7 | import { Action } from '@reduxjs/toolkit'; 8 | 9 | export default function DeleteConvModal({ 10 | modalState, 11 | setModalState, 12 | handleDeleteAllConv, 13 | }: { 14 | modalState: ActiveState; 15 | setModalState: (val: ActiveState) => Action; 16 | handleDeleteAllConv: () => void; 17 | }) { 18 | const modalRef = React.useRef(null); 19 | const dispatch = useDispatch(); 20 | const { isMobile } = useMediaQuery(); 21 | const { t } = useTranslation(); 22 | useOutsideAlerter(modalRef, () => { 23 | if (isMobile && modalState === 'ACTIVE') { 24 | dispatch(setModalState('INACTIVE')); 25 | } 26 | }, [modalState]); 27 | 28 | function handleSubmit() { 29 | handleDeleteAllConv(); 30 | dispatch(setModalState('INACTIVE')); 31 | } 32 | 33 | function handleCancel() { 34 | dispatch(setModalState('INACTIVE')); 35 | } 36 | 37 | return ( 38 | 47 | ); 48 | } 49 | -------------------------------------------------------------------------------- /frontend/src/modals/JWTModal.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | 3 | import Input from '../components/Input'; 4 | import { ActiveState } from '../models/misc'; 5 | import WrapperModal from './WrapperModal'; 6 | 7 | type JWTModalProps = { 8 | modalState: ActiveState; 9 | handleTokenSubmit: (enteredToken: string) => void; 10 | }; 11 | 12 | export default function JWTModal({ 13 | modalState, 14 | handleTokenSubmit, 15 | }: JWTModalProps) { 16 | const [jwtToken, setJwtToken] = useState(''); 17 | 18 | if (modalState !== 'ACTIVE') return null; 19 | 20 | return ( 21 | undefined} 25 | > 26 |
27 | 28 | Add JWT Token 29 | 30 |
31 |
32 | setJwtToken(e.target.value)} 38 | borderVariant="thin" 39 | /> 40 |
41 | 48 |
49 | ); 50 | } 51 | -------------------------------------------------------------------------------- /frontend/src/modals/types/index.ts: -------------------------------------------------------------------------------- 1 | export type AvailableToolType = { 2 | name: string; 3 | displayName: string; 4 | description: string; 5 | configRequirements: object; 6 | actions: { 7 | name: string; 8 | description: string; 9 | parameters: object; 10 | }[]; 11 | }; 12 | 13 | export type WrapperModalPropsType = { 14 | children?: React.ReactNode; 15 | isPerformingTask?: boolean; 16 | close: () => void; 17 | className?: string; 18 | }; 19 | -------------------------------------------------------------------------------- /frontend/src/models/misc.ts: -------------------------------------------------------------------------------- 1 | export type ActiveState = 'ACTIVE' | 'INACTIVE'; 2 | 3 | export type User = { 4 | avatar: string; 5 | }; 6 | export type Doc = { 7 | id?: string; 8 | name: string; 9 | date: string; 10 | model: string; 11 | tokens?: string; 12 | type?: string; 13 | retriever?: string; 14 | syncFrequency?: string; 15 | }; 16 | 17 | export type GetDocsResponse = { 18 | docs: Doc[]; 19 | totalDocuments: number; 20 | totalPages: number; 21 | nextCursor: string; 22 | }; 23 | 24 | export type Prompt = { 25 | name: string; 26 | id: string; 27 | type: string; 28 | }; 29 | 30 | export type PromptProps = { 31 | prompts: { name: string; id: string; type: string }[]; 32 | selectedPrompt: { name: string; id: string; type: string }; 33 | onSelectPrompt: (name: string, id: string, type: string) => void; 34 | setPrompts: (prompts: { name: string; id: string; type: string }[]) => void; 35 | }; 36 | 37 | export type DocumentsProps = { 38 | paginatedDocuments: Doc[] | null; 39 | handleDeleteDocument: (index: number, document: Doc) => void; 40 | }; 41 | 42 | export type CreateAPIKeyModalProps = { 43 | close: () => void; 44 | createAPIKey: (payload: { 45 | name: string; 46 | source: string; 47 | prompt_id: string; 48 | chunks: string; 49 | }) => void; 50 | }; 51 | 52 | export type SaveAPIKeyModalProps = { 53 | apiKey: string; 54 | close: () => void; 55 | }; 56 | -------------------------------------------------------------------------------- /frontend/src/preferences/types/index.ts: -------------------------------------------------------------------------------- 1 | export type ConversationSummary = { 2 | id: string; 3 | name: string; 4 | agent_id: string | null; 5 | }; 6 | 7 | export type GetConversationsResult = { 8 | data: ConversationSummary[] | null; 9 | loading: boolean; 10 | }; 11 | -------------------------------------------------------------------------------- /frontend/src/utils/browserUtils.ts: -------------------------------------------------------------------------------- 1 | export function getOS() { 2 | const userAgent = window.navigator.userAgent; 3 | if (userAgent.indexOf('Mac') !== -1) return 'mac'; 4 | if (userAgent.indexOf('Win') !== -1) return 'win'; 5 | return 'linux'; 6 | } 7 | 8 | export function isTouchDevice() { 9 | return 'ontouchstart' in window || navigator.maxTouchPoints > 0; 10 | } 11 | -------------------------------------------------------------------------------- /frontend/src/utils/dateTimeUtils.ts: -------------------------------------------------------------------------------- 1 | export function formatDate(dateString: string): string { 2 | if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{2}:\d{2}$/.test(dateString)) { 3 | // ISO 8601 format 4 | const dateTime = new Date(dateString); 5 | return dateTime.toLocaleDateString('en-US', { 6 | month: 'short', 7 | day: 'numeric', 8 | year: 'numeric', 9 | hour: '2-digit', 10 | minute: '2-digit', 11 | }); 12 | } else if (/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/.test(dateString)) { 13 | const dateTime = new Date(dateString); 14 | return dateTime.toLocaleDateString('en-US', { 15 | month: 'short', 16 | day: 'numeric', 17 | year: 'numeric', 18 | hour: '2-digit', 19 | minute: '2-digit', 20 | }); 21 | } else if (/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/.test(dateString)) { 22 | const dateTime = new Date(dateString); 23 | return dateTime.toLocaleDateString('en-US', { 24 | month: 'short', 25 | day: 'numeric', 26 | year: 'numeric', 27 | hour: '2-digit', 28 | minute: '2-digit', 29 | }); 30 | } else if (/^\d{4}-\d{2}-\d{2}$/.test(dateString)) { 31 | const date = new Date(dateString); 32 | return date.toLocaleDateString('en-US', { 33 | month: 'short', 34 | day: 'numeric', 35 | year: 'numeric', 36 | }); 37 | } else { 38 | return dateString; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /frontend/src/utils/objectUtils.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Deeply compares two objects for equality 3 | * @param obj1 First object to compare 4 | * @param obj2 Second object to compare 5 | * @returns boolean indicating if objects are equal 6 | */ 7 | export function areObjectsEqual(obj1: any, obj2: any): boolean { 8 | if (obj1 === obj2) return true; 9 | if (obj1 == null || obj2 == null) return false; 10 | if (typeof obj1 !== 'object' || typeof obj2 !== 'object') return false; 11 | 12 | if (Array.isArray(obj1) && Array.isArray(obj2)) { 13 | if (obj1.length !== obj2.length) return false; 14 | return obj1.every((val, idx) => areObjectsEqual(val, obj2[idx])); 15 | } 16 | 17 | if (obj1 instanceof Date && obj2 instanceof Date) { 18 | return obj1.getTime() === obj2.getTime(); 19 | } 20 | 21 | const keys1 = Object.keys(obj1); 22 | const keys2 = Object.keys(obj2); 23 | 24 | if (keys1.length !== keys2.length) return false; 25 | 26 | return keys1.every((key) => { 27 | return keys2.includes(key) && areObjectsEqual(obj1[key], obj2[key]); 28 | }); 29 | } 30 | -------------------------------------------------------------------------------- /frontend/src/utils/stringUtils.ts: -------------------------------------------------------------------------------- 1 | export function truncate(str: string, n: number) { 2 | // slices long strings and ends with ... 3 | return str.length > n ? str.slice(0, n - 1) + '...' : str; 4 | } 5 | -------------------------------------------------------------------------------- /frontend/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 6 | "allowJs": false, 7 | "skipLibCheck": true, 8 | "esModuleInterop": false, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "ESNext", 13 | "moduleResolution": "Node", 14 | "resolveJsonModule": true, 15 | "types": ["vite-plugin-svgr/client"], 16 | "isolatedModules": true, 17 | "noEmit": true, 18 | "jsx": "react-jsx" 19 | }, 20 | "include": ["src"], 21 | "references": [{ "path": "./tsconfig.node.json" }] 22 | } 23 | -------------------------------------------------------------------------------- /frontend/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "allowSyntheticDefaultImports": true 7 | }, 8 | "include": ["vite.config.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /frontend/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | import svgr from 'vite-plugin-svgr'; 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | plugins: [react(), svgr()], 8 | }); 9 | -------------------------------------------------------------------------------- /tests/llm/test_openai.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from application.llm.openai import OpenAILLM 3 | 4 | class TestOpenAILLM(unittest.TestCase): 5 | 6 | def setUp(self): 7 | self.api_key = "test_api_key" 8 | self.llm = OpenAILLM(self.api_key) 9 | 10 | def test_init(self): 11 | self.assertEqual(self.llm.api_key, self.api_key) 12 | -------------------------------------------------------------------------------- /tests/test_app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | 3 | from application.api.answer.routes import answer 4 | from application.api.internal.routes import internal 5 | from application.api.user.routes import user 6 | from application.core.settings import settings 7 | 8 | 9 | 10 | def test_app_config(): 11 | app = Flask(__name__) 12 | app.register_blueprint(user) 13 | app.register_blueprint(answer) 14 | app.register_blueprint(internal) 15 | app.config["UPLOAD_FOLDER"] = "inputs" 16 | app.config["CELERY_BROKER_URL"] = settings.CELERY_BROKER_URL 17 | app.config["CELERY_RESULT_BACKEND"] = settings.CELERY_RESULT_BACKEND 18 | app.config["MONGO_URI"] = settings.MONGO_URI 19 | 20 | assert app.config["UPLOAD_FOLDER"] == "inputs" 21 | assert app.config["CELERY_BROKER_URL"] == settings.CELERY_BROKER_URL 22 | assert app.config["CELERY_RESULT_BACKEND"] == settings.CELERY_RESULT_BACKEND 23 | assert app.config["MONGO_URI"] == settings.MONGO_URI 24 | -------------------------------------------------------------------------------- /tests/test_celery.py: -------------------------------------------------------------------------------- 1 | from unittest.mock import patch 2 | from application.core.settings import settings 3 | from application.celery_init import make_celery 4 | 5 | 6 | @patch('application.celery_init.Celery') 7 | def test_make_celery(mock_celery): 8 | # Arrange 9 | app_name = 'test_app_name' 10 | 11 | # Act 12 | celery = make_celery(app_name) 13 | 14 | # Assert 15 | mock_celery.assert_called_once_with( 16 | app_name, 17 | broker=settings.CELERY_BROKER_URL, 18 | backend=settings.CELERY_RESULT_BACKEND 19 | ) 20 | celery.conf.update.assert_called_once_with(settings) 21 | assert celery == mock_celery.return_value -------------------------------------------------------------------------------- /tests/test_error.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from flask import Flask 3 | from application.error import bad_request, response_error 4 | 5 | 6 | @pytest.fixture 7 | def app(): 8 | app = Flask(__name__) 9 | return app 10 | 11 | 12 | def test_bad_request_with_message(app): 13 | with app.app_context(): 14 | message = "Invalid input" 15 | response = bad_request(status_code=400, message=message) 16 | assert response.status_code == 400 17 | assert response.json == {'error': 'Bad Request', 'message': message} 18 | 19 | 20 | def test_bad_request_without_message(app): 21 | with app.app_context(): 22 | response = bad_request(status_code=400) 23 | assert response.status_code == 400 24 | assert response.json == {'error': 'Bad Request'} 25 | 26 | 27 | def test_response_error_with_message(app): 28 | with app.app_context(): 29 | message = "Something went wrong" 30 | response = response_error(code_status=500, message=message) 31 | assert response.status_code == 500 32 | assert response.json == {'error': 'Internal Server Error', 'message': message} 33 | 34 | 35 | def test_response_error_without_message(app): 36 | with app.app_context(): 37 | response = response_error(code_status=500) 38 | assert response.status_code == 500 39 | assert response.json == {'error': 'Internal Server Error'} -------------------------------------------------------------------------------- /tests/test_openapi3parser.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from openapi_parser import parse 3 | from application.parser.file.openapi3_parser import OpenAPI3Parser 4 | 5 | 6 | @pytest.mark.parametrize( 7 | "urls, expected_base_urls", 8 | [ 9 | ( 10 | [ 11 | "http://petstore.swagger.io/v1", 12 | "https://api.example.com/v1/resource", 13 | "https://api.example.com/v1/another/resource", 14 | "https://api.example.com/v1/some/endpoint", 15 | ], 16 | ["http://petstore.swagger.io", "https://api.example.com"], 17 | ), 18 | ], 19 | ) 20 | def test_get_base_urls(urls, expected_base_urls): 21 | assert OpenAPI3Parser().get_base_urls(urls) == expected_base_urls 22 | 23 | 24 | def test_get_info_from_paths(): 25 | file_path = "tests/test_openapi3.yaml" 26 | data = parse(file_path) 27 | path = data.paths[1] 28 | assert ( 29 | OpenAPI3Parser().get_info_from_paths(path) 30 | == "\nget=Expected response to a valid request" 31 | ) 32 | 33 | 34 | def test_parse_file(): 35 | file_path = "tests/test_openapi3.yaml" 36 | results_expected = ( 37 | "Base URL:http://petstore.swagger.io,https://api.example.com\nPath1: " 38 | + "/pets\ndescription: None\nparameters: []\nmethods: \n" 39 | + "get=A paged array of pets\npost=Null " 40 | + "response\nPath2: /pets/{petId}\ndescription: None\n" 41 | + "parameters: []\nmethods: " 42 | + "\nget=Expected response to a valid request\n" 43 | ) 44 | openapi_parser_test = OpenAPI3Parser() 45 | results = openapi_parser_test.parse_file(file_path) 46 | assert results == results_expected 47 | 48 | 49 | if __name__ == "__main__": 50 | pytest.main() 51 | --------------------------------------------------------------------------------