File size: 5,334 Bytes
8f6910f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
"""FastAPI application for Myanmar Ghost model."""

import logging
from pathlib import Path
from typing import Any, Dict, List, Optional

from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel, Field
import torch

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

app = FastAPI(
    title="Myanmar Ghost API",
    description="Advanced Myanmar Language Understanding Model",
    version="1.0.0",
)

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# Global model reference
model = None
tokenizer = None


class TextInput(BaseModel):
    text: str = Field(..., description="Myanmar text to analyze")
    include_prosody: bool = Field(False, description="Include prosody features")


class SentimentResponse(BaseModel):
    text: str
    sentiment: str
    confidence: float
    probabilities: Dict[str, float]


class BatchTextInput(BaseModel):
    texts: List[str] = Field(..., description="List of Myanmar texts")


class BatchSentimentResponse(BaseModel):
    results: List[SentimentResponse]


@app.on_event("startup")
async def startup_event():
    """Load model on startup."""
    global model, tokenizer
    
    logger.info("Loading Myanmar Ghost model...")
    
    try:
        from transformers import AutoModelForSequenceClassification, AutoTokenizer
        
        model_name = "amkyawdev/Myanmar-Ghost-Instruct"
        tokenizer = AutoTokenizer.from_pretrained(model_name)
        model = AutoModelForSequenceClassification.from_pretrained(model_name)
        model.eval()
        
        logger.info(f"Model loaded: {model_name}")
    except Exception as e:
        logger.warning(f"Could not load model from HuggingFace: {e}")
        logger.info("Using placeholder for demonstration")


@app.get("/")
async def root():
    """Root endpoint."""
    return {
        "name": "Myanmar Ghost API",
        "version": "1.0.0",
        "status": "online",
    }


@app.get("/health")
async def health():
    """Health check endpoint."""
    return {
        "status": "healthy",
        "model_loaded": model is not None,
    }


@app.post("/predict", response_model=SentimentResponse)
async def predict(input_data: TextInput) -> SentimentResponse:
    """Predict sentiment for a single text."""
    if model is None or tokenizer is None:
        raise HTTPException(status_code=503, detail="Model not loaded")
    
    try:
        # Tokenize
        inputs = tokenizer(
            input_data.text,
            return_tensors="pt",
            truncation=True,
            max_length=512,
        )
        
        # Predict
        with torch.no_grad():
            outputs = model(**inputs)
            probs = torch.softmax(outputs.logits, dim=-1)[0]
        
        # Get prediction
        sentiment_idx = probs.argmax().item()
        confidence = probs[sentiment_idx].item()
        
        sentiment_labels = ["negative", "neutral", "positive", "sarcastic"]
        sentiment = sentiment_labels[sentiment_idx]
        
        probabilities = {
            label: probs[i].item()
            for i, label in enumerate(sentiment_labels)
        }
        
        return SentimentResponse(
            text=input_data.text,
            sentiment=sentiment,
            confidence=confidence,
            probabilities=probabilities,
        )
    
    except Exception as e:
        logger.error(f"Prediction error: {e}")
        raise HTTPException(status_code=500, detail=str(e))


@app.post("/predict_batch", response_model=BatchSentimentResponse)
async def predict_batch(input_data: BatchTextInput) -> BatchSentimentResponse:
    """Predict sentiment for multiple texts."""
    if model is None or tokenizer is None:
        raise HTTPException(status_code=503, detail="Model not loaded")
    
    results = []
    
    try:
        for text in input_data.texts:
            # Tokenize
            inputs = tokenizer(
                text,
                return_tensors="pt",
                truncation=True,
                max_length=512,
            )
            
            # Predict
            with torch.no_grad():
                outputs = model(**inputs)
                probs = torch.softmax(outputs.logits, dim=-1)[0]
            
            # Get prediction
            sentiment_idx = probs.argmax().item()
            confidence = probs[sentiment_idx].item()
            
            sentiment_labels = ["negative", "neutral", "positive", "sarcastic"]
            sentiment = sentiment_labels[sentiment_idx]
            
            probabilities = {
                label: probs[i].item()
                for i, label in enumerate(sentiment_labels)
            }
            
            results.append(SentimentResponse(
                text=text,
                sentiment=sentiment,
                confidence=confidence,
                probabilities=probabilities,
            ))
        
        return BatchSentimentResponse(results=results)
    
    except Exception as e:
        logger.error(f"Batch prediction error: {e}")
        raise HTTPException(status_code=500, detail=str(e))


if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)