Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/api/admin-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2165,8 +2165,8 @@ export class AdminAPI {
const debugInfo = {
timestamp: new Date().toISOString(),
environment: {
nodeVersion: process.version || 'unknown',
platform: process.platform || 'unknown',
nodeVersion: 'cloudflare-worker',
platform: 'cloudflare-worker',
cloudflareWorker: true,
region: this.env?.CF_RAY || 'unknown'
},
Expand Down
44 changes: 10 additions & 34 deletions src/bot/leitner-bot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,37 +9,13 @@ import {
TelegramInlineKeyboard,
User,
Card,
LanguageCode
LanguageCode,
LANGUAGES
} from '../types';
import { ConversationStateManager } from '../services/conversation-state-manager';
import { AdminService } from '../services/admin-service';
import { AddTopicStep, ConversationState, ReviewConversationState, RegistrationConversationState } from '../types/conversation-state';

// 1. Add more languages including Persian (Farsi)
export const LANGUAGES: Record<string, string> = {
en: 'English',
es: 'Spanish',
fr: 'French',
de: 'German',
it: 'Italian',
ru: 'Russian',
zh: 'Chinese',
ja: 'Japanese',
ko: 'Korean',
tr: 'Turkish',
ar: 'Arabic',
fa: 'Persian (Farsi)',
hi: 'Hindi',
pt: 'Portuguese',
pl: 'Polish',
nl: 'Dutch',
sv: 'Swedish',
uk: 'Ukrainian',
el: 'Greek',
he: 'Hebrew'
// Add more as needed
};

// Helper to build condensed inline keyboard (N per row)
function buildCondensedKeyboard<T extends { text: string; callback_data: string }>(buttons: T[], perRow = 3) {
const rows: T[][] = [];
Expand Down Expand Up @@ -855,7 +831,7 @@ Choose what you'd like to do:
state.addTopic.step = 'ask_target_language';
await this.conversationStateManager.setState(userId, state);

const langButtons = Object.entries(LANGUAGES).map(([code, name]) => ({
const langButtons: { text: string; callback_data: string }[] = Object.entries(LANGUAGES).map(([code, name]) => ({
text: name, callback_data: `set_target_lang:${code}`
}));
// Add Back button
Expand All @@ -873,7 +849,7 @@ Choose what you'd like to do:
state.addTopic.step = 'ask_description_language';
await this.conversationStateManager.setState(userId, state);

const langButtons = Object.entries(LANGUAGES).map(([code, name]) => ({
const langButtons: { text: string; callback_data: string }[] = Object.entries(LANGUAGES).map(([code, name]) => ({
text: name, callback_data: `set_desc_lang:${code}`
}));
langButtons.push({ text: '⬅️ Back', callback_data: 'back:ask_source_language' });
Expand Down Expand Up @@ -960,7 +936,7 @@ Choose what you'd like to do:
await this.sendMessage(chatId, '📝 What topic do you want to add vocabulary for?');
break;
case 'ask_source_language': {
const langButtons = Object.entries(LANGUAGES).map(([code, name]) => ({
const langButtons: { text: string; callback_data: string }[] = Object.entries(LANGUAGES).map(([code, name]) => ({
text: name, callback_data: `set_source_lang:${code}`
}));
langButtons.push({ text: '⬅️ Back', callback_data: 'back:ask_topic' });
Expand All @@ -970,7 +946,7 @@ Choose what you'd like to do:
break;
}
case 'ask_target_language': {
const langButtons = Object.entries(LANGUAGES).map(([code, name]) => ({
const langButtons: { text: string; callback_data: string }[] = Object.entries(LANGUAGES).map(([code, name]) => ({
text: name, callback_data: `set_target_lang:${code}`
}));
langButtons.push({ text: '⬅️ Back', callback_data: 'back:ask_source_language' });
Expand All @@ -980,7 +956,7 @@ Choose what you'd like to do:
break;
}
case 'ask_description_language': {
const langButtons = Object.entries(LANGUAGES).map(([code, name]) => ({
const langButtons: { text: string; callback_data: string }[] = Object.entries(LANGUAGES).map(([code, name]) => ({
text: name, callback_data: `set_desc_lang:${code}`
}));
langButtons.push({ text: '⬅️ Back', callback_data: 'back:ask_target_language' });
Expand Down Expand Up @@ -1964,7 +1940,7 @@ Thank you for contacting us! 🎯`, keyboard);
addTopic.step = 'ask_source_language';
await this.conversationStateManager.setState(userId, state);
// Show language options as buttons
const langButtons = Object.entries(LANGUAGES).map(([code, name]) => [{ text: name, callback_data: `set_source_lang:${code}` }]);
const langButtons: { text: string; callback_data: string }[][] = Object.entries(LANGUAGES).map(([code, name]) => [{ text: name, callback_data: `set_source_lang:${code}` }]);
const keyboard: TelegramInlineKeyboard = { inline_keyboard: langButtons };
await this.sendMessage(chatId, '🌍 What is the language of the words?', keyboard);
break;
Expand All @@ -1973,7 +1949,7 @@ Thank you for contacting us! 🎯`, keyboard);
addTopic.sourceLanguage = text;
addTopic.step = 'ask_target_language';
await this.conversationStateManager.setState(userId, state);
const langButtons = Object.entries(LANGUAGES).map(([code, name]) => [{ text: name, callback_data: `set_target_lang:${code}` }]);
const langButtons: { text: string; callback_data: string }[][] = Object.entries(LANGUAGES).map(([code, name]) => [{ text: name, callback_data: `set_target_lang:${code}` }]);
const keyboard: TelegramInlineKeyboard = { inline_keyboard: langButtons };
await this.sendMessage(chatId, '🌐 What is the language for the meaning/translation?', keyboard);
break;
Expand All @@ -1982,7 +1958,7 @@ Thank you for contacting us! 🎯`, keyboard);
addTopic.targetLanguage = text;
addTopic.step = 'ask_description_language';
await this.conversationStateManager.setState(userId, state);
const langButtons = Object.entries(LANGUAGES).map(([code, name]) => [{ text: name, callback_data: `set_desc_lang:${code}` }]);
const langButtons: { text: string; callback_data: string }[][] = Object.entries(LANGUAGES).map(([code, name]) => [{ text: name, callback_data: `set_desc_lang:${code}` }]);
const keyboard: TelegramInlineKeyboard = { inline_keyboard: langButtons };
await this.sendMessage(chatId, '📝 What is the language for the description/definition? (should match the word language)', keyboard);
break;
Expand Down
58 changes: 50 additions & 8 deletions src/services/health-check.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { Env } from '../index';

// Global variable to track service start time
let serviceStartTime = Date.now();

export class HealthCheckService {
constructor(private env: Env) {}

Expand All @@ -9,7 +12,6 @@ export class HealthCheckService {
timestamp: string;
uptime: number;
}> {
const startTime = Date.now();
const checks: Record<string, boolean> = {};

// Check KV store connectivity
Expand Down Expand Up @@ -39,7 +41,8 @@ export class HealthCheckService {
}

const allChecksPass = Object.values(checks).every(Boolean);
const uptime = Date.now() - startTime;
// Calculate actual service uptime since service started
const uptime = Date.now() - serviceStartTime;

return {
status: allChecksPass ? 'healthy' : 'unhealthy',
Expand All @@ -54,12 +57,51 @@ export class HealthCheckService {
requestCount: number;
errorCount: number;
lastError?: string;
uptime: number;
}> {
// Basic system stats - can be extended
return {
memoryUsage: 0, // Memory usage tracking would need to be implemented
requestCount: 0, // Request counting would need to be implemented
errorCount: 0, // Error counting would need to be implemented
};
try {
// Get system stats from KV store if available
const stats = await this.env.LEITNER_DB.get('system_stats', 'json') as {
memoryUsage?: number;
requestCount?: number;
errorCount?: number;
lastError?: string;
} || {};

return {
memoryUsage: stats.memoryUsage || 0,
requestCount: stats.requestCount || 0,
errorCount: stats.errorCount || 0,
lastError: stats.lastError,
uptime: Date.now() - serviceStartTime
};
} catch (error) {
return {
memoryUsage: 0,
requestCount: 0,
errorCount: 0,
uptime: Date.now() - serviceStartTime
};
}
}

// Method to update system stats
async updateSystemStats(stats: {
requestCount?: number;
errorCount?: number;
lastError?: string;
}): Promise<void> {
try {
const currentStats = await this.env.LEITNER_DB.get('system_stats', 'json') || {};
const updatedStats = {
...currentStats,
...stats,
lastUpdated: Date.now()
};

await this.env.LEITNER_DB.put('system_stats', JSON.stringify(updatedStats));
} catch (error) {
console.error('Failed to update system stats:', error);
}
}
}
3 changes: 2 additions & 1 deletion src/services/language-manager.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { TelegramInlineKeyboard } from '../types/index';
import { TelegramInlineKeyboard, LANGUAGES } from '../types/index';

export interface BotTexts {
// Welcome and onboarding
Expand Down Expand Up @@ -159,6 +159,7 @@ export interface BotTexts {
leitnerTip: string;
}

// Interface languages with native names for display
export const SUPPORTED_LANGUAGES = {
en: 'English',
fa: 'فارسی',
Expand Down
8 changes: 7 additions & 1 deletion src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,14 +140,20 @@ export const LANGUAGES = {
'ja': 'Japanese',
'ko': 'Korean',
'ar': 'Arabic',
'fa': 'Persian (Farsi)',
'hi': 'Hindi',
'tr': 'Turkish',
'pl': 'Polish',
'nl': 'Dutch',
'sv': 'Swedish',
'da': 'Danish',
'no': 'Norwegian',
'fi': 'Finnish'
'fi': 'Finnish',
'th': 'Thai',
'vi': 'Vietnamese',
'uk': 'Ukrainian',
'el': 'Greek',
'he': 'Hebrew'
} as const;

export type LanguageCode = keyof typeof LANGUAGES;
Expand Down