Ingestion data-quality + map fixes: AI salary, geocode coverage, in-place backfill & purge
- Jobs now keep the AI-extracted salary (d.PayAmount ?? parsed.PayAmount); they previously used only the parser figure, so every aggregated opening showed «توافقی». - Geocoder also scans the ad body, so Tehran ads that name a neighbourhood only in free text («… در سهروردی») get an approximate map point. - New BackfillCoordsAsync (+ admin button): fills missing coords on existing aggregated listings from their stored text, in place — no ID/URL churn, SEO-safe. - New PurgeInvalidAggregatedAsync + DedupeJobsAsync (+ admin button): in-place removal of out-of-scope (domestic/promo/spam) aggregated jobs/shifts and duplicate job reposts, keeping valid listings' IDs. - Jobs detail page always renders the location card (matches Shifts) instead of hiding it when coords are missing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -58,6 +58,24 @@
|
||||
توصیهشده برای پاکسازیِ آمادهبهکارها: متنِ خام نگه داشته میشود و فقط با منطقِ جدید (یکنفر=یکآگهی، نقش پایه، گروه ثابت، تگ تمیز، موقعیت تقریبی) بازساخته میشوند. صفحاتِ «آماده به کار» ایندکس نمیشوند، پس آدرسِ ایندکسشدهای تغییر نمیکند؛ شیفت/استخدام بهمرور با ایمیجستِ تازه پاک میشوند.
|
||||
</p>
|
||||
|
||||
<form method="post" onsubmit="return confirm('برای آگهیهای جمعآوریشدهٔ تهران که موقعیت روی نقشه ندارند، از روی متنِ آگهی محلهٔ تقریبی پیدا و مختصات تنظیم میشود. شناسه و آدرس صفحات تغییر نمیکند (امن برای SEO). ادامه؟');">
|
||||
<button type="submit" asp-page-handler="BackfillCoords" class="btn btn-primary btn-block" style="margin-top:10px;">
|
||||
📍 تکمیل موقعیتِ نقشه برای آگهیهای موجود
|
||||
</button>
|
||||
</form>
|
||||
<p class="muted" style="font-size:11px; margin:6px 0 0;">
|
||||
شیفت/استخدام/آمادهبهکارِ جمعآوریشدهای که مختصات ندارند، از روی محلهٔ ذکرشده در متنِ آگهی روی نقشه قرار میگیرند (محدودهٔ تقریبی). فقط مختصاتِ خالی پر میشود؛ موقعیتِ واقعیِ مراکز دستنخورده میماند.
|
||||
</p>
|
||||
|
||||
<form method="post" onsubmit="return confirm('آگهیهای جمعآوریشدهٔ شیفت/استخدام که اکنون خارج از حوزهاند (خدمات منزل/نظافت، تبلیغاتی/آموزشی، اسپم) و استخدامهای تکراری حذف میشوند. آگهیهای معتبر و شناسه/آدرسشان دستنخورده میماند. این کار بازگشتناپذیر است. ادامه؟');">
|
||||
<button type="submit" asp-page-handler="PurgeInvalid" class="btn btn-outline btn-block" style="margin-top:10px; color:var(--danger); border-color:var(--danger);">
|
||||
🧽 حذفِ درجای آگهیهای خارج از حوزه و تکراری (شیفت/استخدام)
|
||||
</button>
|
||||
</form>
|
||||
<p class="muted" style="font-size:11px; margin:6px 0 0;">
|
||||
فقط آگهیهایی که با صافیِ فعلی «خارج از حوزه» تشخیص داده میشوند (نه صرفاً ناقص) و استخدامهای تکراری پاک میشوند. آگهیهای معتبر دستنخوردهاند، پس آدرسِ ایندکسشدهشان تغییر نمیکند؛ فقط صفحاتِ بد ۴۰۴ میشوند.
|
||||
</p>
|
||||
|
||||
<hr style="border:none; border-top:1px solid var(--line); margin:16px 0;" />
|
||||
|
||||
<h3>افزودن دستی</h3>
|
||||
|
||||
@@ -120,6 +120,30 @@ public class IndexModel : PageModel
|
||||
return RedirectToPage();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fill missing map coordinates on existing aggregated Tehran listings from their stored ad text
|
||||
/// (TehranGeo). In place — no AI calls, no re-fetch, and crucially no delete/recreate, so indexed
|
||||
/// shift/job URLs keep their IDs. Fast (pure DB + string matching), so it runs inline.
|
||||
/// </summary>
|
||||
public async Task<IActionResult> OnPostBackfillCoordsAsync()
|
||||
{
|
||||
var n = await _ingest.BackfillCoordsAsync();
|
||||
IngestMessage = $"مختصات تقریبی برای {n} آگهی جمعآوریشده از روی متن آگهی تکمیل شد (بدون تغییر شناسه یا آدرس صفحه).";
|
||||
return RedirectToPage();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// In-place cleanup of existing aggregated jobs/shifts: delete only the out-of-scope ones
|
||||
/// (domestic-helper / promotional / spam) per the current validator, plus near-duplicate job
|
||||
/// reposts. Valid listings keep their IDs/URLs. No re-fetch, no AI — runs inline.
|
||||
/// </summary>
|
||||
public async Task<IActionResult> OnPostPurgeInvalidAsync()
|
||||
{
|
||||
var (removed, deduped) = await _ingest.PurgeInvalidAggregatedAsync();
|
||||
IngestMessage = $"پاکسازیِ درجا: {removed} آگهیِ خارج از حوزه (خدمات منزل/تبلیغاتی/اسپم) و {deduped} استخدامِ تکراری حذف شد. سایر آگهیها و شناسه/آدرسشان دستنخورده ماند.";
|
||||
return RedirectToPage();
|
||||
}
|
||||
|
||||
private async Task LoadAsync()
|
||||
{
|
||||
Queue = await _db.RawListings
|
||||
|
||||
Reference in New Issue
Block a user