openai-translate 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- openai_translate-1.0.0/PKG-INFO +9 -0
- openai_translate-1.0.0/README.md +61 -0
- openai_translate-1.0.0/openai_translate/__init__.py +3 -0
- openai_translate-1.0.0/openai_translate/main.py +143 -0
- openai_translate-1.0.0/openai_translate.egg-info/PKG-INFO +9 -0
- openai_translate-1.0.0/openai_translate.egg-info/SOURCES.txt +9 -0
- openai_translate-1.0.0/openai_translate.egg-info/dependency_links.txt +1 -0
- openai_translate-1.0.0/openai_translate.egg-info/requires.txt +1 -0
- openai_translate-1.0.0/openai_translate.egg-info/top_level.txt +1 -0
- openai_translate-1.0.0/setup.cfg +4 -0
- openai_translate-1.0.0/setup.py +10 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: openai-translate
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Translate via OpenAI ChatGPT Translate with requests, no login or API key
|
|
5
|
+
Requires-Python: >=3.8
|
|
6
|
+
Requires-Dist: requests
|
|
7
|
+
Dynamic: requires-dist
|
|
8
|
+
Dynamic: requires-python
|
|
9
|
+
Dynamic: summary
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# OpenAI Translate without login/keys
|
|
2
|
+
|
|
3
|
+
`translate.py` translates via OpenAI's ChatGPT Translate (`chatgpt.com/translate/`)
|
|
4
|
+
with plain `requests` — no login, no API key. Everything is auto-extracted at
|
|
5
|
+
runtime by replicating the page's own anonymous handshake (reverse-engineered
|
|
6
|
+
from its JS bundles).
|
|
7
|
+
|
|
8
|
+
## Request chain
|
|
9
|
+
|
|
10
|
+
1. `GET https://chatgpt.com/translate/` → cookies (`oai-did` device id, Cloudflare).
|
|
11
|
+
2. `POST https://chatgpt.com/backend-api/sentinel/chat-requirements/prepare`
|
|
12
|
+
body `{"p": "gAAAAAC" + base64(JSON(fingerprint config))}`
|
|
13
|
+
→ `{prepare_token, proofofwork: {seed, difficulty}, turnstile, so}`.
|
|
14
|
+
3. Solve the proof-of-work in Python: FNV-1a-32 + fmix32 avalanche over
|
|
15
|
+
`seed + base64(JSON(config))`, find config with
|
|
16
|
+
`digest[:len(difficulty)] <= difficulty` (string compare, ~2.6% hit rate,
|
|
17
|
+
solves in milliseconds). Answer = `"gAAAAAB" + base64(JSON(config)) + "~S"`.
|
|
18
|
+
4. `POST https://chatgpt.com/backend-api/sentinel/chat-requirements/finalize`
|
|
19
|
+
body `{"prepare_token", "proofofwork": answer}` → `{token}` (persona
|
|
20
|
+
`chatgpt-noauth`). Turnstile is listed as required but the translate
|
|
21
|
+
endpoint accepts a valid PoW without it.
|
|
22
|
+
5. `POST https://chatgpt.com/translate/stream` with anonymous headers
|
|
23
|
+
(`OAI-Language`, `OAI-Device-Id`, `x-openai-web-frontend: core_web`,
|
|
24
|
+
`OAI-Client-Version`, `OAI-Client-Build-Number`, `OAI-Session-Id`) and body
|
|
25
|
+
`{request: {sourceLanguageCode, targetLanguageCode, text, pipeline:
|
|
26
|
+
"latency-optimized", ...}, sentinel: {chatReqToken, chatReqPrepareToken,
|
|
27
|
+
turnstileToken: null, proofToken}}`.
|
|
28
|
+
Response is SSE: `data: {"delta": "..."}` chunks, ends with `data: [DONE]`.
|
|
29
|
+
|
|
30
|
+
Notes: tokens are effectively single-use — a 403 triggers one automatic fresh
|
|
31
|
+
handshake + retry. `source="detect"` auto-detects the input language.
|
|
32
|
+
|
|
33
|
+
## Usage
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
from openai_translate import OpenAITranslate
|
|
37
|
+
|
|
38
|
+
t = OpenAITranslate()
|
|
39
|
+
print(t.translate("Hello world", target="es", source="en"))
|
|
40
|
+
print(t.translate("مرحبا بالعالم", target="en")) # source auto-detected
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Install as a library:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install .
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Or from PyPI (after a GitHub release is published):
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pip install openai-translate
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Publishing to PyPI uses an API token:
|
|
56
|
+
|
|
57
|
+
1. On pypi.org: Account settings → API tokens → create a token scoped to the
|
|
58
|
+
`openai-translate` project
|
|
59
|
+
2. In this repo: Settings → Secrets and variables → Actions → add it as
|
|
60
|
+
`PYPI_API_TOKEN`
|
|
61
|
+
3. Create a GitHub release — the workflow builds and publishes automatically
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
import json
|
|
3
|
+
import time
|
|
4
|
+
import uuid
|
|
5
|
+
|
|
6
|
+
import requests
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class OpenAITranslate:
|
|
10
|
+
UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"
|
|
11
|
+
BASE = "https://chatgpt.com"
|
|
12
|
+
LABELS = {
|
|
13
|
+
"detect": "Detect language", "en": "English", "ar": "Arabic", "es": "Spanish",
|
|
14
|
+
"fr": "French", "de": "German", "it": "Italian", "pt": "Portuguese",
|
|
15
|
+
"ru": "Russian", "zh": "Chinese", "ja": "Japanese", "ko": "Korean",
|
|
16
|
+
"tr": "Turkish", "hi": "Hindi", "nl": "Dutch", "pl": "Polish",
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
def __init__(self):
|
|
20
|
+
self.s = requests.Session()
|
|
21
|
+
self.s.headers.update({
|
|
22
|
+
"User-Agent": self.UA,
|
|
23
|
+
"Origin": self.BASE,
|
|
24
|
+
"Referer": self.BASE + "/translate/",
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
@staticmethod
|
|
28
|
+
def _fnv(s):
|
|
29
|
+
e = 2166136261
|
|
30
|
+
for ch in s:
|
|
31
|
+
e ^= ord(ch)
|
|
32
|
+
e = (e * 16777619) & 0xFFFFFFFF
|
|
33
|
+
e ^= e >> 16
|
|
34
|
+
e = (e * 2246822507) & 0xFFFFFFFF
|
|
35
|
+
e ^= e >> 13
|
|
36
|
+
e = (e * 3266489909) & 0xFFFFFFFF
|
|
37
|
+
e ^= e >> 16
|
|
38
|
+
return format(e & 0xFFFFFFFF, "08x")
|
|
39
|
+
|
|
40
|
+
@staticmethod
|
|
41
|
+
def _b64json(o):
|
|
42
|
+
return base64.b64encode(json.dumps(o, separators=(",", ":"), ensure_ascii=False).encode()).decode()
|
|
43
|
+
|
|
44
|
+
@classmethod
|
|
45
|
+
def _config(cls):
|
|
46
|
+
return [3000, "Fri Oct 16 2026 23:10:00 GMT+0200", 1792191746000.5, 0, cls.UA,
|
|
47
|
+
"https://chatgpt.com/cdn/assets/entry.client.js", "20260219f9f6",
|
|
48
|
+
"en-US", "en-US,en", 0, "webdriver-function", "hidden", "location",
|
|
49
|
+
1234.5, str(uuid.uuid4()), "", 8, {"totalJSHeapSize": 1000000},
|
|
50
|
+
0, 0, 0, 0, 0, 0, 0]
|
|
51
|
+
|
|
52
|
+
@classmethod
|
|
53
|
+
def _solve_pow(cls, seed, difficulty):
|
|
54
|
+
cfg = cls._config()
|
|
55
|
+
t0 = time.time()
|
|
56
|
+
n = len(difficulty)
|
|
57
|
+
for attempt in range(500000):
|
|
58
|
+
cfg[3] = attempt
|
|
59
|
+
cfg[9] = round((time.time() - t0) * 1000)
|
|
60
|
+
b = cls._b64json(cfg)
|
|
61
|
+
if cls._fnv(seed + b)[:n] <= difficulty:
|
|
62
|
+
return "gAAAAAB" + b + "~S"
|
|
63
|
+
raise RuntimeError("proof-of-work failed")
|
|
64
|
+
|
|
65
|
+
def _handshake(self):
|
|
66
|
+
self.s.get(self.BASE + "/translate/", timeout=30)
|
|
67
|
+
c = self._config()
|
|
68
|
+
c[3] = 1
|
|
69
|
+
c[9] = 1
|
|
70
|
+
prep = self.s.post(self.BASE + "/backend-api/sentinel/chat-requirements/prepare",
|
|
71
|
+
json={"p": "gAAAAAC" + self._b64json(c)}, timeout=30).json()
|
|
72
|
+
self._prepare_token = prep["prepare_token"]
|
|
73
|
+
self._proof = self._solve_pow(prep["proofofwork"]["seed"], prep["proofofwork"]["difficulty"])
|
|
74
|
+
fin = self.s.post(self.BASE + "/backend-api/sentinel/chat-requirements/finalize",
|
|
75
|
+
json={"prepare_token": self._prepare_token,
|
|
76
|
+
"proofofwork": self._proof}, timeout=30).json()
|
|
77
|
+
if not fin.get("token"):
|
|
78
|
+
raise RuntimeError("handshake failed")
|
|
79
|
+
self._token = fin["token"]
|
|
80
|
+
|
|
81
|
+
def _stream(self, text, target, source):
|
|
82
|
+
payload = {
|
|
83
|
+
"request": {
|
|
84
|
+
"includeDetectedLanguage": source == "detect",
|
|
85
|
+
"sourceLanguageCode": source,
|
|
86
|
+
"sourceLanguageLabel": self.LABELS.get(source, source),
|
|
87
|
+
"targetLanguageCode": target,
|
|
88
|
+
"targetLanguageLabel": self.LABELS.get(target, target),
|
|
89
|
+
"text": text,
|
|
90
|
+
"pipeline": "latency-optimized",
|
|
91
|
+
},
|
|
92
|
+
"dedicatedRequest": None,
|
|
93
|
+
"sentinel": {
|
|
94
|
+
"chatReqToken": self._token,
|
|
95
|
+
"chatReqPrepareToken": self._prepare_token,
|
|
96
|
+
"turnstileToken": None,
|
|
97
|
+
"proofToken": self._proof,
|
|
98
|
+
},
|
|
99
|
+
}
|
|
100
|
+
headers = {
|
|
101
|
+
"Content-Type": "application/json",
|
|
102
|
+
"Accept": "text/event-stream",
|
|
103
|
+
"OAI-Language": "en-US",
|
|
104
|
+
"OAI-Device-Id": self.s.cookies.get("oai-did", ""),
|
|
105
|
+
"x-openai-web-frontend": "core_web",
|
|
106
|
+
"OAI-Client-Version": "prod-c8f39f744fd82e629b912bf379c8c9837ab5ccde",
|
|
107
|
+
"OAI-Client-Build-Number": "12327112",
|
|
108
|
+
"OAI-Session-Id": str(uuid.uuid4()),
|
|
109
|
+
}
|
|
110
|
+
return self.s.post(self.BASE + "/translate/stream", json=payload,
|
|
111
|
+
headers=headers, timeout=90, stream=True)
|
|
112
|
+
|
|
113
|
+
@staticmethod
|
|
114
|
+
def _read_deltas(response):
|
|
115
|
+
out = []
|
|
116
|
+
for line in response.iter_lines(decode_unicode=True):
|
|
117
|
+
if not line.startswith("data:"):
|
|
118
|
+
continue
|
|
119
|
+
data = line[5:].strip()
|
|
120
|
+
if data == "[DONE]":
|
|
121
|
+
break
|
|
122
|
+
try:
|
|
123
|
+
out.append(json.loads(data).get("delta", ""))
|
|
124
|
+
except ValueError:
|
|
125
|
+
pass
|
|
126
|
+
return "".join(out)
|
|
127
|
+
|
|
128
|
+
def translate(self, text, target="en", source="detect"):
|
|
129
|
+
self._handshake()
|
|
130
|
+
r = self._stream(text, target, source)
|
|
131
|
+
if r.status_code == 403:
|
|
132
|
+
self._handshake()
|
|
133
|
+
r = self._stream(text, target, source)
|
|
134
|
+
if r.status_code != 200:
|
|
135
|
+
raise RuntimeError(f"translate failed ({r.status_code})")
|
|
136
|
+
return self._read_deltas(r)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
if __name__ == "__main__":
|
|
140
|
+
t = OpenAITranslate()
|
|
141
|
+
print(t.translate("Hello world, how are you today?", target="es", source="en"))
|
|
142
|
+
print(t.translate("مرحبا بالعالم، كيف حالك اليوم؟", target="en"))
|
|
143
|
+
print(t.translate("Good morning", target="ar", source="en"))
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: openai-translate
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Translate via OpenAI ChatGPT Translate with requests, no login or API key
|
|
5
|
+
Requires-Python: >=3.8
|
|
6
|
+
Requires-Dist: requests
|
|
7
|
+
Dynamic: requires-dist
|
|
8
|
+
Dynamic: requires-python
|
|
9
|
+
Dynamic: summary
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
setup.py
|
|
3
|
+
openai_translate/__init__.py
|
|
4
|
+
openai_translate/main.py
|
|
5
|
+
openai_translate.egg-info/PKG-INFO
|
|
6
|
+
openai_translate.egg-info/SOURCES.txt
|
|
7
|
+
openai_translate.egg-info/dependency_links.txt
|
|
8
|
+
openai_translate.egg-info/requires.txt
|
|
9
|
+
openai_translate.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
requests
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
openai_translate
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from setuptools import setup
|
|
2
|
+
|
|
3
|
+
setup(
|
|
4
|
+
name="openai-translate",
|
|
5
|
+
version="1.0.0",
|
|
6
|
+
description="Translate via OpenAI ChatGPT Translate with requests, no login or API key",
|
|
7
|
+
packages=["openai_translate"],
|
|
8
|
+
install_requires=["requests"],
|
|
9
|
+
python_requires=">=3.8",
|
|
10
|
+
)
|