Mazenbs commited on
Commit
69715cb
·
verified ·
1 Parent(s): 686e415

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +49 -141
app.py CHANGED
@@ -9,11 +9,18 @@ from parser.assembler import parse_law_from_texts
9
  app = FastAPI(
10
  title="Text Extractor API",
11
  description="API لاستخراج النصوص من صفحات الويب مع إمكانية التحكم في النطاقات",
12
- version="2.0.0"
13
  )
14
 
 
 
 
15
  class URLRequest(BaseModel):
16
  url: HttpUrl
 
 
 
 
17
  timeout: int = Field(default=10, ge=1, le=60)
18
  ranges: Optional[List[List[int]]] = Field(
19
  default=None,
@@ -27,198 +34,99 @@ class CountResponse(BaseModel):
27
  total_texts: int
28
  url: str
29
 
30
- # new response model for parsed legal documents
31
  class LegalDocumentResponse(BaseModel):
32
- raw_texts: List[TextResponse]
33
- parsed_document: Dict[str, Any]
34
 
 
 
 
35
  def validate_ranges(ranges: List[List[int]]) -> List[Tuple[int, int]]:
36
- """
37
- التحقق من صحة النطاقات وتحويلها للتنسيق المطلوب
38
-
39
- Args:
40
- ranges: النطاقات في شكل [[start, end], ...]
41
-
42
- Returns:
43
- النطاقات المحولة [(start, end), ...]
44
-
45
- Raises:
46
- HTTPException: في حالة وجود نطاق غير صحيح
47
- """
48
  validated_ranges = []
49
-
50
  for i, range_pair in enumerate(ranges):
51
  if len(range_pair) != 2:
52
  raise HTTPException(
53
  status_code=400,
54
  detail=f"النطاق رقم {i+1} غير صحيح. كل نطاق يجب أن يحتوي على عنصرين: [start, end]"
55
  )
56
-
57
  start, end = range_pair
58
-
59
  if not isinstance(start, int) or not isinstance(end, int):
60
  raise HTTPException(
61
  status_code=400,
62
  detail=f"النطاق رقم {i+1} غير صحيح. القيم يجب أن تكون أرقام صحيحة"
63
  )
64
-
65
- if start < 0:
66
- raise HTTPException(
67
- status_code=400,
68
- detail=f"النطاق رقم {i+1} غير صحيح. البداية يجب أن تكون >= 0"
69
- )
70
-
71
- if end <= start:
72
  raise HTTPException(
73
  status_code=400,
74
- detail=f"النطاق رقم {i+1} غير صحيح. النهاية يجب أن تكون أكبر من البداية"
75
  )
76
-
77
  validated_ranges.append((start, end))
78
-
79
  return validated_ranges
80
 
 
 
 
81
  @app.post("/extract", response_model=LegalDocumentResponse)
82
  async def extract_text_endpoint(request: URLRequest):
83
  """
84
  استخراج النصوص من رابط صفحة ويب مع إمكانية تحديد النطاقات
85
- ثم تحليلها كمستند قانوني
86
-
87
- Examples:
88
- - استخراج الكل: {"url": "https://example.com"}
89
- - استخراج نطاقات محددة: {"url": "https://example.com", "ranges": [[0, 10], [20, 30]]}
90
  """
91
  try:
92
- # استخراج جميع النصوص أولاً باستخدام المستخرج الأصلي
93
  all_texts = extract_text_from_url(str(request.url), request.timeout)
94
 
95
- # إذا لم يتم تحديد نطاقات، استخدام جميع النصوص
96
- if not request.ranges:
97
- filtered_texts = all_texts
98
- else:
99
- # التحقق من صحة النطاقات
100
  validated_ranges = validate_ranges(request.ranges)
101
- # تطبيق فلترة النطاقات باستخدام output_clipper
102
  filtered_texts = clip_by_ranges(all_texts, validated_ranges)
 
 
103
 
104
- # هنا يتم إرسال filtered_texts إلى المحلل القانوني
105
- parsed_document = parse_law_from_texts(filtered_texts)
 
 
 
 
106
 
107
- return LegalDocumentResponse(
108
- raw_texts=filtered_texts,
109
- parsed_document=parsed_document
110
- )
111
 
112
  except requests.RequestException as e:
113
- raise HTTPException(
114
- status_code=400,
115
- detail=f"خطأ في جلب الصفحة: {str(e)}"
116
- )
117
  except HTTPException:
118
- # إعادة إثارة أخطاء HTTP كما هي
119
  raise
120
  except Exception as e:
121
- raise HTTPException(
122
- status_code=500,
123
- detail=f"خطأ في معالجة المحتوى: {str(e)}"
124
- )
125
 
 
 
 
126
  @app.post("/text-count", response_model=CountResponse)
127
  async def get_text_count_endpoint(request: URLRequest):
128
- """
129
- الحصول على عدد النصوص الكلي في الصفحة
130
- مفيد لمعرفة النطاقات المتاحة قبل الاستخراج
131
- """
132
  try:
133
- # استخراج جميع النصوص للحصول على العدد
134
  all_texts = extract_text_from_url(str(request.url), request.timeout)
135
- count = len(all_texts)
136
-
137
- return CountResponse(total_texts=count, url=str(request.url))
138
-
139
  except requests.RequestException as e:
140
- raise HTTPException(
141
- status_code=400,
142
- detail=f"خطأ في جلب الصفحة: {str(e)}"
143
- )
144
  except Exception as e:
145
- raise HTTPException(
146
- status_code=500,
147
- detail=f"خطأ في معالجة المحتوى: {str(e)}"
148
- )
149
 
 
 
 
150
  @app.get("/")
151
  async def root():
152
- return {
153
- "message": "Text Extractor API with Legal Parser v2.0 is running! 🔥⚖️",
154
- "endpoints": {
155
- "extract": "/extract (POST) - استخراج وتحليل النصوص القانونية",
156
- "text_count": "/text-count (POST)",
157
- "docs": "/docs",
158
- "health": "/health"
159
- },
160
- "features": [
161
- "استخراج جميع النصوص من صفحات الويب",
162
- "استخراج نطاقات محددة",
163
- "تحليل المستندات القانونية تلقائياً",
164
- "تقسيم النصوص إلى (عنوان، مقدمة، أقسام، مواد)",
165
- "عد النصوص الكلي",
166
- "فلترة متقدمة للمخرجات",
167
- "معالجة النصوص العربية والإنجليزية"
168
- ],
169
- "response_structure": {
170
- "raw_texts": "النصوص المستخرجة الخام",
171
- "parsed_document": {
172
- "title": "العنوان الرئيسي",
173
- "preamble": "مقدمة القانون",
174
- "sections": [
175
- {
176
- "title": "الباب/الفصل",
177
- "articles": [
178
- {
179
- "title": "مادة رقم X",
180
- "content": "محتوى المادة"
181
- }
182
- ]
183
- }
184
- ]
185
- }
186
- },
187
- "example_requests": {
188
- "extract_all": {
189
- "url": "https://legal-site.com/constitution"
190
- },
191
- "extract_ranges": {
192
- "url": "https://legal-site.com/law",
193
- "ranges": [[0, 10], [50, 100]]
194
- },
195
- "get_count": {
196
- "url": "https://example.com",
197
- "timeout": 15
198
- }
199
- }
200
- }
201
 
 
 
 
202
  @app.get("/health")
203
  async def health_check():
204
- return {
205
- "status": "healthy",
206
- "version": "2.0.0",
207
- "modules": [
208
- "text_extractor",
209
- "output_clipper",
210
- "parser.assembler (legal document parser)",
211
- "fastapi"
212
- ],
213
- "legal_features": [
214
- "automatic title extraction",
215
- "preamble detection",
216
- "section parsing (الباب/الفصل)",
217
- "article extraction (مادة)",
218
- "structured legal document output"
219
- ]
220
- }
221
 
222
  if __name__ == "__main__":
223
  import uvicorn
224
- uvicorn.run(app, host="0.0.0.0", port=8000, reload=True)
 
9
  app = FastAPI(
10
  title="Text Extractor API",
11
  description="API لاستخراج النصوص من صفحات الويب مع إمكانية التحكم في النطاقات",
12
+ version="2.1.0"
13
  )
14
 
15
+ # -----------------------------
16
+ # نماذج البيانات
17
+ # -----------------------------
18
  class URLRequest(BaseModel):
19
  url: HttpUrl
20
+ return_parsed: bool = Field(
21
+ default=False,
22
+ description="إذا True → إرجاع المستند القانوني المحلل، إذا False → إرجاع النصوص الخام"
23
+ )
24
  timeout: int = Field(default=10, ge=1, le=60)
25
  ranges: Optional[List[List[int]]] = Field(
26
  default=None,
 
34
  total_texts: int
35
  url: str
36
 
 
37
  class LegalDocumentResponse(BaseModel):
38
+ raw_texts: Optional[List[TextResponse]] = None
39
+ parsed_document: Optional[Dict[str, Any]] = None
40
 
41
+ # -----------------------------
42
+ # التحقق من صحة النطاقات
43
+ # -----------------------------
44
  def validate_ranges(ranges: List[List[int]]) -> List[Tuple[int, int]]:
 
 
 
 
 
 
 
 
 
 
 
 
45
  validated_ranges = []
 
46
  for i, range_pair in enumerate(ranges):
47
  if len(range_pair) != 2:
48
  raise HTTPException(
49
  status_code=400,
50
  detail=f"النطاق رقم {i+1} غير صحيح. كل نطاق يجب أن يحتوي على عنصرين: [start, end]"
51
  )
 
52
  start, end = range_pair
 
53
  if not isinstance(start, int) or not isinstance(end, int):
54
  raise HTTPException(
55
  status_code=400,
56
  detail=f"النطاق رقم {i+1} غير صحيح. القيم يجب أن تكون أرقام صحيحة"
57
  )
58
+ if start < 0 or end <= start:
 
 
 
 
 
 
 
59
  raise HTTPException(
60
  status_code=400,
61
+ detail=f"النطاق رقم {i+1} غير صحيح. النهاية يجب أن تكون أكبر من البداية والبداية >= 0"
62
  )
 
63
  validated_ranges.append((start, end))
 
64
  return validated_ranges
65
 
66
+ # -----------------------------
67
+ # نقطة النهاية لاستخراج النصوص / القانون
68
+ # -----------------------------
69
  @app.post("/extract", response_model=LegalDocumentResponse)
70
  async def extract_text_endpoint(request: URLRequest):
71
  """
72
  استخراج النصوص من رابط صفحة ويب مع إمكانية تحديد النطاقات
73
+ ثم إرجاع النصوص الخام أو المستند القانوني المحلل بناء على return_parsed
 
 
 
 
74
  """
75
  try:
76
+ # 1) استخراج جميع النصوص
77
  all_texts = extract_text_from_url(str(request.url), request.timeout)
78
 
79
+ # 2) تطبيق النطاقات إذا وجدت
80
+ if request.ranges:
 
 
 
81
  validated_ranges = validate_ranges(request.ranges)
 
82
  filtered_texts = clip_by_ranges(all_texts, validated_ranges)
83
+ else:
84
+ filtered_texts = all_texts
85
 
86
+ # 3) إذا طلب تحليل القانون
87
+ if request.return_parsed:
88
+ # تحويل TextResponse إلى str إذا لزم الأمر
89
+ texts_as_str = [t.text if isinstance(t, TextResponse) else t for t in filtered_texts]
90
+ parsed_document = parse_law_from_texts(texts_as_str)
91
+ return LegalDocumentResponse(parsed_document=parsed_document)
92
 
93
+ # 4) خلاف ذلك: إرجاع النصوص الخام
94
+ return LegalDocumentResponse(raw_texts=filtered_texts)
 
 
95
 
96
  except requests.RequestException as e:
97
+ raise HTTPException(status_code=400, detail=f"خطأ في جلب الصفحة: {str(e)}")
 
 
 
98
  except HTTPException:
 
99
  raise
100
  except Exception as e:
101
+ raise HTTPException(status_code=500, detail=f"خطأ في معالجة المحتوى: {str(e)}")
 
 
 
102
 
103
+ # -----------------------------
104
+ # نقطة النهاية لعدد النصوص
105
+ # -----------------------------
106
  @app.post("/text-count", response_model=CountResponse)
107
  async def get_text_count_endpoint(request: URLRequest):
 
 
 
 
108
  try:
 
109
  all_texts = extract_text_from_url(str(request.url), request.timeout)
110
+ return CountResponse(total_texts=len(all_texts), url=str(request.url))
 
 
 
111
  except requests.RequestException as e:
112
+ raise HTTPException(status_code=400, detail=f"خطأ في جلب الصفحة: {str(e)}")
 
 
 
113
  except Exception as e:
114
+ raise HTTPException(status_code=500, detail=f"خطأ في معالجة المحتوى: {str(e)}")
 
 
 
115
 
116
+ # -----------------------------
117
+ # صفحة البداية
118
+ # -----------------------------
119
  @app.get("/")
120
  async def root():
121
+ return {"message": "Text Extractor API v2.1 with optional legal parsing is running! ⚖️"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
 
123
+ # -----------------------------
124
+ # health check
125
+ # -----------------------------
126
  @app.get("/health")
127
  async def health_check():
128
+ return {"status": "healthy", "version": "2.1.0"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129
 
130
  if __name__ == "__main__":
131
  import uvicorn
132
+ uvicorn.run(app, host="0.0.0.0", port=8000, reload=True)