Spaces:
Running
Running
Update app.js
Browse files
app.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
/* v10.
|
| 2 |
|
| 3 |
const EXPORT_COLUMNS = [
|
| 4 |
"التصنيف","نوع المشكلة","وقت حدوث المشكلة","اسم صاحب المشكلة",
|
|
@@ -16,6 +16,8 @@ const FIELD_ALIASES = {
|
|
| 16 |
"المنطقة": ["المنطقة","المنطقه","اسم المنطقة","المدينة","المحافظة","منطقة"]
|
| 17 |
};
|
| 18 |
|
|
|
|
|
|
|
| 19 |
const CLASS_RULES = {
|
| 20 |
"استفسار": ["استفسار","سؤال","استعلام","معلومة","استفسارات"],
|
| 21 |
"إضافة أجهزة": ["اضافة جهاز","إضافة أجهزة","اضافة اجهزة","تركيب جهاز","جهاز جديد","تسجيل جهاز","ربط جهاز","اضافة ماسح","إضافة ماسح"],
|
|
@@ -38,7 +40,7 @@ const CLASS_PRIORITY = [
|
|
| 38 |
];
|
| 39 |
|
| 40 |
const TICKET_SEP = /\n\s*(?:\n|—+|-{3,}|={3,}|🔴+)+\s*\n/;
|
| 41 |
-
const MIN_SPLIT_SPAN =
|
| 42 |
|
| 43 |
const arabicDigitsMap = {"٠":"0","١":"1","٢":"2","٣":"3","٤":"4","٥":"5","٦":"6","٧":"7","٨":"8","٩":"9"};
|
| 44 |
function normalizeText(s){
|
|
@@ -106,13 +108,40 @@ function findStartsByLabels(text, labels){
|
|
| 106 |
return idxs;
|
| 107 |
}
|
| 108 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 109 |
function splitTickets(raw){
|
| 110 |
const text = normalizeText(raw);
|
| 111 |
if(!text) return [];
|
| 112 |
if(TICKET_SEP.test(text)){
|
| 113 |
return text.split(TICKET_SEP).map(p=>p.trim()).filter(Boolean);
|
| 114 |
}
|
| 115 |
-
const starts = findStartsByLabels(text,
|
| 116 |
.sort((a,b)=>a-b)
|
| 117 |
.filter((pos,i,arr)=> i===0 || (pos - arr[i-1]) >= MIN_SPLIT_SPAN);
|
| 118 |
if(starts.length >= 2){
|
|
@@ -130,17 +159,6 @@ function splitTickets(raw){
|
|
| 130 |
return [text];
|
| 131 |
}
|
| 132 |
|
| 133 |
-
function findAfterLabel(text, labels){
|
| 134 |
-
const hay = "\n" + normalizeText(text) + "\n";
|
| 135 |
-
for(const rawLbl of labels){
|
| 136 |
-
const lbl = rawLbl.replace(/[.*+?^${}()|[\]\\]/g,'\\$&');
|
| 137 |
-
let m = hay.match(new RegExp(`(?:^|\\n)\\s*${lbl}\\s*[::]\\s*([^\\n]+)`, "i"));
|
| 138 |
-
if(m) return m[1].trim();
|
| 139 |
-
m = hay.match(new RegExp(`(?:^|\\n)\\s*${lbl}\\s+([^\\n]+)`, "i"));
|
| 140 |
-
if(m) return m[1].trim();
|
| 141 |
-
}
|
| 142 |
-
return "";
|
| 143 |
-
}
|
| 144 |
function extractFields(ticketText){
|
| 145 |
const text = normalizeText(ticketText);
|
| 146 |
const out = {
|
|
@@ -148,8 +166,9 @@ function extractFields(ticketText){
|
|
| 148 |
"رقم الهوية":"", "رقم الجهاز":"", "رقم الجوال":"", "المسح":"", "المنطقة":""
|
| 149 |
};
|
| 150 |
|
| 151 |
-
|
| 152 |
-
|
|
|
|
| 153 |
|
| 154 |
v = findAfterLabel(text, FIELD_ALIASES["وقت حدوث المشكلة"]);
|
| 155 |
if(v) out["وقت حدوث المشكلة"] = parseDateTime(v);
|
|
|
|
| 1 |
+
/* v10.4: Smarter splitting using all labels + multi-line "نوع المشكلة" block */
|
| 2 |
|
| 3 |
const EXPORT_COLUMNS = [
|
| 4 |
"التصنيف","نوع المشكلة","وقت حدوث المشكلة","اسم صاحب المشكلة",
|
|
|
|
| 16 |
"المنطقة": ["المنطقة","المنطقه","اسم المنطقة","المدينة","المحافظة","منطقة"]
|
| 17 |
};
|
| 18 |
|
| 19 |
+
const START_LABELS = Array.from(new Set(Object.values(FIELD_ALIASES).flat()));
|
| 20 |
+
|
| 21 |
const CLASS_RULES = {
|
| 22 |
"استفسار": ["استفسار","سؤال","استعلام","معلومة","استفسارات"],
|
| 23 |
"إضافة أجهزة": ["اضافة جهاز","إضافة أجهزة","اضافة اجهزة","تركيب جهاز","جهاز جديد","تسجيل جهاز","ربط جهاز","اضافة ماسح","إضافة ماسح"],
|
|
|
|
| 40 |
];
|
| 41 |
|
| 42 |
const TICKET_SEP = /\n\s*(?:\n|—+|-{3,}|={3,}|🔴+)+\s*\n/;
|
| 43 |
+
const MIN_SPLIT_SPAN = 40;
|
| 44 |
|
| 45 |
const arabicDigitsMap = {"٠":"0","١":"1","٢":"2","٣":"3","٤":"4","٥":"5","٦":"6","٧":"7","٨":"8","٩":"9"};
|
| 46 |
function normalizeText(s){
|
|
|
|
| 108 |
return idxs;
|
| 109 |
}
|
| 110 |
|
| 111 |
+
function findAfterLabel(text, labels){
|
| 112 |
+
const hay = "\n" + normalizeText(text) + "\n";
|
| 113 |
+
for(const rawLbl of labels){
|
| 114 |
+
const lbl = rawLbl.replace(/[.*+?^${}()|[\]\\]/g,'\\$&');
|
| 115 |
+
let m = hay.match(new RegExp(`(?:^|\\n)\\s*${lbl}\\s*[::]\\s*([^\\n]+)`, "i"));
|
| 116 |
+
if(m) return m[1].trim();
|
| 117 |
+
m = hay.match(new RegExp(`(?:^|\\n)\\s*${lbl}\\s+([^\\n]+)`, "i"));
|
| 118 |
+
if(m) return m[1].trim();
|
| 119 |
+
}
|
| 120 |
+
return "";
|
| 121 |
+
}
|
| 122 |
+
|
| 123 |
+
function findBlockAfterLabel(text, labels, allLabels = START_LABELS){
|
| 124 |
+
const hay = "\n" + normalizeText(text) + "\n";
|
| 125 |
+
const esc = s => s.replace(/[.*+?^${}()|[\]\\]/g,'\\$&');
|
| 126 |
+
|
| 127 |
+
const lblAlt = labels.map(esc).join("|");
|
| 128 |
+
const allAlt = allLabels.map(esc).join("|");
|
| 129 |
+
|
| 130 |
+
const re = new RegExp(
|
| 131 |
+
`(?:^|\\n)\\s*(?:${lblAlt})\\s*(?::|:|\\s)\\s*([\\s\\S]*?)(?=\\n\\s*(?:${allAlt})\\s*(?::|:|\\s)|$)`,
|
| 132 |
+
"i"
|
| 133 |
+
);
|
| 134 |
+
const m = hay.match(re);
|
| 135 |
+
return m ? m[1].trim() : "";
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
function splitTickets(raw){
|
| 139 |
const text = normalizeText(raw);
|
| 140 |
if(!text) return [];
|
| 141 |
if(TICKET_SEP.test(text)){
|
| 142 |
return text.split(TICKET_SEP).map(p=>p.trim()).filter(Boolean);
|
| 143 |
}
|
| 144 |
+
const starts = findStartsByLabels(text, START_LABELS)
|
| 145 |
.sort((a,b)=>a-b)
|
| 146 |
.filter((pos,i,arr)=> i===0 || (pos - arr[i-1]) >= MIN_SPLIT_SPAN);
|
| 147 |
if(starts.length >= 2){
|
|
|
|
| 159 |
return [text];
|
| 160 |
}
|
| 161 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 162 |
function extractFields(ticketText){
|
| 163 |
const text = normalizeText(ticketText);
|
| 164 |
const out = {
|
|
|
|
| 166 |
"رقم الهوية":"", "رقم الجهاز":"", "رقم الجوال":"", "المسح":"", "المنطقة":""
|
| 167 |
};
|
| 168 |
|
| 169 |
+
// نوع المشكلة: التقط بلوك متعدد الأسطر حتى أقرب ليبل تالٍ
|
| 170 |
+
let v = findBlockAfterLabel(text, FIELD_ALIASES["نوع المشكلة"], START_LABELS);
|
| 171 |
+
if(v) out["نوع المشكلة"] = normalizeText(v);
|
| 172 |
|
| 173 |
v = findAfterLabel(text, FIELD_ALIASES["وقت حدوث المشكلة"]);
|
| 174 |
if(v) out["وقت حدوث المشكلة"] = parseDateTime(v);
|