Habiba A. Elbehairy commited on
Commit
40cf02f
·
1 Parent(s): 2113508
Files changed (1) hide show
  1. app.py +43 -119
app.py CHANGED
@@ -1,12 +1,9 @@
1
- from fastapi import FastAPI, HTTPException
2
  from pydantic import BaseModel
3
- from typing import Dict, List, Optional
4
- import torch
5
- import torch.nn as nn
6
- import os
7
- import json
8
  import uvicorn
9
- from transformers import AutoTokenizer, AutoConfig, AutoModel
10
 
11
  app = FastAPI(
12
  title="CodeBERT Multitask Similarity API",
@@ -14,70 +11,17 @@ app = FastAPI(
14
  version="1.0.0"
15
  )
16
 
17
- # Define the MultitaskCodeSimilarityModel class
18
- class MultitaskCodeSimilarityModel(nn.Module):
19
- def __init__(self, model_name, num_labels, tokenizer):
20
- super().__init__()
21
- self.tokenizer = tokenizer
22
- self.config = AutoConfig.from_pretrained(model_name)
23
- self.config.num_labels = num_labels
24
- self.encoder = AutoModel.from_pretrained(model_name, config=self.config)
25
- self.classifier = nn.Linear(self.config.hidden_size, num_labels)
26
-
27
- def forward(self, input_ids, attention_mask):
28
- outputs = self.encoder(input_ids=input_ids, attention_mask=attention_mask)
29
- pooled = outputs.last_hidden_state[:, 0]
30
- logits = self.classifier(pooled)
31
- return logits
32
-
33
  # Load model and tokenizer
34
- try:
35
- model_name = "HabibaElbehairy/codebert-multitask-similarity"
36
- tokenizer = AutoTokenizer.from_pretrained(model_name)
37
-
38
- # Get the config to extract num_labels
39
- config = AutoConfig.from_pretrained(model_name)
40
- num_labels = getattr(config, "num_labels", 3) # Default to 3 if not found
41
-
42
- # Initialize the custom model
43
- model = MultitaskCodeSimilarityModel(model_name, num_labels=num_labels, tokenizer=tokenizer)
44
-
45
- # Load the weights - try different paths
46
- try:
47
- # Try to load from hub path
48
- model.load_state_dict(torch.load(os.path.join(model_name, "pytorch_model.bin"), map_location="cpu"))
49
- except:
50
- try:
51
- # Try local path relative to file
52
- model_weights_path = os.path.join(os.path.dirname(__file__), "pytorch_model.bin")
53
- if os.path.exists(model_weights_path):
54
- model.load_state_dict(torch.load(model_weights_path, map_location="cpu"))
55
- except Exception as e:
56
- print(f"Error loading weights: {e}")
57
- # Try to use hub's model directly as fallback
58
- model = AutoModelForSequenceClassification.from_pretrained(model_name)
59
-
60
- device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
61
- model.to(device)
62
- model.eval()
63
- print(f"Model loaded successfully and running on {device}")
64
-
65
- # Load label mapping or use default
66
- # Default mapping - 1-indexed (adjust based on your trained model)
67
- label_to_class = {1: "Duplicate", 2: "Redundant", 3: "Distinct"}
68
-
69
- except Exception as e:
70
- print(f"Error during model initialization: {e}")
71
- # Create a dummy model for API documentation/testing
72
- tokenizer = None
73
- model = None
74
- label_to_class = {1: "Duplicate", 2: "Redundant", 3: "Distinct"}
75
 
76
  # Input schema definitions
77
  class SourceCode(BaseModel):
78
  class_name: str
79
  code: str
80
-
81
  class TestCase(BaseModel):
82
  id: str
83
  test_fixture: str
@@ -85,74 +29,54 @@ class TestCase(BaseModel):
85
  code: str
86
  target_class: str
87
  target_method: List[str]
88
-
89
  class SimilarityInput(BaseModel):
90
  pair_id: str
91
  source_code: SourceCode
92
  test_case_1: TestCase
93
  test_case_2: TestCase
94
-
95
- @app.get("/health")
96
- async def health_check():
97
- """Check if the API is up and running."""
98
- return {"status": "healthy", "model": "CodeBERT Multitask Similarity", "timestamp": "2025-04-21 20:08:44"}
99
 
100
  @app.post("/predict")
101
  async def predict(data: SimilarityInput):
102
  """
103
  Predict similarity class between two test cases for a given source class.
104
  """
105
- if model is None:
106
- raise HTTPException(status_code=500, detail="Model not loaded correctly")
107
-
108
- try:
109
- # Format input to match training format
110
- combined_input = (
111
- f"SOURCE CODE: {data.source_code.code}\n"
112
- f"TEST 1: {data.test_case_1.code}\n"
113
- f"TEST 2: {data.test_case_2.code}"
114
- )
115
 
116
- # Tokenize input
117
- inputs = tokenizer(combined_input, return_tensors="pt", padding=True, truncation=True, max_length=512).to(device)
118
 
119
- # Get prediction from the model
120
- with torch.no_grad():
121
- # Check if using custom model or fallback
122
- if hasattr(model, 'forward'):
123
- # Our custom model
124
- logits = model(
125
- input_ids=inputs["input_ids"],
126
- attention_mask=inputs["attention_mask"]
127
- )
128
- else:
129
- # Fallback to standard model
130
- outputs = model(**inputs)
131
- logits = outputs.logits
132
 
133
- # Process results
134
- probs = torch.softmax(logits, dim=-1)[0].cpu().tolist()
135
- prediction = torch.argmax(logits, dim=-1).item()
136
-
137
- # Map prediction to class name
138
- classification = label_to_class.get(prediction, "Unknown")
139
-
140
- return {
141
- "pair_id": data.pair_id,
142
- "test_case_1_name": data.test_case_1.name,
143
- "test_case_2_name": data.test_case_2.name,
144
- "similarity": {
145
- "score": prediction,
146
- "classification": classification,
147
- },
148
- "probabilities": probs
149
- }
150
-
151
- except Exception as e:
152
- import traceback
153
- print(traceback.format_exc())
154
- raise HTTPException(status_code=500, detail=f"Prediction error: {str(e)}")
155
 
156
  # This allows the app to run locally or in HF Spaces
157
  if __name__ == "__main__":
158
- uvicorn.run(app, host="0.0.0.0", port=7860)
 
 
1
+ from fastapi import FastAPI
2
  from pydantic import BaseModel
3
+ from transformers import AutoModelForSequenceClassification, AutoTokenizer
4
+ from typing import Dict, List
 
 
 
5
  import uvicorn
6
+ import torch
7
 
8
  app = FastAPI(
9
  title="CodeBERT Multitask Similarity API",
 
11
  version="1.0.0"
12
  )
13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  # Load model and tokenizer
15
+ model_name = "HabibaElbehairy/codebert-multitask-similarity"
16
+ tokenizer = AutoTokenizer.from_pretrained(model_name)
17
+ model = AutoModelForSequenceClassification.from_pretrained(model_name)
18
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
19
+ model.to(device)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
 
21
  # Input schema definitions
22
  class SourceCode(BaseModel):
23
  class_name: str
24
  code: str
 
25
  class TestCase(BaseModel):
26
  id: str
27
  test_fixture: str
 
29
  code: str
30
  target_class: str
31
  target_method: List[str]
 
32
  class SimilarityInput(BaseModel):
33
  pair_id: str
34
  source_code: SourceCode
35
  test_case_1: TestCase
36
  test_case_2: TestCase
37
+
 
 
 
 
38
 
39
  @app.post("/predict")
40
  async def predict(data: SimilarityInput):
41
  """
42
  Predict similarity class between two test cases for a given source class.
43
  """
44
+ combined_input = (
45
+ f"[SOURCE CLASS]: {data.source_code.class_name}\n"
46
+ f"[SOURCE CODE]: {data.source_code.code}\n"
47
+ f"[TEST 1]: {data.test_case_1.code}\n"
48
+ f"[TEST 2]: {data.test_case_2.code}"
49
+ )
 
 
 
 
50
 
51
+ inputs = tokenizer(combined_input, return_tensors="pt", padding=True, truncation=True).to(device)
 
52
 
53
+ with torch.no_grad():
54
+ outputs = model(**inputs)
 
 
 
 
 
 
 
 
 
 
 
55
 
56
+ probs = torch.softmax(outputs.logits, dim=-1)
57
+ score = torch.argmax(probs, dim=-1).item()
58
+
59
+ label_map = {
60
+ 1: ("Duplicate", "Tests cover the same logic with similar inputs."),
61
+ 2: ("Redundant", "Tests validate similar behavior but with slightly varied input."),
62
+ 3: ("Distinct", "Tests verify opposite ends of battery status spectrum through different charge levels.")
63
+ }
64
+
65
+ label, explanation = label_map[score]
66
+
67
+ return {
68
+ "pair_id": data.pair_id,
69
+ "test_case_1_name": data.test_case_1.name,
70
+ "test_case_2_name": data.test_case_2.name,
71
+ "similarity": {
72
+ "score": score,
73
+ "classification": label,
74
+ "explanation": explanation
75
+ },
76
+ "probabilities": probs[0].tolist()
77
+ }
78
 
79
  # This allows the app to run locally or in HF Spaces
80
  if __name__ == "__main__":
81
+
82
+ uvicorn.run(app, host="0.0.0.0", port=7860)