From a6aac46a21b6216ad1db0dceed9aa6966f35dcd9 Mon Sep 17 00:00:00 2001 From: Kyo Lee Date: Fri, 15 Mar 2024 18:42:30 +0000 Subject: [PATCH 1/2] [Release] Docs Agent version 0.3.0 What's changed: - Refactoring of Docs Agent to support a more modularized architecture. - Added features: - Benchmarking: Includes benchmark test to measure the quality of AI generated responses. - Semantic Retrieval API: Supports using Gemini's Semantic Retrieval API to store text chunks online and the AQA model for question-answering. - Docs Agent CLI: Allows easy management of chunking documents, populating a vector database, launching the chatbot and more. --- demos/palm/python/docs-agent/README.md | 795 ++--- .../python/docs-agent/apps_script/README.md | 16 +- demos/palm/python/docs-agent/aqa.py | 132 - .../palm/python/docs-agent/chatbot/chatui.py | 314 -- .../palm/python/docs-agent/chatbot/launch.sh | 38 - .../docs-agent/chatbot/static/css/chatbox.css | 1 - .../docs-agent/chatbot/static/css/style.css | 339 -- .../chatbot/templates/chatui/result.html | 70 - demos/palm/python/docs-agent/config.yaml | 128 +- .../python/docs-agent/docs/cli-reference.md | 166 + demos/palm/python/docs-agent/docs/concepts.md | 376 +++ .../docs-agent-chat-app-screenshot-01.png | Bin 0 -> 265045 bytes .../palm/python/docs-agent/docs/whats-new.md | 2 + demos/palm/python/docs-agent/docs_agent.py | 377 --- .../docs_agent/agents/docs_agent.py | 493 +++ .../docs_agent/benchmarks/README.md | 164 + .../docs_agent/benchmarks/benchmarks.yaml | 52 + .../docs_agent/benchmarks/results.out | 12 + .../benchmarks/run_benchmark_tests.py | 223 ++ .../docs_agent/interfaces/README.md | 211 ++ .../interfaces/chatbot/__init__.py} | 15 +- .../docs_agent/interfaces/chatbot/chatui.py | 326 ++ .../interfaces/chatbot/static/css/chatbox.css | 1 + .../chatbot/static/css/style-chatui.css | 507 +++ .../chatbot/static/css/style-old.css | 406 +++ .../chatbot/static/images/favicon.png | Bin .../chatbot/static/javascript/app.js | 0 .../chatbot/templates/chatui/base.html | 4 +- .../chatbot/templates/chatui/index.html | 4 +- .../templates/chatui/index_experimental.html | 18 + .../chatbot/templates/chatui/result.html | 126 + .../templates/chatui/result_experimental.html | 117 + .../docs-agent/docs_agent/interfaces/cli.py | 313 ++ .../docs_agent/interfaces/hello_world.py | 84 + .../docs_agent/interfaces/run_console.py | 239 ++ .../docs-agent/docs_agent/memory/logging.py | 67 + .../docs_agent/models/google_genai.py | 143 + .../{modules => docs_agent/models}/palm.py | 0 .../models}/tokenCount.py | 29 +- .../docs_agent/postprocess/docs_retriever.py | 237 ++ .../preprocess}/README.md | 4 +- .../preprocess/files_to_plain_text.py | 470 +++ .../preprocess/populate_vector_database.py | 406 +++ .../preprocess/splitters}/html_splitter.py | 14 +- .../splitters}/markdown_splitter.py | 237 +- .../docs-agent/docs_agent/storage/chroma.py | 569 ++++ .../storage/google_semantic_retriever.py | 274 ++ .../testing/test_vector_database.py | 184 ++ .../docs-agent/docs_agent/utilities/config.py | 458 +++ .../docs_agent/utilities/helpers.py | 182 ++ demos/palm/python/docs-agent/hello_world.py | 74 - .../palm/python/docs-agent/modules/chroma.py | 203 -- demos/palm/python/docs-agent/poetry.lock | 2765 ++++++----------- demos/palm/python/docs-agent/pyproject.toml | 24 +- demos/palm/python/docs-agent/run_console.py | 72 - .../docs-agent/scripts/files_to_plain_text.py | 402 --- .../scripts/markdown_to_plain_text.py | 419 --- .../scripts/populate_vector_database.py | 440 --- .../python/docs-agent/scripts/read_config.py | 143 - .../scripts/test_vector_database.py | 140 - .../{chatbot/__init__.py => tellme.sh} | 12 +- .../third_party/g2docsmd-html/exportmd.gs | 86 +- 62 files changed, 8373 insertions(+), 5750 deletions(-) delete mode 100644 demos/palm/python/docs-agent/aqa.py delete mode 100644 demos/palm/python/docs-agent/chatbot/chatui.py delete mode 100755 demos/palm/python/docs-agent/chatbot/launch.sh delete mode 120000 demos/palm/python/docs-agent/chatbot/static/css/chatbox.css delete mode 100644 demos/palm/python/docs-agent/chatbot/static/css/style.css delete mode 100644 demos/palm/python/docs-agent/chatbot/templates/chatui/result.html create mode 100644 demos/palm/python/docs-agent/docs/cli-reference.md create mode 100644 demos/palm/python/docs-agent/docs/concepts.md create mode 100644 demos/palm/python/docs-agent/docs/images/docs-agent-chat-app-screenshot-01.png delete mode 100644 demos/palm/python/docs-agent/docs_agent.py create mode 100644 demos/palm/python/docs-agent/docs_agent/agents/docs_agent.py create mode 100644 demos/palm/python/docs-agent/docs_agent/benchmarks/README.md create mode 100644 demos/palm/python/docs-agent/docs_agent/benchmarks/benchmarks.yaml create mode 100644 demos/palm/python/docs-agent/docs_agent/benchmarks/results.out create mode 100644 demos/palm/python/docs-agent/docs_agent/benchmarks/run_benchmark_tests.py create mode 100644 demos/palm/python/docs-agent/docs_agent/interfaces/README.md rename demos/palm/python/docs-agent/{setup.py => docs_agent/interfaces/chatbot/__init__.py} (67%) create mode 100644 demos/palm/python/docs-agent/docs_agent/interfaces/chatbot/chatui.py create mode 120000 demos/palm/python/docs-agent/docs_agent/interfaces/chatbot/static/css/chatbox.css create mode 100644 demos/palm/python/docs-agent/docs_agent/interfaces/chatbot/static/css/style-chatui.css create mode 100644 demos/palm/python/docs-agent/docs_agent/interfaces/chatbot/static/css/style-old.css rename demos/palm/python/docs-agent/{ => docs_agent/interfaces}/chatbot/static/images/favicon.png (100%) rename demos/palm/python/docs-agent/{ => docs_agent/interfaces}/chatbot/static/javascript/app.js (100%) rename demos/palm/python/docs-agent/{ => docs_agent/interfaces}/chatbot/templates/chatui/base.html (94%) rename demos/palm/python/docs-agent/{ => docs_agent/interfaces}/chatbot/templates/chatui/index.html (91%) create mode 100644 demos/palm/python/docs-agent/docs_agent/interfaces/chatbot/templates/chatui/index_experimental.html create mode 100644 demos/palm/python/docs-agent/docs_agent/interfaces/chatbot/templates/chatui/result.html create mode 100644 demos/palm/python/docs-agent/docs_agent/interfaces/chatbot/templates/chatui/result_experimental.html create mode 100644 demos/palm/python/docs-agent/docs_agent/interfaces/cli.py create mode 100644 demos/palm/python/docs-agent/docs_agent/interfaces/hello_world.py create mode 100644 demos/palm/python/docs-agent/docs_agent/interfaces/run_console.py create mode 100644 demos/palm/python/docs-agent/docs_agent/memory/logging.py create mode 100644 demos/palm/python/docs-agent/docs_agent/models/google_genai.py rename demos/palm/python/docs-agent/{modules => docs_agent/models}/palm.py (100%) rename demos/palm/python/docs-agent/{scripts => docs_agent/models}/tokenCount.py (85%) create mode 100644 demos/palm/python/docs-agent/docs_agent/postprocess/docs_retriever.py rename demos/palm/python/docs-agent/{scripts => docs_agent/preprocess}/README.md (97%) create mode 100644 demos/palm/python/docs-agent/docs_agent/preprocess/files_to_plain_text.py create mode 100644 demos/palm/python/docs-agent/docs_agent/preprocess/populate_vector_database.py rename demos/palm/python/docs-agent/{scripts => docs_agent/preprocess/splitters}/html_splitter.py (88%) rename demos/palm/python/docs-agent/{scripts => docs_agent/preprocess/splitters}/markdown_splitter.py (76%) create mode 100644 demos/palm/python/docs-agent/docs_agent/storage/chroma.py create mode 100644 demos/palm/python/docs-agent/docs_agent/storage/google_semantic_retriever.py create mode 100644 demos/palm/python/docs-agent/docs_agent/testing/test_vector_database.py create mode 100644 demos/palm/python/docs-agent/docs_agent/utilities/config.py create mode 100644 demos/palm/python/docs-agent/docs_agent/utilities/helpers.py delete mode 100644 demos/palm/python/docs-agent/hello_world.py delete mode 100644 demos/palm/python/docs-agent/modules/chroma.py delete mode 100644 demos/palm/python/docs-agent/run_console.py delete mode 100644 demos/palm/python/docs-agent/scripts/files_to_plain_text.py delete mode 100644 demos/palm/python/docs-agent/scripts/markdown_to_plain_text.py delete mode 100644 demos/palm/python/docs-agent/scripts/populate_vector_database.py delete mode 100644 demos/palm/python/docs-agent/scripts/read_config.py delete mode 100644 demos/palm/python/docs-agent/scripts/test_vector_database.py rename demos/palm/python/docs-agent/{chatbot/__init__.py => tellme.sh} (76%) mode change 100644 => 100755 diff --git a/demos/palm/python/docs-agent/README.md b/demos/palm/python/docs-agent/README.md index 69b6067e9..4b30e9644 100644 --- a/demos/palm/python/docs-agent/README.md +++ b/demos/palm/python/docs-agent/README.md @@ -1,390 +1,158 @@ # Docs Agent -The Docs Agent project enables [Gemini API][genai-doc-site] (previously PaLM API) users to -launch a chat application on a Linux host machine using their documents as a dataset. +The Docs Agent project explores applications and use cases that involve using a large +corpus of documentation as a knowledge source for AI language models. -**Note**: If you want to set up and launch the Docs Agent sample app on your host machine, -check out the [Set up Docs Agent][set-up-docs-agent] section below. +Docs Agent provides a set of easy-to-use self-service tools designed to give you and +your team access to Google's [Gemini API][genai-doc-site] for learning, experimentation, +and project deployment. ## Overview -The Docs Agent project is being developed to demonstrate an AI-powered chatbot application -(including a backend server and web UI) that can answer questions specific to any product, -service, or topic that has a large amount of information available in documentation (which -can be from various sources such as Markdown, HTML, Google Docs, Gmail, PDF, etc.). - -The main goal of the Docs Agent project is: - -- You can supply your own set of documents to enable Google AI models to generate useful, - relevant, and accurate responses that are grounded on the documented information. - -The Docs Agent sample app is designed to be easily set up and configured in a Linux environment -and is required that you have access to Google’s [Gemini API][genai-doc-site]. - -Keep in mind that this approach does not involve “fine-tuning” an LLM (large language model). -Instead, the Docs Agent sample app uses a mixture of prompt engineering and embedding techniques, -also known as Retrieval Augmented Generation (RAG), on top of a publicly available LLM model -like Gemini Pro. +Docs Agent apps use a technique known as Retrieval Augmented Generation (RAG), which allows +you to bring your own documents as knowledge sources to AI language models. This approach +helps the AI language models to generate relevant and accurate responses that are grounded +in the information that you provide and control. ![Docs Agent architecture](docs/images/docs-agent-architecture-01.png) **Figure 1**. Docs Agent uses a vector database to retrieve context for augmenting prompts. -## Main features - -The key features of the Docs Agent sample app are: - -- Add context to user questions to augment their prompts to an LLM. -- Process documents into embeddings and store them in a vector database for context retrieval. - -![Docs Agent flow](docs/images/docs-agent-architecture-02.png) - -**Figure 2**. A user question is augmented by the Docs Agent server and passed to an LLM. - -**Note**: For the moment, the Docs Agent project focuses on providing Python scripts that make it -easy to process Markdown files into embeddings. However, there is no hard requirement that the -source documents must exist in Markdown format. What’s important is that the processed content -is available as embeddings in the vector database. - -### Structure of a prompt to a language model - -To enable an LLM to answer questions that are not part of the public knowledge (which the LLM -is likely trained on), the Docs Agent project applies a mixture of prompt engineering and -embeddings techniques. That is, we process a set of documents (which contain domain specific -knowledge) into embeddings and store them in a vector database. This vector database allows -the Docs Agent server to perform semantic search on stored embeddings to find the most relevant -content from the source documents given user questions. - -Once the most relevant content is returned, the Docs Agent server uses the prompt structure -shown in Figure 3 to augment the user question with a preset **condition** and a list of -**context**. (When the Docs Agent server starts, the condition value is read from the -[`config.yaml`][config-yaml] file.) Then the Docs Agent server sends this prompt to a -language model using the Gemini API and receives a response generated by the model. - -![Docs Agent prompt strcture](docs/images/docs-agent-prompt-structure-01.png) - -**Figure 3**. Prompt structure for augmenting a user question with related context -(Context source: [eventhorizontelescope.org][context-source-01]) - -### Processing of Markdown files into embeddings - -To process information into embeddings using the Python scripts in the project, the -information needs to be stored in Markdown format. Once you have a set of Markdown files -stored in a directory on your host machine, you can run the -[`markdown_to_plain_text.py`][markdown-to-plain-text] script to process those Markdown -files into small plain text files – the script splits the content by the top three Markdown -headers (`#`, `##`, and `###`). - -Once Markdown files are processed into small plain text files, you can run the -[`populate_vector_database.py`][populate-vector-database] script to generate embeddings -for each text file and store those embeddings into a [Chroma][chroma-docs] vector database -running on the host machine. - -The embeddings in this vector database enable the Docs Agent server to perform semantic search -and retrieve context related to user questions for augmenting prompts. - -For more information on the processing of Markdown files, see the [`README`][scripts-readme] -file in the `scripts` directory. - -![Document to embeddings](docs/images/docs-agent-embeddings-01.png) +Docs Agent apps are designed to be easily set up and configured in a Linux environment. +If you want to set up and launch the Docs Agent chat app on your host machine, check out +the [Set up Docs Agent][set-up-docs-agent] section below. -**Figure 4**. A document is split into small semantic chunks, which are then used to generate -embeddings. +### Summary of features -![Markdown to embeddings](docs/images/docs-agent-embeddings-02.png) - -**Figure 5**. A Markdown page is split by headers and processed into embeddings. - -## Summary of tasks and features - -The following list summarizes the tasks and features of the Docs Agent sample app: +The following list summarizes the tasks and features supported by Docs Agent: - **Process Markdown**: Split Markdown files into small plain text files. (See the - [`markdown_to_plain_text.py`][markdown-to-plain-text] script.) -- **Generate embeddings**: Use small plain text files to generate embeddings, processed by - an embedding model (`embedding-gecko-001`), and store them in a local Chroma vector - database. (See the [`populate_vector_database.py`][populate-vector-database] script.) -- **Semantic search using embeddings**: Compare embeddings in the vector database for most - relevant content given user questions (which are also processed into embeddings using - the same `embedding-gecko-001` model). -- **Add context to a user question in a prompt**: Add the list of content returned from - the semantic search as context to the user question and send the prompt to a language - model using the Gemini API. -- **(Experimental) “Fact-check” responses**: This experimental feature composes a - follow-up prompt and asks the language model to “fact-check” its own previous response. - (See the [Using a language model to fact-check its own response][fact-check-section] section.) -- **Generate 5 related questions**: In addition to displaying a response to the user - question, the web UI displays five questions generated by the language model based on + Python scripts in the [`preprocess`][preprocess-dir] directory.) +- **Generate embeddings**: Use an embedding model to process small plain text files + into embeddings, and store them in a vector database. (See the + [`populate_vector_database.py`][populate-vector-database] script.) +- **Perform semantic search**: Compare embeddings in the vector database to retrieve + most relevant content given user questions. +- **Add context to a user question**: Add a list of text chunks returned from + a semantic search as context in a prompt. (See the + [Structure of a prompt to a language model][prompt-structure] section.) +- **(Experimental) “Fact-check” responses**: This experimental feature composes + a follow-up prompt and asks the language model to “fact-check” its own previous response. + (See the [Using a language model to fact-check its own response][fact-check-section] + section.) +- **Generate related questions**: In addition to displaying a response to the user + question, the web UI displays 5 questions generated by the language model based on the context of the user question. (See the - [Using a language model to suggest related questions][related-questions-section] section.) -- **Display URLs of knowledge sources**: The vector database stores URLs as metadata for - embeddings. Whenever the vector database is used to retrieve context (for instance, to - provide context to user questions), the database can also return the URLs of the sources - that were originally used to generate the embeddings. -- **Submit rewrites and likes**: The web UI includes the buttons at the bottom of the - display that allow users to like generated responses or submit rewrites of - the responses. (See the - [Enabling users to submit a rewrite of a generated response][submit-a-rewrite] and - [Enabling users to like generated responses][like-generate-responses] sections.) + [Using a language model to suggest related questions][related-questions-section] + section.) +- **Return URLs of documentation sources**: Docs Agent's vector database stores URLs + as metadata next to embeddings. Whenever the vector database is used to retrieve + text chunks for context, the database can also return the URLs of the sources used + to generate the embeddings. +- **Collect feedback from users**: Docs Agent's chatbot web UI includes buttons that + allow users to [like generated responses][like-generated-responses] or + [submit rewrites][submit-a-rewrite]. - **Convert Google Docs, PDF, and Gmail into Markdown files**: This feature uses Apps Script to convert Google Docs, PDF, and Gmail into Markdown files, which then - can be used as input datasets for Docs Agent. For more information, see the - [`README`][apps-script-readme] file in the `apps_script` directory. -- **Use Gemini's Semantic Retrieval API and AQA model**: You can set up Docs Agent - to use Gemini's [Semantic Retrieval API][semantic-api] and [AQA model][aqa-model]. - This API enables you to upload your source documents online, instead of using - a local vector database, and use Gemini's `aqa` model that is specifically - created for question-answering. - -## Flow of events - -The following events take place in the Docs Agent sample app: - -1. The [`markdown_to_plain_text.py`][markdown-to-plain-text] script converts input - Markdown documents into small plain text files, split by Markdown headings - (`#`, `##`, and `###`). -2. The [`populate_vector_database.py`][populate-vector-database] script generates - embeddings from the small plain text files and populates a vector database. -3. When the [`chatbot/launch.sh`][launch-script] script is run, it starts the - Docs Agent server and vector database, which loads generated embeddings and - metadata (URLs and filenames) stored in the `vector_store` directory. -4. When the user asks a question, the Docs Agent server uses the vector database to - perform semantic search on embeddings, which represent content in the source - documents. -5. Using this semantic search capability, the Docs Agent server finds a list of - text chunks that are most relevant to the user question. -6. The Docs Agent server adds this list of text chunks as context (plus a condition - for responses) to the user question and constructs them into a prompt. -7. The system sends the prompt to a language model via the Gemini API. -8. The language model generates a response and the Docs Agent server renders it on - the chat UI. - -Additional events for [“fact-checking” a generated response][fact-check-section]: - -9. The Docs Agent server prepares another prompt that compares the generated response - (in step 8) to the context (in step 6) and asks the language model to look for - a discrepancy in the response. -10. The language model generates a response that points out one major discrepancy - (if it exists) between its previous response and the context. -11. The Docs Agent server renders this response on the chat UI as a call-out note. -12. The Docs Agent server passes this second response to the vector database to - perform semantic search. -13. The vector database returns a list of relevant content (that is closely related - to the second response). -14. The Docs Agent server renders the top URL of this list on the chat UI and - suggests that the user checks out this URL for fact-checking. - -Additional events for -[suggesting 5 questions related to the user question][related-questions-section]: - -15. The Docs Agent server prepares another prompt that asks the language model to - generate 5 questions based on the context (in step 6). -16. The language model generates a response that contains a list of questions related - to the context. -17. The Docs Agent server renders the questions on the chat UI. - -## Supplementary features - -This section describes additional features implemented on the Docs Agent sample app for -enhancing the usability of the Q&A experience powered by generative AI. - -![Docs Agent UI](docs/images/docs-agent-ui-screenshot-01.png) - -**Figure 6**. A screenshot of the Docs Agent chat UI showing the sections generated by -three distinct prompts. - -### Using a language model to fact-check its own response - -In addition to using the prompt structure above (shown in Figure 3), we‘re currently -experimenting with the following prompt setup for “fact-checking” responses generated -by the language model: - -- Condition: - - ``` - You are a helpful chatbot answering questions from users. Read the following context - first and answer the question at the end: - ``` - -- Context: - - ``` - - ``` - -- Additional condition (for fact-checking): - - ``` - Can you compare the text below to the information provided in this prompt above - and write a short message that warns the readers about which part of the text they - should consider fact-checking? (Please keep your response concise and focus on only - one important item.)" - ``` - -- Previously generated response - - ``` - Text: - ``` - -This "fact-checking" prompt returns a response similar to the following example: - -``` -The text states that Flutter chose to use Dart because it is a fast, productive, object-oriented -language that is well-suited for building user interfaces. However, the context provided in the -prompt states that Flutter chose Dart because it is a fast, productive language that is well-suited -for Flutter's problem domain: creating visual user experiences. Therefore, readers should consider -fact-checking the claim that Dart is well-suited for building user interfaces. -``` - -After the second response, notice that the Docs Agent chat UI also suggests a URL to visit for -fact-checking (see Figure 6), which looks similar to the following example: - -``` -To verify this information, please check out: - -https://docs.flutter.dev/resources/faq -``` - -To identify this URL, the Docs Agent server takes the second response (which is the paragraph that -begins with “The text states that ...” in the example above) and uses it to query the vector -database. Once the vector database returns a list of the most relevant content to this response, -the UI only displays the top URL to the user. - -Keep in mind that this "fact-checking" prompt setup is currently considered **experimental** -because we‘ve seen cases where a language model would end up adding incorrect information into its -second response as well. However, we saw that adding this second response (which brings attention -to the language model’s possible hallucinations) seems to improve the usability of the system since it -serves as a reminder to the users that the language model‘s response is far from being perfect, which -helps encourage the users to take more steps to validate generated responses for themselves. - -### Using a language model to suggest related questions - -The project‘s latest web UI includes the “Related questions” section, which displays five -questions that are related to the user question (see Figure 6). These five questions are also -generated by a language model (via the Gemini API). Using the list of contents returned from the vector -database as context, the system prepares another prompt asking the language model to generate five -questions from the included context. - -The following is the exact structure of this prompt: - -- Condition: - - ``` - Read the context below and answer the question at the end: - ``` - -- Context: + can be used as input datasets for Docs Agent. (See the + [`apps_script`][apps-script-readme] directory.) +- **Run benchmark test to monitor the quality of AI-generated responses**: Using + Docs Agent, you can run [benchmark test][benchmark-test] to measure and compare + the quality of text chunks, embeddings, and AI-generated responses. +- **Use the Semantic Retrieval API and AQA model**: You can use Gemini's + [Semantic Retrieval API][semantic-api] to upload source documents to an online + corpus and use the [AQA model][aqa-model] that is specifically created for answering + questions using an online corpus. +- **Manage online corpora using the Docs Agent CLI**: The Docs Agent CLI enables you + to create, populate, update and delete online corpora using the Semantic Retrieval AI. + For the list of all available Docs Agent command lines, see the + [Docs Agent CLI reference][cli-reference] page. +- **Run the Docs Agent CLI from anywhere on a terminal**: You can set up the + Docs Agent CLI to ask questions to the Gemini model from anywhere on a terminal. + For more information, see the [Set up Docs Agent CLI][cli-readme] page. + +For more information on Docs Agent's architecture and features, +see the [Docs Agent concepts][docs-agent-concepts] page. + +![Docs Agent chat app](docs/images/docs-agent-chat-app-screenshot-01.png) + +**Figure 2**. A screenshot of the Docs Agent chat app launched using Flutter docs. - ``` - - ``` - -- Question: - - ``` - What are 5 questions developers might ask after reading the context? - ``` +## Set up Docs Agent -### Enabling users to submit a rewrite of a generated response +**Note**: For instructions on the Docs Agent CLI setup, see the +[`README.md`][cli-readme] file in the `docs_agent/interfaces` directory. -The project‘s latest web UI includes the **Rewrite this response** button at the bottom of -the panel (see Figure 6). When this button is clicked, a widget opens up, expanding the -main UI panel, and reveals a textarea containing the generated response to the user's question. -The user is then allowed to edit this response in the textarea and click the **Submit** button -to submit the updated response to the system. +This section provides instructions on how to set up and launch the Docs Agent +chatbot web app on a Linux host machine. -The system stores the submitted response as a Markdown file in the project's local `rewrites` -directory. The user may re-click the **Submit** button to update the submitted rewrite multiple -times. +### 1. Prerequisites -### Enabling users to like generated responses +Setting up Docs Agent requires the following prerequisite items: -The project's latest web UI includes the **Like this response** button at the bottom of the panel -(see Figure 6). When this button is clicked, the server logs the event of "like" for the response. -However, clicking the **Liked** button again will reset the button. Then the server logs this reset -event of "like" for the response. +- A Linux host machine -The user may click this like button multiple times to toggle the state of the like button. But when -examining the logs, only the final state of the like button will be considered for the response. +- A [Google Cloud][google-cloud] project with the setup below: -### Using Google Docs, PDF, or Gmail as input sources + - An API key enabled with the Generative Language API (that is, + the [Gemini API][genai-doc-site]) -The project includes Apps Script files that allow you to convert various sources of content -(including Google Docs and PDF) from your Google Drive and Gmail into Markdown files. You can then -use these Markdown files as additional input sources for Docs Agent. For more information, see the -[`README`][apps-script-readme] file in the `apps_script` directory. + - (**Optional**) [Authenticated OAuth client credentials][oauth-client] + stored on the host machine -![Docs Agent pre-processing flow](docs/images/docs-agent-pre-processing-01.png) +### 2 Update your host machine's environment -**Figure 7**. Docs Agent's pre-processing flow for various doc types. +Update your host machine's environment to prepare for the Docs Agent setup: -### Using the Semantic Retrieval API and AQA model +1. Update the Linux package repositories on the host machine: -Docs Agent provides options to use Gemini's [Semantic Retrieval API][semantic-api] for storing text -chunks in Google Cloud's online storage (and using this online storage for context retrieval), -in combination with using the [AQA model][aqa-model] for question-answering. + ```posix-terminal + sudo apt update + ``` -To use the Semantic Retrieval API, update the `config.yaml` file to include the following settings: +2. Install the following dependencies: -``` -db_type: "ONLINE_STORAGE" -is_aqa_used: "YES" -``` + ```posix-terminal + sudo apt install git pip python3-venv + ``` -The setup above uses both the Semantic Retrieval API to store text chunks online and the AQA model. +3. Install `poetry`: -**Note**: At the moment, when `db_type` is set to `ONLINE_STORAGE`, running the -`populate_vector_database.py` script will also create and popluate a local vector database using -Chroma as well as creating and populating a corpus online using the Semantic Retrieval API. + ```posix-terminal + curl -sSL https://install.python-poetry.org | python3 - + ``` -However, if you want to use only the AQA model for question-answering, but without creating a -corpus online, update the `config.yaml` file to include the following settings instead: + **Important**: Make sure that `$HOME/.local/bin` is in your `PATH` variable + (for example, `export PATH=$PATH:~/.local/bin`). -``` -db_type: "LOCAL_DB" -is_aqa_used: "YES" -``` - -The setup above uses the AQA model with your local Chroma vector database. (For more information, -see the [More Options: AQA Using Inline Passages][inline-passages] section on the -_Semantic Retriever Quickstart_ page.) +4. Set the following environment variable: -**Note**: To use the Semantic Retrieval API, you need to complete the OAuth setup for your Google -Cloud project from your host machine. For detailed instructions, see the -[Authentication with OAuth quickstart][oauth-quickstart] page. + ```posix-terminal + export PYTHON_KEYRING_BACKEND=keyring.backends.null.Keyring + ``` -## Issues identified + This is a [known issue][poetry-known-issue] in `poetry`. -The following issues have been identified and need to be worked on: +5. Set the Google API key as a environment variable: -- **Logical content chunking**: When splitting documents, content is divided into chunks only by the - current 1500-character limit. This approach splits large docs into small chunks, which results in - losing context, especially in large how-to guides with a long sequence of instructions. **[Done]** -- **Clean plain text for embeddings**: The current Markdown processing method doesn’t fully filter - out all Markdown and HTML syntax, which seems to have a negative influence on embeddings. -- **Database support for embeddings**: The system needs a proper database setup for faster lookup - and for enabling us to store metadata (such as URLs) next to embeddings. **[Done]** -- **Better prompting**: We haven’t widely explored all best practices in prompting. Also consider - supporting dynamic prompting given user questions. -- **Real-world feedback**: We need to set up a feedback loop to collect real-world user - interactions, including example prompts and responses, and start using them as part of embeddings. + ``` + export GOOGLE_API_KEY= + ``` -## Set up Docs Agent + Replace `` with the API key to the + [Gemini API][genai-doc-site]. -This section provides instructions on how to set up the Docs Agent project on a Linux host machine. + **Tip**: To avoid repeating these `export` lines, add them to your + `$HOME/.bashrc` file. -### 0. (Optional) Authorize credentials for Docs Agent +### 3. (Optional) Authorize credentials for Docs Agent -**This step is needed only if you plan to use Gemini's AQA model.** For more information on this -feature, see the -[Using the Semantic Retrieval API and AQA model](#using-the-semantic-retrieval-api-and-aqa-model) -section above. +**This step is needed only if you plan to use [Gemini's AQA model][aqa-model-concept].** -1. Download the `client_secret.json` file from your Google Cloud Project (GCP) account. +Authorize Google Cloud credentials on your host machine: - See [Authorize credentials for a desktop application][authorize-credentials] - on the _AI for Developers_ doc site. +1. Download the `client_secret.json` file from your + [Google Cloud project][authorize-credentials]. 2. Copy the `client_secret.json` file to your host machine. @@ -406,63 +174,30 @@ section above. (`application_default_credentials.json`) in the `$HOME/.config/gcloud/` directory of your host machine. -### 1. Prerequisites +### 4. Clone the Docs Agent project repository -1. Update the Linux package repositories on the host machine: - - ```posix-terminal - sudo apt update - ``` - -2. Install the following dependencies: +**Note**: This guide assumes that you're creating a new project directory +from your `$HOME` directory. - ```posix-terminal - sudo apt install git pip python3-venv - ``` +Clone the Docs Agent repository and install dependencies: -3. Install `poetry`: +1. Clone the following internal repo: ```posix-terminal - curl -sSL https://install.python-poetry.org | python3 - + git clone sso://doc-llm-internal/docs-agent ``` - **Important**: Make sure that `$HOME/.local/bin` is in your `PATH` variable. - -4. Set the following environment variable: +2. Go to the project directory: ```posix-terminal - export PYTHON_KEYRING_BACKEND=keyring.backends.null.Keyring + cd docs-agent ``` - This is a [known issue][poetry-known-issue] in `poetry`. - -5. Set the Gemini API key as a environment variable: +3. (**Optional**) If you plan on contributing to the `docs-agent` repo, + run the following command to set up your commit hook: ``` - export PALM_API_KEY= - ``` - - Replace `` with the API key to - [Generative Language API][genai-doc-site]. - - **Tip**: To avoid repeating these `export` lines, add them to your - `$HOME/.bashrc` file. - -### 2. Clone this project repository and install dependencies - -**Note**: This guide assumes that you're cloning the `generative-ai-docs` repository -from your `$HOME` directory. - -1. Clone the `generative-ai-docs` repository, for example: - - ```posix-terminal - git clone https://github.com/google/generative-ai-docs - ``` - -2. Go to the Docs Agent project directory: - - ```posix-terminal - cd ./generative-ai-docs/demos/palm/python/docs-agent + curl -Lo `git rev-parse --git-dir`/hooks/commit-msg https://gerrit-review.googlesource.com/tools/hooks/commit-msg ; chmod +x `git rev-parse --git-dir`/hooks/commit-msg ``` 4. Install dependencies using `poetry`: @@ -479,42 +214,27 @@ from your `$HOME` directory. poetry shell ``` - **Important**: From this point, all command lines in the sections below need to run - in this `poetry shell` environment. - - -Now, the next step is to populate a vector database with your own documents. See the -[Populate a new vector database from Markdown files][populate-db-steps] section below. + **Important**: From this point, all `agent` command lines below need to + run in this `poetry shell` environment. -## Populate a new vector database from Markdown files +### 5. Edit the Docs Agent configuration file -This section provides instructions on how to bring your own set of documents and create and -populate a vector database (`vector_stores/chroma`) on your host machine. The Python scripts -in the project's `scripts` directory can help you populate documents, embeddings and metadata -from Markdown files (`.md`). +This guide uses the [open source Flutter documents][flutter-docs-src] as an example dataset, +which are the source Markdown files for the [Flutter website][flutter-docs-site]. -This section uses the [open source Flutter documents][flutter-docs-src] as an example dataset, -which are the source Markdown files for the [Flutter website][flutter-docs-site]. To download -the open source Flutter documents on your host machine, run the following command: +To complete this setup walkthrough, run the command below to download the open source +Flutter documents somewhere on your host machine (for instance, in your `$HOME` directory): ``` git clone --recurse-submodules https://github.com/flutter/website.git ``` -**Note**: The Flutter documents are used in this section as an example dataset only. The -Python scripts below are designed to work with any documents in the standard Markdown format. - -### 1. Convert Markdown files to plain text files - -Before generating embeddings, you need to process Markdown files into small chunks of -plain text files. +Update settings in the Docs Agent project to use your custom dataset: -To convert Markdown files to plain text files: - -1. Go to the Docs Agent project directory, for example: +1. Go to the Docs Agent project home directory, for example: ``` - cd $HOME/generative-ai-docs/demos/palm/python/docs-agent + cd $HOME/docs-agent ``` 2. Open the [`config.yaml`][config-yaml] file using a text editor, for example: @@ -523,204 +243,203 @@ To convert Markdown files to plain text files: nano config.yaml ``` -3. (**Optional**) Edit `output_path` to a directory that will store plain text files, - for example: +3. Edit the file to update the `product_name` field, for example: ``` - output_path: "data/plain_docs" + product_name: "Flutter" ``` - The example above creates a new directory named `data/plain_docs` in the current project - directory (which results in `generative-ai-docs/demos/palm/python/docs-agent/data/plain_docs`). - Then the project uses this `output_path` directory to store the plain text files processed - from the input Markdown files. + This product name is displayed on the Docs Agent chat app UI. -4. Under the `input` field, define the following entries to specify the directories +4. Under the `inputs` field, define the following entries to specify the directories that contain your source Markdown files. - `path`: The directory where the source Markdown files are stored. - `url_prefix`: The prefix used to create URLs for the source Markdown files. - If the URLs do not exist for the source files, provide a mock string. - - (**Optional**) `exclude_path`: The sub-directory to be excluded from - the path directory. - The example below shows the entries for the Flutter documents downloaded on the - host machine (that is, in the `/home/downloads/website` directory): + **Important**: If URLs do not exist for your Markdown files, you still need to + provide a placeholder string in the `url_prefix` field. + + The example below shows the entries for the Flutter documents downloaded in the + `$HOME/website` directory): ``` - input: - - path: "/home/downloads/website/src" + inputs: + - path: "/usr/local/home/user01/website/src" url_prefix: "https://docs.flutter.dev" ``` - You can also provide a number of input directories (`path` and `url_prefix` sets) under - the input field, for example: + You can also provide multiple input directories (`path` and `url_prefix` sets) under + the `inputs` field, for example: ``` - input: - - path: "/home/downloads/website/src/ui" + inputs: + - path: "/usr/local/home/user01/website/src/ui" url_prefix: "https://docs.flutter.dev/ui" - - path: "/home/downloads/website/src/codelabs" - url_prefix: "https://docs.flutter.dev/codelabs" + - path: "/usr/local/home/user01/website/src/tools" + url_prefix: "https://docs.flutter.dev/tools" ``` -5. Save the file and exit the text editor. - -6. Run the Python script: +6. (**Optional**) If you want to use the Gemini AQA model and populate a corpus online + via the [Semantic Retrieval API][semantic-api], use the following settings: ``` - python3 scripts/files_to_plain_text.py + models: + - language_model: "models/aqa" + ... + db_type: "google_semantic_retriever" ``` - For a large number of Markdown files, it may take a few minutes to process - Markdown files. + Or if you want to use the `gemini-pro` model with a local vector database setup + (`chroma`), use the following settings: - **Important**: The `markdown_to_plain_text.py` script is being deprecated in - favor of the [`files_to_plain_text.py`][files-to-plain-text] script. + ``` + models: + - language_model: "models/gemini-pro" + ... + db_type: "chroma" + ``` -### 2. Populate a new vector database +7. Save the `config.yaml` file and exit the text editor. -Once you have plain text files processed and stored in the `output_path` directory, -you can run the `populat_vector_database.py` script to populate a vector database -with the contents of the plain text files and their embeddings (and metadata). -**Important**: For a clean setup, if the `vector_stores/chroma` directory already -exists, delete (or move) the `chroma` directory before populating a new vector -database. (Otherwise, new entries will be added to your existing vector database.) -Also, if the Docs Agent chat app is already running using this `chroma` directory, -shut down the app before deleting the directory. +### 6. Populate a new vector database -To populate a new vector database: +The Docs Agent CLI can help you chunk documents, generate embeddings extract metadata, +and populate a vector database from Markdown files and more. -1. Go to the Docs Agent project directory, for example: +**Note**: The `agent` commands below need to run within the `poetry shell` environment. - ``` - cd $HOME/generative-ai-docs/demos/palm/python/docs-agent - ``` +To populate a new vector database: -2. Create and populate a new vector database: +1. Go to the Docs Agent project home directory, for example: ``` - python3 ./scripts/populate_vector_database.py + cd $HOME/docs-agent ``` - This script uses the `output_path` directory from the `config.yaml` file to locate - plain text files and creates a new directory at - `generative-ai-docs/demos/palm/python/docs-agent/vector_stores/chroma`, which - contains embeddings and metadata. - -3. To test the new vector database, run the following script: +2. Process Markdown files into small text chunks: ``` - python3 ./scripts/test_vector_database.py + agent chunk ``` - **Note**: Adjust `QUESTION` in `scripts/test_vector_database.py` to be suitable for - the content in your database. - -The next step is to launch the Docs Agent chat app to use the new vector database. See -the [Start the Docs Agent chat app][start-the-app-steps] section below. - -## Start the Docs Agent chat app - -**Important**: This section assumes that you've already created a `vector_stores/chroma` -directory, which contains artifacts for the vector database. If you haven't, see the -[Populate a new vector database from Markdown files][populate-db-steps] section above. + The command takes documents under the `inputs` fields (specified in your + `config.yaml` file), splits the documents into small text chunk files, and + stores them in the `output_path` direcoty. -This Flask app lets users interact with the Docs Agent service through a web browser. The -`launch.sh` script deploys the Flask app in a Python virtual environment (`poetry`), -allowing you to easily bring up and destory the Flask app instance. - -### 1. Configure the Docs Agent chat app - -To customize settings in the Docs Agent chat app, do the following: - -1. Edit the [`config.yaml`][config-yaml] file to update the following field: +3. Create and populate a new vector database: ``` - product_name: "My product" + agent populate ``` - Replace `My product` with your product name (which shows up as the main label on the UI), - for example: - - ``` - product_name: "Flutter" - ``` + This command takes the plain text files in the `output_path` directory + and creates a new Chroma collection in the `vector_stores/` directory. -2. (**Optional**) Edit the `config.yaml` file to provide a more specific prompt - condition for your custom dataset, for example: +### 7. Launch the Docs Agent chat app - ``` - condition_text: "You are a helpful chatbot answering questions from **Flutter app developers**. - Read the context below first and answer the user's question at the end. - In your answer, provide a summary in three or five sentences. (BUT DO NOT USE - ANY INFORMATION YOU KNOW ABOUT THE WORLD.)" - ``` +Docs Agent's Flask-based chat app lets users interact with the Docs Agent service through +a web browser. -### 2. Launch the Docs Agent chat app +**Note**: The `agent chatbot` command needs to run within the `poetry shell` environment. -To launch the Docs Agent chat app, do the following: +To start the Docs Agent chat app: -1. Go to the Docs Agent project directory, for example: +1. Go to the Docs Agent project home directory, for example: ``` - cd $HOME/generative-ai-docs/demos/palm/python/docs-agent + cd $HOME/docs-agent ``` 2. Launch the Docs Agent chat app: ``` - poetry run ./chatbot/launch.sh + agent chatbot ``` - **Note**: The Docs Agent chat app runs on port 5000 by default. If you have an application - already running on port 5000 on your host machine, you can use the `-p` flag to specify - a different port (for example, `poetry run ./chatbot/launch.sh -p 5050`). + The Docs Agent chat app runs on port 5000 by default. If you have an application + already running on port 5000 on your host machine, you can use the `--port` flag to + specify a different port (for example, `agent chatbot --port 5050`). - **Note**: If this `poetry run ./chatbot/launch.sh` command fails to run, check the `HOSTNAME` environment - variable on your host machine (for example, `echo $HOSTNAME`). If this variable is unset, try setting it to - `localhost` by running `export HOSTNAME=localhost`. + **Note**: If this `agent chatbot` command fails to run, check the `HOSTNAME` environment + variable on your host machine (for example, `echo $HOSTNAME`). If this variable is unset, + try setting it to `localhost` by running `export HOSTNAME=localhost` Once the app starts running, this command prints output similar to the following: ``` - $ poetry run ./chatbot/launch.sh - Reading the config file: /home/alice/docs-agent/config.yaml - Reading the config file: /home/alice/docs-agent/config.yaml - * Serving Flask app 'chatbot' + $ agent chatbot + Launching the chatbot UI. + * Serving Flask app 'docs_agent.interfaces.chatbot' * Debug mode: on INFO:werkzeug:WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Running on http://example.com:5000 INFO:werkzeug:Press CTRL+C to quit INFO:werkzeug: * Restarting with stat - Reading the config file: /home/alice/docs-agent/config.yaml - Reading the config file: /home/alice/docs-agent/config.yaml + Launching the chatbot UI. WARNING:werkzeug: * Debugger is active! - INFO:werkzeug: * Debugger PIN: 825-594-989 + INFO:werkzeug: * Debugger PIN: 391-260-142 ``` - Notice the line that shows the URL of this server (`http://example.com:5000` in - the example above). + Notice the line that shows the URL of this server (`http://example.com:5000` + in the example above). 3. Open the URL above on a browser. - Now, users can start asking questions related to the source dataset. + Now, users can start asking questions related to your product. **The Docs Agent chat app is all set!** ## Contribute to Docs Agent -To contribute to the Docs Agent project, do the following: +The section provides instructions on how to set up your account with the Docs Agent +repository so that you can start contributing to the Docs Agent project. + +To set up your account for the Docs Agent repository, do the following: -1. Visit https://cla.developers.google.com/ to see your current agreements - or to sign a new one. +1. To create an account on Gerrit Code Review, open the following page + on a browser: -2. Fork the [`generative-ai-docs`][gen-ai-docs-repo] repository. + ``` + https://doc-llm-internal-review.git.corp.google.com/ + ``` + +1. Click **Create account**. -3. Make changes in your forked reposiotry. +1. Clone the `docs-agent` repository on your host machine: -4. Create a pull request. + ``` + git clone sso://doc-llm-internal/docs-agent + ``` + +1. Go to the project directory: + + ``` + cd docs-agent + ``` + +1. To set up your commit hook, run the following command: + + ``` + curl -Lo `git rev-parse --git-dir`/hooks/commit-msg https://gerrit-review.googlesource.com/tools/hooks/commit-msg ; chmod +x `git rev-parse --git-dir`/hooks/commit-msg + ``` + +1. Create a new Gerrit change, for example: + + ``` + git add + ``` + + ``` + git commit [--amend] + ``` + +1. Upload the change for review: + + ``` + git push origin HEAD:refs/for/main + ``` ## Contributors @@ -731,28 +450,30 @@ Meggin Kearney (`@Meggin`), and Kyo Lee (`@kyolee415`). [contribute-to-docs-agent]: #contribute-to-docs-agent [set-up-docs-agent]: #set-up-docs-agent -[markdown-to-plain-text]: ./scripts/markdown_to_plain_text.py -[files-to-plain-text]: ./scripts/files_to_plain_text.py -[populate-vector-database]: ./scripts/populate_vector_database.py -[context-source-01]: http://eventhorizontelescope.org -[fact-check-section]: #using-a-language-model-to-fact-check-its-own-response -[related-questions-section]: #using-a-language-model-to-suggest-related-questions -[submit-a-rewrite]: #enabling-users-to-submit-a-rewrite-of-a-generated-response -[like-generate-responses]: #enabling-users-to-like-generated-responses +[preprocess-dir]: ./docs_agent/preprocess/ +[populate-vector-database]: ./docs_agent/preprocess/populate_vector_database.py +[fact-check-section]: ./docs/concepts.md#using-a-language-model-to-fact_check-its-own-response +[related-questions-section]: ./docs/concepts.md#using-a-language-model-to-suggest-related-questions +[submit-a-rewrite]: ./docs/concepts.md#enabling-users-to-submit-a-rewrite-of-a-generated-response +[like-generated-responses]: ./docs/concepts.md#enabling-users-to-like-generated-responses [populate-db-steps]: #populate-a-new-vector-database-from-markdown-files [start-the-app-steps]: #start-the-docs-agent-chat-app -[launch-script]: ./chatbot/launch.sh -[genai-doc-site]: https://ai.google.dev/docs +[genai-doc-site]: https://ai.google.dev/docs/gemini_api_overview [chroma-docs]: https://docs.trychroma.com/ [flutter-docs-src]: https://github.com/flutter/website/tree/main/src [flutter-docs-site]: https://docs.flutter.dev/ [poetry-known-issue]: https://github.com/python-poetry/poetry/issues/1917 [apps-script-readme]: ./apps_script/README.md -[scripts-readme]: ./scripts/README.md +[scripts-readme]: ./docs_agent/preprocess/README.md [config-yaml]: config.yaml -[gen-ai-docs-repo]: https://github.com/google/generative-ai-docs +[benchmark-test]: ./docs_agent/benchmarks/README.md [semantic-api]: https://ai.google.dev/docs/semantic_retriever [aqa-model]: https://ai.google.dev/models/gemini#model_variations -[oauth-quickstart]: https://ai.google.dev/docs/oauth_quickstart -[inline-passages]: https://ai.google.dev/docs/semantic_retriever#more_options_aqa_using_inline_passages [authorize-credentials]: https://ai.google.dev/docs/oauth_quickstart#authorize-credentials +[aqa-model-concept]: ./docs/concepts.md#using-the-semantic-retrieval-api-and-aqa-model +[prompt-structure]: ./docs/concepts.md#structure-of-a-prompt-to-a-language-model +[docs-agent-concepts]: ./docs/concepts.md +[google-cloud]: https://console.cloud.google.com/ +[oauth-client]: https://ai.google.dev/docs/oauth_quickstart#set-cloud +[cli-readme]: docs_agent/interfaces/README.md +[cli-reference]: docs/cli-reference.md diff --git a/demos/palm/python/docs-agent/apps_script/README.md b/demos/palm/python/docs-agent/apps_script/README.md index 995922597..e792ace01 100644 --- a/demos/palm/python/docs-agent/apps_script/README.md +++ b/demos/palm/python/docs-agent/apps_script/README.md @@ -6,11 +6,11 @@ compatible with Docs Agent. The steps are: -1. [Prepare a Google Drive folder](#1-prepare-a-google-driver-folder). -2. [Mount Google Drive on your host machine](#2-mount-google-drive-on-your-host-machine). -3. [Create an Apps Script project](#3-create-an-apps-script-project). -4. [Edit and run main.gs on Apps Script](#4-edit-and-run-maings-on-apps-script). -5. [Update config.yaml to include the mounted directory](#5-update-configyaml-to-include-the-mounted-directory). +1. [Prepare a Google Drive folder](#1_prepare-a-google-driver-folder). +2. [Mount Google Drive on your host machine](#2_mount-google-drive-on-your-host-machine). +3. [Create an Apps Script project](#3_create-an-apps-script-project). +4. [Edit and run main.gs on Apps Script](#4_edit-and-run-main_gs-on-apps-script). +5. [Update config.yaml to include the mounted directory](#5_update-config_yaml-to-include-the-mounted-directory). ## 1. Prepare a Google Drive folder @@ -134,7 +134,7 @@ Do the following: ``` input: - - path: "/home/user/DriveFileStream/My Drive/my source Google Docs-output" + - path: "/usr/local/home/user01/DriveFileStream/My Drive/my source Google Docs-output" url_prefix: "docs.google.com" ``` @@ -146,9 +146,9 @@ Do the following: ``` input: - - path: "/home/user/DriveFileStream/My Drive/my source Google Docs-output" + - path: "/usr/local/home/user01/DriveFileStream/My Drive/my source Google Docs-output" url_prefix: "docs.google.com" - - path: "/home/user/DriveFileStream/My Drive/psa-output" + - path: "/usr/local/home/user01/DriveFileStream/My Drive/psa-output" url_prefix: "mail.google.com" ``` diff --git a/demos/palm/python/docs-agent/aqa.py b/demos/palm/python/docs-agent/aqa.py deleted file mode 100644 index 3eb10c27a..000000000 --- a/demos/palm/python/docs-agent/aqa.py +++ /dev/null @@ -1,132 +0,0 @@ -# -# Copyright 2023 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -"""AQA module for using the Semantic Retrieval API""" - -import google.ai.generativelanguage as glm - - -class AQA: - def __init__(self): - # Initialize variables for the Semantic Retrieval API - self.generative_service_client = glm.GenerativeServiceClient() - self.retriever_service_client = glm.RetrieverServiceClient() - self.permission_service_client = glm.PermissionServiceClient() - - def list_existing_corpora(self): - corpora_list = glm.ListCorporaRequest() - response = self.retriever_service_client.list_corpora(corpora_list) - print("List of existing corpora:\n") - print(response) - - def delete_a_corpus(self, corpus_name): - try: - delete = glm.DeleteCorpusRequest(name=corpus_name) - delete = glm.DeleteCorpusRequest(name=corpus_name, force=True) - delete_corpus_response = self.retriever_service_client.delete_corpus(delete) - print("Successfully deleted corpus: " + corpus_name) - except: - print("Failed to delete the corpus: " + corpus_name) - - def create_a_new_corpus(self, corpus_display, corpus_name): - try: - # Get an existing corpus - get_corpus_request = glm.GetCorpusRequest(name=corpus_name) - get_corpus_response = self.retriever_service_client.get_corpus( - get_corpus_request - ) - print() - print(f"{corpus_name} exists.\n{get_corpus_response}") - except: - # Create a new corpus - corpus = glm.Corpus(display_name=corpus_display, name=corpus_name) - create_corpus_request = glm.CreateCorpusRequest(corpus=corpus) - create_corpus_response = self.retriever_service_client.create_corpus( - create_corpus_request - ) - print() - print(f"Created a new corpus {corpus_name}.\n{create_corpus_response}") - - def create_a_doc(self, corpus_name, page_title, page_url): - document_resource_name = "" - try: - # Create a new document with a custom display name. - example_document = glm.Document(display_name=page_title) - # Add metadata. - document_metadata = [glm.CustomMetadata(key="url", string_value=page_url)] - example_document.custom_metadata.extend(document_metadata) - # Make the request - create_document_request = glm.CreateDocumentRequest( - parent=corpus_name, document=example_document - ) - create_document_response = self.retriever_service_client.create_document( - create_document_request - ) - # Set the `document_resource_name` for subsequent sections. - document_resource_name = create_document_response.name - except: - get_document_request = glm.GetDocumentRequest(name=document_resource_name) - # Make the request - get_document_response = self.retriever_service_client.get_document( - get_document_request - ) - document_resource_name = get_document_response.name - return document_resource_name - - def create_a_chunk(self, doc_name, text, url): - response = "" - try: - # Create a chunk. - chunk = glm.Chunk(data={"string_value": text}) - # Add metadata. - chunk.custom_metadata.append( - glm.CustomMetadata(key="url", string_value=url) - ) - create_chunk_requests = [] - create_chunk_requests.append( - glm.CreateChunkRequest(parent=doc_name, chunk=chunk) - ) - # Make the request - request = glm.BatchCreateChunksRequest( - parent=doc_name, requests=create_chunk_requests - ) - response = self.retriever_service_client.batch_create_chunks(request) - # Print the response - print("Created a new text chunk:\n") - print(response) - except: - print("[ERROR] Failed to create a text chunk for:\n\n" + text) - # Failed possibly because the size of the text is too large. - # Quick fix: Split the text into 2 chunks - lines = text.splitlines() - text_01 = "" - text_02 = "" - text_size = len(lines) - half_size = int(text_size / 2) - i = 0 - for line in lines: - if i < half_size: - text_01 += line + "\n" - else: - text_02 += line + "\n" - i += 1 - self.create_a_chunk(doc_name, text_01, url) - self.create_a_chunk(doc_name, text_02, url) - return response - - def create_a_doc_chunk(self, corpus_name, page_title, page_url, text): - doc_name = self.create_a_doc(corpus_name, page_title, page_url) - return self.create_a_chunk(doc_name, text, page_url) diff --git a/demos/palm/python/docs-agent/chatbot/chatui.py b/demos/palm/python/docs-agent/chatbot/chatui.py deleted file mode 100644 index f18925d2c..000000000 --- a/demos/palm/python/docs-agent/chatbot/chatui.py +++ /dev/null @@ -1,314 +0,0 @@ -# -# Copyright 2023 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -"""Chatbot web service for Docs Agent""" - -from flask import ( - Blueprint, - render_template, - request, - redirect, - url_for, - json, -) -import markdown -import markdown.extensions.fenced_code -from bs4 import BeautifulSoup -import urllib -import os -from datetime import datetime -from pytz import timezone -import pytz -import uuid -from scripts import read_config - -from modules.chroma import Format -from docs_agent import DocsAgent - - -# Read the configuration file -config = read_config.ReadConfig() -# Create the 'rewrites' directory if it does not exist. -rewrites_dir = "rewrites" -is_exist = os.path.exists(rewrites_dir) -if not is_exist: - os.makedirs(rewrites_dir) - -product = config.returnConfigValue("product_name") -bp = Blueprint("chatui", __name__) -docs_agent = DocsAgent() - - -@bp.route("/", methods=["GET", "POST"]) -def index(): - server_url = request.url_root.replace("http", "https") - return render_template("chatui/index.html", product=product, server_url=server_url) - - -@bp.route("/like", methods=["GET", "POST"]) -def like(): - if request.method == "POST": - json_data = json.loads(request.data) - is_like = json_data.get("like") - uuid_found = json_data.get("uuid") - log_like(is_like, str(uuid_found).strip()) - return "OK" - else: - return redirect(url_for("chatui.index")) - - -@bp.route("/rewrite", methods=["GET", "POST"]) -def rewrite(): - if request.method == "POST": - json_data = json.loads(request.data) - user_id = json_data.get("user_id") - question_captured = json_data.get("question") - original_response = json_data.get("original_response") - rewrite_captured = json_data.get("rewrite") - date_format = "%m%d%Y-%H%M%S" - date = datetime.now(tz=pytz.utc) - date = date.astimezone(timezone("US/Pacific")) - print("[" + date.strftime(date_format) + "] A user has submitted a rewrite.") - print("Submitted by: " + user_id + "\n") - print("# " + question_captured.strip() + "\n") - print("## Original response\n") - print(original_response.strip() + "\n") - print("## Rewrite\n") - print(rewrite_captured + "\n") - filename = ( - rewrites_dir - + "/" - + question_captured.strip() - .replace(" ", "-") - .replace("?", "") - .replace("'", "") - .lower() - + "-" - + date.strftime(date_format) - + ".md" - ) - with open(filename, "w", encoding="utf-8") as file: - file.write("Submitted by: " + user_id + "\n\n") - file.write("# " + question_captured.strip() + "\n\n") - file.write("## Original response\n\n") - file.write(original_response.strip() + "\n\n") - file.write("## Rewrite\n\n") - file.write(rewrite_captured + "\n") - file.close() - return "OK" - else: - return redirect(url_for("chatui.index")) - - -# Render a response page when the user asks a question -# using input text box. -@bp.route("/result", methods=["GET", "POST"]) -def result(): - if request.method == "POST": - question = request.form["question"] - return ask_model(question) - else: - return redirect(url_for("chatui.index")) - - -# Render a response page when the user clicks a question -# from the related questions list. -@bp.route("/question/", methods=["GET", "POST"]) -def question(ask): - if request.method == "GET": - question = urllib.parse.unquote_plus(ask) - return ask_model(question) - else: - return redirect(url_for("chatui.index")) - - -# Construct a set of prompts using the user question, send the prompts to -# the lanaguage model, receive responses, and present them into a page. -def ask_model(question): - ### PROMPT 1: AUGMENT THE USER QUESTION WITH CONTEXT. - # 1. Use the question to retrieve a list of related contents from the database. - # 2. Convert the list of related contents into plain Markdown text (context). - # 3. Add the custom condition text to the context. - # 4. Send the prompt (condition + context + question) to the language model. - query_result = docs_agent.query_vector_store(question) - context = query_result.fetch_formatted(Format.CONTEXT) - context_with_instruction = docs_agent.add_instruction_to_context(context) - if docs_agent.check_if_aqa_is_used(): - response = docs_agent.ask_aqa_model(question) - elif "gemini" in docs_agent.get_language_model_name(): - response = docs_agent.ask_content_model_with_context( - context_with_instruction, question - ) - else: - response = docs_agent.ask_text_model_with_context( - context_with_instruction, question - ) - - ### PROMPT 2: FACT-CHECK THE PREVIOUS RESPONSE. - if "gemini" in docs_agent.get_language_model_name(): - fact_checked_response = docs_agent.ask_content_model_to_fact_check( - context_with_instruction, response - ) - else: - fact_checked_response = docs_agent.ask_text_model_to_fact_check( - context_with_instruction, response - ) - - ### PROMPT 3: GET 5 RELATED QUESTIONS. - # 1. Use the response from Prompt 1 as context and add a custom condition. - # 2. Prepare a new question asking the model to come up with 5 related questions. - # 3. Ask the language model with the new question. - # 4. Parse the model's response into a list in HTML format. - new_condition = "Read the context below and answer the user's question at the end." - new_context_with_instruction = docs_agent.add_custom_instruction_to_context( - new_condition, response - ) - new_question = ( - "What are 5 questions developers might ask after reading the context?" - ) - new_response = markdown.markdown( - docs_agent.ask_text_model_with_context( - new_context_with_instruction, new_question - ) - ) - related_questions = parse_related_questions_response_to_html_list(new_response) - - ### RETRIEVE SOURCE URLS. - # - Construct clickable URLs using the returned related contents above. - # - Extract the URL of the top related content for the fact-check message. - clickable_urls = markdown.markdown( - query_result.fetch_formatted(Format.CLICKABLE_URL) - ) - fact_check_url = "" - if docs_agent.check_if_aqa_is_used() and docs_agent.get_db_type() == "ONLINE_STORAGE": - aqa_response_url = docs_agent.get_aqa_response_url() - fact_check_url = ( - '' + aqa_response_url + "" - ) - else: - fact_check_url = markdown.markdown( - query_result.fetch_nearest_formatted(Format.CLICKABLE_URL) - ) - - ### PREPARE OTHER ELEMENTS NEEDED BY UI. - # - Create a uuid for this request. - # - (Optional) Prepare the AQA model's JSON response into HTML for rendering. - # - Convert the context returned from the database into HTML for rendering. - # - Convert the first response from the model into HTML for rendering. - # - Convert the fact-check response from the model into HTML for rendering. - # - A workaround to get the server's URL to work with the rewrite and like features. - new_uuid = uuid.uuid1() - aqa_response_in_html = "" - if docs_agent.check_if_aqa_is_used(): - aqa_response_json = docs_agent.get_saved_aqa_response_json() - if aqa_response_json: - aqa_response_in_html = "Grounding attributions:

" - aqa_response_in_html += str(aqa_response_json.answer.grounding_attributions) - aqa_response_in_html += "

Answerable probability: " - aqa_response_in_html += str(aqa_response_json.answerable_probability) - context_in_html = markdown.markdown(context, extensions=["fenced_code"]) - response_in_html = markdown.markdown(response, extensions=["fenced_code"]) - fact_checked_response_in_html = markdown.markdown(fact_checked_response) - server_url = request.url_root.replace("http", "https") - - ### LOG THIS REQUEST. - log_question(new_uuid, question, response) - - return render_template( - "chatui/index.html", - question=question, - context_in_html=context_in_html, - response=response, - response_in_html=response_in_html, - clickable_urls=clickable_urls, - fact_checked_response_in_html=fact_checked_response_in_html, - fact_check_url=fact_check_url, - related_questions=related_questions, - product=product, - server_url=server_url, - uuid=new_uuid, - aqa_response_in_html=aqa_response_in_html, - ) - - -# Parse a response containing a list of related questions from the language model -# and convert it into an HTML-based list. -def parse_related_questions_response_to_html_list(response): - soup = BeautifulSoup(response, "html.parser") - for item in soup.find_all("li"): - # In case there are code tags, remove the tag and just replace with - # plain text - if item.find("code"): - text = item.find("code").text - item.code.replace_with(text) - # In case there are

tags within the

  • strip

    - if item.find("p"): - text = item.find("p").text - link = soup.new_tag( - "a", - href=url_for("chatui.question", ask=urllib.parse.quote_plus(text)), - ) - link.string = text - item.string = "" - item.append(link) - if item.string is not None: - link = soup.new_tag( - "a", - href=url_for( - "chatui.question", ask=urllib.parse.quote_plus(item.string) - ), - ) - link.string = item.string - item.string = "" - item.append(link) - return soup - - -# Log the question and response to the server's log file. -def log_question(uid, user_question, response): - date_format = "%m/%d/%Y %H:%M:%S %Z" - date = datetime.now(tz=pytz.utc) - date = date.astimezone(timezone("US/Pacific")) - print("UID: " + str(uid)) - print("Question: " + user_question.strip() + "\n") - print("Response:") - print(response.strip() + "\n") - if docs_agent.check_if_aqa_is_used(): - aqa_response = docs_agent.get_saved_aqa_response_json() - try: - probability = aqa_response.answerable_probability - except: - probability = 0.0 - print("Answerable probability: " + str(probability) + "\n") - with open("chatui_logs.txt", "a", encoding="utf-8") as log_file: - log_file.write("[" + date.strftime(date_format) + "][UID " + str(uid) + "]\n") - log_file.write("# " + user_question.strip() + "\n\n") - log_file.write(response.strip() + "\n\n") - if docs_agent.check_if_aqa_is_used(): - log_file.write("Answerable probability: " + str(probability) + "\n\n") - log_file.close() - - -def log_like(is_like, uid): - date_format = "%m/%d/%Y %H:%M:%S %Z" - date = datetime.now(tz=pytz.utc) - date = date.astimezone(timezone("US/Pacific")) - print("UID: " + str(uid)) - print("Like: " + str(is_like)) - with open("chatui_logs.txt", "a", encoding="utf-8") as log_file: - log_file.write("[" + date.strftime(date_format) + "][UID " + str(uid) + "]\n") - log_file.write("Like: " + str(is_like) + "\n\n") - log_file.close() diff --git a/demos/palm/python/docs-agent/chatbot/launch.sh b/demos/palm/python/docs-agent/chatbot/launch.sh deleted file mode 100755 index ae94cd222..000000000 --- a/demos/palm/python/docs-agent/chatbot/launch.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/bash - -# -# Copyright 2023 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Default values -port=5000 -name='chatbot' -# Specify port number with -p argument `launch.sh -p 5555` -while getopts "n:p:h" opt; do - case $opt in - p) port="${OPTARG}";; - h) echo "Usage: $0 [-p port]"; exit 1;; - \?) echo "Invalid option: -$OPTARG"; exit 1;; - esac -done -# Define your hostname -if [[ -z "$HOSTNAME" ]]; then - export HOSTNAME="localhost" -fi -export FLASK_PORT=$port -export FLASK_APP=$name -export FLASK_DEBUG=true - -flask run --host=$HOSTNAME --port=$FLASK_PORT diff --git a/demos/palm/python/docs-agent/chatbot/static/css/chatbox.css b/demos/palm/python/docs-agent/chatbot/static/css/chatbox.css deleted file mode 120000 index 3d344232e..000000000 --- a/demos/palm/python/docs-agent/chatbot/static/css/chatbox.css +++ /dev/null @@ -1 +0,0 @@ -../../../third_party/css/chatbox.css \ No newline at end of file diff --git a/demos/palm/python/docs-agent/chatbot/static/css/style.css b/demos/palm/python/docs-agent/chatbot/static/css/style.css deleted file mode 100644 index cf814ea75..000000000 --- a/demos/palm/python/docs-agent/chatbot/static/css/style.css +++ /dev/null @@ -1,339 +0,0 @@ -/** - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* ======= General style for HTML elements ======= */ - -body { - font: 16px/1.5em Overpass, "Open Sans", Helvetica, sans-serif; - color: #333; - font-weight: 300; - max-width: 960px; - margin: auto; - background-color: #d9d9d9; - padding-top: 15px; - padding-bottom: 15px; -} - -a { - color: #22578c; -} - -p { - margin: 0 0 1em; - line-height: 130%; -} - -h1 { - margin: 0 0 0.5em; - font-weight: 500; - font-size: 2.0em; - margin-left: 0.8em; - margin-top: 0.3em; -} - -h2 { - margin: 0; - margin-top: 17px; - margin-bottom: 15px; -} - -h3 { - margin: 0; - margin-top: 10px; - margin-bottom: 10px; -} - -h4 { - color: #505050; - margin: 0; - margin-top: 3px; - margin-bottom: 10px; -} - -li { - margin: 0 0 0.3em; -} - -code { - font-family: math; - color: darkgreen; -} - -/* ======= Style layout by ID ======= */ - -#callout-box { - margin: auto; - max-width: 800px; - font: 13px arial, sans-serif; - background-color: white; - border-style: solid; - border-width: 1px; - padding: 10px 25px; - box-shadow: 5px 5px 5px grey; - border-radius: 15px; -} - -/* ======= Style by class ======= */ - -.hidden { - display: none; -} - -.disable { - display: none; -} - -.header-wrapper { - display: flex; -} - -.loading { - font: 15px arial, sans-serif; - width: 100%; - margin-left: 12px; - color: #505050; - padding: 2px; -} - -.notselected { - background-color: #303936e6; - padding-top: 3px; - padding-bottom: 5px; -} - -.notselected:hover { - background-color: #121a17e6; - cursor:pointer; -} - -.selected { - background-color: #1e6a9c; - padding-top: 7px; - padding-bottom: 7px; -} - -.selected:hover { - background-color: #0a619a; - cursor:pointer; -} - -.rewrite { - padding: 15px; - border: 2px solid #000; - margin-top: 6px; - border-radius: 15px; -} - -.question, .response, .response-text, .fact-checked-text, .related-questions { - max-width: 700px; - margin-left: 3px; -} - -.full-response { - max-width: 700px; - margin-left: 10px; -} - -/* ======= Style buttons by ID ======= */ - -#rewrite-button { - border: 0; - background-color: #cf633ff2; - color: #fff; - padding: 7px; - border-radius: 5px; - cursor:pointer; -} - -#rewrite-button:hover { - background: #ce3705f2; - cursor:pointer; -} - -#like-button { - border: 0; - color: #fff; - padding-left: 7px; - padding-right: 7px; - border-radius: 5px; - cursor:pointer; -} - -#submit-button { - border: 0; - background: none; - background-color: #CF5C3F; - color: #fff; - padding: 7px; - border-radius: 5px; - cursor:pointer; -} - -#submit-button:hover { - background: #ce3705f2; - cursor:pointer; -} - -#submit-result { - color: #027f02d6; -} - -#edit-text-area { - font: 13px/1.5em Overpass, "Open Sans", Helvetica, sans-serif; - max-height: 500px; - max-width: 650px; - height: 300px; - width: 650px; - padding: 8px; -} - -#rewrite-question-header { - margin: 0; - margin-bottom: 5px; -} - -#rewrite-response-header { - margin: 0; - margin-top: 10px; - margin-bottom: 5px; -} - -#user-id { - margin: 0; - margin-top: 10px; - margin-bottom: 15px; -} - -#fact-check-url { - margin: 0 0 0.7em; -} - -/* ======= Search Box ======= */ - -.search { - border: 2px solid #CF5C3F; - overflow: auto; - max-width: 700px; - margin-top: 15px; - margin-left: 10px; - margin-bottom: 10px; - border-radius: 5px; -} - -.search input[type="text"] { - border: 0; - width: 91%; - padding: 10px; -} - -.search input[type="text"]:focus { - outline: 0; -} - -.search input[type="submit"] { - border: 0; - background: none; - background-color: #CF5C3F; - color: #fff; - float: right; - padding: 10px; - -moz-border-radius-top-right: 5px; - -webkit-border-radius-top-right: 5px; - -moz-border-radius-bottom-right: 5px; - -webkit-border-radius-bottom-right: 5px; - cursor:pointer; -} - -/* ======= Accordion ======= */ - -.accordion { - max-width: 65em; - margin-bottom: 1em; -} - -.accordion > input[type="checkbox"] { - position: absolute; - left: -100vw; -} - -.accordion .content { - overflow-y: hidden; - height: 0; - transition: height 0.3s ease; -} - -.accordion .reference-content { - font-size: 13px; -} - -.accordion > input[type="checkbox"]:checked ~ .content { - height: auto; - overflow: visible; - padding: 15px; - border: 2px solid #000; - margin-top: 6px; - border-radius: 15px; -} - -.accordion .handle { - margin: 0; - font-size: 1.125em; - line-height: 1.2em; -} - -.accordion label { - display: block; - font-weight: normal; - border: 2px solid #000; - padding: 12px; - background: #4490b8ab; - border-radius: 15px; -} - -.accordion label:hover, -.accordion label:focus { - background: #d9d9d9; - cursor:pointer; -} - -.accordion .handle label::before { - font-family: fontawesome, sans-serif; - display: inline-block; - content: "\2964"; - margin-right: 10px; - font-size: .58em; - line-height: 1.556em; - vertical-align: middle; -} - -.accordion > input[type="checkbox"]:checked ~ .handle label::before { - content: "\2965"; -} - -.accordion p:last-child { - margin-bottom: 0; -} - -.accordion #aqa-label { - padding: 2px; - background: #add1e8; - border-radius: 0px; -} - -.accordion .content #aqa-content{ - background: #d4d4d4; -} - diff --git a/demos/palm/python/docs-agent/chatbot/templates/chatui/result.html b/demos/palm/python/docs-agent/chatbot/templates/chatui/result.html deleted file mode 100644 index 64403f921..000000000 --- a/demos/palm/python/docs-agent/chatbot/templates/chatui/result.html +++ /dev/null @@ -1,70 +0,0 @@ -

    -

    Question

    -

    {{ question | replace("+", " ") | replace("%3F", "?")}}

    -
    -
    -

    Generated answer

    - - {{ response_in_html | safe }} - -

    Important:

    - {{ fact_checked_response_in_html | safe }} -

    To verify this information, please check out:

    - {{ fact_check_url | safe }} -
    - -
    - -

    - -

    -
    - {{ context_in_html | safe }} - -

    Reference:

    - {{ clickable_urls | safe }} -
    -
    - -
    -
    -
    - - -
    - - diff --git a/demos/palm/python/docs-agent/config.yaml b/demos/palm/python/docs-agent/config.yaml index 655c3bb94..b1f74bc5f 100644 --- a/demos/palm/python/docs-agent/config.yaml +++ b/demos/palm/python/docs-agent/config.yaml @@ -14,97 +14,37 @@ # limitations under the License. # -### Configuration for Docs Agent ### - -### PaLM environment -# -# api_endpoint: The PaLM API endpoint used by Docs Agent. -# -# embedding_model: The PaLM embedding model used to generate embeddings. -# -api_endpoint: "generativelanguage.googleapis.com" -language_model: "models/gemini-pro" -embedding_model: "models/embedding-001" - - -### Docs Agent environment -# -# product_name: The name of your product to appears on the chatbot UI. -# -# output_path: The directory where plain text files will be stored -# after documentation source files are processed by -# the `markdown-to-plain-text.py` script. -# Use a relative path to Doc Agent' home directory. -# -# vector_db_dir: The directory where dataset collections for the Chroma -# vector database are stored. -# -# collection_name: The name used to identify a dataset collection by -# the Chroma vector database. -# -# log_level: The verbosity level of logs printed on the terminal -# by the chatbot app: NORMAL, VERBOSE, or DEBUG -# -# db_type: Use a local vector database or an online storage -# using the Semantic Retrieval API: -# LOCAL_DB or ONLINE_STORAGE -# -# is_aqa_used: Use Gemini's AQA model for question-answering: -# NO or YES -# -product_name: "My product" -output_path: "data/plain_docs" -vector_db_dir: "vector_stores/chroma" -collection_name: "docs_collection" -log_level: "NORMAL" -db_type: "LOCAL_DB" -is_aqa_used: "NO" - - -### Documentation sources -# -# List your documentation sources under the `input` field: -# -# path (Required): The directory where the source Markdown files -# are stored. -# -# url_prefix (Required): The prefix used to create URLs for the source -# files. Even if URLs don't exist for the source, -# you still need to provide a mock string. -# -# exclude_path (Optional): The sub-directory to be excluded from the `path` -# directory when processing source files. -# -input: - - path: "data/example/markdown-src-01" - url_prefix: "https://example.com/markdown-src-01" - - path: "data/example/markdown-src-02" - url_prefix: "https://example.com/makrdown-src-02" - exclude_path: "/reference/changelogs/" - - -### Docs Agent prompts -# -# condition_text: The condition added at the top of each prompt to -# language models. -# -# fact_check_question: The additional condition used in promopts when asking -# language models to "fact check" their own responses. -# -# model_error_message: The error message returned to the user when language -# models are unable to provide responses. -# -condition_text: "You are a helpful chatbot answering questions from users. -Read the context below first and answer the user's question at the end. -In your answer, provide a summary in three or five sentences. (BUT DO NOT USE -ANY INFORMATION YOU KNOW ABOUT THE WORLD.)" - -fact_check_question: "Can you compare the text below to the information -provided in this prompt above and write a short message that warns the readers -about which part of the text they should consider fact-checking? (Please keep -your response concise, focus on only one important item, but DO NOT USE BOLD -TEXT IN YOUR RESPONSE.)" - -model_error_message: "Gemini is not able to answer this question at the moment. -Rephrase the question and try asking again." - +configs: + - product_name: "Flutter" + models: + - language_model: "models/aqa" + embedding_model: "models/embedding-001" + api_endpoint: "generativelanguage.googleapis.com" + embedding_api_call_limit: 1400 + embedding_api_call_period: 60 + docs_agent_config: "normal" + markdown_splitter: "token_splitter" + log_level: "NORMAL" + db_type: "google_semantic_retriever" + db_configs: + - db_type: "chroma" + vector_db_dir: "vector_stores/chroma" + collection_name: "docs_collection" + - db_type: "google_semantic_retriever" + corpus_name: "corpora/flutter-dev" + output_path: "data/plain_docs" + inputs: + - path: "/usr/local/home/user01/website/src" + url_prefix: "https://docs.flutter.dev/" + conditions: + - condition_text: "You are a helpful chatbot answering questions from users. + Read the context below first and answer the user's question at the end. + In your answer, provide a summary in three or five sentences. (BUT DO NOT USE + ANY INFORMATION YOU KNOW ABOUT THE WORLD.)" + fact_check_question: "Can you compare the text below to the information + provided in this prompt above and write a short message that warns the readers + about which part of the text they should consider fact-checking? (Please keep + your response concise, focus on only one important item, but DO NOT USE BOLD + TEXT IN YOUR RESPONSE.)" + model_error_message: "Gemini is not able to answer this question at the moment. + Rephrase the question and try asking again." diff --git a/demos/palm/python/docs-agent/docs/cli-reference.md b/demos/palm/python/docs-agent/docs/cli-reference.md new file mode 100644 index 000000000..8e32da7a0 --- /dev/null +++ b/demos/palm/python/docs-agent/docs/cli-reference.md @@ -0,0 +1,166 @@ +# Docs Agent CLI reference + +This page provides a list of the Docs Agent command lines and their usages +and examples. + +**Important**: All `agent` commands in this page need to run in the +`poetry shell` environment. + +## Processing of Markdown files + +### Chunk Markdown files into small text chunks + +The command below splits Markdown files (and other source files) into small +chunks of plain text files: + +```sh +agent chunk +``` + +### Populate a vector database using text chunks + +The command below populates a vector database using plain text files (created +by running the `agent chunk` command): + +```sh +agent populate +``` + +### Show the Docs Agent configuration + +The command below prints all the fields and values in the current +[`config.yaml`][config-yaml] file: + +```sh +agent show-config +``` + +## Docs Agent chatbot web app + +### Launch the Docs Agent web app + +The command below launches Docs Agent's Flask-based chatbot web application: + +```sh +agent chatbot +``` + +### Launch the Docs Agent web app using a different port + +The command below launches the Docs Agent web app to run on port 5005: + +```sh +agent chatbot --port 5005 +``` + +## Docs Agent benchmark test + +### Run the Docs Agent benchmark test + +The command below runs benchmark test using the questions and answers listed +in the [`benchmarks.yaml`][benchmarks-yaml] file: + +```sh +agent benchmark +``` + +## Interacting with language models + +### Ask a question + +The command below reads a question from the arguments, asks the Gemini model, +and prints its response: + +```sh +agent tellme +``` + +Replace `QUESTION` with a question written in plain English, for example: + +```sh +agent tellme does flutter support material design 3? +``` + +**Note**: This `agent tellme` command is used to set up the `gemini` command +in the [Set up Docs Agent CLI][set-up-docs-agent-cli] guide. + +### Ask a question to a specific product + +The command below enables you to ask a question to a specific product in your +Docs Agent setup: + +```sh +agent tellme --product +``` + +The example below asks the question to the `Flutter` product in your +Docs Agent setup: + +```sh +agent tellme which modules are available? --product=Flutter +``` + +You may also specify multiple products, for example: + +```sh +agent tellme which modules are available? --product=Flutter --product=Angular --product=Android +``` + +## Online corpus management + +### List all existing online corpora + +The command below prints the list of all existing online corpora created +using the [Semantic Retrieval API][semantic-api]: + +```sh +agent list-corpora +``` + +### Share an online corpora with a user + +The command below enables `user01@gmail.com` to read text chunks stored in +`corpora/example01`: + +```sh +agent share-corpus --name corpora/example01 --user user01@gmail.com --role READER +``` + +The command below enables `user01@gmail.com` to read and write to +`corpora/example01`: + +```sh +agent share-corpus --name corpora/example01 --user user01@gmail.com --role WRITER +``` + +### Share an online corpora with everyone + +The command below enables `EVERYONE` to read text chunks stored in +`corpora/example01`: + +```sh +agent open-corpus --name corpora/example01 +``` + +### Remove a user permission from an online corpora + +The command below remove an existing user permission set in `corpora/example01`: + +```sh +agent remove-corpus-permission --name corpora/example01/permissions/123456789123456789 +``` + +### Delete an online corpora + +The command below deletes an online corpus: + +```sh +agent delete-corpus --name corpora/example01 +``` + + + +[config-yaml]: ../config.yaml +[benchmarks-yaml]: ../docs_agent/benchmarks/benchmarks.yaml +[set-up-docs-agent-cli]: ../docs_agent/interfaces/README.md +[semantic-api]: https://ai.google.dev/docs/semantic_retriever diff --git a/demos/palm/python/docs-agent/docs/concepts.md b/demos/palm/python/docs-agent/docs/concepts.md new file mode 100644 index 000000000..c8cfb53ac --- /dev/null +++ b/demos/palm/python/docs-agent/docs/concepts.md @@ -0,0 +1,376 @@ +# Docs Agent concepts + +**Note**: If you want to set up and launch the Docs Agent chat app on your host machine, +see the [Set up Docs Agent][set-up-docs-agent] section in README. + +This page describes the architecture and features of Docs Agent. + +## Overview + +The Docs Agent chat app is designed to be easily set up and configured in a Linux environment. +and require that you have access to Google’s [Gemini API][genai-doc-site]. + +Docs Agent uses a technique known as Retrieval Augmented Generation (RAG), which allows +you to bring your own documents as knowledge sources to AI language models. This approach +helps the AI language models to generate relevant and accurate responses that are grounded +in the information that you provide and control. + +![Docs Agent architecture](./images/docs-agent-architecture-01.png) + +**Figure 1**. Docs Agent uses a vector database to retrieve context for augmenting prompts. + +## Main features + +The key features of the Docs Agent chat app are: + +- Add contextual information to user questions to augment prompts for AI language models. +- Process documents into embeddings and store them in a vector database for semnatic retrieval. + +![Docs Agent flow](./images/docs-agent-architecture-02.png) + +**Figure 2**. A user question is augmented by the Docs Agent server and passed to an LLM. + +For the moment, the Docs Agent project focuses on providing Python scripts that make it +easy to process Markdown files into embeddings. However, there is no hard requirement that the +source documents must exist in Markdown format. What’s important is that the processed content +is available as embeddings in the vector database. + +### Structure of a prompt to a language model + +To enable an LLM to answer questions that are not part of the public knowledge (which the LLM +is likely trained on), the Docs Agent project applies a mixture of prompt engineering and +embeddings techniques. That is, we process a set of documents (which contain domain specific +knowledge) into embeddings and store them in a vector database. This vector database allows +the Docs Agent server to perform semantic search on stored embeddings to find the most relevant +content from the source documents given user questions. + +Once the most relevant content is returned, the Docs Agent server uses the prompt structure +shown in Figure 3 to augment the user question with a preset **condition** and a list of +**context**. (When the Docs Agent server starts, the condition value is read from the +[`config.yaml`][config-yaml] file.) Then the Docs Agent server sends this prompt to a +language model using the Gemini API and receives a response generated by the model. + +![Docs Agent prompt strcture](./images/docs-agent-prompt-structure-01.png) + +**Figure 3**. Prompt structure for augmenting a user question with related context +(Context source: [eventhorizontelescope.org][context-source-01]) + +### Processing of Markdown files into embeddings + +To process information into embeddings using the Python scripts in the project, the +information needs to be stored in Markdown format. Once you have a set of Markdown files +stored in a directory on your host machine, you can run the +[`files_to_plain_text.py`][files-to-plain-text] script to process those Markdown +files into small plain text files – the script splits the content by the top three Markdown +headers (`#`, `##`, and `###`). + +Once Markdown files are processed into small plain text files, you can run the +[`populate_vector_database.py`][populate-vector-database] script to generate embeddings +for each text file and store those embeddings into a [Chroma][chroma-docs] vector database +running on the host machine. + +The embeddings in this vector database enable the Docs Agent server to perform semantic search +and retrieve context related to user questions for augmenting prompts. + +For more information on the processing of Markdown files, see the [`README`][scripts-readme] +file in the `scripts` directory. + +![Document to embeddings](./images/docs-agent-embeddings-01.png) + +**Figure 4**. A document is split into small semantic chunks, which are then used to generate +embeddings. + +![Markdown to embeddings](./images/docs-agent-embeddings-02.png) + +**Figure 5**. A Markdown page is split by headers and processed into embeddings. + +## Summary of tasks and features + +The following list summarizes the tasks and features of the Docs Agent chat app: + +- **Process Markdown**: Split Markdown files into small plain text files. (See the + Python scripts in the [`preprocess`][preprocess-dir] directory.) +- **Generate embeddings**: Use an embedding model to process small plain text files + into embeddings, and store them in a vector database. (See the + [`populate_vector_database.py`][populate-vector-database] script.) +- **Perform semantic search**: Compare embeddings in the vector database to retrieve + most relevant content given user questions. +- **Add context to a user question**: Add a list of text chunks returned from + a semantic search as context in a prompt. +- **(Experimental) “Fact-check” responses**: This experimental feature composes + a follow-up prompt and asks the language model to “fact-check” its own previous response. + (See the [Using a language model to fact-check its own response][fact-check-section] + section.) +- **Generate related questions**: In addition to displaying a response to the user + question, the web UI displays 5 questions generated by the language model based on + the context of the user question. (See the + [Using a language model to suggest related questions][related-questions-section] + section.) +- **Return URLs of documentation sources**: Docs Agent's vector database stores URLs + as metadata next to embeddings. Whenever the vector database is used to retrieve + text chunks for context, the database can also return the URLs of the sources used + to generate the embeddings. +- **Collect feedback from users**: Docs Agent's chatbot web UI includes buttons that + allow users to [like generated responses][like-generated-responses] or + [submit rewrites][submit-a-rewrite]. +- **Convert Google Docs, PDF, and Gmail into Markdown files**: This feature uses + Apps Script to convert Google Docs, PDF, and Gmail into Markdown files, which then + can be used as input datasets for Docs Agent. (See the + [`apps_script`][apps-script-readme] directory.) +- **Run benchmark test to monitor the quality of AI-generated responses**: Using + Docs Agent, you can run [benchmark test][benchmark-test] to measure and compare + the quality of text chunks, embeddings, and AI-generated responses. +- **Use the Semantic Retrieval API and AQA model**: You can use Gemini's + [Semantic Retrieval API][semantic-api] to upload source documents to an online + corpus and use the [AQA model][aqa-model] that is specifically created for answering + questions using an online corpus. + +## Flow of events + +The following events take place in the Docs Agent chat app: + +1. The [`files_to_plain_text.py`][files-to-plain-text] script converts input + Markdown documents into small plain text files, split by Markdown headings + (`#`, `##`, and `###`). +2. The [`populate_vector_database.py`][populate-vector-database] script generates + embeddings from the small plain text files and populates a vector database. +3. When the [`agent chatbot`] command is run, it starts the Docs Agent server and + vector database, which loads generated embeddings and metadata (URLs and filenames) + stored in the `vector_store` directory. +4. When the user asks a question, the Docs Agent server uses the vector database to + perform semantic search on embeddings, which represent content in the source + documents. +5. Using this semantic search capability, the Docs Agent server finds a list of + text chunks that are most relevant to the user question. +6. The Docs Agent server adds this list of text chunks as context (plus a condition + for responses) to the user question and constructs them into a prompt. +7. The system sends the prompt to a language model via the Gemini API. +8. The language model generates a response and the Docs Agent server renders it on + the chat UI. + +Additional events for [“fact-checking” a generated response][fact-check-section]: + +9. The Docs Agent server prepares another prompt that compares the generated response + (in step 8) to the context (in step 6) and asks the language model to look for + a discrepancy in the response. +10. The language model generates a response that points out one major discrepancy + (if it exists) between its previous response and the context. +11. The Docs Agent server renders this response on the chat UI as a call-out note. +12. The Docs Agent server passes this second response to the vector database to + perform semantic search. +13. The vector database returns a list of relevant content (that is closely related + to the second response). +14. The Docs Agent server renders the top URL of this list on the chat UI and + suggests that the user checks out this URL for fact-checking. + +Additional events for +[suggesting 5 questions related to the user question][related-questions-section]: + +15. The Docs Agent server prepares another prompt that asks the language model to + generate 5 questions based on the context (in step 6). +16. The language model generates a response that contains a list of questions related + to the context. +17. The Docs Agent server renders the questions on the chat UI. + +## Supplementary features + +This section describes additional features implemented on the Docs Agent chat app for +enhancing the usability of the Q&A experience powered by generative AI. + +![Docs Agent UI](./images/docs-agent-ui-screenshot-01.png) + +**Figure 6**. A screenshot of the Docs Agent chat UI showing the sections generated by +three distinct prompts. + +### Using a language model to fact-check its own response + +In addition to using the prompt structure above (shown in Figure 3), we‘re currently +experimenting with the following prompt setup for “fact-checking” responses generated +by the language model: + +- Condition: + + ``` + You are a helpful chatbot answering questions from users. Read the following context + first and answer the question at the end: + ``` + +- Context: + + ``` + + ``` + +- Additional condition (for fact-checking): + + ``` + Can you compare the text below to the information provided in this prompt above + and write a short message that warns the readers about which part of the text they + should consider fact-checking? (Please keep your response concise and focus on only + one important item.)" + ``` + +- Previously generated response + + ``` + Text: + ``` + +This "fact-checking" prompt returns a response similar to the following example: + +``` +The text states that Flutter chose to use Dart because it is a fast, productive, object-oriented +language that is well-suited for building user interfaces. However, the context provided in the +prompt states that Flutter chose Dart because it is a fast, productive language that is well-suited +for Flutter's problem domain: creating visual user experiences. Therefore, readers should consider +fact-checking the claim that Dart is well-suited for building user interfaces. +``` + +After the second response, notice that the Docs Agent chat UI also suggests a URL to visit for +fact-checking (see Figure 6), which looks similar to the following example: + +``` +To verify this information, please check out: + +https://docs.flutter.dev/resources/faq +``` + +To identify this URL, the Docs Agent server takes the second response (which is the paragraph that +begins with “The text states that ...” in the example above) and uses it to query the vector +database. Once the vector database returns a list of the most relevant content to this response, +the UI only displays the top URL to the user. + +Keep in mind that this "fact-checking" prompt setup is currently considered **experimental** +because we‘ve seen cases where a language model would end up adding incorrect information into its +second response as well. However, we saw that adding this second response (which brings attention +to the language model’s possible hallucinations) seems to improve the usability of the system since it +serves as a reminder to the users that the language model‘s response is far from being perfect, which +helps encourage the users to take more steps to validate generated responses for themselves. + +### Using a language model to suggest related questions + +The project‘s latest web UI includes the “Related questions” section, which displays five +questions that are related to the user question (see Figure 6). These five questions are also +generated by a language model (via the Gemini API). Using the list of contents returned from the vector +database as context, the system prepares another prompt asking the language model to generate five +questions from the included context. + +The following is the exact structure of this prompt: + +- Condition: + + ``` + Read the context below and answer the question at the end: + ``` + +- Context: + + ``` + + ``` + +- Question: + + ``` + What are 5 questions developers might ask after reading the context? + ``` + +### Enabling users to submit a rewrite of a generated response + +The project‘s latest web UI includes the **Rewrite this response** button at the bottom of +the panel (see Figure 6). When this button is clicked, a widget opens up, expanding the +main UI panel, and reveals a textarea containing the generated response to the user's question. +The user is then allowed to edit this response in the textarea and click the **Submit** button +to submit the updated response to the system. + +The system stores the submitted response as a Markdown file in the project's local `rewrites` +directory. The user may re-click the **Submit** button to update the submitted rewrite multiple +times. + +### Enabling users to like generated responses + +The project's latest web UI includes the **Like this response** button at the bottom of the panel +(see Figure 6). When this button is clicked, the server logs the event of "like" for the response. +However, clicking the **Liked** button again will reset the button. Then the server logs this reset +event of "like" for the response. + +The user may click this like button multiple times to toggle the state of the like button. But when +examining the logs, only the final state of the like button will be considered for the response. + +### Using Google Docs, PDF, or Gmail as input sources + +The project includes Apps Script files that allow you to convert various sources of content +(including Google Docs and PDF) from your Google Drive and Gmail into Markdown files. You can then +use these Markdown files as additional input sources for Docs Agent. For more information, see the +[`README`][apps-script-readme] file in the `apps_script` directory. + +![Docs Agent pre-processing flow](./images/docs-agent-pre-processing-01.png) + +**Figure 7**. Docs Agent's pre-processing flow for various doc types. + +### Using the Semantic Retrieval API and AQA model + +Docs Agent provides options to use Gemini's [Semantic Retrieval API][semantic-api] for storing text +chunks in Google Cloud's online storage (and using this online storage for context retrieval), +in combination with using the [AQA model][aqa-model] for question-answering. + +To use the Semantic Retrieval API, update the `config.yaml` file to the following settings: + +``` +models: + - language_model: "models/aqa" + +... + +db_type: "google_semantic_retriever" +``` + +The setup above uses both the Semantic Retrieval API and the AQA model. + +**Note**: At the moment, when `db_type` is set to `google_semantic_retriever`, running the +`populate_vector_database.py` script will also create and popluate a local vector database using +Chroma as well as creating and populating an online corpus using the Semantic Retrieval API. + +However, if you want to use only the AQA model without using an online corpus, update the +`config.yaml` file to the following settings instead: + +``` +models: + - language_model: "models/aqa" + +... + +db_type: "chroma" +``` + +The setup above uses the AQA model with your local Chroma vector database. For more information, +see the [More Options: AQA Using Inline Passages][inline-passages] section on the +_Semantic Retriever Quickstart_ page. + +**Note**: To use the Semantic Retrieval API, you need to complete the OAuth setup for your Google +Cloud project from your host machine. For detailed instructions, see the +[Authentication with OAuth quickstart][oauth-quickstart] page. + + + +[set-up-docs-agent]: ../README.md#set-up-docs-agent +[files-to-plain-text]: ../docs_agent/preprocess/files_to_plain_text.py +[populate-vector-database]: ../docs_agent/preprocess/populate_vector_database.py +[context-source-01]: http://eventhorizontelescope.org +[fact-check-section]: #using-a-language-model-to-fact_check-its-own-response +[related-questions-section]: #using-a-language-model-to-suggest-related-questions +[submit-a-rewrite]: #enabling-users-to-submit-a-rewrite-of-a-generated-response +[like-generated-responses]: #enabling-users-to-like-generated-responses +[populate-db-steps]: #populate-a-new-vector-database-from-markdown-files +[genai-doc-site]: https://ai.google.dev/docs/gemini_api_overview +[chroma-docs]: https://docs.trychroma.com/ +[apps-script-readme]: ../apps_script/README.md +[scripts-readme]: ../docs_agent/preprocess/README.md +[config-yaml]: ../config.yaml +[benchmark-test]: ../docs_agent/benchmarks/README.md +[semantic-api]: https://ai.google.dev/docs/semantic_retriever +[aqa-model]: https://ai.google.dev/models/gemini#model_variations +[oauth-quickstart]: https://ai.google.dev/docs/oauth_quickstart +[inline-passages]: https://ai.google.dev/docs/semantic_retriever#more_options_aqa_using_inline_passages +[authorize-credentials]: https://ai.google.dev/docs/oauth_quickstart#authorize-credentials +[preprocess-dir]: ../docs_agent/preproces/ diff --git a/demos/palm/python/docs-agent/docs/images/docs-agent-chat-app-screenshot-01.png b/demos/palm/python/docs-agent/docs/images/docs-agent-chat-app-screenshot-01.png new file mode 100644 index 0000000000000000000000000000000000000000..6efb51c9a2ef98ed28a59a5f14e9c8088df5c1f7 GIT binary patch literal 265045 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 + +[benchmarks-yaml]: benchmarks.yaml +[config-yaml]: ../../config.yaml +[flutter-faq]: https://docs.flutter.dev/resources/faq +[flutter-git]: https://github.com/flutter/website/tree/main/src +[results-out]: results.out +[embedding-generation]: https://ai.google.dev/docs/embeddings_guide diff --git a/demos/palm/python/docs-agent/docs_agent/benchmarks/benchmarks.yaml b/demos/palm/python/docs-agent/docs_agent/benchmarks/benchmarks.yaml new file mode 100644 index 000000000..a5a6e4c7e --- /dev/null +++ b/demos/palm/python/docs-agent/docs_agent/benchmarks/benchmarks.yaml @@ -0,0 +1,52 @@ +# +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +### Configuration for Docs Agent benchmark tests ### + +# Source docs: https://github.com/flutter/website/tree/main/src (flutter.dev) +# +# These questions and target answers are captured from https://docs.flutter.dev/resources/faq. +# +# For this benchmark testing, use a config.yaml setup similar to the following: +# +# inputs: +# - path: "/usr/local/home/user01/website/src/ui" +# url_prefix: "https://docs.flutter.dev/ui" +# - path: "/usr/local/home/user01/website/src/tools" +# url_prefix: "https://docs.flutter.dev/tools" + + +benchmarks: + - question: "What is inside the Flutter SDK?" + target_answer: "Flutter includes: * Heavily optimized, mobile-first 2D rendering engine with excellent support for text * Modern react-style framework * Rich set of widgets implementing Material Design and iOS-style * APIs for unit and integration tests * Interop and plugin APIs to connect to the system and 3rd-party SDKs * Headless test runner for running tests on Windows, Linux, and Mac * Flutter DevTools (also called Dart DevTools) for testing, debugging, and profiling your app * Command-line tools for creating, building, testing, and compiling your apps" + - question: "Does Flutter work with any editors or IDEs?" + target_answer: "We provide plugins for VS Code, Android Studio, and IntelliJ IDEA. See editor configuration for setup details, and VS Code and Android Studio/IntelliJ for tips on how to use the plugins. Alternatively, you can use the flutter command from a terminal, along with one of the many editors that support editing Dart." + - question: "Does Flutter come with a framework?" + target_answer: "Yes! Flutter ships with a modern react-style framework. Flutter’s framework is designed to be layered and customizable (and optional). Developers can choose to use only parts of the framework, or even replace upper layers of the framework entirely." + - question: "Does Flutter come with widgets?" + target_answer: "Yes! Flutter ships with a set of high-quality Material Design and Cupertino (iOS-style) widgets, layouts, and themes. Of course, these widgets are only a starting point. Flutter is designed to make it easy to create your own widgets, or customize the existing widgets." + - question: "Does Flutter support Material Design?" + target_answer: "Yes! The Flutter and Material teams collaborate closely, and Material is fully supported. For more information, check out the Material 2 and Material 3 widgets in the widget catalog." + - question: "Does Flutter come with a testing framework?" + target_answer: "Yes, Flutter provides APIs for writing unit and integration tests. Learn more about testing with Flutter. We use our own testing capabilities to test our SDK, and we measure our test coverage on every commit." + - question: "Does Flutter come with debugging tools?" + target_answer: "Yes, Flutter comes with Flutter DevTools (also called Dart DevTools). For more information, see Debugging with Flutter and the Flutter DevTools docs." + - question: "Does Flutter come with a dependency injection framework?" + target_answer: "We don’t ship with an opinionated solution, but there are a variety of packages that offer dependency injection and service location, such as injectable, get_it, kiwi, and riverpod." + - question: "What technology is Flutter built with?" + target_answer: "Flutter is built with C, C++, Dart, Skia (a 2D rendering engine), and Impeller (the default rendering engine on iOS). See this architecture diagram for a better picture of the main components. For a more detailed description of the layered architecture of Flutter, read the architectural overview." + - question: "What language is Flutter written in?" + target_answer: "Dart, a fast-growing modern language optimized for client apps. The underlying graphics framework and the Dart virtual machine are implemented in C/C++." diff --git a/demos/palm/python/docs-agent/docs_agent/benchmarks/results.out b/demos/palm/python/docs-agent/docs_agent/benchmarks/results.out new file mode 100644 index 000000000..7418b92cc --- /dev/null +++ b/demos/palm/python/docs-agent/docs_agent/benchmarks/results.out @@ -0,0 +1,12 @@ +Similarity (-1, 1) Question +================== ======== +0.9693597667161213 What is inside the Flutter SDK? +0.8810758779307981 Does Flutter work with any editors or IDEs? +0.8760932771858571 Does Flutter come with a framework? +0.8924252745816632 Does Flutter come with widgets? +0.8637181105900334 Does Flutter support Material Design? +0.9340505894484676 Does Flutter come with a testing framework? +0.9192416276439515 Does Flutter come with debugging tools? +0.7491969164696617 Does Flutter come with a dependency injection framework? +0.7895399136265219 What technology is Flutter built with? +0.7802681514431923 What language is Flutter written in? diff --git a/demos/palm/python/docs-agent/docs_agent/benchmarks/run_benchmark_tests.py b/demos/palm/python/docs-agent/docs_agent/benchmarks/run_benchmark_tests.py new file mode 100644 index 000000000..925329880 --- /dev/null +++ b/demos/palm/python/docs-agent/docs_agent/benchmarks/run_benchmark_tests.py @@ -0,0 +1,223 @@ +# +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +"""Run benchmark tests to measure the quality of embeddings, context chunks, and AI responses""" + +import os +import sys +import yaml + +import numpy as np + +from rich.console import Console +from rich.markdown import Markdown +from rich.panel import Panel + +from docs_agent.storage.chroma import Format +from docs_agent.agents.docs_agent import DocsAgent +from docs_agent.utilities import config +from docs_agent.utilities.config import ProductConfig + + +# A function that asks the questin to the AI model using the RAG technique. +def ask_model(question: str, docs_agent: DocsAgent): + results_num = 5 + if "gemini" in docs_agent.config.models.language_model: + # print("Asking a Gemini model") + (search_result, final_context) = docs_agent.query_vector_store_to_build( + question=question, + token_limit=30000, + results_num=results_num, + max_sources=results_num, + ) + response, full_prompt = docs_agent.ask_content_model_with_context_prompt( + context=final_context, question=question + ) + elif "aqa" in docs_agent.config.models.language_model: + # print("Asking the AQA model") + if docs_agent.config.db_type == "google_semantic_retriever": + (response, search_result) = docs_agent.ask_aqa_model_using_corpora( + question=question + ) + elif docs_agent.config.db_type == "chroma": + ( + response, + search_result, + ) = docs_agent.ask_aqa_model_using_local_vector_store( + question=question, results_num=results_num + ) + else: + (response, search_result) = docs_agent.ask_aqa_model_using_corpora( + question=question + ) + return response + + +# A customized print function +def vprint(text: str, VERBOSE: bool = False): + if VERBOSE: + print(text) + + +# A function that computes cosine similarity between two vectors +def compute_cosine_similarity(v1, v2): + a = np.asarray(v1) + b = np.asarray(v2) + dot = np.dot(a, b) + a_norm = np.linalg.norm(a, 2) + b_norm = np.linalg.norm(b, 2) + cosine = dot / (a_norm * b_norm) + return cosine + + +# Read the `benchmarks.yaml` file in the `benchmarks` directory of the project. +def read_benchmarks_yaml(): + BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + BENCHMARKS_YAML = os.path.join(BASE_DIR, "benchmarks/benchmarks.yaml") + try: + with open(BENCHMARKS_YAML, "r", encoding="utf-8") as b_yaml: + read_values = yaml.safe_load(b_yaml) + except FileNotFoundError: + print("The " + BENCHMARKS_YAML + " file is missing.") + sys.exit(1) + return read_values + + +def run_benchmarks(): + # VERBOSE = False + BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + # Initialize Rich console + my_console = Console(width=160) + + # Read the configuration file (`config.yaml`) + config_file = config.ReadConfig().returnProducts() + # TODO: This benchmark test only selects the first product + # in the product list in the config file at the moment. + product = config_file.products[0] + print(f"===========================================") + print(f"Benchmark test target product: {product.product_name}") + print(f"===========================================") + + # Initialize Docs Agent + if product.db_type == "google_semantic_retriever": + docs_agent = DocsAgent(config=product, init_chroma=False) + else: + docs_agent = DocsAgent(config=product) + + # Read the `benchmarks.yaml` file. + benchmark_values = read_benchmarks_yaml() + + questions = [] + results = [] + index = 0 + print() + for benchmark in benchmark_values["benchmarks"]: + embedding_01 = "" + embedding_02 = "" + response = "" + similarity = "" + + # Step 1. Read a `question` and `target_answer` pair. + question = benchmark["question"] + target_answer = benchmark["target_answer"] + questions.append(question) + print("================") + print("Benchmark " + str(index)) + print("================") + print("Question: " + question) + print("Target answer: " + target_answer) + print() + + # Step 2. Generate an embedding using `target_answer` - Embedding 1. + vprint("################") + vprint("# Embedding 1 #") + vprint("################") + vprint("Input text:") + vprint(target_answer) + embedding_01 = docs_agent.generate_embedding(target_answer) + vprint("") + vprint("Embedding:") + vprint(embedding_01) + + # Step 3. Ask `question` to the AI model. + response = ask_model(question, docs_agent) + vprint("################") + vprint("# Response #") + vprint("################") + vprint(response) + + # Step 4. Generate an embedding using the response - Embedding 2. + vprint("################") + vprint("# Embedding 2 #") + vprint("################") + vprint("Input text:") + vprint(response) + embedding_02 = docs_agent.generate_embedding(response) + vprint("") + vprint("Embedding:") + vprint(embedding_02) + + # Step 5. Compute the similarity between Embedding 1 and Embedding 2. + vprint("################") + vprint("# Similarity #") + vprint("################") + similarity = compute_cosine_similarity(embedding_01, embedding_02) + vprint(similarity) + vprint("") + results.append(similarity) + + # Step 6. Print the summary of this run. + print("################") + print("# Result #") + print("################") + print("Question:") + my_console.print(Panel.fit(Markdown(question))) + print() + print("Target answer:") + my_console.print(Panel.fit(Markdown(target_answer))) + print() + print("AI Response:") + my_console.print(Panel.fit(Markdown(response))) + print() + print("Similarity:") + print(similarity) + print() + + index += 1 + + # Print the benchmark test results. + print("################################") + print("# Benchmark tests summary #") + print("################################") + print() + print("Similarity (-1, 1)" + " " + "Question") + print("==================" + " " + "========") + for i, q in enumerate(questions): + print(str("{:.16f}".format(results[i])) + " " + q) + print() + + # Store the benchmark test results into benchmarks/results.out. + BENCHMARKS_OUT = os.path.join(BASE_DIR, "benchmarks/results.out") + with open(BENCHMARKS_OUT, "w", encoding="utf-8") as outfile: + outfile.write("Similarity (-1, 1)" + " " + "Question\n") + outfile.write("==================" + " " + "========\n") + for i, q in enumerate(questions): + outfile.write(str("{:.16f}".format(results[i])) + " " + q + "\n") + print("Created " + BENCHMARKS_OUT + " to store the results of the benchmark tests.") + + +if __name__ == "__main__": + run_benchmarks() diff --git a/demos/palm/python/docs-agent/docs_agent/interfaces/README.md b/demos/palm/python/docs-agent/docs_agent/interfaces/README.md new file mode 100644 index 000000000..bd383e5ae --- /dev/null +++ b/demos/palm/python/docs-agent/docs_agent/interfaces/README.md @@ -0,0 +1,211 @@ +# Set up Docs Agent CLI + +This guide provides instructions on setting up Docs Agent's command-line +interface (CLI) that allows you to ask questions from anywhere in a terminal. + +Using Docs Agent, you can configure your host machine's environment to make +the `gemini` command run from anywhere in your terminal. The `gemini` command +(which is an `alias` to Docs Agent's `agent tellme` command) reads a question +from the arguments, asks the [Gemini AQA][gemini-aqa] model, and prints its +response in the terminal. + +The example below shows that a user can run the `gemini` command directly +from a terminal: + +``` +user@user01:~$ gemini does Flutter support material design 3? + +As of the Flutter 3.16 release, Material 3 is enabled by default. + +To verify this information, see: + + • https://docs.flutter.dev/ui/design/material/index#more-information + +user@user01:~$ +``` + +In this setup guide, Docs Agent's AQA model is configured to use an example +online corpus. However, using the tools available in the Docs Agent project, +you can [create and populate a new corpus][populate-corpus] with your own +documents and adjust your Docs Agent configuration to use that corpus +instead – you can also [share the corpus][share-corpus] with other members +in your team. + +## 1. Prerequisites + +Setting up Docs Agent requires the following prerequisite items: + +- A Linux host machine + +- A [Google Cloud][google-cloud] project with the setup below: + + - An API key enabled with the Generative Language API (that is, + the [Gemini API][genai-doc-site]) + + - (**Optional**) [Authenticated OAuth client credentials][oauth-client] + stored on the host machine + +## 2 Update your host machine's environment + +1. Update the Linux package repositories on the host machine: + + ```posix-terminal + sudo apt update + ``` + +2. Install the following dependencies: + + ```posix-terminal + sudo apt install git pip python3-venv + ``` + +3. Install `poetry`: + + ```posix-terminal + curl -sSL https://install.python-poetry.org | python3 - + ``` + + **Important**: Make sure that `$HOME/.local/bin` is in your `PATH` variable + (for example, `export PATH=$PATH:~/.local/bin`). + +4. Set the following environment variable: + + ```posix-terminal + export PYTHON_KEYRING_BACKEND=keyring.backends.null.Keyring + ``` + + This is a [known issue][poetry-known-issue] in `poetry`. + +5. Set the Google API key as a environment variable: + + ``` + export GOOGLE_API_KEY= + ``` + + Replace `` with the API key to the + [Gemini API][genai-doc-site]. + + **Tip**: To avoid repeating these `export` lines, add them to your + `$HOME/.bashrc` file. + +## 3. Authorize credentials for Docs Agent + +**Note**: This step may not be necessary if you already have OAuth client +credentials (via `gcloud`) stored on your host machine. + +1. Download the `client_secret.json` file from your + [Google Cloud project][authorize-credentials]. + +2. Copy the `client_secret.json` file to your host machine. + +3. To authenticate credentials, run the following command in the directory of + the host machine where the `client_secret.json` file is located: + + ``` + gcloud auth application-default login --client-id-file=client_secret.json --scopes='https://www.googleapis.com/auth/cloud-platform,https://www.googleapis.com/auth/generative-language.retriever' + ``` + + This command opens a browser and asks to log in using your Google account. + + **Note**: If the `gcloud` command doesn’t exist, install the Google Cloud SDK + on your host machine: `sudo apt install google-cloud-sdk` + +4. Follow the instructions on the browser and click **Allow** to authenticate. + + This saves the authenticated credentials for Docs Agent + (`application_default_credentials.json`) in the `$HOME/.config/gcloud/` + directory of your host machine. + +## 4. Clone the Docs Agent project repository + +**Note**: This guide assumes that you're creating a new project directory +from your `$HOME` directory. + +1. Clone the following internal repo: + + ```posix-terminal + git clone sso://doc-llm-internal/docs-agent + ``` + +2. Go to the project directory: + + ```posix-terminal + cd docs-agent + ``` + +3. Install dependencies using `poetry`: + + ```posix-terminal + poetry install + ``` + + This may take some time to complete. + +## 5. Set up an alias to the gemini command + +**Note**: If your Docs Agent project is not cloned in the `$HOME` directory, +you need to edit the `tellme.sh` script in your `docs-agent` project directory. + +Update your shell environment so that the `gemini` command can be run +from anywhere in the terminal: + +1. (**Optional**) Open the `tellme.sh` file using a text editor, for example: + + ```sh + nano tellme.sh + ``` + + If necessary, adjust the path (`$HOME/docs-agent`) to match your + `docs-agent` project directory on the host machine: + + ``` + #!/bin/bash + + # Check if the POETRY_ACTIVE environment variable is set + if [ -z "$POETRY_ACTIVE" ]; then + cd $HOME/docs-agent && poetry run agent tellme $@ + else + agent tellme $@ + fi + ``` + + Save the file and close text editor. + +2. Add the following `alias` line to your `$HOME/.bashrc` file: + + ``` + alias gemini='$HOME/docs-agent/tellme.sh' + ``` + + Similarly, if necessary, you need to adjust the path + (`$HOME/docs-agent`) to match your the `docs-agent` project directory + on the host machine. + +3. Update your environment: + + ```sh + source ~/.bashrc + ``` + +4. Now you can run the `gemini` command from anywhere in your terminal: + + ```sh + gemini + ``` + + For example: + + ``` + user@user01:~/temp$ gemini does flutter support material design 3? + ``` + + + +[gemini-aqa]: https://ai.google.dev/docs/semantic_retriever +[populate-corpus]: ../preprocess/README.md +[share-corpus]: https://ai.google.dev/docs/semantic_retriever#share_the_corpus +[google-cloud]: https://console.cloud.google.com/ +[oauth-client]: https://ai.google.dev/docs/oauth_quickstart#set-cloud +[authorize-credentials]: https://ai.google.dev/docs/oauth_quickstart#authorize-credentials +[poetry-known-issue]: https://github.com/python-poetry/poetry/issues/1917 +[genai-doc-site]: https://ai.google.dev/docs/gemini_api_overview diff --git a/demos/palm/python/docs-agent/setup.py b/demos/palm/python/docs-agent/docs_agent/interfaces/chatbot/__init__.py similarity index 67% rename from demos/palm/python/docs-agent/setup.py rename to demos/palm/python/docs-agent/docs_agent/interfaces/chatbot/__init__.py index 1d9261f80..629ffe29f 100644 --- a/demos/palm/python/docs-agent/setup.py +++ b/demos/palm/python/docs-agent/docs_agent/interfaces/chatbot/__init__.py @@ -14,11 +14,12 @@ # limitations under the License. # -"""For setting up local packages in the project.""" -from setuptools import setup +from flask import Flask +from docs_agent.interfaces.chatbot import chatui +from docs_agent.utilities import config -setup( - name="docs_agent", - packages=["chatbot", "docs_agent"], - install_requires=["flask"], -) + +def create_app(product: config.ProductConfig): + app = Flask(__name__) + app.register_blueprint(chatui.construct_blueprint(product_config=product)) + return app diff --git a/demos/palm/python/docs-agent/docs_agent/interfaces/chatbot/chatui.py b/demos/palm/python/docs-agent/docs_agent/interfaces/chatbot/chatui.py new file mode 100644 index 000000000..084dfa884 --- /dev/null +++ b/demos/palm/python/docs-agent/docs_agent/interfaces/chatbot/chatui.py @@ -0,0 +1,326 @@ +# +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +"""Chatbot web service for Docs Agent""" + +from flask import Blueprint, render_template, request, redirect, url_for, json, jsonify +import markdown +import markdown.extensions.fenced_code +from bs4 import BeautifulSoup +import urllib +import os +from datetime import datetime +from pytz import timezone +from absl import logging +import pytz +import uuid + +from docs_agent.utilities.helpers import ( + parse_related_questions_response_to_html_list, + trim_section_for_page_link, + named_link_html, + md_to_html, +) +from docs_agent.utilities import config +from docs_agent.preprocess.splitters import markdown_splitter +from docs_agent.postprocess.docs_retriever import SectionProbability + +from docs_agent.storage.chroma import Format +from docs_agent.agents.docs_agent import DocsAgent + +from docs_agent.memory.logging import log_question, log_like + + +# This is used to define the app blueprint using a productConfig +def construct_blueprint(product_config: config.ProductConfig): + bp = Blueprint("chatui", __name__) + if product_config.db_type == "google_semantic_retriever": + docs_agent = DocsAgent(config=product_config, init_chroma=False) + else: + docs_agent = DocsAgent(config=product_config) + logging.info(f"Launching the flask app for product: {product_config.product_name}") + + @bp.route("/", methods=["GET", "POST"]) + def index(): + server_url = request.url_root.replace("http", "https") + return render_template( + "chatui/index.html", + product=product_config.product_name, + server_url=server_url, + ) + + @bp.route("/api/ask-docs-agent", methods=["GET", "POST"]) + def api(): + try: + input = request.get_json() + if input["question"]: + ( + full_prompt, + response, + context, + sources_ref, + plain_token, + ) = ask_model_2_with_sources(input["question"], agent=docs_agent) + source_array = [] + for source in sources_ref: + source_array.append(source.returnDictionary()) + dictionary = { + "response": response, + "full_prompt": full_prompt, + "token_count_context": plain_token, + "sources": source_array, + } + return jsonify(dictionary) + else: + error = "Must have a valid question key in your JSON" + return jsonify({"error": error}), 400 + except: + error = "Must be a valid JSON" + return jsonify({"error": error}), 400 + + @bp.route("/like", methods=["GET", "POST"]) + def like(): + if request.method == "POST": + json_data = json.loads(request.data) + is_like = json_data.get("like") + uuid_found = json_data.get("uuid") + log_like(is_like, str(uuid_found).strip()) + return "OK" + else: + return redirect(url_for("chatui.index")) + + @bp.route("/rewrite", methods=["GET", "POST"]) + def rewrite(): + # Create the 'rewrites' directory if it does not exist. + rewrites_dir = "rewrites" + is_exist = os.path.exists(rewrites_dir) + if not is_exist: + os.makedirs(rewrites_dir) + if request.method == "POST": + json_data = json.loads(request.data) + user_id = json_data.get("user_id") + question_captured = json_data.get("question") + original_response = json_data.get("original_response") + rewrite_captured = json_data.get("rewrite") + date_format = "%m%d%Y-%H%M%S" + date = datetime.now(tz=pytz.utc) + date = date.astimezone(timezone("US/Pacific")) + print( + "[" + date.strftime(date_format) + "] A user has submitted a rewrite." + ) + print("Submitted by: " + user_id + "\n") + print("# " + question_captured.strip() + "\n") + print("## Original response\n") + print(original_response.strip() + "\n") + print("## Rewrite\n") + print(rewrite_captured + "\n") + filename = ( + rewrites_dir + + "/" + + question_captured.strip() + .replace(" ", "-") + .replace("?", "") + .replace("'", "") + .lower() + + "-" + + date.strftime(date_format) + + ".md" + ) + with open(filename, "w", encoding="utf-8") as file: + file.write("Submitted by: " + user_id + "\n\n") + file.write("# " + question_captured.strip() + "\n\n") + file.write("## Original response\n\n") + file.write(original_response.strip() + "\n\n") + file.write("## Rewrite\n\n") + file.write(rewrite_captured + "\n") + file.close() + return "OK" + else: + if product_config.docs_agent_config == "experimental": + return redirect(url_for("chatui.index_experimental")) + elif product_config.docs_agent_config == "normal": + return redirect(url_for("chatui.index")) + + # Render a response page when the user asks a question + # using input text box. + @bp.route("/result", methods=["GET", "POST"]) + def result(): + if request.method == "POST": + question = request.form["question"] + if product_config.docs_agent_config == "experimental": + return ask_model2(question, agent=docs_agent, template="chatui/index_experimental.html") + elif product_config.docs_agent_config == "normal": + return ask_model2( + question, agent=docs_agent, template="chatui/index.html" + ) + else: + if product_config.docs_agent_config == "experimental": + return redirect(url_for("chatui.index_experimental")) + elif product_config.docs_agent_config == "normal": + return redirect(url_for("chatui.index")) + + # Render a response page when the user clicks a question + # from the related questions list. + @bp.route("/question/", methods=["GET", "POST"]) + def question(ask): + if request.method == "GET": + question = urllib.parse.unquote_plus(ask) + if product_config.docs_agent_config == "experimental": + return ask_model2(question, agent=docs_agent, template="chatui/index_experimental.html") + elif product_config.docs_agent_config == "normal": + return ask_model2( + question, agent=docs_agent, template="chatui/index.html" + ) + else: + if product_config.docs_agent_config == "experimental": + return redirect(url_for("chatui.index_expiremental")) + elif product_config.docs_agent_config == "normal": + return redirect(url_for("chatui.index")) + + return bp + + +# Construct a set of prompts using the user question, send the prompts to +# the lanaguage model, receive responses, and present them into a page. +# Use template to specify a custom template for the classic web UI +def ask_model2(question, agent, template: str = "chatui/index.html"): + # Returns a built context, a total token count of the context and an array + # of sourceOBJ + full_prompt = "" + final_context = "" + docs_agent = agent + new_question_count = 5 + results_num = 5 + aqa_response_in_html = "" + if "gemini" in docs_agent.config.models.language_model: + if docs_agent.config.docs_agent_config == "experimental": + results_num = 10 + new_question_count = 5 + else: + results_num = 5 + new_question_count = 5 + # Issue if max_sources > results_num, so leave the same for now + search_result, final_context = docs_agent.query_vector_store_to_build( + question=question, + token_limit=30000, + results_num=results_num, + max_sources=results_num, + ) + response, full_prompt = docs_agent.ask_content_model_with_context_prompt( + context=final_context, question=question + ) + aqa_response_in_html = "" + elif "aqa" in docs_agent.config.models.language_model: + if docs_agent.config.db_type == "google_semantic_retriever": + (response, search_result) = docs_agent.ask_aqa_model_using_corpora( + question=question + ) + elif docs_agent.config.db_type == "chroma": + ( + response, + search_result, + ) = docs_agent.ask_aqa_model_using_local_vector_store( + question=question, results_num=results_num + ) + else: + (response, search_result) = docs_agent.ask_aqa_model_using_corpora( + question=question + ) + # Buid a final_context item + context_count = 0 + for item in search_result: + context_count += 1 + final_context += ( + item.section.content + "\nReference [" + str(context_count) + "]\n\n" + ) + final_context = final_context.strip() + aqa_response_json = docs_agent.get_saved_aqa_response_json() + if aqa_response_json: + aqa_response_in_html = json.dumps( + type(aqa_response_json).to_dict(aqa_response_json), indent=2 + ) + + ### PROMPT: GET RELATED QUESTIONS. + # 1. Use the response from Prompt 1 as context and add a custom condition. + # 2. Prepare a new question asking the model to come up with 5 related questions. + # 3. Ask the language model with the new question. + # 4. Parse the model's response into a list in HTML format. + new_condition = f"Read the context below and answer the question at the end:" + new_question = f"Can you think of {new_question_count} questions whose answers can be found in the context above?" + ( + related_questions_response, + new_prompt_questions, + ) = docs_agent.ask_content_model_with_context_prompt( + context=final_context, question=new_question, prompt=new_condition + ) + # Clean up the response to a proper html list + related_questions = parse_related_questions_response_to_html_list( + markdown.markdown(related_questions_response) + ) + + ### PREPARE OTHER ELEMENTS NEEDED BY UI. + # - Create a uuid for this request. + # - A workaround to get the server's URL to work with the rewrite and like features. + new_uuid = uuid.uuid1() + server_url = request.url_root.replace("http", "https") + ### Check the AQA model's answerable_probability field + probability = "None" + if docs_agent.check_if_aqa_is_used(): + aqa_response = docs_agent.get_saved_aqa_response_json() + try: + probability = aqa_response.answerable_probability + except: + probability = 0.0 + ### LOG THIS REQUEST. + log_question(new_uuid, question, response, probability) + + return render_template( + template, + question=question, + response=response, + related_questions=related_questions, + product=docs_agent.config.product_name, + server_url=server_url, + uuid=new_uuid, + aqa_response_in_html=aqa_response_in_html, + named_link_html=named_link_html, + trim_section_for_page_link=trim_section_for_page_link, + md_to_html=md_to_html, + final_context=final_context, + search_result=search_result, + ) + + +# Not fully implemented +# This method is used for the API endpoint, so it returns values that can be +# packaged as JSON +def ask_model_2_with_sources(question, agent): + docs_agent = agent + full_prompt = "" + context, plain_token, sources_ref = docs_agent.query_vector_store_to_build( + question=question, token_limit=30000, results_num=10, max_sources=10 + ) + context_with_instruction = docs_agent.add_instruction_to_context(context) + if "gemini" in docs_agent.get_language_model_name(): + response, full_prompt = docs_agent.ask_content_model_with_context_prompt( + context=context, question=question + ) + else: + response = docs_agent.ask_text_model_with_context( + context_with_instruction, question + ) + + return full_prompt, response, context, sources_ref, plain_token diff --git a/demos/palm/python/docs-agent/docs_agent/interfaces/chatbot/static/css/chatbox.css b/demos/palm/python/docs-agent/docs_agent/interfaces/chatbot/static/css/chatbox.css new file mode 120000 index 000000000..44ad5badf --- /dev/null +++ b/demos/palm/python/docs-agent/docs_agent/interfaces/chatbot/static/css/chatbox.css @@ -0,0 +1 @@ +../../../../../third_party/css/chatbox.css \ No newline at end of file diff --git a/demos/palm/python/docs-agent/docs_agent/interfaces/chatbot/static/css/style-chatui.css b/demos/palm/python/docs-agent/docs_agent/interfaces/chatbot/static/css/style-chatui.css new file mode 100644 index 000000000..fb67d4b4b --- /dev/null +++ b/demos/palm/python/docs-agent/docs_agent/interfaces/chatbot/static/css/style-chatui.css @@ -0,0 +1,507 @@ +/** + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* ======= General style for HTML elements ======= */ + +body { + font: 16px/1.5em Overpass, "Open Sans", Helvetica, sans-serif; + color: #333; + font-weight: 300; + max-width: 960px; + margin: auto; + background-color: #d9d9d9; + padding-top: 15px; + padding-bottom: 15px; + } + + a { + color: #0a619a; + } + + p { + margin: 0 0 1em; + line-height: 130%; + } + + h1 { + margin: 0 0 0.5em; + font-weight: 500; + font-size: 1.3em; + margin-left: 1.0em; + margin-top: 0.3em; + } + + h2 { + margin: 0; + margin-top: 17px; + margin-bottom: 15px; + font-weight: normal; + font-size: 1.5em; + } + + h3 { + margin: 0; + margin-top: 10px; + margin-bottom: 10px; + } + + h4 { + color: #505050; + margin-top: 3px; + margin-left: 5px; + margin-bottom: 8px; + } + + li { + margin: 0 0 0.3em; + } + + code { + font-family: math; + color: darkgreen; + text-wrap: pretty; + } + + /* ======= Style layout by ID ======= */ + + #callout-box { + margin: auto; + max-width: 800px; + font: 13px arial, sans-serif; + background-color: white; + border-style: solid; + border-width: 1px; + padding: 10px 25px; + box-shadow: 5px 5px 5px grey; + border-radius: 15px; + } + + #important-box { + font-size: 0.9em; + font-family: system-ui; + line-height: 150%; + padding: 4px; + } + + #response-box { + font-size: 1.0em; + font-family: sans-serif; + line-height: 100%; + margin-top: 10px; + } + + #suggested-questions { + font-family: sans-serif; + } + + #context-content{ + background: #d7dbd7; + font-family: sans-serif; + word-break: break-all; + } + + #context-pre { + font-size: small; + font-family: monospace; + text-wrap: pretty; + margin-top: 0.3px; + } + + #probability-box { + font-size: small; + padding: 4px; + margin-bottom: 10px; + } + + #grounding-box { + font-size: small; + padding: 4px; + word-break: break-all; + } + + #grounding-pre { + font-size: small; + font-family: monospace; + text-wrap: pretty; + } + + #reference-box { + font-size: 0.9em; + font-family: system-ui; + text-wrap: pretty; + word-break: break-all; + margin-bottom: 12px; + line-height: 1.5em; + } + + #reference-box-no-aqa { + font-size: 0.9em; + font-family: system-ui; + text-wrap: pretty; + word-break: break-all; + line-height: 1.5em; + } + + #aqa-content{ + background: #9fc7db; + font-family: math; + } + + #aqa-label{ + background: #49a5d2; + } + + #aqa-json { + font-family: system-ui; + font-size: small; + text-wrap: pretty; + word-break: break-all; + margin: 0; + } + + #rewrite-buttons-box { + margin-top: 12px; + } + + /* ======= Style by class ======= */ + + .hidden { + display: none; + } + + .disable { + display: none; + } + + .header-wrapper { + display: flex; + } + + .loading { + font: 15px arial, sans-serif; + width: 100%; + margin-left: 12px; + color: #505050; + padding: 2px; + } + + .notselected { + background-color: #303936e6; + padding-top: 3px; + padding-bottom: 5px; + } + + .notselected:hover { + background-color: #121a17e6; + cursor:pointer; + } + + .selected { + background-color: #1e6a9c; + padding-top: 7px; + padding-bottom: 7px; + } + + .selected:hover { + background-color: #0a619a; + cursor:pointer; + } + + .rewrite { + padding: 15px; + border: 2px solid #000; + margin-top: 6px; + border-radius: 15px; + } + + .question, .response, .response-text, .fact-checked-text { + max-width: 700px; + margin-left: 3px; + } + + .full-response { + max-width: 700px; + margin-left: 10px; + } + + .related-questions { + margin-bottom: 20px; + font-size: 0.9em; + } + + /* ======= Style buttons by ID ======= */ + + #rewrite-button { + border: 0; + background-color: #cf633ff2; + color: #fff; + padding: 7px; + border-radius: 5px; + cursor:pointer; + margin-top: 0.3em; + } + + #rewrite-button:hover { + background: #ce3705f2; + cursor:pointer; + } + + #like-button { + border: 0; + color: #fff; + padding-left: 7px; + padding-right: 7px; + border-radius: 5px; + cursor:pointer; + } + + #submit-button { + border: 0; + background: none; + background-color: #CF5C3F; + color: #fff; + padding: 7px; + border-radius: 5px; + cursor:pointer; + } + + #submit-button:hover { + background: #ce3705f2; + cursor:pointer; + } + + #submit-result { + color: #027f02d6; + font-family: fantasy; + } + + #edit-text-area { + font: 13px/1.5em Overpass, "Open Sans", Helvetica, sans-serif; + max-height: 500px; + max-width: 650px; + height: 300px; + width: 650px; + padding: 8px; + } + + #rewrite-question-header { + margin: 0; + margin-bottom: 5px; + } + + #rewrite-response-header { + margin: 0; + margin-top: 10px; + margin-bottom: 5px; + } + + #user-id { + margin: 0; + margin-top: 10px; + margin-bottom: 15px; + } + + #fact-check-url { + margin: 0 0 0.7em; + } + + #source-para { + margin: 0 0 0.7em; + } + + #distance-para { + margin: 0 0 0.7em; + font: 11px/1.5em Overpass, "Open Sans", Helvetica, sans-serif; + } + /* ======= Search Box ======= */ + + .search { + border: 2px solid #CF5C3F; + overflow: auto; + max-width: 700px; + margin-top: 15px; + margin-left: 10px; + margin-bottom: 10px; + border-radius: 5px; + } + + .search input[type="text"] { + border: 0; + width: 91%; + padding: 10px; + } + + .search input[type="text"]:focus { + outline: 0; + } + + .search input[type="submit"] { + border: 0; + background: none; + background-color: #CF5C3F; + color: #fff; + float: right; + padding: 10px; + -moz-border-radius-top-right: 5px; + -webkit-border-radius-top-right: 5px; + -moz-border-radius-bottom-right: 5px; + -webkit-border-radius-bottom-right: 5px; + cursor:pointer; + } + + /* ======= Accordion ======= */ + + .accordion { + max-width: 65em; + #margin-bottom: 1em; + } + + .accordion > input[type="checkbox"] { + position: absolute; + left: -100vw; + } + + .accordion .content { + overflow-y: hidden; + height: 0; + transition: height 0.3s ease; + } + + .accordion .reference-content { + font-size: 15px; + font-family: serif; + } + + .accordion > input[type="checkbox"]:checked ~ .content { + height: auto; + overflow: visible; + padding: 15px; + border: 2px solid #000; + margin-top: 6px; + border-radius: 15px; + } + + .accordion .handle { + margin: 0; + font-size: 1.0em; + } + + .accordion label { + display: block; + font-weight: normal; + border: 2px solid #000; + #padding: 12px; + background: #4490b8ab; + #border-radius: 15px; + padding: 5px; + #background: #027f023b; + border-radius: 10px; + } + + .accordion label:hover, + .accordion label:focus { + background: #d9d9d9; + cursor:pointer; + } + + .accordion .handle label::before { + font-family: fontawesome, sans-serif; + display: inline-block; + content: "\2964"; + margin-right: 10px; + font-size: .58em; + line-height: 1.556em; + vertical-align: middle; + } + + .accordion > input[type="checkbox"]:checked ~ .handle label::before { + content: "\2965"; + } + + .accordion p:last-child { + margin-bottom: 0; + } + + /* ======= Accordion Source ======= */ + + .accordion-source { + max-width: 65em; + margin-bottom: 1em; + } + + .accordion-source > input[type="checkbox"] { + position: absolute; + left: -100vw; + } + + .accordion-source .content { + overflow-y: hidden; + height: 0; + transition: height 0.3s ease; + } + + .accordion-source .content{ + font-size: 13px; + } + + .accordion-source > input[type="checkbox"]:checked ~ .content { + height: auto; + overflow: visible; + padding: 15px; + border: 2px solid #000; + margin-top: 6px; + border-radius: 15px; + } + + .accordion-source .handle { + margin: 0; + font-size: 1em; + line-height: 1.2em; + } + + .accordion-source label { + display: block; + font-weight: normal; + border: 1px solid #000; + padding: 6px; + background: #4490b8ab; + border-radius: 15px; + } + + .accordion-source label:hover, + .accordion-source label:focus { + background: #d9d9d9; + cursor:pointer; + } + + .accordion-source .handle label::before { + font-family: fontawesome, sans-serif; + display: inline-block; + content: "\2964"; + margin-right: 10px; + font-size: .58em; + line-height: .556em; + vertical-align: middle; + } + + .accordion-source > input[type="checkbox"]:checked ~ .handle label::before { + content: "\2965"; + } + + .accordion-source p:last-child { + margin-bottom: 0; + } + diff --git a/demos/palm/python/docs-agent/docs_agent/interfaces/chatbot/static/css/style-old.css b/demos/palm/python/docs-agent/docs_agent/interfaces/chatbot/static/css/style-old.css new file mode 100644 index 000000000..b1c0c1b3c --- /dev/null +++ b/demos/palm/python/docs-agent/docs_agent/interfaces/chatbot/static/css/style-old.css @@ -0,0 +1,406 @@ +/** + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* ======= General style for HTML elements ======= */ + +body { + font: 16px/1.5em Overpass, "Open Sans", Helvetica, sans-serif; + color: #333; + font-weight: 300; + max-width: 960px; + margin: auto; + background-color: #d9d9d9; + padding-top: 15px; + padding-bottom: 15px; + } + + a { + color: #22578c; + } + + p { + margin: 0 0 1em; + line-height: 130%; + } + + h1 { + margin: 0 0 0.5em; + font-weight: 500; + font-size: 2.0em; + margin-left: 0.8em; + margin-top: 0.3em; + } + + h2 { + margin: 0; + margin-top: 17px; + margin-bottom: 15px; + } + + h3 { + margin: 0; + margin-top: 10px; + margin-bottom: 10px; + } + + h4 { + color: #505050; + margin: 0; + margin-top: 3px; + margin-bottom: 10px; + } + + li { + margin: 0 0 0.3em; + } + + /* code { + font-family: math; + color: darkgreen; + } */ + + /* ======= Style layout by ID ======= */ + + #callout-box { + margin: auto; + max-width: 800px; + font: 13px arial, sans-serif; + background-color: white; + border-style: solid; + border-width: 1px; + padding: 10px 25px; + box-shadow: 5px 5px 5px grey; + border-radius: 15px; + } + + /* ======= Style by class ======= */ + + .hidden { + display: none; + } + + .disable { + display: none; + } + + .header-wrapper { + display: flex; + } + + .loading { + font: 15px arial, sans-serif; + width: 100%; + margin-left: 12px; + color: #505050; + padding: 2px; + } + + .notselected { + background-color: #303936e6; + padding-top: 3px; + padding-bottom: 5px; + } + + .notselected:hover { + background-color: #121a17e6; + cursor:pointer; + } + + .selected { + background-color: #1e6a9c; + padding-top: 7px; + padding-bottom: 7px; + } + + .selected:hover { + background-color: #0a619a; + cursor:pointer; + } + + .rewrite { + padding: 15px; + border: 2px solid #000; + margin-top: 6px; + border-radius: 15px; + } + + .question, .response, .response-text, .fact-checked-text, .related-questions { + max-width: 700px; + margin-left: 3px; + } + + .full-response { + max-width: 700px; + margin-left: 10px; + } + + /* ======= Style buttons by ID ======= */ + + #rewrite-button { + border: 0; + background-color: #cf633ff2; + color: #fff; + padding: 7px; + border-radius: 5px; + cursor:pointer; + } + + #rewrite-button:hover { + background: #ce3705f2; + cursor:pointer; + } + + #like-button { + border: 0; + color: #fff; + padding-left: 7px; + padding-right: 7px; + border-radius: 5px; + cursor:pointer; + } + + #submit-button { + border: 0; + background: none; + background-color: #CF5C3F; + color: #fff; + padding: 7px; + border-radius: 5px; + cursor:pointer; + } + + #submit-button:hover { + background: #ce3705f2; + cursor:pointer; + } + + #submit-result { + color: #027f02d6; + } + + #edit-text-area { + font: 13px/1.5em Overpass, "Open Sans", Helvetica, sans-serif; + max-height: 500px; + max-width: 650px; + height: 300px; + width: 650px; + padding: 8px; + } + + #rewrite-question-header { + margin: 0; + margin-bottom: 5px; + } + + #rewrite-response-header { + margin: 0; + margin-top: 10px; + margin-bottom: 5px; + } + + #user-id { + margin: 0; + margin-top: 10px; + margin-bottom: 15px; + } + + #fact-check-url { + margin: 0 0 0.7em; + } + + #source-para { + margin: 0 0 0.7em; + } + + #distance-para { + margin: 0 0 0.7em; + font: 11px/1.5em Overpass, "Open Sans", Helvetica, sans-serif; + } + /* ======= Search Box ======= */ + + .search { + border: 2px solid #CF5C3F; + overflow: auto; + max-width: 700px; + margin-top: 15px; + margin-left: 10px; + margin-bottom: 10px; + border-radius: 5px; + } + + .search input[type="text"] { + border: 0; + width: 91%; + padding: 10px; + } + + .search input[type="text"]:focus { + outline: 0; + } + + .search input[type="submit"] { + border: 0; + background: none; + background-color: #CF5C3F; + color: #fff; + float: right; + padding: 10px; + -moz-border-radius-top-right: 5px; + -webkit-border-radius-top-right: 5px; + -moz-border-radius-bottom-right: 5px; + -webkit-border-radius-bottom-right: 5px; + cursor:pointer; + } + + /* ======= Accordion ======= */ + + .accordion { + max-width: 65em; + margin-bottom: 1em; + } + + .accordion > input[type="checkbox"] { + position: absolute; + left: -100vw; + } + + .accordion .content { + overflow-y: hidden; + height: 0; + transition: height 0.3s ease; + } + + .accordion .reference-content { + font-size: 13px; + } + + .accordion > input[type="checkbox"]:checked ~ .content { + height: auto; + overflow: visible; + padding: 15px; + border: 2px solid #000; + margin-top: 6px; + border-radius: 15px; + } + + .accordion .handle { + margin: 0; + font-size: 1.125em; + line-height: 1.2em; + } + + .accordion label { + display: block; + font-weight: normal; + border: 2px solid #000; + padding: 12px; + background: #4490b8ab; + border-radius: 15px; + } + + .accordion label:hover, + .accordion label:focus { + background: #d9d9d9; + cursor:pointer; + } + + .accordion .handle label::before { + font-family: fontawesome, sans-serif; + display: inline-block; + content: "\2964"; + margin-right: 10px; + font-size: .58em; + line-height: 1.556em; + vertical-align: middle; + } + + .accordion > input[type="checkbox"]:checked ~ .handle label::before { + content: "\2965"; + } + + .accordion p:last-child { + margin-bottom: 0; + } + + /* ======= Accordion Source ======= */ + + .accordion-source { + max-width: 65em; + margin-bottom: 1em; + } + + .accordion-source > input[type="checkbox"] { + position: absolute; + left: -100vw; + } + + .accordion-source .content { + overflow-y: hidden; + height: 0; + transition: height 0.3s ease; + } + + .accordion-source .content{ + font-size: 13px; + } + + .accordion-source > input[type="checkbox"]:checked ~ .content { + height: auto; + overflow: visible; + padding: 15px; + border: 2px solid #000; + margin-top: 6px; + border-radius: 15px; + } + + .accordion-source .handle { + margin: 0; + font-size: 1em; + line-height: 1.2em; + } + + .accordion-source label { + display: block; + font-weight: normal; + border: 1px solid #000; + padding: 6px; + background: #4490b8ab; + border-radius: 15px; + } + + .accordion-source label:hover, + .accordion-source label:focus { + background: #d9d9d9; + cursor:pointer; + } + + .accordion-source .handle label::before { + font-family: fontawesome, sans-serif; + display: inline-block; + content: "\2964"; + margin-right: 10px; + font-size: .58em; + line-height: .556em; + vertical-align: middle; + } + + .accordion-source > input[type="checkbox"]:checked ~ .handle label::before { + content: "\2965"; + } + + .accordion-source p:last-child { + margin-bottom: 0; + } \ No newline at end of file diff --git a/demos/palm/python/docs-agent/chatbot/static/images/favicon.png b/demos/palm/python/docs-agent/docs_agent/interfaces/chatbot/static/images/favicon.png similarity index 100% rename from demos/palm/python/docs-agent/chatbot/static/images/favicon.png rename to demos/palm/python/docs-agent/docs_agent/interfaces/chatbot/static/images/favicon.png diff --git a/demos/palm/python/docs-agent/chatbot/static/javascript/app.js b/demos/palm/python/docs-agent/docs_agent/interfaces/chatbot/static/javascript/app.js similarity index 100% rename from demos/palm/python/docs-agent/chatbot/static/javascript/app.js rename to demos/palm/python/docs-agent/docs_agent/interfaces/chatbot/static/javascript/app.js diff --git a/demos/palm/python/docs-agent/chatbot/templates/chatui/base.html b/demos/palm/python/docs-agent/docs_agent/interfaces/chatbot/templates/chatui/base.html similarity index 94% rename from demos/palm/python/docs-agent/chatbot/templates/chatui/base.html rename to demos/palm/python/docs-agent/docs_agent/interfaces/chatbot/templates/chatui/base.html index 7fee30eb6..944984182 100644 --- a/demos/palm/python/docs-agent/chatbot/templates/chatui/base.html +++ b/demos/palm/python/docs-agent/docs_agent/interfaces/chatbot/templates/chatui/base.html @@ -2,7 +2,7 @@ - + {{ product }} ChatBot @@ -16,6 +16,8 @@ +
    +

    XIvQ`Jb``YrHdiN`s@7f7u0 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