From c11f59af0cac597877715585e6b3ae8955e1d882 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Adam=20Lui=20=E5=88=98=E5=B1=95=E9=B9=8F?=
Date: Thu, 30 Mar 2023 22:46:24 -0700
Subject: [PATCH] Initial commit to address #10
---
chatgpt/duckduckgpt/duckduckgpt-ios.user.js | 151 ++++++++++++++++++++
1 file changed, 151 insertions(+)
create mode 100644 chatgpt/duckduckgpt/duckduckgpt-ios.user.js
diff --git a/chatgpt/duckduckgpt/duckduckgpt-ios.user.js b/chatgpt/duckduckgpt/duckduckgpt-ios.user.js
new file mode 100644
index 0000000000..26b31ca183
--- /dev/null
+++ b/chatgpt/duckduckgpt/duckduckgpt-ios.user.js
@@ -0,0 +1,151 @@
+// ==UserScript==
+// @name DuckDuckGPT 🤖 iOS
+// @version 2023.03.30
+// @author Adam Lui
+// @namespace https://github.com/adamlui
+// @description Adds ChatGPT answers to DuckDuckGo sidebar on iOS
+// @description:zh-CN 将 ChatGPT 答案添加到 iOS 上的 DuckDuckGo 侧边栏
+// @description:zh-SG 将 ChatGPT 答案添加到 iOS 上的 DuckDuckGo 侧边栏
+// @description:zh-TW 將 ChatGPT 答案添加到 iOS 上的 DuckDuckGo 側邊欄
+// @description:zh-HK 將 ChatGPT 答案添加到 iOS 上的 DuckDuckGo 側邊欄
+// @description:ja iOS の DuckDuckGo サイドバーに ChatGPT の回答を追加します
+// @description:ko iOS의 DuckDuckGo 사이드바에 ChatGPT 답변 추가
+// @description:ru Добавляет ответы ChatGPT на боковую панель DuckDuckGo на iOS
+// @description:de Fügt ChatGPT-Antworten zur DuckDuckGo-Seitenleiste auf iOS hinzu
+// @description:es Agrega respuestas de ChatGPT a la barra lateral de DuckDuckGo en iOS
+// @description:fr Ajoute les réponses ChatGPT à la barre latérale DuckDuckGo sur iOS
+// @description:it Aggiunge le risposte ChatGPT alla barra laterale DuckDuckGo su iOS
+// @license MIT
+// @icon https://media.ddgpt.com/images/ddgpt-icon48.png
+// @icon64 https://media.ddgpt.com/images/ddgpt-icon64.png
+// @match https://duckduckgo.com/*
+// @connect api.pawan.krd
+// @grant GM.xmlHttpRequest
+// @downloadURL https://github.com/kudoai/duckduckgpt/raw/main/greasemonkey/duckduckgpt-ios.user.js
+// @updateURL https://github.com/kudoai/duckduckgpt/raw/main/greasemonkey/duckduckgpt-ios.user.js
+// @homepageURL https://www.duckduckgpt.com
+// @supportURL https://github.duckduckgpt.com/issues
+// ==/UserScript==
+
+(function() {
+
+ // API endpoints
+ var proxyEndpointMap = {
+ 'https://api.pawan.krd/v1/chat/completions' : 'pk-pJNAtlAqCHbUDTrDudubjSKeUVgbOMvkRQWMLtscqsdiKmhI'
+ }
+
+ var ddgptDivAlerts = {
+ waitingResponse: 'Waiting for ChatGPT response...',
+ tooManyRequests: 'ChatGPT is flooded with too many requests. Check back later!'
+ }
+
+ // Define console/alert functions
+
+ var ddgptConsole = {
+ info: function(msg) {console.info('🐤 DuckDuckGPT >> ' + msg)},
+ error: function(msg) {console.error('🐤 DuckDuckGPT >> ' + msg)},
+ }
+
+ function ddgptAlert(msg) {
+ if (msg.includes('login')) deleteOpenAIcookies()
+ ddgptDiv.innerHTML = (
+ /waiting|loading/i.test(msg) ? // if alert involves loading, add class
+ '' : '
') + ddgptDivAlerts[msg]
+ + (ddgptDivAlerts[msg].includes('@') ? // if msg needs login link, add it
+ 'chat.openai.com
' : '
')
+ }
+
+ // Define ANSWER functions
+
+ async function getShowAnswer(question, callback) {
+
+ // Initialize attempt properties
+ if (!getShowAnswer.triedEndpoints) getShowAnswer.triedEndpoints = []
+ if (!getShowAnswer.attemptCnt) getShowAnswer.attemptCnt = 0
+
+ // Randomize proxy API
+ var endpoints = Object.keys(proxyEndpointMap).filter(function(endpoint) {
+ return !getShowAnswer.triedEndpoints?.includes(endpoint) })
+ var endpoint = endpoints[Math.floor(Math.random() * endpoints.length)]
+ var accessKey = proxyEndpointMap[endpoint]
+
+ // Get answer from ChatGPT
+ GM.xmlHttpRequest({
+ method: 'POST', url: endpoint,
+ headers: { 'Content-Type': 'application/json', Authorization: 'Bearer ' + accessKey },
+ responseType: 'text',
+ data: JSON.stringify({
+// action: 'next',
+ messages: [{ role: 'user', content: question }],
+ model: 'text-davinci-003',
+ max_tokens: 4000
+ }),
+ onload: onLoad(),
+ onerror: function(error) {
+ if (getShowAnswer.attemptCnt < 1) {
+ retryDiffHost() } else { ddgptConsole.error(error) }}
+ })
+
+ function retryDiffHost() {
+ ddgptConsole.error(`Error calling ${ endpoint }. Trying another endpoint...`)
+ getShowAnswer.triedEndpoints.push(endpoint) // store current proxy to not retry
+ getShowAnswer.attemptCnt++
+ getShowAnswer(question, callback)
+ }
+
+ function onLoad() {
+ return function(event) {
+ if (event.status !== 200 && getShowAnswer.attemptCnt < 1) {
+ retryDiffHost() }
+ else if (event.status === 429) { ddgptAlert('tooManyRequests') }
+ else if (event.responseText) {
+ try {
+ var answer = JSON.parse(event.responseText).choices[0].message.content
+ ddgptShow(answer) ; getShowAnswer.triedEndpoints = [] ; getShowAnswer.attemptCnt = 0
+ } catch (error) {
+ ddgptConsole.error('Failed to parse response JSON: ' + error)
+ if (getShowAnswer.attemptCnt < 1) retryDiffHost()
+ }
+ }}}
+ }
+
+ function ddgptShow(answer) {
+ ddgptDiv.innerHTML = 'ChatGPT
'
+ ddgptDiv.querySelector('pre').textContent = answer
+ }
+
+ async function loadDDGPT() {
+ ddgptAlert('waitingResponse')
+ var siderbarContainer = document.getElementsByClassName('results--sidebar')[0]
+ siderbarContainer.prepend(ddgptDiv, ddgptFooter)
+ getShowAnswer(new URL(location.href).searchParams.get('q'))
+ }
+
+ // Run main routine
+
+ // Stylize ChatGPT container + footer
+ var ddgptStyle = document.createElement('style')
+ ddgptStyle.innerText = (
+ '.chatgpt-container { border-radius: 8px ; border: 1px solid #dadce0 ; padding: 15px ; flex-basis: 0 ;'
+ + 'flex-grow: 1 ; word-wrap: break-word ; white-space: pre-wrap ; box-shadow: 0 2px 3px rgba(0, 0, 0, 0.06) }'
+ + '.chatgpt-container p { margin: 0 }'
+ + '.chatgpt-container .prefix { font-weight: 700 }'
+ + '.chatgpt-container .loading { color: #b6b8ba ; animation: pulse 2s cubic-bezier(.4,0,.6,1) infinite }'
+ + '.chatgpt-container.sidebar-free { margin-left: 60px ; height: fit-content }'
+ + '.chatgpt-container pre { white-space: pre-wrap ; min-width: 0 ; margin-bottom: 0 ; line-height: 20px }'
+ + '@keyframes pulse { 0%, to { opacity: 1 } 50% { opacity: .5 }}'
+ + '.chatgpt-feedback { margin: 2px 0 25px 0 }' )
+ document.head.appendChild(ddgptStyle) // append style to
+
+ // Create DDGPT container & add class
+ var ddgptDiv = document.createElement('div') // create container div
+ ddgptDiv.className = 'chatgpt-container'
+
+ // Create feedback footer & add classes/HTML
+ var ddgptFooter = document.createElement('div')
+ ddgptFooter.className = 'feedback-prompt chatgpt-feedback'
+ ddgptFooter.innerHTML = 'Share Feedback'
+
+ loadDDGPT()
+
+})()