Spaces:
Running
Running
Replace Copilot with HuggingChat provider
Browse files- Remove Microsoft Copilot (blocked by CAPTCHA)
- Add HuggingChat provider with 6 models:
* Omni (auto-router)
* Llama 3.3 70B
* Qwen 2.5 72B
* DeepSeek R1
* Llama 3.1 8B
* Mistral 7B
- Handles welcome modal automatically
- Works without authentication
- Update config, engine, and documentation
- KAIGUIDE.md +14 -7
- config.py +10 -3
- debug_screenshots/01_initial_load.png +0 -0
- debug_screenshots/02_after_hydration.png +0 -0
- debug_screenshots/03_after_typing.png +0 -0
- debug_screenshots/04_after_send.png +0 -0
- debug_screenshots/05_response.png +0 -0
- debug_screenshots/hc_initial.png +0 -0
- debug_screenshots/hc_page_source.html +95 -0
- engine.py +5 -5
- providers/{copilot_provider.py β huggingchat_provider.py} +109 -84
- test_copilot_browser.py +0 -61
- test_huggingchat_browser.py +74 -0
KAIGUIDE.md
CHANGED
|
@@ -68,13 +68,20 @@ Uses Playwright Chromium to interact with `gemini.google.com` as a real browser.
|
|
| 68 |
- **Files**: `providers/gemini_provider.py`, `test_gemini_browser.py`.
|
| 69 |
- **Status**: **Experimental**. Requires local Playwright environment.
|
| 70 |
|
| 71 |
-
### E.
|
| 72 |
-
Uses Playwright Chromium to interact with `
|
| 73 |
-
- **Why Browser**:
|
| 74 |
-
- **Input**:
|
| 75 |
-
- **Features**:
|
| 76 |
-
-
|
| 77 |
-
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 78 |
- **Status**: **Experimental**. Requires local Playwright environment.
|
| 79 |
- **Vercel**: **DISABLED** (no Chromium in serverless). Local/Docker only.
|
| 80 |
|
|
|
|
| 68 |
- **Files**: `providers/gemini_provider.py`, `test_gemini_browser.py`.
|
| 69 |
- **Status**: **Experimental**. Requires local Playwright environment.
|
| 70 |
|
| 71 |
+
### E. HuggingChat (Browser-Based Provider)
|
| 72 |
+
Uses Playwright Chromium to interact with `huggingface.co/chat` as a real browser.
|
| 73 |
+
- **Why Browser**: HuggingChat provides access to 100+ open-source models via web interface.
|
| 74 |
+
- **Input**: `textarea` with placeholder text.
|
| 75 |
+
- **Features**:
|
| 76 |
+
- Handles the welcome modal automatically (clicks "Start chatting")
|
| 77 |
+
- Supports model selection from dropdown (optional, defaults to "Omni" router)
|
| 78 |
+
- Access to top models: Llama 3.3 70B, Qwen 2.5 72B, DeepSeek R1, etc.
|
| 79 |
+
- **Models**:
|
| 80 |
+
- `omni` - Auto-routes to best model (default)
|
| 81 |
+
- `meta-llama/Llama-3.3-70B-Instruct` - Meta's latest Llama model
|
| 82 |
+
- `Qwen/Qwen2.5-72B-Instruct` - Alibaba's Qwen model
|
| 83 |
+
- `deepseek-ai/DeepSeek-R1` - DeepSeek reasoning model
|
| 84 |
+
- **Files**: `providers/huggingchat_provider.py`.
|
| 85 |
- **Status**: **Experimental**. Requires local Playwright environment.
|
| 86 |
- **Vercel**: **DISABLED** (no Chromium in serverless). Local/Docker only.
|
| 87 |
|
config.py
CHANGED
|
@@ -25,7 +25,9 @@ MODEL_RANKING = [
|
|
| 25 |
("gpt-4o-mini", "g4f", "gpt-4o-mini"),
|
| 26 |
("glm-5", "zai", "glm-5"),
|
| 27 |
("gemini-3-flash", "gemini", "gemini-3-flash"),
|
| 28 |
-
("
|
|
|
|
|
|
|
| 29 |
("gpt-oss-20b", "pollinations", "openai"),
|
| 30 |
("mistral-small-3.2", "pollinations", "mistral"),
|
| 31 |
|
|
@@ -82,8 +84,13 @@ PROVIDER_MODELS = {
|
|
| 82 |
"gemini": [
|
| 83 |
"gemini-3-flash",
|
| 84 |
],
|
| 85 |
-
"
|
| 86 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 87 |
],
|
| 88 |
"pollinations": [
|
| 89 |
"gpt-oss-20b",
|
|
|
|
| 25 |
("gpt-4o-mini", "g4f", "gpt-4o-mini"),
|
| 26 |
("glm-5", "zai", "glm-5"),
|
| 27 |
("gemini-3-flash", "gemini", "gemini-3-flash"),
|
| 28 |
+
("huggingchat-omni", "huggingchat", "omni"),
|
| 29 |
+
("llama-3.3-70b", "huggingchat", "meta-llama/Llama-3.3-70B-Instruct"),
|
| 30 |
+
("qwen2.5-72b", "huggingchat", "Qwen/Qwen2.5-72B-Instruct"),
|
| 31 |
("gpt-oss-20b", "pollinations", "openai"),
|
| 32 |
("mistral-small-3.2", "pollinations", "mistral"),
|
| 33 |
|
|
|
|
| 84 |
"gemini": [
|
| 85 |
"gemini-3-flash",
|
| 86 |
],
|
| 87 |
+
"huggingchat": [
|
| 88 |
+
"omni",
|
| 89 |
+
"meta-llama/Llama-3.3-70B-Instruct",
|
| 90 |
+
"Qwen/Qwen2.5-72B-Instruct",
|
| 91 |
+
"deepseek-ai/DeepSeek-R1",
|
| 92 |
+
"meta-llama/Llama-3.1-8B-Instruct",
|
| 93 |
+
"mistralai/Mistral-7B-Instruct-v0.3",
|
| 94 |
],
|
| 95 |
"pollinations": [
|
| 96 |
"gpt-oss-20b",
|
debug_screenshots/01_initial_load.png
ADDED
|
debug_screenshots/02_after_hydration.png
ADDED
|
debug_screenshots/03_after_typing.png
ADDED
|
debug_screenshots/04_after_send.png
ADDED
|
debug_screenshots/05_response.png
ADDED
|
debug_screenshots/hc_initial.png
ADDED
|
debug_screenshots/hc_page_source.html
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html><html lang="en"><head>
|
| 2 |
+
<meta charset="utf-8">
|
| 3 |
+
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
| 4 |
+
<meta name="theme-color" content="rgb(249, 250, 251)">
|
| 5 |
+
<script>
|
| 6 |
+
(function () {
|
| 7 |
+
try {
|
| 8 |
+
var prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
|
| 9 |
+
var stored = localStorage.getItem("theme");
|
| 10 |
+
var followSystem = stored === null || stored === "system";
|
| 11 |
+
var isDark = stored === "dark" || (followSystem && prefersDark);
|
| 12 |
+
if (isDark) {
|
| 13 |
+
document.documentElement.classList.add("dark");
|
| 14 |
+
document.querySelector('meta[name="theme-color"]').setAttribute("content", "#07090d");
|
| 15 |
+
}
|
| 16 |
+
} catch (e) {}
|
| 17 |
+
})();
|
| 18 |
+
|
| 19 |
+
// For some reason, Sveltekit doesn't let us load env variables from .env here, so we load it from hooks.server.ts
|
| 20 |
+
window.gaId = "";
|
| 21 |
+
</script>
|
| 22 |
+
|
| 23 |
+
<link href="/chat/_app/immutable/assets/0.BxyA4mCL.css" rel="stylesheet">
|
| 24 |
+
<link href="/chat/_app/immutable/assets/models.Dncc1Dh7.css" rel="stylesheet"><!--[--><meta name="description" content="Making the community's best AI chat models available to everyone"> <meta name="twitter:site" content="@huggingface"> <!--[--><meta name="twitter:card" content="summary_large_image"> <meta name="twitter:title" content="HuggingChat - Chat with AI models"> <meta name="twitter:description" content="Making the community's best AI chat models available to everyone"> <meta name="twitter:image" content="https://huggingface.cohttps://huggingface.co/chat/huggingchat/thumbnail.png"> <meta name="twitter:image:alt" content="HuggingChat preview"> <meta property="og:title" content="HuggingChat - Chat with AI models"> <meta property="og:type" content="website"> <meta property="og:url" content="https://huggingface.co/chat"> <meta property="og:image" content="https://huggingface.co/chat/huggingchat/thumbnail.png"> <meta property="og:description" content="Making the community's best AI chat models available to everyone"> <meta property="og:site_name" content="HuggingChat"> <meta property="og:locale" content="en_US"><!--]--> <link rel="icon" href="https://huggingface.co/chat/huggingchat/icon.svg" type="image/svg+xml"> <!--[--><link rel="icon" href="https://huggingface.co/chat/huggingchat/favicon.svg" type="image/svg+xml" media="(prefers-color-scheme: light)"> <link rel="icon" href="https://huggingface.co/chat/huggingchat/favicon-dark.svg" type="image/svg+xml" media="(prefers-color-scheme: dark)"><!--]--> <link rel="apple-touch-icon" href="https://huggingface.co/chat/huggingchat/apple-touch-icon.png"> <link rel="manifest" href="https://huggingface.co/chat/huggingchat/manifest.json"> <!--[--><script async="" src="https://plausible.io/js/pa-Io_oigECawqdlgpf5qvHb.js"></script><!----><!--]--> <!--[!--><!--]--><!--]--><!--[--><!--]--><title>HuggingChat</title>
|
| 25 |
+
<link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/nodes/0.VN2xao_R.js"><link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/chunks/GndUUp11.js"><link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/chunks/DzUYxSXu.js"><link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/chunks/DIeogL5L.js"><link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/chunks/BdtUgkxI.js"><link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/chunks/CbcL9FWQ.js"><link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/chunks/CX1QUvAJ.js"><link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/chunks/CqkleIqs.js"><link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/chunks/xysgetnd.js"><link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/chunks/D0-cVBWo.js"><link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/chunks/CWj6FrbW.js"><link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/chunks/CWu0D6G8.js"><link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/chunks/BH7apXi0.js"><link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/chunks/Bpq93ek1.js"><link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/chunks/69_IOA4Y.js"><link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/chunks/BU5FWNU6.js"><link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/chunks/jQCsKN1q.js"><link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/chunks/BUaLhwi4.js"><link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/chunks/C63Vvf_s.js"><link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/chunks/CnIGUk-s.js"><link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/chunks/DZW4JsdA.js"><link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/chunks/DgiNCJ3I.js"><link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/chunks/7SkvYd_D.js"><link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/chunks/Cenn58bB.js"><link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/chunks/B62QhTgY.js"><link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/chunks/CPwLOqZt.js"><link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/chunks/CTQezUnf.js"><link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/chunks/C9EUFfAi.js"><link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/chunks/BCVoH2qL.js"><link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/nodes/1.CWz-xcMS.js"><link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/chunks/KlzHiDQJ.js"><link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/nodes/4.C1iPylfh.js"><link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/chunks/BCpzjSyf.js"><link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/chunks/BuybuBbN.js"><link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/chunks/DMtCQNue.js"><link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/chunks/Vz2epAnn.js"><link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/chunks/BtUAYA0X.js"><link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/chunks/BMNPVVsa.js"><link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/chunks/DhUvgpHA.js"><link rel="modulepreload" as="script" crossorigin="" href="/chat/_app/immutable/chunks/DuDrw0Kc.js"></head>
|
| 26 |
+
<body data-sveltekit-preload-data="hover" class="h-dvh dark:bg-gray-900">
|
| 27 |
+
<div id="app" class="contents h-full" inert="true"><!--[--><!--[--><!----><!--[--><!--]--> <!----> <div class="fixed grid h-dvh w-screen grid-cols-1 grid-rows-[auto,1fr] overflow-hidden text-smd md:grid-cols-[290px,1fr] transition-[300ms] [transition-property:grid-template-columns] dark:text-gray-300 md:grid-rows-[1fr]"><button title="Collapse sidebar" class="absolute inset-y-0 z-10 my-auto left-[290px] *:transition-transform group flex h-16 w-6 flex-col items-center justify-center -space-y-1 outline-none *:h-3 *:w-1 *:rounded-full *:hover:bg-gray-400 dark:*:hover:bg-gray-400 max-md:hidden *:bg-gray-300/70 dark:*:bg-gray-600" name="sidebar-toggle" aria-label="Toggle sidebar navigation"><div class="group-hover:rotate-[20deg]"></div> <div class="group-hover:-rotate-[20deg]"></div></button><!----> <!--[!--><!--]--> <nav class="flex h-12 items-center justify-between rounded-b-xl border-b bg-gray-50 px-3 dark:border-gray-800 dark:bg-gray-800/30 dark:shadow-xl md:hidden"><button type="button" class="-ml-3 flex size-12 shrink-0 items-center justify-center text-lg" aria-label="Open menu"><svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="none" viewBox="0 0 16 16"><path d="M8.795 10.418a.84.84 0 1 1 0 1.681H1.907a.84.84 0 0 1 0-1.681h6.888ZM14.093 3.9a.841.841 0 0 1 0 1.682H1.907a.84.84 0 0 1 0-1.682h12.186Z" fill="currentColor"></path></svg><!----></button> <div class="flex h-full items-center justify-center overflow-hidden"><!--[!--><!--]--></div> <div class="flex items-center"><!--[--><button type="button" class="flex size-8 shrink-0 items-center justify-center text-lg" disabled="" aria-label="Share conversation"><svg xmlns="http://www.w3.org/2000/svg" class="opacity-40" width="1em" height="1em" fill="none" viewBox="0 0 12 12"><path d="M10.4646 6.85139C10.7605 6.85139 11 7.09093 11 7.38679V7.78965C11 8.35479 11.0013 8.82459 10.9581 9.20053C10.9136 9.58762 10.8165 9.94247 10.5745 10.2495C10.478 10.3719 10.3672 10.4826 10.2448 10.5791C9.93774 10.8212 9.58211 10.9183 9.19497 10.9628C8.81915 11.006 8.34979 11.0055 7.78496 11.0055H4.21503C3.6502 11.0055 3.18083 11.006 2.80502 10.9628C2.41788 10.9183 2.06224 10.8212 1.75515 10.5791C1.63274 10.4826 1.52198 10.3718 1.42554 10.2495C1.18354 9.94248 1.08635 9.58761 1.04186 9.20053C0.998661 8.82458 1 8.35479 1 7.78965V7.38679C1.00003 7.09093 1.23954 6.85139 1.53541 6.85139C1.83128 6.85139 2.07078 7.09093 2.07081 7.38679V7.78965C2.07081 8.38023 2.07202 8.77788 2.10656 9.07845C2.13978 9.36728 2.19822 9.49857 2.26701 9.58595C2.31143 9.64228 2.3625 9.69333 2.41873 9.73767C2.50614 9.80657 2.63774 9.86487 2.9271 9.89812C3.2276 9.93264 3.62467 9.93387 4.21503 9.93387H7.78496C8.37532 9.93387 8.77238 9.93264 9.07289 9.89812C9.36227 9.86487 9.49384 9.80658 9.58126 9.73767C9.63752 9.69329 9.68862 9.64222 9.73298 9.58595C9.80176 9.49856 9.86021 9.3673 9.89343 9.07845C9.92796 8.77788 9.92918 8.38023 9.92918 7.78965V7.38679C9.92921 7.09093 10.1687 6.85139 10.4646 6.85139ZM6.01046 1.00034C6.15239 1.0004 6.2885 1.05697 6.3889 1.15729L9.36849 4.13601C9.57767 4.34519 9.57759 4.68454 9.36849 4.89377C9.15925 5.10283 8.8199 5.10294 8.61073 4.89377L6.54586 2.8289V8.02945C6.54586 8.32526 6.30624 8.56559 6.01046 8.56572C5.71472 8.56555 5.47418 8.32523 5.47418 8.02945V2.8289L3.40931 4.89377C3.20011 5.10268 2.86157 5.10279 2.65243 4.89377C2.44341 4.68459 2.44341 4.34519 2.65243 4.13601L5.63114 1.15729C5.73154 1.0569 5.86848 1.00042 6.01046 1.00034Z" fill="currentColor"></path></svg><!----></button><!--]--> <a href="/chat/" class="flex size-8 shrink-0 items-center justify-center text-lg"><svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="none" viewBox="0 0 16 16"><path d="M7.258 1.856c.333 0 .66.024.979.07-.558.319-.972.86-1.123 1.503A5.254 5.254 0 1 0 9.32 13.513l.275-.127c.334-.17.712-.229 1.08-.17l.158.031.01.003 1.343.36-.359-1.345a1.77 1.77 0 0 1 .137-1.247 5.23 5.23 0 0 0 .538-2.041 2.356 2.356 0 0 0 1.544-1 6.808 6.808 0 0 1-.676 3.742v.001c-.034.066-.031.116-.025.14l.36 1.345a1.572 1.572 0 0 1-1.823 1.945l-.1-.024-1.334-.357a.2.2 0 0 0-.14.018l-.012.005A6.825 6.825 0 1 1 7.259 1.856Zm4.837-1.36c.434 0 .785.352.785.786v1.905h1.9a.785.785 0 0 1 0 1.57h-1.9v1.9a.786.786 0 1 1-1.57 0v-1.9H9.404a.785.785 0 0 1 0-1.57h1.906V1.282c0-.434.352-.787.785-.787Z" fill="currentColor"></path></svg><!----></a></div></nav> <!--[!--><!--]--> <nav style="transform: translateX(-100%); width: 85%; will-change: transform;" class="fixed bottom-0 left-0 top-0 z-30 grid max-h-dvh grid-cols-1
|
| 28 |
+
grid-rows-[auto,1fr,auto,auto] rounded-r-xl bg-white pt-4 dark:bg-gray-900 md:hidden"><div class="sticky top-0 flex flex-none touch-none items-center justify-between px-1.5 py-3.5 max-sm:pt-0"><a class="flex select-none items-center rounded-xl text-lg font-semibold" href="https://huggingface.co/chat/"><img width="32" height="32" class="dark:invert mr-[2px]" alt="HuggingChat logo" src="https://huggingface.co/chat/huggingchat/logo.svg"><!----> HuggingChat</a> <a href="/chat/" class="flex rounded-lg border bg-white px-2 py-0.5 text-center shadow-sm hover:shadow-none dark:border-gray-600 dark:bg-gray-700 sm:text-smd" title="Ctrl/Cmd + Shift + O">New Chat</a></div> <div class="scrollbar-custom flex touch-pan-y flex-col gap-1 overflow-y-auto rounded-r-xl border border-l-0 border-gray-100 from-gray-50 px-3 pb-3 pt-2 text-[.9rem] dark:border-transparent dark:from-gray-800/30 max-sm:bg-gradient-to-t md:bg-gradient-to-l"><div class="flex flex-col gap-0.5"><!--[--><!--[!--><!--]--><!--[!--><!--]--><!--[!--><!--]--><!--[!--><!--]--><!--]--></div> <!--[--><div class="h-2"></div><!--]--></div> <div class="flex touch-none flex-col gap-1 rounded-r-xl border border-l-0 border-gray-100 p-3 text-sm dark:border-transparent md:mt-3 md:bg-gradient-to-l md:from-gray-50 md:dark:from-gray-800/30"><!--[!--><!--]--> <a href="/chat/models" class="flex h-9 flex-none items-center gap-1.5 rounded-lg pl-2.5 pr-2 text-gray-500 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-700">Models <span class="ml-auto rounded-md bg-gray-500/5 px-1.5 py-0.5 text-xs text-gray-400 dark:bg-gray-500/20 dark:text-gray-400">126</span></a> <!--[!--><!--]--> <span class="flex gap-1"><a href="/chat/settings/application" class="flex h-9 flex-none flex-grow items-center gap-1.5 rounded-lg pl-2.5 pr-2 text-gray-500 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-700">Settings</a> <button aria-label="Toggle theme" class="flex size-9 min-w-[1.5em] flex-none items-center justify-center rounded-lg p-2 text-gray-500 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-700"><!--[!--><!----><svg width="50" height="50" viewBox="0 0 50 50" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M25.054 43.02C20.02 43.02 15.762 41.278 12.28 37.794C8.79695 34.31 7.05496 30.052 7.05396 25.02C7.05396 20.42 8.55396 16.428 11.554 13.044C14.554 9.66 18.387 7.685 23.054 7.12C23.487 7.053 23.87 7.112 24.204 7.296C24.537 7.48 24.804 7.721 25.004 8.02C25.204 8.318 25.312 8.668 25.33 9.07C25.347 9.471 25.222 9.854 24.954 10.22C24.3955 11.0688 23.9655 11.9955 23.678 12.97C23.3906 13.961 23.2477 14.9882 23.254 16.02C23.254 19.02 24.304 21.57 26.404 23.67C28.504 25.77 31.054 26.82 34.054 26.82C35.087 26.82 36.112 26.67 37.13 26.37C38.096 26.0936 39.0145 25.6721 39.854 25.12C40.22 24.886 40.596 24.778 40.98 24.796C41.364 24.813 41.705 24.904 42.004 25.07C42.337 25.236 42.596 25.486 42.78 25.82C42.964 26.153 43.022 26.553 42.954 27.02C42.487 31.62 40.529 35.436 37.08 38.47C33.63 41.503 29.622 43.02 25.054 43.02Z" fill="#D2D5DB"></path></svg><!--]--></button></span></div> <!--[!--><!--]--><!----></nav><!----> <nav class="grid max-h-dvh grid-cols-1 grid-rows-[auto,1fr,auto] overflow-hidden *:w-[290px] max-md:hidden"><div class="sticky top-0 flex flex-none touch-none items-center justify-between px-1.5 py-3.5 max-sm:pt-0"><a class="flex select-none items-center rounded-xl text-lg font-semibold" href="https://huggingface.co/chat/"><img width="32" height="32" class="dark:invert mr-[2px]" alt="HuggingChat logo" src="https://huggingface.co/chat/huggingchat/logo.svg"><!----> HuggingChat</a> <a href="/chat/" class="flex rounded-lg border bg-white px-2 py-0.5 text-center shadow-sm hover:shadow-none dark:border-gray-600 dark:bg-gray-700 sm:text-smd" title="Ctrl/Cmd + Shift + O">New Chat</a></div> <div class="scrollbar-custom flex touch-pan-y flex-col gap-1 overflow-y-auto rounded-r-xl border border-l-0 border-gray-100 from-gray-50 px-3 pb-3 pt-2 text-[.9rem] dark:border-transparent dark:from-gray-800/30 max-sm:bg-gradient-to-t md:bg-gradient-to-l"><div class="flex flex-col gap-0.5"><!--[--><!--[!--><!--]--><!--[!--><!--]--><!--[!--><!--]--><!--[!--><!--]--><!--]--></div> <!--[--><!--]--></div> <div class="flex touch-none flex-col gap-1 rounded-r-xl border border-l-0 border-gray-100 p-3 text-sm dark:border-transparent md:mt-3 md:bg-gradient-to-l md:from-gray-50 md:dark:from-gray-800/30"><!--[!--><!--]--> <a href="/chat/models" class="flex h-9 flex-none items-center gap-1.5 rounded-lg pl-2.5 pr-2 text-gray-500 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-700">Models <span class="ml-auto rounded-md bg-gray-500/5 px-1.5 py-0.5 text-xs text-gray-400 dark:bg-gray-500/20 dark:text-gray-400">126</span></a> <!--[!--><!--]--> <span class="flex gap-1"><a href="/chat/settings/application" class="flex h-9 flex-none flex-grow items-center gap-1.5 rounded-lg pl-2.5 pr-2 text-gray-500 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-700">Settings</a> <button aria-label="Toggle theme" class="flex size-9 min-w-[1.5em] flex-none items-center justify-center rounded-lg p-2 text-gray-500 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-700"><!--[!--><!----><svg width="50" height="50" viewBox="0 0 50 50" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M25.054 43.02C20.02 43.02 15.762 41.278 12.28 37.794C8.79695 34.31 7.05496 30.052 7.05396 25.02C7.05396 20.42 8.55396 16.428 11.554 13.044C14.554 9.66 18.387 7.685 23.054 7.12C23.487 7.053 23.87 7.112 24.204 7.296C24.537 7.48 24.804 7.721 25.004 8.02C25.204 8.318 25.312 8.668 25.33 9.07C25.347 9.471 25.222 9.854 24.954 10.22C24.3955 11.0688 23.9655 11.9955 23.678 12.97C23.3906 13.961 23.2477 14.9882 23.254 16.02C23.254 19.02 24.304 21.57 26.404 23.67C28.504 25.77 31.054 26.82 34.054 26.82C35.087 26.82 36.112 26.67 37.13 26.37C38.096 26.0936 39.0145 25.6721 39.854 25.12C40.22 24.886 40.596 24.778 40.98 24.796C41.364 24.813 41.705 24.904 42.004 25.07C42.337 25.236 42.596 25.486 42.78 25.82C42.964 26.153 43.022 26.553 42.954 27.02C42.487 31.62 40.529 35.436 37.08 38.47C33.63 41.503 29.622 43.02 25.054 43.02Z" fill="#D2D5DB"></path></svg><!--]--></button></span></div> <!--[!--><!--]--><!----></nav> <!--[!--><!--]--> <!--[!--><!----><!--[--><div class="relative z-[-1] min-h-0 min-w-0 svelte-1pgzd69"><!--[!--><!--]--> <div class="scrollbar-custom h-full overflow-y-auto svelte-1pgzd69"><div class="mx-auto flex h-full max-w-3xl flex-col gap-6 px-5 pt-6 sm:gap-8 xl:max-w-4xl xl:pt-10 svelte-1pgzd69"><!--[!--><!--]--> <!--[!--><div class="my-auto grid items-center justify-center gap-8 text-center"><div class="flex -translate-y-16 select-none items-center rounded-xl text-3xl font-semibold md:-translate-y-12 md:text-5xl"><img width="32" height="32" class="size-12 md:size-20 dark:invert mr-0.5" alt="HuggingChat logo" src="https://huggingface.co/chat/huggingchat/logo.svg"><!----> HuggingChat</div></div><!--]--><div aria-hidden="true" data-scroll-sentinel="" style="height: 1px; width: 100%;"></div></div> <!--[!--><!--]--><!----> <!--[!--><!--]--><!----></div> <div class="pointer-events-none absolute inset-x-0 bottom-0 z-0 mx-auto flex w-full max-w-3xl flex-col items-center justify-center bg-gradient-to-t from-white via-white/100 to-white/0 px-3.5 pt-2 dark:border-gray-800 dark:from-gray-900 dark:via-gray-900/100 dark:to-gray-900/0 max-sm:py-0 sm:px-5 md:pb-4 xl:max-w-4xl [&>*]:pointer-events-auto svelte-1pgzd69"><!--[!--><div class="no-scrollbar mb-3 flex w-full select-none justify-start gap-2 overflow-x-auto whitespace-nowrap text-gray-400 dark:text-gray-500 svelte-1pgzd69"><button class="flex items-center rounded-lg bg-gray-100/90 px-2 py-0.5 text-center text-sm backdrop-blur hover:text-gray-500 dark:bg-gray-700/50 dark:hover:text-gray-400 svelte-1pgzd69">Latest world news</button><button class="flex items-center rounded-lg bg-gray-100/90 px-2 py-0.5 text-center text-sm backdrop-blur hover:text-gray-500 dark:bg-gray-700/50 dark:hover:text-gray-400 svelte-1pgzd69">Trending models</button><button class="flex items-center rounded-lg bg-gray-100/90 px-2 py-0.5 text-center text-sm backdrop-blur hover:text-gray-500 dark:bg-gray-700/50 dark:hover:text-gray-400 svelte-1pgzd69">Plan a trip</button><button class="flex items-center rounded-lg bg-gray-100/90 px-2 py-0.5 text-center text-sm backdrop-blur hover:text-gray-500 dark:bg-gray-700/50 dark:hover:text-gray-400 svelte-1pgzd69">Compare technologies</button><button class="flex items-center rounded-lg bg-gray-100/90 px-2 py-0.5 text-center text-sm backdrop-blur hover:text-gray-500 dark:bg-gray-700/50 dark:hover:text-gray-400 svelte-1pgzd69">Find a dataset</button><button class="flex items-center rounded-lg bg-gray-100/90 px-2 py-0.5 text-center text-sm backdrop-blur hover:text-gray-500 dark:bg-gray-700/50 dark:hover:text-gray-400 svelte-1pgzd69">Gift ideas</button><button class="flex items-center rounded-lg bg-gray-100/90 px-2 py-0.5 text-center text-sm backdrop-blur hover:text-gray-500 dark:bg-gray-700/50 dark:hover:text-gray-400 svelte-1pgzd69">Learn something new</button></div><!--]--> <!--[!--><!--]--> <!--[!--><!--]--> <div class="w-full svelte-1pgzd69"><div class="flex w-full *:mb-3 svelte-1pgzd69"><!--[!--><!--]--></div> <form tabindex="-1" aria-label="file dropzone" class="relative flex w-full max-w-4xl flex-1 items-center rounded-xl border bg-gray-100 dark:border-gray-700 dark:bg-gray-800 svelte-1pgzd69"><!--[!--><div class="flex w-full flex-1 rounded-xl border-none bg-transparent svelte-1pgzd69"><!--[!--><div class="flex min-h-full flex-1 flex-col"><textarea rows="1" tabindex="0" inputmode="text" class="scrollbar-custom max-h-[4lh] w-full resize-none overflow-y-auto overflow-x-hidden border-0 bg-transparent px-2.5 py-2.5 outline-none focus:ring-0 focus-visible:ring-0 sm:px-3 md:max-h-[8lh]" placeholder="Ask anything" style="height: 44px;"></textarea> <!--[--><div class="scrollbar-custom -ml-0.5 flex max-w-[calc(100%-40px)] flex-wrap items-center justify-start gap-2.5 px-3 pb-2.5 pt-1.5 text-gray-500 dark:text-gray-400 max-md:flex-nowrap max-md:overflow-x-auto sm:gap-2"><!--[--><div class="flex items-center"><input class="absolute hidden size-0" aria-label="Upload file" type="file" multiple="" accept="text/*,application/json,application/xml,application/csv,image/*" style=""> <!----><!----><!--#s1--><!--[!--><button class="btn size-8 rounded-full border bg-white text-black shadow transition-none enabled:hover:bg-white enabled:hover:shadow-inner dark:border-transparent dark:bg-gray-600/50 dark:text-white dark:hover:enabled:bg-gray-600 sm:size-7" aria-label="Add attachment" id="bits-s1" aria-haspopup="menu" aria-expanded="false" data-state="closed" data-dropdown-menu-trigger="" type="button"><svg viewBox="0 0 24 24" width="1.2em" height="1.2em" class="text-base sm:text-sm"><!----><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 12h14m-7-7v14"></path><!----></svg><!----></button><!--]--><!----><!----> <!----><!--[!--><!--]--><!----><!----><!----><!----> <!--[!--><div class="ml-1.5 inline-flex h-8 items-center gap-1.5 rounded-full border border-blue-500/10 bg-blue-600/10 pl-2 pr-1 text-xs font-semibold text-blue-700 dark:bg-blue-600/20 dark:text-blue-400 sm:h-7" title="MCP servers enabled"><button type="button" title="Manage MCP Servers" class="inline-flex cursor-pointer select-none items-center gap-1 bg-transparent p-0 leading-none text-current focus:outline-none"><span class="flex items-center -space-x-1"><img alt="" class="size-4 rounded bg-white p-px shadow-sm ring-1 ring-black/5 dark:bg-gray-900 dark:ring-white/10" src="https://www.google.com/s2/favicons?sz=64&domain_url=https%3A%2F%2Fexa.ai"><img alt="" class="size-4 rounded bg-white p-px shadow-sm ring-1 ring-black/5 dark:bg-gray-900 dark:ring-white/10" src="https://www.google.com/s2/favicons?sz=64&domain_url=https%3A%2F%2Fhf.co"><!----> <!----></span><!----> MCP (2)</button> <button class="grid size-5 place-items-center rounded-full bg-blue-600/15 text-blue-700 transition-colors hover:bg-blue-600/25 dark:bg-blue-600/25 dark:text-blue-300 dark:hover:bg-blue-600/35" aria-label="Disable all MCP servers" type="button"><svg viewBox="0 0 32 32" width="1.2em" height="1.2em" class="size-3.5"><path fill="currentColor" d="M17.414 16L24 9.414L22.586 8L16 14.586L9.414 8L8 9.414L14.586 16L8 22.586L9.414 24L16 17.414L22.586 24L24 22.586z"></path><!----></svg><!----></button></div><!--]--></div><!--]--></div><!--]--> <!----> <!--[!--><!--]--><!----> <!--[!--><!--]--></div><!--]--> <!--[!--><!--[--><button type="button" class="btn absolute bottom-2 right-10 mr-1.5 size-8 self-end rounded-full border bg-white/50 text-gray-500 transition-none hover:bg-gray-50 hover:text-gray-700 dark:border-transparent dark:bg-gray-600/50 dark:text-gray-300 dark:hover:bg-gray-500 dark:hover:text-white sm:right-9 sm:size-7 svelte-1pgzd69" aria-label="Start voice recording"><svg viewBox="0 0 24 24" width="1.2em" height="1.2em" class="size-4"><!----><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path d="M12 19v3m7-12v2a7 7 0 0 1-14 0v-2"></path><rect width="6" height="13" x="9" y="2" rx="3"></rect></g><!----></svg><!----></button><!--]--> <button class="btn absolute bottom-2 right-2 size-8 self-end rounded-full border bg-white text-black shadow transition-none enabled:hover:bg-white enabled:hover:shadow-inner dark:border-transparent dark:bg-gray-600 dark:text-white dark:hover:enabled:bg-black sm:size-7 svelte-1pgzd69" disabled="" type="submit" aria-label="Send message" name="submit"><svg viewBox="0 0 24 24" width="1.2em" height="1.2em"><!----><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m5 12l7-7l7 7m-7 7V5"></path><!----></svg><!----></button><!--]--></div><!--]--></form> <div class="mt-1.5 flex h-5 items-center self-stretch whitespace-nowrap px-0.5 text-xs text-gray-400/90 max-md:mb-2 max-sm:gap-2 svelte-1pgzd69"><!--[--><!--[1--><a href="/chat/settings/omni" class="inline-flex items-center gap-1 hover:underline svelte-1pgzd69"><!--[--><svg class=" hidden dark:inline" width="1em" height="1em" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M5.97736 12.1813C6.25011 12.516 6.57428 12.8946 6.98029 13.2741C5.89251 13.8066 4.44063 14.1305 2.34747 14.1306V12.7272C4.02144 12.7272 5.15855 12.5026 5.97736 12.1813ZM10.0789 6.00458C10.3483 6.3067 10.6247 6.56949 10.9725 6.79364C11.5911 7.19216 12.4914 7.49774 14.0526 7.49774V8.90204C12.4915 8.90204 11.5911 9.20765 10.9725 9.60614C10.6249 9.83013 10.3481 10.0924 10.0789 10.3942C9.78258 10.1597 9.52333 9.87047 9.21271 9.48798C9.18183 9.44996 9.14961 9.40984 9.11603 9.36786C9.42491 9.03403 9.77986 8.70638 10.2127 8.42743C10.3378 8.34683 10.4686 8.27118 10.6053 8.19989C10.4686 8.12858 10.3378 8.05297 10.2127 7.97235C9.77958 7.69322 9.42506 7.365 9.11603 7.03094C9.1494 6.98922 9.18201 6.9496 9.21271 6.9118C9.52349 6.52912 9.78237 6.2392 10.0789 6.00458ZM2.34747 2.26923C4.44032 2.26927 5.89256 2.59232 6.98029 3.12469C6.57429 3.50414 6.25012 3.8828 5.97736 4.21747C5.15858 3.89631 4.02115 3.67356 2.34747 3.67352V2.26923Z" fill="url(#paint0_linear_3699_582)"></path><path d="M14.052 3.67331C12.0512 3.67337 10.8161 3.98917 9.97647 4.41441C9.14382 4.83623 8.63688 5.39533 8.12318 6.02791C7.62178 6.64535 7.06413 7.40735 6.18741 7.97235C6.06225 8.053 5.93137 8.12889 5.79462 8.20022C5.93144 8.27158 6.06219 8.34739 6.18741 8.42808C7.06422 8.99314 7.62174 9.75505 8.12318 10.3725C8.6369 11.0051 9.14374 11.5642 9.97647 11.986C10.8161 12.4113 12.0512 12.7271 14.052 12.7271V14.1312C11.9098 14.1311 10.4387 13.7932 9.34279 13.2382C8.24007 12.6797 7.58149 11.9313 7.03377 11.2569C6.47365 10.5671 6.07238 10.0218 5.42786 9.60647C4.80925 9.20786 3.90875 8.90226 2.34735 8.90226V7.49818C3.90859 7.49818 4.80926 7.19251 5.42786 6.79397C6.07232 6.37865 6.47373 5.83323 7.03377 5.14358C7.58147 4.46911 8.24014 3.72078 9.34279 3.16224C10.4387 2.60722 11.9098 2.26929 14.052 2.26923V3.67331Z" fill="url(#paint1_linear_3699_582)"></path><defs><linearGradient id="paint0_linear_3699_582" x1="10.2846" y1="8.06294" x2="-0.714687" y2="8.06294" gradientUnits="userSpaceOnUse"><stop stop-color="white"></stop><stop offset="1" stop-color="white" stop-opacity="0"></stop></linearGradient><linearGradient id="paint1_linear_3699_582" x1="1.34749" y1="8.06326" x2="14.273" y2="8.06326" gradientUnits="userSpaceOnUse"><stop stop-color="white" stop-opacity="0"></stop><stop offset="1" stop-color="white"></stop></linearGradient></defs></svg><svg class=" inline dark:hidden" width="1em" height="1em" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M5.97723 12.3813C6.24999 12.716 6.57417 13.0946 6.98016 13.4741C5.89247 14.0066 4.44119 14.3305 2.34833 14.3306V12.9272C4.02198 12.9272 5.1585 12.7025 5.97723 12.3813ZM10.0788 6.20459C10.3481 6.50673 10.6245 6.76948 10.9724 6.99365C11.5909 7.39219 12.4912 7.69774 14.0524 7.69775V9.10205C12.4913 9.10207 11.5909 9.40765 10.9724 9.80615C10.6248 10.0302 10.348 10.2924 10.0788 10.5942C9.78249 10.3597 9.52319 10.0704 9.21259 9.68799C9.18171 9.64997 9.14949 9.60986 9.11591 9.56787C9.42481 9.23402 9.77972 8.9064 10.2126 8.62744C10.3377 8.54682 10.4685 8.47121 10.6052 8.3999C10.4685 8.32859 10.3377 8.25299 10.2126 8.17236C9.77943 7.89322 9.42495 7.56504 9.11591 7.23096C9.1493 7.18921 9.18187 7.14963 9.21259 7.11182C9.52337 6.72913 9.78226 6.43921 10.0788 6.20459ZM2.34833 2.46924C4.44088 2.46933 5.89252 2.7924 6.98016 3.32471C6.57418 3.70415 6.25 4.08282 5.97723 4.41748C5.15853 4.09637 4.0217 3.87361 2.34833 3.87354V2.46924Z" fill="url(#paint0_linear_3699_575)"></path><path d="M14.052 3.87332C12.0512 3.87338 10.8161 4.18918 9.97647 4.61442C9.14382 5.03624 8.63688 5.59534 8.12318 6.22792C7.62178 6.84536 7.06413 7.60736 6.18741 8.17236C6.06225 8.25301 5.93137 8.3289 5.79462 8.40023C5.93144 8.47159 6.06219 8.5474 6.18741 8.62809C7.06422 9.19316 7.62174 9.95506 8.12318 10.5725C8.6369 11.2051 9.14374 11.7642 9.97647 12.186C10.8161 12.6113 12.0512 12.9271 14.052 12.9271V14.3312C11.9098 14.3312 10.4387 13.9932 9.34279 13.4382C8.24007 12.8797 7.58149 12.1313 7.03377 11.4569C6.47365 10.7671 6.07238 10.2218 5.42786 9.80648C4.80925 9.40788 3.90875 9.10227 2.34735 9.10227V7.69819C3.90859 7.69819 4.80926 7.39252 5.42786 6.99398C6.07232 6.57866 6.47373 6.03324 7.03377 5.34359C7.58147 4.66913 8.24014 3.92079 9.34279 3.36225C10.4387 2.80724 11.9098 2.4693 14.052 2.46924V3.87332Z" fill="url(#paint1_linear_3699_575)"></path><defs><linearGradient id="paint0_linear_3699_575" x1="10.2848" y1="8.26295" x2="-0.713577" y2="8.26295" gradientUnits="userSpaceOnUse"><stop></stop><stop offset="1" stop-opacity="0"></stop></linearGradient><linearGradient id="paint1_linear_3699_575" x1="1.34749" y1="8.26327" x2="14.273" y2="8.26327" gradientUnits="userSpaceOnUse"><stop stop-opacity="0"></stop><stop offset="1"></stop></linearGradient></defs></svg><!----> Omni<!--]--> <svg viewBox="0 0 32 32" width="1.2em" height="1.2em" class="-ml-0.5 text-xxs"><!----><path fill="currentColor" d="m24 12l-8 10l-8-10z"></path><!----></svg><!----></a><!--]--><!--]--> <!--[--><span class="max-sm:hidden svelte-1pgzd69">Generated content may be inaccurate or false.</span><!--]--></div></div></div></div><!--]--><!----><!--]--><!----> <!--[--><script>
|
| 29 |
+
(window.plausible =
|
| 30 |
+
window.plausible ||
|
| 31 |
+
function () {
|
| 32 |
+
(plausible.q = plausible.q || []).push(arguments);
|
| 33 |
+
}),
|
| 34 |
+
(plausible.init =
|
| 35 |
+
plausible.init ||
|
| 36 |
+
function (i) {
|
| 37 |
+
plausible.o = i || {};
|
| 38 |
+
});
|
| 39 |
+
plausible.init();
|
| 40 |
+
</script><!----><!--]--></div><!----><!--]--> <!--[!--><div id="svelte-announcer" aria-live="assertive" aria-atomic="true" style="position: absolute; left: 0; top: 0; clip: rect(0 0 0 0); clip-path: inset(50%); overflow: hidden; white-space: nowrap; width: 1px; height: 1px"><!----></div><!--]--><!--]-->
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
<script>
|
| 48 |
+
{
|
| 49 |
+
__sveltekit_15tyi6u = {
|
| 50 |
+
base: "/chat",
|
| 51 |
+
assets: "/chat",
|
| 52 |
+
env: {"PUBLIC_LLM_ROUTER_DISPLAY_NAME":"Omni","PUBLIC_VERSION":"0.20.0","PUBLIC_LLM_ROUTER_LOGO_URL":"https://cdn-uploads.huggingface.co/production/uploads/5f17f0a0925b9863e28ad517/C5V0v1xZXv6M7FXsdJH9b.png","PUBLIC_LLM_ROUTER_ALIAS_ID":"omni","PUBLIC_APP_ASSETS":"huggingchat","PUBLIC_PLAUSIBLE_SCRIPT_URL":"https://plausible.io/js/pa-Io_oigECawqdlgpf5qvHb.js","PUBLIC_ORIGIN":"https://huggingface.co","PUBLIC_COMMIT_SHA":"72227a6","PUBLIC_APP_NAME":"HuggingChat","PUBLIC_APP_DESCRIPTION":"Making the community's best AI chat models available to everyone","PUBLIC_SHARE_PREFIX":"","PUBLIC_GOOGLE_ANALYTICS_ID":"","PUBLIC_APPLE_APP_ID":""}
|
| 53 |
+
};
|
| 54 |
+
|
| 55 |
+
const element = document.currentScript.parentElement;
|
| 56 |
+
|
| 57 |
+
Promise.all([
|
| 58 |
+
import("/chat/_app/immutable/entry/start.DScfOO8g.js"),
|
| 59 |
+
import("/chat/_app/immutable/entry/app.Cap7ung_.js")
|
| 60 |
+
]).then(([kit, app]) => {
|
| 61 |
+
kit.start(app, element, {
|
| 62 |
+
node_ids: [0, 4],
|
| 63 |
+
data: [null,null],
|
| 64 |
+
form: null,
|
| 65 |
+
error: null
|
| 66 |
+
});
|
| 67 |
+
});
|
| 68 |
+
}
|
| 69 |
+
</script>
|
| 70 |
+
</div>
|
| 71 |
+
|
| 72 |
+
<!-- Google Tag Manager -->
|
| 73 |
+
<script>
|
| 74 |
+
if (window.gaId) {
|
| 75 |
+
const script = document.createElement("script");
|
| 76 |
+
script.src = "https://www.googletagmanager.com/gtag/js?id=" + window.gaId;
|
| 77 |
+
script.async = true;
|
| 78 |
+
document.head.appendChild(script);
|
| 79 |
+
|
| 80 |
+
window.dataLayer = window.dataLayer || [];
|
| 81 |
+
function gtag() {
|
| 82 |
+
dataLayer.push(arguments);
|
| 83 |
+
}
|
| 84 |
+
gtag("js", new Date());
|
| 85 |
+
/// ^ See https://developers.google.com/tag-platform/gtagjs/install
|
| 86 |
+
gtag("config", window.gaId);
|
| 87 |
+
gtag("consent", "default", { ad_storage: "denied", analytics_storage: "denied" });
|
| 88 |
+
/// ^ See https://developers.google.com/tag-platform/gtagjs/reference#consent
|
| 89 |
+
/// TODO: ask the user for their consent and update this with gtag('consent', 'update')
|
| 90 |
+
}
|
| 91 |
+
</script>
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
<div class="contents" hidden=""><div role="presentation" tabindex="-1" class="fixed inset-0 z-40 flex items-center justify-center bg-black/80 backdrop-blur-sm dark:bg-black/50"><!--[!--><div role="dialog" tabindex="-1" class="scrollbar-custom relative mx-auto max-h-[95dvh] max-w-[90dvw] overflow-y-auto overflow-x-hidden rounded-2xl bg-white shadow-2xl outline-none dark:bg-gray-800 dark:text-gray-200 !max-w-[420px] !m-4"><!--[!--><!--]--> <div class="flex w-full flex-col gap-8 bg-white bg-gradient-to-b to-transparent px-6 pb-7 dark:bg-black dark:from-white/10 dark:to-white/5"><div class="relative -mx-6 grid h-48 select-none place-items-center bg-gradient-to-t from-black/5 dark:from-white/10"><img class="size-full bg-black object-cover" src="https://huggingface.co/chat/huggingchat/omni-welcome.gif" alt="Omni AI model router animation"> <div class="absolute bottom-3 right-3 rounded-lg border border-blue-500/20 bg-blue-500/20 px-2 py-0.5 text-sm font-semibold text-blue-500">Now with MCP!</div></div> <div class="text-gray-700 dark:text-gray-200"><p class="text-[15px] leading-relaxed">Welcome to HuggingChat, the chat app powered by open source AI models.</p> <p class="mt-3 text-[15px] leading-relaxed"><svg class="-translate-y-px hidden dark:inline" width="1em" height="1em" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M5.97736 12.1813C6.25011 12.516 6.57428 12.8946 6.98029 13.2741C5.89251 13.8066 4.44063 14.1305 2.34747 14.1306V12.7272C4.02144 12.7272 5.15855 12.5026 5.97736 12.1813ZM10.0789 6.00458C10.3483 6.3067 10.6247 6.56949 10.9725 6.79364C11.5911 7.19216 12.4914 7.49774 14.0526 7.49774V8.90204C12.4915 8.90204 11.5911 9.20765 10.9725 9.60614C10.6249 9.83013 10.3481 10.0924 10.0789 10.3942C9.78258 10.1597 9.52333 9.87047 9.21271 9.48798C9.18183 9.44996 9.14961 9.40984 9.11603 9.36786C9.42491 9.03403 9.77986 8.70638 10.2127 8.42743C10.3378 8.34683 10.4686 8.27118 10.6053 8.19989C10.4686 8.12858 10.3378 8.05297 10.2127 7.97235C9.77958 7.69322 9.42506 7.365 9.11603 7.03094C9.1494 6.98922 9.18201 6.9496 9.21271 6.9118C9.52349 6.52912 9.78237 6.2392 10.0789 6.00458ZM2.34747 2.26923C4.44032 2.26927 5.89256 2.59232 6.98029 3.12469C6.57429 3.50414 6.25012 3.8828 5.97736 4.21747C5.15858 3.89631 4.02115 3.67356 2.34747 3.67352V2.26923Z" fill="url(#paint0_linear_3699_582)"></path><path d="M14.052 3.67331C12.0512 3.67337 10.8161 3.98917 9.97647 4.41441C9.14382 4.83623 8.63688 5.39533 8.12318 6.02791C7.62178 6.64535 7.06413 7.40735 6.18741 7.97235C6.06225 8.053 5.93137 8.12889 5.79462 8.20022C5.93144 8.27158 6.06219 8.34739 6.18741 8.42808C7.06422 8.99314 7.62174 9.75505 8.12318 10.3725C8.6369 11.0051 9.14374 11.5642 9.97647 11.986C10.8161 12.4113 12.0512 12.7271 14.052 12.7271V14.1312C11.9098 14.1311 10.4387 13.7932 9.34279 13.2382C8.24007 12.6797 7.58149 11.9313 7.03377 11.2569C6.47365 10.5671 6.07238 10.0218 5.42786 9.60647C4.80925 9.20786 3.90875 8.90226 2.34735 8.90226V7.49818C3.90859 7.49818 4.80926 7.19251 5.42786 6.79397C6.07232 6.37865 6.47373 5.83323 7.03377 5.14358C7.58147 4.46911 8.24014 3.72078 9.34279 3.16224C10.4387 2.60722 11.9098 2.26929 14.052 2.26923V3.67331Z" fill="url(#paint1_linear_3699_582)"></path><defs><linearGradient id="paint0_linear_3699_582" x1="10.2846" y1="8.06294" x2="-0.714687" y2="8.06294" gradientUnits="userSpaceOnUse"><stop stop-color="white"></stop><stop offset="1" stop-color="white" stop-opacity="0"></stop></linearGradient><linearGradient id="paint1_linear_3699_582" x1="1.34749" y1="8.06326" x2="14.273" y2="8.06326" gradientUnits="userSpaceOnUse"><stop stop-color="white" stop-opacity="0"></stop><stop offset="1" stop-color="white"></stop></linearGradient></defs></svg><svg class="-translate-y-px inline dark:hidden" width="1em" height="1em" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M5.97723 12.3813C6.24999 12.716 6.57417 13.0946 6.98016 13.4741C5.89247 14.0066 4.44119 14.3305 2.34833 14.3306V12.9272C4.02198 12.9272 5.1585 12.7025 5.97723 12.3813ZM10.0788 6.20459C10.3481 6.50673 10.6245 6.76948 10.9724 6.99365C11.5909 7.39219 12.4912 7.69774 14.0524 7.69775V9.10205C12.4913 9.10207 11.5909 9.40765 10.9724 9.80615C10.6248 10.0302 10.348 10.2924 10.0788 10.5942C9.78249 10.3597 9.52319 10.0704 9.21259 9.68799C9.18171 9.64997 9.14949 9.60986 9.11591 9.56787C9.42481 9.23402 9.77972 8.9064 10.2126 8.62744C10.3377 8.54682 10.4685 8.47121 10.6052 8.3999C10.4685 8.32859 10.3377 8.25299 10.2126 8.17236C9.77943 7.89322 9.42495 7.56504 9.11591 7.23096C9.1493 7.18921 9.18187 7.14963 9.21259 7.11182C9.52337 6.72913 9.78226 6.43921 10.0788 6.20459ZM2.34833 2.46924C4.44088 2.46933 5.89252 2.7924 6.98016 3.32471C6.57418 3.70415 6.25 4.08282 5.97723 4.41748C5.15853 4.09637 4.0217 3.87361 2.34833 3.87354V2.46924Z" fill="url(#paint0_linear_3699_575)"></path><path d="M14.052 3.87332C12.0512 3.87338 10.8161 4.18918 9.97647 4.61442C9.14382 5.03624 8.63688 5.59534 8.12318 6.22792C7.62178 6.84536 7.06413 7.60736 6.18741 8.17236C6.06225 8.25301 5.93137 8.3289 5.79462 8.40023C5.93144 8.47159 6.06219 8.5474 6.18741 8.62809C7.06422 9.19316 7.62174 9.95506 8.12318 10.5725C8.6369 11.2051 9.14374 11.7642 9.97647 12.186C10.8161 12.6113 12.0512 12.9271 14.052 12.9271V14.3312C11.9098 14.3312 10.4387 13.9932 9.34279 13.4382C8.24007 12.8797 7.58149 12.1313 7.03377 11.4569C6.47365 10.7671 6.07238 10.2218 5.42786 9.80648C4.80925 9.40788 3.90875 9.10227 2.34735 9.10227V7.69819C3.90859 7.69819 4.80926 7.39252 5.42786 6.99398C6.07232 6.57866 6.47373 6.03324 7.03377 5.34359C7.58147 4.66913 8.24014 3.92079 9.34279 3.36225C10.4387 2.80724 11.9098 2.4693 14.052 2.46924V3.87332Z" fill="url(#paint1_linear_3699_575)"></path><defs><linearGradient id="paint0_linear_3699_575" x1="10.2848" y1="8.26295" x2="-0.713577" y2="8.26295" gradientUnits="userSpaceOnUse"><stop></stop><stop offset="1" stop-opacity="0"></stop></linearGradient><linearGradient id="paint1_linear_3699_575" x1="1.34749" y1="8.26327" x2="14.273" y2="8.26327" gradientUnits="userSpaceOnUse"><stop stop-opacity="0"></stop><stop offset="1"></stop></linearGradient></defs></svg><!----> Omni automatically picks the best AI model to give
|
| 95 |
+
you optimal answers depending on your requests.</p> <p class="mt-3 text-[15px] leading-relaxed">You can also choose from any available open source models to chat with directly.</p></div> <button class="k w-full rounded-xl bg-black px-5 py-2.5 text-base font-medium text-white hover:bg-gray-800 dark:bg-white dark:text-black dark:hover:bg-gray-200">Start chatting</button></div><!----></div><!--]--></div><!----></div><!----><!----><!----><!----><!----></body></html>
|
engine.py
CHANGED
|
@@ -19,7 +19,7 @@ from providers.g4f_provider import G4FProvider
|
|
| 19 |
from providers.pollinations_provider import PollinationsProvider
|
| 20 |
from providers.gemini_provider import GeminiProvider
|
| 21 |
from providers.zai_provider import ZaiProvider
|
| 22 |
-
from providers.
|
| 23 |
from config import MODEL_RANKING, PROVIDER_MODELS, SUPABASE_URL, SUPABASE_KEY
|
| 24 |
from models import ModelInfo
|
| 25 |
from sanitizer import sanitize_response
|
|
@@ -58,11 +58,11 @@ class AIEngine:
|
|
| 58 |
self._providers["gemini"] = GeminiProvider()
|
| 59 |
logger.info("β
Gemini provider enabled")
|
| 60 |
|
| 61 |
-
#
|
| 62 |
-
self._providers["
|
| 63 |
-
logger.info("β
|
| 64 |
else:
|
| 65 |
-
logger.warning("β οΈ Z.ai/Gemini/
|
| 66 |
# Success Tracker: Key = "provider/model_id"
|
| 67 |
# Value = {success, failure, consecutive_failures, avg_time_ms, total_time_ms, count_samples}
|
| 68 |
self._stats: dict[str, dict] = {}
|
|
|
|
| 19 |
from providers.pollinations_provider import PollinationsProvider
|
| 20 |
from providers.gemini_provider import GeminiProvider
|
| 21 |
from providers.zai_provider import ZaiProvider
|
| 22 |
+
from providers.huggingchat_provider import HuggingChatProvider
|
| 23 |
from config import MODEL_RANKING, PROVIDER_MODELS, SUPABASE_URL, SUPABASE_KEY
|
| 24 |
from models import ModelInfo
|
| 25 |
from sanitizer import sanitize_response
|
|
|
|
| 58 |
self._providers["gemini"] = GeminiProvider()
|
| 59 |
logger.info("β
Gemini provider enabled")
|
| 60 |
|
| 61 |
+
# HuggingChat also uses Playwright
|
| 62 |
+
self._providers["huggingchat"] = HuggingChatProvider()
|
| 63 |
+
logger.info("β
HuggingChat provider enabled")
|
| 64 |
else:
|
| 65 |
+
logger.warning("β οΈ Z.ai/Gemini/HuggingChat providers disabled (Playwright not installed)")
|
| 66 |
# Success Tracker: Key = "provider/model_id"
|
| 67 |
# Value = {success, failure, consecutive_failures, avg_time_ms, total_time_ms, count_samples}
|
| 68 |
self._stats: dict[str, dict] = {}
|
providers/{copilot_provider.py β huggingchat_provider.py}
RENAMED
|
@@ -1,13 +1,13 @@
|
|
| 1 |
"""
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
Uses Playwright Chromium to interact with https://
|
| 5 |
|
| 6 |
Strategy:
|
| 7 |
-
-
|
| 8 |
-
- Uses EPHEMERAL contexts
|
| 9 |
-
-
|
| 10 |
-
-
|
| 11 |
"""
|
| 12 |
|
| 13 |
import asyncio
|
|
@@ -16,25 +16,25 @@ import re
|
|
| 16 |
from providers.base import BaseProvider
|
| 17 |
from config import PROVIDER_MODELS
|
| 18 |
|
| 19 |
-
logger = logging.getLogger("kai_api.
|
| 20 |
|
| 21 |
_playwright = None
|
| 22 |
_browser = None
|
| 23 |
_lock = asyncio.Lock()
|
| 24 |
|
| 25 |
|
| 26 |
-
class
|
| 27 |
-
"""AI provider using
|
| 28 |
|
| 29 |
-
RESPONSE_TIMEOUT =
|
| 30 |
-
HYDRATION_DELAY =
|
| 31 |
|
| 32 |
@property
|
| 33 |
def name(self) -> str:
|
| 34 |
-
return "
|
| 35 |
|
| 36 |
def get_available_models(self) -> list[str]:
|
| 37 |
-
return PROVIDER_MODELS.get("
|
| 38 |
|
| 39 |
@staticmethod
|
| 40 |
def is_available() -> bool:
|
|
@@ -53,7 +53,7 @@ class CopilotProvider(BaseProvider):
|
|
| 53 |
if _browser and _browser.is_connected():
|
| 54 |
return
|
| 55 |
|
| 56 |
-
logger.info("π
|
| 57 |
from playwright.async_api import async_playwright
|
| 58 |
|
| 59 |
_playwright = await async_playwright().start()
|
|
@@ -64,11 +64,9 @@ class CopilotProvider(BaseProvider):
|
|
| 64 |
"--no-sandbox",
|
| 65 |
"--disable-dev-shm-usage",
|
| 66 |
"--disable-gpu",
|
| 67 |
-
"--disable-web-security",
|
| 68 |
-
"--disable-features=IsolateOrigins,site-per-process",
|
| 69 |
],
|
| 70 |
)
|
| 71 |
-
logger.info("β
|
| 72 |
|
| 73 |
async def send_message(
|
| 74 |
self,
|
|
@@ -77,80 +75,81 @@ class CopilotProvider(BaseProvider):
|
|
| 77 |
system_prompt: str | None = None,
|
| 78 |
**kwargs,
|
| 79 |
) -> dict:
|
| 80 |
-
"""Send a message via
|
| 81 |
if not self.is_available():
|
| 82 |
raise RuntimeError("Playwright not installed.")
|
| 83 |
|
| 84 |
await self._ensure_browser()
|
| 85 |
-
selected_model = model or "
|
| 86 |
|
| 87 |
# Create Ephemeral Context
|
| 88 |
context = await _browser.new_context(
|
| 89 |
viewport={"width": 1920, "height": 1080},
|
| 90 |
-
user_agent="Mozilla/5.0 (
|
| 91 |
"AppleWebKit/537.36 (KHTML, like Gecko) "
|
| 92 |
-
"Chrome/120.0.0.0 Safari/537.36
|
| 93 |
locale="en-US",
|
| 94 |
-
timezone_id="America/New_York",
|
| 95 |
)
|
| 96 |
|
| 97 |
# Hide webdriver flag
|
| 98 |
await context.add_init_script("""
|
| 99 |
Object.defineProperty(navigator, 'webdriver', {get: () => undefined});
|
| 100 |
-
Object.defineProperty(navigator, 'plugins', {get: () => [1, 2, 3, 4, 5]});
|
| 101 |
-
window.chrome = { runtime: {} };
|
| 102 |
""")
|
| 103 |
|
| 104 |
page = await context.new_page()
|
| 105 |
|
| 106 |
try:
|
| 107 |
-
logger.info(f"
|
| 108 |
-
|
| 109 |
-
# Navigate to
|
| 110 |
-
await page.goto("https://
|
| 111 |
-
|
| 112 |
-
#
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
break
|
| 129 |
-
except:
|
| 130 |
-
continue
|
| 131 |
-
|
| 132 |
-
if not input_selector:
|
| 133 |
-
raise RuntimeError("Could not find Copilot chat input")
|
| 134 |
|
| 135 |
await asyncio.sleep(self.HYDRATION_DELAY)
|
| 136 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 137 |
# Type the message
|
| 138 |
full_prompt = prompt
|
| 139 |
if system_prompt:
|
| 140 |
full_prompt = f"[System: {system_prompt}]\n\n{prompt}"
|
| 141 |
|
| 142 |
-
await page.
|
| 143 |
-
await page.keyboard.type(full_prompt, delay=10)
|
| 144 |
await asyncio.sleep(0.5)
|
|
|
|
|
|
|
| 145 |
await page.keyboard.press("Enter")
|
| 146 |
-
|
| 147 |
-
logger.info("Copilot: Message sent...")
|
| 148 |
|
| 149 |
# Wait for response
|
| 150 |
response_text = await self._wait_for_response(page)
|
| 151 |
|
| 152 |
if not response_text:
|
| 153 |
-
raise ValueError("Empty response from
|
| 154 |
|
| 155 |
return {
|
| 156 |
"response": response_text,
|
|
@@ -158,43 +157,70 @@ class CopilotProvider(BaseProvider):
|
|
| 158 |
}
|
| 159 |
|
| 160 |
except Exception as e:
|
| 161 |
-
logger.error(f"
|
| 162 |
raise
|
| 163 |
finally:
|
| 164 |
await context.close()
|
| 165 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 166 |
async def _wait_for_response(self, page) -> str:
|
| 167 |
"""Wait for and extract the AI response from the DOM."""
|
| 168 |
last_text = ""
|
| 169 |
stable_count = 0
|
| 170 |
-
required_stable =
|
| 171 |
|
| 172 |
for i in range(self.RESPONSE_TIMEOUT * 2):
|
| 173 |
await asyncio.sleep(0.5)
|
| 174 |
|
| 175 |
-
# Check for
|
| 176 |
-
|
| 177 |
-
|
| 178 |
-
'
|
| 179 |
-
|
| 180 |
-
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
pass
|
| 186 |
|
| 187 |
# Extract response text
|
| 188 |
current_text = await page.evaluate("""
|
| 189 |
() => {
|
|
|
|
| 190 |
const selectors = [
|
| 191 |
-
'[data-
|
| 192 |
-
'.message
|
| 193 |
-
'[
|
| 194 |
-
'
|
| 195 |
-
'[class*="response"]',
|
| 196 |
-
'[class*="message"] div',
|
| 197 |
'.markdown-body',
|
|
|
|
|
|
|
| 198 |
];
|
| 199 |
|
| 200 |
for (const sel of selectors) {
|
|
@@ -224,20 +250,19 @@ class CopilotProvider(BaseProvider):
|
|
| 224 |
last_text = clean
|
| 225 |
|
| 226 |
if i % 10 == 9:
|
| 227 |
-
logger.info(f"
|
| 228 |
|
| 229 |
if last_text:
|
| 230 |
-
logger.warning("
|
| 231 |
return last_text
|
| 232 |
|
| 233 |
-
raise TimeoutError("
|
| 234 |
|
| 235 |
def _clean_response(self, text: str) -> str:
|
| 236 |
-
"""Clean up
|
| 237 |
clean = text.strip()
|
| 238 |
-
|
| 239 |
-
# Remove common
|
| 240 |
-
clean = re.sub(r"^(Copilot\s*|Microsoft Copilot\s*)", "", clean, flags=re.IGNORECASE)
|
| 241 |
clean = re.sub(r"\n+\s*\n+", "\n\n", clean)
|
| 242 |
-
|
| 243 |
return clean.strip()
|
|
|
|
| 1 |
"""
|
| 2 |
+
HuggingChat Provider (Browser-Based)
|
| 3 |
+
-------------------------------------
|
| 4 |
+
Uses Playwright Chromium to interact with https://huggingface.co/chat as a real browser.
|
| 5 |
|
| 6 |
Strategy:
|
| 7 |
+
- Handles the welcome modal by clicking "Start chatting"
|
| 8 |
+
- Uses EPHEMERAL contexts per request
|
| 9 |
+
- Supports model selection via the model dropdown
|
| 10 |
+
- Scrapes AI response from the DOM
|
| 11 |
"""
|
| 12 |
|
| 13 |
import asyncio
|
|
|
|
| 16 |
from providers.base import BaseProvider
|
| 17 |
from config import PROVIDER_MODELS
|
| 18 |
|
| 19 |
+
logger = logging.getLogger("kai_api.huggingchat")
|
| 20 |
|
| 21 |
_playwright = None
|
| 22 |
_browser = None
|
| 23 |
_lock = asyncio.Lock()
|
| 24 |
|
| 25 |
|
| 26 |
+
class HuggingChatProvider(BaseProvider):
|
| 27 |
+
"""AI provider using HuggingChat via Persistent Playwright Browser."""
|
| 28 |
|
| 29 |
+
RESPONSE_TIMEOUT = 90
|
| 30 |
+
HYDRATION_DELAY = 2.0
|
| 31 |
|
| 32 |
@property
|
| 33 |
def name(self) -> str:
|
| 34 |
+
return "huggingchat"
|
| 35 |
|
| 36 |
def get_available_models(self) -> list[str]:
|
| 37 |
+
return PROVIDER_MODELS.get("huggingchat", ["omni", "meta-llama/Llama-3.3-70B-Instruct"])
|
| 38 |
|
| 39 |
@staticmethod
|
| 40 |
def is_available() -> bool:
|
|
|
|
| 53 |
if _browser and _browser.is_connected():
|
| 54 |
return
|
| 55 |
|
| 56 |
+
logger.info("π HuggingChat: Launching Persistent Browser...")
|
| 57 |
from playwright.async_api import async_playwright
|
| 58 |
|
| 59 |
_playwright = await async_playwright().start()
|
|
|
|
| 64 |
"--no-sandbox",
|
| 65 |
"--disable-dev-shm-usage",
|
| 66 |
"--disable-gpu",
|
|
|
|
|
|
|
| 67 |
],
|
| 68 |
)
|
| 69 |
+
logger.info("β
HuggingChat: Browser is Ready.")
|
| 70 |
|
| 71 |
async def send_message(
|
| 72 |
self,
|
|
|
|
| 75 |
system_prompt: str | None = None,
|
| 76 |
**kwargs,
|
| 77 |
) -> dict:
|
| 78 |
+
"""Send a message via HuggingChat browser automation."""
|
| 79 |
if not self.is_available():
|
| 80 |
raise RuntimeError("Playwright not installed.")
|
| 81 |
|
| 82 |
await self._ensure_browser()
|
| 83 |
+
selected_model = model or "omni"
|
| 84 |
|
| 85 |
# Create Ephemeral Context
|
| 86 |
context = await _browser.new_context(
|
| 87 |
viewport={"width": 1920, "height": 1080},
|
| 88 |
+
user_agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
|
| 89 |
"AppleWebKit/537.36 (KHTML, like Gecko) "
|
| 90 |
+
"Chrome/120.0.0.0 Safari/537.36",
|
| 91 |
locale="en-US",
|
|
|
|
| 92 |
)
|
| 93 |
|
| 94 |
# Hide webdriver flag
|
| 95 |
await context.add_init_script("""
|
| 96 |
Object.defineProperty(navigator, 'webdriver', {get: () => undefined});
|
|
|
|
|
|
|
| 97 |
""")
|
| 98 |
|
| 99 |
page = await context.new_page()
|
| 100 |
|
| 101 |
try:
|
| 102 |
+
logger.info(f"HuggingChat request: {selected_model}")
|
| 103 |
+
|
| 104 |
+
# Navigate to HuggingChat
|
| 105 |
+
await page.goto("https://huggingface.co/chat", timeout=60000)
|
| 106 |
+
|
| 107 |
+
# Handle welcome modal if present
|
| 108 |
+
try:
|
| 109 |
+
start_btn = await page.wait_for_selector(
|
| 110 |
+
'button:has-text("Start chatting")',
|
| 111 |
+
timeout=5000
|
| 112 |
+
)
|
| 113 |
+
if start_btn:
|
| 114 |
+
logger.info("HuggingChat: Clicking 'Start chatting' button...")
|
| 115 |
+
await start_btn.click()
|
| 116 |
+
await asyncio.sleep(1)
|
| 117 |
+
except:
|
| 118 |
+
logger.info("HuggingChat: No welcome modal found, continuing...")
|
| 119 |
+
|
| 120 |
+
# If specific model requested (not omni), try to select it
|
| 121 |
+
if selected_model and selected_model != "omni":
|
| 122 |
+
await self._select_model(page, selected_model)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 123 |
|
| 124 |
await asyncio.sleep(self.HYDRATION_DELAY)
|
| 125 |
|
| 126 |
+
# Find and use the chat input
|
| 127 |
+
input_selector = 'textarea[placeholder*="Ask anything"]'
|
| 128 |
+
|
| 129 |
+
try:
|
| 130 |
+
await page.wait_for_selector(input_selector, timeout=10000)
|
| 131 |
+
except:
|
| 132 |
+
# Fallback selectors
|
| 133 |
+
input_selector = 'textarea'
|
| 134 |
+
await page.wait_for_selector(input_selector, timeout=5000)
|
| 135 |
+
|
| 136 |
# Type the message
|
| 137 |
full_prompt = prompt
|
| 138 |
if system_prompt:
|
| 139 |
full_prompt = f"[System: {system_prompt}]\n\n{prompt}"
|
| 140 |
|
| 141 |
+
await page.fill(input_selector, full_prompt)
|
|
|
|
| 142 |
await asyncio.sleep(0.5)
|
| 143 |
+
|
| 144 |
+
# Press Enter to send
|
| 145 |
await page.keyboard.press("Enter")
|
| 146 |
+
logger.info("HuggingChat: Message sent...")
|
|
|
|
| 147 |
|
| 148 |
# Wait for response
|
| 149 |
response_text = await self._wait_for_response(page)
|
| 150 |
|
| 151 |
if not response_text:
|
| 152 |
+
raise ValueError("Empty response from HuggingChat")
|
| 153 |
|
| 154 |
return {
|
| 155 |
"response": response_text,
|
|
|
|
| 157 |
}
|
| 158 |
|
| 159 |
except Exception as e:
|
| 160 |
+
logger.error(f"HuggingChat Error: {e}")
|
| 161 |
raise
|
| 162 |
finally:
|
| 163 |
await context.close()
|
| 164 |
|
| 165 |
+
async def _select_model(self, page, model: str):
|
| 166 |
+
"""Try to select a specific model from the dropdown."""
|
| 167 |
+
try:
|
| 168 |
+
# Click the model selector button
|
| 169 |
+
model_btn = await page.wait_for_selector(
|
| 170 |
+
'button:has-text("Models")',
|
| 171 |
+
timeout=5000
|
| 172 |
+
)
|
| 173 |
+
if model_btn:
|
| 174 |
+
await model_btn.click()
|
| 175 |
+
await asyncio.sleep(1)
|
| 176 |
+
|
| 177 |
+
# Try to find and click the specific model
|
| 178 |
+
model_option = await page.query_selector(
|
| 179 |
+
f'text={model}'
|
| 180 |
+
)
|
| 181 |
+
if model_option:
|
| 182 |
+
await model_option.click()
|
| 183 |
+
logger.info(f"HuggingChat: Selected model {model}")
|
| 184 |
+
await asyncio.sleep(1)
|
| 185 |
+
else:
|
| 186 |
+
# Close dropdown if model not found
|
| 187 |
+
await page.keyboard.press("Escape")
|
| 188 |
+
logger.warning(f"HuggingChat: Model {model} not found, using default")
|
| 189 |
+
except Exception as e:
|
| 190 |
+
logger.warning(f"HuggingChat: Could not select model: {e}")
|
| 191 |
+
|
| 192 |
async def _wait_for_response(self, page) -> str:
|
| 193 |
"""Wait for and extract the AI response from the DOM."""
|
| 194 |
last_text = ""
|
| 195 |
stable_count = 0
|
| 196 |
+
required_stable = 3
|
| 197 |
|
| 198 |
for i in range(self.RESPONSE_TIMEOUT * 2):
|
| 199 |
await asyncio.sleep(0.5)
|
| 200 |
|
| 201 |
+
# Check for loading/spinner and skip
|
| 202 |
+
is_loading = await page.evaluate("""
|
| 203 |
+
() => {
|
| 204 |
+
const spinners = document.querySelectorAll('[class*="loading"], [class*="spinner"], .animate-pulse');
|
| 205 |
+
return spinners.length > 0;
|
| 206 |
+
}
|
| 207 |
+
""")
|
| 208 |
+
|
| 209 |
+
if is_loading:
|
| 210 |
+
continue
|
|
|
|
| 211 |
|
| 212 |
# Extract response text
|
| 213 |
current_text = await page.evaluate("""
|
| 214 |
() => {
|
| 215 |
+
// Look for the last assistant message
|
| 216 |
const selectors = [
|
| 217 |
+
'[data-message-role="assistant"]',
|
| 218 |
+
'.assistant-message',
|
| 219 |
+
'[class*="prose"]',
|
| 220 |
+
'article',
|
|
|
|
|
|
|
| 221 |
'.markdown-body',
|
| 222 |
+
'[class*="message-content"]',
|
| 223 |
+
'.chat-message:last-child .content',
|
| 224 |
];
|
| 225 |
|
| 226 |
for (const sel of selectors) {
|
|
|
|
| 250 |
last_text = clean
|
| 251 |
|
| 252 |
if i % 10 == 9:
|
| 253 |
+
logger.info(f"HuggingChat: Stream... {len(last_text)} chars")
|
| 254 |
|
| 255 |
if last_text:
|
| 256 |
+
logger.warning("HuggingChat: Timeout, returning partial.")
|
| 257 |
return last_text
|
| 258 |
|
| 259 |
+
raise TimeoutError("HuggingChat no response")
|
| 260 |
|
| 261 |
def _clean_response(self, text: str) -> str:
|
| 262 |
+
"""Clean up HuggingChat response text."""
|
| 263 |
clean = text.strip()
|
| 264 |
+
|
| 265 |
+
# Remove common artifacts
|
|
|
|
| 266 |
clean = re.sub(r"\n+\s*\n+", "\n\n", clean)
|
| 267 |
+
|
| 268 |
return clean.strip()
|
test_copilot_browser.py
DELETED
|
@@ -1,61 +0,0 @@
|
|
| 1 |
-
"""
|
| 2 |
-
Test script for Microsoft Copilot Provider
|
| 3 |
-
Run this to verify the Copilot browser automation works.
|
| 4 |
-
"""
|
| 5 |
-
|
| 6 |
-
import asyncio
|
| 7 |
-
import sys
|
| 8 |
-
import os
|
| 9 |
-
|
| 10 |
-
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
| 11 |
-
|
| 12 |
-
from providers.copilot_provider import CopilotProvider
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
async def test_copilot():
|
| 16 |
-
"""Test the Copilot provider."""
|
| 17 |
-
print("π§ͺ Testing Microsoft Copilot Provider...")
|
| 18 |
-
print("-" * 50)
|
| 19 |
-
|
| 20 |
-
provider = CopilotProvider()
|
| 21 |
-
|
| 22 |
-
# Check if Playwright is available
|
| 23 |
-
if not provider.is_available():
|
| 24 |
-
print("β Playwright not installed. Run: pip install playwright && playwright install chromium")
|
| 25 |
-
return False
|
| 26 |
-
|
| 27 |
-
print("β
Playwright is available")
|
| 28 |
-
print(f"π Available models: {provider.get_available_models()}")
|
| 29 |
-
print()
|
| 30 |
-
|
| 31 |
-
# Test prompts
|
| 32 |
-
test_prompts = [
|
| 33 |
-
"Say 'Hello from Copilot test' and nothing else.",
|
| 34 |
-
"What is 2+2? Answer with just the number.",
|
| 35 |
-
]
|
| 36 |
-
|
| 37 |
-
for i, prompt in enumerate(test_prompts, 1):
|
| 38 |
-
print(f"\nπ Test {i}: {prompt[:50]}...")
|
| 39 |
-
print("-" * 50)
|
| 40 |
-
|
| 41 |
-
try:
|
| 42 |
-
result = await provider.send_message(prompt)
|
| 43 |
-
print(f"β
SUCCESS!")
|
| 44 |
-
print(f"π€ Model: {result['model']}")
|
| 45 |
-
print(f"π¬ Response: {result['response'][:200]}...")
|
| 46 |
-
print()
|
| 47 |
-
except Exception as e:
|
| 48 |
-
print(f"β FAILED: {e}")
|
| 49 |
-
import traceback
|
| 50 |
-
traceback.print_exc()
|
| 51 |
-
return False
|
| 52 |
-
|
| 53 |
-
print("\n" + "=" * 50)
|
| 54 |
-
print("π All Copilot tests passed!")
|
| 55 |
-
print("=" * 50)
|
| 56 |
-
return True
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
if __name__ == "__main__":
|
| 60 |
-
success = asyncio.run(test_copilot())
|
| 61 |
-
sys.exit(0 if success else 1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
test_huggingchat_browser.py
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Test script for HuggingChat Provider
|
| 3 |
+
Run this to verify the HuggingChat browser automation works.
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
import asyncio
|
| 7 |
+
import sys
|
| 8 |
+
import os
|
| 9 |
+
|
| 10 |
+
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
| 11 |
+
|
| 12 |
+
from providers.huggingchat_provider import HuggingChatProvider
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
async def test_huggingchat():
|
| 16 |
+
"""Test the HuggingChat provider."""
|
| 17 |
+
print("π§ͺ Testing HuggingChat Provider...")
|
| 18 |
+
print("-" * 50)
|
| 19 |
+
|
| 20 |
+
provider = HuggingChatProvider()
|
| 21 |
+
|
| 22 |
+
# Check if Playwright is available
|
| 23 |
+
if not provider.is_available():
|
| 24 |
+
print("β Playwright not installed. Run: pip install playwright && playwright install chromium")
|
| 25 |
+
return False
|
| 26 |
+
|
| 27 |
+
print("β
Playwright is available")
|
| 28 |
+
print(f"π Available models: {provider.get_available_models()}")
|
| 29 |
+
print()
|
| 30 |
+
|
| 31 |
+
# Test with default Omni router
|
| 32 |
+
print("\nπ Test 1: Using Omni router (default)")
|
| 33 |
+
print("-" * 50)
|
| 34 |
+
|
| 35 |
+
try:
|
| 36 |
+
result = await provider.send_message("Say 'Hello from HuggingChat test' and nothing else.")
|
| 37 |
+
print(f"β
SUCCESS!")
|
| 38 |
+
print(f"π€ Model: {result['model']}")
|
| 39 |
+
print(f"π¬ Response: {result['response'][:200]}...")
|
| 40 |
+
print()
|
| 41 |
+
except Exception as e:
|
| 42 |
+
print(f"β FAILED: {e}")
|
| 43 |
+
import traceback
|
| 44 |
+
traceback.print_exc()
|
| 45 |
+
return False
|
| 46 |
+
|
| 47 |
+
# Test with specific model
|
| 48 |
+
print("\nπ Test 2: Using Llama 3.3 70B")
|
| 49 |
+
print("-" * 50)
|
| 50 |
+
|
| 51 |
+
try:
|
| 52 |
+
result = await provider.send_message(
|
| 53 |
+
"What is 2+2? Answer with just the number.",
|
| 54 |
+
model="meta-llama/Llama-3.3-70B-Instruct"
|
| 55 |
+
)
|
| 56 |
+
print(f"β
SUCCESS!")
|
| 57 |
+
print(f"π€ Model: {result['model']}")
|
| 58 |
+
print(f"π¬ Response: {result['response'][:200]}...")
|
| 59 |
+
print()
|
| 60 |
+
except Exception as e:
|
| 61 |
+
print(f"β FAILED: {e}")
|
| 62 |
+
import traceback
|
| 63 |
+
traceback.print_exc()
|
| 64 |
+
# Don't fail completely if specific model doesn't work
|
| 65 |
+
|
| 66 |
+
print("\n" + "=" * 50)
|
| 67 |
+
print("π HuggingChat tests completed!")
|
| 68 |
+
print("=" * 50)
|
| 69 |
+
return True
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
if __name__ == "__main__":
|
| 73 |
+
success = asyncio.run(test_huggingchat())
|
| 74 |
+
sys.exit(0 if success else 1)
|