├── .github ├── utils │ ├── requirements.txt │ └── validate_prompts.py └── workflows │ ├── docker-release.yml │ ├── ecs-deploy.yml │ ├── project.yml │ └── prompt-validation.yml ├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── api ├── api.go ├── errors.go └── prompt.go ├── go.mod ├── go.sum ├── index ├── index.go └── prompt.go ├── main.go ├── output └── output.go ├── prompthub.yaml.example └── prompts ├── deepset-conditioned-question-generation.md ├── deepset-conditioned-question-generation.yaml ├── deepset-conversational-agent-without-tools.md ├── deepset-conversational-agent-without-tools.yaml ├── deepset-conversational-agent.md ├── deepset-conversational-agent.yaml ├── deepset-conversational-summary.yaml ├── deepset-few-shot-hotpot-qa.md ├── deepset-few-shot-hotpot-qa.yaml ├── deepset-language-detection.md ├── deepset-language-detection.yaml ├── deepset-multiple-choice-question-answering.md ├── deepset-multiple-choice-question-answering.yaml ├── deepset-question-answering-check.md ├── deepset-question-answering-check.yaml ├── deepset-question-answering-per-document.md ├── deepset-question-answering-per-document.yaml ├── deepset-question-answering-with-document-scores.md ├── deepset-question-answering-with-document-scores.yaml ├── deepset-question-answering-with-references.md ├── deepset-question-answering-with-references.yaml ├── deepset-question-answering.md ├── deepset-question-answering.yaml ├── deepset-question-generation.md ├── deepset-question-generation.yaml ├── deepset-sentiment-analysis.md ├── deepset-sentiment-analysis.yaml ├── deepset-summarization-chain-of-density.md ├── deepset-summarization-chain-of-density.yaml ├── deepset-summarization.md ├── deepset-summarization.yaml ├── deepset-topic-classification.md ├── deepset-topic-classification.yaml ├── deepset-translation.md ├── deepset-translation.yaml ├── deepset-zero-shot-react.md └── deepset-zero-shot-react.yaml /.github/utils/requirements.txt: -------------------------------------------------------------------------------- 1 | PyYAML==6.0 -------------------------------------------------------------------------------- /.github/utils/validate_prompts.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | import yaml 4 | 5 | 6 | def is_valid(prompt_file: Path) -> bool: 7 | if not prompt_file.exists(): 8 | # We consider a non existing file to be valid 9 | return True 10 | 11 | try: 12 | data = yaml.safe_load(prompt_file.read_text()) 13 | except: 14 | # Parsing failure means either the file is not yaml or it's malformed 15 | print(f"Failed parsing file: {prompt_file}", file=sys.stderr) 16 | return False 17 | 18 | required_fields = { 19 | "name": str, 20 | "text": str, 21 | "description": str, 22 | "tags": list, 23 | "meta": dict, 24 | "version": str, 25 | } 26 | 27 | reports = [] 28 | for key, expected_type in required_fields.items(): 29 | if key not in data: 30 | reports.append(f"Required field {key} is missing") 31 | continue 32 | 33 | value = data[key] 34 | # Check the type of each field is the one we expect 35 | if type(value) is not expected_type: 36 | reports.append(f"Field {key} must be of type {expected_type}") 37 | continue 38 | 39 | # For list fields we have an extra check as we want to verify that they contain strings 40 | if expected_type is list and len(value) > 0 and type(value[0]) is not str: 41 | reports.append(f"Field {key} must be a list of strings") 42 | 43 | # Print a report if any field doesn't respect requirements 44 | if reports: 45 | print(f"File not valid: {prompt_file}", file=sys.stderr) 46 | for report in reports: 47 | print(f" - {report}", file=sys.stderr) 48 | 49 | # If there's any number of reports the file must not be valid 50 | return len(reports) == 0 51 | 52 | 53 | if __name__ == "__main__": 54 | import sys 55 | import argparse 56 | 57 | parser = argparse.ArgumentParser( 58 | description="Utility script to validate prompts", 59 | ) 60 | parser.add_argument("files", nargs="+") 61 | args = parser.parse_args() 62 | 63 | files = [Path(f) for f in args.files] 64 | 65 | print() 66 | any_not_valid = any([not is_valid(f) for f in files]) 67 | 68 | if any_not_valid: 69 | sys.exit(1) 70 | -------------------------------------------------------------------------------- /.github/workflows/docker-release.yml: -------------------------------------------------------------------------------- 1 | name: Publish Docker image 2 | 3 | on: 4 | push: 5 | tags: 6 | - "v[0-9].*[0-9]" 7 | 8 | env: 9 | DOCKER_IMAGE_TAG: ${{ github.ref_name }} 10 | 11 | jobs: 12 | push_to_registry: 13 | name: Push Docker image to Dockerhub 14 | runs-on: ubuntu-latest 15 | outputs: 16 | docker_image_tag: ${{ steps.echo.outputs.docker_image_tag }} 17 | steps: 18 | - name: Checkout 19 | uses: actions/checkout@v3 20 | 21 | - name: Login to DockerHub 22 | uses: docker/login-action@v2 23 | with: 24 | username: ${{ secrets.DOCKERHUB_USERNAME }} 25 | password: ${{ secrets.DOCKERHUB_TOKEN }} 26 | 27 | - name: Build and push 28 | uses: docker/build-push-action@v4 29 | with: 30 | push: true 31 | tags: deepset/prompthub:latest,deepset/prompthub:${{ env.DOCKER_IMAGE_TAG }} 32 | 33 | - name: Output Docker image tag 34 | id: echo 35 | # We can't use the env context when calling another workflow 36 | # so we output it here and pass it to the deploy job 37 | run: echo "docker_image_tag=${{ env.DOCKER_IMAGE_TAG }}" >> "$GITHUB_OUTPUT" 38 | 39 | deploy: 40 | needs: push_to_registry 41 | uses: ./.github/workflows/ecs-deploy.yml 42 | secrets: inherit 43 | with: 44 | docker-image: "deepset/prompthub:${{ needs.push_to_registry.outputs.docker_image_tag }}" 45 | -------------------------------------------------------------------------------- /.github/workflows/ecs-deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy to Amazon ECS 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | docker-image: 7 | required: true 8 | type: string 9 | 10 | jobs: 11 | deploy: 12 | name: Deploy 13 | runs-on: ubuntu-latest 14 | environment: production 15 | # These permissions are needed to interact with GitHub's OIDC Token endpoint. 16 | # If we remove these aws-actions/configure-aws-credentials won't assume the 17 | # specified role. 18 | permissions: 19 | id-token: write 20 | contents: read 21 | 22 | steps: 23 | - name: Checkout 24 | uses: actions/checkout@v3 25 | 26 | - name: Configure AWS credentials 27 | uses: aws-actions/configure-aws-credentials@v2 28 | with: 29 | role-to-assume: ${{ secrets.AWS_ROLE }} 30 | aws-region: ${{ secrets.AWS_REGION }} 31 | 32 | - name: Store task definition 33 | run: | 34 | cat >> task-definition.json<< EOF 35 | ${{ secrets.ECS_TASK_DEFINITION }} 36 | EOF 37 | 38 | - name: Fill in the new image ID in the Amazon ECS task definition 39 | id: task-def 40 | uses: aws-actions/amazon-ecs-render-task-definition@v1 41 | with: 42 | task-definition: task-definition.json 43 | container-name: ${{ secrets.ECS_CONTAINER_NAME }} 44 | image: ${{ inputs.docker-image }} 45 | 46 | - name: Deploy Amazon ECS task definition 47 | uses: aws-actions/amazon-ecs-deploy-task-definition@v1 48 | with: 49 | task-definition: ${{ steps.task-def.outputs.task-definition }} 50 | service: ${{ secrets.ECS_SERVICE }} 51 | cluster: ${{ secrets.ECS_CLUSTER }} 52 | wait-for-service-stability: true 53 | 54 | - name: Calculate alert data 55 | id: calculator 56 | shell: bash 57 | if: success() || failure() 58 | run: | 59 | if [ "${{ job.status }}" = "success" ]; then 60 | echo "alert_type=success" >> "$GITHUB_OUTPUT"; 61 | else 62 | echo "alert_type=error" >> "$GITHUB_OUTPUT"; 63 | fi 64 | 65 | - name: Send event to Datadog 66 | if: success() || failure() 67 | uses: masci/datadog@v1 68 | with: 69 | api-key: ${{ secrets.CORE_DATADOG_API_KEY }} 70 | api-url: https://api.datadoghq.eu 71 | events: | 72 | - title: "PromptHub deployment" 73 | text: "Job ${{ github.job }} for image ${{ inputs.docker-image }}" 74 | alert_type: "${{ steps.calculator.outputs.alert_type }}" 75 | source_type_name: "Github" 76 | host: ${{ github.repository_owner }} 77 | tags: 78 | - "project:${{ github.repository }}" 79 | - "job:${{ github.job }}" 80 | - "run_id:${{ github.run_id }}" 81 | - "workflow:${{ github.workflow }}" 82 | - "image:${{ inputs.docker-image }}" 83 | - "url:https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" 84 | -------------------------------------------------------------------------------- /.github/workflows/project.yml: -------------------------------------------------------------------------------- 1 | name: Track issues with Github project 2 | 3 | on: 4 | issues: 5 | types: 6 | - opened 7 | 8 | jobs: 9 | add-to-project: 10 | name: Add new issues to project for triage 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/add-to-project@v0.3.0 14 | with: 15 | project-url: https://github.com/orgs/deepset-ai/projects/5 16 | github-token: ${{ secrets.GH_PROJECT_PAT }} 17 | -------------------------------------------------------------------------------- /.github/workflows/prompt-validation.yml: -------------------------------------------------------------------------------- 1 | name: Verify prompt is valid 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - prompts/*.yml 7 | - prompts/*.yaml 8 | - prompts/*.md 9 | 10 | jobs: 11 | validate: 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v3 17 | 18 | - name: Get changed files 19 | id: files 20 | uses: tj-actions/changed-files@v34 21 | with: 22 | json_raw_format: true 23 | files: | 24 | prompts/*.{yaml,yml} 25 | 26 | - name: Setup Python 27 | uses: actions/setup-python@v4 28 | with: 29 | python-version: "3.11" 30 | 31 | - name: Install dependencies 32 | run: | 33 | pip install --upgrade pip 34 | pip install -r .github/utils/requirements.txt 35 | 36 | - name: Validate prompts 37 | if: steps.files.outputs.any_changed == 'true' 38 | run: | 39 | python .github/utils/validate_prompts.py ${{ steps.files.outputs.all_changed_files }} 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | prompthub 2 | prompthub.yaml 3 | 4 | .vscode 5 | __pycache__ -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.20-alpine AS build 2 | 3 | ENV CGO_ENABLED=0 4 | WORKDIR /go/src/github.com/deepset-ai/prompthub 5 | COPY . /go/src/github.com/deepset-ai/prompthub 6 | RUN go build 7 | 8 | 9 | FROM alpine:3.17 10 | 11 | COPY --from=build /go/src/github.com/deepset-ai/prompthub/prompthub /usr/bin/prompthub 12 | # In case you don't want to run the service wit default values, 13 | # put your configuration in the example file and uncomment the 14 | # following line: 15 | # COPY prompthub.yaml.example /prompthub.yaml 16 | COPY prompts ./prompts 17 | EXPOSE 80 18 | CMD ["prompthub", "-c /prompthub.yaml"] 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PromptHub 2 | 3 | PromptHub serves a collection of ready-made prompts for the most common NLP tasks. The service is deployed at the 4 | public URL https://api.prompthub.deepset.ai and there's a nice UI to browse the prompts at https://prompthub.deepset.ai. 5 | 6 | ## Prompt format 7 | 8 | A prompt is defined in a yaml file with the following format: 9 | 10 | ```yaml 11 | name: an-example 12 | text: Your prompt text goes here 13 | description: A brief description of what your prompt is for 14 | tags: 15 | - translation 16 | meta: 17 | authors: 18 | - your name 19 | version: v0.1 20 | ``` 21 | 22 | ## PromptHub API 23 | 24 | ### Get all the prompts 25 | 26 | `GET /prompts` 27 | 28 | Request: 29 | 30 | ```sh 31 | curl -i -H 'Accept: application/json' https://api.prompthub.deepset.ai/prompts 32 | ``` 33 | 34 | Response: 35 | 36 | ``` 37 | HTTP/1.1 200 OK 38 | Content-Type: application/json; charset=utf-8 39 | Date: Fri, 24 Mar 2023 07:59:55 GMT 40 | Content-Length: 42 41 | 42 | [ 43 | { 44 | "name":"deepset/an-example-prompt", 45 | "tags":["question-answering"], 46 | "meta":{"authors":["Alice","Bob"]}, 47 | "version":"1.0", 48 | "text":"My prompt text", 49 | "description":"Provides a prompt for question answering with references to documents" 50 | } 51 | ] 52 | ``` 53 | 54 | ### Get a specific prompt by name 55 | 56 | `GET /prompts/prompt-name` 57 | 58 | Request: 59 | 60 | ```sh 61 | curl -i -H 'Accept: application/json' https://api.prompthub.deepset.ai/prompts/prompt-name 62 | ``` 63 | 64 | Response: 65 | 66 | ``` 67 | HTTP/1.1 200 OK 68 | Content-Type: application/json; charset=utf-8 69 | Date: Fri, 24 Mar 2023 08:06:19 GMT 70 | Content-Length: 211 71 | 72 | {"name":"prompt-name","tags":["translation"],"meta":{"authors":["vblagoje"]},"version":"v0.1.0","text":"Your prompt text goes here","description":"Prompt to translate text into a target language"} 73 | ``` 74 | 75 | ### Get a model card by model name 76 | 77 | Request: 78 | 79 | ```sh 80 | curl -i https://api.prompthub.deepset.ai/cards/prompt-name 81 | ``` 82 | 83 | Response: 84 | 85 | ``` 86 | HTTP/1.1 200 OK 87 | Content-Type: text/plain; charset=utf-8 88 | Vary: Origin 89 | Date: Wed, 07 Jun 2023 10:46:53 GMT 90 | Content-Length: 762 91 | 92 | This prompt is simply designed to answer a `query` given a set of `documents`. There will be 1 answer generated. 93 | 94 | ... 95 | ``` 96 | 97 | ## API clients 98 | 99 | You can consume the PromptHub API natively from one of the supported languages: 100 | - Python: https://github.com/deepset-ai/prompthub-py 101 | - Typescript: https://github.com/deepset-ai/prompthub-ts 102 | 103 | ## Run the PromptHub API by yourself 104 | 105 | The easiest way to run the PromptHub API on your premises is to use the official Docker image: 106 | 107 | ```sh 108 | $ docker run -p80:80 deepset/prompthub 109 | INFO Prompthub running at 0.0.0.0:80 110 | ``` 111 | 112 | You can also serve your very own set of prompts by overriding the default `prompts` folder in the container: 113 | 114 | ```sh 115 | $ docker run -p80:80 --volume $PWD/path/to/your/prompts:/prompts deepset/prompthub 116 | INFO Prompthub running at 0.0.0.0:80 117 | ``` 118 | 119 | ## Development 120 | 121 | You can build and run the PromptHub API service locally following these steps: 122 | 123 | - Ensure you have a recent version of [Go](https://go.dev) installed: 124 | 125 | ```sh 126 | $ go version 127 | go version go1.20.2 darwin/arm64 128 | ``` 129 | 130 | If you get an error, follow the install instructions from the [official documentation](https://go.dev/doc/install) and 131 | try again. 132 | 133 | - From the root of the repo, build the binary with: 134 | 135 | ```sh 136 | $ go build 137 | ``` 138 | 139 | - Run the server with: 140 | 141 | ```sh 142 | $ ./prompthub 143 | ``` 144 | 145 | - Run the tests with: 146 | 147 | ```sh 148 | $ go test ./... 149 | ``` 150 | -------------------------------------------------------------------------------- /api/api.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "context" 5 | fmt "fmt" 6 | "net/http" 7 | "os" 8 | "os/signal" 9 | "time" 10 | 11 | "github.com/deepset-ai/prompthub/index" 12 | "github.com/deepset-ai/prompthub/output" 13 | "github.com/go-chi/chi/v5" 14 | "github.com/go-chi/cors" 15 | "github.com/go-chi/render" 16 | "github.com/spf13/viper" 17 | ) 18 | 19 | // Serve starts the HTTP server and blocks 20 | func Serve() { 21 | r := chi.NewRouter() // root router 22 | r.Use(render.SetContentType(render.ContentTypeJSON)) 23 | r.Use(cors.Handler(cors.Options{ 24 | AllowedOrigins: viper.GetStringSlice("allowed_origins"), 25 | })) 26 | output.DEBUG.Printf("AllowedOrigins set to: %s", viper.GetStringSlice("allowed_origins")) 27 | 28 | promptsRouter := chi.NewRouter() 29 | promptsRouter.Get("/", ListPrompts) 30 | promptsRouter.Get("/*", GetPrompt) 31 | 32 | r.Mount("/prompts", promptsRouter) 33 | 34 | promptCardRouter := chi.NewRouter() 35 | promptCardRouter.Get("/*", GetCard) 36 | 37 | r.Mount("/cards", promptCardRouter) 38 | 39 | // Start the HTTP server 40 | srv := &http.Server{ 41 | Addr: fmt.Sprintf("0.0.0.0:%s", viper.GetString("port")), 42 | // Set timeouts to avoid Slowloris attacks. 43 | WriteTimeout: time.Second * 15, 44 | ReadTimeout: time.Second * 15, 45 | IdleTimeout: time.Second * 60, 46 | Handler: r, 47 | } 48 | 49 | // Run our server in a goroutine so that it doesn't block. 50 | go func() { 51 | if err := srv.ListenAndServe(); err != nil { 52 | output.FATAL.Println(err) 53 | } 54 | }() 55 | 56 | output.INFO.Println("Prompthub running at", srv.Addr) 57 | 58 | c := make(chan os.Signal, 1) 59 | // We'll accept graceful shutdowns when quit via SIGINT (Ctrl+C) 60 | // SIGKILL, SIGQUIT or SIGTERM (Ctrl+/) will not be caught. 61 | signal.Notify(c, os.Interrupt) 62 | 63 | // Block until we receive our signal. 64 | <-c 65 | 66 | // Create a deadline to wait for. 67 | ctx, cancel := context.WithTimeout(context.Background(), 10) 68 | defer cancel() 69 | // Doesn't block if no connections, but will otherwise wait 70 | // until the timeout deadline. 71 | srv.Shutdown(ctx) 72 | output.INFO.Println("shutting down") 73 | } 74 | 75 | func ListPrompts(w http.ResponseWriter, r *http.Request) { 76 | prompts := index.GetPrompts() 77 | if err := render.RenderList(w, r, NewPromptListResponse(prompts)); err != nil { 78 | render.Render(w, r, ErrRender(err)) 79 | return 80 | } 81 | } 82 | 83 | func NewPromptListResponse(prompts []*index.Prompt) []render.Renderer { 84 | list := []render.Renderer{} 85 | for _, prompt := range prompts { 86 | list = append(list, NewPromptResponse(prompt)) 87 | } 88 | return list 89 | } 90 | 91 | func GetPrompt(w http.ResponseWriter, r *http.Request) { 92 | promptName := chi.URLParam(r, "*") 93 | prompt, err := index.GetPrompt(promptName) 94 | if err != nil { 95 | render.Render(w, r, ErrNotFound) 96 | return 97 | } 98 | 99 | if err := render.Render(w, r, NewPromptResponse(prompt)); err != nil { 100 | render.Render(w, r, ErrRender(err)) 101 | return 102 | } 103 | } 104 | 105 | func GetCard(w http.ResponseWriter, r *http.Request) { 106 | promptName := chi.URLParam(r, "*") 107 | card, err := index.GetCard(promptName) 108 | if err != nil { 109 | render.Render(w, r, ErrNotFound) 110 | return 111 | } 112 | render.PlainText(w, r, card) 113 | } 114 | -------------------------------------------------------------------------------- /api/errors.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/go-chi/render" 7 | ) 8 | 9 | //-- 10 | // Error response payloads & renderers 11 | //-- 12 | 13 | // ErrResponse renderer type for handling all sorts of errors. 14 | // 15 | // In the best case scenario, the excellent github.com/pkg/errors package 16 | // helps reveal information on the error, setting it on Err, and in the Render() 17 | // method, using it to set the application-specific error code in AppCode. 18 | type ErrResponse struct { 19 | Err error `json:"-"` // low-level runtime error 20 | HTTPStatusCode int `json:"-"` // http response status code 21 | 22 | StatusText string `json:"status"` // user-level status message 23 | AppCode int64 `json:"code,omitempty"` // application-specific error code 24 | ErrorText string `json:"error,omitempty"` // application-level error message, for debugging 25 | } 26 | 27 | func (e *ErrResponse) Render(w http.ResponseWriter, r *http.Request) error { 28 | render.Status(r, e.HTTPStatusCode) 29 | return nil 30 | } 31 | 32 | func ErrInvalidRequest(err error) render.Renderer { 33 | return &ErrResponse{ 34 | Err: err, 35 | HTTPStatusCode: 400, 36 | StatusText: "Invalid request.", 37 | ErrorText: err.Error(), 38 | } 39 | } 40 | 41 | func ErrRender(err error) render.Renderer { 42 | return &ErrResponse{ 43 | Err: err, 44 | HTTPStatusCode: 422, 45 | StatusText: "Error rendering response.", 46 | ErrorText: err.Error(), 47 | } 48 | } 49 | 50 | var ErrNotFound = &ErrResponse{HTTPStatusCode: 404, StatusText: "Resource not found."} 51 | -------------------------------------------------------------------------------- /api/prompt.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/deepset-ai/prompthub/index" 7 | ) 8 | 9 | // PromptResponse is the response payload for the Prompt data model. 10 | type PromptResponse struct { 11 | *index.Prompt 12 | } 13 | 14 | func (rd *PromptResponse) Render(w http.ResponseWriter, r *http.Request) error { 15 | // Pre-processing before a response is marshalled and sent across the wire 16 | return nil 17 | } 18 | 19 | func NewPromptResponse(prompt *index.Prompt) *PromptResponse { 20 | resp := &PromptResponse{Prompt: prompt} 21 | 22 | return resp 23 | } 24 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/deepset-ai/prompthub 2 | 3 | go 1.20 4 | 5 | require ( 6 | github.com/go-chi/chi/v5 v5.0.8 7 | github.com/go-chi/cors v1.2.1 8 | github.com/go-chi/render v1.0.2 9 | github.com/spf13/jwalterweatherman v1.1.0 10 | github.com/spf13/pflag v1.0.5 11 | github.com/spf13/viper v1.15.0 12 | gopkg.in/yaml.v3 v3.0.1 13 | ) 14 | 15 | require ( 16 | github.com/ajg/form v1.5.1 // indirect 17 | github.com/fsnotify/fsnotify v1.6.0 // indirect 18 | github.com/hashicorp/hcl v1.0.0 // indirect 19 | github.com/magiconair/properties v1.8.7 // indirect 20 | github.com/mitchellh/mapstructure v1.5.0 // indirect 21 | github.com/pelletier/go-toml/v2 v2.0.6 // indirect 22 | github.com/spf13/afero v1.9.3 // indirect 23 | github.com/spf13/cast v1.5.0 // indirect 24 | github.com/subosito/gotenv v1.4.2 // indirect 25 | golang.org/x/sys v0.3.0 // indirect 26 | golang.org/x/text v0.5.0 // indirect 27 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect 28 | gopkg.in/ini.v1 v1.67.0 // indirect 29 | ) 30 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 3 | cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= 4 | cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= 5 | cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= 6 | cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= 7 | cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= 8 | cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= 9 | cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= 10 | cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= 11 | cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= 12 | cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= 13 | cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= 14 | cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= 15 | cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= 16 | cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= 17 | cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= 18 | cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= 19 | cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= 20 | cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= 21 | cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= 22 | cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= 23 | cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= 24 | cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= 25 | cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= 26 | cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= 27 | cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= 28 | cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= 29 | cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= 30 | cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= 31 | cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= 32 | cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= 33 | cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= 34 | cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= 35 | cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= 36 | cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= 37 | cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= 38 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= 39 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 40 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 41 | github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= 42 | github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= 43 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 44 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 45 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= 46 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 47 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 48 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 49 | github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 50 | github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 51 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 52 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 53 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 54 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 55 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 56 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= 57 | github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= 58 | github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= 59 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 60 | github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= 61 | github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= 62 | github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= 63 | github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0= 64 | github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= 65 | github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4= 66 | github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= 67 | github.com/go-chi/render v1.0.2 h1:4ER/udB0+fMWB2Jlf15RV3F4A2FDuYi/9f+lFttR/Lg= 68 | github.com/go-chi/render v1.0.2/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0= 69 | github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= 70 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 71 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 72 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 73 | github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 74 | github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 75 | github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 76 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 77 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 78 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= 79 | github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 80 | github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 81 | github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 82 | github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= 83 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 84 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 85 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 86 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 87 | github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 88 | github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= 89 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 90 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 91 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 92 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 93 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 94 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 95 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 96 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 97 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 98 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 99 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 100 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 101 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 102 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 103 | github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 104 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 105 | github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 106 | github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 107 | github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 108 | github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= 109 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 110 | github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= 111 | github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= 112 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 113 | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 114 | github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 115 | github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 116 | github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 117 | github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 118 | github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 119 | github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 120 | github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 121 | github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 122 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 123 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 124 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 125 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= 126 | github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= 127 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 128 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 129 | github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= 130 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= 131 | github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 132 | github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 133 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 134 | github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= 135 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 136 | github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= 137 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 138 | github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= 139 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 140 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 141 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 142 | github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= 143 | github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= 144 | github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= 145 | github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= 146 | github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= 147 | github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= 148 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 149 | github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= 150 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 151 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 152 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 153 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 154 | github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= 155 | github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk= 156 | github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= 157 | github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= 158 | github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= 159 | github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= 160 | github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= 161 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 162 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 163 | github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU= 164 | github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA= 165 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 166 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 167 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 168 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 169 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 170 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 171 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 172 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 173 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 174 | github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= 175 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 176 | github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= 177 | github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= 178 | github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 179 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 180 | github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 181 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 182 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= 183 | go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= 184 | go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 185 | go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 186 | go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 187 | go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= 188 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 189 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 190 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 191 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 192 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 193 | golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= 194 | golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 195 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 196 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 197 | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 198 | golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= 199 | golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= 200 | golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 201 | golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 202 | golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 203 | golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= 204 | golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= 205 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 206 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 207 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 208 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 209 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 210 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 211 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 212 | golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 213 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 214 | golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= 215 | golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 216 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 217 | golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 218 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 219 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= 220 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 221 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= 222 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 223 | golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 224 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 225 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 226 | golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 227 | golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 228 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 229 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 230 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 231 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 232 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 233 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 234 | golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 235 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 236 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 237 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 238 | golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 239 | golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 240 | golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 241 | golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 242 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 243 | golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 244 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 245 | golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 246 | golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 247 | golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 248 | golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 249 | golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 250 | golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 251 | golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 252 | golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 253 | golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 254 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 255 | golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 256 | golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 257 | golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 258 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 259 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 260 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 261 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 262 | golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 263 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 264 | golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 265 | golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 266 | golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 267 | golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 268 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 269 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 270 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 271 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 272 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 273 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 274 | golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 275 | golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 276 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 277 | golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 278 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 279 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 280 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 281 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 282 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 283 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 284 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 285 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 286 | golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 287 | golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 288 | golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 289 | golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 290 | golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 291 | golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 292 | golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 293 | golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 294 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 295 | golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 296 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 297 | golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 298 | golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 299 | golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 300 | golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 301 | golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 302 | golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 303 | golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 304 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 305 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 306 | golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 307 | golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 308 | golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 309 | golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 310 | golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 311 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 312 | golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 313 | golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= 314 | golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 315 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 316 | golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 317 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 318 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 319 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 320 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 321 | golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 322 | golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= 323 | golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 324 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 325 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 326 | golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 327 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 328 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 329 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 330 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 331 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 332 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 333 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 334 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 335 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 336 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 337 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 338 | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 339 | golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 340 | golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 341 | golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 342 | golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 343 | golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 344 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 345 | golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 346 | golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 347 | golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 348 | golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 349 | golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 350 | golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 351 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 352 | golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 353 | golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 354 | golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 355 | golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 356 | golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 357 | golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 358 | golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 359 | golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= 360 | golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 361 | golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 362 | golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 363 | golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 364 | golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 365 | golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 366 | golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 367 | golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= 368 | golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 369 | golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 370 | golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 371 | golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 372 | golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 373 | golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= 374 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 375 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 376 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 377 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 378 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= 379 | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= 380 | google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 381 | google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 382 | google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 383 | google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 384 | google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 385 | google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 386 | google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 387 | google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 388 | google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 389 | google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 390 | google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 391 | google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 392 | google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= 393 | google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= 394 | google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= 395 | google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= 396 | google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= 397 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 398 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 399 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 400 | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= 401 | google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 402 | google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 403 | google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 404 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 405 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 406 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 407 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 408 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 409 | google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 410 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 411 | google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= 412 | google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 413 | google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 414 | google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 415 | google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 416 | google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 417 | google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 418 | google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= 419 | google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 420 | google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 421 | google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 422 | google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 423 | google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 424 | google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 425 | google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 426 | google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 427 | google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= 428 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 429 | google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= 430 | google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 431 | google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 432 | google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 433 | google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 434 | google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 435 | google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 436 | google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 437 | google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 438 | google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 439 | google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 440 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 441 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 442 | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 443 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 444 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 445 | google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 446 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 447 | google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 448 | google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= 449 | google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= 450 | google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 451 | google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 452 | google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 453 | google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= 454 | google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= 455 | google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= 456 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 457 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 458 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 459 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 460 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 461 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 462 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 463 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 464 | google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= 465 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 466 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 467 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 468 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= 469 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 470 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 471 | gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= 472 | gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 473 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 474 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 475 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 476 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 477 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 478 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 479 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 480 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 481 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 482 | honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 483 | honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 484 | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= 485 | rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= 486 | rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= 487 | -------------------------------------------------------------------------------- /index/index.go: -------------------------------------------------------------------------------- 1 | package index 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "log" 7 | "os" 8 | "path/filepath" 9 | "strings" 10 | 11 | "gopkg.in/yaml.v3" 12 | ) 13 | 14 | type PromptIndex map[string]*Prompt 15 | 16 | var prompts PromptIndex 17 | var cards map[string]string 18 | 19 | func GetPrompt(name string) (*Prompt, error) { 20 | val, ok := prompts[name] 21 | if ok { 22 | return val, nil 23 | } 24 | return nil, errors.New("not found") 25 | } 26 | 27 | func GetPrompts() []*Prompt { 28 | v := make([]*Prompt, 0, len(prompts)) 29 | 30 | for _, value := range prompts { 31 | v = append(v, value) 32 | } 33 | 34 | return v 35 | } 36 | 37 | func GetCard(name string) (string, error) { 38 | val, ok := cards[name] 39 | if ok { 40 | return val, nil 41 | } 42 | return "", errors.New("not found") 43 | } 44 | 45 | func Init(path string) error { 46 | 47 | files, err := os.ReadDir(path) 48 | if err != nil { 49 | return err 50 | } 51 | 52 | prompts = PromptIndex{} 53 | cards = map[string]string{} 54 | 55 | for _, file := range files { 56 | // yaml files only 57 | ext := strings.ToLower(filepath.Ext(file.Name())) 58 | if ext != ".yaml" && ext != ".yml" { 59 | continue 60 | } 61 | 62 | var p Prompt 63 | yamlFile, err := os.ReadFile(filepath.Join(path, file.Name())) 64 | if err != nil { 65 | log.Printf("Readfile error: %v", err) 66 | } 67 | err = yaml.Unmarshal(yamlFile, &p) 68 | if err != nil { 69 | log.Fatalf("Unmarshal %s: %v", file.Name(), err) 70 | } 71 | 72 | prompts[p.Name] = &p 73 | 74 | // If the prompt has a related markdown with more detailed explanation 75 | // add it to a separate index. Note we use the prompt file name 76 | // as the name of the card, not the actual name of the prompt. 77 | cardName := strings.TrimSuffix(file.Name(), filepath.Ext(file.Name())) 78 | cardFile := filepath.Join(path, fmt.Sprintf("%s.md", cardName)) 79 | if _, err := os.Stat(cardFile); errors.Is(err, os.ErrNotExist) { 80 | log.Printf("Card not found for prompt %s", p.Name) 81 | continue 82 | } 83 | cardData, err := os.ReadFile(cardFile) 84 | if err != nil { 85 | log.Printf("Readfile error: %v", err) 86 | } 87 | cards[p.Name] = string(cardData) 88 | } 89 | 90 | return nil 91 | } 92 | -------------------------------------------------------------------------------- /index/prompt.go: -------------------------------------------------------------------------------- 1 | package index 2 | 3 | // Prompt data model. 4 | type Prompt struct { 5 | Name string `json:"name"` 6 | Tags []string `json:"tags,omitempty"` 7 | Meta map[string]interface{} `json:"meta,omitempty"` 8 | Version string `json:"version"` 9 | Text string `json:"text"` 10 | Description string `json:"description"` 11 | } 12 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/deepset-ai/prompthub/api" 7 | "github.com/deepset-ai/prompthub/index" 8 | "github.com/deepset-ai/prompthub/output" 9 | "github.com/spf13/pflag" 10 | "github.com/spf13/viper" 11 | ) 12 | 13 | func main() { 14 | // Define and parse command args 15 | verbosity := pflag.IntP("verbose", "v", 1, "set verbosity level: 0 silent, 1 normal, 2 debug") 16 | configPath := pflag.StringP("config", "c", "", "path to config file") 17 | help := pflag.BoolP("help", "h", false, "print args help") 18 | pflag.Parse() 19 | 20 | // Print the help message and exit if --help is passed 21 | if *help { 22 | pflag.PrintDefaults() 23 | os.Exit(0) 24 | } 25 | 26 | // Configure cmdline output facilities 27 | output.Init(*verbosity) 28 | 29 | // Bootstrap config, this has to be called first 30 | initConfig(configPath) 31 | 32 | // Initialize the index by reading all the prompts from file 33 | if err := index.Init(viper.GetString("prompts_path")); err != nil { 34 | os.Exit(1) 35 | } 36 | 37 | // Start the HTTP server, block until shutdown 38 | api.Serve() 39 | os.Exit(0) 40 | } 41 | 42 | func initConfig(configPath *string) { 43 | // Defaults 44 | viper.SetDefault("port", "80") 45 | viper.SetDefault("prompts_path", "./prompts") 46 | viper.SetDefault("allowed_origins", []string{"https://prompthub.deepset.ai"}) 47 | 48 | // Automatically bind all the config options to env vars 49 | viper.SetEnvPrefix("prompthub") 50 | viper.AutomaticEnv() 51 | 52 | // Setup the config lookup 53 | viper.SetConfigName("prompthub.yaml") 54 | viper.SetConfigType("yaml") 55 | viper.AddConfigPath(".") 56 | if *configPath != "" { 57 | viper.AddConfigPath(*configPath) 58 | } 59 | err := viper.ReadInConfig() 60 | if err != nil { 61 | output.INFO.Println("Configuration file not found, running with default parameters") 62 | } else { 63 | output.DEBUG.Println("Config file found at", viper.ConfigFileUsed()) 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /output/output.go: -------------------------------------------------------------------------------- 1 | package output 2 | 3 | import ( 4 | "io/ioutil" 5 | "log" 6 | "os" 7 | 8 | jww "github.com/spf13/jwalterweatherman" 9 | ) 10 | 11 | var ( 12 | DEBUG *log.Logger 13 | INFO *log.Logger 14 | ERROR *log.Logger 15 | FATAL *log.Logger 16 | 17 | np *jww.Notepad 18 | ) 19 | 20 | const DefaultVerbosity = jww.LevelInfo 21 | 22 | func Init(verbosity int) { 23 | threshold := DefaultVerbosity 24 | if verbosity == 0 { 25 | threshold = jww.LevelFatal 26 | } else if verbosity == 1 { 27 | threshold = jww.LevelInfo 28 | } else if verbosity == 2 { 29 | threshold = jww.LevelDebug 30 | } 31 | 32 | np = jww.NewNotepad(threshold, threshold, os.Stdout, ioutil.Discard, "", 0) 33 | DEBUG = np.DEBUG 34 | INFO = np.INFO 35 | ERROR = np.ERROR 36 | FATAL = np.FATAL 37 | } 38 | -------------------------------------------------------------------------------- /prompthub.yaml.example: -------------------------------------------------------------------------------- 1 | port: 80 2 | prompts_path: ./prompts 3 | allowed_origins: 4 | - http://localhost:5173 -------------------------------------------------------------------------------- /prompts/deepset-conditioned-question-generation.md: -------------------------------------------------------------------------------- 1 | This prompt aims to generate a question, given `documents` and an `answers`. 2 | 3 | ## How to use in Haystack 4 | 5 | ```python 6 | from haystack.nodes import PromptNode, PromptTemplate 7 | 8 | documents = [MY_DOCUMENTS] 9 | answers = [MY_ANSWERS] 10 | 11 | conditioned_question_generation_from_hub = PromptTemplate("deepset/conditioned-question-generation") 12 | 13 | prompt_node = PromptNode(model_name_or_path="text-davinci-003", api_key='YOUR_API_KEY') 14 | 15 | prompt_node.prompt(prompt_template=conditioned_question_generation_from_hub, documents=documents, answers=answers) 16 | ``` 17 | 18 | ### Example 19 | 20 | With the following news snippets as documents and answers: 21 | 22 | ```python 23 | from haystack.schema import Document 24 | 25 | # https://www.theguardian.com/business/2023/feb/12/inflation-may-have-peaked-but-the-cost-of-living-pain-is-far-from-over 26 | news_economics = Document( 27 | """At long last, Britain’s annual inflation rate is on the way down. After hitting the highest level since the 1980s, heaping pressure on millions of households as living costs soared, official figures this week could bring some rare good news. 28 | City economists expect UK inflation to have cooled for a third month running in January – the exact number is announced on Wednesday – helped by falling petrol prices and a broader decline in the global price of oil and gas in recent months. The hope now is for a sustained decline in the months ahead, continuing a steady drop from the peak of 11.1% seen in October. 29 | The message from the Bank of England has been clear. Inflation is on track for a “rapid” decline over the coming months, raising hopes that the worst of Britain’s cost of living crisis is now in the rearview mirror. 30 | There are two good reasons for this. Energy costs are moving in the right direction, while the initial rise in wholesale oil and gas prices that followed Russia’s invasion of Ukraine in February last year will soon drop from the calculation of the annual inflation rate.""" 31 | ) 32 | 33 | # https://www.theguardian.com/science/2023/feb/13/starwatch-orions-belt-and-sirius-lead-way-to-hydras-head 34 | news_science = Document( 35 | """On northern winter nights, it is so easy to be beguiled by the gloriously bright constellations of Orion, the hunter, and Taurus, the bull, that one can overlook the fainter constellations. 36 | So this week, find the three stars of Orion’s belt, follow them down to Sirius, the brightest star in the night sky, and then look eastward until you find the faint ring of stars that makes up the head of Hydra, the water snake. The chart shows the view looking south-east from London at 8pm GMT on Monday, but the view will be similar every night this week. 37 | Hydra is the largest of the 88 modern constellations covering an area of 1,303 square degrees. To compare, nearby Orion only covers 594 square degrees. Hydra accounts for most of its area by its length, crossing more than 100 degrees of the sky (the full moon spans half a degree). 38 | As evening becomes night and into the early hours, the rotation of Earth causes Hydra to slither its way across the southern meridian until dawn washes it from the sky. From the southern hemisphere, the constellation is easily visible in the eastern sky by mid-evening.""" 39 | ) 40 | 41 | # https://www.theguardian.com/music/2023/jan/30/salisbury-cathedral-pipe-organ-new-life-holst-the-planets 42 | news_culture = Document( 43 | """A unique performance of Gustav Holst’s masterwork The Planets – played on a magnificent pipe organ rather than by an orchestra and punctuated by poems inspired by children’s responses to the music – is to be staged in the suitably vast Salisbury Cathedral. 44 | The idea of the community music project is to introduce more people, young and old, to the 140-year-old “Father” Willis organ, one of the treasures of the cathedral. 45 | It is also intended to get the children who took part and the adults who will watch and listen thinking afresh about the themes Holst’s suite tackles – war, peace, joy and mysticism – which seem as relevant now as when he wrote the work a century ago. 46 | John Challenger, the cathedral’s principal organist, said: “We have a fantastic pipe organ largely as it was when built. It’s a thrilling thing. I view it as my purpose in life to share it with as many people as possible.” 47 | The Planets is written for a large orchestra. “Holst calls for huge instrumental forces and an unseen distant choir of sopranos and altos,” said Challenger. But he has transposed the suite for the organ, not copying the effect of the orchestral instruments but finding a new version of the suite.""" 48 | ) 49 | 50 | # https://www.theguardian.com/sport/blog/2023/feb/14/multi-million-dollar-wpl-auction-signals-huge-step-forward-for-womens-sport 51 | news_sport = Document( 52 | """It was only a few days ago that members of the Australian women’s cricket team were contemplating how best to navigate the impending “distraction” of the inaugural Women’s Premier League auction, scheduled during the first week of the T20 World Cup. “It’s a little bit awkward,” captain Meg Lanning said in South Africa last week. “But it’s just trying to embrace that and understanding it’s actually a really exciting time and you actually don’t have a lot of control over most of it, so you’ve just got to wait and see.” 53 | What a pleasant distraction it turned out to be. Lanning herself will be $192,000 richer for three weeks’ work with the Delhi Capitals. Her teammate, Ash Gardner, will earn three times that playing for the Gujarat Giants. The allrounder’s figure of $558,000 is more than Sam Kerr pockets in a season with Chelsea and more than the WNBA’s top earner, Jackie Young. 54 | If that sounds like a watershed moment, it’s perhaps because it is. And it is not the only one this past week. The NRLW made its own wage-related headlines on Tuesday, to the effect that the next (agreed in principle) collective bargaining agreement will bring with it a $1.5m salary cap in 2027, at an average salary of $62,500. Women’s rugby, too, is making moves, with news on the weekend that Rugby Australia will begin contracting the Wallaroos.""" 55 | ) 56 | 57 | news = [news_economics, news_science, news_culture, news_sport] 58 | answers = ["1980s", "Orion", "The Planets", "the first week of the T20 World Cup"] 59 | ``` 60 | 61 | ```python 62 | prompt_node.prompt(prompt_template="deepset/conditioned-question-generation", documents=news, answers=answers) 63 | ``` 64 | 65 | ``` 66 | ['What was the last time UK inflation rate hit the highest level?', 67 | 'What constellation is easy to spot in the eastern sky by mid-evening in the southern hemisphere?', 68 | "How has John Challenger transposed Gustav Holst's suite for the pipe organ?", 69 | "What event was Meg Lanning referring to as a possible distraction for the Australian women's cricket team?"] 70 | ``` -------------------------------------------------------------------------------- /prompts/deepset-conditioned-question-generation.yaml: -------------------------------------------------------------------------------- 1 | name: deepset/conditioned-question-generation 2 | text: | 3 | Please come up with a question for the given context and the answer. 4 | Context: {documents}; 5 | Answer: {answers}; 6 | Question: 7 | description: Generate a question given the context and the answer. 8 | tags: 9 | - question-generation 10 | meta: 11 | authors: 12 | - deepset-ai 13 | version: '0.0.1' -------------------------------------------------------------------------------- /prompts/deepset-conversational-agent-without-tools.md: -------------------------------------------------------------------------------- 1 | This prompt is intended to be used with a Haystack `Agent`, specifically, a [`ConversationalAgent`](https://docs.haystack.deepset.ai/docs/agent#conversational-agent). 2 | 3 | To learn how to use this prompt and the `ConversationalAgent`, check out our [Building a Conversational Chat App Tutorial](https://haystack.deepset.ai/tutorials/24_building_chat_app). 4 | 5 | By default, the `ConversationalAgent` without any tools would use this prompt. If you want more flexibility, below is an example of how you might use this prompt with the `Agent`. 6 | 7 | ## How to use in Haystack 8 | 9 | ```python 10 | import os 11 | 12 | from haystack.nodes import PromptNode 13 | from haystack.agents.utils import agent_without_tools_parameter_resolver 14 | from haystack.agents.memory import ConversationMemory 15 | from haystack.agents import Agent 16 | 17 | prompt_node = PromptNode("gpt-3.5-turbo", api_key=os.environ.get("OPENAI_API_KEY"), max_length=256) 18 | memory = ConversationMemory() 19 | 20 | conversational_agent_without_tools = Agent( 21 | prompt_node=prompt_node, 22 | memory=memory, 23 | prompt_template="deepset/conversational-agent-without-tools", 24 | prompt_parameters_resolver=agent_without_tools_parameter_resolver, 25 | final_answer_pattern=r"^([\s\S]+)$", 26 | ) 27 | ``` -------------------------------------------------------------------------------- /prompts/deepset-conversational-agent-without-tools.yaml: -------------------------------------------------------------------------------- 1 | name: deepset/conversational-agent-without-tools 2 | text: | 3 | The following is a conversation between a human and an AI.\n{memory}\nHuman: {query}\nAI: 4 | description: A simple chat agent without tools that holds the history of the conversation. 5 | tags: 6 | - agent 7 | - conversational 8 | meta: 9 | authors: 10 | - deepset-ai 11 | version: '0.1.0' -------------------------------------------------------------------------------- /prompts/deepset-conversational-agent.md: -------------------------------------------------------------------------------- 1 | This prompt is intended to be used with a Haystack `Agent`, specifically, a [`ConversationalAgent`](https://docs.haystack.deepset.ai/docs/agent#conversational-agent). 2 | 3 | To learn how to use this prompt and the `ConversationalAgent`, check out our [Building a Conversational Chat App Tutorial](https://haystack.deepset.ai/tutorials/24_building_chat_app). 4 | 5 | By default, the `ConversationalAgent` would use this prompt when it's initialized with tools. If you want more flexibility, below is an example of how you might use this prompt with the `Agent`. 6 | 7 | ## How to use in Haystack 8 | 9 | ```python 10 | import os 11 | 12 | from haystack.nodes import PromptNode 13 | from haystack.agents.utils import conversational_agent_parameter_resolver 14 | from haystack.agents.memory import ConversationMemory 15 | from haystack.agents import Agent 16 | from haystack.agents.base import ToolsManager 17 | 18 | prompt_node = PromptNode( 19 | "gpt-3.5-turbo", api_key=os.environ.get("OPENAI_API_KEY"), max_length=256, stop_words=["Observation:"] 20 | ) 21 | memory = ConversationMemory() 22 | 23 | conversational_agent = Agent( 24 | prompt_node=prompt_node, 25 | memory=memory, 26 | prompt_template="deepset/conversational-agent", 27 | prompt_parameters_resolver=conversational_agent_parameter_resolver, 28 | tools_manager=ToolsManager(tools=[YOUR_TOOL]), 29 | ) 30 | ``` -------------------------------------------------------------------------------- /prompts/deepset-conversational-agent.yaml: -------------------------------------------------------------------------------- 1 | name: deepset/conversational-agent 2 | text: | 3 | In the following conversation, a human user interacts with an AI Agent. The human user poses questions, and the AI Agent goes through several steps to provide well-informed answers. 4 | If the AI Agent knows the answer, the response begins with "Final Answer:" on a new line. 5 | If the AI Agent is uncertain or concerned that the information may be outdated or inaccurate, it must use the available tools to find the most up-to-date information. The AI has access to these tools: 6 | {tool_names_with_descriptions} 7 | 8 | The following is the previous conversation between a human and an AI: 9 | {memory} 10 | 11 | AI Agent responses must start with one of the following: 12 | 13 | Thought: [AI Agent's reasoning process] 14 | Tool: {tool_names} (on a new line) Tool Input: [input for the selected tool WITHOUT quotation marks and on a new line] (These must always be provided together and on separate lines.) 15 | Final Answer: [final answer to the human user's question] 16 | When selecting a tool, the AI Agent must provide both the "Tool:" and "Tool Input:" pair in the same response, but on separate lines. "Observation:" marks the beginning of a tool's result, and the AI Agent trusts these results. 17 | 18 | The AI Agent should not ask the human user for additional information, clarification, or context. 19 | If the AI Agent cannot find a specific answer after exhausting available tools and approaches, it answers with Final Answer: inconclusive 20 | 21 | Question: {query} 22 | Thought: 23 | {transcript} 24 | description: Agent that holds the history of the conversation. Follows ReAct style 'Thought, Tool and Observation' steps but in a conversational agent setting. 25 | tags: 26 | - agent 27 | - conversational 28 | meta: 29 | authors: 30 | - deepset-ai 31 | version: '0.1.0' -------------------------------------------------------------------------------- /prompts/deepset-conversational-summary.yaml: -------------------------------------------------------------------------------- 1 | name: deepset/conversational-summary 2 | text: | 3 | Condense the following chat transcript by shortening and summarizing the content 4 | without losing important information:\n{chat_transcript}\nCondensed Transcript: 5 | description: Summarize chat history. 6 | tags: 7 | - agent 8 | - conversational 9 | - summarization 10 | meta: 11 | authors: 12 | - deepset-ai 13 | version: '0.1.0' -------------------------------------------------------------------------------- /prompts/deepset-few-shot-hotpot-qa.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deepset-ai/prompthub/51ef3e9a217c469c1e68d63ccc7c41a8b5ca5dd1/prompts/deepset-few-shot-hotpot-qa.md -------------------------------------------------------------------------------- /prompts/deepset-few-shot-hotpot-qa.yaml: -------------------------------------------------------------------------------- 1 | name: deepset/few-shot-hotpot-qa 2 | text: | 3 | You are a helpful and knowledgeable agent. To achieve your goal of answering complex questions correctly, you have access to the following tools: 4 | Search: useful for when you need to Google questions. You should ask targeted questions, for example, Who is Anthony Dirrell's brother? 5 | To answer questions, you'll need to go through multiple steps involving step-by-step thinking and selecting appropriate tools and their inputs; tools will respond with observations. When you are ready for a final answer, respond with the `Final Answer:` 6 | Examples: 7 | ## 8 | Question: Anthony Dirrell is the brother of which super middleweight title holder? 9 | Thought: Let's think step by step. To answer this question, we first need to know who Anthony Dirrell is. 10 | Tool: Search 11 | Tool Input: Who is Anthony Dirrell? 12 | Observation: Boxer 13 | Thought: We've learned Anthony Dirrell is a Boxer. Now, we need to find out who his brother is. 14 | Tool: Search 15 | Tool Input: Who is Anthony Dirrell brother? 16 | Observation: Andre Dirrell 17 | Thought: We've learned Andre Dirrell is Anthony Dirrell's brother. Now, we need to find out what title Andre Dirrell holds. 18 | Tool: Search 19 | Tool Input: What is the Andre Dirrell title? 20 | Observation: super middleweight 21 | Thought: We've learned Andre Dirrell title is super middleweight. Now, we can answer the question. 22 | Final Answer: Andre Dirrell 23 | ## 24 | Question: What year was the party of the winner of the 1971 San Francisco mayoral election founded? 25 | Thought: Let's think step by step. To answer this question, we first need to know who won the 1971 San Francisco mayoral election. 26 | Tool: Search 27 | Tool Input: Who won the 1971 San Francisco mayoral election? 28 | Observation: Joseph Alioto 29 | Thought: We've learned Joseph Alioto won the 1971 San Francisco mayoral election. Now, we need to find out what party he belongs to. 30 | Tool: Search 31 | Tool Input: What party does Joseph Alioto belong to? 32 | Observation: Democratic Party 33 | Thought: We've learned Democratic Party is the party of Joseph Alioto. Now, we need to find out when the Democratic Party was founded. 34 | Tool: Search 35 | Tool Input: When was the Democratic Party founded? 36 | Observation: 1828 37 | Thought: We've learned the Democratic Party was founded in 1828. Now, we can answer the question. 38 | Final Answer: 1828 39 | ## 40 | Question: Right Back At It Again contains lyrics co-written by the singer born in what city? 41 | Thought: Let's think step by step. To answer this question, we first need to know what song the question is referring to. 42 | Tool: Search 43 | Tool Input: What is the song Right Back At It Again? 44 | Observation: "Right Back at It Again" is the song by A Day to Remember 45 | Thought: We've learned Right Back At It Again is a song by A Day to Remember. Now, we need to find out who co-wrote the song. 46 | Tool: Search 47 | Tool Input: Who co-wrote the song Right Back At It Again? 48 | Observation: Jeremy McKinnon 49 | Thought: We've learned Jeremy McKinnon co-wrote the song Right Back At It Again. Now, we need to find out what city he was born in. 50 | Tool: Search 51 | Tool Input: Where was Jeremy McKinnon born? 52 | Observation: Gainsville, Florida 53 | Thought: We've learned Gainsville, Florida is the city Jeremy McKinnon was born in. Now, we can answer the question. 54 | Final Answer: Gainsville, Florida 55 | ## 56 | Question: {query} 57 | Thought: 58 | {transcript} 59 | 60 | description: A few-shot HotpotQA ReaAct Agent prompt. 61 | tags: 62 | - agent 63 | meta: 64 | authors: 65 | - deepset-ai 66 | version: '0.1.0' -------------------------------------------------------------------------------- /prompts/deepset-language-detection.md: -------------------------------------------------------------------------------- 1 | This prompt is designed to detect the language of given documents. 2 | 3 | ## How to use in Haystack 4 | 5 | 1. Create a `PromptNode`. There are many models to pick from that can be used with `PromptNode`. Here is an example of one that uses `text-davinci-003`. 6 | 7 | ```python 8 | from haystack.nodes import PromptTemplate, PromptNode 9 | 10 | language_detection = PromptTemplate("deepset/language-detection") 11 | 12 | prompt_node = PromptNode(model_name_or_path="text-davinci-003", api_key=os.environ.get("OPENAI_API_KEY"),) 13 | ``` 14 | 15 | 2. Prompt is with some documents for context 16 | 17 | ```python 18 | document = [MY_DOCUMENTS] 19 | 20 | prompt_node.prompt(prompt_template=language_detection, documents=documents) 21 | ``` 22 | 23 | ### Example 24 | 25 | With the following `documents`: 26 | 27 | ```python 28 | from haystack.schema import Document 29 | 30 | en_doc = Document("This is a document with English content") 31 | 32 | tr_doc = Document("İstanbul'da hava yağışlı") 33 | 34 | fr_doc = Document("Bonjour, comment allez-vous?") 35 | 36 | de_doc = Document("Ich werde bald in Berlin sein.") 37 | 38 | documents = [en_doc, tr_doc, fr_doc, de_doc] 39 | ``` 40 | 41 | ```python 42 | prompt_node.prompt(prompt_template="language-detection", documents=documents) 43 | ``` 44 | 45 | ``` 46 | ['English', 'Turkish', 'French', 'German'] 47 | ``` -------------------------------------------------------------------------------- /prompts/deepset-language-detection.yaml: -------------------------------------------------------------------------------- 1 | name: deepset/language-detection 2 | text: | 3 | Detect the language in the following context and answer with the 4 | name of the language. 5 | Context: {documents}; 6 | Answer: 7 | description: Detect the language of the given context. 8 | tags: 9 | - language-detection 10 | meta: 11 | authors: 12 | - deepset-ai 13 | version: '0.0.1' -------------------------------------------------------------------------------- /prompts/deepset-multiple-choice-question-answering.md: -------------------------------------------------------------------------------- 1 | This prompt is designed to answer a `query` from a set of given `options`. 2 | 3 | ## How to use in Haystack 4 | 5 | To use this prompt with Haystack, we recommend defining an `output_parser` with `AnswerParser()` in the `PromptTemplate`. This way, the result of the `PromptNode` will return Haystack `Answer` objects 6 | 7 | ```python 8 | import os 9 | 10 | from haystack.nodes import AnswerParser 11 | from haystack.nodes import PromptNode, PromptTemplate 12 | 13 | multiple_choice = PromptTemplate("deepset/multiple-choice-question-answering", output_parser=AnswerParser()) 14 | 15 | prompt_node = PromptNode(model_name_or_path="text-davinci-003", api_key=os.environ.get("OPENAI_API_KEY")) 16 | 17 | prompt_node.prompt(prompt_template=multiple_choice, query="YOUR_QUERY", options="YOUR_OPTIONS") 18 | ``` 19 | 20 | ### Example 21 | 22 | ```python 23 | prompt_node.prompt(prompt_template=multiple_choice, query="What is the capital of France?", options=["Paris", "London", "Istanbul"]) 24 | ``` -------------------------------------------------------------------------------- /prompts/deepset-multiple-choice-question-answering.yaml: -------------------------------------------------------------------------------- 1 | name: deepset/multiple-choice-question-answering 2 | text: | 3 | Question:{query} ; 4 | Choose the most suitable option to answer the above question. 5 | Options: {options}; 6 | Answer: 7 | description: Given a set of answer options, choose the best one to answer the query. 8 | tags: 9 | - question-answering 10 | meta: 11 | authors: 12 | - deepset-ai 13 | version: '0.0.1' -------------------------------------------------------------------------------- /prompts/deepset-question-answering-check.md: -------------------------------------------------------------------------------- 1 | This prompt is designed to check whether a query can be answered with the provided context or not. The `PromptNode` that uses this prompt will reply with "yes" or "no" 2 | 3 | ## How to use in Haystack 4 | 5 | To use this prompt with Haystack, we recommend defining an `output_parser` with `AnswerParser()` in the `PromptTemplate`. This way, the result of the `PromptNode` will return Haystack `Answer` objects 6 | 7 | ```python 8 | import os 9 | 10 | from haystack.nodes import AnswerParser, PromptNode, PromptTemplate 11 | 12 | question_answering_check = PromptTemplate("deepset/question-answering-check", output_parser=AnwerParser()) 13 | 14 | prompt_node = PromptNode(model_name_or_path="text-davinci-003", api_key=os.environ.get("OPENAI_API_KEY"),) 15 | 16 | prompt_node.prompt(prompt_template=question_answering_check, query="YOUR_QUERY", documents="YOUR_documents") 17 | ``` 18 | 19 | ### Example 20 | 21 | With the following `documents`: 22 | 23 | ```python 24 | from haystack.schema import Document 25 | 26 | doc1 = Document("Paris is the capital of France") 27 | 28 | doc2 = Document("Haystack is an NLP framework") 29 | 30 | doc3 = Document("deepset is the company behind Haystack") 31 | 32 | doc4 = Document("Obama was the president of the USA from 2009 to 2017") 33 | 34 | documents = [doc1, doc2, doc3, doc4] 35 | ``` 36 | 37 | ```python 38 | prompt_node.prompt(prompt_template=question_answering_check, query="What is the capital of France?", documents=documents) 39 | ``` 40 | 41 | ``` 42 | [, 43 | , 44 | , 45 | ] 46 | ``` -------------------------------------------------------------------------------- /prompts/deepset-question-answering-check.yaml: -------------------------------------------------------------------------------- 1 | name: deepset/question-answering-check 2 | text: | 3 | Does the following context contain the answer to the question? 4 | Context: {documents}; 5 | Question: {query}; 6 | Please answer yes or no! Answer: 7 | description: Check whether the given context contains the answer to the question. 8 | tags: 9 | - question-answering 10 | meta: 11 | authors: 12 | - deepset-ai 13 | version: '0.0.1' -------------------------------------------------------------------------------- /prompts/deepset-question-answering-per-document.md: -------------------------------------------------------------------------------- 1 | Given a set of `document` and a single `query`, this prompt is designed to answer the query once per document. 2 | 3 | ## How to use in Haystack 4 | 5 | To use this prompt with Haystack, we recommend defining an `output_parser` with `AnswerParser()` in the `PromptTemplate`. This way, the result of the `PromptNode` will return Haystack `Answer` objects 6 | 7 | ```python 8 | import os 9 | 10 | from haystack.nodes import AnswerParser, PromptNode, PromptTemplate 11 | 12 | question_answering_per_doc = PromptTemplate("deepset/question-answering-per-document", output_parser=AnwerParser()) 13 | 14 | prompt_node = PromptNode(model_name_or_path="text-davinci-003", api_key=os.environ.get("OPENAI_API_KEY")) 15 | 16 | prompt_node.prompt(prompt_template=question_answering_per_doc, query="YOUR_QUERY", documents="YOUR_documents") 17 | ``` 18 | 19 | ### Example 20 | 21 | With the following `documents`: 22 | 23 | ```python 24 | from haystack.schema import Document 25 | 26 | doc1 = Document("The main suspect is John") 27 | 28 | doc2 = Document("The main suspect is Jane") 29 | 30 | documents = [doc1, doc2] 31 | ``` 32 | 33 | ```python 34 | prompt_node.prompt(prompt_template=question_answering_per_doc, query="Who is the main suspect?", documents=documents) 35 | ``` 36 | 37 | ``` 38 | [, 39 | ] 40 | ``` -------------------------------------------------------------------------------- /prompts/deepset-question-answering-per-document.yaml: -------------------------------------------------------------------------------- 1 | name: deepset/question-answering-per-document 2 | text: | 3 | Given the context please answer the question. Context: {documents}; 4 | Question: {query}; 5 | Answer: 6 | description: Answer a question per document. 7 | tags: 8 | - question-answering 9 | meta: 10 | authors: 11 | - deepset-ai 12 | version: '0.0.1' -------------------------------------------------------------------------------- /prompts/deepset-question-answering-with-document-scores.md: -------------------------------------------------------------------------------- 1 | This prompt is intended to be used in a `PromptNode` which receives documents with corresponding scores. For example, a pipeline with a `Retriever` which returnes scored documents is a good candidate to use in combination with this prompt. 2 | 3 | ## How to use in Haystack 4 | 5 | For example, given a query, the `WebRetriever` will return documents from the web, with scores. This prompt might be used in the following pipeline: 6 | 7 | ```python 8 | import os 9 | 10 | from haystack.nodes import PromptNode, PromptTemplate, WebRetriever 11 | 12 | question_anwering_with_scores = PromptTemplate("deepset/question-answering-with-document-scores") 13 | 14 | prompt_node = PromptNode("text-davinci-003", 15 | api_key=os.environ.get("OPENAI_API_KEY"), 16 | max_length=256, 17 | default_prompt_template=question_anwering_with_scores) 18 | 19 | retriever = WebRetriever(api_key=os.environ.get("SERPER_API_KEY")) 20 | 21 | ``` 22 | 23 | ```python 24 | from haystack import Pipeline 25 | 26 | pipe = Pipeline() 27 | 28 | pipe.add_node(component=retriever, name="WebRetriever", inputs=['Query']) 29 | pipe.add_node(component=prompt_node, name="QAwithScoresPrompt", inputs=['WebRetriever']) 30 | ``` 31 | 32 | ```python 33 | pipe.run(query="What years was Obama president?") 34 | ``` 35 | -------------------------------------------------------------------------------- /prompts/deepset-question-answering-with-document-scores.yaml: -------------------------------------------------------------------------------- 1 | name: deepset/question-answering-with-document-scores 2 | text: | 3 | Answer the following question using the paragraphs below as sources. 4 | An answer should be short, a few words at most. 5 | Paragraphs: 6 | {documents} 7 | Question: {query} 8 | 9 | Instructions: Consider all the paragraphs above and their corresponding scores to generate 10 | the answer. While a single paragraph may have a high score, it's important to consider all 11 | paragraphs for the same answer candidate to answer accurately. 12 | 13 | After having considered all possibilities, the final answer is: 14 | description: Answer a question given a set of documents and their corresponding scores from the Retriever. 15 | tags: 16 | - question-answering 17 | meta: 18 | authors: 19 | - deepset-ai 20 | version: '0.0.1' -------------------------------------------------------------------------------- /prompts/deepset-question-answering-with-references.md: -------------------------------------------------------------------------------- 1 | This prompt is designed to answer a `query` given a list of `documents`. It will also reference which document the final answer came from. For example, if the answer was in the first document, the first document, the restult will indicate that the answer was 'stated in Document[1]' 2 | 3 | ## How to use in Haystack 4 | 5 | To use this prompt with Haystack, we recommend defining an `output_parser` with `AnswerParser(reference_pattern=r"Document\[(\d+)\]")` in the `PromptTemplate`. This way, the result of the `PromptNode` will return Haystack `Answer` objects. 6 | 7 | ```python 8 | import os 9 | 10 | from haystack.nodes import AnswerParser, PromptNode, PromptTemplate 11 | 12 | question_answering_with_references = PromptTemplate("deepset/question-answering-with-references", output_parser=AnswerParser(reference_pattern=r"Document\[(\d+)\]")) 13 | 14 | prompt_node = PromptNode(model_name_or_path="text-davinci-003", api_key=os.environ.get("OPENAI_API_KEY")) 15 | 16 | prompt_node.prompt(prompt_template=question_answering_with_references, query="YOUR_QUERY", documents="YOUR_DOCUMENTS") 17 | ``` -------------------------------------------------------------------------------- /prompts/deepset-question-answering-with-references.yaml: -------------------------------------------------------------------------------- 1 | name: deepset/question-answering-with-references 2 | text: | 3 | Create a concise and informative answer (no more than 50 words) for a given question 4 | based solely on the given documents. You must only use information from the given documents. 5 | Use an unbiased and journalistic tone. Do not repeat text. Cite the documents using Document[number] notation. 6 | If multiple documents contain the answer, cite those documents like ‘as stated in Document[number], Document[number], etc.’. 7 | If the documents do not contain the answer to the question, say that ‘answering is not possible given the available information.’ 8 | {join(documents, delimiter=new_line, pattern=new_line+'Document[$idx]: $content', str_replace={new_line: ' ', '[': '(', ']': ')'})} 9 | Question: {query}; Answer: 10 | tags: 11 | - question-answering 12 | description: Perform question answering with references to documents. 13 | meta: 14 | authors: 15 | - deepset-ai 16 | version: '0.1.0' 17 | -------------------------------------------------------------------------------- /prompts/deepset-question-answering.md: -------------------------------------------------------------------------------- 1 | This prompt is simply designed to answer a `query` given a set of `documents`. There will be 1 answer generated. 2 | 3 | ## How to use in Haystack 4 | To use this prompt with Haystack, we recommend defining an `output_parser` with `AnswerParser()` in the `PromptTemplate`. This way, the result of the `PromptNode` will return Haystack `Answer` objects 5 | 6 | ```python 7 | import os 8 | 9 | from haystack.nodes import AnswerParser, PromptNode, PromptTemplate 10 | 11 | question_answering_template = PromptTemplate("deepset/question-answering", output_parser=AnswerParser()) 12 | 13 | prompt_node = PromptNode(model_name_or_path="text-davinci-003", api_key=os.environ.get("OPENAI_API_KEY")) 14 | 15 | prompt_node.prompt(prompt_template=question_answering_template, query="YOUR_QUERY", documents="YOUR_DOCUMENTS") 16 | 17 | ``` 18 | -------------------------------------------------------------------------------- /prompts/deepset-question-answering.yaml: -------------------------------------------------------------------------------- 1 | name: deepset/question-answering 2 | text: | 3 | Given the context please answer the question. Context: {join(documents)}; 4 | Question: {query}; 5 | Answer: 6 | description: Answer a question given a set of documents. 7 | tags: 8 | - question-answering 9 | meta: 10 | authors: 11 | - deepset-ai 12 | version: '0.1.1' -------------------------------------------------------------------------------- /prompts/deepset-question-generation.md: -------------------------------------------------------------------------------- 1 | This prompt creates a single question for each document in the provided `documents` 2 | 3 | ## How to use in Haystack 4 | 5 | ```python 6 | import os 7 | 8 | from haystack.nodes import PromptNode, PromptTemplate 9 | 10 | question_generation_template = PromptTemplate("deepset/question-answering") 11 | 12 | prompt_node = PromptNode(model_name_or_path="text-davinci-003", api_key=os.environ.get("OPENAI_API_KEY")) 13 | 14 | prompt_node.prompt(prompt_template=question_generation_template, documents="YOUR_DOCUMENTS") 15 | ``` 16 | 17 | -------------------------------------------------------------------------------- /prompts/deepset-question-generation.yaml: -------------------------------------------------------------------------------- 1 | name: deepset/question-generation 2 | text: | 3 | Given the context please generate a question. 4 | Context: {documents}; 5 | Question: 6 | description: Generate a question given a set of documents. 7 | tags: 8 | - question-generation 9 | meta: 10 | authors: 11 | - deepset-ai 12 | version: '0.0.1' -------------------------------------------------------------------------------- /prompts/deepset-sentiment-analysis.md: -------------------------------------------------------------------------------- 1 | For each document in the provided `documents`, tells you whether it is 'postivie', 'negative' or 'neutral'. 2 | 3 | ## How to use in Haystack 4 | 5 | ```python 6 | import os 7 | 8 | from haystack.nodes import PromptNode, PromptTemplate 9 | 10 | sentiment_analysis_template = PromptTemplate("deepset/sentiment-analysis") 11 | 12 | prompt_node = PromptNode(model_name_or_path="text-davinci-003", api_key=os.environ.get("OPENAI_API_KEY")) 13 | 14 | prompt_node.prompt(prompt_template=sentiment_analysis_template, documents="YOUR_DOCUMENTS") 15 | ``` 16 | 17 | ### Example 18 | 19 | For example, with the following documents: 20 | 21 | ```python 22 | from haystack.schema import Document 23 | 24 | doc1 = Document("I am super happy") 25 | 26 | doc2 = Document("Today sucks") 27 | 28 | doc3 = Document("There is nothing wrong with what's going on") 29 | 30 | documents = [doc1, doc2, doc3] 31 | ``` 32 | 33 | ```python 34 | prompt_node.prompt(prompt_template=sentiment_analysis_template, documents=documents) 35 | 36 | ``` 37 | 38 | Result: 39 | ``` 40 | ['Positive', 'Negative.', 'Neutral'] 41 | 42 | ``` -------------------------------------------------------------------------------- /prompts/deepset-sentiment-analysis.yaml: -------------------------------------------------------------------------------- 1 | name: deepset/sentiment-analysis 2 | text: | 3 | Please give a sentiment for this context. 4 | Answer with positive, negative or neutral. 5 | Context: {documents}; 6 | Answer: 7 | description: Provide the sentiment (positive, negative, or neutral) of a set of documents. 8 | tags: 9 | - sentiment-analysis 10 | meta: 11 | authors: 12 | - deepset-ai 13 | version: '0.0.1' -------------------------------------------------------------------------------- /prompts/deepset-summarization-chain-of-density.md: -------------------------------------------------------------------------------- 1 | This prompt is designed to produce a summary for each document provided in `documents`. 2 | It uses a technique called "chain of density" (from https://arxiv.org/pdf/2309.04269.pdf), that iteratively refines the summary in each step. 3 | The prompt yields 5 summaries of the article with increasing density. Typically, users prefer summary 4 or 5. 4 | 5 | ## How to use in Haystack 6 | 7 | ```python 8 | from haystack.nodes import PromptNode, PromptTemplate 9 | 10 | prompt_node = PromptNode(model_name_or_path="gpt-4", max_length=3000, api_key="", model_kwargs={"stream":True}) 11 | summarization_template = PromptTemplate("deepset/summarization-chain-of-density") 12 | 13 | res = prompt_node.prompt(prompt_template=summarization_template, documents=["YOUR_DOCUMENT"]) 14 | print(res) 15 | ``` -------------------------------------------------------------------------------- /prompts/deepset-summarization-chain-of-density.yaml: -------------------------------------------------------------------------------- 1 | name: deepset/summarization-chain-of-density 2 | text: | 3 | I will provide you with an article at the very end of this instruction. Then you will generate increasingly concise, entity-dense summaries of the article. 4 | Repeat the following 2 steps 5 times. 5 | Step 1. Identify 1-3 informative entities (";" delimited) from the article which are missing from the previously generated summary. 6 | Step 2. Write a new, denser summary of identical length which covers every entity and detail from the previous summary plus the missing entities. 7 | A missing entity is: 8 | - relevant to the main story, 9 | - specific yet concise (5 words or fewer), 10 | - novel (not in the previous summary), 11 | - faithful (present in the article), 12 | - anywhere (can be located anywhere in the article). 13 | Guidelines: 14 | - The first summary should be long (4-5 sentences, ~80 words) yet highly non-specific, containing little information beyond the entities marked as missing. Use overly verbose language and fillers (e.g., "this article discusses") to reach ~80 words. 15 | - Make every word count: rewrite the previous summary to improve flow and make space for additional entities. 16 | - Make space with fusion, compression, and removal of uninformative phrases like "the article discusses". 17 | - The summaries should become highly dense and concise yet self-contained, i.e., easily understood without the article. 18 | - Missing entities can appear anywhere in the new summary. 19 | - Never drop entities from the previous summary. If space cannot be made, add fewer new entities. 20 | Remember, use the exact same number of words for each summary. 21 | Answer in JSON. The JSON should be a list (length 5) of dictionaries whose keys are "Missing_Entities" and "Denser_Summary". 22 | Here is the article that you should summarize: {documents} 23 | description: Summarize the given document using the chain of density technique (from https://arxiv.org/pdf/2309.04269.pdf). The prompt yields 5 summaries of the article with increasing density. Typically, users prefer summary 4 or 5. 24 | tags: 25 | - summarization 26 | meta: 27 | authors: 28 | - deepset-ai 29 | version: '0.0.1' -------------------------------------------------------------------------------- /prompts/deepset-summarization.md: -------------------------------------------------------------------------------- 1 | This promopt is designed to produce a summary for each document provided in `documents` 2 | 3 | ## How to use in Haystack 4 | 5 | ```python 6 | import os 7 | 8 | from haystack.nodes import PromptNode, PromptTemplate 9 | 10 | summarization_template = PromptTemplate("deepset/summarization") 11 | 12 | prompt_node = PromptNode(model_name_or_path="text-davinci-003", api_key=os.environ.get("OPENAI_API_KEY")) 13 | 14 | prompt_node.prompt(prompt_template=summarization_template, documents="YOUR_DOCUMENTS") 15 | ``` -------------------------------------------------------------------------------- /prompts/deepset-summarization.yaml: -------------------------------------------------------------------------------- 1 | name: deepset/summarization 2 | text: | 3 | Summarize this document: {documents} 4 | Summary: 5 | description: Summarize the given document. 6 | tags: 7 | - summarization 8 | meta: 9 | authors: 10 | - deepset-ai 11 | version: '0.0.1' -------------------------------------------------------------------------------- /prompts/deepset-topic-classification.md: -------------------------------------------------------------------------------- 1 | This prompt is designed to categorize each document provided in `documents` based on the categories provided in `options`. 2 | 3 | ## How to use in Haystack 4 | 5 | ```python 6 | import os 7 | 8 | from haystack.nodes import PromptNode, PromptTemplate 9 | 10 | topic_classifier_template = PromptTemplate("deepset/topic-classification") 11 | 12 | prompt_node = PromptNode(model_name_or_path="text-davinci-003", api_key=os.environ.get("OPENAI_API_KEY")) 13 | 14 | prompt_node.prompt(prompt_template=topic_classifier_template, documents="YOUR_DOCUMENTS", options=["A LIST OF TOPICS"]) 15 | ``` 16 | 17 | ### Example 18 | 19 | For example, with a list of news articles defined in `news`, we may use this template as follows: 20 | 21 | ```python 22 | prompt_node.prompt(prompt_template=topic_classifier_template, documents=news, options=["economics", "politics", "culture"]) 23 | ``` -------------------------------------------------------------------------------- /prompts/deepset-topic-classification.yaml: -------------------------------------------------------------------------------- 1 | name: deepset/topic-classification 2 | text: | 3 | Categories: {options}; 4 | What category best describes: {documents}; 5 | Answer: 6 | description: Classify the given documents into categories. 7 | tags: 8 | - classification 9 | meta: 10 | authors: 11 | - deepset-ai 12 | version: '0.0.1' -------------------------------------------------------------------------------- /prompts/deepset-translation.md: -------------------------------------------------------------------------------- 1 | This prompt is designed to accept a `target_language` and translate each document procided in `documents` to this target language. 2 | 3 | ## How to use in Haystack 4 | 5 | ```python 6 | import os 7 | 8 | from haystack.nodes import PromptNode, PromptTemplate 9 | 10 | translation_template = PromptTemplate("deepset/translation") 11 | 12 | prompt_node = PromptNode(model_name_or_path="text-davinci-003", api_key=os.environ.get("OPENAI_API_KEY")) 13 | 14 | prompt_node.prompt(prompt_template=translation_template, documents=["YOUR_DOCUMENTS"], target_language="your_target_language") 15 | ``` 16 | 17 | ### Example 18 | 19 | For example, let's assume we have a set of english documents in `english_documents` that we want to translate to French. 20 | 21 | ```python 22 | prompt_node.prompt(prompt_template=translation_template, documents=english_documents, target_language="french") 23 | ``` -------------------------------------------------------------------------------- /prompts/deepset-translation.yaml: -------------------------------------------------------------------------------- 1 | name: deepset/translation 2 | text: | 3 | Translate the following context to {target_language}. Context: {documents}; Translation: 4 | description: Translate the given text into the target language. 5 | tags: 6 | - translation 7 | meta: 8 | authors: 9 | - deepset-ai 10 | version: '0.1.0' 11 | -------------------------------------------------------------------------------- /prompts/deepset-zero-shot-react.md: -------------------------------------------------------------------------------- 1 | This prompt is intended to be used with a Haystack `Agent`. It's the backbone of an LLM powered `Agent` and expects to be provided `Tools`. 2 | 3 | To learn how to use this prompt and an `Agent` check out our [Answering Multihop Questions with Agents Tutorial](https://haystack.deepset.ai/tutorials/23_answering_multihop_questions_with_agents). 4 | 5 | ## How to use in Haystack 6 | 7 | To use this prompt from the PromptHub in an Agent: 8 | 9 | ```python 10 | import os 11 | 12 | from haystack.agents import Agent 13 | from haystack.nodes import PromptNode, PromptTemplate 14 | 15 | zero_shot_agent_template = PromptTemplate("deepset/zero-shot-react") 16 | 17 | prompt_node = PromptNode(model_name_or_path="text-davinci-003", api_key=os.environ.get("OPENAI_API_KEY"), stop_words=["Observation:"]) 18 | agent = Agent(prompt_node=prompt_node, prompt_template=zero_shot_agent_template) 19 | 20 | agent.run("Your query") 21 | ``` -------------------------------------------------------------------------------- /prompts/deepset-zero-shot-react.yaml: -------------------------------------------------------------------------------- 1 | name: deepset/zero-shot-react 2 | text: | 3 | You are a helpful and knowledgeable agent. To achieve your goal of answering complex questions 4 | correctly, you have access to the following tools: 5 | 6 | {tool_names_with_descriptions} 7 | 8 | To answer questions, you'll need to go through multiple steps involving step-by-step thinking and 9 | selecting appropriate tools and their inputs; tools will respond with observations. When you are ready 10 | for a final answer, respond with the `Final Answer:` 11 | 12 | Use the following format: 13 | 14 | Question: the question to be answered 15 | Thought: Reason if you have the final answer. If yes, answer the question. If not, find out the missing information needed to answer it. 16 | Tool: pick one of {tool_names} 17 | Tool Input: the input for the tool 18 | Observation: the tool will respond with the result 19 | ... 20 | 21 | Final Answer: the final answer to the question, make it short (1-5 words) 22 | Thought, Tool, Tool Input, and Observation steps can be repeated multiple times, but sometimes we can find an answer in the first pass 23 | --- 24 | 25 | Question: {query} 26 | Thought: Let's think step-by-step, I first need to 27 | description: An agent prompt. Follows 'Thought, Tool and Observation' steps. 28 | tags: 29 | - agent 30 | meta: 31 | authors: 32 | - deepset-ai 33 | version: '0.1.0' --------------------------------------------------------------------------------