devusman commited on
Commit
42693f7
·
1 Parent(s): 0da9a81

let deploy

Browse files
Files changed (3) hide show
  1. Dockerfile +16 -0
  2. app.py +147 -0
  3. requirements.txt +3 -0
Dockerfile ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Read the doc: https://huggingface.co/docs/hub/spaces-sdks-docker
2
+ # you will also find guides on how best to write your Dockerfile
3
+
4
+ FROM python:3.9
5
+
6
+ RUN useradd -m -u 1000 user
7
+ USER user
8
+ ENV PATH="/home/user/.local/bin:$PATH"
9
+
10
+ WORKDIR /app
11
+
12
+ COPY --chown=user ./requirements.txt requirements.txt
13
+ RUN pip install --no-cache-dir --upgrade -r requirements.txt
14
+
15
+ COPY --chown=user . /app
16
+ CMD ["gunicorn","-b","0.0.0.0:7860", "app:app"]
app.py ADDED
@@ -0,0 +1,147 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app.py
2
+
3
+ import os
4
+ from flask import Flask, request, jsonify
5
+ from flask_cors import CORS
6
+ import spacy
7
+
8
+ # --- CORRECTED MODEL LOADING SECTION ---
9
+ # This path points to the 'it_core_news_pruned' directory
10
+ # located in the same folder as this 'app.py' script.
11
+ try:
12
+ # Get the absolute path to the directory containing this script
13
+ base_dir = os.path.dirname(os.path.abspath(__file__))
14
+ # Join it with the name of our model directory
15
+ model_path = os.path.join(base_dir, 'it_core_news_pruned')
16
+ # Load the model from the specified path
17
+ nlp = spacy.load(model_path)
18
+ except Exception as e:
19
+ # This provides a more detailed error if loading fails
20
+ raise RuntimeError(f"Error loading spaCy model from {model_path}: {e}")
21
+ # --- END SECTION ---
22
+
23
+ # Initialize the Flask app
24
+ app = Flask(__name__)
25
+ # Enable Cross-Origin Resource Sharing (CORS) to allow your frontend to call this API
26
+ CORS(app)
27
+
28
+ # A mapping from spaCy dependency labels to our logical analysis labels
29
+ DEP_MAP = {
30
+ "nsubj": "Soggetto",
31
+ "ROOT": "Predicato Verbale",
32
+ "obj": "Complemento Oggetto",
33
+ "iobj": "Complemento di Termine",
34
+ "obl": "Complemento Indiretto",
35
+ "nmod": "Complemento di Specificazione",
36
+ "amod": "Attributo",
37
+ "advmod": "Complemento Avverbiale",
38
+ "appos": "Apposizione",
39
+ "cop": "Copula (parte del Predicato Nominale)",
40
+ "aux": "Ausiliare (parte del Predicato)",
41
+ "case": "Preposizione (introduce un complemento)"
42
+ }
43
+
44
+ def get_complement_type(token):
45
+ """Refine the complement type based on the preceding preposition."""
46
+ preposition = ""
47
+ # Look for a preposition attached to this token
48
+ for child in token.children:
49
+ if child.dep_ == "case":
50
+ preposition = child.text.lower()
51
+ break
52
+
53
+ # If no preposition found, check if the token's head has one (for multi-word complements)
54
+ if not preposition:
55
+ if token.head.dep_ == 'obl':
56
+ for child in token.head.children:
57
+ if child.dep_ == "case":
58
+ preposition = child.text.lower()
59
+ break
60
+
61
+ if preposition in ["di", "del", "dello", "della", "dei", "degli", "delle"]:
62
+ return "Complemento di Specificazione"
63
+ if preposition in ["a", "al", "allo", "alla", "ai", "agli", "alle"]:
64
+ return "Complemento di Termine"
65
+ if preposition in ["da", "dal", "dallo", "dalla", "dai", "dagli", "dalle"]:
66
+ return "Complemento (introdotto da 'da')"
67
+ if preposition in ["in", "nel", "nello", "nella", "nei", "negli", "nelle"]:
68
+ return "Complemento di Luogo/Tempo"
69
+ if preposition in ["con", "col", "coi"]:
70
+ return "Complemento di Compagnia/Mezzo"
71
+ if preposition in ["su", "sul", "sullo", "sulla", "sui", "sugli", "sulle"]:
72
+ return "Complemento di Argomento/Luogo"
73
+ if preposition in ["per"]:
74
+ return "Complemento di Fine/Causa"
75
+ if preposition in ["tra", "fra"]:
76
+ return "Complemento di Luogo/Tempo (Partitivo)"
77
+
78
+ return "Complemento Indiretto"
79
+
80
+ @app.route("/")
81
+ def home():
82
+ return jsonify({"message": "API is running. Use the /api/analyze endpoint."})
83
+
84
+ @app.route('/api/analyze', methods=['POST'])
85
+ def analyze_sentence():
86
+ try:
87
+ data = request.get_json()
88
+ if not data or 'sentence' not in data:
89
+ return jsonify({"error": "Sentence not provided"}), 400
90
+
91
+ sentence = data['sentence']
92
+ doc = nlp(sentence)
93
+
94
+ # This token-based analysis logic is more robust
95
+ analysis = []
96
+ for token in doc:
97
+ if token.is_punct or token.dep_ in ['case', 'det', 'aux', 'mark']:
98
+ continue
99
+
100
+ # Determine the label for the token
101
+ dep = token.dep_
102
+ label = ""
103
+
104
+ if dep == "ROOT":
105
+ # Check for nominal predicate (e.g., "è bello")
106
+ is_nominal = any(c.dep_ == 'cop' for c in token.children)
107
+ label = "Predicato Nominale" if is_nominal else "Predicato Verbale"
108
+ elif dep == 'obl':
109
+ label = get_complement_type(token)
110
+ else:
111
+ label = DEP_MAP.get(dep)
112
+
113
+ if label:
114
+ analysis.append({ "text": token.text, "label": label, "head": token.head.text })
115
+
116
+ # Simple merging logic
117
+ if not analysis:
118
+ return jsonify([])
119
+
120
+ final_analysis = []
121
+ current_phrase = analysis[0]
122
+
123
+ for i in range(1, len(analysis)):
124
+ # If the current token belongs to the same phrase (same head and label), merge them
125
+ if analysis[i]['label'] == current_phrase['label'] and analysis[i]['head'] == current_phrase['head']:
126
+ current_phrase['text'] += " " + analysis[i]['text']
127
+ else:
128
+ final_analysis.append({'text': current_phrase['text'], 'label': current_phrase['label']})
129
+ current_phrase = analysis[i]
130
+
131
+ final_analysis.append({'text': current_phrase['text'], 'label': current_phrase['label']})
132
+
133
+ return jsonify(final_analysis)
134
+
135
+ except Exception as e:
136
+ # Log the full error to the console for debugging
137
+ print(f"An error occurred: {e}")
138
+ return jsonify({"error": "An internal error occurred. See server logs for details."}), 500
139
+
140
+ # --- FIX: ADD THIS BLOCK TO BIND TO THE CORRECT HOST AND PORT ---
141
+ if __name__ == "__main__":
142
+ # The host '0.0.0.0' makes the server publicly available
143
+ # The port is dynamically read from the 'PORT' environment variable,
144
+ # with a default of 10000 for local testing.
145
+ port = int(os.environ.get('PORT', 10000))
146
+ app.run(host='0.0.0.0', port=port)
147
+ # --- END FIX ---
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ flask
2
+ spacy
3
+ Flask-Cors