-
Notifications
You must be signed in to change notification settings - Fork 224
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix: duckduckgo provider #347
Comments
Well if you check the |
oh yeah.. didn't notice that... maybe we can creates a client-side hash when the server doesn't provide one |
Well for now its working without any hash, i don't know how they compute hashes on their site, you will have to check their js code for that, I guess |
rather than using random values for |
The app isn't using random values |
only for hash maybe
Anyway, so far I've seen that using x-vqd-hash-1 from the status response works. If tgpt works without any hash, that's great. I haven't been able to try it yet, since it hasn't been updated in the Arch repo. |
tgpt DDG is broken again; maybe this can help? |
Hmm it doesn't work |
i've tried fixing tgpt, and it's working now, but chat continuation still doesn't work. in the gpt4free (Python) project, this fix works. ❯ tgpt --provider openai --url "http://localhost:1337/api/DDG/chat/completions" --model "o3-mini" hi
Hello! How can I assist you today? |
In the meantime, I'm trying to figure out how they generate the client hash. I think I've mostly figured out how it works. sequenceDiagram
participant C as Client
participant S as Server
Note over C,S: Authentication Flow
C->>+S: GET /duckchat/v1/status
S-->>-C: Response Headers:<br/>• x-vqd-4<br/>• x-vqd-hash-1 (base64 encoded)
Note over C: Decode x-vqd-hash-1<br/>(base64 decode)
Note over C: Generate client hash<br/>using response hash
Note over C: Create POST payload:<br/>• Array 1: Server hash<br/>• Array 2: Client hash<br/>(both base64 decoded)
C->>+S: POST /duckchat/v1/chat<br/>Headers: x-vqd-hash-1
S-->>-C: Response
DDG client hash generation(messy notes)DDG client hash generation(messy notes)(function () {
return {
server_hashes: ["vYj6hsWWTchDO3IXFrpngPddPRcHwCYHO/mpN+mkImc=","TItQYWEYyMCYaunWovmHN33r67rb9SUTbGQeAqeujKE="],
client_hashes: [navigator.userAgent + (navigator.userAgentData ? navigator.userAgentData.brands.map(brand => `"${brand.brand}";v="${brand.version}"`).join(', ') : ''),(function(){const e = document.createElement('div');e.innerHTML = '<div><div></div><div></div';return String(101 + e.innerHTML.length);})()],
signals: {}
};
})()
const result = (function () {
return {
server_hashes: ["MZeO1rN3+EphrLyzM8hEoAIncpk+40pv1EyLrlGWJJE=","ukJU198teAczYKtLiGI9R62lttWRHIdzKvIKhIzfbFc="],
client_hashes: [
navigator.userAgent + (navigator.userAgentData ? navigator.userAgentData.brands.map(brand => `"${brand.brand}";v="${brand.version}"`).join(', ') : ''),
(function() {
const e = document.createElement('div');
e.innerHTML = '<div><div></div><div></div';
return String(3393 + e.innerHTML.length);
})()
],
signals: {}
};
})();
console.log(result.client_hashes);
{
"server_hashes":["kXtEAXHnC8ngOLACsX8RHUBtdz93TZ/+cz1e7aeehGc=","i1IgsmXoCsdo2Mur54pxFX5p8rwaI4S+TboMYshkU94="],
"client_hashes":["1IiuLsAouAVDiqKmlX+Y86x5fbiGXweBTXOUBwKWrvs=","v6u2zwLapr8dnpHF0UH1Xji4Rgr0A7wKQ3JqjqtHWFU="],"signals":{}}
{
"input": [
"Mozilla/5.0 (X11; Linux x86_64; rv:136.0) Gecko/20100101 Firefox/136.0",
"3426"
],
"client_hashes": [
"1IiuLsAouAVDiqKmlX+Y86x5fbiGXweBTXOUBwKWrvs=",
"TF+GOieSINg5xUfwMw+OijvQ+SdSoL1/n2A6azoza/U="
]
}
(async () => {
const hashString = async (input) => {
const encoder = new TextEncoder();
const data = encoder.encode(input);
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
const hashArray = new Uint8Array(hashBuffer);
const hashString = Array.from(hashArray)
.map(byte => String.fromCharCode(byte))
.join('');
return btoa(hashString);
};
const clientHashes = [
"Mozilla/5.0 (X11; Linux x86_64; rv:136.0) Gecko/20100101 Firefox/136.0",
"3426"
];
const hashedValues = await Promise.all(clientHashes.map(str => hashString(str)));
console.log({
"input": clientHashes,
"client_hashes": hashedValues
});
})();
const e = document.createElement('div');
e.innerHTML = '<div><div></div><div></div';
const hashValue = String(101 + e.innerHTML.length);
console.log(hashValue);
(function () {
return {
server_hashes: ["RvarLp3KDHoq62Hxyw8VFxZsqJVPU5iHB/Fg0yHVZpk=","hcpqmi1rdGyBN9cavGF/s+zdbOulBanh6L2BxZA/YOE="],
client_hashes: [navigator.userAgent + (navigator.userAgentData ? navigator.userAgentData.brands.map(brand => `"${brand.brand}";v="${brand.version}"`).join(', ') : ''),(function(){const e = document.createElement('div');e.innerHTML = '<p><div></p><p></div';return String(7728 + e.innerHTML.length);})()],
signals: {}
};
})()
const e = document.createElement('div');
e.innerHTML = '<p><div></p><p></div';
const hashValue = String(7728 + e.innerHTML.length);
console.log(hashValue);
7760
[ "1IiuLsAouAVDiqKmlX+Y86x5fbiGXweBTXOUBwKWrvs=", "cr302oumqbbldEmkjsj1xYRNskrpw+UbGfGPMEezOSU=" ]
{"server_hashes":["RvarLp3KDHoq62Hxyw8VFxZsqJVPU5iHB/Fg0yHVZpk=","hcpqmi1rdGyBN9cavGF/s+zdbOulBanh6L2BxZA/YOE="],"client_hashes":["1IiuLsAouAVDiqKmlX+Y86x5fbiGXweBTXOUBwKWrvs=","cr302oumqbbldEmkjsj1xYRNskrpw+UbGfGPMEezOSU="],"signals":{}}
eyJzZXJ2ZXJfaGFzaGVzIjpbIlJ2YXJMcDNLREhvcTYySHh5dzhWRnhac3FKVlBVNWlIQi9GZzB5SFZacGs9IiwiaGNwcW1pMXJkR3lCTjljYXZHRi9zK3pkYk91bEJhbmg2TDJCeFpBL1lPRT0iXSwiY2xpZW50X2hhc2hlcyI6WyIxSWl1THNBb3VBVkRpcUttbFgrWTg2eDVmYmlHWHdlQlRYT1VCd0tXcnZzPSIsImNyMzAyb3VtcWJibGRFbWtqc2oxeFlSTnNrcnB3K1ViR2ZHUE1FZXpPU1U9Il0sInNpZ25hbHMiOnt9fQ==
4-323184417266863052404559269421880207118
HTTP/2 200
server: nginx
date: Wed, 26 Mar 2025 23:32:47 GMT
content-type: application/json; charset=utf-8
content-length: 14
etag: W/"e-BBQeGsEgpElDZSMrc0GIzke09hU"
strict-transport-security: max-age=31536000
permissions-policy: interest-cohort=()
x-frame-options: SAMEORIGIN
x-xss-protection: 1;mode=block
x-content-type-options: nosniff
referrer-policy: origin
expect-ct: max-age=0
expires: Wed, 26 Mar 2025 23:32:46 GMT
cache-control: no-cache, no-store
X-Firefox-Spdy: h2 |
I was able to implement their hash generation, however i am still getting errors. |
ca0d215#diff-8860bac4854ca37cd04b6daa0a75d8b33e9397fd67e2a97e4299f35e3e7efd86R84-R86
second element of the client_hashes is dynamically calculated as
|
Just updated to 2.9.4 but I'm still unable to use duck.ai as provider |
Well it hasn't been fixed |
DuckDuckGo AI Chat API Guide
API Flow
Step 1: Obtaining VQD Token and Hash
Make a GET request to fetch the required authentication tokens:
Headers:
The response headers will contain:
x-vqd-4
: Your VQD tokenx-vqd-hash-1
: Your VQD hash (might not always be present)Step 2: Making Chat Requests
Make a POST request to the chat endpoint:
Headers:
Request body:
Available Models:
gpt-4o-mini
(default)meta-llama/Llama-3.3-70B-Instruct-Turbo
claude-3-haiku-20240307
o3-mini
mistralai/Mistral-Small-24B-Instruct-2501
Handling Responses
The response is a stream of Server-Sent Events (SSE), where each line begins with
data:
followed by a JSON object.Example response line:
The stream ends with:
To process this stream and get the complete response:
data:
(excludingdata: [DONE]
)message
field from each JSON objectMaintaining Conversations
To continue a conversation, include previous messages in your next request:
Error Handling
The
x-vqd-4
andx-vqd-hash-1
tokens expire periodically, so refresh them if you get authentication errors.Example Implementations
cURL Example
Python Example
JavaScript Example
The text was updated successfully, but these errors were encountered: