232 lines
10 KiB
HTML
232 lines
10 KiB
HTML
{% extends "layouts/base.html" %}
|
|
{% load i18n %}
|
|
|
|
{% block title %}{% trans "Sentiment Analysis Results" %}{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="container-fluid">
|
|
<!-- Page Header -->
|
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
<div>
|
|
<h1 class="h3 mb-0">{% trans "Sentiment Analysis Results" %}</h1>
|
|
<p class="text-muted">{% trans "AI-powered sentiment analysis of text content" %}</p>
|
|
</div>
|
|
<div>
|
|
<a href="{% url 'ai_engine:analyze_text' %}" class="btn btn-primary">
|
|
<i class="bi bi-plus-circle"></i> {% trans "Analyze Text" %}
|
|
</a>
|
|
<a href="{% url 'ai_engine:sentiment_dashboard' %}" class="btn btn-outline-secondary">
|
|
<i class="bi bi-graph-up"></i> {% trans "Dashboard" %}
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Statistics Cards -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-3">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<h6 class="text-muted mb-2">{% trans "Total Results" %}</h6>
|
|
<h3 class="mb-0">{{ stats.total }}</h3>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card border-success">
|
|
<div class="card-body">
|
|
<h6 class="text-muted mb-2">{% trans "Positive" %}</h6>
|
|
<h3 class="mb-0 text-success">
|
|
{{ stats.positive }} <small>({{ stats.positive_pct }}%)</small>
|
|
</h3>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card border-secondary">
|
|
<div class="card-body">
|
|
<h6 class="text-muted mb-2">{% trans "Neutral" %}</h6>
|
|
<h3 class="mb-0 text-secondary">
|
|
{{ stats.neutral }} <small>({{ stats.neutral_pct }}%)</small>
|
|
</h3>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card border-danger">
|
|
<div class="card-body">
|
|
<h6 class="text-muted mb-2">{% trans "Negative" %}</h6>
|
|
<h3 class="mb-0 text-danger">
|
|
{{ stats.negative }} <small>({{ stats.negative_pct }}%)</small>
|
|
</h3>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Filters -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">{% trans "Filters" %}</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<form method="get" class="row g-3">
|
|
<div class="col-md-2">
|
|
{{ filter_form.sentiment }}
|
|
</div>
|
|
<div class="col-md-2">
|
|
{{ filter_form.language }}
|
|
</div>
|
|
<div class="col-md-2">
|
|
{{ filter_form.ai_service }}
|
|
</div>
|
|
<div class="col-md-2">
|
|
{{ filter_form.min_confidence }}
|
|
</div>
|
|
<div class="col-md-4">
|
|
{{ filter_form.search }}
|
|
</div>
|
|
<div class="col-md-2">
|
|
{{ filter_form.date_from }}
|
|
</div>
|
|
<div class="col-md-2">
|
|
{{ filter_form.date_to }}
|
|
</div>
|
|
<div class="col-md-8 text-end">
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="bi bi-funnel"></i> {% trans "Apply Filters" %}
|
|
</button>
|
|
<a href="{% url 'ai_engine:sentiment_list' %}" class="btn btn-outline-secondary">
|
|
<i class="bi bi-x-circle"></i> {% trans "Clear" %}
|
|
</a>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Results Table -->
|
|
<div class="card">
|
|
<div class="card-header d-flex justify-content-between align-items-center">
|
|
<h5 class="mb-0">{% trans "Results" %} ({{ page_obj.paginator.count }})</h5>
|
|
<div>
|
|
<select class="form-select form-select-sm" onchange="window.location.href='?page_size=' + this.value + '{% for key, value in filters.items %}{% if key != 'page_size' %}&{{ key }}={{ value }}{% endif %}{% endfor %}'">
|
|
<option value="25" {% if request.GET.page_size == '25' %}selected{% endif %}>25 per page</option>
|
|
<option value="50" {% if request.GET.page_size == '50' %}selected{% endif %}>50 per page</option>
|
|
<option value="100" {% if request.GET.page_size == '100' %}selected{% endif %}>100 per page</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="table-responsive">
|
|
<table class="table table-hover mb-0">
|
|
<thead>
|
|
<tr>
|
|
<th>{% trans "Text" %}</th>
|
|
<th>{% trans "Sentiment" %}</th>
|
|
<th>{% trans "Score" %}</th>
|
|
<th>{% trans "Confidence" %}</th>
|
|
<th>{% trans "Language" %}</th>
|
|
<th>{% trans "Related To" %}</th>
|
|
<th>{% trans "Date" %}</th>
|
|
<th>{% trans "Actions" %}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for result in results %}
|
|
<tr>
|
|
<td>
|
|
<div class="text-truncate" style="max-width: 300px;" title="{{ result.text }}">
|
|
{{ result.text }}
|
|
</div>
|
|
</td>
|
|
<td>
|
|
{% if result.sentiment == 'positive' %}
|
|
<span class="badge bg-success">😊 {% trans "Positive" %}</span>
|
|
{% elif result.sentiment == 'negative' %}
|
|
<span class="badge bg-danger">😞 {% trans "Negative" %}</span>
|
|
{% else %}
|
|
<span class="badge bg-secondary">😐 {% trans "Neutral" %}</span>
|
|
{% endif %}
|
|
</td>
|
|
<td>
|
|
<span class="badge bg-light text-dark">{{ result.sentiment_score|floatformat:2 }}</span>
|
|
</td>
|
|
<td>
|
|
<div class="progress" style="height: 20px;">
|
|
<div class="progress-bar" role="progressbar"
|
|
style="width: {{ result.confidence|floatformat:0 }}%"
|
|
aria-valuenow="{{ result.confidence|floatformat:0 }}"
|
|
aria-valuemin="0" aria-valuemax="100">
|
|
{{ result.confidence|floatformat:0 }}%
|
|
</div>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
{% if result.language == 'ar' %}
|
|
<span class="badge bg-info">العربية</span>
|
|
{% else %}
|
|
<span class="badge bg-info">English</span>
|
|
{% endif %}
|
|
</td>
|
|
<td>
|
|
{% if result.content_type %}
|
|
<small class="text-muted">{{ result.content_type.model }}</small>
|
|
{% else %}
|
|
<small class="text-muted">-</small>
|
|
{% endif %}
|
|
</td>
|
|
<td>
|
|
<small>{{ result.created_at|date:"Y-m-d H:i" }}</small>
|
|
</td>
|
|
<td>
|
|
<a href="{% url 'ai_engine:sentiment_detail' result.id %}"
|
|
class="btn btn-sm btn-outline-primary">
|
|
<i class="bi bi-eye"></i>
|
|
</a>
|
|
</td>
|
|
</tr>
|
|
{% empty %}
|
|
<tr>
|
|
<td colspan="8" class="text-center text-muted py-4">
|
|
{% trans "No sentiment results found." %}
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- Pagination -->
|
|
{% if page_obj.has_other_pages %}
|
|
<div class="card-footer">
|
|
<nav aria-label="Page navigation">
|
|
<ul class="pagination justify-content-center mb-0">
|
|
{% if page_obj.has_previous %}
|
|
<li class="page-item">
|
|
<a class="page-link" href="?page=1{% for key, value in filters.items %}{% if key != 'page' %}&{{ key }}={{ value }}{% endif %}{% endfor %}">{% trans "First" %}</a>
|
|
</li>
|
|
<li class="page-item">
|
|
<a class="page-link" href="?page={{ page_obj.previous_page_number }}{% for key, value in filters.items %}{% if key != 'page' %}&{{ key }}={{ value }}{% endif %}{% endfor %}">{% trans "Previous" %}</a>
|
|
</li>
|
|
{% endif %}
|
|
|
|
<li class="page-item active">
|
|
<span class="page-link">
|
|
{% trans "Page" %} {{ page_obj.number }} {% trans "of" %} {{ page_obj.paginator.num_pages }}
|
|
</span>
|
|
</li>
|
|
|
|
{% if page_obj.has_next %}
|
|
<li class="page-item">
|
|
<a class="page-link" href="?page={{ page_obj.next_page_number }}{% for key, value in filters.items %}{% if key != 'page' %}&{{ key }}={{ value }}{% endif %}{% endfor %}">{% trans "Next" %}</a>
|
|
</li>
|
|
<li class="page-item">
|
|
<a class="page-link" href="?page={{ page_obj.paginator.num_pages }}{% for key, value in filters.items %}{% if key != 'page' %}&{{ key }}={{ value }}{% endif %}{% endfor %}">{% trans "Last" %}</a>
|
|
</li>
|
|
{% endif %}
|
|
</ul>
|
|
</nav>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|