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.
@@ -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,3 @@
1
+ from .main import OpenAITranslate
2
+
3
+ __all__ = ["OpenAITranslate"]
@@ -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
+ openai_translate
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -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
+ )