feat(bot): Groq as primary AI provider, Claude fallback

The Telegram assistant now answers via Groq (free) first and falls back to
Claude when ANTHROPIC has credit. Keys come from env (GROQ_API_KEY /
ANTHROPIC_API_KEY) — no secrets in source. Wallet/p2p logic untouched.
This commit is contained in:
2026-06-28 11:16:24 -07:00
parent 2017ae77da
commit fd6b2cc28e
3 changed files with 58 additions and 24 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "pezkuwi-telegram-miniapp",
"version": "1.0.235",
"version": "1.0.236",
"type": "module",
"description": "Pezkuwichain Telegram Mini App - Forum, Announcements, Rewards",
"author": "Pezkuwichain Team",
+3 -3
View File
@@ -1,5 +1,5 @@
{
"version": "1.0.233",
"buildTime": "2026-06-13T04:42:17.513Z",
"buildNumber": 1781325737513
"version": "1.0.236",
"buildTime": "2026-06-28T18:16:24.919Z",
"buildNumber": 1782670584920
}
+54 -20
View File
@@ -26,6 +26,8 @@ const MINI_APP_URLS: Record<string, string> = {
};
const ANTHROPIC_API_KEY = Deno.env.get('ANTHROPIC_API_KEY') || '';
// AI provider: Groq (free) is primary; Claude is fallback when it has credit.
const GROQ_API_KEY = Deno.env.get('GROQ_API_KEY') || '';
function getBotId(req: Request): string {
const url = new URL(req.url);
@@ -234,24 +236,59 @@ async function handleAIChat(token: string, chatId: number, userMessage: string,
});
try {
const response = await fetch('https://api.anthropic.com/v1/messages', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': ANTHROPIC_API_KEY,
'anthropic-version': '2023-06-01',
},
body: JSON.stringify({
model: 'claude-sonnet-4-20250514',
max_tokens: 1024,
system: CLAUDE_SYSTEM_PROMPT,
messages: [{ role: 'user', content: userMessage }],
}),
});
// Primary provider: Groq (free). Fallback: Claude when it has credit.
let aiReply: string | null = null;
if (!response.ok) {
const errorText = await response.text();
console.error('[AI] Claude API error:', response.status, errorText);
if (GROQ_API_KEY) {
try {
const gr = await fetch('https://api.groq.com/openai/v1/chat/completions', {
method: 'POST',
headers: { Authorization: 'Bearer ' + GROQ_API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({
model: 'llama-3.3-70b-versatile',
temperature: 0.3,
max_tokens: 900,
messages: [
{ role: 'system', content: CLAUDE_SYSTEM_PROMPT },
{ role: 'user', content: userMessage },
],
}),
});
if (gr.ok) {
const gd = await gr.json();
aiReply = gd.choices?.[0]?.message?.content || null;
} else {
console.error('[AI] Groq error:', gr.status, await gr.text());
}
} catch (e) {
console.error('[AI] Groq exception:', e);
}
}
if (!aiReply && ANTHROPIC_API_KEY) {
const response = await fetch('https://api.anthropic.com/v1/messages', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': ANTHROPIC_API_KEY,
'anthropic-version': '2023-06-01',
},
body: JSON.stringify({
model: 'claude-sonnet-4-20250514',
max_tokens: 1024,
system: CLAUDE_SYSTEM_PROMPT,
messages: [{ role: 'user', content: userMessage }],
}),
});
if (response.ok) {
const result = await response.json();
aiReply = result.content?.[0]?.text || null;
} else {
console.error('[AI] Claude API error:', response.status, await response.text());
}
}
if (!aiReply) {
await sendTelegramRequest(token, 'sendMessage', {
chat_id: chatId,
text: 'Sorry, I could not process your question right now. Please try again.',
@@ -259,9 +296,6 @@ async function handleAIChat(token: string, chatId: number, userMessage: string,
return;
}
const result = await response.json();
const aiReply = result.content?.[0]?.text || 'No response generated.';
// Telegram message limit is 4096 chars
if (aiReply.length <= 4096) {
await sendTelegramRequest(token, 'sendMessage', {