From ec1a587c420e063eb0e5f9936aea7ac3b6659c92 Mon Sep 17 00:00:00 2001 From: aedes Date: Mon, 20 Apr 2026 21:10:58 +0300 Subject: [PATCH] backup: working version 2026-04-20 (direct API + undici + acc3) --- backups/index.html.2026-04-20 | 315 ++++++++++++++++++++++++++++++++++ backups/server.js.2026-04-20 | 110 ++++++++++++ 2 files changed, 425 insertions(+) create mode 100644 backups/index.html.2026-04-20 create mode 100644 backups/server.js.2026-04-20 diff --git a/backups/index.html.2026-04-20 b/backups/index.html.2026-04-20 new file mode 100644 index 0000000..5d62983 --- /dev/null +++ b/backups/index.html.2026-04-20 @@ -0,0 +1,315 @@ + + + + + + Sechenov — Claude Chat + + + +
+

Claude Chat

+ + +
+ +
+
+
Запрос
+ +
+
+
Ответ
+
Ответ появится здесь...
+
+
+ + + + + + diff --git a/backups/server.js.2026-04-20 b/backups/server.js.2026-04-20 new file mode 100644 index 0000000..637e7c9 --- /dev/null +++ b/backups/server.js.2026-04-20 @@ -0,0 +1,110 @@ +const express = require('express'); +const path = require('path'); +const fs = require('fs'); +const os = require('os'); +const { ProxyAgent, setGlobalDispatcher } = require('undici'); + +const proxyUrl = process.env.HTTPS_PROXY || process.env.HTTP_PROXY; +if (proxyUrl) { + setGlobalDispatcher(new ProxyAgent(proxyUrl)); + console.log(`✓ Using proxy: ${proxyUrl}`); +} + +const app = express(); +app.use(express.json({ limit: '10mb' })); +app.use(express.static(path.join(__dirname, 'public'))); + +const MODELS = { + sonnet: 'claude-sonnet-4-6', + haiku: 'claude-haiku-4-5-20251001', +}; + +function getAccessToken() { + const configDir = process.env.CLAUDE_CONFIG_DIR || path.join(os.homedir(), '.claude'); + const credsPath = path.join(configDir, '.credentials.json'); + try { + const creds = JSON.parse(fs.readFileSync(credsPath, 'utf8')); + return creds?.claudeAiOauth?.accessToken || null; + } catch (e) { + return null; + } +} + +app.post('/api/chat', async (req, res) => { + const { text, model = 'sonnet' } = req.body; + if (!text?.trim()) return res.status(400).json({ error: 'text required' }); + + const modelId = MODELS[model] || MODELS.sonnet; + const accessToken = getAccessToken(); + + if (!accessToken) { + return res.status(500).json({ error: 'No credentials in ' + (process.env.CLAUDE_CONFIG_DIR || '~/.claude') }); + } + + res.setHeader('Content-Type', 'text/event-stream'); + res.setHeader('Cache-Control', 'no-cache'); + res.setHeader('Connection', 'keep-alive'); + res.flushHeaders(); + + const heartbeat = setInterval(() => res.write(': ping\n\n'), 15000); + + try { + const apiResp = await fetch('https://api.anthropic.com/v1/messages', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${accessToken}`, + 'anthropic-version': '2023-06-01', + 'anthropic-beta': 'claude-code-20250219,oauth-2025-04-20,interleaved-thinking-2025-05-14,fine-grained-tool-streaming-2025-05-14', + 'x-app': 'cli', + 'User-Agent': 'claude-cli/2.1.114', + }, + body: JSON.stringify({ + model: modelId, + max_tokens: 8192, + stream: true, + system: "You are Claude Code, Anthropic's official CLI for Claude.", + messages: [{ role: 'user', content: text }], + }), + }); + + if (!apiResp.ok) { + const errText = await apiResp.text(); + res.write(`data: ${JSON.stringify({ error: `${apiResp.status}: ${errText.substring(0, 500)}` })}\n\n`); + return; + } + + const reader = apiResp.body.getReader(); + const decoder = new TextDecoder(); + let buf = ''; + + while (true) { + const { done, value } = await reader.read(); + if (done) break; + buf += decoder.decode(value, { stream: true }); + const events = buf.split('\n\n'); + buf = events.pop(); + for (const ev of events) { + const dataLine = ev.split('\n').find(l => l.startsWith('data: ')); + if (!dataLine) continue; + const payload = dataLine.slice(6); + if (payload === '[DONE]') continue; + try { + const obj = JSON.parse(payload); + if (obj.type === 'content_block_delta' && obj.delta?.type === 'text_delta') { + res.write(`data: ${JSON.stringify({ text: obj.delta.text })}\n\n`); + } + } catch (e) {} + } + } + } catch (err) { + console.error('[api error]', err.message); + res.write(`data: ${JSON.stringify({ error: err.message })}\n\n`); + } finally { + clearInterval(heartbeat); + res.write('data: [DONE]\n\n'); + res.end(); + } +}); + +app.listen(8108, () => console.log('sechenov :8108'));