{"id":31767649,"url":"https://github.com/edoigtrd/ubiquite","last_synced_at":"2026-04-19T07:35:28.848Z","repository":{"id":318196171,"uuid":"1069364213","full_name":"edoigtrd/ubiquite","owner":"edoigtrd","description":"Ubiquité : Open-source Perplexity clone with multi-LLM support and KaTeX math rendering.","archived":false,"fork":false,"pushed_at":"2025-11-09T00:23:55.000Z","size":3713,"stargazers_count":36,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-11-09T01:14:10.425Z","etag":null,"topics":["ai","katex","katex-support","langchain","llm","perplexity","perplexity-ai","searxng"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/edoigtrd.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-03T20:16:05.000Z","updated_at":"2025-11-09T00:22:43.000Z","dependencies_parsed_at":"2025-10-05T19:25:01.247Z","dependency_job_id":"90098ef6-6c88-4d23-bb88-f43ac45d4e28","html_url":"https://github.com/edoigtrd/ubiquite","commit_stats":null,"previous_names":["edoigtrd/ubiquite"],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/edoigtrd/ubiquite","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/edoigtrd%2Fubiquite","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/edoigtrd%2Fubiquite/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/edoigtrd%2Fubiquite/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/edoigtrd%2Fubiquite/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/edoigtrd","download_url":"https://codeload.github.com/edoigtrd/ubiquite/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/edoigtrd%2Fubiquite/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31999169,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-18T20:23:30.271Z","status":"online","status_checked_at":"2026-04-19T02:00:07.110Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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","katex","katex-support","langchain","llm","perplexity","perplexity-ai","searxng"],"created_at":"2025-10-10T01:18:32.825Z","updated_at":"2026-04-19T07:35:28.841Z","avatar_url":"https://github.com/edoigtrd.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Ubiquité\n\n\u003e Ubiquité is an open-source Perplexity clone.\n\nThis project is inspired by other Perplexity clones such as [Perplexica](https://github.com/ItzCrazyKns/Perplexica) and [Morphic](https://github.com/miurla/morphic).\nI made this project because both Perplexica and Morphic were not exactly what I needed.\n\nCompared to those projects, Ubiquité aims to improve on the following points:\n- **Multiple LLM providers**: You can choose between multiple LLM providers.\n- **Easy model switching**: You can easily switch between models for different use cases while maintaining the ability to connect to multiple AI providers.\n- **Unified and complete configuration**: All configuration is done in a single file, with all the options available for each provider and model, this file is editable from the UI.\n- **KaTeX support**: Math rendering with KaTeX.\n- **Map Tool**: A tool that allows the LLM to generate maps based on user queries.\n\n[![Map Tool](assets/map-tool.png)](assets/map-tool.png)\n*MistralAI • magistral-medium-latest*\n\n# Features\n\n- Multiple LLM providers (OpenAI, Mistral, Groq, Nous, XAI)\n- Unified and complete configuration.\n- Streaming responses.\n- Url query search. ie: http://localhost:6003/?q=What+is+the+capital+of+France\n\n# Installation (with Docker)\n\n1. Clone the repository:\n   ```bash\n   git clone https://github.com/edoigtrd/ubiquite.git\n   cd ubiquite\n    ```\n\n2. Move the example configuration file:\n   ```bash\n   mv config.sample.toml config.toml\n   ```\n\n3. Run the application using Docker Compose:\n   ```bash\n   docker-compose -p ubiquite up -d\n   ```\n\n4. Access the application at `http://localhost:6003`. You can edit the configuration file from the UI (go to the settings).\n\n*Note: Ubiquité needs your location to work properly which don't work on \"unsafes\" origins, if you are on your own domain you can set it as trusted in chrome using chrome://flags/#unsafely-treat-insecure-origin-as-secure* \n\n# How to configure\n\nMove `config.sample.toml` to `config.toml` and fill in the required fields.\n\nIn this file you can configure:\n\n### Providers\n\nIn the provider section, you can configure the LLM provider you want to use.\n```toml\n[provider]\n[provider.openai]\ntype = \"openai\"\napi_key = \"your_api_key\"\nopenai_api_base = \"https://api.openai.com/v1\" # Optional, only if you want to use a different endpoint default is OpenAI's endpoint\n```\n\nSupported providers are:\n- anthropic\n- groq\n- mistral\n- openai (+ any openai compatible endpoint such as xai, nous ...)\n- ollama\n\n*Note: the codebase make it easy to add new providers, look into infrastructure/providers.py*\n\nIf your provider is available to an openai compatible endpoint (xai, nous ...), you can use the `openai` type and set the `openai_api_base` to your provider's endpoint.\n\nTechnically speaking every parameter in one model will be unpacked to the appropriate langchain provider class.\n\n### Models presets\n\nIn the models section you can configure model presets.\n```toml\n[models]\n[models.fast]\nprovider = \"groq\" # Point towards the provider configured in the provider section, in this case provider.groq\nmodel_name = \"moonshotai/kimi-k2-instruct-0905\"\n```\n\nStandard presets are:\n- fast: A fast and cheap model for quick responses.\n- smart: A smarter model for more complex queries.\n- balanced: A balanced model for general use.\n- related: The model used to generate related questions.\n- title: The model used to generate titles for saved conversations.\n- image_search: The model used to generate image search queries.\n\n### Prompts\n\nEach prompt is configurable\n```toml\n[prompts]\n[prompts.search]\ntemplate = \"\"\"\nYou are a helpful AI assistant with access to real-time web search, content retrieval, video search capabilities, and the ability to ask clarifying questions.\n\n[REDACTED FOR BREVITY]\n\nAdditional information:\n{additional_context}\n\"\"\"\n```\n\n\u003e search and related prompt is copied from Morphic; image_search is from Perplexica\n\nAvailable prompts are:\n- search: The main prompt used to answer user queries, note that {additional_context} placeholder will be replaced with a yaml containing user informations such as timezone, location and other preferences.\n- related: The prompt used to generate related questions.\n- image_search: The prompt used to generate image search queries.\n- title: The prompt used to generate titles for saved conversations.\n\n### SearX configuration\n\nIn the SearX section you can configure the SearX instance you want to use.\n```toml\n[searx]\nurl = \"https://your-searx-instance.com\"\n```\nYou can find a list of public SearX instances [here](https://searx.space/).\n\n### Database configuration\n\nIn the database section you can configure the database you want to use.\n```toml\n[database]\nurl = \"sqlite:///data/ubiquite.db\"\n```\nI only tested SQLite but any url supported by [SQLModel](https://sqlmodel.tiangolo.com/) should work.\n\n### Focus configuration\n\nFocus mode lets you concentrate on a specific topic by adding custom conditions to SearX search queries.\nThese conditions can use **any valid SearX syntax**, such as `site:`, `file:`, `intitle:`, or others.\n\nExample:\n\n```toml\n[focuses]\n[focuses.reddit]\ncond = [\"site:reddit.com\"]\nname = \"Reddit\"\nicon = \"logos:reddit-icon\"\ndescription = \"Reddit focus\"\nllm_description = \"\"\"\n**Reddit focus:**\nIf the user has activated the Reddit Focus, it is likely because they want to know users' opinions and get responses based on real experiences from online discussions.\n\"\"\"\n```\n* **cond** — List of conditions to append to the search query.\n\n  * Multiple conditions are joined with the **OR** operator by default.\n  * If you need a different logic, you can group them manually, e.g.:\n\n    ```toml\n    cond = [\"site:example.com AND file:pdf\"]\n    ```\n  * You can use any SearX-compatible flags like `filetype:`, `inurl:`, `intitle:`, etc.\n  * You can also leave this list **empty** if your focus only provides additional LLM context (e.g. a behavioral mode or reasoning focus).\n* **name** — Display name of the focus (UI label).\n* **icon** — Iconify icon name. [icônes collection](https://icones.netlify.app/collection/all)\n* **description** — Shown in the UI.\n* **llm_description** — Description injected into the system prompt when this focus is active.\n\n# Map Tool (Nominatim / Geocoder Configuration)\n\nThe map tool (my personal favorite feature) allows the LLM to answer geolocation-related questions by generating a GeoJSON object that is then rendered as an interactive map.  \nIt relies on any `geopy` geocoder for address lookup, and you can configure the geocoder URL in the configuration file.\n\nBy default, the map tool uses the public OpenStreetMap Nominatim instance.  \nIt is **not recommended for heavy usage**, as it enforces strict rate limits and usage policies that may lead to increased errors.  \nYou can either host your own instance or use a different geocoding provider by changing the `cls` parameter in the `[nominatim]` section of the configuration file.\n\nFor example, here is my personal GoogleV3 configuration:\n```toml\n[nominatim]\ncls = \"geopy.geocoders.GoogleV3\"\napi_key = \"\"\nratelimiter = { min_delay_seconds = 1.0 }\n```\n\n`cls` refers to the full import path of the `geopy` geocoder class you want to use.\nYou can find the list of supported classes [here](https://geopy.readthedocs.io/en/stable/#module-geopy.geocoders).\n\nI haven’t tested all geocoders, so please refer to the `geopy` documentation for details on how to configure each one.\nIf your geocoder doesn’t work properly with Ubiquité, it’s probably because its response paths are not compatible with `reverse_geocode_city` in [geo.py](./backend/infrastructure/geo.py).\nIn that case, please open an issue or a pull request.\n\n# Image search\n\nImage search is supported using the same SearX instance configured for web search.\nUnder the hood the `prompts.image_search` prompt is used to generate the search query for images based on the user query.\nThen we fetch the searx instance for image results.\nThen a reranker is used to reorder the results based on their relevance to the user query.\nThe default (and recommended) reranker is the `ClipReranker` which uses a CLIP model to rank the images.\n\nHere is the recommended configuration for reranker:\n```toml\n[images_search.reranker]\nclass = \"ClipReranker\"\n[images_search.reranker.config]\nmodel_name = \"hf-hub:apple/MobileCLIP-S1-OpenCLIP\"\ndevice = \"auto\"\n```\n\nYou can change the `model_name` to use a different CLIP model. The list of available models can be found [here](https://huggingface.co/models?library=open_clip).\n\nIf you want to write your own reranker, you can start by looking at the `ClipReranker` implementation in [clip.py](./backend/infrastructure/rerankers/clip.py).\n\nYour reranker should return a sorted list of `ImageResult` objects.\n\nImageResult definition is in [master.py](./backend/infrastructure/rerankers/__init__.py)\n\nYou'll need to register your reranker in the `ImageRerankerRegistry` to make it available for use. `master.ImageRerankerRegistry.get_default_registry().register(MyReranker)`\nAnd that's it!\nNote that the content of `images_search.reranker.config` will be passed to your reranker constructor as unpacked kwargs.\n\n\n# Architecture\n\nUbiquité is composed of two main parts:\n- The backend: A FastAPI server that handles the LLM requests, search requests and database.\n- The frontend: A React app that handles the user interface.\n\nThe database is a SQLite database managed by SQLModel.\nAll the LLM requests are handled by LangChain.\n\n# Contributing\n\nContributions are welcome!  \nIf you'd like to add features or improve the project, please fork the repo and submit a pull request.\n\n# Roadmap\n\n- [ ] Ability to fork a conversation.\n- [ ] Deep research mode.\n- [ ] Find something to do with placeholders quick actions.\n- [ ] Logging (debugging)\n- [ ] Token usage tracking, ability to generate invoices.\n- [ ] Animation when waiting for first token.\n- [ ] Frontend responsive design.\n- [ ] Discovery page\n- [ ] Better settings page (i think we can't do better actually :D)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fedoigtrd%2Fubiquite","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fedoigtrd%2Fubiquite","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fedoigtrd%2Fubiquite/lists"}