Repository: pingcap/ossinsight-lite Branch: main Commit: 86e9015a8709 Files: 62 Total size: 310.0 KB Directory structure: gitextract_rmebsf2k/ ├── .cursor/ │ └── rules/ │ └── styleguide.mdc ├── .github/ │ └── workflows/ │ ├── docs.yml │ └── sitemap-sync.yml ├── .gitignore ├── .vscode/ │ └── settings.json ├── DEVELOPMENT.md ├── LICENSE ├── Makefile ├── README.md ├── demos.yml ├── mkdocs.yml ├── pyproject.toml ├── scripts/ │ ├── check_dependencies.py │ ├── generate_demos.py │ └── sync_from_tidb_docs.py └── src/ ├── ai/ │ ├── concepts/ │ │ └── vector-search.md │ ├── examples/ │ │ ├── auto-embedding-with-pytidb.md │ │ ├── basic-with-pytidb.md │ │ ├── fulltext-search-with-pytidb.md │ │ ├── hybrid-search-with-pytidb.md │ │ ├── image-search-with-pytidb.md │ │ ├── index.md │ │ ├── memory-with-pytidb.md │ │ ├── rag-with-pytidb.md │ │ ├── text2sql-with-pytidb.md │ │ └── vector-search-with-pytidb.md │ ├── guides/ │ │ ├── auto-embedding.md │ │ ├── connect.md │ │ ├── filtering.md │ │ ├── fulltext-search.md │ │ ├── hybrid-search.md │ │ ├── image-search.md │ │ ├── joins.md │ │ ├── raw-queries.md │ │ ├── reranking.md │ │ ├── tables.md │ │ ├── transaction.md │ │ └── vector-search.md │ ├── index.md │ ├── integrations/ │ │ ├── embedding-cohere.md │ │ ├── embedding-gemini.md │ │ ├── embedding-huggingface.md │ │ ├── embedding-jinaai.md │ │ ├── embedding-nvidia-nim.md │ │ ├── embedding-openai-compatible.md │ │ ├── embedding-openai.md │ │ ├── embedding-overview.md │ │ ├── embedding-tidb-cloud-hosted.md │ │ ├── langchain.md │ │ ├── llamaindex.md │ │ ├── tidb-mcp-claude-code.md │ │ ├── tidb-mcp-claude-desktop.md │ │ ├── tidb-mcp-cursor.md │ │ ├── tidb-mcp-server.md │ │ ├── tidb-mcp-vscode.md │ │ └── tidb-mcp-windsurf.md │ ├── javascripts/ │ │ └── mathjax.js │ └── quickstart.md ├── robots.txt ├── styles/ │ └── extra.css └── templates/ ├── demo_gallery_template.j2 └── demo_page_template.j2 ================================================ FILE CONTENTS ================================================ ================================================ FILE: .cursor/rules/styleguide.mdc ================================================ --- description: globs: alwaysApply: true --- # Documentation Review Style Guide ## Behavior instruction You are acting as a **senior technical writer** who is reviewing TiDB documentation pull requests and you always provide ready-to-commit doc suggestions so the PR author can commit them directly. ## Note - When you finish the review, you directly add comments to the PR instead of requesting changes to avoid blocking the pull request from being merged. - If the PR author is ti-chi-bot, you only correct English grammar, spelling, and punctuation mistakes, if any. ## Review aspects - Clarity, simplicity, completeness, and readability - Logical flow and sentence structure - Technical accuracy and terminology consistency ## General writing principles - Correct English grammar, spelling, and punctuation mistakes, if any. - Make sure the documentation is easy to understand for TiDB users. - Write in **second person** ("you") when addressing users. - Prefer **present tense** unless describing historical behavior. - Avoid unnecessary words and repetition. - Use **consistent terminology**. For example: - ❌ Do not mix "database" and "instance" - ✅ Use "replicate" instead of "synchronize" when referring to replicating data from one TiDB cluster to another. ## Structure and format - Use sentence case for headings (e.g., `## Configure the cluster`). - Use ordered lists (`1.`, `2.`) for steps. - Code snippets, command names, options, and paths should be in backticks (`` ` ``). ## Markdown style - Add a blank line before and after headings and lists. - Use proper heading hierarchy (no jumping from `##` to `####`). ## Common issues to flag - Passive voice overuse _"The cluster is started by TiUP"_ → _"TiUP starts the cluster"_ - Inconsistent use of technical terms _"TiDB Cloud Starter clusters" vs. "TiDB Cloud clusters"_ – pick one. - Unclear step instructions _"Do it like before"_ → _"Repeat step 3 using the updated config file"_ - Grammar and spelling issues _"recieve"_ → _"receive"_, _"an TiDB instance"_ → _"a TiDB instance"_ ## Special notes - Follow any existing terminology in our glossary (`/glossary.md` if available). - When in doubt, favor clarity over cleverness. - If something might confuse a new user, suggest a reword. ## Purposes of this style guide This guide helps Gemini Code Assist provide actionable, high-quality suggestions for improving technical documentation, especially for PRs related to user guides, how-to articles, and product reference material. ================================================ FILE: .github/workflows/docs.yml ================================================ name: Docs Publish on: push: branches: - main permissions: contents: write jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Configure Git Credentials run: | git config user.name github-actions[bot] git config user.email 41898282+github-actions[bot]@users.noreply.github.com - name: Install uv uses: astral-sh/setup-uv@v5 with: enable-cache: true - name: Set up Python run: uv python install - run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV - uses: actions/cache@v4 with: key: mkdocs-material-${{ env.cache_id }} path: .cache restore-keys: | mkdocs-material- - name: Install dependencies run: uv sync - name: Generate demo pages and gallery run: make generate-demos - name: Deploy docs run: uv run mkdocs gh-deploy --force ================================================ FILE: .github/workflows/sitemap-sync.yml ================================================ name: Sync Sitemap on: push: branches: - gh-pages paths: - 'sitemap.xml' permissions: contents: write jobs: sync-sitemap: runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 with: ref: gh-pages token: ${{ secrets.GITHUB_TOKEN }} - name: Configure Git Credentials run: | git config user.name github-actions[bot] git config user.email 41898282+github-actions[bot]@users.noreply.github.com - name: Check if sitemap.xml exists in root id: check-sitemap run: | if [ -f "sitemap.xml" ]; then echo "exists=true" >> $GITHUB_OUTPUT else echo "exists=false" >> $GITHUB_OUTPUT fi - name: Create ai directory if it doesn't exist if: steps.check-sitemap.outputs.exists == 'true' run: mkdir -p ai - name: Copy sitemap.xml to ai/sitemap.xml if: steps.check-sitemap.outputs.exists == 'true' run: cp sitemap.xml ai/sitemap.xml - name: Commit and push changes if: steps.check-sitemap.outputs.exists == 'true' run: | git add ai/sitemap.xml if git diff --staged --quiet; then echo "No changes to commit" else git commit -m "Sync sitemap.xml to ai/sitemap.xml" git push origin gh-pages fi ================================================ FILE: .gitignore ================================================ # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ share/python-wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .nox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover *.py,cover .hypothesis/ .pytest_cache/ cover/ # Translations *.mo *.pot # Django stuff: *.log local_settings.py db.sqlite3 db.sqlite3-journal # Flask stuff: instance/ .webassets-cache # Scrapy stuff: .scrapy # Sphinx documentation docs/_build/ # PyBuilder .pybuilder/ target/ # Jupyter Notebook .ipynb_checkpoints # IPython profile_default/ ipython_config.py # pyenv # For a library or package, you might want to ignore these files since the code is # intended to run in multiple environments; otherwise, check them in: .python-version # pipenv # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. # However, in case of collaboration, if having platform-specific dependencies or dependencies # having no cross-platform support, pipenv may install dependencies that don't work, or not # install all needed dependencies. #Pipfile.lock # UV # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. # This is especially recommended for binary packages to ensure reproducibility, and is more # commonly ignored for libraries. #uv.lock # poetry # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. # This is especially recommended for binary packages to ensure reproducibility, and is more # commonly ignored for libraries. # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control #poetry.lock # pdm # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. #pdm.lock # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it # in version control. # https://pdm.fming.dev/latest/usage/project/#working-with-version-control .pdm.toml .pdm-python .pdm-build/ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm __pypackages__/ # Celery stuff celerybeat-schedule celerybeat.pid # SageMath parsed files *.sage.py # Environments .env .venv env/ venv/ ENV/ env.bak/ venv.bak/ # Spyder project settings .spyderproject .spyproject # Rope project settings .ropeproject # mkdocs documentation /site # mypy .mypy_cache/ .dmypy.json dmypy.json # Pyre type checker .pyre/ # pytype static type analyzer .pytype/ # Cython debug symbols cython_debug/ # PyCharm # JetBrains specific template is maintained in a separate JetBrains.gitignore that can # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. .idea/ # Ruff stuff: .ruff_cache/ # PyPI configuration file .pypirc ================================================ FILE: .vscode/settings.json ================================================ { "cSpell.words": [ "FULLTEXT", "Pydantic", "getenv", "jina", "jinaai", "Rerank", "reranker", "reranking", "tablename", "multimodal" ] } ================================================ FILE: DEVELOPMENT.md ================================================ # Development Guide This guide covers the development setup and maintenance of the TiDB for AI documentation site. ## Quick Start 1. **Install UV** (fast dependency manager): ```bash curl -LsSf https://astral.sh/uv/install.sh | sh ``` 2. **Install dependencies**: ```bash make install ``` 3. **Start development server**: ```bash make serve ``` ## Project Structure ``` ├── demos.yml # Demo Gallery configuration ├── scripts/generate_demos.py # Demo Gallery generation script ├── src/ │ ├── templates/ # Jinja2 templates │ └── ai/examples/ # Generated demo pages └── Makefile # Build commands ``` ## Helpful Commands ```bash # Dependencies make check # Check dependencies and setup make install # Install/update dependencies # Development workflow make serve # Start development server make build # Build documentation site make clean # Clean build artifacts # Demo management make generate-demos # Generate demo pages and gallery from demos.yml config make generate-demo-pages # Only generate demo pages. make generate-demo-gallery # Only generate demo gallery. # Other make help # Show all available commands ``` ## Maintain the Demo Gallery The Demo Gallery showcases AI demos of TiDB and is configured via [demos.yml](demos.yml). To regenerate the demo gallery from configuration, run: ```bash make generate-demos ``` ### How to add a new demo You can follow the steps below to add a new demo: 1. Add entry to `demos` array in `demos.yml` with unique `id`, title, description, and display properties For example: ```yaml demos: - id: "basic" title: "Basic Usage" description: "Learn fundamental PyTiDB operations" icon: "⚙️" background: "linear-gradient(135deg, #10b981, var(--brand-color))" link: "basic-with-pytidb/" doc_link: "https://github.com/pingcap/pytidb/tree/main/examples/basic/README.md" cover_image: null ``` 2. Add the demo `id` to appropriate category's `demos` array For example: ```yaml categories: - id: "featured" title: "Search" demos: ["image-search"] ``` 3. Run `make generate-demos` to regenerate 4. Commit changes ================================================ FILE: LICENSE ================================================ Attribution-ShareAlike 3.0 Unported ======================================================================= CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM ITS USE. License THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS. 1. Definitions a. "Adaptation" means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered an Adaptation for the purpose of this License. b. "Collection" means a collection of literary or artistic works, such as encyclopedias and anthologies, or performances, phonograms or broadcasts, or other works or subject matter other than works listed in Section 1(f) below, which, by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. A work that constitutes a Collection will not be considered an Adaptation (as defined below) for the purposes of this License. c. "Creative Commons Compatible License" means a license that is listed at https://creativecommons.org/compatiblelicenses that has been approved by Creative Commons as being essentially equivalent to this License, including, at a minimum, because that license: (i) contains terms that have the same purpose, meaning and effect as the License Elements of this License; and, (ii) explicitly permits the relicensing of adaptations of works made available under that license under this License or a Creative Commons jurisdiction license with the same License Elements as this License. d. "Distribute" means to make available to the public the original and copies of the Work or Adaptation, as appropriate, through sale or other transfer of ownership. e. "License Elements" means the following high-level license attributes as selected by Licensor and indicated in the title of this License: Attribution, ShareAlike. f. "Licensor" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License. g. "Original Author" means, in the case of a literary or artistic work, the individual, individuals, entity or entities who created the Work or if no individual or entity can be identified, the publisher; and in addition (i) in the case of a performance the actors, singers, musicians, dancers, and other persons who act, sing, deliver, declaim, play in, interpret or otherwise perform literary or artistic works or expressions of folklore; (ii) in the case of a phonogram the producer being the person or legal entity who first fixes the sounds of a performance or other sounds; and, (iii) in the case of broadcasts, the organization that transmits the broadcast. h. "Work" means the literary and/or artistic work offered under the terms of this License including without limitation any production in the literary, scientific and artistic domain, whatever may be the mode or form of its expression including digital form, such as a book, pamphlet and other writing; a lecture, address, sermon or other work of the same nature; a dramatic or dramatico-musical work; a choreographic work or entertainment in dumb show; a musical composition with or without words; a cinematographic work to which are assimilated works expressed by a process analogous to cinematography; a work of drawing, painting, architecture, sculpture, engraving or lithography; a photographic work to which are assimilated works expressed by a process analogous to photography; a work of applied art; an illustration, map, plan, sketch or three-dimensional work relative to geography, topography, architecture or science; a performance; a broadcast; a phonogram; a compilation of data to the extent it is protected as a copyrightable work; or a work performed by a variety or circus performer to the extent it is not otherwise considered a literary or artistic work. i. "You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation. j. "Publicly Perform" means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images. k. "Reproduce" means to make copies of the Work by any means including without limitation by sound or visual recordings and the right of fixation and reproducing fixations of the Work, including storage of a protected performance or phonogram in digital form or other electronic medium. 2. Fair Dealing Rights. Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright or rights arising from limitations or exceptions that are provided for in connection with the copyright protection under copyright law or other applicable laws. 3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below: a. to Reproduce the Work, to incorporate the Work into one or more Collections, and to Reproduce the Work as incorporated in the Collections; b. to create and Reproduce Adaptations provided that any such Adaptation, including any translation in any medium, takes reasonable steps to clearly label, demarcate or otherwise identify that changes were made to the original Work. For example, a translation could be marked "The original work was translated from English to Spanish," or a modification could indicate "The original work has been modified."; c. to Distribute and Publicly Perform the Work including as incorporated in Collections; and, d. to Distribute and Publicly Perform Adaptations. e. For the avoidance of doubt: i. Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; ii. Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor waives the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; and, iii. Voluntary License Schemes. The Licensor waives the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License. The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. Subject to Section 8(f), all rights not expressly granted by Licensor are hereby reserved. 4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following restrictions: a. You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from any Licensor You must, to the extent practicable, remove from the Collection any credit as required by Section 4(c), as requested. If You create an Adaptation, upon notice from any Licensor You must, to the extent practicable, remove from the Adaptation any credit as required by Section 4(c), as requested. b. You may Distribute or Publicly Perform an Adaptation only under the terms of: (i) this License; (ii) a later version of this License with the same License Elements as this License; (iii) a Creative Commons jurisdiction license (either this or a later license version) that contains the same License Elements as this License (e.g., Attribution-ShareAlike 3.0 US)); (iv) a Creative Commons Compatible License. If you license the Adaptation under one of the licenses mentioned in (iv), you must comply with the terms of that license. If you license the Adaptation under the terms of any of the licenses mentioned in (i), (ii) or (iii) (the "Applicable License"), you must comply with the terms of the Applicable License generally and the following provisions: (I) You must include a copy of, or the URI for, the Applicable License with every copy of each Adaptation You Distribute or Publicly Perform; (II) You may not offer or impose any terms on the Adaptation that restrict the terms of the Applicable License or the ability of the recipient of the Adaptation to exercise the rights granted to that recipient under the terms of the Applicable License; (III) You must keep intact all notices that refer to the Applicable License and to the disclaimer of warranties with every copy of the Work as included in the Adaptation You Distribute or Publicly Perform; (IV) when You Distribute or Publicly Perform the Adaptation, You may not impose any effective technological measures on the Adaptation that restrict the ability of a recipient of the Adaptation from You to exercise the rights granted to that recipient under the terms of the Applicable License. This Section 4(b) applies to the Adaptation as incorporated in a Collection, but this does not require the Collection apart from the Adaptation itself to be made subject to the terms of the Applicable License. c. If You Distribute, or Publicly Perform the Work or any Adaptations or Collections, You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or if the Original Author and/or Licensor designate another party or parties (e.g., a sponsor institute, publishing entity, journal) for attribution ("Attribution Parties") in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and (iv) , consistent with Ssection 3(b), in the case of an Adaptation, a credit identifying the use of the Work in the Adaptation (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). The credit required by this Section 4(c) may be implemented in any reasonable manner; provided, however, that in the case of a Adaptation or Collection, at a minimum such credit will appear, if a credit for all contributing authors of the Adaptation or Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior written permission of the Original Author, Licensor and/or Attribution Parties. d. Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable law, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Adaptations or Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author's honor or reputation. Licensor agrees that in those jurisdictions (e.g. Japan), in which any exercise of the right granted in Section 3(b) of this License (the right to make Adaptations) would be deemed to be a distortion, mutilation, modification or other derogatory action prejudicial to the Original Author's honor and reputation, the Licensor will waive or not assert, as appropriate, this Section, to the fullest extent permitted by the applicable national law, to enable You to reasonably exercise Your right under Section 3(b) of this License (right to make Adaptations) but not otherwise. 5. Representations, Warranties and Disclaimer UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. 6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 7. Termination a. This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Adaptations or Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License. b. Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above. 8. Miscellaneous a. Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License. b. Each time You Distribute or Publicly Perform an Adaptation, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License. c. If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. d. No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent. e. This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You. f. The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). These rights and subject matter take effect in the relevant jurisdiction in which the License terms are sought to be enforced according to the corresponding provisions of the implementation of those treaty provisions in the applicable national law. If the standard suite of rights granted under applicable copyright law includes additional rights not granted under this License, such additional rights are deemed to be included in the License; this License is not intended to restrict the license of any rights under applicable law. ======================================================================= Creative Commons Notice Creative Commons is not a party to this License, and makes no warranty whatsoever in connection with the Work. Creative Commons will not be liable to You or any party on any legal theory for any damages whatsoever, including without limitation any general, special, incidental or consequential damages arising in connection to this license. Notwithstanding the foregoing two (2) sentences, if Creative Commons has expressly identified itself as the Licensor hereunder, it shall have all rights and obligations of Licensor. Except for the limited purpose of indicating to the public that the Work is licensed under the CCPL, Creative Commons does not authorize the use by either party of the trademark "Creative Commons" or any related trademark or logo of Creative Commons without the prior written consent of Creative Commons. Any permitted use will be in compliance with Creative Commons' then-current trademark usage guidelines, as may be published on its website or otherwise made available upon request from time to time. For the avoidance of doubt, this trademark restriction does not form part of the License. Creative Commons may be contacted at https://creativecommons.org/. ================================================ FILE: Makefile ================================================ # TiDB for AI Documentation Site .PHONY: help install generate-demos generate-demo-pages generate-demo-gallery serve build clean check help: @echo "TiDB for AI Documentation Site" @echo "=============================" @echo "Available commands:" @echo " install - Install dependencies using UV" @echo " generate-demos - Generate demo pages and gallery from demos.yml config" @echo " generate-demo-pages - Only generate demo pages." @echo " generate-demo-gallery - Only generate demo gallery." @echo " serve - Start the development server" @echo " build - Build the documentation site" @echo " clean - Clean build artifacts" @echo " check - Check dependencies and project setup" @echo "" @echo "Demo gallery configuration:" @echo " Edit demos.yml in the project root to manage gallery content" @echo "" @echo "Prerequisites:" @echo " UV package manager - curl -LsSf https://astral.sh/uv/install.sh | sh" install: uv pip install -e . generate-demos: python scripts/generate_demos.py generate-demo-pages: python scripts/generate_demos.py --skip-gallery generate-demo-gallery: python scripts/generate_demos.py --skip-demos serve: mkdocs serve build: mkdocs build clean: rm -rf site/ rm -rf .mkdocs_cache/ check: python scripts/check_dependencies.py ================================================ FILE: README.md ================================================ # TiDB for AI TiDB is an open-source, distributed SQL database designed for modern AI applications, offering seamless scalability, real-time analytics, and unified storage for vectors, documents, knowledge graphs, operational data and more. 🚀 Follow our [Quickstart Guide](https://pingcap.github.io/ai/quickstart/) to begin building your first AI application with TiDB ## PyTiDB TiDB provide a Python SDK and a series of integrations with popular AI frameworks to help developers build AI applications efficiently. To install the TiDB Python SDK, run the following command: ```bash pip install pytidb ``` Examples: - Getting Started: [Basic Usage](https://pingcap.github.io/ai/examples/basic-with-pytidb/), [Auto Embedding](https://pingcap.github.io/ai/examples/auto-embedding-with-pytidb/) - Search & Retrieval: [Vector Search](https://pingcap.github.io/ai/examples/vector-search-with-pytidb/), [Fulltext Search](https://pingcap.github.io/ai/examples/fulltext-search-with-pytidb/), [Hybrid Search](https://pingcap.github.io/ai/examples/hybrid-search-with-pytidb/), [Image Search](https://pingcap.github.io/ai/examples/image-search-with-pytidb/) - AI Applications: [RAG](https://pingcap.github.io/ai/examples/rag-with-pytidb/), [Text2SQL](https://pingcap.github.io/ai/examples/text2sql-with-pytidb/), [Memory](https://pingcap.github.io/ai/examples/memory-with-pytidb/) Integrations: - AI Frameworks: [LlamaIndex](https://docs.pingcap.com/tidbcloud/vector-search-integrate-with-llamaindex/), [LangChain](https://docs.pingcap.com/tidbcloud/vector-search-integrate-with-langchain/) - ORM Libraries: [SQLAlchemy](https://docs.pingcap.com/tidbcloud/vector-search-integrate-with-sqlalchemy/), [Django-ORM](https://docs.pingcap.com/tidbcloud/vector-search-integrate-with-django-orm/), [Peewee](https://docs.pingcap.com/tidbcloud/vector-search-integrate-with-peewee/) - AI Services: [Bedrock](https://docs.pingcap.com/tidbcloud/vector-search-integrate-with-amazon-bedrock/) - Embedding Models/Services: [JinaAI](https://docs.pingcap.com/tidbcloud/vector-search-integrate-with-jinaai-embedding/) ## Contribute We welcome contributions to improve the TiDB for AI documentation! For development setup, maintenance scripts, and detailed contribution guidelines, please see [DEVELOPMENT.md](DEVELOPMENT.md). ## FAQ ### How can I get support? - [Join our Discord](https://discord.com/invite/vYU9h56kAX) (recommended) - [Ask questions in our forum](https://ask.pingcap.com/) - [Send support tickets](https://tidb.support.pingcap.com/) ================================================ FILE: demos.yml ================================================ # Demo Gallery Configuration title: "Demo Gallery" description: | Explore hands-on demos showcasing how TiDB empowers AI applications.
Get started quickly with TiDB Cloud Starter to build your own AI-powered solutions. meta: description: "Explore hands-on demos showcasing how TiDB empowers AI applications. Get started quickly with TiDB Cloud Starter to build your own AI-powered solutions." categories: - id: "featured" title: "⭐ Featured" demos: ["image-search", "rag", "memory"] - id: "getting-started" title: "🚀 Getting Started" demos: ["basic", "auto-embedding"] - id: "search" title: "🔍 Search & Retrieval" demos: ["vector-search", "fulltext-search", "hybrid-search", "image-search"] - id: "ai-apps" title: "🤖 AI Applications" demos: ["rag", "memory", "text2sql"] demos: - id: "image-search" title: "Image Search" description: "Build an image search application using multimodal embeddings for both text-to-image and image-to-image search." category: "search" icon: null background: null link: "image-search-with-pytidb/" doc_link: "https://github.com/pingcap/pytidb/tree/main/examples/image_search/README.md" cover_image: "https://github.com/user-attachments/assets/7ba9733a-4d1f-4094-8edb-58731ebd08e9" - id: "rag" title: "RAG" description: "Build a RAG application that combines document retrieval with language generation." category: "ai-apps" icon: null background: null link: "rag-with-pytidb/" doc_link: "https://github.com/pingcap/pytidb/tree/main/examples/rag/README.md" cover_image: "https://github.com/user-attachments/assets/dfd85672-65ce-4a46-8dd2-9f77d826363e" - id: "basic" title: "Basic Usage" description: "Learn fundamental PyTiDB operations including database connection, table creation, and data manipulation." category: "getting-started" icon: "⚙️" background: "linear-gradient(135deg, #10b981, var(--brand-color))" link: "basic-with-pytidb/" doc_link: "https://github.com/pingcap/pytidb/tree/main/examples/basic/README.md" cover_image: null - id: "auto-embedding" title: "Auto Embedding" description: "Automatically generate embeddings for your text data using built-in embedding models." category: "getting-started" icon: "🤖" background: "radial-gradient(circle at center, #8b5cf6 0%, var(--brand-color) 100%)" link: "auto-embedding-with-pytidb/" doc_link: "https://github.com/pingcap/pytidb/tree/main/examples/auto_embedding/README.md" cover_image: null - id: "vector-search" title: "Vector Search" description: "Implement semantic search using vector embeddings to find similar content." category: "search" icon: null background: null link: "vector-search-with-pytidb/" doc_link: "https://github.com/pingcap/pytidb/tree/main/examples/vector_search/README.md" cover_image: "https://github.com/user-attachments/assets/6d7783a5-ce9c-4dcc-8b95-49d5f0ca735a" - id: "fulltext-search" title: "Fulltext Search" description: "Perform traditional text search using MySQL fulltext search capabilities." category: "search" icon: null background: null link: "fulltext-search-with-pytidb/" doc_link: "https://github.com/pingcap/pytidb/tree/main/examples/fulltext_search/README.md" cover_image: "https://github.com/user-attachments/assets/c81ddad4-f996-4b1f-85c0-5cbb55bc2a3a" - id: "hybrid-search" title: "Hybrid Search" description: "Combine vector search and fulltext search for more comprehensive results." category: "search" icon: null background: null link: "hybrid-search-with-pytidb/" doc_link: "https://github.com/pingcap/pytidb/tree/main/examples/hybrid_search/README.md" cover_image: "https://github.com/user-attachments/assets/6e1c639d-2160-44c8-86b4-958913b9eca5" - id: "memory" title: "Memory" description: "Implement conversation memory for chatbots and conversational AI applications." category: "ai-apps" icon: null background: null link: "memory-with-pytidb/" doc_link: "https://github.com/pingcap/pytidb/tree/main/examples/memory/README.md" cover_image: "https://github.com/user-attachments/assets/74dee96b-ea20-49dc-ad27-679faa5bf9b8" - id: "text2sql" title: "Text2SQL" description: "Convert natural language queries into SQL statements using AI models." category: "ai-apps" icon: "💬" background: "linear-gradient(135deg, #06b6d4, var(--brand-color))" link: "text2sql-with-pytidb/" doc_link: "https://github.com/pingcap/pytidb/tree/main/examples/text2sql/README.md" cover_image: null # CTA section configuration cta: title: "Ready to build your AI application?" description: "Start your AI journey with TiDB Cloud Starter. Follow our quickstart guide to build your first AI-powered application in minutes, or explore specific examples for your use case." buttons: - text: "Try TiDB Cloud Starter" url: "https://tidbcloud.com/?utm_source=github&utm_medium=referral&utm_campaign=pytidb_readme" type: "primary" external: true - text: "View Quickstart Guide" url: "/ai/quickstart/" type: "secondary" external: false ================================================ FILE: mkdocs.yml ================================================ site_name: TiDB for AI site_url: https://pingcap.github.io repo_name: pingcap/tidb repo_url: https://github.com/pingcap/tidb edit_uri: https://github.com/pingcap/pingcap.github.io/tree/main/src docs_dir: src watch: - src theme: name: material logo: assets/logo.svg favicon: assets/favicon.ico color_mode: dark palette: # Palette toggle for dark mode - scheme: tidb-dark primary: custom toggle: icon: material/weather-night name: Switch to light mode # Palette toggle for light mode - scheme: tidb-light primary: custom toggle: icon: material/weather-sunny name: Switch to dark mode features: - content.code.copy - content.tabs.link - content.action.edit - content.tooltips - toc.follow - navigation.top - navigation.tabs - navigation.tabs.sticky - navigation.footer - navigation.tracking - navigation.instant - content.footnote.tooltips icon: repo: fontawesome/brands/github annotation: material/arrow-right-circle plugins: - search # - autorefs # - mkdocs-jupyter - redirects: redirect_maps: "index.md": "ai/index.md" "ai/integrations/mcp.md": "ai/integrations/tidb-mcp-server.md" markdown_extensions: - admonition - footnotes - pymdownx.critic - pymdownx.caret - pymdownx.keys - pymdownx.mark - pymdownx.tilde - pymdownx.details - pymdownx.highlight: anchor_linenums: true line_spans: __span pygments_lang_class: true - pymdownx.inlinehilite - pymdownx.snippets: base_path: .. dedent_subsections: true - pymdownx.superfences - pymdownx.tabbed: alternate_style: true - md_in_html - abbr - attr_list - pymdownx.snippets - pymdownx.emoji: emoji_index: !!python/name:material.extensions.emoji.twemoji emoji_generator: !!python/name:material.extensions.emoji.to_svg - markdown.extensions.toc: baselevel: 1 permalink: "" - pymdownx.arithmatex: generic: true nav: - Home: - TiDB for AI: ai/index.md - 🚀 Quickstart: ai/quickstart.md - 📖 Concepts: - Vector Search: ai/concepts/vector-search.md - 📚 Guides: - Connect to database: ai/guides/connect.md - Working with tables: ai/guides/tables.md - Vector Search: ai/guides/vector-search.md - Fulltext Search: ai/guides/fulltext-search.md - Hybrid Search: ai/guides/hybrid-search.md - Image Search: ai/guides/image-search.md - Auto Embedding: ai/guides/auto-embedding.md - Reranking: ai/guides/reranking.md - Filtering: ai/guides/filtering.md - 💡 Demos: - Gallery: ai/examples/index.md - Basic Usage: ai/examples/basic-with-pytidb.md - Auto Embedding: ai/examples/auto-embedding-with-pytidb.md - Vector Search: ai/examples/vector-search-with-pytidb.md - Fulltext Search: ai/examples/fulltext-search-with-pytidb.md - Hybrid Search: ai/examples/hybrid-search-with-pytidb.md - Image Search: ai/examples/image-search-with-pytidb.md - RAG: ai/examples/rag-with-pytidb.md - Memory: ai/examples/memory-with-pytidb.md - Text2SQL: ai/examples/text2sql-with-pytidb.md - 🔌 Integrations: - MCP Integration: - TiDB MCP Server: ai/integrations/tidb-mcp-server.md - IDE & Tool Integration: - Cursor: ai/integrations/tidb-mcp-cursor.md - Claude Desktop: ai/integrations/tidb-mcp-claude-desktop.md - Claude Code: ai/integrations/tidb-mcp-claude-code.md - Visual Studio Code: ai/integrations/tidb-mcp-vscode.md - Windsurf: ai/integrations/tidb-mcp-windsurf.md - AI Frameworks: - LlamaIndex: ai/integrations/llamaindex.md - LangChain: ai/integrations/langchain.md - Embeddings: - Overview: ai/integrations/embedding-overview.md - TiDB Cloud Hosted: ai/integrations/embedding-tidb-cloud-hosted.md - OpenAI: ai/integrations/embedding-openai.md - OpenAI Compatible: ai/integrations/embedding-openai-compatible.md - Cohere: ai/integrations/embedding-cohere.md - Jina AI: ai/integrations/embedding-jinaai.md - Google Gemini: ai/integrations/embedding-gemini.md - Hugging Face: ai/integrations/embedding-huggingface.md - NVIDIA NIM: ai/integrations/embedding-nvidia-nim.md - Concepts: - Vector Search: ai/concepts/vector-search.md - Guides: - Connect to database: ai/guides/connect.md - Working with tables: ai/guides/tables.md - Vector Search: ai/guides/vector-search.md - Fulltext Search: ai/guides/fulltext-search.md - Hybrid Search: ai/guides/hybrid-search.md - Image Search: ai/guides/image-search.md - Auto Embedding: ai/guides/auto-embedding.md - Reranking: ai/guides/reranking.md - Filtering: ai/guides/filtering.md - Transaction: ai/guides/transaction.md - Raw Queries: ai/guides/raw-queries.md - Multiple Table Joins: ai/guides/joins.md - Demos: - Gallery: ai/examples/index.md - Basic Usage: ai/examples/basic-with-pytidb.md - Auto Embedding: ai/examples/auto-embedding-with-pytidb.md - Vector Search: ai/examples/vector-search-with-pytidb.md - Fulltext Search: ai/examples/fulltext-search-with-pytidb.md - Hybrid Search: ai/examples/hybrid-search-with-pytidb.md - Image Search: ai/examples/image-search-with-pytidb.md - RAG: ai/examples/rag-with-pytidb.md - Memory: ai/examples/memory-with-pytidb.md - Text2SQL: ai/examples/text2sql-with-pytidb.md - Integrations: - MCP Integration: - TiDB MCP Server: ai/integrations/tidb-mcp-server.md - IDE & Tool Integration: - Cursor: ai/integrations/tidb-mcp-cursor.md - Claude Desktop: ai/integrations/tidb-mcp-claude-desktop.md - Claude Code: ai/integrations/tidb-mcp-claude-code.md - Visual Studio Code: ai/integrations/tidb-mcp-vscode.md - Windsurf: ai/integrations/tidb-mcp-windsurf.md - AI Frameworks: - LlamaIndex: ai/integrations/llamaindex.md - LangChain: ai/integrations/langchain.md - Embeddings: - Overview: ai/integrations/embedding-overview.md - TiDB Cloud Hosted: ai/integrations/embedding-tidb-cloud-hosted.md - OpenAI: ai/integrations/embedding-openai.md - OpenAI Compatible: ai/integrations/embedding-openai-compatible.md - Cohere: ai/integrations/embedding-cohere.md - Jina AI: ai/integrations/embedding-jinaai.md - Google Gemini: ai/integrations/embedding-gemini.md - Hugging Face: ai/integrations/embedding-huggingface.md - NVIDIA NIM: ai/integrations/embedding-nvidia-nim.md extra: social: - icon: fontawesome/brands/github link: https://github.com/pingcap/pytidb - icon: fontawesome/brands/x-twitter link: https://twitter.com/TiDB_Developer - icon: fontawesome/brands/linkedin link: https://www.linkedin.com/company/pingcap analytics: provider: google property: G-W2XGDSWFBH extra_css: - styles/extra.css extra_javascript: - https://unpkg.com/mathjax@3/es5/tex-mml-chtml.js ================================================ FILE: pyproject.toml ================================================ # TiDB for AI Documentation # This project uses UV for fast dependency management # Install UV: curl -LsSf https://astral.sh/uv/install.sh | sh # Install deps: make install (which runs: uv pip install -e .) [project] name = "docs" version = "0.1.0" description = "The documentation for TiDB and its AI capabilities" readme = "README.md" requires-python = ">=3.12" dependencies = [ "mkdocs-material>=9.6.12", "mkdocs-jupyter>=0.25.1", "mkdocstrings[python]>=0.29.1", "mkdocs>=1.6.1", "mkdocs-redirects>=1.2.2", "requests>=2.31.0", "PyYAML>=6.0", "Jinja2>=3.1.0", "click>=8.0.0", ] ================================================ FILE: scripts/check_dependencies.py ================================================ #!/usr/bin/env python3 """Simple dependency check for TiDB for AI documentation.""" import sys import subprocess def main(): print("🚀 TiDB for AI Documentation - Quick Check") # Check UV try: result = subprocess.run(["uv", "--version"], capture_output=True, text=True) if result.returncode == 0: print("✅ UV is available") else: print("❌ UV not working") return 1 except FileNotFoundError: print("❌ UV not found - Install: curl -LsSf https://astral.sh/uv/install.sh | sh") return 1 # Check basic imports try: import mkdocs, requests, yaml print("✅ Dependencies are installed") except ImportError as e: print(f"❌ Missing dependency: {e}") print("💡 Run: make install") return 1 print("🎉 Ready to go! Run 'make serve' to start.") return 0 if __name__ == "__main__": sys.exit(main()) ================================================ FILE: scripts/generate_demos.py ================================================ #!/usr/bin/env python3 """ Generate demo gallery and individual demo documentation pages. This script reads configuration from demos.yml and generates: 1. Individual demo pages using demo_template.j2 2. Gallery index page using gallery_template.j2 """ import sys import requests import re import yaml from pathlib import Path from jinja2 import Environment, FileSystemLoader import click # Configuration LOCAL_EXAMPLES_DIR = Path("src/ai/examples") CONFIG_FILE = Path("demos.yml") DEMO_TEMPLATE_FILE = Path("src/templates/demo_page_template.j2") GALLERY_TEMPLATE_FILE = Path("src/templates/demo_gallery_template.j2") OUTPUT_FILE = LOCAL_EXAMPLES_DIR / "index.md" def load_config(): """Load configuration from YAML file.""" if not CONFIG_FILE.exists(): raise click.ClickException(f"Configuration file {CONFIG_FILE} not found.") try: with open(CONFIG_FILE, 'r', encoding='utf-8') as f: config = yaml.safe_load(f) return config except yaml.YAMLError as e: raise click.ClickException(f"Error parsing {CONFIG_FILE}: {e}") def fetch_readme_from_doc_link(doc_link): """Fetch README.md content from the provided doc_link.""" # Convert GitHub tree URL to raw content URL if "github.com" in doc_link and "/tree/" in doc_link: raw_url = doc_link.replace("github.com", "raw.githubusercontent.com").replace("/tree/", "/") elif doc_link.endswith("/README.md"): raw_url = doc_link else: # Assume it's a directory link, append README.md raw_url = doc_link.rstrip('/') + '/README.md' if "github.com" in raw_url and "/tree/" in raw_url: raw_url = raw_url.replace("github.com", "raw.githubusercontent.com").replace("/tree/", "/") try: response = requests.get(raw_url, timeout=30) response.raise_for_status() return response.text except requests.RequestException as e: click.echo(f"Error fetching README from {raw_url}: {e}", err=True) return None def extract_repo_info_from_doc_link(doc_link): """Extract repository and path information from doc_link.""" if "github.com" not in doc_link: return None, None, None, None # Parse URL to extract owner, repo, and path parts = doc_link.replace("https://github.com/", "").split("/") if len(parts) < 2: return None, None, None, None owner, repo = parts[0], parts[1] # Extract path after /tree/branch/ if "/tree/" in doc_link: try: tree_index = parts.index("tree") if len(parts) > tree_index + 2: # owner/repo/tree/branch/path... branch = parts[tree_index + 1] path_parts = parts[tree_index + 2:] # Remove README.md if present if path_parts and path_parts[-1] == "README.md": path_parts = path_parts[:-1] path = "/".join(path_parts) return owner, repo, branch, path except ValueError: pass return None, None, None, None def process_readme_content(content, demo_config): """Process README content to adapt it for the documentation site.""" if not content: return None # Extract repository info owner, repo, branch, example_path = extract_repo_info_from_doc_link(demo_config['doc_link']) if not all([owner, repo, branch, example_path]): click.echo(f"Warning: Could not extract repo info from {demo_config['doc_link']}", err=True) return content base_repo_url = f"https://github.com/{owner}/{repo}" base_raw_url = f"https://raw.githubusercontent.com/{owner}/{repo}/{branch}" # Fix relative links to point to the original repository processed_content = re.sub( r'\]\((?!https?://)(.*?)\)', f']({base_repo_url}/tree/{branch}/{example_path}/\\1)', content ) # Fix relative image links processed_content = re.sub( r'!\[([^\]]*)\]\((?!https?://)(.*?)\)', f'![\\1]({base_raw_url}/{example_path}/\\2)', processed_content ) return processed_content def create_demo_page(demo_config, content): """Create a markdown file for a demo using the demo template.""" if not DEMO_TEMPLATE_FILE.exists(): raise click.ClickException(f"Demo template file {DEMO_TEMPLATE_FILE} not found.") # Create the local examples directory if it doesn't exist LOCAL_EXAMPLES_DIR.mkdir(parents=True, exist_ok=True) try: # Set up Jinja2 environment env = Environment(loader=FileSystemLoader("src/templates")) template = env.get_template('demo_page_template.j2') # Render the template rendered_content = template.render( demo=demo_config, content=content ) # Create the markdown file filename = f"{demo_config['id'].replace('_', '-')}-with-pytidb.md" filepath = LOCAL_EXAMPLES_DIR / filename with open(filepath, 'w', encoding='utf-8') as f: f.write(rendered_content) return filepath except Exception as e: raise click.ClickException(f"Error creating demo page for {demo_config['id']}: {e}") def generate_gallery_page(config): """Generate the gallery page using Jinja2 template.""" if not GALLERY_TEMPLATE_FILE.exists(): raise click.ClickException(f"Gallery template file {GALLERY_TEMPLATE_FILE} not found.") try: # Set up Jinja2 environment env = Environment(loader=FileSystemLoader("src/templates")) template = env.get_template('demo_gallery_template.j2') # Render the template rendered_content = template.render( config=config, categories=config.get('categories', {}), demos=config.get('demos', {}) ) # Write the rendered content to the output file with open(OUTPUT_FILE, 'w', encoding='utf-8') as f: f.write(rendered_content) return True except Exception as e: raise click.ClickException(f"Error generating gallery page: {e}") def sync_demo_docs(config, fetch_from_remote=True): """Sync demo documentation files based on demos.yml configuration.""" if not fetch_from_remote: return [] created_files = [] demos_config = config.get('demos', []) with click.progressbar(demos_config, label='Processing demos') as demos: for demo_config in demos: demo_id = demo_config['id'] doc_link = demo_config.get('doc_link') if not doc_link: click.echo(f"Warning: No doc_link found for demo '{demo_id}', skipping...", err=True) continue # Fetch README content readme_content = fetch_readme_from_doc_link(doc_link) if readme_content: # Process content processed_content = process_readme_content(readme_content, demo_config) if processed_content: # Create demo page filepath = create_demo_page(demo_config, processed_content) if filepath: created_files.append((demo_id, filepath)) else: click.echo(f"Failed to process content for {demo_id}", err=True) else: click.echo(f"Failed to fetch README for {demo_id}", err=True) return created_files @click.command() @click.option('--skip-demos', is_flag=True, help='Skip generating individual demo pages from remote repositories') @click.option('--skip-gallery', is_flag=True, help='Skip generating the demo gallery index page') @click.option('--verbose', '-v', is_flag=True, help='Enable verbose output') def main(skip_demos, skip_gallery, verbose): """Generate demo gallery and individual demo documentation pages. This script reads configuration from demos.yml and generates: 1. Individual demo pages using demo_template.j2 2. Gallery index page using gallery_template.j2 By default, both demo pages and gallery are generated. """ if verbose: click.echo("Running in verbose mode...") # Load configuration try: config = load_config() except click.ClickException: raise created_files = [] # Generate demo pages (unless skipped) if not skip_demos: if verbose: click.echo("Generating demo pages from remote repositories...") created_files = sync_demo_docs(config, fetch_from_remote=True) if created_files: click.echo(f"\n✅ Generated {len(created_files)} demo pages:") for demo_id, filepath in created_files: click.echo(f" • {demo_id} → {filepath}") elif verbose: click.echo("No demo pages were generated.") else: if verbose: click.echo("Skipping demo page generation...") # Generate gallery page (unless skipped) if not skip_gallery: if verbose: click.echo("Generating gallery page from template...") if generate_gallery_page(config): click.echo(f"✅ Gallery page generated: {OUTPUT_FILE}") else: raise click.ClickException("Failed to generate gallery page.") else: if verbose: click.echo("Skipping gallery page generation...") # Check if nothing was generated if skip_demos and skip_gallery: click.echo("⚠️ Both demos and gallery generation were skipped. Nothing to do.") else: click.echo("\n🎉 Done! You can now run 'mkdocs serve' to view the documentation site.") if __name__ == "__main__": main() ================================================ FILE: scripts/sync_from_tidb_docs.py ================================================ import requests import re import sys def remove_custom_content_blocks(content): """Remove ... blocks from the content.""" return re.sub(r"", "", content) def collapse_extra_blank_lines(content): """Collapse 3 or more blank lines to 2 blank lines.""" return re.sub(r"\n{3,}", "\n\n", content) def convert_note_blocks(content): """Convert '> **Note:**' blocks to '!!! note' syntax with indented content.""" def note_repl(m): note_body = re.sub(r"^> ?", "", m.group(2), flags=re.MULTILINE).strip() indented = "\n".join( " " + line if line.strip() else "" for line in note_body.splitlines() ) return "!!! note\n\n" + indented + "\n\n" return re.sub(r"> \*\*Note:\*\*\n((?:> *\n)*)(> .*(?:\n|$)+)", note_repl, content) def convert_warning_blocks(content): """Convert '> **Warning:**' blocks to '!!! warning' syntax with indented content.""" def warning_repl(m): warning_body = re.sub(r"^> ?", "", m.group(2), flags=re.MULTILINE).strip() indented = "\n".join( " " + line if line.strip() else "" for line in warning_body.splitlines() ) return "!!! warning\n\n" + indented + "\n\n" return re.sub(r"> \*\*Warning:\*\*\n((?:> *\n)*)(> .*(?:\n|$)+)", warning_repl, content) def convert_tip_blocks(content): """Convert '> **Tip**' blocks to '!!! tip' syntax with indented content.""" def tip_repl(m): tip_body = re.sub(r"^> ?", "", m.group(2), flags=re.MULTILINE).strip() indented = "\n".join( " " + line if line.strip() else "" for line in tip_body.splitlines() ) return "!!! tip\n\n" + indented + "\n\n" return re.sub(r"> \*\*Tip:?\*\*\n((?:> *\n)*)(> .*(?:\n|$)+)", tip_repl, content) def remove_see_also_section(content): """Remove the '## See also' section and everything after it.""" return re.sub(r"## See also[\s\S]*$", "", content) def replace_image_paths(content): """Replace image paths to point to the local assets directory.""" return content.replace( "/media/vector-search/embedding-search.png", "../../assets/embedding-search.png" ) def replace_relative_doc_links(content): """Replace relative doc links with full tidbcloud doc links, remove .md suffix and 'vector-search/' in path.""" def link_repl(m): path = m.group(1) # Remove leading /, ./ or ../ path = re.sub(r"^/|^\./|^\.\./", "", path) path = path.replace("vector-search/", "") # Remove 'vector-search/' directory return f"(https://docs.pingcap.com/tidbcloud/{path})" return re.sub(r"\(((?:/|\./|\.\./)[^)]+?)\.md\)", link_repl, content) def remove_overview_from_title(content): """Remove 'Overview' from the main title if present.""" return re.sub( r"^(# .*)Overview(.*)$", lambda m: m.group(1).rstrip() + m.group(2) + "\n", content, flags=re.MULTILINE, ) def remove_front_matter(content): """Remove YAML front matter if present.""" return re.sub(r"^---[\s\S]*?---\n", "", content) def remove_simpletab_blocks(content): """Remove and
...
blocks, flattening their content.""" content = re.sub(r"|", "", content) content = re.sub(r'
', "", content) content = re.sub(r"
", "", content) return content def process_overview(): url = "https://raw.githubusercontent.com/pingcap/docs/refs/heads/master/vector-search/vector-search-overview.md" response = requests.get(url) content = response.text content = remove_custom_content_blocks(content) content = collapse_extra_blank_lines(content) content = convert_note_blocks(content) content = remove_see_also_section(content) content = replace_image_paths(content) content = replace_relative_doc_links(content) content = remove_overview_from_title(content) save_to_file(content, "./src/ai/concepts/vector-search.md") def process_llamaindex(): url = "https://raw.githubusercontent.com/pingcap/docs/master/vector-search/vector-search-integrate-with-llamaindex.md" response = requests.get(url) content = response.text content = remove_front_matter(content) content = remove_custom_content_blocks(content) content = remove_simpletab_blocks(content) content = collapse_extra_blank_lines(content) content = convert_warning_blocks(content) content = convert_note_blocks(content) content = convert_tip_blocks(content) content = remove_see_also_section(content) content = replace_image_paths(content) content = replace_relative_doc_links(content) save_to_file(content, "./src/ai/integrations/llamaindex.md") def process_langchain(): url = "https://raw.githubusercontent.com/pingcap/docs/master/vector-search/vector-search-integrate-with-langchain.md" response = requests.get(url) content = response.text content = remove_front_matter(content) content = remove_custom_content_blocks(content) content = remove_simpletab_blocks(content) content = collapse_extra_blank_lines(content) content = convert_warning_blocks(content) content = convert_note_blocks(content) content = convert_tip_blocks(content) content = remove_see_also_section(content) content = replace_image_paths(content) content = replace_relative_doc_links(content) save_to_file(content, "./src/ai/integrations/langchain.md") def save_to_file(content, filename): """Save the processed content to a file.""" with open(filename, "w") as f: f.write(content) def main(): if len(sys.argv) > 1: arg = sys.argv[1].lower() if arg in ("--llamaindex", "llamaindex"): process_llamaindex() print("llamaindex doc synced.") return elif arg in ("--langchain", "langchain"): process_langchain() print("langchain doc synced.") return elif arg in ("--overview", "overview"): process_overview() print("overview doc synced.") return else: print(f"Unknown argument: {arg}") print("Usage: python sync_from_tidb_docs.py [--llamaindex|--langchain|--overview]") return process_overview() print("overview doc synced (default).") if __name__ == "__main__": main() ================================================ FILE: src/ai/concepts/vector-search.md ================================================ --- title: Vector Search Overview summary: Learn about Vector Search in TiDB. This feature provides an advanced search solution for performing semantic similarity searches across various data types, including documents, images, audio, and video. --- # Vector Search Vector search offers a powerful solution for semantic similarity searches across diverse data types, such as documents, images, audio, and video. It allows developers to leverage their MySQL expertise to build scalable applications enriched with generative AI capabilities, simplifying the integration of advanced search functionality. !!! note The vector search feature is only available for TiDB Self-Managed clusters and [TiDB Cloud Starter](https://docs.pingcap.com/tidbcloud/select-cluster-tier#tidb-cloud-starter) clusters. ## Concepts Vector search is a search method that prioritizes the meaning of your data to deliver relevant results. Unlike traditional full-text search, which relies on exact keyword matching and word frequency, vector search converts various data types (such as text, images, or audio) into high-dimensional vectors and queries based on the similarity between these vectors. This search method captures the semantic meaning and contextual information of the data, leading to a more precise understanding of user intent. Even when the search terms do not exactly match the content in the database, vector search can still provide results that align with the user's intent by analyzing the semantics of the data. For example, a full-text search for "a swimming animal" only returns results containing these exact keywords. In contrast, vector search can return results for other swimming animals, such as fish or ducks, even if these results do not contain the exact keywords. ### Vector embedding A vector embedding, also known as an embedding, is a sequence of numbers that represents real-world objects in a high-dimensional space. It captures the meaning and context of unstructured data, such as documents, images, audio, and videos. Vector embeddings are essential in machine learning and serve as the foundation for semantic similarity searches. TiDB introduces [Vector data types](https://docs.pingcap.com/tidbcloud/vector-search-data-types) and [Vector search index](https://docs.pingcap.com/tidbcloud/vector-search-index) designed to optimize the storage and retrieval of vector embeddings, enhancing their use in AI applications. You can store vector embeddings in TiDB and perform vector search queries to find the most relevant data using these data types. ### Embedding model Embedding models are algorithms that transform data into [vector embeddings](#vector-embedding). Choosing an appropriate embedding model is crucial for ensuring the accuracy and relevance of semantic search results. For unstructured text data, you can find top-performing text embedding models on the [Massive Text Embedding Benchmark (MTEB) Leaderboard](https://huggingface.co/spaces/mteb/leaderboard). To learn how to generate vector embeddings for your specific data types, refer to integration tutorials or examples of embedding models. ## How vector search works After converting raw data into vector embeddings and storing them in TiDB, your application can execute vector search queries to find the data most semantically or contextually relevant to a user's query. TiDB vector search identifies the top-k nearest neighbor (KNN) vectors by using a [distance function](https://docs.pingcap.com/tidbcloud/vector-search-functions-and-operators) to calculate the distance between the given vector and vectors stored in the database. The vectors closest to the given vector in the query represent the most similar data in meaning. ![The Schematic TiDB Vector Search](../../assets/embedding-search.png) As a relational database with integrated vector search capabilities, TiDB enables you to store data and their corresponding vector representations (that is, vector embeddings) together in one database. You can choose any of the following ways for storage: - Store data and their corresponding vector representations in different columns of the same table. - Store data and their corresponding vector representation in different tables. In this way, you need to use `JOIN` queries to combine the tables when retrieving data. ## Use cases ### Retrieval-Augmented Generation (RAG) Retrieval-Augmented Generation (RAG) is an architecture designed to optimize the output of Large Language Models (LLMs). By using vector search, RAG applications can store vector embeddings in the database and retrieve relevant documents as additional context when the LLM generates responses, thereby improving the quality and relevance of the answers. ### Semantic search Semantic search is a search technology that returns results based on the meaning of a query, rather than simply matching keywords. It interprets the meaning across different languages and various types of data (such as text, images, and audio) using embeddings. Vector search algorithms then use these embeddings to find the most relevant data that satisfies the user's query. ### Recommendation engine A recommendation engine is a system that proactively suggests content, products, or services that are relevant and personalized to users. It accomplishes this by creating embeddings that represent user behavior and preferences. These embeddings help the system identify similar items that other users have interacted with or shown interest in. This increases the likelihood that the recommendations will be both relevant and appealing to the user. ================================================ FILE: src/ai/examples/auto-embedding-with-pytidb.md ================================================ --- title: Auto Embedding description: "Automatically generate embeddings for your text data using built-in embedding models." source_repo: "https://github.com/pingcap/pytidb/tree/main/examples/auto_embedding" --- # Auto Embedding Demo This example showcases how to use the auto embedding feature with PyTiDB Client. * Connect to TiDB with PyTiDB Client * Define a table with a VectorField configured for automatic embedding * Insert plain text data, embeddings are populated automatically in the background * Run vector searches with natural language queries, embedding happens transparently ## Prerequisites - **Python 3.10+** - **A TiDB Cloud Starter cluster**: Create a free cluster here: [tidbcloud.com ↗️](https://tidbcloud.com/?utm_source=github&utm_medium=referral&utm_campaign=pytidb_readme) ## How to run **Step 1**: Clone the repository ```bash git clone https://github.com/pingcap/pytidb.git cd pytidb/examples/auto_embedding/ ``` **Step 2**: Install the required packages ```bash python -m venv .venv source .venv/bin/activate pip install -r reqs.txt ``` **Step 3**: Set up environment to connect to database Go to [TiDB Cloud console](https://tidbcloud.com/clusters) to get the connection parameters and set up the environment variable like this: ```bash cat > .env < .env < E-commerce product search with full-text search

E-commerce product search with full-text search

## Prerequisites - **Python 3.10+** - **A TiDB Cloud Starter cluster**: Create a free cluster here: [tidbcloud.com ↗️](https://tidbcloud.com/?utm_source=github&utm_medium=referral&utm_campaign=pytidb_readme) ## How to run **Step 1**: Clone the repository to local ```bash git clone https://github.com/pingcap/pytidb.git cd pytidb/examples/fulltext_search/; ``` **Step 2**: Install the required packages and setup environment ```bash python -m venv .venv source .venv/bin/activate pip install -r reqs.txt ``` **Step 3**: Set up environment to connect to database Go to the [TiDB Cloud console](https://tidbcloud.com/), create a new cluster if you don't have one, and then get the connection parameters on the connection dialog. ```bash cat > .env < TiDB Hybrid Search Demo

TiDB Hybrid Search Demo

## Prerequisites * Python 3.10+ * TiDB database instance (👉 [Create a free TiDB Serverless Cluster](https://tidbcloud.com/free-trial)) * OpenAI API key (Go to [OpenAI](https://platform.openai.com/api-keys) to get the API key) > **Note** > > Currently, full-text search is only available for the following product option and region: > > - TiDB Cloud Starter: Frankfurt (eu-central-1), Singapore (ap-southeast-1) ## How to run **Step 1**: Clone the repository ```bash git clone https://github.com/pingcap/pytidb.git cd pytidb/examples/hybrid_search; ``` **Step 2**: Install the required packages and setup environment ```bash python -m venv .venv source .venv/bin/activate pip install -r reqs.txt ``` **Step 3**: Set up environment to connect to storage If you are using TiDB Cloud, you can find the connection parameters in the [TiDB Cloud console](https://tidbcloud.com/). ```bash cat > .env < EOF ``` **Step 4**: Run the demo **Option 1**: Run the Streamlit app If you want to check the demo with a web UI, you can run the following command: ```bash streamlit run app.py ``` Open the browser and visit `http://localhost:8501` **Option 2**: Run the demo script If you want to check the demo with a script, you can run the following command: ```bash python example.py ``` Expected output: ``` === CONNECT TO TIDB === Connected to TiDB. === CREATE TABLE === Table created. === INSERT SAMPLE DATA === Inserted 3 rows. === PERFORM HYBRID SEARCH === Search results: [ { "_distance": 0.4740166257687124, "_match_score": 1.6804268, "_score": 0.03278688524590164, "id": 60013, "text": "TiDB is a distributed database that supports OLTP, OLAP, HTAP and AI workloads." }, { "_distance": 0.6428459116216618, "_match_score": 0.78427225, "_score": 0.03200204813108039, "id": 60015, "text": "LlamaIndex is a Python library for building AI-powered applications." }, { "_distance": 0.641581407158715, "_match_score": null, "_score": 0.016129032258064516, "id": 60014, "text": "PyTiDB is a Python library for developers to connect to TiDB." } ] ``` --- ## Related Resources - **Source Code**: [View on GitHub](https://github.com/pingcap/pytidb/tree/main/examples/hybrid_search) - **Category**: Search - **Description**: Combine vector search and fulltext search for more comprehensive results. [🏠 Back to Demo Gallery](../index.md){ .md-button .md-button--primary } ================================================ FILE: src/ai/examples/image-search-with-pytidb.md ================================================ --- title: Image Search description: "Build an image search application using multimodal embeddings for both text-to-image and image-to-image search." source_repo: "https://github.com/pingcap/pytidb/tree/main/examples/image_search" --- # Pet Image Search Demo This example showcases how to build a powerful image search application by combining TiDB's vector search capabilities with multimodal embedding models. With just a few lines of code, you can create an intelligent search system that understands both text and images. - 🔍 **Text-to-Image Search**: Find the perfect pet photos by describing what you're looking for in natural language - from "fluffy orange cat" - 🖼️ **Image-to-Image Search**: Upload a photo and instantly discover visually similar pets based on breed, color, pose and more

PyTiDB Image Search Demo

Pet image search via multimodal embeddings

## Prerequisites - **Python 3.10+** - **A TiDB Cloud Starter cluster**: Create a free cluster here: [tidbcloud.com ↗️](https://tidbcloud.com/?utm_source=github&utm_medium=referral&utm_campaign=pytidb_readme) - **Jina AI API Key**: Get your free API key at [jina.ai Embeddings ↗️](https://jina.ai/embeddings/) ## How to run **Step 1**: Clone the repository to local ```bash git clone https://github.com/pingcap/pytidb.git cd pytidb/examples/image_search/ ``` **Step 2**: Install the required packages ```bash python -m venv .venv source .venv/bin/activate # Windows: .venv\Scripts\activate pip install -r reqs.txt ``` **Step 3**: Set up environment variables Go to [TiDB Cloud console](https://tidbcloud.com/clusters) and get the connection parameters, then set up the environment variable like this: ```bash cat > .env < /* CSS Variables */ :root { --brand-color: #de243d; --brand-hover: #b71e34; --border-radius-sm: 0.5rem; --border-radius-md: 0.75rem; --border-radius-lg: 1rem; --spacing-sm: 1rem; --spacing-md: 2rem; --spacing-lg: 3rem; --transition-fast: 0.2s; --transition-normal: 0.3s; --dark-overlay: rgba(255, 255, 255, 0.08); --dark-border: rgba(255, 255, 255, 0.1); --dark-bg-subtle: rgba(255, 255, 255, 0.05); } /* Smooth scrolling for the entire page */ html { scroll-behavior: smooth; } /* Gallery Container */ .gallery-container { max-width: 1280px; margin: 0 auto; padding: var(--spacing-md) var(--spacing-sm); } /* Header */ .gallery-header { text-align: center; margin-bottom: var(--spacing-lg); } .gallery-title { font-size: 72px !important; font-weight: 800 !important; margin-bottom: 8px !important; line-height: 1 !important; color: var(--md-default-fg-color) !important; } .gallery-description { font-size: 22px !important; color: var(--md-default-fg-color--light) !important; padding: 0 120px; margin-bottom: 5rem !important; } /* Gallery CTA link styles */ .gallery-cta-link { position: relative; text-decoration: none; transition: all 0.3s ease-in-out; } .gallery-cta-link:hover { border-bottom: 3px solid var(--brand-color); } /* Layout */ .gallery-layout { display: flex; gap: var(--spacing-sm) !important; } /* Sidebar */ .gallery-sidebar { width: 8rem; flex-shrink: 0; } .sidebar-nav { position: sticky; top: 140px; } .sidebar-title { font-size: 14px !important; font-weight: 400 !important; color: var(--md-default-fg-color--light) !important; text-transform: uppercase; letter-spacing: 0.05em; margin: 0 0 0.5rem 0 !important; } .sidebar-links { display: flex; flex-direction: column; gap: 2px; margin-left: -12px; } .sidebar-link { display: block; padding: 8px 12px; border-radius: var(--border-radius-sm); font-size: 14px; font-weight: 400 !important; color: var(--md-default-fg-color--light) !important; text-decoration: none !important; transition: all var(--transition-fast) ease; text-align: left; cursor: pointer; } .sidebar-link:hover { background-color: var(--md-default-fg-color--lightest) !important; color: var(--md-default-fg-color) !important; font-weight: 500 !important; transform: translateX(2px); } .sidebar-link:focus-visible { outline: 2px solid var(--brand-color); outline-offset: 2px; } /* Content */ .gallery-content { flex: 1; padding: 0 var(--spacing-lg); } .gallery-section { margin-bottom: var(--spacing-lg); scroll-margin-top: 120px; } .section-title { font-size: 24px !important; font-weight: 700 !important; color: var(--md-default-fg-color) !important; margin: 0 0 1.5rem 0 !important; } .cards-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--spacing-sm) !important; } /* Cards */ .gallery-card { display: block; background: var(--md-default-bg-color); border: 1px solid var(--md-default-fg-color--lightest); border-radius: var(--border-radius-md); overflow: hidden; transition: all var(--transition-normal) ease; text-decoration: none !important; color: inherit; } .gallery-card:hover { transform: translateY(-2px); box-shadow: var(--md-shadow-z2); text-decoration: none !important; outline: 2px solid var(--brand-color); outline-offset: 2px; } .gallery-card:hover .card-title { color: var(--brand-color) !important; } .card-image { height: 8rem; position: relative; overflow: hidden; background-color: var(--md-default-fg-color--lightest); border-bottom: 1px solid var(--md-default-fg-color--lightest); } .card-image img { width: 100%; height: 100%; object-fit: cover; } .card-gradient { display: flex; align-items: center; justify-content: center; font-size: 2.5rem; } .card-badge { position: absolute; top: 0.5rem; left: 0.5rem; background: rgba(0, 0, 0, 0.7); color: white; padding: 0.2rem 0.4rem; border-radius: 0.2rem; font-size: 0.5rem !important; font-weight: 500 !important; } .card-content { padding: 12px; } .card-title { font-size: 0.75rem !important; font-weight: 600 !important; line-height: 1.5 !important; margin: 0 !important; color: var(--md-default-fg-color) !important; } .card-description { color: var(--md-default-fg-color--light) !important; font-size: 0.65rem !important; line-height: 1.5; display: -webkit-box; margin: 0; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; } /* CTA */ .gallery-cta { background: linear-gradient(135deg, rgba(222, 36, 61, 0.08) 0%, rgba(99, 102, 241, 0.08) 100%); border: 1px solid rgba(222, 36, 61, 0.1); border-radius: var(--border-radius-lg); padding: var(--spacing-md); text-align: center; margin-top: var(--spacing-lg); } .cta-title { font-size: 1.5rem; font-weight: 700; color: var(--md-default-fg-color); margin-bottom: var(--spacing-sm); } .cta-description { color: var(--md-default-fg-color--light); margin: 0 auto var(--spacing-md); max-width: 42rem; } .cta-buttons { display: flex; justify-content: center; gap: var(--spacing-sm); flex-wrap: wrap; } /* Button shared styles */ .btn-primary, .btn-secondary { padding: 0.75rem 1.5rem; border-radius: var(--border-radius-sm); font-weight: 500; text-decoration: none !important; transition: all var(--transition-fast); } .btn-primary { background-color: var(--brand-color); color: white !important; } .btn-primary:hover { background-color: var(--brand-hover); color: white !important; } .btn-secondary { border: 1px solid var(--md-default-fg-color--lighter); background-color: var(--md-default-bg-color); color: var(--md-default-fg-color) !important; } .btn-secondary:hover { background-color: var(--md-default-fg-color--lightest); color: var(--md-default-fg-color) !important; } /* Dark mode styles */ [data-md-color-scheme="tidb-dark"] .sidebar-link:hover { background-color: var(--dark-overlay) !important; } [data-md-color-scheme="tidb-dark"] .gallery-card { border-color: var(--dark-border); } [data-md-color-scheme="tidb-dark"] .card-image { background-color: var(--dark-bg-subtle); border-bottom-color: var(--dark-border); } [data-md-color-scheme="tidb-dark"] .gallery-cta { background: linear-gradient(135deg, rgba(222, 36, 61, 0.12) 0%, rgba(99, 102, 241, 0.12) 100%); border-color: rgba(222, 36, 61, 0.2); } [data-md-color-scheme="tidb-dark"] .btn-secondary:hover { background-color: rgba(255, 255, 255, 0.1); } /* Responsive adjustments */ @media (max-width: 768px) { .gallery-layout { flex-direction: column; } .gallery-sidebar { width: 100%; } .sidebar-nav { position: static; } .sidebar-links { flex-direction: row; gap: 0.5rem; flex-wrap: wrap; } .sidebar-link { padding: 12px 16px !important; min-height: 44px; display: flex; align-items: center; } .gallery-content { padding: 0; } .gallery-description { padding: 0 20px; } .cards-grid { grid-template-columns: 1fr; } .gallery-title { font-size: 48px !important; } } @media (max-width: 1024px) and (min-width: 769px) { .cards-grid { grid-template-columns: repeat(2, 1fr); } } ================================================ FILE: src/ai/examples/memory-with-pytidb.md ================================================ --- title: Memory description: "Implement conversation memory for chatbots and conversational AI applications." source_repo: "https://github.com/pingcap/pytidb/tree/main/examples/memory" --- # AI Agent Memory Demo This example showcases how to build an intelligent AI agent with persistent memory powered by TiDB's vector search capabilities. With just a few lines of code, you can create a conversational AI that remembers past interactions and builds context over time. - 🧠 **Persistent Memory**: The AI remembers conversations across sessions and user interactions - 💬 **Interactive Chat**: Both web interface and command-line options for flexible interaction - 👤 **Multi-User Support**: Different users can have separate memory contexts - 🔍 **Real-Time Memory Viewing**: Visual display of all stored memories in the web interface

AI Agent with memory powered by TiDB

AI Agent with memory powered by TiDB

## Prerequisites - **Python 3.10+** - **A TiDB Cloud Starter cluster**: Create a free cluster here: [tidbcloud.com ↗️](https://tidbcloud.com/?utm_source=github&utm_medium=referral&utm_campaign=pytidb_readme) - **OpenAI API Key**: Get your API key at [OpenAI Platform ↗️](https://platform.openai.com/api-keys) ## How to run **Step 1**: Clone the repository to local ```bash git clone https://github.com/pingcap/pytidb.git cd pytidb/examples/memory/ ``` **Step 2**: Install the required packages ```bash python -m venv .venv source .venv/bin/activate # Windows: .venv\Scripts\activate pip install -r reqs.txt ``` **Step 3**: Set up environment variables Go to [TiDB Cloud console](https://tidbcloud.com/clusters) and get the connection parameters, then set up the environment variable like this: ```bash cat > .env < RAG application built with PyTiDB

RAG application built with PyTiDB

## Prerequisites - **Python 3.10+** - **A TiDB Cloud Starter cluster**: Create a free cluster here: [tidbcloud.com ↗️](https://tidbcloud.com/?utm_source=github&utm_medium=referral&utm_campaign=pytidb_readme) - **Ollama**: You can install it from [Ollama ↗️](https://ollama.com/download) ## How to run **Step 1**: Prepare the inference API Pull the embedding and LLM model via ollama CLI: ```bash ollama pull mxbai-embed-large ollama pull gemma3:4b ollama run gemma3:4b ``` Test the `/embed` and `/generate` endpoints to make sure they are running: ```bash curl http://localhost:11434/api/embed -d '{ "model": "mxbai-embed-large", "input": "Llamas are members of the camelid family" }' ``` ```bash curl http://localhost:11434/api/generate -d '{ "model": "gemma3:4b", "prompt": "Hello, Who are you?" }' ``` **Step 2**: Clone the repository to local ```bash git clone https://github.com/pingcap/pytidb.git cd pytidb/examples/rag/; ``` **Step 3**: Install the required packages and setup environment ```bash python -m venv .venv source .venv/bin/activate pip install -r reqs.txt ``` **Step 4**: Set up environment to connect to database Go to [TiDB Cloud console](https://tidbcloud.com/clusters) and get the connection parameters, then set up the environment variable like this: ```bash cat > .env < Semantic search with vector embeddings

Semantic search with vector embeddings

## Prerequisites - **Python 3.10+** - **A TiDB Cloud Starter cluster**: Create a free cluster here: [tidbcloud.com ↗️](https://tidbcloud.com/?utm_source=github&utm_medium=referral&utm_campaign=pytidb_readme) - **Ollama**: You can install it from [Ollama ↗️](https://ollama.com/download) ## How to run **Step 1**: Start the embedding service with Ollama Pull the embedding model: ```bash ollama pull mxbai-embed-large ``` Test the embedding service to make sure it is running: ```bash curl http://localhost:11434/api/embed -d '{ "model": "mxbai-embed-large", "input": "Llamas are members of the camelid family" }' ``` **Step 2**: Clone the repository to local ```bash git clone https://github.com/pingcap/pytidb.git cd pytidb/examples/vector_search/ ``` **Step 3**: Install the required packages and set up the environment ```bash python -m venv .venv source .venv/bin/activate pip install -r reqs.txt ``` **Step 4**: Set up environment to connect to TiDB Go to [TiDB Cloud console](https://tidbcloud.com/clusters) and get the connection parameters, then set up the environment variable like this: ```bash cat > .env <": { "": }, ... } ``` - ``: The key can be a column name, a JSON path expression to access a JSON field (see [Metadata filtering](./vector-search.md#metadata-filtering)), or a [logical operator](#logical-operators). - ``: The operator can be a [compare operator](#compare-operators) or an [inclusion operator](#inclusion-operators). - ``: The value can be a scalar value, an array, it depends on the operator. **Example: Filter records where `created_at` is greater than 2024-01-01** ```python table.query({ # The `created_at` is a scalar field with DATETIME type "created_at": { "$gt": "2024-01-01" } }) ``` **Example: Filter records where `meta.category` is in the array ["tech", "science"]** ```python results = ( table.search("some query", search_type="vector") .filter({ # The `meta` is a JSON field, and its value is a JSON object like {"category": "tech"} "meta.category": { "$in": ["tech", "science"] } }) .limit(10) .to_list() ) ``` ### Compare operators You can use the following compare operators to filter records: | Operator | Description | |----------|-----------------------------------| | `$eq` | Equal to value | | `$ne` | Not equal to value | | `$gt` | Greater than value | | `$gte` | Greater than or equal to value | | `$lt` | Less than value | | `$lte` | Less than or equal to value | **Example: filter records where `user_id` is equal to 1** ```python { "user_id": { "$eq": 1 } } ``` You can omit the `$eq` operator. The following query is equivalent to the above: ```python { "user_id": 1 } ``` ### Inclusion operators You can use the following inclusion operators to filter records: | Operator | Description | |----------|-----------------------------------| | `$in` | In array (string, int, or float) | | `$nin` | Not in array (string, int, float) | **Example: Filter records where `category` is in the array ["tech", "science"]** ```python { "category": { "$in": ["tech", "science"] } } ``` ### Logical operators You can use the logical operators `$and` and `$or` to combine multiple filters. | Operator | Description | |----------|-----------------------------------------------------| | `$and` | Returns results that match **all** filters in the list | | `$or` | Returns results that match **any** filter in the list | **Syntax for using `$and` or `$or`:** ```python { "$and|$or": [ { "field_name": { : } }, { "field_name": { : } } ... ] } ``` **Example: using `$and` to combine multiple filters:** ```python { "$and": [ { "created_at": { "$gt": "2024-01-01" } }, { "meta.category": { "$in": ["tech", "science"] } } ] } ``` ## SQL String Filters === "Python" You can also use a SQL string as the `filters` parameter. The string should be a valid SQL `WHERE` clause (without the `WHERE` keyword) using TiDB's SQL syntax. **Example: Filter records where `created_at` is greater than 2024-01-01** ```python results = table.query( filters="created_at > '2024-01-01'", limit=10 ).to_list() ``` **Example: Filter records where the JSON field `meta.category` equals 'tech'** ```python results = table.query( filters="meta->>'$.category' = 'tech'", limit=10 ).to_list() ``` You can combine multiple conditions using `AND`, `OR`, and parentheses, and use any [SQL operators](https://docs.pingcap.com/tidbcloud/operators/) supported by TiDB. !!! warning When using SQL string filters with dynamic user input, always validate the input to prevent [SQL injection](https://en.wikipedia.org/wiki/SQL_injection) vulnerabilities. ================================================ FILE: src/ai/guides/fulltext-search.md ================================================ # Full-text Search **Full-text search** enables you to find documents or data by matching keywords or phrases within the entire text content. It is widely used in search engines, document management, e-commerce, and any scenario where users need to search large volumes of unstructured or semi-structured text. TiDB provides full-text search capabilities for **massive datasets** with high performance and built-in **multilingual support**. !!! note Full-text search is currently in the early stages with limited accessibility. It is only available for **TiDB Cloud Starter** in the following regions: - **Frankfurt (eu-central-1)** - **Singapore (ap-southeast-1)** If you have feedback or need help, feel free to reach out to us on [Discord](https://discord.gg/zcqexutz2R). !!! tip For a complete example of full-text search, see the [E-commerce product search demo](../examples/fulltext-search-with-pytidb.md). ## Basic Usage ### Step 1. Create Table and Full-text Index === "Python" You can use `FullTextField` to define a text field with full-text search enabled. The `fts_parser` parameter in Python corresponds to the `WITH PARSER` clause in SQL. For example, the following code creates a table with a full-text index on the `title` column: ```python hl_lines="6" from pytidb.schema import TableModel, Field, FullTextField class Item(TableModel): __tablename__ = "items" id: int = Field(primary_key=True) title: str = FullTextField(fts_parser="MULTILINGUAL") table = client.create_table(schema=Item, if_exists="overwrite") ``` The `fts_parser` parameter specifies the parser for the full-text index. Supported values: - `STANDARD`: Fast, works for English content, splits words by spaces and punctuation. - `MULTILINGUAL` (default): Supports multiple languages, including English, Chinese, Japanese, and Korean. === "SQL" Create a table with a full-text index: ```sql hl_lines="4" CREATE TABLE items( id INT PRIMARY KEY, title TEXT, FULLTEXT INDEX (title) WITH PARSER MULTILINGUAL ); ``` You can also add a full-text index to an existing table with a separate statement: ```sql CREATE TABLE items( id INT PRIMARY KEY, title TEXT ); ALTER TABLE items ADD FULLTEXT INDEX (title) WITH PARSER MULTILINGUAL ADD_COLUMNAR_REPLICA_ON_DEMAND; ``` The following parsers are supported in the `WITH PARSER ` clause: - `STANDARD`: Fast, works for English content, splits words by spaces and punctuation. - `MULTILINGUAL`: Supports multiple languages, including English, Chinese, Japanese, and Korean. ### Step 2. Insert Sample Data For demonstration purposes, the following sample data covers English, Japanese, and Chinese text. === "Python" You can use the `bulk_insert` method to insert sample data into the table. ```python table.bulk_insert([ Item(id=1, title="Bluetooth Earphones, HiFi sound, 48h battery, Fast charge, Low latency"), Item(id=2, title="Bluetooth 5.3 Headphones, Noise Cancelling, Immersive sound, Comfortable"), Item(id=3, title="IPX7 Waterproof Earbuds, Sport ready, Touch control, High-quality music"), Item(id=4, title="Sports Earbuds, Secure fit, Sweatproof, Long battery, Workout support"), Item(id=5, title="Wired Headphones, Studio-grade, HD sound, Comfortable, Pro music experience"), Item(id=6, title="Bluetoothイヤホン HiFi音質 48hバッテリー 急速充電 低遅延"), Item(id=7, title="Bluetooth5.3ヘッドホン ノイズキャンセリング 没入サウンド 快適装着"), Item(id=8, title="IPX7防水イヤホン スポーツ対応 タッチ操作 高音質音楽"), Item(id=9, title="スポーツイヤホン 安定装着 防汗 長持ちバッテリー ワークアウト対応"), Item(id=10, title="有線ヘッドホン スタジオ級 HDサウンド 快適装着 プロ音楽体験"), Item(id=11, title="无线蓝牙耳机 HiFi音质 48小时超长续航 快速充电 低延迟"), Item(id=12, title="蓝牙5.3降噪头戴式耳机 杜比全景声 沉浸音效 舒适佩戴 畅享静谧音乐时光"), Item(id=13, title="IPX7防水真无线耳机 运动无忧 智能触控 随时畅听高品质音乐"), Item(id=14, title="运动专用耳机 稳固佩戴 防汗设计 超长续航 低延迟音频 高清通话"), Item(id=15, title="录音室级有线耳机 高清音质 舒适佩戴 可拆卸线材 多设备兼容 降噪麦克风"), ]) ``` === "SQL" You can use the `INSERT INTO` statement to insert the sample data into the table. ```sql INSERT INTO items (id, title) VALUES (1, 'Bluetooth Earphones, HiFi sound, 48h battery, Fast charge, Low latency'), (2, 'Bluetooth 5.3 Headphones, Noise Cancelling, Immersive sound, Comfortable'), (3, 'IPX7 Waterproof Earbuds, Sport ready, Touch control, High-quality music'), (4, 'Sports Earbuds, Secure fit, Sweatproof, Long battery, Workout support'), (5, 'Wired Headphones, Studio-grade, HD sound, Comfortable, Pro music experience'), (6, 'Bluetoothイヤホン HiFi音質 48hバッテリー 急速充電 低遅延'), (7, 'Bluetooth5.3ヘッドホン ノイズキャンセリング 没入サウンド 快適装着'), (8, 'IPX7防水イヤホン スポーツ対応 タッチ操作 高音質音楽'), (9, 'スポーツイヤホン 安定装着 防汗 長持ちバッテリー ワークアウト対応'), (10, '有线ヘッドホン スタジオ级 HDサウンド 快适装着 プロ音楽体験'), (11, '无线蓝牙耳机 HiFi音质 48小时超长续航 快速充电 低延迟'), (12, '蓝牙5.3降噪头戴式耳机 杜比全景声 沉浸音效 舒适佩戴 畅享静谧音乐时光'), (13, 'IPX7防水真无线耳机 运动无忧 智能触控 随时畅听高品质音乐'), (14, '运动专用耳机 稳固佩戴 防汗设计 超长续航 低延迟音频 高清通话'), (15, '录音室级有线耳机 高清音质 舒适佩戴 可拆卸线材 多设备兼容 降噪麦克风'); ``` ### Step 3. Perform a Full-text Search === "Python" To perform a full-text search with pytidb, use the `search` method and set the `search_type` parameter to `"fulltext"`. **Example: Search for the 3 most relevant documents** ```python results = table.search("Bluetooth Headphones", search_type="fulltext").limit(3).to_list() print(json.dumps(results, indent=2, ensure_ascii=False)) ``` ```python title="Execution result" [ { "id": 2, "title": "Bluetooth 5.3 Headphones, Noise Cancelling, Immersive sound, Comfortable", "_match_score": 3.7390857, "_score": 3.7390857 }, { "id": 5, "title": "Wired Headphones, Studio-grade, HD sound, Comfortable, Pro music experience", "_match_score": 1.9798478, "_score": 1.9798478 }, { "id": 1, "title": "Bluetooth Earphones, HiFi sound, 48h battery, Fast charge, Low latency", "_match_score": 1.620981, "_score": 1.620981 } ] ``` The results are sorted by relevance, with the most relevant documents listed first. The `_match_score` (or `_score`) field indicates the relevance score of each document, calculated using the [BM25](https://en.wikipedia.org/wiki/Okapi_BM25) algorithm—a widely used ranking function in information retrieval. **Example: Search for the 3 most relevant documents in another language** ```python results = table.search("蓝牙耳机", search_type="fulltext").limit(3).to_list() print(json.dumps(results, indent=2, ensure_ascii=False)) ``` ```python title="Execution result" [ { "id": 11, "title": "无线蓝牙耳机 HiFi音质 48小时超长续航 快速充电 低延迟", "_match_score": 3.000002, "_score": 3.000002 }, { "id": 12, "title": "蓝牙5.3降噪头戴式耳机 杜比全景声 沉浸音效 舒适佩戴 畅享静谧音乐时光", "_match_score": 2.5719738, "_score": 2.5719738 }, { "id": 14, "title": "运动专用耳机 稳固佩戴 防汗设计 超长续航 低延迟音频 高清通话", "_match_score": 1.1418362, "_score": 1.1418362 } ] ``` === "SQL" To perform a full-text search, use the `fts_match_word()` function. **Example: Search for the 3 most relevant documents** ```sql SELECT *, fts_match_word("Bluetooth Headphones", title) AS score FROM items WHERE fts_match_word("Bluetooth Headphones", title) ORDER BY score DESC LIMIT 3; ``` ```plain title="Execution result" +----+-----------------------------------------------------------------------------+-----------+ | id | title | score | +----+-----------------------------------------------------------------------------+-----------+ | 2 | Bluetooth 5.3 Headphones, Noise Cancelling, Immersive sound, Comfortable | 3.7390857 | | 5 | Wired Headphones, Studio-grade, HD sound, Comfortable, Pro music experience | 1.9798478 | | 1 | Bluetooth Earphones, HiFi sound, 48h battery, Fast charge, Low latency | 1.620981 | +----+-----------------------------------------------------------------------------+-----------+ ``` The results are ordered by relevance, with the most relevant documents first. **Example: Search for the 3 most relevant documents in another language** ```sql SELECT *, fts_match_word("蓝牙耳机", title) AS score FROM items WHERE fts_match_word("蓝牙耳机", title) ORDER BY score DESC LIMIT 3; ``` ```plain title="Execution result" +----+------------------------------------------------------------------+-----------+ | id | title | score | +----+------------------------------------------------------------------+-----------+ | 11 | 无线蓝牙耳机 HiFi音质 48小时超长续航 快速充电 低延迟 | 3.000002 | | 12 | 蓝牙5.3降噪头戴式耳机 杜比全景声 沉浸音效 舒适佩戴 畅享静谧音乐时光 | 2.5719738 | | 14 | 运动专用耳机 稳固佩戴 防汗设计 超长续航 低延迟音频 高清通话 | 1.1418362 | +----+------------------------------------------------------------------+-----------+ ``` ## See Also In Retrieval-Augmented Generation (RAG) scenarios, it is often beneficial to utilize both full-text search and vector search for optimal results. - Learn how to combine these approaches in the [hybrid search guide](./hybrid-search.md). - For more on vector search, see the [vector search guide](../concepts/vector-search.md). ================================================ FILE: src/ai/guides/hybrid-search.md ================================================ # Hybrid Search Hybrid search is a technique that combines multiple search algorithms to deliver more accurate and relevant results. TiDB supports both semantic search (also known as vector search) and keyword-based search (full-text search). By leveraging the strengths of both approaches, you can achieve superior search results through hybrid search.

hybrid search overview

!!! tip For a complete example of hybrid search, refer to the [hybrid-search example](../examples/hybrid-search-with-pytidb.md). ## Basic Usage ### Step 1. Define an Embedding Function Define an embedding function to generate vector representations of text data. ```python from pytidb.embeddings import EmbeddingFunction embed_fn = EmbeddingFunction( model_name="openai/text-embedding-3-small", api_key=os.getenv("OPENAI_API_KEY"), ) ``` ### Step 2. Create a Table with Vector and Full-Text Indexes === "Python" After you have [connected to your TiDB database](./connect.md) using `TiDBClient` and get the `client` instance: You can now create a table with both a `FullTextField` and a `VectorField` to store the text data and its vector embedding. Example: ```python from pytidb.schema import TableModel, Field, FullTextField class Chunk(TableModel): __tablename__ = "chunks_for_hybrid_search" id: int = Field(primary_key=True) text: str = FullTextField() text_vec: list[float] = embed_fn.VectorField(source_field="text") table = client.create_table(schema=Chunk, if_exists="overwrite") ``` In this example, PyTiDB will automatically create a full-text index on the `text` column and a vector index on the `text_vec` column. ### Step 3. Insert Sample Data === "Python" Use the `bulk_insert()` method to insert sample data into the table. ```python table.truncate() table.bulk_insert([ Chunk( text="TiDB is a distributed database that supports OLTP, OLAP, HTAP and AI workloads.", ), Chunk( text="PyTiDB is a Python library for developers to connect to TiDB.", ), Chunk( text="LlamaIndex is a Python library for building AI-powered applications.", ), ]) ``` The `text_vec` field is automatically populated with the vector embedding of the text data via the [Auto Embedding](../guides/auto-embedding.md) feature. ### Step 4. Perform Hybrid Search To enable hybrid search, set the `search_type` parameter to `hybrid` when calling the `search()` method. ```python results = ( table.search( "AI database", search_type="hybrid" ) .limit(3) .to_list() ) for item in results: item.pop("text_vec") print(json.dumps(results, indent=4, sort_keys=True)) ``` The search results contain three special fields: - `_distance`: The distance between the query vector and the vector data in the table, as returned by the vector search. - `_match_score`: The match score between the query and the text field, as returned by the full-text search. - `_score`: The final score of the search result, calculated by the fusion algorithm. ```json title="Output" [ { "_distance": 0.4740166257687124, "_match_score": 1.6804268, "_score": 0.03278688524590164, "id": 60013, "text": "TiDB is a distributed database that supports OLTP, OLAP, HTAP and AI workloads." }, { "_distance": 0.6428459116216618, "_match_score": 0.78427225, "_score": 0.03200204813108039, "id": 60015, "text": "LlamaIndex is a Python library for building AI-powered applications." }, { "_distance": 0.641581407158715, "_match_score": null, "_score": 0.016129032258064516, "id": 60014, "text": "PyTiDB is a Python library for developers to connect to TiDB." } ] ``` ## Fusion Methods Fusion methods combine results from vector (semantic) and full-text (keyword) searches into a single, unified ranking. This ensures that the final results leverage both semantic relevance and keyword matching. PyTiDB supports two fusion methods: - `rrf`: Reciprocal Rank Fusion (default) - `weighted`: Weighted Score Fusion You can select the fusion method that best fits your use case to optimize hybrid search results. ### Reciprocal Rank Fusion (RRF) Reciprocal Rank Fusion (RRF) is an algorithm that evaluates search results by leveraging the rank of documents in multiple result sets. For more details, see the [RRF paper](https://plg.uwaterloo.ca/~gvcormac/cormacksigir09-rrf.pdf). === "Python" Enable reciprocal rank fusion by specifying the `method` parameter as `"rrf"` in the `.fusion()` method. ```python results = ( table.search( "AI database", search_type="hybrid" ) .fusion(method="rrf") .limit(3) .to_list() ) ``` Parameters: - `k`: A constant (default: 60) to prevent division by zero and control the impact of high-ranked documents. ### Weighted Score Fusion Weighted Score Fusion combines vector search and full-text search scores using weighted sum: ```python final_score = vs_weight * vector_score + fts_weight * fulltext_score ``` === "Python" Enable weighted score fusion by specifying the `method` parameter as `"weighted"` in the `.fusion()` method. For example, to give more weight to vector search, set the `vs_weight` parameter to 0.7 and the `fts_weight` parameter to 0.3: ```python results = ( table.search( "AI database", search_type="hybrid" ) .fusion(method="weighted", vs_weight=0.7, fts_weight=0.3) .limit(3) .to_list() ) ``` Parameters: - `vs_weight`: The weight of the vector search score. - `fts_weight`: The weight of the full-text search score. ## Rerank Method Hybrid search also supports reranking using reranker-specific models. === "Python" Use the `rerank()` method to specify a reranker that sorts search results by relevance between the query and the documents. **Example: Using JinaAI Reranker to rerank the hybrid search results** ```python reranker = Reranker( # Use the `jina-reranker-m0` model model_name="jina_ai/jina-reranker-m0", api_key="{your-jinaai-api-key}" ) results = ( table.search( "AI database", search_type="hybrid" ) .fusion(method="rrf", k=60) .rerank(reranker, "text") .limit(3) .to_list() ) ``` To check other reranker models, see the [Reranking](../guides/reranking.md) guide. ================================================ FILE: src/ai/guides/image-search.md ================================================ # Image search **Image search** helps you find similar images by comparing their visual content, not just text or metadata. This feature is useful for e-commerce, content moderation, digital asset management, and any scenario where you need to search for or deduplicate images based on appearance. TiDB enables image search using **vector search**. With automatic embedding, you can generate image embeddings from image URLs, PIL images, or keyword text using a multimodal embedding model. TiDB then efficiently searches for similar vectors at scale. !!! tip For a complete example of image search, see the [Pet image search demo](../examples/image-search-with-pytidb.md). ## Basic usage ### Step 1. Define an embedding function To generate image embeddings, you need an embedding model that supports image input. For demonstration, you can use Jina AI's multimodal embedding model to generate image embeddings. Go to [Jina AI](https://jina.ai/embeddings) to create an API key, then initialize the embedding function as follows: ```python hl_lines="7" from pytidb.embeddings import EmbeddingFunction image_embed = EmbeddingFunction( # Or another provider/model that supports multimodal input model_name="jina_ai/jina-embedding-v4", api_key="{your-jina-api-key}", multimodal=True, ) ``` ### Step 2. Create a table and vector field Use `VectorField()` to define a vector field for storing image embeddings. Set the `source_field` parameter to specify the field that stores image URLs. ```python from pytidb.schema import TableModel, Field class ImageItem(TableModel): __tablename__ = "image_items" id: int = Field(primary_key=True) image_uri: str = Field() image_vec: list[float] = image_embed.VectorField( source_field="image_uri" ) table = client.create_table(schema=ImageItem, if_exists="overwrite") ``` ### Step 3. Insert image data When you insert data, the `image_vec` field is automatically populated with the embedding generated from the `image_uri`. ```python table.bulk_insert([ ImageItem(image_uri="https://example.com/image1.jpg"), ImageItem(image_uri="https://example.com/image2.jpg"), ImageItem(image_uri="https://example.com/image3.jpg"), ]) ``` ### Step 4. Perform image search Image search is a type of vector search. Automatic embedding lets you input an image URL, PIL image, or keyword text directly. All these inputs are converted to vector embeddings for similarity matching. #### Option 1: Search by image URL Search for similar images by providing an image URL: ```python results = table.search("https://example.com/query.jpg").limit(3).to_list() ``` The client converts the input image URL into a vector. TiDB then finds and returns the most similar images by comparing their vectors. #### Option 2: Search by PIL image You can also search for similar images by providing an image file or bytes: ```python from PIL import Image image = Image.open("/path/to/query.jpg") results = table.search(image).limit(3).to_list() ``` The client converts the PIL image object into a Base64 string before sending it to the embedding model. #### Option 3: Search by keyword text You can also search for similar images by providing keyword text. For example, if you are working on a pet image dataset, you can search for similar images by keywords like "orange tabby cat" or "golden retriever puppy". ```python results = table.search("orange tabby cat").limit(3).to_list() ``` The keyword text will be converted to a vector embedding that captures the semantic meaning by the multimodal embedding model, and then a vector search will be performed to find the images whose embeddings are most similar to the keyword embedding. ## See also - [Automatic embedding guide](./auto-embedding.md) - [Vector search guide](../concepts/vector-search.md) - [Pet image search demo](../examples/image-search-with-pytidb.md) ================================================ FILE: src/ai/guides/joins.md ================================================ # Multiple Table Joins As a relational database, TiDB allows you to store diverse data in tables with different structures (for example: `chunks`, `documents`, `users`, `chats`) in a single database. Moreover, you can use joins to combine data from multiple tables to perform complex queries. ## Basic Usage ### Step 1. Create tables and insert sample data === "Python" Assuming you have already [connected to the TiDB database](./connect.md) via TiDBClient: Create a `documents` table and insert some sample data: ```python from pytidb import Session from pytidb.schema import TableModel, Field from pytidb.sql import select class Document(TableModel): __tablename__ = "documents" id: int = Field(primary_key=True) title: str = Field(max_length=255) client.create_table(schema=Document, if_exists="overwrite") client.table("documents").truncate() client.table("documents").bulk_insert([ Document(id=1, title="The Power of Positive Thinking"), Document(id=2, title="The Happiness Advantage"), Document(id=3, title="The Art of Happiness"), ]) ``` Create a `chunks` table and insert some sample data: ```python class Chunk(TableModel): __tablename__ = "chunks" id: int = Field(primary_key=True) text: str = Field(max_length=255) document_id: int = Field(foreign_key="documents.id") client.create_table(schema=Chunk, if_exists="overwrite") client.table("chunks").truncate() client.table("chunks").bulk_insert([ Chunk(id=1, text="Positive thinking can change your life", document_id=1), Chunk(id=2, text="Happiness leads to success", document_id=2), Chunk(id=3, text="Finding joy in everyday moments", document_id=3), ]) ``` === "SQL" Create a `documents` table and insert some sample data: ```sql CREATE TABLE documents ( id INT PRIMARY KEY, title VARCHAR(255) NOT NULL ); INSERT INTO documents (id, title) VALUES (1, 'The Power of Positive Thinking'), (2, 'The Happiness Advantage'), (3, 'The Art of Happiness'); ``` Create a `chunks` table and insert some sample data: ```sql CREATE TABLE chunks ( id INT PRIMARY KEY, text VARCHAR(255) NOT NULL, document_id INT NOT NULL, FOREIGN KEY (document_id) REFERENCES documents(id) ); INSERT INTO chunks (id, text, document_id) VALUES (1, 'Positive thinking can change your life', 1), (2, 'Happiness leads to success', 2), (3, 'Finding joy in everyday moments', 3); ``` ### Step 2. Perform a join query === "Python" ```python with Session(client.db_engine) as db_session: query = ( select(Chunk) .join(Document, Chunk.document_id == Document.id) .where(Document.title == "The Power of Positive Thinking") ) chunks = db_session.exec(query).all() [(c.id, c.text, c.document_id) for c in chunks] ``` === "SQL" Perform a join query to combine data from the `chunks` and `documents` tables: ```sql SELECT c.id, c.text, c.document_id FROM chunks c JOIN documents d ON c.document_id = d.id WHERE d.title = 'The Power of Positive Thinking'; ``` ================================================ FILE: src/ai/guides/raw-queries.md ================================================ # Raw Queries ## Operate data with raw SQL You can use `client.execute()` method to execute `INSERT`, `UPDATE`, `DELETE` and other data manipulation SQL statements. ```python client.execute("INSERT INTO chunks(text, user_id) VALUES ('sample text', 5)") ``` ### SQL injection prevention Both of the `execute` and `query` methods are support the **Parameterized SQL** feature, which help you avoid [SQL injection](https://en.wikipedia.org/wiki/SQL_injection) while building dynamic SQL statements. ```python client.execute( "INSERT INTO chunks(text, user_id) VALUES (:text, :user_id)", { "text": "sample text", "user_id": 6, }, ) ``` ## Query data with rawSQL You can use `client.query()` method to execute `SELECT`, `SHOW` and other query SQL statements. ### Output query result The `client.query()` method will return a `SQLQueryResult` instance with some helper methods: - `to_pydantic()` - `to_list()` - `to_pandas()` - `to_rows()` - `scalar()` #### As Pydantic model The `to_pydantic()` method will return a list of Pydantic models. ```python client.query("SELECT id, text, user_id FROM chunks").to_pydantic() ``` #### As SQLAlchemy result rows The `to_rows()` method will return a list of tuple, every tuple represent of one row of data. ```python client.query("SHOW TABLES;").to_rows() ``` #### As list of dict The `to_list()` method will convert the query result into a list of dict. ```python client.query( "SELECT id, text, user_id FROM chunks WHERE user_id = :user_id", { "user_id": 3 } ).to_list() ``` #### As pandas DataFrame The `to_pandas()` method to convert the query result to a `pandas.DataFrame`, which is displayed as human-friendly style on the notebook: ```python client.query("SELECT id, text, user_id FROM chunks").to_pandas() ``` #### As scalar value The `scalar()` method will return the first column of the first row of the result set. ```python client.query("SELECT COUNT(*) FROM chunks;").scalar() ``` ================================================ FILE: src/ai/guides/reranking.md ================================================ # Reranking Reranking is a technique used to improve the relevance and accuracy of search results by re-evaluating and reordering them using a dedicated rerank model. The search process works in two stages: 1. **Initial Retrieval**: Vector search identifies the top `k` most similar documents from the collection 2. **Reranking**: A reranking model evaluates these `k` documents based on the relevance between the query and the documents and reorders them to produce the final top `n` results (where `n` ≤ `k`) This two-stage retrieval approach significantly improves both document relevance and accuracy. ## Basic Usage === "Python" PyTiDB provides the `Reranker` class that allows you to use reranker models from multiple third-party providers. 1. Create a reranker instance ```python from pytidb.rerankers import Reranker reranker = Reranker(model_name="{provider}/{model_name}") ``` 2. Apply reranker via `.rerank()` method ```python table.search("{query}").rerank(reranker, "{field_to_rerank}").limit(3) ``` ## Supported Providers Here are some examples to use reranker models from third-party providers. ### Jina AI To enable reranker provided by JinaAI, go to their [website](https://jina.ai/reranker) to create a API key. For example: ```python jinaai = Reranker( # Using the `jina-reranker-m0` model model_name="jina_ai/jina-reranker-m0", api_key="{your-jinaai-api-key}" ) ``` ================================================ FILE: src/ai/guides/tables.md ================================================ # Working with tables TiDB uses tables to organize and store collections of related data. It provides flexible schema definition capabilities, allowing you to structure your tables according to your specific requirements. A table can contain multiple columns with different data types to store various kinds of data. Supported data types include text, numbers, vectors, binary data (`BLOB`), JSON, and more. !!! tip For a complete working example, see the [basic example](https://github.com/pingcap/pytidb/tree/main/examples/basic) in our repository. ## Create a table ### Using TableModel TiDB provides a `TableModel` class that represents the schema of a table. This class is compatible with the [Pydantic Model](https://docs.pydantic.dev/latest/concepts/models/) and allows you to define the table structure in a declarative way. In the following example, you create a table named `items` with these columns: - `id`: a primary key column with an integer type - `content`: a text type column - `embedding`: a vector type column with 3 dimensions - `meta`: a JSON type column === "Python" After you [connect to the database](./connect.md) using PyTiDB and obtain a `client` instance, you can create a table with the `create_table` method. ```python hl_lines="12" from pytidb.schema import TableModel, Field, VectorField from pytidb.datatype import TEXT, JSON class Item(TableModel): __tablename__ = "items" id: int = Field(primary_key=True) content: str = Field(sa_type=TEXT) embedding: list[float] = VectorField(dimensions=3) meta: dict = Field(sa_type=JSON, default_factory=dict) table = client.create_table(schema=Item, if_exists="overwrite") ``` The `create_table` method accepts these parameters: - `schema`: The `TableModel` class that defines your table structure. - `if_exists`: The creation mode of the table. - `raise` (default): Creates the table if it does not exist; raises an error if it already exists. - `skip`: Creates the table if it does not exist; does nothing if it already exists. - `overwrite`: Drops the existing table and creates a new one. This is useful for **testing and development**, but not recommended for production environments. Once the table is created, you can use the `table` object to insert, update, delete, and query data. === "SQL" Use the `CREATE TABLE` statement to create a table. ```sql CREATE TABLE items ( id INT PRIMARY KEY, content TEXT, embedding VECTOR(3), meta JSON ); ``` ## Add data to a table ### With TableModel You can use a `TableModel` instance to represent a record and insert it into the table. To insert a single record: === "Python" Use the `table.insert()` method to insert a single record into the table. ```python table.insert( Item( id=1, content="TiDB is a distributed SQL database", embedding=[0.1, 0.2, 0.3], meta={"category": "database"}, ) ) ``` === "SQL" Use the `INSERT INTO` statement to insert a single record into the table. ```sql INSERT INTO items(id, content, embedding, meta) VALUES (1, 'TiDB is a distributed SQL database', '[0.1, 0.2, 0.3]', '{"category": "database"}'); ``` To insert multiple records: === "Python" Use the `table.bulk_insert()` method to insert multiple records into the table. ```python table.bulk_insert([ Item( id=2, content="GPT-4 is a large language model", embedding=[0.4, 0.5, 0.6], meta={"category": "llm"}, ), Item( id=3, content="LlamaIndex is a Python library for building AI-powered applications", embedding=[0.7, 0.8, 0.9], meta={"category": "rag"}, ), ]) ``` === "SQL" Use the `INSERT INTO` statement to insert multiple records into the table. ```sql INSERT INTO items(id, content, embedding, meta) VALUES (2, 'GPT-4 is a large language model', '[0.4, 0.5, 0.6]', '{"category": "llm"}'), (3, 'LlamaIndex is a Python library for building AI-powered applications', '[0.7, 0.8, 0.9]', '{"category": "rag"}'); ``` ### With Dict You can also use `dict` to represent records and insert them into the table. This approach is more flexible and doesn't require to use a `TableModel` to insert data. To insert a single record: === "Python" Use the `table.insert()` method with a dictionary to insert a single record into the table. ```python table.insert({ "id": 1, "content": "TiDB is a distributed SQL database", "embedding": [0.1, 0.2, 0.3], "meta": {"category": "database"}, }) ``` === "SQL" Use the `INSERT INTO` statement to insert a single record into the table. ```sql INSERT INTO items(id, content, embedding, meta) VALUES (1, 'TiDB is a distributed SQL database', '[0.1, 0.2, 0.3]', '{"category": "database"}'); ``` ## Save data to a table The `save` method provides a convenient way to insert or update a single record. If a record with the specified primary key does not exist, it creates a new record. If the record already exists, it overwrites the entire record. !!! note If a record ID already exists, `table.save()` function overwrites the entire record. To change only part of a record, use `table.update()`. === "Python" Use the `table.save()` method to save a single record to the table. **Example: Save a new record** ```python saved_record = table.save( Item( id=4, content="Vector databases enable AI applications", embedding=[1.0, 1.1, 1.2], meta={"category": "vector-db"}, ) ) ``` **Example: Save an existing record (overwrites the entire record)** ```python # This overwrites the entire record with id=1 updated_record = table.save( Item( id=1, # Existing ID content="Updated content for TiDB", embedding=[0.2, 0.3, 0.4], meta={"category": "updated"}, ) ) ``` === "SQL" Use the `INSERT ... ON DUPLICATE KEY UPDATE` statement to save a record. **Example: Save a new record or update if it exists** ```sql INSERT INTO items(id, content, embedding, meta) VALUES (4, 'Vector databases enable AI applications', '[1.0, 1.1, 1.2]', '{"category": "vector-db"}') ON DUPLICATE KEY UPDATE content = VALUES(content), embedding = VALUES(embedding), meta = VALUES(meta); ``` ## Query data from a table To fetch records from a table: === "Python" Use the `table.query()` method to fetch the records from the table. **Example: Fetch the first 10 records** ```python result = table.query(limit=10).to_list() ``` === "SQL" Use the `SELECT` statement to fetch the records from the table. **Example: Fetch the first 10 records** ```sql SELECT * FROM items LIMIT 10; ``` To fetch records based on query conditions: === "Python" Pass the `filters` parameter to the `table.query()` method. ```python result = table.query( filters={"meta.category": "database"}, limit=10 ).to_list() ``` === "SQL" Use the `WHERE` clause to filter records. **Example: Fetch the 10 records with category "database"** ```sql SELECT * FROM items WHERE meta->>'$.category' = 'database' LIMIT 10; ``` For a complete list of supported filter operations and examples, refer to the [filtering](./filtering.md) guide. ## Update data in a table === "Python" Use the `table.update()` method to update records with [filters](./filtering.md). **Example: Update the record whose `id` equals 1** ```python table.update( values={ "content": "TiDB Cloud Starter is a fully managed, auto-scaling cloud database service" "embedding": [0.1, 0.2, 0.4], "meta": {"category": "dbass"}, }, filters={ "id": 1 }, ) ``` === "SQL" Use the `UPDATE` statement to update records with [filters](./filtering.md). **Example: Update the record whose `id` equals 1** ```sql UPDATE items SET content = 'TiDB Cloud Starter is a fully managed, auto-scaling cloud database service', embedding = '[0.1, 0.2, 0.4]', meta = '{"category": "dbass"}' WHERE id = 1; ``` ## Delete from a table === "Python" Use the `table.delete()` method to delete records with [filters](./filtering.md). **Example: Delete the record where `id` equals 2** ```python table.delete( filters={ "id": 2 } ) ``` === "SQL" Use the `DELETE` statement to delete records with [filters](./filtering.md). **Example: Delete the record where `id` equals 2** ```sql DELETE FROM items WHERE id = 2; ``` ## Truncate a table === "Python" To remove all data from the table but keep the table structure, use the `table.truncate()` method. ```python table.truncate() ``` To check that the table is truncated, verify that it contains 0 rows. ```python table.rows() ``` === "SQL" To remove all data from the table but keep the table structure, use the `TRUNCATE TABLE` statement. ```sql TRUNCATE TABLE items; ``` To check that the table is truncated, verify that it contains 0 rows. ```sql SELECT COUNT(*) FROM items; ``` ## Drop a table === "Python" To permanently remove a table from the database, use the `client.drop_table()` method. ```python client.drop_table("items") ``` To check that the table is removed from the database: ```python client.table_names() ``` === "SQL" To permanently remove a table from the database, use the `DROP TABLE` statement. ```sql DROP TABLE items; ``` To check that the table is removed from the database: ```sql SHOW TABLES; ``` ================================================ FILE: src/ai/guides/transaction.md ================================================ # Transaction TiDB supports ACID transactions, which ensure data consistency and reliability. ## Basic Usage === "Python" ```python with client.session() as session: initial_total_balance = session.query("SELECT SUM(balance) FROM players").scalar() # Transfer 10 coins from player 1 to player 2 session.execute("UPDATE players SET balance = balance - 10 WHERE id = 1") session.execute("UPDATE players SET balance = balance + 10 WHERE id = 2") session.commit() # or session.rollback() final_total_balance = session.query("SELECT SUM(balance) FROM players").scalar() assert final_total_balance == initial_total_balance ``` ## See also - [TiDB Develop Guide - Transaction](https://docs.pingcap.com/tidbcloud/dev-guide-transaction-overview/) - [TiDB Docs- SQL Reference - Transactions](https://docs.pingcap.com/tidbcloud/transaction-overview/) ================================================ FILE: src/ai/guides/vector-search.md ================================================ # Vector Search Vector search uses semantic similarity to help you find the most relevant records, even if your query does not explicitly include all the keywords. !!! tip For a complete example of vector search, see the [vector-search example](../examples/vector-search-with-pytidb.md). ## Basic Usage This section shows you how to use vector search in your application in minimal steps. Before you start, you need to [connect to the database](./connect.md). ### Step 1. Create a table with a vector field === "Python" You can use `client.create_table()` to create a table and use `VectorField` to define a vector field. In this example, we create a table named `documents` with four columns: - `id`: The primary key of the table. - `text`: The text content of the document. - `text_vec`: The vector embedding of the text content. - `meta`: The metadata of the document, which is a JSON object. ```python hl_lines="9" from pytidb.schema import TableModel, Field, VectorField from pytidb.datatype import TEXT, JSON class Document(TableModel): __tablename__ = "documents" id: int = Field(primary_key=True) text: str = Field(sa_type=TEXT) text_vec: list[float] = VectorField(dimensions=3) meta: dict = Field(sa_type=JSON, default_factory=dict) table = client.create_table(schema=Document, if_exists="overwrite") ``` The `VectorField` class accepts the following parameters: - `dimensions`: The number of dimensions of the vector. Once specified, only vectors with this exact dimension can be stored in this field. - `index`: Whether to create a [vector index](https://docs.pingcap.com/tidbcloud/vector-search-index/) for the vector field. Defaults to `True`. - `distance_metric`: The distance metric to use for the vector index. Supported values: - `DistanceMetric.COSINE` (default): Cosine distance metric, suitable for measuring text similarity - `DistanceMetric.L2`: L2 distance metric, suitable for capturing overall difference === "SQL" You can use the `CREATE TABLE` statement to create a table and using `VECTOR` type to define a vector column. ```sql hl_lines="4 5" CREATE TABLE documents ( id INT PRIMARY KEY, text TEXT, text_vec VECTOR(3), VECTOR INDEX `vec_idx_text_vec`((VEC_COSINE_DISTANCE(`text_vec`))) ); ``` In this example: - The `text_vec` column is defined as a `VECTOR` type with 3 dimensions, it means that the vector to be stored in this column must have 3 dimensions. - A vector index is created using the `VEC_COSINE_DISTANCE` function to optimize vector search performance TiDB supports two distance functions for vector indexes: - `VEC_COSINE_DISTANCE`: Calculates the cosine distance between two vectors - `VEC_L2_DISTANCE`: Calculates L2 distance (Euclidean distance) between two vectors ### Step 2. Insert vector data into the table For demonstration purposes, insert some text and their corresponding vector embeddings into the table. In this example, we use simple 3-dimensional vectors. We insert three documents: - `dog` with the vector embedding `[1, 2, 1]` - `fish` with the vector embedding `[1, 2, 4]` - `tree` with the vector embedding `[1, 0, 0]` === "Python" ```python table.bulk_insert([ Document(text="dog", text_vec=[1,2,1], meta={"category": "animal"}), Document(text="fish", text_vec=[1,2,4], meta={"category": "animal"}), Document(text="tree", text_vec=[1,0,0], meta={"category": "plant"}), ]) ``` === "SQL" ```sql INSERT INTO documents (id, text, text_vec, meta) VALUES (1, 'dog', '[1,2,1]', '{"category": "animal"}'), (2, 'fish', '[1,2,4]', '{"category": "animal"}'), (3, 'tree', '[1,0,0]', '{"category": "plant"}'); ``` !!! tip In real-world applications, vector embeddings are usually generated by an [embedding model](../concepts/vector-search.md#embedding-model). For convenience, pytidb provides an auto embedding feature that can automatically generate vector embeddings for your text fields when you insert, update, or search—no manual processing needed. For details, see the [Auto Embedding](./auto-embedding.md) guide. ### Step 3. Perform vector search Vector search uses vector distance metrics to measure the similarity and relevance between vectors. The closer the distance, the more relevant the record. To find the most relevant documents in the table, you need to specify a query vector. In this example, we assume the query is `A swimming animal` and its vector embedding is `[1, 2, 3]`. === "Python" You can use the `table.search()` method to perform vector search, which uses `search_mode="vector"` by default. ```python table.search([1, 2, 3]).limit(3).to_list() ``` ```python title="Execution result" [ {"id": 2, "text": "fish", "text_vec": [1,2,4], "_distance": 0.00853986601633272}, {"id": 1, "text": "dog", "text_vec": [1,2,1], "_distance": 0.12712843905603044}, {"id": 3, "text": "tree", "text_vec": [1,0,0], "_distance": 0.7327387580875756}, ] ``` The result shows that the most relevant document is `fish` with a distance of `0.00853986601633272`. === "SQL" You can use the `ORDER BY (, ) LIMIT ` clause in the `SELECT` statement to get the n nearest neighbors of the query vector. In this example, we use the `vec_cosine_distance` function to calculate the cosine distance between the vectors stored in the `text_vec` column and the provided query vector `[1, 2, 3]`. ```sql SELECT id, text, vec_cosine_distance(text_vec, '[1,2,3]') AS distance FROM documents ORDER BY distance LIMIT 3; ``` ```plain title="Execution result" +----+----------+---------------------+ | id | text | distance | +----+----------+---------------------+ | 2 | fish | 0.00853986601633272 | | 1 | dog | 0.12712843905603044 | | 3 | tree | 0.7327387580875756 | +----+----------+---------------------+ 3 rows in set (0.15 sec) ``` The result shows that the most relevant document is `fish` with a distance of `0.00853986601633272`. ## Distance metrics Distance metrics are a measure of the similarity between a pair of vectors. Currently, TiDB supports the following distance metrics: === "Python" The `table.search()` API supports the following distance metrics: | Metric Name | Description | Best For | |--------------------------|----------------------------------------------------------------|----------| | `DistanceMetric.COSINE` | Calculates the cosine distance between two vectors (default). Measures the angle between vectors. | Text embeddings, semantic search | | `DistanceMetric.L2` | Calculates the L2 distance (Euclidean distance) between two vectors. Measures the straight-line distance. | Image features | To change the distance metric used for vector search, use the `.distance_metric()` method. **Example: Use the L2 distance metric** ```python from pytidb.schema import DistanceMetric results = ( table.search([1, 2, 3]) .distance_metric(DistanceMetric.L2) .limit(10) .to_list() ) ``` === "SQL" In SQL, you can use the following built-in functions to calculate vector distances directly in your queries: | Function Name | Description | |-------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------| | [`VEC_L2_DISTANCE`](https://docs.pingcap.com/tidbcloud/vector-search-functions-and-operators/#vec_l2_distance) | Calculates L2 distance (Euclidean distance) between two vectors | | [`VEC_COSINE_DISTANCE`](https://docs.pingcap.com/tidbcloud/vector-search-functions-and-operators/#vec_cosine_distance) | Calculates the cosine distance between two vectors | | [`VEC_NEGATIVE_INNER_PRODUCT`](https://docs.pingcap.com/tidbcloud/vector-search-functions-and-operators/#vec_negative_inner_product) | Calculates the negative of the inner product between two vectors| | [`VEC_L1_DISTANCE`](https://docs.pingcap.com/tidbcloud/vector-search-functions-and-operators/#vec_l1_distance) | Calculates L1 distance (Manhattan distance) between two vectors | ## Distance threshold The `table.search()` API allows you to set a distance threshold to control the similarity of the returned results. By specifying this threshold, you can exclude less similar vectors and return only those that meet your relevance criteria. === "Python" Use the `.distance_threshold()` method to set a maximum distance for the search results. Only records with a distance less than the threshold are returned. **Example: Only return documents with a distance less than 0.5** ```python results = table.search([1, 2, 3]).distance_threshold(0.5).limit(10).to_list() ``` === "SQL" In SQL, use the `HAVING` clause with a distance function to filter results by distance: **Example: Only return documents with a distance less than 0.1** ```sql SELECT id, text, vec_cosine_distance(text_vec, '[1,2,3]') AS distance FROM documents HAVING distance < 0.1 ORDER BY distance LIMIT 10; ``` ## Distance range The `table.search()` API also supports specifying a distance range to further refine the results. === "Python" Use the `.distance_range()` method to set both minimum and maximum distance values. Only records with a distance within this range are returned. **Example: Only return documents with a distance between 0.01 and 0.05** ```python results = table.search([1, 2, 3]).distance_range(0.01, 0.05).limit(10).to_list() ``` === "SQL" To specify a distance range in SQL, use `BETWEEN` or other comparison operators in the `HAVING` clause: **Example: Only return documents with a distance between 0.01 and 0.05** ```sql SELECT id, text, vec_l2_distance(text_vec, '[1,2,3]') AS distance FROM documents HAVING distance BETWEEN 0.01 AND 0.05 ORDER BY distance LIMIT 10; ``` ## Metadata filtering As a relational database, TiDB supports a rich set of [SQL operators](https://docs.pingcap.com/tidbcloud/operators/) and allows flexible combinations of filtering conditions. For vector search in TiDB, you can apply metadata filtering on scalar fields (e.g., integers, strings) or JSON fields. Typically, vector search combined with metadata filtering operates in two modes: - **Post-filtering**: In a two-stage retrieval process, TiDB first performs vector search to retrieve the top-k candidate results from the entire vector space, then applies the filter to this candidate set. The vector search stage typically leverages a vector index for efficiency. - **Pre-filtering**: The filter is applied before vector search. If the filter is highly selective and the filtered field is indexed with a scalar index, this approach can significantly reduce the search space and improve performance. ### Post-filtering === "Python" Use the `.filter()` method with a filter dictionary to apply filtering to vector search. By default, the `table.search()` API uses post-filtering mode to maximize search performance with the vector index. **Example: Vector search with post-filtering** ```python results = ( table.search([1, 2, 3]) # The `meta` is a JSON field, and its value is a JSON object # like {"category": "animal"} .filter({"meta.category": "animal"}) .num_candidate(50) .limit(10) .to_list() ) ``` !!! tip When using a vector index, if the final `limit` is very small, the accuracy of the results may decrease. You can use the `.num_candidate()` method to control how many candidates to retrieve from the vector index during the vector search phase, without changing the `limit` parameter. A higher `num_candidate` value generally improves recall but may reduce query performance. Adjust this value based on your dataset and accuracy requirements. === "SQL" Currently, vector indexes are only effective in strict ANN (Approximate Nearest Neighbor) queries, such as: ```sql SELECT * FROM ORDER BY () LIMIT ``` In other words, you cannot use a `WHERE` clause together with a vector index in the same query. If you need to combine vector search with additional filtering conditions, you can use the post-filtering pattern. In this approach, the ANN query will be divided into two parts: - The inner query performs the vector search using the vector index. - The outer query applies the `WHERE` condition to filter the results. ```sql hl_lines="8" SELECT * FROM ( SELECT id, text, meta, vec_cosine_distance(text_vec, '[1,2,3]') AS distance FROM documents ORDER BY distance LIMIT 50 ) candidates WHERE meta->>'$.category' = 'animal' ORDER BY distance LIMIT 10; ``` !!! tip The post-filtering pattern may lead to false positives — for example, the inner query may retrieve the top 50 most similar records, but none of them match the `WHERE` condition. To mitigate this, you can increase the `LIMIT` value (e.g., 50) in the **inner query** to fetch more candidates, improving the chances of returning enough valid results after filtering. For supported SQL operators, see [Operators](https://docs.pingcap.com/tidbcloud/operators/) in the TiDB Cloud documentation. ### Pre-filtering === "Python" To enable pre-filtering, set the `prefilter` parameter to `True` in the `.filter()` method. **Example: Vector search with pre-filtering** ```python results = ( table.search([1, 2, 3]) .filter({"meta.category": "animal"}, prefilter=True) .limit(10) .to_list() ) ``` For supported filter operators, see [Filtering](./filtering.md). === "SQL" In SQL, use the `->>` operator or `JSON_EXTRACT` to access JSON fields in the `WHERE` clause: ```sql SELECT id, text, meta, vec_cosine_distance(text_vec, '[1,2,3]') AS distance FROM documents WHERE meta->>'$.category' = 'animal' ORDER BY distance LIMIT 10; ``` For supported SQL operators, see [Operators](https://docs.pingcap.com/tidbcloud/operators/) in the TiDB Cloud documentation. ## Multiple vector fields TiDB supports defining multiple vector columns in a single table, allowing you to store and search different types of vector embeddings. For example, you can store both text embeddings and image embeddings in the same table, making it convenient to manage multi-modal data. === "Python" You can define multiple vector fields in the schema and perform vector search on the specified vector field by using the `.vector_column()` method. **Example: Specify the vector field to search on** ```python hl_lines="6 8 17" # Create a table with multiple vector fields class RichTextDocument(TableModel): __tablename__ = "rich_text_documents" id: int = Field(primary_key=True) text: str = Field(sa_type=TEXT) text_vec: list[float] = VectorField(dimensions=3) image_url: str image_vec: list[float] = VectorField(dimensions=3) table = client.create_table(schema=RichTextDocument, if_exists="overwrite") # Insert sample data ... # Search using image vector field results = ( table.search([1, 2, 3]) .vector_column("image_vec") .distance_metric(DistanceMetric.COSINE) .limit(10) .to_list() ) ``` === "SQL" You can create multiple vector columns in a table and search them using suitable distance functions: ```sql -- Create a table with multiple vector fields CREATE TABLE rich_text_documents ( id BIGINT PRIMARY KEY, text TEXT, text_vec VECTOR(3), image_url VARCHAR(255), image_vec VECTOR(3) ); -- Insert sample data ... -- Search using text vector SELECT id, image_url, vec_l2_distance(image_vec, '[4,5,6]') AS image_distance FROM rich_text_documents ORDER BY image_distance LIMIT 10; ``` ## Output search results === "Python" The `table.search()` API lets you convert search results into several common data processing formats: ### As SQLAlchemy result rows To work with raw SQLAlchemy result rows, use: ```python table.search([1, 2, 3]).limit(10).to_rows() ``` ### As a list of Python dictionaries For easier manipulation in Python, convert the results to a list of dictionaries: ```python table.search([1, 2, 3]).limit(10).to_list() ``` ### As a pandas DataFrame To display results in a user-friendly table—especially useful in Jupyter notebooks—convert them to a pandas DataFrame: ```python table.search([1, 2, 3]).limit(10).to_pandas() ``` ### As a list of Pydantic model instances The `TableModel` class can also be used as a Pydantic model to represent data entities. To work with results as Pydantic model instances, use: ```python table.search([1, 2, 3]).limit(10).to_pydantic() ``` ================================================ FILE: src/ai/index.md ================================================ # TiDB for AI TiDB is an open-source, distributed SQL database designed for modern AI applications, offering seamless scalability, real-time analytics, and unified storage for vectors, documents, knowledge graphs, operational data and more. === "Python" TiDB provide a Python SDK and a series of integrations with popular AI frameworks to help developers build AI applications efficiently. To install the TiDB Python SDK, run the following command: ```bash pip install pytidb ``` Integrations: - AI Frameworks: [LlamaIndex](https://docs.pingcap.com/tidbcloud/vector-search-integrate-with-llamaindex/), [LangChain](https://docs.pingcap.com/tidbcloud/vector-search-integrate-with-langchain/) - ORM Libraries: [SQLAlchemy](https://docs.pingcap.com/tidbcloud/vector-search-integrate-with-sqlalchemy/), [Django-ORM](https://docs.pingcap.com/tidbcloud/vector-search-integrate-with-django-orm/), [Peewee](https://docs.pingcap.com/tidbcloud/vector-search-integrate-with-peewee/) - AI Services: [Bedrock](https://docs.pingcap.com/tidbcloud/vector-search-integrate-with-amazon-bedrock/) - Embedding Models/Services: [JinaAI](https://docs.pingcap.com/tidbcloud/vector-search-integrate-with-jinaai-embedding/) ## Next Steps - 📖 Explore [Concepts](./concepts/vector-search.md) to understand the fundamentals of building modern AI applications - 🚀 Follow our [Quickstart Guide](./quickstart.md) to begin building your first AI application with TiDB ================================================ FILE: src/ai/integrations/embedding-cohere.md ================================================ --- title: "Integrate TiDB Vector Search with Cohere Embeddings API" description: "Learn how to integrate TiDB Vector Search with Cohere Embeddings API to store embeddings and perform semantic search." keywords: "TiDB, Cohere, Vector search, text embeddings, multilingual embeddings" --- # Integrate TiDB Vector Search with Cohere Embeddings API This tutorial demonstrates how to use [Cohere](https://cohere.com/embed) to generate text embeddings, store them in TiDB vector storage, and perform semantic search. !!! info Currently, [Server-Side Auto Embedding](../guides/auto-embedding.md) is only available on [TiDB Cloud Starter](https://tidbcloud.com/?utm_source=github&utm_medium=referral&utm_campaign=pytidb_readme) clusters in the following AWS regions: - `Frankfurt (eu-central-1)` - `Oregon (us-west-2)` - `N. Virginia (us-east-1)` ## Cohere Embeddings Cohere offers multilingual embedding models for search, RAG, and classification. The latest `embed-v4.0` model supports text, images, and mixed content. You can use the Cohere Embeddings API with TiDB through the AI SDK or native SQL functions for automatic embedding generation. ### Supported Models | Model Name | Dimensions | Max Input Tokens | Description | |----------------------------------|------------|------------------|-------------| | `cohere/embed-v4.0` | 256, 512, 1024, 1536 (default) | 128k | Latest multimodal model supporting text, images, and mixed content (PDFs) | | `cohere/embed-english-v3.0` | 1024 | 512 | High-performance English embedding model optimized for search and classification | | `cohere/embed-multilingual-v3.0`| 1024 | 512 | Multilingual model supporting 100+ languages | | `cohere/embed-english-light-v3.0` | 384 | 512 | Lightweight English model for faster processing with similar performance | | `cohere/embed-multilingual-light-v3.0` | 384 | 512 | Lightweight multilingual model for faster processing with similar performance | For a complete list of supported models and detailed specifications, see the [Cohere Embeddings Documentation](https://docs.cohere.com/docs/cohere-embed). ## Usage example This example demonstrates creating a vector table, inserting documents, and performing similarity search using Cohere embedding models. ### Step 1: Connect to the database === "Python" ```python from pytidb import TiDBClient tidb_client = TiDBClient.connect( host="{gateway-region}.prod.aws.tidbcloud.com", port=4000, username="{prefix}.root", password="{password}", database="{database}", ensure_db=True, ) ``` === "SQL" ```bash mysql -h {gateway-region}.prod.aws.tidbcloud.com \ -P 4000 \ -u {prefix}.root \ -p{password} \ -D {database} ``` ### Step 2: Configure the API key Create your API key from the [Cohere Dashboard](https://dashboard.cohere.com/api-keys) and bring your own key (BYOK) to use the embedding service. === "Python" Configure the API key for the Cohere embedding provider using the TiDB Client: ```python tidb_client.configure_embedding_provider( provider="cohere", api_key="{your-cohere-api-key}", ) ``` === "SQL" Set the API key for the Cohere embedding provider using SQL: ```sql SET @@GLOBAL.TIDB_EXP_EMBED_COHERE_API_KEY = "{your-cohere-api-key}"; ``` ### Step 3: Create a vector table Create a table with a vector field that uses the `cohere/embed-v4.0` model to generate 1536-dimensional vectors (default dimension): === "Python" ```python from pytidb.schema import TableModel, Field from pytidb.embeddings import EmbeddingFunction from pytidb.datatype import TEXT class Document(TableModel): __tablename__ = "sample_documents" id: int = Field(primary_key=True) content: str = Field(sa_type=TEXT) embedding: list[float] = EmbeddingFunction( model_name="cohere/embed-v4.0" ).VectorField(source_field="content") table = tidb_client.create_table(schema=Document, if_exists="overwrite") ``` === "SQL" ```sql CREATE TABLE sample_documents ( `id` INT PRIMARY KEY, `content` TEXT, `embedding` VECTOR(1536) GENERATED ALWAYS AS (EMBED_TEXT( "cohere/embed-v4.0", `content` )) STORED ); ``` ### Step 4: Insert data into the table === "Python" Use the `table.insert()` or `table.bulk_insert()` API to add data: ```python documents = [ Document(id=1, content="Python: High-level programming language for data science and web development."), Document(id=2, content="Python snake: Non-venomous constrictor found in tropical regions."), Document(id=3, content="Python framework: Django and Flask are popular web frameworks."), Document(id=4, content="Python libraries: NumPy and Pandas for data analysis."), Document(id=5, content="Python ecosystem: Rich collection of packages and tools."), ] table.bulk_insert(documents) ``` === "SQL" Insert data using the `INSERT INTO` statement: ```sql INSERT INTO sample_documents (id, content) VALUES (1, "Python: High-level programming language for data science and web development."), (2, "Python snake: Non-venomous constrictor found in tropical regions."), (3, "Python framework: Django and Flask are popular web frameworks."), (4, "Python libraries: NumPy and Pandas for data analysis."), (5, "Python ecosystem: Rich collection of packages and tools."); ``` ### Step 5: Search for similar documents === "Python" Use the `table.search()` API to perform vector search: ```python results = table.search("How to learn Python programming?") \ .limit(2) \ .to_list() print(results) ``` === "SQL" Use the `VEC_EMBED_COSINE_DISTANCE` function to perform vector search based on cosine distance metric: ```sql SELECT `id`, `content`, VEC_EMBED_COSINE_DISTANCE(embedding, "How to learn Python programming?") AS _distance FROM sample_documents ORDER BY _distance ASC LIMIT 2; ``` ================================================ FILE: src/ai/integrations/embedding-gemini.md ================================================ --- title: "Integrate TiDB Vector Search with Google Gemini Embeddings API" description: "Learn how to integrate TiDB Vector Search with Google Gemini Embeddings API to store embeddings and perform semantic search." keywords: "TiDB, Google Gemini, Vector search, text embeddings, multimodal embeddings" --- # Integrate TiDB Vector Search with Google Gemini Embeddings API This tutorial demonstrates how to use [Google Gemini](https://ai.google.dev/models/gemini) to generate embeddings for text and image data, store them in TiDB vector storage, and perform semantic search. !!! info Currently, [Server-Side Auto Embedding](../guides/auto-embedding.md) is only available on [TiDB Cloud Starter](https://tidbcloud.com/?utm_source=github&utm_medium=referral&utm_campaign=pytidb_readme) clusters in the following AWS regions: - `Frankfurt (eu-central-1)` - `Oregon (us-west-2)` - `N. Virginia (us-east-1)` ## Google Gemini Embeddings The Gemini API provides text embedding models that generate embeddings for words, phrases, sentences, and code. These embeddings enable advanced natural language processing (NLP) tasks such as semantic search, classification, and clustering. By using context-aware embeddings, you can achieve more accurate results than with traditional keyword-based methods. ### Supported Models | Model Name | Dimensions (recommended) | Max Input Tokens | Description | |------------|--------------------------|------------|-------------| | `gemini-embedding-001` | 128–3072 (768, 1536, 3072) | 2048 | Text and code embeddings | For a complete list of supported models and detailed specifications, see the [Google Gemini Embeddings Documentation](https://ai.google.dev/gemini-api/docs/embeddings). ## Usage example This example demonstrates creating a vector table, inserting documents, and performing similarity search using Google Gemini embedding models. ### Step 1: Connect to the database === "Python" ```python from pytidb import TiDBClient tidb_client = TiDBClient.connect( host="{gateway-region}.prod.aws.tidbcloud.com", port=4000, username="{prefix}.root", password="{password}", database="{database}", ensure_db=True, ) ``` === "SQL" ```bash mysql -h {gateway-region}.prod.aws.tidbcloud.com \ -P 4000 \ -u {prefix}.root \ -p{password} \ -D {database} ``` ### Step 2: Configure the API key Create your API key from the [Google AI Studio](https://makersuite.google.com/app/apikey) and bring your own key (BYOK) to use the embedding service. === "Python" Configure the API key for the Google Gemini embedding provider using the TiDB Client: ```python tidb_client.configure_embedding_provider( provider="google_gemini", api_key="{your-google-api-key}", ) ``` === "SQL" Set the API key for the Google Gemini embedding provider using SQL: ```sql SET @@GLOBAL.TIDB_EXP_EMBED_GEMINI_API_KEY = "{your-google-api-key}"; ``` ### Step 3: Create a vector table Create a table with a vector field that uses the `gemini-embedding-001` model to generate 3072-dimensional vectors (default): === "Python" ```python from pytidb.schema import TableModel, Field from pytidb.embeddings import EmbeddingFunction from pytidb.datatype import TEXT class Document(TableModel): __tablename__ = "sample_documents" id: int = Field(primary_key=True) content: str = Field(sa_type=TEXT) embedding: list[float] = EmbeddingFunction( model_name="gemini-embedding-001" ).VectorField(source_field="content") table = tidb_client.create_table(schema=Document, if_exists="overwrite") ``` === "SQL" ```sql CREATE TABLE sample_documents ( `id` INT PRIMARY KEY, `content` TEXT, `embedding` VECTOR(3072) GENERATED ALWAYS AS (EMBED_TEXT( "gemini-embedding-001", `content` )) STORED ); ``` ### Step 4: Insert data into the table === "Python" Use the `table.insert()` or `table.bulk_insert()` API to add data: ```python documents = [ Document(id=1, content="Java: Object-oriented language for cross-platform development."), Document(id=2, content="Java coffee: Bold Indonesian beans with low acidity."), Document(id=3, content="Java island: Densely populated, home to Jakarta."), Document(id=4, content="Java's syntax is used in Android apps."), Document(id=5, content="Dark roast Java beans enhance espresso blends."), ] table.bulk_insert(documents) ``` === "SQL" Insert data using the `INSERT INTO` statement: ```sql INSERT INTO sample_documents (id, content) VALUES (1, "Java: Object-oriented language for cross-platform development."), (2, "Java coffee: Bold Indonesian beans with low acidity."), (3, "Java island: Densely populated, home to Jakarta."), (4, "Java's syntax is used in Android apps."), (5, "Dark roast Java beans enhance espresso blends."); ``` ### Step 5: Search for similar documents === "Python" Use the `table.search()` API to perform vector search: ```python results = table.search("How to start learning Java programming?") \ .limit(2) \ .to_list() print(results) ``` === "SQL" Use the `VEC_EMBED_COSINE_DISTANCE` function to perform vector search based on cosine distance metric: ```sql SELECT `id`, `content`, VEC_EMBED_COSINE_DISTANCE(embedding, "How to start learning Java programming?") AS _distance FROM sample_documents ORDER BY _distance ASC LIMIT 2; ``` ## Custom embedding dimensions The `gemini-embedding-001` model supports flexible vector dimensions through Matryoshka Representation Learning (MRL). You can specify the desired dimensions in your embedding function: === "Python" ```python # For 1536 dimensions embedding: list[float] = EmbeddingFunction( model_name="gemini-embedding-001", dimensions=1536 ).VectorField(source_field="content") # For 768 dimensions embedding: list[float] = EmbeddingFunction( model_name="gemini-embedding-001", dimensions=768 ).VectorField(source_field="content") ``` === "SQL" ```sql -- For 1536 dimensions `embedding` VECTOR(1536) GENERATED ALWAYS AS (EMBED_TEXT( "gemini-embedding-001", `content`, '{"embedding_config": {"output_dimensionality": 1536}}' )) STORED -- For 768 dimensions `embedding` VECTOR(768) GENERATED ALWAYS AS (EMBED_TEXT( "gemini-embedding-001", `content`, '{"embedding_config": {"output_dimensionality": 768}}' )) STORED ``` Choose the appropriate dimensions based on your performance requirements and storage constraints. Higher dimensions provide better accuracy but require more storage and computational resources. ================================================ FILE: src/ai/integrations/embedding-huggingface.md ================================================ --- title: "Integrate TiDB Vector Search with Hugging Face Embeddings" description: "Learn how to integrate TiDB Vector Search with Hugging Face models to store embeddings and perform semantic search." keywords: "TiDB, Hugging Face, Vector search, text embeddings, transformers" --- # Integrate TiDB Vector Search with Hugging Face Embeddings This tutorial demonstrates how to use [Hugging Face](https://huggingface.co/) models to generate text embeddings, store them in TiDB vector storage, and perform semantic search. !!! info Currently, [Server-Side Auto Embedding](../guides/auto-embedding.md) is only available on [TiDB Cloud Starter](https://tidbcloud.com/?utm_source=github&utm_medium=referral&utm_campaign=pytidb_readme) clusters in the following AWS regions: - `Frankfurt (eu-central-1)` - `Oregon (us-west-2)` - `N. Virginia (us-east-1)` ## Hugging Face Embeddings Hugging Face provides access to a vast collection of pre-trained embedding models through the Hugging Face Hub. You can integrate these models with TiDB using the AI SDK, which enables automatic embedding generation from various transformer-based models. ### Supported Models Hugging Face supports a wide range of embedding models. Here are some popular examples: | Model Name | Dimensions | Max Input Tokens | Description | |------------|------------|------------------|-------------| | `sentence-transformers/all-MiniLM-L6-v2` | 384 | 256 | Fast, lightweight model for general-purpose embeddings | | `sentence-transformers/all-mpnet-base-v2` | 768 | 384 | High-quality embeddings with good performance | | `sentence-transformers/all-MiniLM-L12-v2` | 384 | 256 | Balanced model between speed and quality | | `BAAI/bge-small-en-v1.5` | 384 | 512 | Multilingual model optimized for semantic search | | `BAAI/bge-base-en-v1.5` | 768 | 512 | Higher quality multilingual embeddings | | `sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2` | 384 | 256 | Multilingual model for semantic similarity across languages | | `sentence-transformers/paraphrase-multilingual-mpnet-base-v2` | 768 | 384 | High-quality multilingual model based on MPNet architecture | | `bert-base-uncased` | 768 | 512 | Google's BERT base model with 12 layers and 12 attention heads | | `distilbert-base-uncased` | 768 | 512 | Lightweight BERT model with ~60% fewer parameters, 60% faster inference | For a complete list of supported models and detailed specifications, see the [Hugging Face Model Hub](https://huggingface.co/models?pipeline_tag=sentence-similarity). ## Usage example This example demonstrates creating a vector table, inserting documents, and performing similarity search using Hugging Face embedding models. ### Step 1: Connect to the database === "Python" ```python from pytidb import TiDBClient tidb_client = TiDBClient.connect( host="{gateway-region}.prod.aws.tidbcloud.com", port=4000, username="{prefix}.root", password="{password}", database="{database}", ensure_db=True, ) ``` === "SQL" ```bash mysql -h {gateway-region}.prod.aws.tidbcloud.com \ -P 4000 \ -u {prefix}.root \ -p{password} \ -D {database} ``` ### Step 2: Configure the API key If you're using a private model or need higher rate limits, you can configure your Hugging Face API token. You can create your token from the [Hugging Face Token Settings](https://huggingface.co/settings/tokens) page: === "Python" Configure the API token for Hugging Face models using the TiDB Client: ```python tidb_client.configure_embedding_provider( provider="huggingface", api_key="{your-huggingface-token}", ) ``` === "SQL" Set the API token for Hugging Face models using SQL: ```sql SET @@GLOBAL.TIDB_EXP_EMBED_HUGGINGFACE_API_KEY = "{your-huggingface-token}"; ``` ### Step 3: Create a vector table Create a table with a vector field that uses a Hugging Face model to generate embeddings: === "Python" ```python from pytidb.schema import TableModel, Field from pytidb.embeddings import EmbeddingFunction from pytidb.datatype import TEXT class Document(TableModel): __tablename__ = "sample_documents" id: int = Field(primary_key=True) content: str = Field(sa_type=TEXT) embedding: list[float] = EmbeddingFunction( model_name="huggingface/sentence-transformers/all-MiniLM-L6-v2" ).VectorField(source_field="content") table = tidb_client.create_table(schema=Document, if_exists="overwrite") ``` === "SQL" ```sql CREATE TABLE sample_documents ( `id` INT PRIMARY KEY, `content` TEXT, `embedding` VECTOR(384) GENERATED ALWAYS AS (EMBED_TEXT( "huggingface/sentence-transformers/all-MiniLM-L6-v2", `content` )) STORED ); ``` !!! tip The vector dimensions depend on the model you choose. For example, `huggingface/sentence-transformers/all-MiniLM-L6-v2` produces 384-dimensional vectors, while `huggingface/sentence-transformers/all-mpnet-base-v2` produces 768-dimensional vectors. ### Step 4: Insert data into the table === "Python" Use the `table.insert()` or `table.bulk_insert()` API to add data: ```python documents = [ Document(id=1, content="Machine learning algorithms can identify patterns in data."), Document(id=2, content="Deep learning uses neural networks with multiple layers."), Document(id=3, content="Natural language processing helps computers understand text."), Document(id=4, content="Computer vision enables machines to interpret images."), Document(id=5, content="Reinforcement learning learns through trial and error."), ] table.bulk_insert(documents) ``` === "SQL" Insert data using the `INSERT INTO` statement: ```sql INSERT INTO sample_documents (id, content) VALUES (1, "Machine learning algorithms can identify patterns in data."), (2, "Deep learning uses neural networks with multiple layers."), (3, "Natural language processing helps computers understand text."), (4, "Computer vision enables machines to interpret images."), (5, "Reinforcement learning learns through trial and error."); ``` ### Step 5: Search for similar documents === "Python" Use the `table.search()` API to perform vector search: ```python results = table.search("How do neural networks work?") \ .limit(3) \ .to_list() for doc in results: print(f"ID: {doc.id}, Content: {doc.content}") ``` === "SQL" Use the `VEC_EMBED_COSINE_DISTANCE` function to perform vector search with cosine distance: ```sql SELECT `id`, `content`, VEC_EMBED_COSINE_DISTANCE(embedding, "How do neural networks work?") AS _distance FROM sample_documents ORDER BY _distance ASC LIMIT 3; ``` ================================================ FILE: src/ai/integrations/embedding-jinaai.md ================================================ --- title: "Integrate TiDB Vector Search with Jina AI Embeddings API" description: "Learn how to integrate TiDB Vector Search with Jina AI Embeddings API to store embeddings and perform semantic search." keywords: "TiDB, Jina AI, Vector search, text embeddings, multimodal embeddings" --- # Integrate TiDB Vector Search with Jina AI Embeddings API This tutorial demonstrates how to use [Jina AI](https://jina.ai/embeddings/) to generate embeddings for text and image data, store them in TiDB vector storage, and perform semantic search. !!! info Currently, [Server-Side Auto Embedding](../guides/auto-embedding.md) is only available on [TiDB Cloud Starter](https://tidbcloud.com/?utm_source=github&utm_medium=referral&utm_campaign=pytidb_readme) clusters in the following AWS regions: - `Frankfurt (eu-central-1)` - `Oregon (us-west-2)` - `N. Virginia (us-east-1)` ## Jina AI Embeddings Jina AI provides high-performance, multimodal, and multilingual long-context embeddings for search, RAG, and agent applications. ### Supported Models | Model Name | Dimensions | Max Input Tokens | Description | |----------------------------------|------------|------------------|-------------| | `jina_ai/jina-embeddings-v4` | 2048 | 32,768 | Multimodal, multilingual, text and image embeddings | | `jina_ai/jina-clip-v2` | 1024 | 8192 | Multilingual multimodal embeddings for texts and images | | `jina_ai/jina-embeddings-v3` | 1024 | 8192 | Multilingual, text and code embeddings | For a complete list of supported models and detailed specifications, see the [Jina AI Embeddings Documentation](https://jina.ai/embeddings/). ## Usage example This example demonstrates creating a vector table, inserting documents, and performing similarity search using Jina AI embedding models. ### Step 1: Connect to the database === "Python" ```python from pytidb import TiDBClient tidb_client = TiDBClient.connect( host="{gateway-region}.prod.aws.tidbcloud.com", port=4000, username="{prefix}.root", password="{password}", database="{database}", ensure_db=True, ) ``` === "SQL" ```bash mysql -h {gateway-region}.prod.aws.tidbcloud.com \ -P 4000 \ -u {prefix}.root \ -p{password} \ -D {database} ``` ### Step 2: Configure the API key Create your API key from the [Jina AI Platform](https://jina.ai/embeddings/) and bring your own key (BYOK) to use the embedding service. === "Python" Configure the API key for the Jina AI embedding provider using the TiDB Client: ```python tidb_client.configure_embedding_provider( provider="jina_ai", api_key="{your-jina-api-key}", ) ``` === "SQL" Set the API key for the Jina AI embedding provider using SQL: ```sql SET @@GLOBAL.TIDB_EXP_EMBED_JINA_AI_API_KEY = "{your-jina-api-key}"; ``` ### Step 3: Create a vector table Create a table with a vector field that uses the `jina_ai/jina-embeddings-v4` model to generate 2048-dimensional vectors: === "Python" ```python from pytidb.schema import TableModel, Field from pytidb.embeddings import EmbeddingFunction from pytidb.datatype import TEXT class Document(TableModel): __tablename__ = "sample_documents" id: int = Field(primary_key=True) content: str = Field(sa_type=TEXT) embedding: list[float] = EmbeddingFunction( model_name="jina_ai/jina-embeddings-v4" ).VectorField(source_field="content") table = tidb_client.create_table(schema=Document, if_exists="overwrite") ``` === "SQL" ```sql CREATE TABLE sample_documents ( `id` INT PRIMARY KEY, `content` TEXT, `embedding` VECTOR(2048) GENERATED ALWAYS AS (EMBED_TEXT( "jina_ai/jina-embeddings-v4", `content` )) STORED ); ``` ### Step 4: Insert data into the table === "Python" Use the `table.insert()` or `table.bulk_insert()` API to add data: ```python documents = [ Document(id=1, content="Java: Object-oriented language for cross-platform development."), Document(id=2, content="Java coffee: Bold Indonesian beans with low acidity."), Document(id=3, content="Java island: Densely populated, home to Jakarta."), Document(id=4, content="Java's syntax is used in Android apps."), Document(id=5, content="Dark roast Java beans enhance espresso blends."), ] table.bulk_insert(documents) ``` === "SQL" Insert data using the `INSERT INTO` statement: ```sql INSERT INTO sample_documents (id, content) VALUES (1, "Java: Object-oriented language for cross-platform development."), (2, "Java coffee: Bold Indonesian beans with low acidity."), (3, "Java island: Densely populated, home to Jakarta."), (4, "Java's syntax is used in Android apps."), (5, "Dark roast Java beans enhance espresso blends."); ``` ### Step 5: Search for similar documents === "Python" Use the `table.search()` API to perform vector search: ```python results = table.search("How to start learning Java programming?") \ .limit(2) \ .to_list() print(results) ``` === "SQL" Use the `VEC_EMBED_COSINE_DISTANCE` function to perform vector search based on cosine distance metric: ```sql SELECT `id`, `content`, VEC_EMBED_COSINE_DISTANCE(embedding, "How to start learning Java programming?") AS _distance FROM sample_documents ORDER BY _distance ASC LIMIT 2; ``` ================================================ FILE: src/ai/integrations/embedding-nvidia-nim.md ================================================ --- title: "Integrate TiDB Vector Search with NVIDIA NIM Embeddings" description: "Learn how to integrate TiDB Vector Search with NVIDIA NIM models to store embeddings and perform semantic search." keywords: "TiDB, NVIDIA NIM, Vector search, text embeddings, AI models" --- # Integrate TiDB Vector Search with NVIDIA NIM Embeddings This tutorial demonstrates how to use [NVIDIA NIM](https://developer.nvidia.com/nim) models to generate text embeddings, store them in TiDB vector storage, and perform semantic search. !!! info Currently, [Server-Side Auto Embedding](../guides/auto-embedding.md) is only available on [TiDB Cloud Starter](https://tidbcloud.com/?utm_source=github&utm_medium=referral&utm_campaign=pytidb_readme) clusters in the following AWS regions: - `Frankfurt (eu-central-1)` - `Oregon (us-west-2)` - `N. Virginia (us-east-1)` ## NVIDIA NIM Embeddings NVIDIA NIM™ (NVIDIA Inference Microservices) provides containers to self-host GPU-accelerated inferencing microservices for pretrained and customized AI models across clouds, data centers, and RTX™ AI PCs and workstations. NIM microservices expose industry-standard APIs for simple integration into AI applications, development frameworks, and workflows. You can integrate NVIDIA NIM embedding models with TiDB using the AI SDK, which enables automatic embedding generation from various transformer-based models. ### Supported Models NVIDIA NIM supports a range of embedding models optimized for different use cases. Here are some popular examples: | Model Name | Dimensions | Max Input Tokens | Description | |------------|------------|------------------|-------------| | `nvidia/nv-embed-v1` | 4096 | 32k | High-quality general-purpose embeddings based on Mistral-7B-v0.1 with Latent-Attention pooling | | `nvidia/llama-3_2-nemoretriever-300m-embed-v1` | 2048 | 8192 | Multilingual embeddings using Llama 3.2 architecture, supporting 20+ languages and long-context reasoning | For a complete list of supported models and detailed specifications, see the [NVIDIA Build Platform](https://build.nvidia.com/search?q=Embedding). ## Usage example This example demonstrates creating a vector table, inserting documents, and performing similarity search using NVIDIA NIM embedding models. ### Step 1: Connect to the database === "Python" ```python from pytidb import TiDBClient tidb_client = TiDBClient.connect( host="{gateway-region}.prod.aws.tidbcloud.com", port=4000, username="{prefix}.root", password="{password}", database="{database}", ensure_db=True, ) ``` === "SQL" ```bash mysql -h {gateway-region}.prod.aws.tidbcloud.com \ -P 4000 \ -u {prefix}.root \ -p{password} \ -D {database} ``` ### Step 2: Configure the API key If you're using NVIDIA NIM models that require authentication, you can configure your API key. You can get free access to NIM API endpoints through the [NVIDIA Developer Program](https://developer.nvidia.com/nim) or create your API key from the [NVIDIA Build Platform](https://build.nvidia.com/settings/api-keys): === "Python" Configure the API key for NVIDIA NIM models using the TiDB Client: ```python tidb_client.configure_embedding_provider( provider="nvidia_nim", api_key="{your-nvidia-api-key}", ) ``` === "SQL" Set the API key for NVIDIA NIM models using SQL: ```sql SET @@GLOBAL.TIDB_EXP_EMBED_NVIDIA_NIM_API_KEY = "{your-nvidia-api-key}"; ``` ### Step 3: Create a vector table Create a table with a vector field that uses an NVIDIA NIM model to generate embeddings: === "Python" ```python from pytidb.schema import TableModel, Field from pytidb.embeddings import EmbeddingFunction from pytidb.datatype import TEXT class Document(TableModel): __tablename__ = "sample_documents" id: int = Field(primary_key=True) content: str = Field(sa_type=TEXT) embedding: list[float] = EmbeddingFunction( model_name="nvidia/nv-embed-v1" ).VectorField(source_field="content") table = tidb_client.create_table(schema=Document, if_exists="overwrite") ``` === "SQL" ```sql CREATE TABLE sample_documents ( `id` INT PRIMARY KEY, `content` TEXT, `embedding` VECTOR(4096) GENERATED ALWAYS AS (EMBED_TEXT( "nvidia/nv-embed-v1", `content` )) STORED ); ``` ### Step 4: Insert data into the table === "Python" Use the `table.insert()` or `table.bulk_insert()` API to add data: ```python documents = [ Document(id=1, content="Machine learning algorithms can identify patterns in data."), Document(id=2, content="Deep learning uses neural networks with multiple layers."), Document(id=3, content="Natural language processing helps computers understand text."), Document(id=4, content="Computer vision enables machines to interpret images."), Document(id=5, content="Reinforcement learning learns through trial and error."), ] table.bulk_insert(documents) ``` === "SQL" Insert data using the `INSERT INTO` statement: ```sql INSERT INTO sample_documents (id, content) VALUES (1, "Machine learning algorithms can identify patterns in data."), (2, "Deep learning uses neural networks with multiple layers."), (3, "Natural language processing helps computers understand text."), (4, "Computer vision enables machines to interpret images."), (5, "Reinforcement learning learns through trial and error."); ``` ### Step 5: Search for similar documents === "Python" Use the `table.search()` API to perform vector search: ```python results = table.search("How do neural networks work?") \ .limit(3) \ .to_list() for doc in results: print(f"ID: {doc.id}, Content: {doc.content}") ``` === "SQL" Use the `VEC_EMBED_COSINE_DISTANCE` function to perform vector search with cosine distance: ```sql SELECT `id`, `content`, VEC_EMBED_COSINE_DISTANCE(embedding, "How do neural networks work?") AS _distance FROM sample_documents ORDER BY _distance ASC LIMIT 3; ``` ================================================ FILE: src/ai/integrations/embedding-openai-compatible.md ================================================ --- title: "Integrate TiDB Vector Search with OpenAI-Compatible Embedding API" description: "Learn how to integrate TiDB Vector Search with OpenAI-Compatible Embedding API to store embeddings and perform semantic search." keywords: "TiDB, OpenAI-like Embeddings, OpenAI Compatible API, Vector search, text embeddings" --- # Integrate TiDB Vector Search with OpenAI-Compatible Embedding API This tutorial demonstrates how to use OpenAI-compatible embedding services to generate text embeddings, store them in TiDB vector storage, and perform semantic search. !!! info Currently, TiDB does not support native SQL functions for OpenAI-compatible embedding services, but you can integrate them using the AI SDK. ## OpenAI-like embedding services Because the OpenAI Embedding API is widely used, many AI service providers offer APIs that are compatible with the OpenAI Embedding API, such as: - [Ollama](https://ollama.com/) - [vLLM](https://vllm.ai/) TiDB AI SDK provides an `EmbeddingFunction` class that can be used to integrate with OpenAI-compatible embedding services. ## Usage example This example demonstrates creating a vector table, inserting documents, and performing similarity search using OpenAI-compatible embedding models. ### Step 1: Connect to the database === "Python" ```python from pytidb import TiDBClient tidb_client = TiDBClient.connect( host="{gateway-region}.prod.aws.tidbcloud.com", port=4000, username="{prefix}.root", password="{password}", database="{database}", ensure_db=True, ) ``` ### Step 2: Define the embedding function === "Python" To integrate with OpenAI-compatible embedding services, initialize the `EmbeddingFunction` class and set the `model_name` parameter with the `openai/` prefix. ```python from pytidb.embeddings import EmbeddingFunction openai_like_embed = EmbeddingFunction( model_name="openai/{model_name}", api_base="{your-api-base}", api_key="{your-api-key}", ) ``` The parameters are: - `model_name`: Specifies the model to use. Use the format `openai/{model_name}`. - `api_base`: The base URL of your OpenAI compatible embedding API service. - `api_key`: The API key can be used to authenticate with the embedding API service. **Example: Using Ollama and `nomic-embed-text` model** === "Python" ```python openai_like_embed = EmbeddingFunction( model_name="openai/nomic-embed-text", api_base="http://localhost:11434/v1" ) ``` **Example: Using vLLM and `nomic-embed-text` model** === "Python" ```python openai_like_embed = EmbeddingFunction( model_name="openai/intfloat/e5-mistral-7b-instruct", api_base="http://localhost:8000/v1" ) ``` ### Step 3: Create a vector table Create a table with a vector field that uses Ollama platform and `nomic-embed-text` model. === "Python" ```python from pytidb.schema import TableModel, Field from pytidb.embeddings import EmbeddingFunction from pytidb.datatype import TEXT openai_like_embed = EmbeddingFunction( model_name="openai/nomic-embed-text", api_base="{your-api-base}", ) class Document(TableModel): __tablename__ = "sample_documents" id: int = Field(primary_key=True) content: str = Field(sa_type=TEXT) embedding: list[float] = openai_like_embed.VectorField(source_field="content") table = tidb_client.create_table(schema=Document, if_exists="overwrite") ``` ### Step 4: Insert data into the table === "Python" Use the `table.insert()` or `table.bulk_insert()` API to add data: ```python documents = [ Document(id=1, content="Java: Object-oriented language for cross-platform development."), Document(id=2, content="Java coffee: Bold Indonesian beans with low acidity."), Document(id=3, content="Java island: Densely populated, home to Jakarta."), Document(id=4, content="Java's syntax is used in Android apps."), Document(id=5, content="Dark roast Java beans enhance espresso blends."), ] table.bulk_insert(documents) ``` With [Auto Embedding](../guides/auto-embedding.md) enabled, TiDB automatically generates vector field values when you insert data. ### Step 5: Search for similar documents === "Python" Use the `table.search()` API to perform vector search: ```python results = table.search("How to start learning Java programming?") \ .limit(2) \ .to_list() print(results) ``` With [Auto Embedding](../guides/auto-embedding.md) enabled, TiDB automatically generates vector embeddings for query text during vector search. ================================================ FILE: src/ai/integrations/embedding-openai.md ================================================ --- title: "Integrate TiDB Vector Search with OpenAI Embeddings API" description: "Learn how to integrate TiDB Vector Search with OpenAI AI Embeddings API to store embeddings and perform semantic search." keywords: "TiDB, OpenAI Embeddings, Vector search, text embeddings" --- # Integrate TiDB Vector Search with OpenAI Embeddings API This tutorial demonstrates how to use [OpenAI](https://openai.com/api/) to generate text embeddings, store them in TiDB vector storage, and perform semantic search. !!! info Currently, Auto Embedding is only available on TiDB Cloud Starter clusters in the following AWS regions: - Frankfurt (eu-central-1) - Oregon (us-west-2) - N. Virginia (us-east-1) ## OpenAI Embeddings OpenAI offers cost-effective, high-performance embedding models. You can integrate the OpenAI Embeddings API with TiDB using the AI SDK or native SQL functions for automatic embedding generation. ### Supported Models | Model Name | Dimensions | Max Input Tokens | |-----------------------------------|------------|------------------| | `openai/text-embedding-3-small` | 1536 | 8191 | | `openai/text-embedding-3-large` | 3072 | 8191 | For a complete list of supported models, see the [OpenAI Embedding API Reference](https://platform.openai.com/docs/api-reference/embeddings). ## Usage example This example demonstrates creating a vector table, inserting documents, and performing similarity search using OpenAI embedding models. ### Step 1: Connect to the database === "Python" ```python from pytidb import TiDBClient tidb_client = TiDBClient.connect( host="{gateway-region}.prod.aws.tidbcloud.com", port=4000, username="{prefix}.root", password="{password}", database="{database}", ensure_db=True, ) ``` === "SQL" ```bash mysql -h {gateway-region}.prod.aws.tidbcloud.com \ -P 4000 \ -u {prefix}.root \ -p{password} \ -D {database} ``` ### Step 2: Configure the API key Create your own API key from the [OpenAI API Platform](https://platform.openai.com/api-keys) and bring your own key (BYOK) to use the embedding service. === "Python" Configure the API key for the OpenAI embedding provider using the TiDB Client: ```python tidb_client.configure_embedding_provider( provider="openai", api_key="{your-openai-api-key}", ) ``` === "SQL" Set the API key for the OpenAI embedding provider using SQL: ```sql SET @@GLOBAL.TIDB_EXP_EMBED_OPENAI_API_KEY = "{your-openai-api-key}"; ``` ### Step 3: Create a vector table Create a table with a vector field that uses the `openai/text-embedding-3-small` model to generate 1536-dimensional vectors: === "Python" ```python from pytidb.schema import TableModel, Field from pytidb.embeddings import EmbeddingFunction from pytidb.datatype import TEXT class Document(TableModel): __tablename__ = "sample_documents" id: int = Field(primary_key=True) content: str = Field(sa_type=TEXT) embedding: list[float] = EmbeddingFunction( model_name="openai/text-embedding-3-small" ).VectorField(source_field="content") table = tidb_client.create_table(schema=Document, if_exists="overwrite") ``` === "SQL" ```sql CREATE TABLE sample_documents ( `id` INT PRIMARY KEY, `content` TEXT, `embedding` VECTOR(1536) GENERATED ALWAYS AS (EMBED_TEXT( "openai/text-embedding-3-small", `content` )) STORED ); ``` ### Step 4: Insert data into the table === "Python" Use the `table.insert()` or `table.bulk_insert()` API to add data: ```python documents = [ Document(id=1, content="Java: Object-oriented language for cross-platform development."), Document(id=2, content="Java coffee: Bold Indonesian beans with low acidity."), Document(id=3, content="Java island: Densely populated, home to Jakarta."), Document(id=4, content="Java's syntax is used in Android apps."), Document(id=5, content="Dark roast Java beans enhance espresso blends."), ] table.bulk_insert(documents) ``` === "SQL" Insert data using the `INSERT INTO` statement: ```sql INSERT INTO sample_documents (id, content) VALUES (1, "Java: Object-oriented language for cross-platform development."), (2, "Java coffee: Bold Indonesian beans with low acidity."), (3, "Java island: Densely populated, home to Jakarta."), (4, "Java's syntax is used in Android apps."), (5, "Dark roast Java beans enhance espresso blends."); ``` ### Step 5: Search for similar documents === "Python" Use the `table.search()` API to perform vector search: ```python results = table.search("How to start learning Java programming?") \ .limit(2) \ .to_list() print(results) ``` === "SQL" Use the `VEC_EMBED_COSINE_DISTANCE` function to perform vector search with cosine distance: ```sql SELECT `id`, `content`, VEC_EMBED_COSINE_DISTANCE(embedding, "How to start learning Java programming?") AS _distance FROM sample_documents ORDER BY _distance ASC LIMIT 2; ``` ================================================ FILE: src/ai/integrations/embedding-overview.md ================================================ # Embeddings Integration ## Overview TiDB provides a unified interface for integrating with various embedding providers and models: - **Programmatic use**: Use the `EmbeddingFunction` class from the AI SDK to create embedding functions for specific providers or models. - **SQL use**: Use the `EMBED_TEXT` function to generate embeddings directly from text data. ## Embedding Function === "Python" Use the `EmbeddingFunction` class to work with different embedding providers and models. ```python from pytidb.embeddings import EmbeddingFunction embed_func = EmbeddingFunction( model_name="/", ) ``` **Parameters:** - `model_name` *(required)*: Specifies the embedding model to use, in the format `{provider_name}/{model_name}`. - `dimensions` *(optional)*: The dimensionality of output vector embeddings. If not provided and the model lacks a default dimension, a test string is embedded during initialization to determine the actual dimension automatically. - `api_key` *(optional)*: The API key for accessing the embedding service. If not explicitly set, retrieves the key from the provider's default environment variable. - `api_base` *(optional)*: The base URL of the embedding API service. - `use_server` *(optional)*: Whether to use TiDB Cloud's hosted embedding service. Defaults to `True` for TiDB Cloud Starter. - `multimodal` *(optional)*: Whether to use a multimodal embedding model. When enabled, `use_server` is automatically set to `False`, and the embedding service is called client-side. === "SQL" ```sql SELECT EMBED_TEXT('{model_id}', '{text}', '{extra_params}'); ``` **Parameters:** - `model_id` *(required)*: The ID of the embedding model, in the format `{provider_name}/{model_name}`, for example, `tidbcloud_free/amazon/titan-embed-text-v2`. - `text` *(required)*: The text to generate embeddings from. - `extra_params` *(optional)*: Additional parameters sent to the embedding API. Refer to the embedding provider's documentation for supported parameters. ## Supported Providers The following embedding providers are supported. Click on the corresponding provider to learn how to integrate and enable automatic embedding for your data. - [TiDB Cloud Hosted](embedding-tidb-cloud-hosted.md) - [OpenAI](embedding-openai.md) - [OpenAI Compatible](embedding-openai-compatible.md) - [Cohere](embedding-cohere.md) - [Jina AI](embedding-jinaai.md) - [Google Gemini](embedding-gemini.md) - [Hugging Face](embedding-huggingface.md) - [NVIDIA NIM](embedding-nvidia-nim.md) ================================================ FILE: src/ai/integrations/embedding-tidb-cloud-hosted.md ================================================ --- title: "Integrate TiDB Vector Search with TiDB Cloud Hosted Embedding Models" description: "Learn how to integrate TiDB Vector Search with TiDB Cloud Hosted Embedding Models to store embeddings and perform semantic search." keywords: "TiDB, TiDB Cloud, Vector search, text embeddings" --- # Integrate TiDB Vector Search with TiDB Cloud Hosted Embedding Models This tutorial demonstrates how to use TiDB Cloud hosted embedding models to generate embeddings for text data, store them in TiDB vector storage, and perform semantic search. !!! info Currently, [Server-Side Auto Embedding](../guides/auto-embedding.md) is only available on [TiDB Cloud Starter](https://tidbcloud.com/?utm_source=github&utm_medium=referral&utm_campaign=pytidb_readme) clusters in the following AWS regions: - `Frankfurt (eu-central-1)` - `Oregon (us-west-2)` - `N. Virginia (us-east-1)` ## TiDB Cloud Hosted Embeddings TiDB Cloud provides hosted embedding models for generating text embeddings without requiring external API keys. ### Supported Models TiDB Cloud currently supports the following hosted embedding models: | Model Name | Dimensions | Max Input Tokens | Features | |-----------------------------------------------|------------|------------------|----------| | `tidbcloud_free/amazon/titan-embed-text-v2` | 1536 | 8192 | Text, Multilingual | | `tidbcloud_free/cohere/embed-english-v3` | 1024 | 512 | Text, English-optimized | | `tidbcloud_free/cohere/embed-multilingual-v3`| 1024 | 512 | Text, Multilingual | !!! info `tidbcloud_free` prefix models are provided by TiDB Cloud for free. ## Usage example This example demonstrates creating a vector table, inserting documents, and performing similarity search using TiDB Cloud hosted embedding models. ### Step 1: Connect to the database === "Python" ```python from pytidb import TiDBClient tidb_client = TiDBClient.connect( host="{gateway-region}.prod.aws.tidbcloud.com", port=4000, username="{prefix}.root", password="{password}", database="{database}", ensure_db=True, ) ``` === "SQL" ```bash mysql -h {gateway-region}.prod.aws.tidbcloud.com \ -P 4000 \ -u {prefix}.root \ -p{password} \ -D {database} ``` ### Step 2: Create a vector table Create a table with a vector field that uses the `tidbcloud_free/amazon/titan-embed-text-v2` model to generate 1536-dimensional vectors: === "Python" ```python from pytidb.schema import TableModel, Field from pytidb.embeddings import EmbeddingFunction from pytidb.datatype import TEXT class Document(TableModel): __tablename__ = "sample_documents" id: int = Field(primary_key=True) content: str = Field(sa_type=TEXT) embedding: list[float] = EmbeddingFunction( model_name="tidbcloud_free/amazon/titan-embed-text-v2" ).VectorField(source_field="content") table = tidb_client.create_table(schema=Document, if_exists="overwrite") ``` === "SQL" ```sql CREATE TABLE sample_documents ( `id` INT PRIMARY KEY, `content` TEXT, `embedding` VECTOR(1536) GENERATED ALWAYS AS (EMBED_TEXT( "tidbcloud_free/amazon/titan-embed-text-v2", `content` )) STORED ); ``` !!! info `tidbcloud_free` prefix models is not required to configure the API key. ### Step 3: Insert data into the table === "Python" Use the `table.insert()` or `table.bulk_insert()` API to add data: ```python documents = [ Document(id=1, content="Java: Object-oriented language for cross-platform development."), Document(id=2, content="Java coffee: Bold Indonesian beans with low acidity."), Document(id=3, content="Java island: Densely populated, home to Jakarta."), Document(id=4, content="Java's syntax is used in Android apps."), Document(id=5, content="Dark roast Java beans enhance espresso blends."), ] table.bulk_insert(documents) ``` === "SQL" Insert data using the `INSERT INTO` statement: ```sql INSERT INTO sample_documents (id, content) VALUES (1, "Java: Object-oriented language for cross-platform development."), (2, "Java coffee: Bold Indonesian beans with low acidity."), (3, "Java island: Densely populated, home to Jakarta."), (4, "Java's syntax is used in Android apps."), (5, "Dark roast Java beans enhance espresso blends."); ``` ### Step 4: Search for similar documents === "Python" Use the `table.search()` API to perform vector search: ```python results = table.search("How to start learning Java programming?") \ .limit(2) \ .to_list() print(results) ``` === "SQL" Use the `VEC_EMBED_COSINE_DISTANCE` function to perform vector search based on cosine distance metric: ```sql SELECT `id`, `content`, VEC_EMBED_COSINE_DISTANCE(embedding, "How to start learning Java programming?") AS _distance FROM sample_documents ORDER BY _distance ASC LIMIT 2; ``` ================================================ FILE: src/ai/integrations/langchain.md ================================================ # Integrate Vector Search with LangChain This tutorial demonstrates how to integrate the [vector search](https://docs.pingcap.com/tidbcloud/vector-search-overview) feature of TiDB with [LangChain](https://python.langchain.com/). !!! note The vector search feature is only available for TiDB Self-Managed clusters and [TiDB Cloud Starter](https://docs.pingcap.com/tidbcloud/select-cluster-tier#tidb-cloud-starter) clusters. !!! tip You can view the complete [sample code](https://github.com/langchain-ai/langchain/blob/master/docs/docs/integrations/vectorstores/tidb_vector.ipynb) on Jupyter Notebook, or run the sample code directly in the [Colab](https://colab.research.google.com/github/langchain-ai/langchain/blob/master/docs/docs/integrations/vectorstores/tidb_vector.ipynb) online environment. ## Prerequisites To complete this tutorial, you need: - [Python 3.8 or higher](https://www.python.org/downloads/) installed. - [Jupyter Notebook](https://jupyter.org/install) installed. - [Git](https://git-scm.com/downloads) installed. - A TiDB cluster. ## Get started This section provides step-by-step instructions for integrating TiDB Vector Search with LangChain to perform semantic searches. ### Step 1. Create a new Jupyter Notebook file In your preferred directory, create a new Jupyter Notebook file named `integrate_with_langchain.ipynb`: ```shell touch integrate_with_langchain.ipynb ``` ### Step 2. Install required dependencies In your project directory, run the following command to install the required packages: ```shell !pip install langchain langchain-community !pip install langchain-openai !pip install pymysql !pip install tidb-vector ``` Open the `integrate_with_langchain.ipynb` file in Jupyter Notebook, and then add the following code to import the required packages: ```python from langchain_community.document_loaders import TextLoader from langchain_community.vectorstores import TiDBVectorStore from langchain_openai import OpenAIEmbeddings from langchain_text_splitters import CharacterTextSplitter ``` ### Step 3. Set up your environment Configure the environment variables depending on the TiDB deployment option you've selected. For a TiDB Cloud Starter cluster, take the following steps to obtain the cluster connection string and configure environment variables: 1. Navigate to the [**Clusters**](https://tidbcloud.com/console/clusters) page, and then click the name of your target cluster to go to its overview page. 2. Click **Connect** in the upper-right corner. A connection dialog is displayed. 3. Ensure the configurations in the connection dialog match your operating environment. - **Connection Type** is set to `Public`. - **Branch** is set to `main`. - **Connect With** is set to `SQLAlchemy`. - **Operating System** matches your environment. 4. Click the **PyMySQL** tab and copy the connection string. > **Tip:** > > If you have not set a password yet, click **Generate Password** to generate a random password. 5. Configure environment variables. This document uses [OpenAI](https://platform.openai.com/docs/introduction) as the embedding model provider. In this step, you need to provide the connection string obtained from the previous step and your [OpenAI API key](https://platform.openai.com/docs/quickstart/step-2-set-up-your-api-key). To configure the environment variables, run the following code. You will be prompted to enter your connection string and OpenAI API key: ```python # Use getpass to securely prompt for environment variables in your terminal. import getpass import os # Copy your connection string from the TiDB Cloud console. # Connection string format: "mysql+pymysql://:@:4000/?ssl_ca=/etc/ssl/cert.pem&ssl_verify_cert=true&ssl_verify_identity=true" tidb_connection_string = getpass.getpass("TiDB Connection String:") os.environ["OPENAI_API_KEY"] = getpass.getpass("OpenAI API Key:") ``` This document uses [OpenAI](https://platform.openai.com/docs/introduction) as the embedding model provider. In this step, you need to provide the connection string obtained from the previous step and your [OpenAI API key](https://platform.openai.com/docs/quickstart/step-2-set-up-your-api-key). To configure the environment variables, run the following code. You will be prompted to enter your connection string and OpenAI API key: ```python # Use getpass to securely prompt for environment variables in your terminal. import getpass import os # Connection string format: "mysql+pymysql://:@:4000/?ssl_ca=/etc/ssl/cert.pem&ssl_verify_cert=true&ssl_verify_identity=true" tidb_connection_string = getpass.getpass("TiDB Connection String:") os.environ["OPENAI_API_KEY"] = getpass.getpass("OpenAI API Key:") ``` Taking macOS as an example, the cluster connection string is as follows: ```dotenv TIDB_DATABASE_URL="mysql+pymysql://:@:/" # For example: TIDB_DATABASE_URL="mysql+pymysql://root@127.0.0.1:4000/test" ``` You need to modify the values of the connection parameters according to your TiDB cluster. If you are running TiDB on your local machine, `` is `127.0.0.1` by default. The initial `` is empty, so if you are starting the cluster for the first time, you can omit this field. The following are descriptions for each parameter: - ``: The username to connect to the TiDB cluster. - ``: The password to connect to the TiDB cluster. - ``: The host of the TiDB cluster. - ``: The port of the TiDB cluster. - ``: The name of the database you want to connect to. ### Step 4. Load the sample document #### Step 4.1 Download the sample document In your project directory, create a directory named `data/how_to/` and download the sample document [`state_of_the_union.txt`](https://github.com/langchain-ai/langchain/blob/master/docs/docs/how_to/state_of_the_union.txt) from the [langchain-ai/langchain](https://github.com/langchain-ai/langchain) GitHub repository. ```shell !mkdir -p 'data/how_to/' !wget 'https://raw.githubusercontent.com/langchain-ai/langchain/master/docs/docs/how_to/state_of_the_union.txt' -O 'data/how_to/state_of_the_union.txt' ``` #### Step 4.2 Load and split the document Load the sample document from `data/how_to/state_of_the_union.txt` and split it into chunks of approximately 1,000 characters each using a `CharacterTextSplitter`. ```python loader = TextLoader("data/how_to/state_of_the_union.txt") documents = loader.load() text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0) docs = text_splitter.split_documents(documents) ``` ### Step 5. Embed and store document vectors TiDB vector store supports both cosine distance (`consine`) and Euclidean distance (`l2`) for measuring similarity between vectors. The default strategy is cosine distance. The following code creates a table named `embedded_documents` in TiDB, which is optimized for vector search. ```python embeddings = OpenAIEmbeddings() vector_store = TiDBVectorStore.from_documents( documents=docs, embedding=embeddings, table_name="embedded_documents", connection_string=tidb_connection_string, distance_strategy="cosine", # default, another option is "l2" ) ``` Upon successful execution, you can directly view and access the `embedded_documents` table in your TiDB database. ### Step 6. Perform a vector search This step demonstrates how to query "What did the president say about Ketanji Brown Jackson" from the document `state_of_the_union.txt`. ```python query = "What did the president say about Ketanji Brown Jackson" ``` #### Option 1: Use `similarity_search_with_score()` The `similarity_search_with_score()` method calculates the vector space distance between the documents and the query. This distance serves as a similarity score, determined by the chosen `distance_strategy`. The method returns the top `k` documents with the lowest scores. A lower score indicates a higher similarity between a document and your query. ```python docs_with_score = vector_store.similarity_search_with_score(query, k=3) for doc, score in docs_with_score: print("-" * 80) print("Score: ", score) print(doc.page_content) print("-" * 80) ```
Expected output ```plain -------------------------------------------------------------------------------- Score: 0.18472413652518527 Tonight. I call on the Senate to: Pass the Freedom to Vote Act. Pass the John Lewis Voting Rights Act. And while you’re at it, pass the Disclose Act so Americans can know who is funding our elections. Tonight, I’d like to honor someone who has dedicated his life to serve this country: Justice Stephen Breyer—an Army veteran, Constitutional scholar, and retiring Justice of the United States Supreme Court. Justice Breyer, thank you for your service. One of the most serious constitutional responsibilities a President has is nominating someone to serve on the United States Supreme Court. And I did that 4 days ago, when I nominated Circuit Court of Appeals Judge Ketanji Brown Jackson. One of our nation’s top legal minds, who will continue Justice Breyer’s legacy of excellence. -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- Score: 0.21757513022785557 A former top litigator in private practice. A former federal public defender. And from a family of public school educators and police officers. A consensus builder. Since she’s been nominated, she’s received a broad range of support—from the Fraternal Order of Police to former judges appointed by Democrats and Republicans. And if we are to advance liberty and justice, we need to secure the Border and fix the immigration system. We can do both. At our border, we’ve installed new technology like cutting-edge scanners to better detect drug smuggling. We’ve set up joint patrols with Mexico and Guatemala to catch more human traffickers. We’re putting in place dedicated immigration judges so families fleeing persecution and violence can have their cases heard faster. We’re securing commitments and supporting partners in South and Central America to host more refugees and secure their own borders. -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- Score: 0.22676987253721725 And for our LGBTQ+ Americans, let’s finally get the bipartisan Equality Act to my desk. The onslaught of state laws targeting transgender Americans and their families is wrong. As I said last year, especially to our younger transgender Americans, I will always have your back as your President, so you can be yourself and reach your God-given potential. While it often appears that we never agree, that isn’t true. I signed 80 bipartisan bills into law last year. From preventing government shutdowns to protecting Asian-Americans from still-too-common hate crimes to reforming military justice. And soon, we’ll strengthen the Violence Against Women Act that I first wrote three decades ago. It is important for us to show the nation that we can come together and do big things. So tonight I’m offering a Unity Agenda for the Nation. Four big things we can do together. First, beat the opioid epidemic. -------------------------------------------------------------------------------- ```
#### Option 2: Use `similarity_search_with_relevance_scores()` The `similarity_search_with_relevance_scores()` method returns the top `k` documents with the highest relevance scores. A higher score indicates a higher degree of similarity between a document and your query. ```python docs_with_relevance_score = vector_store.similarity_search_with_relevance_scores(query, k=2) for doc, score in docs_with_relevance_score: print("-" * 80) print("Score: ", score) print(doc.page_content) print("-" * 80) ```
Expected output ```plain -------------------------------------------------------------------------------- Score: 0.8152758634748147 Tonight. I call on the Senate to: Pass the Freedom to Vote Act. Pass the John Lewis Voting Rights Act. And while you’re at it, pass the Disclose Act so Americans can know who is funding our elections. Tonight, I’d like to honor someone who has dedicated his life to serve this country: Justice Stephen Breyer—an Army veteran, Constitutional scholar, and retiring Justice of the United States Supreme Court. Justice Breyer, thank you for your service. One of the most serious constitutional responsibilities a President has is nominating someone to serve on the United States Supreme Court. And I did that 4 days ago, when I nominated Circuit Court of Appeals Judge Ketanji Brown Jackson. One of our nation’s top legal minds, who will continue Justice Breyer’s legacy of excellence. -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- Score: 0.7824248697721444 A former top litigator in private practice. A former federal public defender. And from a family of public school educators and police officers. A consensus builder. Since she’s been nominated, she’s received a broad range of support—from the Fraternal Order of Police to former judges appointed by Democrats and Republicans. And if we are to advance liberty and justice, we need to secure the Border and fix the immigration system. We can do both. At our border, we’ve installed new technology like cutting-edge scanners to better detect drug smuggling. We’ve set up joint patrols with Mexico and Guatemala to catch more human traffickers. We’re putting in place dedicated immigration judges so families fleeing persecution and violence can have their cases heard faster. We’re securing commitments and supporting partners in South and Central America to host more refugees and secure their own borders. -------------------------------------------------------------------------------- ```
### Use as a retriever In Langchain, a [retriever](https://python.langchain.com/v0.2/docs/concepts/#retrievers) is an interface that retrieves documents in response to an unstructured query, providing more functionality than a vector store. The following code demonstrates how to use TiDB vector store as a retriever. ```python retriever = vector_store.as_retriever( search_type="similarity_score_threshold", search_kwargs={"k": 3, "score_threshold": 0.8}, ) docs_retrieved = retriever.invoke(query) for doc in docs_retrieved: print("-" * 80) print(doc.page_content) print("-" * 80) ``` The expected output is as follows: ``` -------------------------------------------------------------------------------- Tonight. I call on the Senate to: Pass the Freedom to Vote Act. Pass the John Lewis Voting Rights Act. And while you’re at it, pass the Disclose Act so Americans can know who is funding our elections. Tonight, I’d like to honor someone who has dedicated his life to serve this country: Justice Stephen Breyer—an Army veteran, Constitutional scholar, and retiring Justice of the United States Supreme Court. Justice Breyer, thank you for your service. One of the most serious constitutional responsibilities a President has is nominating someone to serve on the United States Supreme Court. And I did that 4 days ago, when I nominated Circuit Court of Appeals Judge Ketanji Brown Jackson. One of our nation’s top legal minds, who will continue Justice Breyer’s legacy of excellence. -------------------------------------------------------------------------------- ``` ### Remove the vector store To remove an existing TiDB vector store, use the `drop_vectorstore()` method: ```python vector_store.drop_vectorstore() ``` ## Search with metadata filters To refine your searches, you can use metadata filters to retrieve specific nearest-neighbor results that match the applied filters. ### Supported metadata types Each document in the TiDB vector store can be paired with metadata, structured as key-value pairs within a JSON object. Keys are always strings, while values can be any of the following types: - String - Number: integer or floating point - Boolean: `true` or `false` For example, the following is a valid metadata payload: ```json { "page": 12, "book_title": "Siddhartha" } ``` ### Metadata filter syntax Available filters include the following: - `$or`: Selects vectors that match any one of the specified conditions. - `$and`: Selects vectors that match all the specified conditions. - `$eq`: Equal to the specified value. - `$ne`: Not equal to the specified value. - `$gt`: Greater than the specified value. - `$gte`: Greater than or equal to the specified value. - `$lt`: Less than the specified value. - `$lte`: Less than or equal to the specified value. - `$in`: In the specified array of values. - `$nin`: Not in the specified array of values. If the metadata of a document is as follows: ```json { "page": 12, "book_title": "Siddhartha" } ``` The following metadata filters can match this document: ```json { "page": 12 } ``` ```json { "page": { "$eq": 12 } } ``` ```json { "page": { "$in": [11, 12, 13] } } ``` ```json { "page": { "$nin": [13] } } ``` ```json { "page": { "$lt": 11 } } ``` ```json { "$or": [{ "page": 11 }, { "page": 12 }], "$and": [{ "page": 12 }, { "page": 13 }] } ``` In a metadata filter, TiDB treats each key-value pair as a separate filter clause and combines these clauses using the `AND` logical operator. ### Example The following example adds two documents to `TiDBVectorStore` and adds a `title` field to each document as the metadata: ```python vector_store.add_texts( texts=[ "TiDB Vector offers advanced, high-speed vector processing capabilities, enhancing AI workflows with efficient data handling and analytics support.", "TiDB Vector, starting as low as $10 per month for basic usage", ], metadatas=[ {"title": "TiDB Vector functionality"}, {"title": "TiDB Vector Pricing"}, ], ) ``` The expected output is as follows: ```plain [UUID('c782cb02-8eec-45be-a31f-fdb78914f0a7'), UUID('08dcd2ba-9f16-4f29-a9b7-18141f8edae3')] ``` Perform a similarity search with metadata filters: ```python docs_with_score = vector_store.similarity_search_with_score( "Introduction to TiDB Vector", filter={"title": "TiDB Vector functionality"}, k=4 ) for doc, score in docs_with_score: print("-" * 80) print("Score: ", score) print(doc.page_content) print("-" * 80) ``` The expected output is as follows: ```plain -------------------------------------------------------------------------------- Score: 0.12761409169211535 TiDB Vector offers advanced, high-speed vector processing capabilities, enhancing AI workflows with efficient data handling and analytics support. -------------------------------------------------------------------------------- ``` ## Advanced usage example: travel agent This section demonstrates a use case of integrating vector search with Langchain for a travel agent. The goal is to create personalized travel reports for clients, helping them find airports with specific amenities, such as clean lounges and vegetarian options. The process involves two main steps: 1. Perform a semantic search across airport reviews to identify airport codes that match the desired amenities. 2. Execute a SQL query to merge these codes with route information, highlighting airlines and destinations that align with user's preferences. ### Prepare data First, create a table to store airport route data: ```python # Create a table to store flight plan data. vector_store.tidb_vector_client.execute( """CREATE TABLE airplan_routes ( id INT AUTO_INCREMENT PRIMARY KEY, airport_code VARCHAR(10), airline_code VARCHAR(10), destination_code VARCHAR(10), route_details TEXT, duration TIME, frequency INT, airplane_type VARCHAR(50), price DECIMAL(10, 2), layover TEXT );""" ) # Insert some sample data into airplan_routes and the vector table. vector_store.tidb_vector_client.execute( """INSERT INTO airplan_routes ( airport_code, airline_code, destination_code, route_details, duration, frequency, airplane_type, price, layover ) VALUES ('JFK', 'DL', 'LAX', 'Non-stop from JFK to LAX.', '06:00:00', 5, 'Boeing 777', 299.99, 'None'), ('LAX', 'AA', 'ORD', 'Direct LAX to ORD route.', '04:00:00', 3, 'Airbus A320', 149.99, 'None'), ('EFGH', 'UA', 'SEA', 'Daily flights from SFO to SEA.', '02:30:00', 7, 'Boeing 737', 129.99, 'None'); """ ) vector_store.add_texts( texts=[ "Clean lounges and excellent vegetarian dining options. Highly recommended.", "Comfortable seating in lounge areas and diverse food selections, including vegetarian.", "Small airport with basic facilities.", ], metadatas=[ {"airport_code": "JFK"}, {"airport_code": "LAX"}, {"airport_code": "EFGH"}, ], ) ``` The expected output is as follows: ```plain [UUID('6dab390f-acd9-4c7d-b252-616606fbc89b'), UUID('9e811801-0e6b-4893-8886-60f4fb67ce69'), UUID('f426747c-0f7b-4c62-97ed-3eeb7c8dd76e')] ``` ### Perform a semantic search The following code searches for airports with clean facilities and vegetarian options: ```python retriever = vector_store.as_retriever( search_type="similarity_score_threshold", search_kwargs={"k": 3, "score_threshold": 0.85}, ) semantic_query = "Could you recommend a US airport with clean lounges and good vegetarian dining options?" reviews = retriever.invoke(semantic_query) for r in reviews: print("-" * 80) print(r.page_content) print(r.metadata) print("-" * 80) ``` The expected output is as follows: ```plain -------------------------------------------------------------------------------- Clean lounges and excellent vegetarian dining options. Highly recommended. {'airport_code': 'JFK'} -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- Comfortable seating in lounge areas and diverse food selections, including vegetarian. {'airport_code': 'LAX'} -------------------------------------------------------------------------------- ``` ### Retrieve detailed airport information Extract airport codes from the search results and query the database for detailed route information: ```python # Extracting airport codes from the metadata airport_codes = [review.metadata["airport_code"] for review in reviews] # Executing a query to get the airport details search_query = "SELECT * FROM airplan_routes WHERE airport_code IN :codes" params = {"codes": tuple(airport_codes)} airport_details = vector_store.tidb_vector_client.execute(search_query, params) airport_details.get("result") ``` The expected output is as follows: ```plain [(1, 'JFK', 'DL', 'LAX', 'Non-stop from JFK to LAX.', datetime.timedelta(seconds=21600), 5, 'Boeing 777', Decimal('299.99'), 'None'), (2, 'LAX', 'AA', 'ORD', 'Direct LAX to ORD route.', datetime.timedelta(seconds=14400), 3, 'Airbus A320', Decimal('149.99'), 'None')] ``` ### Streamline the process Alternatively, you can streamline the entire process using a single SQL query: ```python search_query = f""" SELECT VEC_Cosine_Distance(se.embedding, :query_vector) as distance, ar.*, se.document as airport_review FROM airplan_routes ar JOIN {TABLE_NAME} se ON ar.airport_code = JSON_UNQUOTE(JSON_EXTRACT(se.meta, '$.airport_code')) ORDER BY distance ASC LIMIT 5; """ query_vector = embeddings.embed_query(semantic_query) params = {"query_vector": str(query_vector)} airport_details = vector_store.tidb_vector_client.execute(search_query, params) airport_details.get("result") ``` The expected output is as follows: ```plain [(0.1219207353407008, 1, 'JFK', 'DL', 'LAX', 'Non-stop from JFK to LAX.', datetime.timedelta(seconds=21600), 5, 'Boeing 777', Decimal('299.99'), 'None', 'Clean lounges and excellent vegetarian dining options. Highly recommended.'), (0.14613754359804654, 2, 'LAX', 'AA', 'ORD', 'Direct LAX to ORD route.', datetime.timedelta(seconds=14400), 3, 'Airbus A320', Decimal('149.99'), 'None', 'Comfortable seating in lounge areas and diverse food selections, including vegetarian.'), (0.19840519342700513, 3, 'EFGH', 'UA', 'SEA', 'Daily flights from SFO to SEA.', datetime.timedelta(seconds=9000), 7, 'Boeing 737', Decimal('129.99'), 'None', 'Small airport with basic facilities.')] ``` ### Clean up data Finally, clean up the resources by dropping the created table: ```python vector_store.tidb_vector_client.execute("DROP TABLE airplan_routes") ``` The expected output is as follows: ```plain {'success': True, 'result': 0, 'error': None} ``` ================================================ FILE: src/ai/integrations/llamaindex.md ================================================ # Integrate Vector Search with LlamaIndex This tutorial demonstrates how to integrate the [vector search](https://docs.pingcap.com/tidbcloud/vector-search-overview) feature of TiDB with [LlamaIndex](https://www.llamaindex.ai). !!! note The vector search feature is only available for TiDB Self-Managed clusters and [TiDB Cloud Starter](https://docs.pingcap.com/tidbcloud/select-cluster-tier#tidb-cloud-starter) clusters. !!! tip You can view the complete [sample code](https://github.com/run-llama/llama_index/blob/main/docs/docs/examples/vector_stores/TiDBVector.ipynb) on Jupyter Notebook, or run the sample code directly in the [Colab](https://colab.research.google.com/github/run-llama/llama_index/blob/main/docs/docs/examples/vector_stores/TiDBVector.ipynb) online environment. ## Prerequisites To complete this tutorial, you need: - [Python 3.8 or higher](https://www.python.org/downloads/) installed. - [Jupyter Notebook](https://jupyter.org/install) installed. - [Git](https://git-scm.com/downloads) installed. - A TiDB cluster. ## Get started This section provides step-by-step instructions for integrating TiDB Vector Search with LlamaIndex to perform semantic searches. ### Step 1. Create a new Jupyter Notebook file In the root directory, create a new Jupyter Notebook file named `integrate_with_llamaindex.ipynb`: ```shell touch integrate_with_llamaindex.ipynb ``` ### Step 2. Install required dependencies In your project directory, run the following command to install the required packages: ```shell pip install llama-index-vector-stores-tidbvector pip install llama-index ``` Open the `integrate_with_llamaindex.ipynb` file in Jupyter Notebook and add the following code to import the required packages: ```python import textwrap from llama_index.core import SimpleDirectoryReader, StorageContext from llama_index.core import VectorStoreIndex from llama_index.vector_stores.tidbvector import TiDBVectorStore ``` ### Step 3. Configure environment variables Configure the environment variables depending on the TiDB deployment option you've selected. For a TiDB Cloud Starter cluster, take the following steps to obtain the cluster connection string and configure environment variables: 1. Navigate to the [**Clusters**](https://tidbcloud.com/console/clusters) page, and then click the name of your target cluster to go to its overview page. 2. Click **Connect** in the upper-right corner. A connection dialog is displayed. 3. Ensure the configurations in the connection dialog match your operating environment. - **Connection Type** is set to `Public`. - **Branch** is set to `main`. - **Connect With** is set to `SQLAlchemy`. - **Operating System** matches your environment. 4. Click the **PyMySQL** tab and copy the connection string. > **Tip:** > > If you have not set a password yet, click **Generate Password** to generate a random password. 5. Configure environment variables. This document uses [OpenAI](https://platform.openai.com/docs/introduction) as the embedding model provider. In this step, you need to provide the connection string obtained from the previous step and your [OpenAI API key](https://platform.openai.com/docs/quickstart/step-2-set-up-your-api-key). To configure the environment variables, run the following code. You will be prompted to enter your connection string and OpenAI API key: ```python # Use getpass to securely prompt for environment variables in your terminal. import getpass import os # Copy your connection string from the TiDB Cloud console. # Connection string format: "mysql+pymysql://:@:4000/?ssl_ca=/etc/ssl/cert.pem&ssl_verify_cert=true&ssl_verify_identity=true" tidb_connection_string = getpass.getpass("TiDB Connection String:") os.environ["OPENAI_API_KEY"] = getpass.getpass("OpenAI API Key:") ``` This document uses [OpenAI](https://platform.openai.com/docs/introduction) as the embedding model provider. In this step, you need to provide the connection string of your TiDB cluster and your [OpenAI API key](https://platform.openai.com/docs/quickstart/step-2-set-up-your-api-key). To configure the environment variables, run the following code. You will be prompted to enter your connection string and OpenAI API key: ```python # Use getpass to securely prompt for environment variables in your terminal. import getpass import os # Connection string format: "mysql+pymysql://:@:4000/?ssl_ca=/etc/ssl/cert.pem&ssl_verify_cert=true&ssl_verify_identity=true" tidb_connection_string = getpass.getpass("TiDB Connection String:") os.environ["OPENAI_API_KEY"] = getpass.getpass("OpenAI API Key:") ``` Taking macOS as an example, the cluster connection string is as follows: ```dotenv TIDB_DATABASE_URL="mysql+pymysql://:@:/" # For example: TIDB_DATABASE_URL="mysql+pymysql://root@127.0.0.1:4000/test" ``` You need to modify the parameters in the connection string according to your TiDB cluster. If you are running TiDB on your local machine, `` is `127.0.0.1` by default. The initial `` is empty, so if you are starting the cluster for the first time, you can omit this field. The following are descriptions for each parameter: - ``: The username to connect to the TiDB cluster. - ``: The password to connect to the TiDB cluster. - ``: The host of the TiDB cluster. - ``: The port of the TiDB cluster. - ``: The name of the database you want to connect to. ### Step 4. Load the sample document #### Step 4.1 Download the sample document In your project directory, create a directory named `data/paul_graham/` and download the sample document [`paul_graham_essay.txt`](https://github.com/run-llama/llama_index/blob/main/docs/docs/examples/data/paul_graham/paul_graham_essay.txt) from the [run-llama/llama_index](https://github.com/run-llama/llama_index) GitHub repository. ```shell !mkdir -p 'data/paul_graham/' !wget 'https://raw.githubusercontent.com/run-llama/llama_index/main/docs/docs/examples/data/paul_graham/paul_graham_essay.txt' -O 'data/paul_graham/paul_graham_essay.txt' ``` #### Step 4.2 Load the document Load the sample document from `data/paul_graham/paul_graham_essay.txt` using the `SimpleDirectoryReader` class. ```python documents = SimpleDirectoryReader("./data/paul_graham").load_data() print("Document ID:", documents[0].doc_id) for index, document in enumerate(documents): document.metadata = {"book": "paul_graham"} ``` ### Step 5. Embed and store document vectors #### Step 5.1 Initialize the TiDB vector store The following code creates a table named `paul_graham_test` in TiDB, which is optimized for vector search. ```python tidbvec = TiDBVectorStore( connection_string=tidb_connection_url, table_name="paul_graham_test", distance_strategy="cosine", vector_dimension=1536, drop_existing_table=False, ) ``` Upon successful execution, you can directly view and access the `paul_graham_test` table in your TiDB database. #### Step 5.2 Generate and store embeddings The following code parses the documents, generates embeddings, and stores them in the TiDB vector store. ```python storage_context = StorageContext.from_defaults(vector_store=tidbvec) index = VectorStoreIndex.from_documents( documents, storage_context=storage_context, show_progress=True ) ``` The expected output is as follows: ```plain Parsing nodes: 100%|██████████| 1/1 [00:00<00:00, 8.76it/s] Generating embeddings: 100%|██████████| 21/21 [00:02<00:00, 8.22it/s] ``` ### Step 6. Perform a vector search The following creates a query engine based on the TiDB vector store and performs a semantic similarity search. ```python query_engine = index.as_query_engine() response = query_engine.query("What did the author do?") print(textwrap.fill(str(response), 100)) ``` > **Note** > > `TiDBVectorStore` only supports the [`default`](https://docs.llamaindex.ai/en/stable/api_reference/storage/vector_store/?h=vectorstorequerymode#llama_index.core.vector_stores.types.VectorStoreQueryMode) query mode. The expected output is as follows: ```plain The author worked on writing, programming, building microcomputers, giving talks at conferences, publishing essays online, developing spam filters, painting, hosting dinner parties, and purchasing a building for office use. ``` ### Step 7. Search with metadata filters To refine your searches, you can use metadata filters to retrieve specific nearest-neighbor results that match the applied filters. #### Query with `book != "paul_graham"` filter The following example excludes results where the `book` metadata field is `"paul_graham"`: ```python from llama_index.core.vector_stores.types import ( MetadataFilter, MetadataFilters, ) query_engine = index.as_query_engine( filters=MetadataFilters( filters=[ MetadataFilter(key="book", value="paul_graham", operator="!="), ] ), similarity_top_k=2, ) response = query_engine.query("What did the author learn?") print(textwrap.fill(str(response), 100)) ``` The expected output is as follows: ```plain Empty Response ``` #### Query with `book == "paul_graham"` filter The following example filters results to include only documents where the `book` metadata field is `"paul_graham"`: ```python from llama_index.core.vector_stores.types import ( MetadataFilter, MetadataFilters, ) query_engine = index.as_query_engine( filters=MetadataFilters( filters=[ MetadataFilter(key="book", value="paul_graham", operator="=="), ] ), similarity_top_k=2, ) response = query_engine.query("What did the author learn?") print(textwrap.fill(str(response), 100)) ``` The expected output is as follows: ```plain The author learned programming on an IBM 1401 using an early version of Fortran in 9th grade, then later transitioned to working with microcomputers like the TRS-80 and Apple II. Additionally, the author studied philosophy in college but found it unfulfilling, leading to a switch to studying AI. Later on, the author attended art school in both the US and Italy, where they observed a lack of substantial teaching in the painting department. ``` ### Step 8. Delete documents Delete the first document from the index: ```python tidbvec.delete(documents[0].doc_id) ``` Check whether the documents had been deleted: ```python query_engine = index.as_query_engine() response = query_engine.query("What did the author learn?") print(textwrap.fill(str(response), 100)) ``` The expected output is as follows: ```plain Empty Response ``` ================================================ FILE: src/ai/integrations/tidb-mcp-claude-code.md ================================================ --- title: Get started with Claude Code and TiDB MCP Server description: This guide shows you how to configure the TiDB MCP Server in Claude Code. --- # Get started with Claude Code and TiDB MCP Server This guide shows you how to configure the TiDB MCP Server in Claude Code. ## Prerequisites Before you begin, ensure you have the following: - **Claude Code**: Install it from [claude.com](https://claude.com/product/claude-code). - **Python (>=3.10) and uv**: Ensure Python (version 3.10 or later) and uv are installed. Follow the [installation guide](https://docs.astral.sh/uv/getting-started/installation/) to install uv. - **A TiDB cluster**: For a managed option, create a TiDB Cloud Starter cluster at [tidbcloud.com](https://tidbcloud.com/free-trial). ## Connect to TiDB Cloud Starter (recommended) Use the TiDB Cloud console to generate a ready-to-run Claude Code command. 1. Go to the [Clusters](https://tidbcloud.com/console/clusters) page, select your cluster, and then click **Use with AI Tools** in the upper-right corner. 2. In the **Access `your_cluster_name` with AI tools** dialog, select the **Branch** and **Database** that Claude Code should access. 3. Review the **Prerequisites** list in the dialog and install any missing dependencies. 4. Configure the root password: - If you have not set a password yet, click **Generate Password** and store it in a secure location (it is shown only once). - If a password already exists, enter it in the **Enter the password for easy setup** field. - If you forget the password, click **Reset password** in the **Prerequisites** section to generate a new one. 5. Select the **Claude Code** tab, copy the setup command, and run it in your terminal. ## Manual configuration (any TiDB cluster) If you prefer manual setup, use one of the following methods and replace the placeholders with your connection parameters. ### Method 1: CLI command ```bash claude mcp add --transport stdio TiDB \ --env TIDB_HOST='' \ --env TIDB_PORT= \ --env TIDB_USERNAME='' \ --env TIDB_PASSWORD='' \ --env TIDB_DATABASE='' \ -- uvx --from 'pytidb[mcp]' 'tidb-mcp-server' ``` ### Method 2: Project config file Add the following configuration to your project-level `.mcp.json` file. For details, see the [Claude Code MCP documentation](https://code.claude.com/docs/en/mcp#project-scope). ```json { "mcpServers": { "TiDB": { "type": "stdio", "command": "uvx", "args": ["--from", "pytidb[mcp]", "tidb-mcp-server"], "env": { "TIDB_HOST": "", "TIDB_PORT": "", "TIDB_USERNAME": "", "TIDB_PASSWORD": "", "TIDB_DATABASE": "" } } } } ``` ## See also - [TiDB MCP Server](./tidb-mcp-server.md) ================================================ FILE: src/ai/integrations/tidb-mcp-claude-desktop.md ================================================ --- title: Get started with Claude Desktop and TiDB MCP Server description: This guide shows you how to configure the TiDB MCP Server in Claude Desktop. --- # Integrate TiDB MCP Server with Claude Desktop This guide shows you how to configure the TiDB MCP Server in Claude Desktop. ## Prerequisites Before you begin, ensure you have the following: - **Claude Desktop**: Download and install Claude Desktop from [claude.ai](https://claude.ai/download). - **Python (>=3.10) and uv**: Ensure Python (version 3.10 or later) and uv is installed. Follow the [installation guide](https://docs.astral.sh/uv/getting-started/installation/) to install uv. - **A TiDB Cloud Starter Cluster**: You can create a free TiDB cluster here [tidbcloud.com](https://tidbcloud.com/free-trial). ## Setup steps You can follow the steps below to set up the TiDB MCP Server in Claude Desktop: 1. Open the **Settings** dialog. 2. Click the **Developers** tab in the dialog. 3. Click the **Edit Config** button to open the MCP config file `claude_desktop_config.json`. 4. Copy the following configuration into the `claude_desktop_config.json` file. ```json { "mcpServers": { "TiDB": { "command": "uvx --from pytidb[mcp] tidb-mcp-server", "env": { "TIDB_HOST": "localhost", "TIDB_PORT": "4000", "TIDB_USERNAME": "root", "TIDB_PASSWORD": "", "TIDB_DATABASE": "test" } } } } ``` 5. Go to the [TiDB Cloud cluster page](https://tidbcloud.com/console/clusters) and navigate to the cluster you want to connect to. 6. Click the **Connect** button to get the connection parameters, and replace the `TIDB_HOST`, `TIDB_PORT`, `TIDB_USERNAME`, `TIDB_PASSWORD`, and `TIDB_DATABASE` values with your own. 7. Restart Claude Desktop. For more details, please refer to the quickstart guide to learn [how to configure the MCP server in Claude Desktop](https://modelcontextprotocol.io/quickstart/user). ================================================ FILE: src/ai/integrations/tidb-mcp-cursor.md ================================================ --- title: Get started with Cursor and TiDB MCP Server description: This guide shows you how to configure the TiDB MCP Server in the Cursor editor. --- # Get started with Cursor and TiDB MCP Server This guide shows you how to configure the TiDB MCP Server in the Cursor editor. For one-click installation, you can click the following button: [![Install TiDB MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](cursor://anysphere.cursor-deeplink/mcp/install?name=TiDB&config=eyJjb21tYW5kIjoidXZ4IC0tZnJvbSBweXRpZGJbbWNwXSB0aWRiLW1jcC1zZXJ2ZXIiLCJlbnYiOnsiVElEQl9IT1NUIjoibG9jYWxob3N0IiwiVElEQl9QT1JUIjoiNDAwMCIsIlRJREJfVVNFUk5BTU0iOiJyb290IiwiVElEQl9QQVNTV09SRCI6IiIsIlRJREJfREFUQUJBU0UiOiJ0ZXN0In19) ## Prerequisites Before you begin, ensure you have the following: - **Cursor Editor**: Download and install Cursor from [cursor.com](https://cursor.com). - **Python (>=3.10) and uv**: Ensure Python (version 3.10 or later) and uv are installed. Follow the [installation guide](https://docs.astral.sh/uv/getting-started/installation/) to install uv. - **A TiDB cluster**: For a managed option, create a TiDB Cloud Starter cluster at [tidbcloud.com](https://tidbcloud.com/free-trial). ## Connect to TiDB Cloud Starter (recommended) Use the TiDB Cloud console to create a Cursor configuration with your cluster credentials. 1. Go to the [Clusters](https://tidbcloud.com/console/clusters) page, select your cluster, and then click **Use with AI Tools** in the upper-right corner. 2. In the **Access `your_cluster_name` with AI tools** dialog, select the **Branch** and **Database** that Cursor should access. 3. Review the **Prerequisites** list in the dialog and install any missing dependencies. 4. Configure the root password: - If you have not set a password yet, click **Generate Password** and store it in a secure location (it is shown only once). - If a password already exists, enter it in the **Enter the password for easy setup** field. - If you forget the password, click **Reset password** in the **Prerequisites** section to generate a new one. 5. Select the **Cursor** tab, click **Add to Cursor**, and then click **Install** in Cursor. ## Manual configuration (any TiDB cluster) If you prefer manual setup, add the following configuration to your `.cursor/mcp.json` file and replace the placeholders with your connection parameters: ```json { "mcpServers": { "TiDB": { "command": "uvx --from pytidb[mcp] tidb-mcp-server", "env": { "TIDB_HOST": "", "TIDB_PORT": "", "TIDB_USERNAME": "", "TIDB_PASSWORD": "", "TIDB_DATABASE": "" } } } } ``` For more details, see the [Model Context Protocol documentation](https://docs.cursor.com/context/model-context-protocol#configuring-mcp-servers). ## Troubleshooting If you encounter any issues installing the TiDB MCP Server, check the MCP logs in the Cursor editor. 1. Click **View** > **Output** in the main menu at the top of the editor. 2. Select **MCP** from the dropdown menu in the **Output** panel. 3. If you see errors like `[error] Could not start MCP server tidb-mcp-server: Error: spawn uvx ENOENT`, it means the `uvx` command may not exist in your `$PATH` system variable. For macOS users, you can install `uvx` by running `brew install uv`. ================================================ FILE: src/ai/integrations/tidb-mcp-server.md ================================================ --- title: TiDB MCP Server description: Manage your TiDB databases using natural language instructions with the TiDB MCP Server. --- # TiDB MCP Server The TiDB MCP Server is an open-source tool that enables you to interact with TiDB databases using natural language instructions. ## Understanding MCP and TiDB MCP Server The [Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction) is a protocol standardizes communication between LLMs and external tools. MCP adopts a client-server architecture, allowing a host application to connect to multiple external servers: - **Hosts**: AI-powered applications, such as Claude Desktop or IDEs like Cursor, that initiate connections to MCP servers. - **Clients**: Components embedded within host applications that establish one-to-one connections with individual MCP servers. - **Servers**: External services, such as the **TiDB MCP Server**, which provide tools, context, and prompts to clients for interacting with external systems. The **TiDB MCP Server** is an MCP-compatible server that provides tools, context to MCP clients for interacting with TiDB databases. ## Prerequisites Before you begin, ensure you have the following: - **An MCP-compatible client**: For example, [Cursor](./tidb-mcp-cursor.md) or [Claude Desktop](./tidb-mcp-claude-desktop.md). - **Python (>=3.10) and uv**: Ensure Python (version 3.10 or later) and uv is installed. Follow the [installation guide](https://docs.astral.sh/uv/getting-started/installation/) to install uv. - **A TiDB Cloud Starter Cluster**: You can create a free TiDB cluster here [tidbcloud.com](https://tidbcloud.com/free-trial). ## Supported MCP Clients Refer to the following guides for detailed examples of using the TiDB MCP Server with specific MCP clients: - [Cursor](./tidb-mcp-cursor.md) - [Claude Desktop](./tidb-mcp-claude-desktop.md) If your MCP client is not listed above, please follow the setup steps below. ## Setup steps The TiDB MCP Server supports two modes to integrate with MCP clients: - Standard Input/Output (STDIO) mode (default) - Server-Sent Events (SSE) mode TiDB MCP Server uses STDIO mode by default, which is not required to start up a standalone server in advance. You can choose one of them to set up the TiDB MCP Server in your MCP client. ### STDIO Mode To set up the TiDB MCP Server in your MCP client using STDIO mode, follow these steps: 1. Refer to your MCP client’s documentation to learn how to configure the MCP Server. 2. Go to your [TiDB Cloud clusters](https://tidbcloud.com/console/clusters) page and navigate to your cluster. 3. Click the **Connect** button in the cluster page to get the connection parameters. 4. Configure the TiDB MCP Server with your connection parameters in the `mcpServers` section of your AI application’s configuration file. Example MCP configuration file: ```json { "mcpServers": { "TiDB": { "command": "uvx --from pytidb[mcp] tidb-mcp-server", "env": { "TIDB_HOST": "localhost", "TIDB_PORT": "4000", "TIDB_USERNAME": "root", "TIDB_PASSWORD": "", "TIDB_DATABASE": "test" } } } } ``` ### Server-Sent Events (SSE) Mode To set up the TiDB MCP Server in your MCP client using SSE mode, follow these steps: 1. Refer to your MCP client’s documentation to learn how to configure the MCP Server. 2. Go to your [TiDB Cloud clusters](https://tidbcloud.com/console/clusters) page and navigate to your cluster. 3. Click the **Connect** button in the cluster page to get the connection parameters. 4. Create a `.env` file with your own connection parameters. Example `.env` file: ```bash cat > .env <=3.10) and uv**: Ensure Python (version 3.10 or later) and uv are installed. Follow the [installation guide](https://docs.astral.sh/uv/getting-started/installation/) to install uv. - **A TiDB cluster**: For a managed option, create a TiDB Cloud Starter cluster at [tidbcloud.com](https://tidbcloud.com/free-trial). ## Connect to TiDB Cloud Starter (recommended) Use the TiDB Cloud console to generate a VS Code configuration. 1. Go to the [Clusters](https://tidbcloud.com/console/clusters) page, select your cluster, and then click **Use with AI Tools** in the upper-right corner. 2. In the **Access `your_cluster_name` with AI tools** dialog, select the **Branch** and **Database** that VS Code should access. 3. Review the **Prerequisites** list in the dialog and install any missing dependencies. 4. Configure the root password: - If you have not set a password yet, click **Generate Password** and store it in a secure location (it is shown only once). - If a password already exists, enter it in the **Enter the password for easy setup** field. - If you forget the password, click **Reset password** in the **Prerequisites** section to generate a new one. 5. Select the **VS Code** tab, click **Add to VS Code**, and then click **Install** in VS Code. ## Manual configuration (any TiDB cluster) If you prefer manual setup, add the following configuration to your `.vscode/mcp.json` file and replace the placeholders with your connection parameters: ```json { "mcpServers": { "TiDB": { "type": "stdio", "command": "uvx", "args": ["--from", "pytidb[mcp]", "tidb-mcp-server"], "env": { "TIDB_HOST": "", "TIDB_PORT": "", "TIDB_USERNAME": "", "TIDB_PASSWORD": "", "TIDB_DATABASE": "" } } } } ``` ## See also - [TiDB MCP Server](./tidb-mcp-server.md) ================================================ FILE: src/ai/integrations/tidb-mcp-windsurf.md ================================================ --- title: Get started with Windsurf and TiDB MCP Server description: This guide shows you how to configure the TiDB MCP Server in Windsurf. --- # Get started with Windsurf and TiDB MCP Server This guide shows you how to configure the TiDB MCP Server in Windsurf. ## Prerequisites Before you begin, ensure you have the following: - **Windsurf**: Download and install Windsurf from [windsurf.com](https://windsurf.com). - **Python (>=3.10) and uv**: Ensure Python (version 3.10 or later) and uv are installed. Follow the [installation guide](https://docs.astral.sh/uv/getting-started/installation/) to install uv. - **A TiDB cluster**: For a managed option, create a TiDB Cloud Starter cluster at [tidbcloud.com](https://tidbcloud.com/free-trial). ## Connect to TiDB Cloud Starter (recommended) Use the TiDB Cloud console to gather the connection details, then update Windsurf's MCP configuration. 1. Go to the [Clusters](https://tidbcloud.com/console/clusters) page, select your cluster, and then click **Use with AI Tools** in the upper-right corner. 2. In the **Access `your_cluster_name` with AI tools** dialog, select the **Branch** and **Database** that Windsurf should access. 3. Review the **Prerequisites** list in the dialog and install any missing dependencies. 4. Configure the root password: - If you have not set a password yet, click **Generate Password** and store it in a secure location (it is shown only once). - If a password already exists, enter it in the **Enter the password for easy setup** field. - If you forget the password, click **Reset password** in the **Prerequisites** section to generate a new one. 5. Select the **Windsurf** tab and copy the provided connection values. 6. Update your `mcp_config.json` file using the copied values. For more information, see the [Windsurf MCP documentation](https://docs.windsurf.com/windsurf/cascade/mcp#adding-a-new-mcp-plugin). ## Manual configuration (any TiDB cluster) If you prefer manual setup, update your `mcp_config.json` file as follows and replace the placeholders with your connection parameters: ```json { "mcpServers": { "TiDB": { "command": "uvx", "args": ["--from", "pytidb[mcp]", "tidb-mcp-server"], "env": { "TIDB_HOST": "", "TIDB_PORT": "", "TIDB_USERNAME": "", "TIDB_PASSWORD": "", "TIDB_DATABASE": "" } } } } ``` ## See also - [TiDB MCP Server](./tidb-mcp-server.md) ================================================ FILE: src/ai/javascripts/mathjax.js ================================================ window.MathJax = { tex: { inlineMath: [["\\(", "\\)"]], displayMath: [["\\[", "\\]"]], processEscapes: true, processEnvironments: true }, options: { ignoreHtmlClass: ".*|", processHtmlClass: "arithmatex" } }; document$.subscribe(() => { MathJax.startup.output.clearCache() MathJax.typesetClear() MathJax.texReset() MathJax.typesetPromise() }) ================================================ FILE: src/ai/quickstart.md ================================================ --- title: Quickstart description: Get started with TiDB using Python SDK. --- # Quickstart In this guide, you will learn how to get started with [vector search](./concepts/vector-search.md) in TiDB using Python SDK. Follow along to build your first AI application working with TiDB. ## Prerequisites - Go [tidbcloud.com](https://tidbcloud.com/) to create a TiDB Cloud Starter cluster for free or using [tiup playground](https://docs.pingcap.com/tidb/stable/quick-start-with-tidb/#deploy-a-local-test-cluster) to a TiDB Self-Managed cluster for local testing. ## Installation [pytidb](https://github.com/pingcap/pytidb) is the official Python SDK for TiDB, designed to help developers build AI applications efficiently. To install the Python SDK, run the following command: ```bash pip install pytidb ``` To use built-in embedding function, install the `models` extension (alternative): ```bash pip install "pytidb[models]" ``` ## Connect to database === "TiDB Cloud Starter" You can get these connection parameters from the [TiDB Cloud console](https://tidbcloud.com/clusters): 1. Navigate to the [Clusters page](https://tidbcloud.com/clusters), and then click the name of your target cluster to go to its overview page. 2. Click **Connect** in the upper-right corner. A connection dialog is displayed, with connection parameters listed. For example, if the connection parameters are displayed as follows: ```text HOST: gateway01.us-east-1.prod.shared.aws.tidbcloud.com PORT: 4000 USERNAME: 4EfqPF23YKBxaQb.root PASSWORD: abcd1234 DATABASE: test CA: /etc/ssl/cert.pem ``` The corresponding Python code to connect to the TiDB Cloud Starter cluster would be as follows: ```python from pytidb import TiDBClient client = TiDBClient.connect( host="gateway01.us-east-1.prod.shared.aws.tidbcloud.com", port=4000, username="4EfqPF23YKBxaQb.root", password="abcd1234", database="test", ) ``` > **Note:** The preceding example is for demonstration purposes only. You need to fill in the parameters with your own values and keep them secure. === "TiDB Self-Managed" Here is a basic example for connecting to a self-managed TiDB cluster: ```python from pytidb import TiDBClient client = TiDBClient.connect( host="localhost", port=4000, username="root", password="", database="test", ensure_db=True, ) ``` > **Tip:** Please modify the connection parameters according to your actual deployment. Once connected, you can use the `client` object to operate tables, query data, and more. ## Create an embedding function When working with [embedding models](./concepts/vector-search.md#embedding-model), you can leverage the embedding function to automatically vectorize your data at both insertion and query stages. It natively supports popular embedding models like OpenAI, Jina AI, Hugging Face, Sentence Transformers, and others. === "OpenAI" Go [OpenAI platform](https://platform.openai.com/api-keys) to create your API key for embedding. ```python from pytidb.embeddings import EmbeddingFunction text_embed = EmbeddingFunction( model_name="openai/text-embedding-3-small", api_key="", ) ``` === "Jina AI" Go [Jina AI](https://jina.ai/embeddings/) to create your API key for embedding. ```python from pytidb.embeddings import EmbeddingFunction text_embed = EmbeddingFunction( model_name="jina/jina-embeddings-v3", api_key="", ) ``` ## Create a table As an example, create a table named `chunks` with the following columns: - `id` (int): the ID of the chunk. - `text` (text): the text content of the chunk. - `text_vec` (vector): the vector embeddings of the text. - `user_id` (int): the ID of the user who created the chunk. === "Python" ```python hl_lines="6" from pytidb.schema import TableModel, Field, VectorField class Chunk(TableModel): id: int | None = Field(default=None, primary_key=True) text: str = Field() text_vec: list[float] = text_embed.VectorField(source_field="text") user_id: int = Field() table = client.create_table(schema=Chunk, if_exists="overwrite") ``` Once created, you can use the `table` object to insert data, search data, and more. ## Insert Data Now let's add some sample data to our table. ```python table.bulk_insert([ # 👇 The text will be automatically embedded and populated into the `text_vec` field. Chunk(text="PyTiDB is a Python library for developers to connect to TiDB.", user_id=2), Chunk(text="LlamaIndex is a framework for building AI applications.", user_id=2), Chunk(text="OpenAI is a company and platform that provides AI models service and tools.", user_id=3), ]) ``` ## Search for nearest neighbors To search for nearest neighbors of a given query, you can use the `table.search()` method, it will perform a [vector search](./guides/vector-search.md) by default. ```python table.search( # 👇 Pass the query text directly, it will be embedded to a query vector automatically. "A library for my artificial intelligence software" ) .limit(3).to_list() ``` In this example, vector search compares the query vector with the stored vectors in the `text_vec` field of the `chunks` table and returns the top 3 most semantically relevant results based on similarity scores. The closer `_distance` means the more similar the two vectors are. ```json title="Expected output" [ { 'id': 2, 'text': 'LlamaIndex is a framework for building AI applications.', 'text_vec': [...], 'user_id': 2, '_distance': 0.5719928358786761, '_score': 0.4280071641213239 }, { 'id': 3, 'text': 'OpenAI is a company and platform that provides AI models service and tools.', 'text_vec': [...], 'user_id': 3, '_distance': 0.603133726213383, '_score': 0.396866273786617 }, { 'id': 1, 'text': 'PyTiDB is a Python library for developers to connect to TiDB.', 'text_vec': [...], 'user_id': 2, '_distance': 0.6202191842385758, '_score': 0.3797808157614242 } ] ``` ## Delete data To delete a specific row from the table, you can use the `table.delete()` method: ```python table.delete({ "id": 1 }) ``` ## Drop table When you no longer need a table, you can drop it using the `client.drop_table()` method: ```python client.drop_table("chunks") ``` ## Next steps - Learn more details about [Vector Search](./guides/vector-search.md), [Fulltext Search](./guides/fulltext-search.md) and [Hybrid Search](./guides/hybrid-search.md) in TiDB. ================================================ FILE: src/robots.txt ================================================ User-agent: * Allow: / Sitemap: https://pingcap.github.io/sitemap.xml ================================================ FILE: src/styles/extra.css ================================================ /* Dark mode */ [data-md-color-scheme="tidb-dark"] { --md-default-fg-color: hsla(0, 0%, 95%, 1); --md-default-fg-color--light: hsla(0, 0%, 95%, 0.7); --md-default-fg-color--lighter: hsla(0, 0%, 95%, 0.3); --md-default-fg-color--lightest: hsla(0, 0%, 90%, 0.12); --md-default-bg-color: hsl(0, 0%, 10%); --md-default-bg-color--light: hsla(0, 0%, 10%, 0.54); --md-default-bg-color--lighter: hsla(0, 0%, 10%, 0.32); --md-default-bg-color--lightest: hsla(0, 0%, 10%, 0.07); /* Code color shades */ --md-code-fg-color: hsla(220, 13%, 85%, 1); --md-code-bg-color: hsla(223, 13%, 16%, 1); /* Code highlighting color shades */ --md-code-hl-color: hsla(220, 100%, 67%, 1); --md-code-hl-color--light: hsla(220, 91%, 39%, 0.1); /* Code highlighting syntax color shades */ --md-code-hl-number-color: hsla(14, 80%, 55%, 1); --md-code-hl-special-color: hsla(340, 80%, 60%, 1); --md-code-hl-function-color: hsla(200, 80%, 65%, 1); --md-code-hl-constant-color: hsla(250, 70%, 65%, 1); --md-code-hl-keyword-color: hsla(219, 80%, 65%, 1); --md-code-hl-string-color: hsla(150, 60%, 45%, 1); --md-code-hl-name-color: var(--md-code-fg-color); --md-code-hl-operator-color: var(--md-default-fg-color--light); --md-code-hl-punctuation-color: var(--md-default-fg-color--light); --md-code-hl-comment-color: var(--md-default-fg-color--light); --md-code-hl-generic-color: var(--md-default-fg-color--light); --md-code-hl-variable-color: var(--md-default-fg-color--light); /* Typeset color shades */ --md-typeset-color: var(--md-default-fg-color); /* Typeset `a` color shades */ --md-typeset-a-color: var(--md-accent-fg-color); /* Typeset `del` and `ins` color shades */ --md-typeset-del-color: hsla(6, 90%, 60%, 0.15); --md-typeset-ins-color: hsla(150, 90%, 44%, 0.15); /* Typeset `kbd` color shades */ --md-typeset-kbd-color: hsla(0, 0%, 98%, 1); --md-typeset-kbd-accent-color: hsla(0, 100%, 100%, 1); --md-typeset-kbd-border-color: hsla(0, 0%, 72%, 1); /* Typeset `mark` color shades */ --md-typeset-mark-color: hsla(48, 100%, 70%, 0.5); /* Typeset `table` color shades */ --md-typeset-table-color: hsla(0, 0%, 0%, 0.12); --md-typeset-table-color--light: hsla(0, 0%, 0%, 0.035); /* Admonition color shades */ --md-admonition-fg-color: var(--md-default-fg-color); --md-admonition-bg-color: var(--md-default-bg-color); /* Warning color shades */ --md-warning-fg-color: hsla(0, 0%, 0%, 0.87); --md-warning-bg-color: hsla(60, 100%, 80%, 1); /* Footer color shades */ --md-footer-fg-color: hsla(0, 0%, 100%, 1); --md-footer-fg-color--light: hsla(0, 0%, 100%, 0.7); --md-footer-fg-color--lighter: hsla(0, 0%, 100%, 0.45); --md-footer-bg-color: hsla(0, 0%, 0%, 0.87); --md-footer-bg-color--dark: hsla(0, 0%, 0%, 0.32); /* Shadow depth 1 */ --md-shadow-z1: 0 0.25rem 0.625rem hsla(0, 0%, 0%, 0.05), 0 0 0.0625rem hsla(0, 0%, 0%, 0.1); /* Shadow depth 2 */ --md-shadow-z2: 0 0.25rem 0.625rem hsla(0, 0%, 0%, 0.1), 0 0 0.0625rem hsla(0, 0%, 0%, 0.25); /* Shadow depth 3 */ --md-shadow-z3: 0 0.25rem 0.625rem hsla(0, 0%, 0%, 0.2), 0 0 0.0625rem hsla(0, 0%, 0%, 0.35); /* Primary - Navbar */ --md-primary-fg-color: hsla(0, 0%, 0%, 1); --md-primary-fg-color--light: hsla(0, 0%, 0%, 0.9); --md-primary-fg-color--dark: hsla(0, 0%, 0%, 0.8); --md-primary-bg-color: hsla(0, 0%, 100%, 1); --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7); --md-accent-fg-color: #de243d; --md-accent-fg-color--transparent: hsla(0, 0%, 100%, 0.5); --md-accent-bg-color: hsla(0, 0%, 100%, 0.9); --md-accent-bg-color--light: hsla(0, 0%, 100%, 0.8); } /* Light mode */ [data-md-color-scheme="tidb-light"] { --md-default-fg-color: hsla(0, 0%, 10%, 1); --md-default-fg-color--light: hsla(0, 0%, 10%, 0.7); --md-default-fg-color--lighter: hsla(0, 0%, 10%, 0.3); --md-default-fg-color--lightest: hsla(0, 0%, 10%, 0.12); --md-default-bg-color: hsl(0, 0%, 100%); --md-default-bg-color--light: hsla(0, 0%, 100%, 0.54); --md-default-bg-color--lighter: hsla(0, 0%, 100%, 0.32); --md-default-bg-color--lightest: hsla(0, 0%, 100%, 0.07); /* Code color shades */ --md-code-fg-color: #2d2d2d; --md-code-bg-color: #f7f7f9; /* Typeset color shades */ --md-typeset-color: var(--md-default-fg-color); /* Typeset `a` color shades */ --md-typeset-a-color: var(--md-accent-fg-color); /* Typeset `del` and `ins` color shades */ --md-typeset-del-color: hsla(6, 90%, 60%, 0.15); --md-typeset-ins-color: hsla(150, 90%, 44%, 0.15); /* Typeset `kbd` color shades */ --md-typeset-kbd-color: hsla(0, 0%, 10%, 1); --md-typeset-kbd-accent-color: hsla(0, 0%, 0%, 1); --md-typeset-kbd-border-color: hsla(0, 0%, 72%, 1); /* Typeset `mark` color shades */ --md-typeset-mark-color: hsla(48, 100%, 70%, 0.5); /* Typeset `table` color shades */ --md-typeset-table-color: hsla(0, 0%, 0%, 0.12); --md-typeset-table-color--light: hsla(0, 0%, 0%, 0.035); /* Admonition color shades */ --md-admonition-fg-color: var(--md-default-fg-color); --md-admonition-bg-color: var(--md-default-bg-color); /* Warning color shades */ --md-warning-fg-color: hsla(0, 0%, 0%, 0.87); --md-warning-bg-color: hsla(60, 100%, 80%, 1); /* Footer color shades */ --md-footer-fg-color: hsla(0, 0%, 100%, 1); --md-footer-fg-color--light: hsla(0, 0%, 100%, 0.7); --md-footer-fg-color--lighter: hsla(0, 0%, 100%, 0.45); --md-footer-bg-color: hsla(0, 0%, 0%, 0.87); --md-footer-bg-color--dark: hsla(0, 0%, 0%, 0.32); /* Shadow depth 1 */ --md-shadow-z1: 0 0.25rem 0.625rem hsla(0, 0%, 0%, 0.05), 0 0 0.0625rem hsla(0, 0%, 0%, 0.1); /* Shadow depth 2 */ --md-shadow-z2: 0 0.25rem 0.625rem hsla(0, 0%, 0%, 0.1), 0 0 0.0625rem hsla(0, 0%, 0%, 0.25); /* Shadow depth 3 */ --md-shadow-z3: 0 0.25rem 0.625rem hsla(0, 0%, 0%, 0.2), 0 0 0.0625rem hsla(0, 0%, 0%, 0.35); /* Primary - Navbar */ --md-primary-fg-color: hsla(0, 0%, 0%, 1); --md-primary-fg-color--light: hsla(0, 0%, 0%, 0.9); --md-primary-fg-color--dark: hsla(0, 0%, 0%, 0.8); --md-primary-bg-color: hsla(0, 0%, 100%, 1); --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7); --md-accent-fg-color: #de243d; --md-accent-fg-color--transparent: hsla(0, 0%, 0%, 0.5); --md-accent-bg-color: hsla(0, 0%, 0%, 0.9); --md-accent-bg-color--light: hsla(0, 0%, 0%, 0.8); } .md-header__title { margin-left: 0 !important; } ================================================ FILE: src/templates/demo_gallery_template.j2 ================================================ --- title: {{ config.title }} description: {{ config.meta.description }} hide: - navigation - toc - pageTitle - editButton --- ================================================ FILE: src/templates/demo_page_template.j2 ================================================ --- title: {{ demo.title }} description: "{{ demo.description }}" source_repo: "{{ demo.doc_link | replace('/README.md', '') }}" --- {{ content | safe }} --- ## Related Resources - **Source Code**: [View on GitHub]({{ demo.doc_link | replace('/README.md', '') }}) - **Category**: {{ demo.category | title }} {% if demo.description %} - **Description**: {{ demo.description }} {% endif %} [🏠 Back to Demo Gallery](../index.md){ .md-button .md-button--primary }