| import numpy as np | |
| import os | |
| from fastapi import FastAPI, HTTPException | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from pydantic import BaseModel | |
| from keras.models import Model | |
| from keras.layers import Dense, Input, Dropout, LSTM, Activation, Embedding | |
| # Initialize FastAPI | |
| app = FastAPI( | |
| title="Emoji Predictor API", | |
| description="Predict emoji from text using LSTM model", | |
| version="1.0.0" | |
| ) | |
| # Enable CORS for Flutter app | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], | |
| allow_credentials=True, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| # Global variables | |
| model = None | |
| word_to_index = None | |
| word_to_vec_map = None | |
| maxLen = 10 | |
| emoji_dictionary = { | |
| 0: "❤️", | |
| 1: "⚾", | |
| 2: "😄", | |
| 3: "😞", | |
| 4: "🍴" | |
| } | |
| emoji_meanings = { | |
| 0: "love", | |
| 1: "sports", | |
| 2: "happy", | |
| 3: "sad", | |
| 4: "food" | |
| } | |
| # Request/Response models | |
| class PredictRequest(BaseModel): | |
| text: str | |
| class PredictResponse(BaseModel): | |
| text: str | |
| emoji: str | |
| emoji_meaning: str | |
| confidence: float | |
| all_predictions: dict | |
| class HealthResponse(BaseModel): | |
| status: str | |
| model_loaded: bool | |
| # Helper functions | |
| def read_glove_vecs(glove_file): | |
| with open(glove_file, 'r', encoding="utf8") as f: | |
| words = set() | |
| word_to_vec_map = {} | |
| for line in f: | |
| line = line.strip().split() | |
| curr_word = line[0] | |
| words.add(curr_word) | |
| word_to_vec_map[curr_word] = np.array(line[1:], dtype=np.float64) | |
| i = 1 | |
| words_to_index = {} | |
| for w in sorted(words): | |
| words_to_index[w] = i | |
| i = i + 1 | |
| return words_to_index, word_to_vec_map | |
| def sentences_to_indices(X, word_to_index, max_len): | |
| m = X.shape[0] | |
| X_indices = np.zeros((m, max_len)) | |
| for i in range(m): | |
| sentence_words = (X[i].lower()).split() | |
| j = 0 | |
| for w in sentence_words: | |
| if w in word_to_index: | |
| X_indices[i, j] = word_to_index[w] | |
| j = j + 1 | |
| if j >= max_len: | |
| break | |
| return X_indices | |
| def pretrained_embedding_layer(word_to_vec_map, word_to_index): | |
| vocab_len = len(word_to_index) + 1 | |
| emb_dim = 50 | |
| emb_matrix = np.zeros((vocab_len, emb_dim)) | |
| for word, index in word_to_index.items(): | |
| if word in word_to_vec_map: | |
| emb_matrix[index, :] = word_to_vec_map[word] | |
| embedding_layer = Embedding(vocab_len, emb_dim) | |
| embedding_layer.build((None,)) | |
| embedding_layer.set_weights([emb_matrix]) | |
| return embedding_layer | |
| def build_model(input_shape, word_to_vec_map, word_to_index): | |
| sentence_indices = Input(shape=input_shape, dtype=np.int32) | |
| embedding_layer = pretrained_embedding_layer(word_to_vec_map, word_to_index) | |
| embeddings = embedding_layer(sentence_indices) | |
| X = LSTM(128, return_sequences=True)(embeddings) | |
| X = Dropout(0.5)(X) | |
| X = LSTM(128)(X) | |
| X = Dropout(0.5)(X) | |
| X = Dense(5, activation='softmax')(X) | |
| X = Activation('softmax')(X) | |
| model = Model(sentence_indices, X) | |
| return model | |
| async def load_model(): | |
| global model, word_to_index, word_to_vec_map | |
| print("Loading GloVe vectors...") | |
| word_to_index, word_to_vec_map = read_glove_vecs('glove.6B.50d.txt') | |
| print("Building model...") | |
| model = build_model((maxLen,), word_to_vec_map, word_to_index) | |
| model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy']) | |
| # Load weights if exists | |
| if os.path.exists('model.weights.h5'): | |
| print("Loading trained weights...") | |
| model.load_weights('model.weights.h5') | |
| else: | |
| print("Warning: No trained weights found. Model will use random weights.") | |
| print("Model loaded successfully!") | |
| async def root(): | |
| return HealthResponse( | |
| status="running", | |
| model_loaded=model is not None | |
| ) | |
| async def health_check(): | |
| return HealthResponse( | |
| status="healthy", | |
| model_loaded=model is not None | |
| ) | |
| async def predict_emoji(request: PredictRequest): | |
| if model is None: | |
| raise HTTPException(status_code=503, detail="Model not loaded") | |
| text = request.text.strip() | |
| if not text: | |
| raise HTTPException(status_code=400, detail="Text cannot be empty") | |
| # Prepare input | |
| x_test = np.array([text]) | |
| X_test_indices = sentences_to_indices(x_test, word_to_index, maxLen) | |
| # Predict | |
| predictions = model.predict(X_test_indices, verbose=0) | |
| predicted_class = int(np.argmax(predictions[0])) | |
| confidence = float(predictions[0][predicted_class]) | |
| # All predictions with probabilities | |
| all_preds = { | |
| emoji_dictionary[i]: { | |
| "probability": float(predictions[0][i]), | |
| "meaning": emoji_meanings[i] | |
| } | |
| for i in range(5) | |
| } | |
| return PredictResponse( | |
| text=text, | |
| emoji=emoji_dictionary[predicted_class], | |
| emoji_meaning=emoji_meanings[predicted_class], | |
| confidence=confidence, | |
| all_predictions=all_preds | |
| ) | |
| async def predict_batch(texts: list[str]): | |
| if model is None: | |
| raise HTTPException(status_code=503, detail="Model not loaded") | |
| results = [] | |
| for text in texts: | |
| x_test = np.array([text.strip()]) | |
| X_test_indices = sentences_to_indices(x_test, word_to_index, maxLen) | |
| predictions = model.predict(X_test_indices, verbose=0) | |
| predicted_class = int(np.argmax(predictions[0])) | |
| results.append({ | |
| "text": text, | |
| "emoji": emoji_dictionary[predicted_class], | |
| "emoji_meaning": emoji_meanings[predicted_class], | |
| "confidence": float(predictions[0][predicted_class]) | |
| }) | |
| return {"predictions": results} | |
| if __name__ == "__main__": | |
| import uvicorn | |
| uvicorn.run(app, host="0.0.0.0", port=7860) | |