@@ -6,6 +6,8 @@ import cors from "cors";
66import helmet from "helmet" ;
77import rateLimit from "express-rate-limit" ;
88import { checkGrammar } from "./services/grammarService" ;
9+ import advancedGrammarService from "./services/advancedGrammarService" ;
10+ import transliterationService from "./services/transliterationService" ;
911import {
1012 validateApiKey ,
1113 checkUserLimits ,
@@ -255,6 +257,382 @@ app.post(
255257 }
256258) ;
257259
260+ // ============================================
261+ // NEW PREMIUM FEATURE ENDPOINTS
262+ // ============================================
263+
264+ // Advanced Tibetan Grammar Analysis Endpoint
265+ app . post ( "/api/grammar/analyze" , async ( req , res ) => {
266+ try {
267+ const { text, mode = "realtime" , style = "formal" , contextualInfo } = req . body ;
268+ const userId = req . headers [ "userid" ] as string ;
269+
270+ if ( ! text || text . trim ( ) . length === 0 ) {
271+ return res . status ( 400 ) . json ( {
272+ success : false ,
273+ error : "Text is required" ,
274+ } ) ;
275+ }
276+
277+ const userLevel = contextualInfo ?. userLevel || "intermediate" ;
278+ const documentType = contextualInfo ?. documentType || "casual" ;
279+
280+ const result = await advancedGrammarService . analyzeTibetanGrammar (
281+ text ,
282+ userLevel ,
283+ documentType
284+ ) ;
285+
286+ // Save to Firestore history
287+ try {
288+ const db = admin . firestore ( ) ;
289+ const userRef = db . collection ( "users" ) . doc ( userId ) ;
290+ const historyRef = userRef . collection ( "grammar_history" ) . doc ( ) ;
291+
292+ await historyRef . set ( {
293+ text,
294+ corrections : result . corrections ,
295+ timestamp : admin . firestore . FieldValue . serverTimestamp ( ) ,
296+ documentType,
297+ savedByUser : false ,
298+ mode,
299+ } ) ;
300+ } catch ( dbError ) {
301+ console . error ( "Error saving to Firestore:" , dbError ) ;
302+ // Don't fail the request if Firestore fails
303+ }
304+
305+ return res . json ( {
306+ success : true ,
307+ data : result ,
308+ usage : {
309+ charactersUsed : text . length ,
310+ } ,
311+ } ) ;
312+ } catch ( error ) {
313+ console . error ( "Grammar analysis error:" , error ) ;
314+ return res . status ( 500 ) . json ( {
315+ success : false ,
316+ error : "Grammar analysis failed" ,
317+ message : error instanceof Error ? error . message : "Unknown error" ,
318+ } ) ;
319+ }
320+ } ) ;
321+
322+ // Tone Alternatives Endpoint
323+ app . post ( "/api/grammar/suggestions" , async ( req , res ) => {
324+ try {
325+ const { text, correctionId, type } = req . body ;
326+
327+ if ( ! text ) {
328+ return res . status ( 400 ) . json ( {
329+ success : false ,
330+ error : "Text is required" ,
331+ } ) ;
332+ }
333+
334+ let result : any = {
335+ alternatives : [ ] ,
336+ examples : [ ] ,
337+ culturalNotes : "" ,
338+ } ;
339+
340+ if ( type === "alternatives" ) {
341+ const tones : Array < "formal" | "casual" | "poetic" | "religious" | "modern" > = [
342+ "formal" ,
343+ "casual" ,
344+ "poetic" ,
345+ ] ;
346+ for ( const tone of tones ) {
347+ const alternatives = await advancedGrammarService . getToneAlternatives ( text , tone ) ;
348+ result . alternatives . push ( {
349+ tone,
350+ suggestions : alternatives ,
351+ } ) ;
352+ }
353+ }
354+
355+ return res . json ( {
356+ success : true ,
357+ data : result ,
358+ } ) ;
359+ } catch ( error ) {
360+ console . error ( "Grammar suggestions error:" , error ) ;
361+ return res . status ( 500 ) . json ( {
362+ success : false ,
363+ error : "Failed to get suggestions" ,
364+ } ) ;
365+ }
366+ } ) ;
367+
368+ // Transliteration Endpoints
369+ app . post ( "/api/transliterate/convert" , async ( req , res ) => {
370+ try {
371+ const { text, sourceSystem = "wylie" , targetSystem = "tibetan" , context = "common" } =
372+ req . body ;
373+ const userId = req . headers [ "userid" ] as string ;
374+
375+ if ( ! text ) {
376+ return res . status ( 400 ) . json ( {
377+ success : false ,
378+ error : "Text is required" ,
379+ } ) ;
380+ }
381+
382+ let result : any ;
383+
384+ // Perform conversion based on source and target systems
385+ if ( sourceSystem === "wylie" && targetSystem === "tibetan" ) {
386+ result = transliterationService . convertWylieToTibetan ( text ) ;
387+ } else if ( sourceSystem === "tibetan" && targetSystem === "wylie" ) {
388+ result = transliterationService . convertTibetanToWylie ( text ) ;
389+ } else if ( targetSystem === "phonetic" ) {
390+ result = transliterationService . convertToPhonetics ( text ) ;
391+ } else {
392+ result = {
393+ result : text ,
394+ alternatives : [ ] ,
395+ confidence : 0 ,
396+ } ;
397+ }
398+
399+ // Save to Firestore history
400+ try {
401+ const db = admin . firestore ( ) ;
402+ const userRef = db . collection ( "users" ) . doc ( userId ) ;
403+ const historyRef = userRef . collection ( "transliteration_history" ) . doc ( ) ;
404+
405+ await historyRef . set ( {
406+ sourceText : text ,
407+ sourceSystem,
408+ targetSystem,
409+ result : result . result ,
410+ timestamp : admin . firestore . FieldValue . serverTimestamp ( ) ,
411+ savedByUser : false ,
412+ } ) ;
413+ } catch ( dbError ) {
414+ console . error ( "Error saving transliteration to Firestore:" , dbError ) ;
415+ }
416+
417+ return res . json ( {
418+ success : true ,
419+ data : result ,
420+ } ) ;
421+ } catch ( error ) {
422+ console . error ( "Transliteration error:" , error ) ;
423+ return res . status ( 500 ) . json ( {
424+ success : false ,
425+ error : "Transliteration failed" ,
426+ message : error instanceof Error ? error . message : "Unknown error" ,
427+ } ) ;
428+ }
429+ } ) ;
430+
431+ // Transliteration Database Lookup
432+ app . post ( "/api/transliterate/database/lookup" , async ( req , res ) => {
433+ try {
434+ const { query, type = "common" , limit = 10 } = req . body ;
435+
436+ if ( ! query ) {
437+ return res . status ( 400 ) . json ( {
438+ success : false ,
439+ error : "Query is required" ,
440+ } ) ;
441+ }
442+
443+ const results = transliterationService . searchNameDatabase ( query ) ;
444+
445+ return res . json ( {
446+ success : true ,
447+ data : {
448+ results : results . slice ( 0 , limit ) ,
449+ } ,
450+ } ) ;
451+ } catch ( error ) {
452+ console . error ( "Transliteration lookup error:" , error ) ;
453+ return res . status ( 500 ) . json ( {
454+ success : false ,
455+ error : "Lookup failed" ,
456+ } ) ;
457+ }
458+ } ) ;
459+
460+ // Enhanced Chat with Tutoring Support
461+ app . post ( "/api/chat/message" , async ( req , res ) => {
462+ try {
463+ const {
464+ sessionId,
465+ message,
466+ conversationMode = "general" ,
467+ tutoringLevel = "intermediate" ,
468+ documentContext,
469+ includeExplanation = false ,
470+ } = req . body ;
471+ const userId = req . headers [ "userid" ] as string ;
472+
473+ if ( ! message ) {
474+ return res . status ( 400 ) . json ( {
475+ success : false ,
476+ error : "Message is required" ,
477+ } ) ;
478+ }
479+
480+ const currentSessionId = sessionId || userId ;
481+
482+ // Create or update session with mode
483+ const chat = await ChatSessionManager . getOrCreateSession (
484+ currentSessionId ,
485+ conversationMode as any ,
486+ tutoringLevel as any ,
487+ documentContext
488+ ) ;
489+
490+ // Send message to Gemini
491+ const tibetanResponse = await ChatSessionManager . sendMessage (
492+ currentSessionId ,
493+ message ,
494+ conversationMode as any
495+ ) ;
496+
497+ // Save message to Firestore
498+ try {
499+ const db = admin . firestore ( ) ;
500+ const conversationRef = db
501+ . collection ( "users" )
502+ . doc ( userId )
503+ . collection ( "conversations" )
504+ . doc ( currentSessionId ) ;
505+
506+ // Create or update conversation document
507+ await conversationRef . set (
508+ {
509+ mode : conversationMode ,
510+ tutoringLevel : conversationMode === "tutoring" ? tutoringLevel : null ,
511+ updatedAt : admin . firestore . FieldValue . serverTimestamp ( ) ,
512+ messageCount : admin . firestore . FieldValue . increment ( 1 ) ,
513+ preview : message . substring ( 0 , 100 ) ,
514+ lastMessageTime : admin . firestore . FieldValue . serverTimestamp ( ) ,
515+ } ,
516+ { merge : true }
517+ ) ;
518+
519+ // Add message to subcollection
520+ const messagesRef = conversationRef . collection ( "messages" ) . doc ( ) ;
521+ await messagesRef . set ( {
522+ sender : "user" ,
523+ content : message ,
524+ timestamp : admin . firestore . FieldValue . serverTimestamp ( ) ,
525+ mode : conversationMode ,
526+ } ) ;
527+
528+ // Add response
529+ const responseRef = conversationRef . collection ( "messages" ) . doc ( ) ;
530+ await responseRef . set ( {
531+ sender : "assistant" ,
532+ content : tibetanResponse ,
533+ timestamp : admin . firestore . FieldValue . serverTimestamp ( ) ,
534+ mode : conversationMode ,
535+ confidence : 0.92 ,
536+ } ) ;
537+ } catch ( dbError ) {
538+ console . error ( "Error saving chat to Firestore:" , dbError ) ;
539+ }
540+
541+ const response : GeminiChatResponse = {
542+ success : true ,
543+ data : {
544+ response : tibetanResponse ,
545+ sessionId : currentSessionId ,
546+ messageId : `msg_${ Date . now ( ) } ` ,
547+ } ,
548+ usage : {
549+ charactersUsed : message . length + tibetanResponse . length ,
550+ } ,
551+ } ;
552+
553+ return res . json ( response ) ;
554+ } catch ( error ) {
555+ console . error ( "Enhanced chat error:" , error ) ;
556+ return res . status ( 500 ) . json ( {
557+ success : false ,
558+ error : "Chat failed" ,
559+ message : error instanceof Error ? error . message : "Unknown error" ,
560+ } ) ;
561+ }
562+ } ) ;
563+
564+ // Chat History Endpoint
565+ app . get ( "/api/chat/history" , async ( req , res ) => {
566+ try {
567+ const userId = req . headers [ "userid" ] as string ;
568+ const limit = parseInt ( req . query . limit as string ) || 20 ;
569+ const offset = parseInt ( req . query . offset as string ) || 0 ;
570+
571+ const db = admin . firestore ( ) ;
572+ const conversationsRef = db . collection ( "users" ) . doc ( userId ) . collection ( "conversations" ) ;
573+
574+ let query : any = conversationsRef . orderBy ( "updatedAt" , "desc" ) . limit ( limit ) ;
575+
576+ if ( offset > 0 ) {
577+ query = query . offset ( offset ) ;
578+ }
579+
580+ const snapshot = await query . get ( ) ;
581+ const conversations = snapshot . docs . map ( ( doc ) => ( {
582+ conversationId : doc . id ,
583+ ...doc . data ( ) ,
584+ } ) ) ;
585+
586+ return res . json ( {
587+ success : true ,
588+ data : {
589+ conversations,
590+ totalCount : snapshot . size ,
591+ } ,
592+ } ) ;
593+ } catch ( error ) {
594+ console . error ( "Chat history error:" , error ) ;
595+ return res . status ( 500 ) . json ( {
596+ success : false ,
597+ error : "Failed to fetch history" ,
598+ } ) ;
599+ }
600+ } ) ;
601+
602+ // Tutoring Mode Configuration
603+ app . post ( "/api/chat/tutoring/mode" , async ( req , res ) => {
604+ try {
605+ const { sessionId, enabled, level = "beginner" , topic = "grammar" } = req . body ;
606+ const userId = req . headers [ "userid" ] as string ;
607+
608+ if ( enabled ) {
609+ ChatSessionManager . updateSessionMode ( sessionId || userId , "tutoring" , level as any ) ;
610+
611+ const curriculum = ChatSessionManager . getTutoringCurriculum ( level as any ) ;
612+
613+ return res . json ( {
614+ success : true ,
615+ data : {
616+ curriculum,
617+ systemPrompt : `Tutoring mode activated for ${ level } level` ,
618+ } ,
619+ } ) ;
620+ } else {
621+ ChatSessionManager . updateSessionMode ( sessionId || userId , "general" ) ;
622+ return res . json ( {
623+ success : true ,
624+ message : "Tutoring mode disabled" ,
625+ } ) ;
626+ }
627+ } catch ( error ) {
628+ console . error ( "Tutoring mode error:" , error ) ;
629+ return res . status ( 500 ) . json ( {
630+ success : false ,
631+ error : "Failed to configure tutoring mode" ,
632+ } ) ;
633+ }
634+ } ) ;
635+
258636// Error handling middleware
259637app . use ( errorHandler ) ;
260638
0 commit comments