magicboris commited on
Commit
cb2bc0c
·
verified ·
1 Parent(s): a4a7cd7

Create index.js

Browse files
Files changed (1) hide show
  1. index.js +141 -0
index.js ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import express from 'express'
2
+ import cors from 'cors'
3
+ import fetch from 'node-fetch'
4
+
5
+ const app = express()
6
+
7
+ // Считываем ключ Helix из переменных окружения
8
+ const HELIX_API_KEY = process.env.HELIX_API_KEY || ''
9
+
10
+ // CORS
11
+ app.use(cors({
12
+ origin: '*',
13
+ methods: ['GET', 'POST', 'OPTIONS'],
14
+ allowedHeaders: ['Content-Type', 'Authorization']
15
+ }))
16
+ app.use(express.json())
17
+ app.options('*', (req, res) => res.sendStatus(204))
18
+
19
+ // Список доступных моделей
20
+ app.get(['/models', '/v1/models'], (req, res) => {
21
+ res.json({
22
+ object: 'list',
23
+ data: [
24
+ // OpenAI — GPT‑4.1 / 4.5
25
+ { id: 'gpt-4.1', object: 'model', created: 0, owned_by: 'helix' },
26
+ { id: 'gpt-4.1-2025-04-14', object: 'model', created: 0, owned_by: 'helix' },
27
+ { id: 'gpt-4.1-mini', object: 'model', created: 0, owned_by: 'helix' },
28
+ { id: 'gpt-4.1-mini-2025-04-14', object: 'model', created: 0, owned_by: 'helix' },
29
+ { id: 'gpt-4.1-nano', object: 'model', created: 0, owned_by: 'helix' },
30
+ { id: 'gpt-4.1-nano-2025-04-14', object: 'model', created: 0, owned_by: 'helix' },
31
+ { id: 'gpt-4.5-preview', object: 'model', created: 0, owned_by: 'helix' },
32
+ { id: 'gpt-4.5-preview-2025-02-27', object: 'model', created: 0, owned_by: 'helix' },
33
+
34
+ // OpenAI — GPT‑4o
35
+ { id: 'gpt-4o', object: 'model', created: 0, owned_by: 'helix' },
36
+ { id: 'gpt-4o-2024-05-13', object: 'model', created: 0, owned_by: 'helix' },
37
+ { id: 'gpt-4o-2024-08-06', object: 'model', created: 0, owned_by: 'helix' },
38
+ { id: 'gpt-4o-2024-11-20', object: 'model', created: 0, owned_by: 'helix' },
39
+ { id: 'gpt-4o-mini', object: 'model', created: 0, owned_by: 'helix' },
40
+ { id: 'gpt-4o-mini-2024-07-18', object: 'model', created: 0, owned_by: 'helix' },
41
+ { id: 'gpt-4o-search-preview', object: 'model', created: 0, owned_by: 'helix' },
42
+ { id: 'gpt-4o-search-preview-2025-03-11', object: 'model', created: 0, owned_by: 'helix' },
43
+ { id: 'gpt-4o-mini-search-preview', object: 'model', created: 0, owned_by: 'helix' },
44
+ { id: 'gpt-4o-mini-search-preview-2025-03-11', object: 'model', created: 0, owned_by: 'helix' },
45
+
46
+ // Helix — GPT‑3.5 Turbo
47
+ { id: 'gpt-3.5-turbo', object: 'model', created: 0, owned_by: 'helix' }
48
+ ]
49
+ })
50
+ })
51
+
52
+ // Прокси для /chat/completions
53
+ app.post(['/chat/completions', '/v1/chat/completions'], async (req, res) => {
54
+ const {
55
+ model,
56
+ messages = [],
57
+ stream = false,
58
+ temperature,
59
+ top_p,
60
+ presence_penalty,
61
+ frequency_penalty,
62
+ ...rest
63
+ } = req.body
64
+
65
+ // Собираем историю, заменяя китайские префиксы на English
66
+ const historyText = messages
67
+ .map(m => (m.role === 'user' ? 'User: ' : 'Assistant: ') + m.content)
68
+ .join('\n')
69
+
70
+ // Формируем полезную нагрузку для Helix
71
+ const helixPayload = {
72
+ type: 'text',
73
+ stream,
74
+ provider: getProvider(model),
75
+ model,
76
+ messages: [
77
+ {
78
+ role: 'user',
79
+ content: { content_type: 'text', parts: [historyText] }
80
+ }
81
+ ],
82
+ temperature,
83
+ top_p,
84
+ presence_penalty,
85
+ frequency_penalty,
86
+ ...rest
87
+ }
88
+
89
+ // Заголовок авторизации для Helix
90
+ const authHeader = HELIX_API_KEY
91
+ ? `Bearer ${HELIX_API_KEY}`
92
+ : (req.header('authorization') || '')
93
+
94
+ // Отправляем запрос в Helix
95
+ const helixRes = await fetch(
96
+ 'https://app.tryhelix.ai/api/v1/sessions/chat',
97
+ {
98
+ method: 'POST',
99
+ headers: {
100
+ 'Content-Type': 'application/json',
101
+ Authorization: authHeader
102
+ },
103
+ body: JSON.stringify(helixPayload)
104
+ }
105
+ )
106
+
107
+ if (!stream) {
108
+ const data = await helixRes.json()
109
+ const reply = data?.choices?.[0]?.message?.content ?? ''
110
+ return res.status(helixRes.status).json({
111
+ id: `chatcmpl-proxy-${data.id ?? Date.now()}`,
112
+ object: 'chat.completion',
113
+ created: Math.floor(Date.now() / 1000),
114
+ model,
115
+ choices: [
116
+ {
117
+ index: 0,
118
+ message: { role: 'assistant', content: reply },
119
+ finish_reason: 'stop'
120
+ }
121
+ ]
122
+ })
123
+ }
124
+
125
+ // При стриме прокидываем SSE напрямую
126
+ res.status(helixRes.status)
127
+ res.set('Content-Type', 'text/event-stream')
128
+ helixRes.body.pipe(res)
129
+ })
130
+
131
+ // Определяем провайдера по имени модели
132
+ function getProvider(modelId) {
133
+ if (/^gpt-[34]|^gpt-3\.5/.test(modelId)) return 'openai'
134
+ if (/^(llama|phi|aya|gemma|deepseek|qwen)/.test(modelId)) return 'helix'
135
+ return 'togetherai'
136
+ }
137
+
138
+ const PORT = process.env.PORT || 7860
139
+ app.listen(PORT, () => {
140
+ console.log(`🚀 Server listening on port ${PORT}`)
141
+ })