{"id":20405545,"url":"https://github.com/astrabert/supabase-ai-chat","last_synced_at":"2025-06-14T18:08:25.221Z","repository":{"id":240317416,"uuid":"802280029","full_name":"AstraBert/supabase-ai-chat","owner":"AstraBert","description":"A journalist that knows lots of news about AI!📰💻","archived":false,"fork":false,"pushed_at":"2024-05-26T08:56:49.000Z","size":16285,"stargazers_count":6,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-06T23:16:56.259Z","etag":null,"topics":["ai","assistant","gradio-python-llm","huggingface-spaces","python","rag","retrieval-augmented-generation","supabase","text-generation"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AstraBert.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-05-17T22:13:37.000Z","updated_at":"2025-05-09T18:20:23.000Z","dependencies_parsed_at":"2024-11-15T05:11:57.626Z","dependency_job_id":"45198817-2121-4bd4-ad2d-40e6c6db48a6","html_url":"https://github.com/AstraBert/supabase-ai-chat","commit_stats":null,"previous_names":["astrabert/supabase-ai-chat"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/AstraBert/supabase-ai-chat","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AstraBert%2Fsupabase-ai-chat","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AstraBert%2Fsupabase-ai-chat/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AstraBert%2Fsupabase-ai-chat/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AstraBert%2Fsupabase-ai-chat/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AstraBert","download_url":"https://codeload.github.com/AstraBert/supabase-ai-chat/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AstraBert%2Fsupabase-ai-chat/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259860405,"owners_count":22922987,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","assistant","gradio-python-llm","huggingface-spaces","python","rag","retrieval-augmented-generation","supabase","text-generation"],"created_at":"2024-11-15T05:11:53.634Z","updated_at":"2025-06-14T18:08:25.195Z","avatar_url":"https://github.com/AstraBert.png","language":"Python","readme":"---\r\ncanonical_url: \"https://coderlegion.com/291/deploy-an-ai-journalist-chatbot-with-gradio-and-supabase\"\r\n---\r\n\r\n\u003ch1 align=\"center\"\u003esupabase-ai-chat\u003c/h1\u003e\r\n\u003ch2 align=\"center\"\u003eA journalist that knows lots of news about AI!\u003c/h2\u003e\r\n\r\n\u003cdiv align=\"center\"\u003e\r\n    \u003cimg src=\"https://img.shields.io/github/languages/top/AstraBert/supabase-ai-chat\" alt=\"GitHub top language\"\u003e\r\n   \u003cimg src=\"https://img.shields.io/github/commit-activity/t/AstraBert/supabase-ai-chat\" alt=\"GitHub commit activity\"\u003e\r\n   \u003cimg src=\"https://img.shields.io/badge/Release-v0.0.0-purple\" alt=\"Static Badge\"\u003e\r\n   \u003cimg src=\"https://img.shields.io/badge/Supported_platforms-Windows/Linux/Mac-brown\" alt=\"Static Badge\"\u003e\r\n   \u003cdiv\u003e\r\n        \u003ca href=\"https://astrabert.github.io/supabase-ai-chat\"\u003e\u003cimg src=\"./data/robotjournalist.png\"\u003e\u003c/a\u003e\r\n        \u003cp\u003e\u003ci\u003eThis image was generated with \u003ca href=\"https://pollinations.ai/\"\u003ePollinations AI\u003c/a\u003e API\u003c/i\u003e\u003c/p\u003e\r\n   \u003c/div\u003e\r\n\u003c/div\u003e\r\n\r\n\u003ch3 align=\"center\"\u003e1. Introduction\u003c/h3\u003e\r\n\r\n**supabase-ai-chat** is natively developed as a Gradio-backed HF space and can be found [here](https://huggingface.co/spaces/as-cle-bert/supabase-ai-chat): it was developed to serve as a knowledgeable assistant in the field of AI news.\r\n\r\n\u003e*There is also a version built on top of Flowise but it is only a test deployment and, due to security reasons, its access is limited: you can request the access writing an email [to this address](mailto:astra.bertelli01@universitadipavia.it) in which you explain who you are and why you would want to use the application.*\r\n\r\nIt is an application that exploits Supabase ([the open-source alternative to Firebase](https://github.com/supabase/supabase)) as a vector store to search for context information and HF Spaces API to query and retrieve responses from Phi-3-128K.\r\n\r\nsupabase-ai-chat was built selecting 5000 AI-related news articles from [ai-tech-articles](https://huggingface.co/datasets/siavava/ai-tech-articles) dataset on HF Hub, with the help of Supabase as a vector store (if you don't know what vectore stores are, here is an article that I wrote about them: [\"Vector databases explained\"](https://astrabert.github.io/hophop-science/Vector-databases-explained/)). Let's break dow the steps we need to take to build this application.\r\n\r\n\u003ch3 align=\"center\"\u003e2. Pre-requisites\u003c/h3\u003e\r\n\r\n\u003ch4 align=\"center\"\u003e2a. Supabase\u003c/h4\u003e\r\n\r\nBefore we start building our application, we will need **to access Supabase**: you can head over to [their website](https://supabase.com/) and register through your GitHub account (which is definitely the simplest way to get access to their services).\r\n\r\nOnce your account has been created, you can go to *\"Dashboard\"* and select *\"New Project\"*. This will take you to the actual project you can build and it will require you to name it and save a password: **do not loose the password**, because it will be useful later on. \r\n\r\nAfter Supabase manages all the dependencies of your project, you will notice that there will be both an **API Key** and a **Project URL** that pop up as soon as you enter the page: they won't be useful to us for this project, but they can definitely be in the future.\r\n\r\nNow make sure to go to **\"Project Settings \u003e Database\"** and copy the *Connection String*: store it somewhere, for now, as it will be fundamental to build the application.\r\n\r\n\u003ch4 align=\"center\"\u003e2b. HuggingFace\u003c/h4\u003e\r\n\r\nIn order to get  an [Hugging Face](https://huggingface.co/) account:\r\n\r\n- Go to Hugging Face from the link above and click on the **Sign up** bottom. Alternatively, you can directly follow [this link](https://huggingface.co/join).\r\n- Provide e-mail address and password\r\n- Follow the instructions as you are prompted by the registration procedure\r\n\r\n\u003ch3 align=\"center\"\u003e3. Folder Setup\u003c/h3\u003e\r\n\r\nYou will need to have a specific folder setup in order to build this application. You can achieve that setup by cloning the [GitHub repository](https://github.com/AstraBert/supabase-ai-chat):\r\n\r\n```bash\r\ngit clone https://github.com/AstraBert/supabase-ai-chat.git\r\ncd supabase-ai-chat\r\n```\r\n\r\nLet's now take a look at the repository:\r\n\r\n```\r\n./\r\n├── README.md\r\n├── app.py\r\n├── .env.example\r\n├── data\r\n│   └── ainews_5k.csv.gz\r\n├── requirements.txt\r\n├── supabase_upsert.py\r\n└── utils.py\r\n```\r\nWe have:\r\n\r\n* **app.py**, which is the script we will be using to design our application\r\n* **utils.py**, which is the script where we will be storing useful classes and functions\r\n* **supabase_upsert.py**, which is the script that we will upload our AI news to our Supabase project with\r\n* **requirements.txt**, which contains the needed dependencies for this project\r\n* **data/ainews_5k.csv.gz**, which is the compressed version of the file that stores all the 5000 news articles about AI\r\n* **.env.example**, which is the example file to store environment variables\r\n\r\nWe can set our environment up by running:\r\n\r\n```bash\r\npython3 -m pip install -r requirements.txt\r\n```\r\n\r\nAnd, on the other hand, we complete the configuration by renaming the **.env.example** file to **.env** and by substituting to the placeholder string associated with *supabase_db* environment variable. An example of that would be:\r\n\r\n```bash\r\nsupabase_db=postgresql://postgres.fsaosjjgbgpbsiag:averycomplexpassword@aws-0-eu-central-1.pooler.supabase.com:5432/postgres\r\n```\r\n\r\nRemember that it is important to write **postgresql** at the beginning of the URL, and not only **postgres**, as the newest versions of *vecs*, the python package the serves as a PostgresSQL client, do not support this last variation of the baseurl. \r\n\r\n\u003ch3 align=\"center\"\u003e4. Prepare Supabase Collection\u003c/h3\u003e\r\n\r\nNow that we have everything set up in terms of environment, we can upload the documents to our Supabase project, configuring them as a collection. We will be doing it using the **supabase_upsert.py** script we downloaded earlier from GitHub.\r\n\r\nLet's take a quick look at the code!\r\n\r\nWe start by importing the needed dependencies and loading the environment variable related to our Supabase database:\r\n\r\n```python\r\nimport vecs\r\nfrom dotenv import load_dotenv\r\nimport os\r\n\r\nload_dotenv()\r\nDB_CONNECTION = os.getenv(\"supabase_db\")\r\n```\r\n\r\nThen we move on to connect to Supabase client and create a new collection called *documents*, which will be receiving vectors embedding of a size of 348:\r\n\r\n```python\r\nvx = vecs.create_client(DB_CONNECTION)\r\n\r\ndocs = vx.get_or_create_collection(name=\"documents\", dimension=384)\r\n```\r\n\r\nNow we load the word-embedding model and proceed with the upsertion of the AI news to the Supabase collection (we need to read the csv, first):\r\n\r\n```python\r\nimport pandas as pd\r\ndf = pd.read_csv(\"data/ainews_5k.csv.gz\")\r\nidex = list(df[\"id\"])\r\ntexts = list(df[\"text\"])\r\ndata = [{'id': idex[i], 'content': texts[i], 'embedding': []} for i in range(len(texts))]\r\n\r\nfrom sentence_transformers import SentenceTransformers\r\nencoder = SentenceTransformer(\"all-MiniLM-L6-v2\")\r\n\r\nfor item in data:\r\n    docs.upsert(records=[(item['id'],encoder.encode(item['content']).tolist(), {\"Content\": item['content']}),])\r\n```\r\n\r\nThe last, but not least, portion of the code creates a vector index to ease the search for our retrieval algorithm:\r\n\r\n```python\r\ndocs.create_index(measure=vecs.IndexMeasure.cosine_distance)\r\n```\r\n\r\n\u003ch3 align=\"center\"\u003e5. Define Utilities\u003c/h3\u003e\r\n\r\nAfter having upserted the AI news to Supabase, we just need to define two classes that will help us managing the queries from the users. \r\n\r\nThe first one involves the possibility of translating the user's prompt from the original language to English, and then the response from English back to the original language:\r\n\r\n```\r\nfrom langdetect import detect\r\nfrom deep_translator import GoogleTranslator\r\n\r\nclass Translation:\r\n    def __init__(self, text, destination):\r\n        self.text = text\r\n        self.destination = destination\r\n        try:\r\n            self.original = detect(self.text)\r\n        except Exception as e:\r\n            self.original = \"auto\"\r\n    def translatef(self):\r\n        translator = GoogleTranslator(source=self.original, target=self.destination)\r\n        translation = translator.translate(self.text)\r\n        return translation\r\n```\r\n\r\nAs you can see, we two python packages, **langdetect** and **deep_translator**, to achieve the goal. \r\n\r\nThe second class allows us to search a Supabase collection using a text query (which is transformed into vectors on the fly by the same encoder we used to upload everything to the collection).\r\n\r\n```python\r\nclass NeuralSearcher:\r\n    def __init__(self, collection, encoder):\r\n        self.collection = collection\r\n        self.encoder = encoder\r\n    def search(self, text):\r\n        results = self.collection.query(\r\n            data=self.encoder.encode(text).tolist(),  # required\r\n            limit=1,                     # number of records to return\r\n            filters={},                  # metadata filters\r\n            measure=\"cosine_distance\",   # distance measure to use\r\n            include_value=True,         # should distance measure values be returned?\r\n            include_metadata=True,      # should record metadata be returned?\r\n        )\r\n        return results\r\n```\r\n\r\nFor this simple example project, we do not define filters: this can be done for more advanced projects and more complex necessities.\r\n\r\n\u003ch3 align=\"center\"\u003e6. Build the Application\u003c/h3\u003e\r\n\r\nNow that we have everything set up, we can actually build our Gradio application that will be hosted in HF Spaces. \r\n\r\nWe open **app.py** and start by importing packages and defining constants:\r\n\r\n```python\r\nimport gradio as gr\r\nfrom utils import Translation, NeuralSearcher\r\nfrom gradio_client import Client\r\nimport os\r\nimport vecs\r\nfrom dotenv import load_dotenv\r\nfrom sentence_transformers import SentenceTransformer\r\n\r\nload_dotenv()\r\n\r\ncollection_name = \"documents\"\r\nencoder = SentenceTransformer(\"all-MiniLM-L6-v2\")\r\nclient = os.getenv(\"supabase_db\")\r\napi_client = Client(\"eswardivi/Phi-3-mini-128k-instruct\")\r\nlan = \"en\"\r\nvx = vecs.create_client(client)\r\ndocs = vx.get_or_create_collection(name=collection_name, dimension=384)\r\n```\r\n\r\nNow that we have defined our Supabase and Gradio API clients, we can finally build a function that takes the user query, recognizes the language, performs various translation tasks, retrieves some relevant information from Supabase collection, feeds them as context to Phi-3-128K along with the actual message from the user, and then finally gets a response. You can refer to the flowchart here, for a better visualization of the process: \r\n\r\n![Description](https://github.com/AstraBert/supabase-ai-chat/raw/main/data/supabase.drawio.png)\r\n\r\n\r\nHere is the function:\r\n\r\n```python\r\ndef reply(message, history):\r\n    global docs\r\n    global encoder\r\n    global api_client\r\n    global lan\r\n    txt = Translation(message, \"en\")\r\n    print(txt.original, lan)\r\n    if txt.original == \"en\" and lan == \"en\":\r\n        txt2txt = NeuralSearcher(docs, encoder)\r\n        results = txt2txt.search(message)\r\n        response = api_client.predict(\r\n            f\"Context: {results[0][2]['Content']}; Prompt: {message}\",\t# str  in 'Message' Textbox component\r\n            0.4,\t# float (numeric value between 0 and 1) in 'Temperature' Slider component\r\n            True,\t# bool  in 'Sampling' Checkbox component\r\n            512,\t# float (numeric value between 128 and 4096)\r\n            api_name=\"/chat\"\r\n        )\r\n        return response\r\n    elif txt.original == \"en\" and lan != \"en\":\r\n        txt2txt = NeuralSearcher(docs, encoder)\r\n        transl = Translation(message, lan)\r\n        message = transl.translatef()\r\n        results = txt2txt.search(message)\r\n        t = Translation(results[0][2]['Content'], txt.original)\r\n        res = t.translatef()\r\n        response = api_client.predict(\r\n            f\"Context: {res}; Prompt: {message}\",\r\n            0.4,\r\n            True,\r\n            512,\r\n            api_name=\"/chat\"\r\n        )\r\n        response = Translation(response, txt.original)\r\n        return response.translatef()\r\n    elif txt.original != \"en\" and lan == \"en\":\r\n        txt2txt = NeuralSearcher(docs, encoder)\r\n        results = txt2txt.search(message)\r\n        transl = Translation(results[0][2]['Content'], \"en\")\r\n        translation = transl.translatef()\r\n        response = api_client.predict(\r\n            f\"Context: {translation}; Prompt: {message}\",\r\n            0.4,\r\n            True,\r\n            512,\r\n            api_name=\"/chat\"\r\n        )\r\n        t = Translation(response, txt.original)\r\n        res = t.translatef()\r\n        return res\r\n    else:\r\n        txt2txt = NeuralSearcher(docs, encoder)\r\n        transl = Translation(message, lan.replace(\"\\\\\",\"\").replace(\"'\",\"\"))\r\n        message = transl.translatef()\r\n        results = txt2txt.search(message)\r\n        t = Translation(results[0][2]['Content'], txt.original)\r\n        res = t.translatef()\r\n        response = api_client.predict(\r\n            f\"Context: {res}; Prompt: {message}\",\t# str  in 'Message' Textbox component\r\n            0.4,\r\n            True,\r\n            512,\r\n            api_name=\"/chat\"\r\n        )\r\n        tr = Translation(response, txt.original)\r\n        ress = tr.translatef()\r\n        return ress\r\n```\r\n\r\nNow, in order to build the Chat Interface, Gradio offers solutions that hardly have competitors in terms of simplicity: as a matter of facts, we actually need one line of code to define the interface and one to launch it. \r\n\r\n```python\r\ndemo = gr.ChatInterface(fn=reply, title=\"Supabase AI Journalist\")\r\ndemo.launch(server_name=\"0.0.0.0\", share=False)\r\n```\r\n\r\nNow, if you run:\r\n\r\n```bash\r\npython3 app.py\r\n```\r\n\r\nFrom your terminal, in less than 30 seconds you will see that **http://localhost:7860** gets crowded and fills with life: it's our chatbot! We can now query it by just writing a prompt and patiently waiting for the results to come!\r\n\r\nWe can also upload our repository to Spaces, or simply create a space [here](https://huggingface.co/spaces) and paste the code we just write in files that are named as our local version of them.\r\n\r\nI strongly suggest, for safety reasons, **not to expose your .env file**: you can set secret keys in the Space settings, and just import the keys by simply including:\r\n\r\n```python\r\nclient = os.getenv(\"your-key-name-here\")\r\n```\r\n\r\n\u003ch3 align=\"center\"\u003e7. Conclusion\u003c/h3\u003e\r\n\r\nWe now created our first Gradio application: this is the first time we build a fully **front-end and back-end** defined tool, without relying on third-party interfaces such as Telegram or Discord. \r\n\r\nMoreover, we natively integrated in our project a **vector database** (Supabase) for text retrieval and a **Large Language Model** (Phi-3-128K) for text generation: we did everything with **pure python** and, what's even better, in **less than 150 lines of code**!\r\n\r\n\u003c!-- Stay tuned for the next article, in which we will conclude our bot series by talking about **Discord bots**, and do not forget to live a little star in the repository! --\u003e\r\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fastrabert%2Fsupabase-ai-chat","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fastrabert%2Fsupabase-ai-chat","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fastrabert%2Fsupabase-ai-chat/lists"}