Skip to content

Commit

Permalink
UPDATE new-version
Browse files Browse the repository at this point in the history
- Pushed graphical user interface by [Zarox](https://github.com/zar0x).
- Updated README for better understanding.
  • Loading branch information
Vauth authored Oct 24, 2024
2 parents 763e15b + 2859b88 commit e6c01da
Show file tree
Hide file tree
Showing 2 changed files with 291 additions and 32 deletions.
87 changes: 67 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,46 @@
# Duck GPT
DuckDuckGo AI Chat Wrapper.
<h1>Duck <a href="#Favicon"><img src="https://github.com/user-attachments/assets/b11de9df-f6b1-47a8-973f-cf66375748b9" width="33px"></a> GPT</h1>
<p>Unlimited ChatGPT using cloudflare workers and duckchat.</p>

<br>

## ⚙️ Usage:
## 🗜 Features
- **Clear Chat**: Start a new conversation at any time.
- **Settings**: Toggle particle effects and theme settings (light/dark).
- **Open Source Contributions**: Open to community contributions for further improvements.

<br>

## 📂 Models
- `gpt-4o-mini`
- `claude-3-haiku-20240307`
- `mistralai/Mixtral-8x7B-Instruct-v0.1`
- `meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo`

<br>

## ⚙️ Deploy
- Create a [Cloudflare](https://www.cloudflare.com/) **account**.
- Navigate to `Workers & Pages > Create > Create Worker`.
- Deploy the worker by clicking **Deploy**.
- Edit the code by clicking **Edit Code**.
- Upload [worker.js](https://github.com/Vauth/duckgpt/blob/main/worker/worker.js) into **Cloudflare**.
- Finally, **Deploy**.

[![Deploy to Cloudflare Workers](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/vauth/duckgpt)

<br>

## 📡 Live Demo
Check out the live demo [here](https://duck.gpt-api.workers.dev).

<br>

## 📷 Screenshot
<a href="#Screenshot"><img src="https://github.com/user-attachments/assets/38f60b5a-6a31-42ed-9446-0ce44a06f20f" width="1612px"></a>

<br>

## 📦 Python Usage ([main.py](https://github.com/Vauth/duckgpt/blob/main/main.py))
```python
if __name__ == "__main__":
Client = DuckGPT(model="gpt-4o-mini")
Expand All @@ -17,28 +54,38 @@ if __name__ == "__main__":

<br>

## 📚 Functions:
#### `DuckGPT.Chat`
- Request to duck api using prompt.
#### `DuckGPT.Models`
- Get list of available models.
## 🛠 Credits
- **Front-End Developer**: [Zarox](https://github.com/Zar0x) ([duck-gui](https://github.com/Zar0x/duck-gui))
- **Back-End Developer & GPT API**: [Vauth](https://github.com/Vauth)

<br>

## 📂 Models:
- `gpt-4o-mini`
- `claude-3-haiku-20240307`
- `mistralai/Mixtral-8x7B-Instruct-v0.1`
- `meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo`
## 🔗 Contributing
Contributions are welcome! Feel free to submit a pull request or report an issue.

<br>

## 🛠 Cloudflare Setup:
### Easy Deploy:
## 🔎 License
```
MIT License
[![Deploy to Cloudflare Workers](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/vauth/duckgpt)
### Manually:
- Upload `worker.js` into [cloudflare workers](https://workers.cloudflare.com/).
- Use `duckgpt.XXXX.workers.dev/chat/?prompt=hi&model=gpt-4o-mini` endpoint.
Copyright (c) 2024 Vauth
**Sample api:** [duck.gpt-api.workers.dev](https://duck.gpt-api.workers.dev/help/)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```
236 changes: 224 additions & 12 deletions worker/worker.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,47 @@
// ---------------------------- //
// - github.com/Vauth/duckgpt - //
// ---------------------------- //

const MODELS = ['gpt-4o-mini', 'claude-3-haiku-20240307', 'meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo', 'mistralai/Mixtral-8x7B-Instruct-v0.1'];
const MAIN_MODEL = 'gpt-4o-mini';
const STATUS_URL = 'https://duckduckgo.com/duckchat/v1/status';
const CHAT_API = 'https://duckduckgo.com/duckchat/v1/chat';

addEventListener('fetch', event => {
const ERROR_404 = {"action":"error", "status": 404, "usage": "GET /chat/?prompt=<text>&model=<model>&history=<List[Dict{str, str}]>", "models": MODELS};
const ERROR_403 = {"action":"error", "status": 403, "response": "Wrong history syntax", "example":"[{'role': 'user','content': 'Expert python geek'}]"};

const HEAD_JSON = { 'content-type': 'application/json', 'Access-Control-Allow-Origin': "*"};
const HEAD_HTML = { 'content-type': 'text/html', 'Access-Control-Allow-Origin': "*"};


// ---------- Event Listener ---------- //

addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
let url = new URL(request.url);
let prompt = url.searchParams.get('prompt');
let history = url.searchParams.get('history') || '[]';
let model = url.searchParams.get('model') || 'gpt-4o-mini';
let headers = { 'content-type': 'application/json', 'Access-Control-Allow-Origin': "*"}
let model = url.searchParams.get('model') || MAIN_MODEL;

if (url.pathname == "/") {
let response = HTML;
return new Response(response, {headers: HEAD_HTML});
}

if (!prompt || request.method !== "GET" || url.pathname !== "/chat/") {
return new Response(await Raise(), {status: 400, headers: headers});
if (prompt && url.pathname == "/chat/") {
let response = JSON.stringify(await Chat(prompt, history, model));
return new Response(response, {headers: HEAD_JSON});
} else {
return new Response(await Chat(prompt, history, model), {status: 200, headers: headers});
let response = JSON.stringify(ERROR_404);
return new Response(response, {headers: HEAD_JSON});
}
}

// ---------- Duckgpt Function ---------- //

async function Chat(prompt, history, model) {
let headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:129.0) Gecko/20100101 Firefox/129.0',
Expand All @@ -45,16 +65,208 @@ async function Chat(prompt, history, model) {
headers['Content-Type'] = 'application/json'; let message;

try {message = JSON.parse(history).concat([{ role: 'user', content: prompt }])
} catch {return JSON.stringify({"action":"error", "status": 403, "response": "Wrong history syntax", "example":"[{'role': 'user','content': 'you are an expert python geek'}]"})}
} catch {return ERROR_403}

let data = JSON.stringify({model: model, messages: message});
let Response = await (await fetch(CHAT_API, { method: 'POST', headers: headers, body: data })).text();
let Response = await (await fetch(CHAT_API, { method: 'POST', headers: headers, body: JSON.stringify({model: model, messages: message}) })).text();
let chatMessages = Response.split('\n').filter(line => line.includes('message')).map(line => JSON.parse(line.split('data: ')[1]).message).join('');

if (chatMessages == "") {return Response;}
else {return JSON.stringify({"action":"success", "status": 200, "response": chatMessages, "model": model});}
else {return {"action":"success", "status": 200, "response": chatMessages, "model": model}}
}

async function Raise() {
return JSON.stringify({"action":"error", "status": 404, "usage": "GET /chat/?prompt=<text>&model=<model>&history=<List[Dict{str, str}]>", "models": MODELS});
// ----------------------------- //
// - github.com/zar0x/duck-gui - //
// ----------------------------- //

let CONFIG = {
"scripts": {
"particles": `https://vauth.github.io/duck-gui/scripts/particles.js`,
"script": `https://vauth.github.io/duck-gui/scripts/script.js`
},
"styles": {
"light": `https://vauth.github.io/duck-gui/styles/light.css`,
"styles": `https://vauth.github.io/duck-gui/styles/styles.css`
},
"resources": {
"clear": `https://vauth.github.io/duck-gui/assets/clear.png`,
"developer": `https://vauth.github.io/duck-gui/assets/developer.png`,
"help": `https://vauth.github.io/duck-gui/assets/help.png`,
"load": `https://vauth.github.io/duck-gui/assets/load.gif`,
"photo": `https://vauth.github.io/duck-gui/assets/photo.jpg`,
"send": `https://vauth.github.io/duck-gui/assets/send.png`,
"setting": `https://vauth.github.io/duck-gui/assets/setting.png`,
"source": `https://vauth.github.io/duck-gui/assets/source.png`,
"favicon": `https://vauth.github.io/duck-gui/assets/favicon.png`,
"ogcover": `https://vauth.github.io/duck-gui/assets/ogcover.png`
}
}


// ---------- HTML Website ---------- //

let HTML = `<!DOCTYPE html>
<html lang="en">
<head>
<link rel="icon" type="image/png" sizes="512x512" href="${CONFIG.resources.favicon}" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="DuckGPT unlimited AI assistant." />
<meta name="keywords" content="chatgpt, duckgpt, duckduckgo, AI" />
<meta property="og:image" content="${CONFIG.resources.ogcover}">
<meta name="author" content="execal">
<title>DuckGPT Chat</title>
<meta charset="UTF-8" />
<style>
body {
margin: 0;
padding: 0;
overflow: hidden;
}
#container {
position: relative;
}
#loader {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
z-index: 9999;
background: linear-gradient(135deg, #2b2b2b, #121212);
}
.loader {
width: 48px;
height: 48px;
border: 2px solid #e1e1e1;
position: absolute;
left: -24px;
top: -24px;
box-sizing: border-box;
animation: rotation 2s ease-in-out infinite;
}
#sq2 {
border-color: #ff3333;
animation-delay: 1s;
}
@keyframes rotation {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>
<script
id="MathJax-script"
async
src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"
></script>
<link
href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css"
rel="stylesheet"
/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-python.min.js"></script>
</head>
<body>
<div id="loader">
<div id="container">
<div id="sq1" class="loader"></div>
<div id="sq2" class="loader"></div>
</div>
</div>
<script>if (JSON.parse(localStorage.getItem("setting"))['light'])
{document.getElementById('loader').style.background = 'linear-gradient(135deg, #ffffff, #a4a4a4)';
document.getElementById('sq1').style.borderColor = '#1e1e1e';
document.getElementById('sq2').style.borderColor = '#2965ff'}</script>
<div id="dailog" class="dailog"></div>
<div class="header" id="nHead">
<button id="new-chat-button">
<img class="iconImg headerIcon" src="${CONFIG.resources.clear}" alt="clear Chat" />
</button>
</div>
<div class="header" id="sHead">
<button id="setting-button">
<img class="iconImg headerIcon" src="${CONFIG.resources.setting}" alt="Settings" />
</button>
</div>
<div id="popup-overlay" class="hidden">
<div id="popup-content">
<span id="close-popup">&times;</span>
<div id="clearchat-popup" class="hidden">
<p>
Are you sure you want to clear the current chat and start a new one?
</p>
<button id="yes-button">Yes</button>
<button id="no-button">No</button>
</div>
<div id="setting-popup" class="hidden">
<div class="setting-option">
<label for="particles-toggle">Particle Effects</label>
<label class="switch">
<input type="checkbox" id="particles-toggle"/>
<span class="slider round"></span>
</label>
</div>
<div class="setting-option">
<label for="theme-toggle">Light Theme</label>
<label class="switch">
<input type="checkbox" id="theme-toggle" />
<span class="slider round"></span>
</label>
</div>
</div>
</div>
</div>
<div id="intro-cards-container" class="intro-cards hidden">
<div class="intro-card card-1">
<img src="${CONFIG.resources.source}" alt="Open Source Icon" />
<p>This GUI is an open-source project for <a href="https://github.com/vauth/duckgpt">DuckGPT</a></p>
</div>
<!-- <div class="intro-card card-2">
<img src="${CONFIG.resources.developer}" alt="Help Icon" />
<p>Click the "Type a message below to start.</p>
</div> -->
<div class="intro-card card-3">
<img src="${CONFIG.resources.developer}" alt="Developer Icon" />
<p>Front-End: <a href="https://github.com/ZAR0X">Zarox</a><br>Back-End: <a href="https://github.com/VAUTH">Vauth</a></p>
</div>
</div>
<div class="chat-container">
<div id="chat-box" class="chat-box">
<div class="message-container" id="spaceChatBox"></div>
</div>
<div class="input-container">
<div
id="chat-input"
class="editable-div"
contenteditable="true"
role="textbox"
aria-multiline="true"
></div>
<div id="placeholder">Type your message here...</div>
<!-- <input type="text" id="chat-input" placeholder="Type your message here..." autofocus> -->
<button id="send-button">
<img class="iconImg" src="${CONFIG.resources.send}" alt="Send" />
</button>
</div>
</div>
<div id="particles-js"></div>
<script type="module" src="${CONFIG.scripts.particles}"></script>
<script type="module" src="${CONFIG.scripts.script}"></script>
</body>
</html>`

0 comments on commit e6c01da

Please sign in to comment.