Spaces:
Sleeping
Sleeping
Commit Β·
b02f039
1
Parent(s): 0ce5100
ueifu
Browse files
app.py
CHANGED
|
@@ -16,7 +16,10 @@ import requests
|
|
| 16 |
from typing import List, Dict
|
| 17 |
import time
|
| 18 |
from functools import wraps
|
| 19 |
-
|
|
|
|
|
|
|
|
|
|
| 20 |
from rag_utils import get_comprehensive_context, format_context_for_prompt
|
| 21 |
|
| 22 |
try:
|
|
@@ -1846,6 +1849,27 @@ def index():
|
|
| 1846 |
<h3><span class="method">GET</span> <code>/history</code> - View Request History</h3>
|
| 1847 |
<p>Browse all QC requests with preview and download options.</p>
|
| 1848 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1849 |
</div>
|
| 1850 |
</body>
|
| 1851 |
</html>
|
|
@@ -2699,20 +2723,24 @@ INSTRUCTIONS:
|
|
| 2699 |
traceback.print_exc()
|
| 2700 |
return jsonify({"error": str(e)}), 500
|
| 2701 |
|
|
|
|
|
|
|
| 2702 |
@app.route("/history", methods=["GET"])
|
| 2703 |
def view_history():
|
| 2704 |
-
"""history view with additional metadata"""
|
| 2705 |
if request.headers.get('Accept') == 'application/json' or request.args.get('format') == 'json':
|
| 2706 |
try:
|
| 2707 |
con = sql.connect("swift_check.db")
|
| 2708 |
cur = con.cursor()
|
| 2709 |
|
| 2710 |
-
# query with parameter counts
|
| 2711 |
cur.execute("""
|
| 2712 |
SELECT r.id, r.doc_type, r.product_name, r.supplier_name, r.created_at,
|
| 2713 |
-
COUNT(p.id) as parameter_count
|
|
|
|
| 2714 |
FROM qc_requests r
|
| 2715 |
LEFT JOIN parameters p ON r.id = p.request_id
|
|
|
|
| 2716 |
GROUP BY r.id
|
| 2717 |
ORDER BY r.created_at DESC
|
| 2718 |
""")
|
|
@@ -2726,7 +2754,10 @@ def view_history():
|
|
| 2726 |
"product_name": row[2],
|
| 2727 |
"supplier_name": row[3],
|
| 2728 |
"created_at": row[4],
|
| 2729 |
-
"parameter_count": row[5]
|
|
|
|
|
|
|
|
|
|
| 2730 |
} for row in rows])
|
| 2731 |
|
| 2732 |
except Exception as e:
|
|
@@ -2739,9 +2770,11 @@ def view_history():
|
|
| 2739 |
|
| 2740 |
cur.execute("""
|
| 2741 |
SELECT r.id, r.doc_type, r.product_name, r.supplier_name, r.created_at,
|
| 2742 |
-
COUNT(p.id) as parameter_count
|
|
|
|
| 2743 |
FROM qc_requests r
|
| 2744 |
LEFT JOIN parameters p ON r.id = p.request_id
|
|
|
|
| 2745 |
GROUP BY r.id
|
| 2746 |
ORDER BY r.created_at DESC
|
| 2747 |
""")
|
|
@@ -2755,22 +2788,42 @@ def view_history():
|
|
| 2755 |
<title>QC Request History</title>
|
| 2756 |
<style>
|
| 2757 |
body { font-family: Arial, sans-serif; margin: 20px; background-color: #f8f9fa; }
|
| 2758 |
-
.container { max-width:
|
| 2759 |
table { border-collapse: collapse; width: 100%; margin-top: 20px; }
|
| 2760 |
th, td { border: 1px solid #ddd; padding: 12px; text-align: left; }
|
| 2761 |
th { background-color: #4CAF50; color: white; font-weight: bold; }
|
| 2762 |
tr:nth-child(even) { background-color: #f2f2f2; }
|
| 2763 |
tr:hover { background-color: #e8f5e8; }
|
| 2764 |
-
a { color: #4CAF50; text-decoration: none; margin: 0
|
| 2765 |
a:hover { background-color: #4CAF50; color: white; }
|
|
|
|
|
|
|
| 2766 |
.badge { background: #28a745; color: white; padding: 2px 6px; border-radius: 10px; font-size: 11px; }
|
| 2767 |
.param-count { font-weight: bold; color: #007bff; }
|
| 2768 |
h1 { color: #333; text-align: center; margin-bottom: 30px; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2769 |
</style>
|
| 2770 |
</head>
|
| 2771 |
<body>
|
| 2772 |
<div class="container">
|
| 2773 |
-
<h1>QC Request History </h1>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2774 |
<table>
|
| 2775 |
<tr>
|
| 2776 |
<th>ID</th>
|
|
@@ -2778,24 +2831,47 @@ def view_history():
|
|
| 2778 |
<th>Doc Type</th>
|
| 2779 |
<th>Supplier</th>
|
| 2780 |
<th>Parameters</th>
|
|
|
|
|
|
|
| 2781 |
<th>Created</th>
|
| 2782 |
<th>Actions</th>
|
| 2783 |
</tr>
|
| 2784 |
"""
|
| 2785 |
|
| 2786 |
for row in rows:
|
| 2787 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2788 |
html += f"""
|
| 2789 |
<tr>
|
| 2790 |
-
<td>{
|
| 2791 |
-
<td><strong>{
|
| 2792 |
-
<td>{
|
| 2793 |
-
<td>{
|
| 2794 |
-
<td class="param-count">{param_badge} {
|
| 2795 |
-
<td>{
|
|
|
|
|
|
|
| 2796 |
<td>
|
| 2797 |
-
<a href="/preview/{
|
| 2798 |
-
<a href="/template/{
|
|
|
|
| 2799 |
</td>
|
| 2800 |
</tr>
|
| 2801 |
"""
|
|
@@ -2806,7 +2882,8 @@ def view_history():
|
|
| 2806 |
<strong>Legend:</strong>
|
| 2807 |
π― 15+ params (Professional) |
|
| 2808 |
β οΈ 10-14 params (Good) |
|
| 2809 |
-
β <10 params (Basic)
|
|
|
|
| 2810 |
</div>
|
| 2811 |
</div>
|
| 2812 |
</body>
|
|
@@ -3126,6 +3203,140 @@ def view_logs():
|
|
| 3126 |
|
| 3127 |
except Exception as e:
|
| 3128 |
return f"<h1>Error</h1><p>{str(e)}</p>", 500
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3129 |
@app.route("/preview/<int:request_id>", methods=["GET"])
|
| 3130 |
def preview_page(request_id):
|
| 3131 |
"""preview with better formatting and metadata"""
|
|
|
|
| 16 |
from typing import List, Dict
|
| 17 |
import time
|
| 18 |
from functools import wraps
|
| 19 |
+
from flask import Flask, request, jsonify, redirect, url_for, render_template_string
|
| 20 |
+
from flask import Flask, request, jsonify, redirect, url_for, render_template_string
|
| 21 |
+
import time
|
| 22 |
+
from functools import wraps
|
| 23 |
from rag_utils import get_comprehensive_context, format_context_for_prompt
|
| 24 |
|
| 25 |
try:
|
|
|
|
| 1849 |
<h3><span class="method">GET</span> <code>/history</code> - View Request History</h3>
|
| 1850 |
<p>Browse all QC requests with preview and download options.</p>
|
| 1851 |
</div>
|
| 1852 |
+
<div class="endpoint new">
|
| 1853 |
+
<h3><span class="method">GET</span> <code>/logs</code> - API Logs Dashboard<span class="badge">NEW</span></h3>
|
| 1854 |
+
<p>Comprehensive API activity monitoring with request details, processing times, file uploads, and error tracking.</p>
|
| 1855 |
+
|
| 1856 |
+
<h4>Features:</h4>
|
| 1857 |
+
<ul>
|
| 1858 |
+
<li><strong>Request Tracking:</strong> All API calls with endpoint, method, and status</li>
|
| 1859 |
+
<li><strong>File Information:</strong> Track uploaded files (OCR documents, reference files)</li>
|
| 1860 |
+
<li><strong>Performance Metrics:</strong> Processing times and success rates</li>
|
| 1861 |
+
<li><strong>Error Monitoring:</strong> Detailed error messages and troubleshooting</li>
|
| 1862 |
+
<li><strong>Filtering:</strong> Filter by endpoint, status, or request ID</li>
|
| 1863 |
+
</ul>
|
| 1864 |
+
|
| 1865 |
+
<h4>Query Parameters:</h4>
|
| 1866 |
+
<ul>
|
| 1867 |
+
<li><code>format=json</code> - Get logs in JSON format</li>
|
| 1868 |
+
<li><code>request_id=123</code> - Filter by specific request</li>
|
| 1869 |
+
<li><code>endpoint=refine</code> - Filter by endpoint</li>
|
| 1870 |
+
<li><code>limit=100</code> - Limit number of results</li>
|
| 1871 |
+
</ul>
|
| 1872 |
+
</div>
|
| 1873 |
</div>
|
| 1874 |
</body>
|
| 1875 |
</html>
|
|
|
|
| 2723 |
traceback.print_exc()
|
| 2724 |
return jsonify({"error": str(e)}), 500
|
| 2725 |
|
| 2726 |
+
# REPLACE THE ENTIRE view_history() FUNCTION
|
| 2727 |
+
|
| 2728 |
@app.route("/history", methods=["GET"])
|
| 2729 |
def view_history():
|
| 2730 |
+
"""history view with additional metadata and logs button"""
|
| 2731 |
if request.headers.get('Accept') == 'application/json' or request.args.get('format') == 'json':
|
| 2732 |
try:
|
| 2733 |
con = sql.connect("swift_check.db")
|
| 2734 |
cur = con.cursor()
|
| 2735 |
|
| 2736 |
+
# query with parameter counts and file info from logs
|
| 2737 |
cur.execute("""
|
| 2738 |
SELECT r.id, r.doc_type, r.product_name, r.supplier_name, r.created_at,
|
| 2739 |
+
COUNT(DISTINCT p.id) as parameter_count,
|
| 2740 |
+
l.file_info, l.endpoint, l.processing_time_ms
|
| 2741 |
FROM qc_requests r
|
| 2742 |
LEFT JOIN parameters p ON r.id = p.request_id
|
| 2743 |
+
LEFT JOIN api_logs l ON r.id = l.request_id
|
| 2744 |
GROUP BY r.id
|
| 2745 |
ORDER BY r.created_at DESC
|
| 2746 |
""")
|
|
|
|
| 2754 |
"product_name": row[2],
|
| 2755 |
"supplier_name": row[3],
|
| 2756 |
"created_at": row[4],
|
| 2757 |
+
"parameter_count": row[5],
|
| 2758 |
+
"file_info": row[6],
|
| 2759 |
+
"endpoint": row[7],
|
| 2760 |
+
"processing_time_ms": row[8]
|
| 2761 |
} for row in rows])
|
| 2762 |
|
| 2763 |
except Exception as e:
|
|
|
|
| 2770 |
|
| 2771 |
cur.execute("""
|
| 2772 |
SELECT r.id, r.doc_type, r.product_name, r.supplier_name, r.created_at,
|
| 2773 |
+
COUNT(DISTINCT p.id) as parameter_count,
|
| 2774 |
+
l.file_info, l.endpoint, l.processing_time_ms, l.status_code
|
| 2775 |
FROM qc_requests r
|
| 2776 |
LEFT JOIN parameters p ON r.id = p.request_id
|
| 2777 |
+
LEFT JOIN api_logs l ON r.id = l.request_id
|
| 2778 |
GROUP BY r.id
|
| 2779 |
ORDER BY r.created_at DESC
|
| 2780 |
""")
|
|
|
|
| 2788 |
<title>QC Request History</title>
|
| 2789 |
<style>
|
| 2790 |
body { font-family: Arial, sans-serif; margin: 20px; background-color: #f8f9fa; }
|
| 2791 |
+
.container { max-width: 1600px; margin: 0 auto; background: white; padding: 30px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
|
| 2792 |
table { border-collapse: collapse; width: 100%; margin-top: 20px; }
|
| 2793 |
th, td { border: 1px solid #ddd; padding: 12px; text-align: left; }
|
| 2794 |
th { background-color: #4CAF50; color: white; font-weight: bold; }
|
| 2795 |
tr:nth-child(even) { background-color: #f2f2f2; }
|
| 2796 |
tr:hover { background-color: #e8f5e8; }
|
| 2797 |
+
a { color: #4CAF50; text-decoration: none; margin: 0 3px; padding: 4px 8px; border-radius: 3px; font-size: 11px; }
|
| 2798 |
a:hover { background-color: #4CAF50; color: white; }
|
| 2799 |
+
.logs-btn { background-color: #007bff; color: white; }
|
| 2800 |
+
.logs-btn:hover { background-color: #0056b3; }
|
| 2801 |
.badge { background: #28a745; color: white; padding: 2px 6px; border-radius: 10px; font-size: 11px; }
|
| 2802 |
.param-count { font-weight: bold; color: #007bff; }
|
| 2803 |
h1 { color: #333; text-align: center; margin-bottom: 30px; }
|
| 2804 |
+
.endpoint { padding: 2px 6px; border-radius: 8px; font-size: 10px; color: white; margin-left: 5px; }
|
| 2805 |
+
.refine { background: #28a745; }
|
| 2806 |
+
.edit { background: #ffc107; color: black; }
|
| 2807 |
+
.digitize { background: #17a2b8; }
|
| 2808 |
+
.validate { background: #6c757d; }
|
| 2809 |
+
.file-info { font-style: italic; color: #6c757d; font-size: 11px; }
|
| 2810 |
+
.processing-time { color: #007bff; font-size: 11px; }
|
| 2811 |
+
.nav-buttons { text-align: center; margin: 20px 0; }
|
| 2812 |
+
.nav-btn { background: linear-gradient(135deg, #007bff, #0056b3); color: white; padding: 12px 20px;
|
| 2813 |
+
border: none; border-radius: 6px; margin: 0 10px; text-decoration: none; display: inline-block;
|
| 2814 |
+
font-weight: bold; transition: all 0.3s ease; }
|
| 2815 |
+
.nav-btn:hover { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(0, 123, 255, 0.3); color: white; }
|
| 2816 |
</style>
|
| 2817 |
</head>
|
| 2818 |
<body>
|
| 2819 |
<div class="container">
|
| 2820 |
+
<h1>QC Request History π</h1>
|
| 2821 |
+
|
| 2822 |
+
<div class="nav-buttons">
|
| 2823 |
+
<a href="/logs" class="nav-btn">π View API Logs</a>
|
| 2824 |
+
<a href="/" class="nav-btn">π Home</a>
|
| 2825 |
+
</div>
|
| 2826 |
+
|
| 2827 |
<table>
|
| 2828 |
<tr>
|
| 2829 |
<th>ID</th>
|
|
|
|
| 2831 |
<th>Doc Type</th>
|
| 2832 |
<th>Supplier</th>
|
| 2833 |
<th>Parameters</th>
|
| 2834 |
+
<th>Endpoint Used</th>
|
| 2835 |
+
<th>File/Processing Info</th>
|
| 2836 |
<th>Created</th>
|
| 2837 |
<th>Actions</th>
|
| 2838 |
</tr>
|
| 2839 |
"""
|
| 2840 |
|
| 2841 |
for row in rows:
|
| 2842 |
+
request_id, doc_type, product_name, supplier_name, created_at, param_count, file_info, endpoint, processing_time, status_code = row
|
| 2843 |
+
|
| 2844 |
+
param_badge = "π―" if param_count >= 15 else "β οΈ" if param_count >= 10 else "β"
|
| 2845 |
+
|
| 2846 |
+
# Format endpoint
|
| 2847 |
+
endpoint_display = ""
|
| 2848 |
+
if endpoint:
|
| 2849 |
+
endpoint_clean = endpoint.replace('/', '').lower()
|
| 2850 |
+
endpoint_display = f'<span class="endpoint {endpoint_clean}">{endpoint}</span>'
|
| 2851 |
+
|
| 2852 |
+
# Format file and processing info
|
| 2853 |
+
info_display = ""
|
| 2854 |
+
if file_info:
|
| 2855 |
+
info_display += f'<div class="file-info">π {file_info}</div>'
|
| 2856 |
+
if processing_time:
|
| 2857 |
+
info_display += f'<div class="processing-time">β±οΈ {processing_time}ms</div>'
|
| 2858 |
+
if not info_display:
|
| 2859 |
+
info_display = "No file uploaded"
|
| 2860 |
+
|
| 2861 |
html += f"""
|
| 2862 |
<tr>
|
| 2863 |
+
<td>{request_id}</td>
|
| 2864 |
+
<td><strong>{product_name}</strong></td>
|
| 2865 |
+
<td>{doc_type}</td>
|
| 2866 |
+
<td>{supplier_name}</td>
|
| 2867 |
+
<td class="param-count">{param_badge} {param_count} params</td>
|
| 2868 |
+
<td>{endpoint_display}</td>
|
| 2869 |
+
<td>{info_display}</td>
|
| 2870 |
+
<td>{created_at}</td>
|
| 2871 |
<td>
|
| 2872 |
+
<a href="/preview/{request_id}">Preview</a>
|
| 2873 |
+
<a href="/template/{request_id}">JSON</a>
|
| 2874 |
+
<a href="/logs?request_id={request_id}" class="logs-btn">Logs</a>
|
| 2875 |
</td>
|
| 2876 |
</tr>
|
| 2877 |
"""
|
|
|
|
| 2882 |
<strong>Legend:</strong>
|
| 2883 |
π― 15+ params (Professional) |
|
| 2884 |
β οΈ 10-14 params (Good) |
|
| 2885 |
+
β <10 params (Basic)<br>
|
| 2886 |
+
<strong>New:</strong> π Click "Logs" to see detailed API request information for each template
|
| 2887 |
</div>
|
| 2888 |
</div>
|
| 2889 |
</body>
|
|
|
|
| 3203 |
|
| 3204 |
except Exception as e:
|
| 3205 |
return f"<h1>Error</h1><p>{str(e)}</p>", 500
|
| 3206 |
+
|
| 3207 |
+
# ADD this new endpoint after the /logs endpoint
|
| 3208 |
+
|
| 3209 |
+
@app.route("/logs/<int:log_id>", methods=["GET"])
|
| 3210 |
+
def view_detailed_log(log_id):
|
| 3211 |
+
"""View detailed information for a specific log entry"""
|
| 3212 |
+
try:
|
| 3213 |
+
con = sql.connect("swift_check.db")
|
| 3214 |
+
cur = con.cursor()
|
| 3215 |
+
|
| 3216 |
+
# Get detailed log information
|
| 3217 |
+
cur.execute("""
|
| 3218 |
+
SELECT
|
| 3219 |
+
l.*,
|
| 3220 |
+
r.doc_type, r.product_name, r.supplier_name, r.user_message,
|
| 3221 |
+
lr.llm_response, lr.summary_text
|
| 3222 |
+
FROM api_logs l
|
| 3223 |
+
LEFT JOIN qc_requests r ON l.request_id = r.id
|
| 3224 |
+
LEFT JOIN llm_responses lr ON l.request_id = lr.request_id
|
| 3225 |
+
WHERE l.id = ?
|
| 3226 |
+
""", (log_id,))
|
| 3227 |
+
|
| 3228 |
+
log_data = cur.fetchone()
|
| 3229 |
+
con.close()
|
| 3230 |
+
|
| 3231 |
+
if not log_data:
|
| 3232 |
+
return jsonify({"error": f"Log ID {log_id} not found"}), 404
|
| 3233 |
+
|
| 3234 |
+
if request.headers.get('Accept') == 'application/json' or request.args.get('format') == 'json':
|
| 3235 |
+
# Return JSON format
|
| 3236 |
+
return jsonify({
|
| 3237 |
+
"log_id": log_data[0],
|
| 3238 |
+
"request_id": log_data[1],
|
| 3239 |
+
"endpoint": log_data[2],
|
| 3240 |
+
"method": log_data[3],
|
| 3241 |
+
"client_ip": log_data[4],
|
| 3242 |
+
"user_agent": log_data[5],
|
| 3243 |
+
"request_data": log_data[6],
|
| 3244 |
+
"response_data": log_data[7],
|
| 3245 |
+
"file_info": log_data[8],
|
| 3246 |
+
"processing_time_ms": log_data[9],
|
| 3247 |
+
"status_code": log_data[10],
|
| 3248 |
+
"error_message": log_data[11],
|
| 3249 |
+
"created_at": log_data[12],
|
| 3250 |
+
"doc_type": log_data[13],
|
| 3251 |
+
"product_name": log_data[14],
|
| 3252 |
+
"supplier_name": log_data[15],
|
| 3253 |
+
"user_message": log_data[16],
|
| 3254 |
+
"llm_response_summary": log_data[18]
|
| 3255 |
+
})
|
| 3256 |
+
|
| 3257 |
+
# HTML detailed view
|
| 3258 |
+
html = f"""
|
| 3259 |
+
<html>
|
| 3260 |
+
<head>
|
| 3261 |
+
<title>Log Details - #{log_id}</title>
|
| 3262 |
+
<style>
|
| 3263 |
+
body {{ font-family: Arial, sans-serif; margin: 20px; background-color: #f8f9fa; }}
|
| 3264 |
+
.container {{ max-width: 1200px; margin: 0 auto; background: white; padding: 30px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }}
|
| 3265 |
+
.section {{ margin: 20px 0; padding: 15px; border-radius: 8px; }}
|
| 3266 |
+
.basic-info {{ background: #e8f4f8; border-left: 4px solid #007bff; }}
|
| 3267 |
+
.request-info {{ background: #f8f9fa; border-left: 4px solid #28a745; }}
|
| 3268 |
+
.response-info {{ background: #fff3cd; border-left: 4px solid #ffc107; }}
|
| 3269 |
+
.error-info {{ background: #f8d7da; border-left: 4px solid #dc3545; }}
|
| 3270 |
+
h1, h2 {{ color: #333; }}
|
| 3271 |
+
h1 {{ text-align: center; }}
|
| 3272 |
+
pre {{ background: #f8f9fa; padding: 15px; border-radius: 5px; overflow: auto; max-height: 300px; }}
|
| 3273 |
+
.status-success {{ color: #28a745; font-weight: bold; }}
|
| 3274 |
+
.status-error {{ color: #dc3545; font-weight: bold; }}
|
| 3275 |
+
.nav-btn {{ background: #007bff; color: white; padding: 10px 15px; text-decoration: none; border-radius: 5px; margin: 5px; display: inline-block; }}
|
| 3276 |
+
.nav-btn:hover {{ background: #0056b3; color: white; }}
|
| 3277 |
+
.metric {{ display: inline-block; margin: 10px 15px 10px 0; padding: 8px 12px; background: white; border-radius: 5px; border: 1px solid #ddd; }}
|
| 3278 |
+
</style>
|
| 3279 |
+
</head>
|
| 3280 |
+
<body>
|
| 3281 |
+
<div class="container">
|
| 3282 |
+
<h1>π Log Details - #{log_id}</h1>
|
| 3283 |
+
|
| 3284 |
+
<div class="nav-buttons">
|
| 3285 |
+
<a href="/logs" class="nav-btn">β¬
οΈ Back to Logs</a>
|
| 3286 |
+
<a href="/history" class="nav-btn">π Request History</a>
|
| 3287 |
+
{f'<a href="/preview/{log_data[1]}" class="nav-btn">ποΈ Preview Template</a>' if log_data[1] else ''}
|
| 3288 |
+
</div>
|
| 3289 |
+
|
| 3290 |
+
<div class="section basic-info">
|
| 3291 |
+
<h2>π Basic Information</h2>
|
| 3292 |
+
<div class="metric"><strong>Endpoint:</strong> {log_data[2]}</div>
|
| 3293 |
+
<div class="metric"><strong>Method:</strong> {log_data[3]}</div>
|
| 3294 |
+
<div class="metric"><strong>Status:</strong> <span class="{'status-success' if log_data[10] == 200 else 'status-error'}">{log_data[10]}</span></div>
|
| 3295 |
+
<div class="metric"><strong>Processing Time:</strong> {log_data[9] or 'N/A'}ms</div>
|
| 3296 |
+
<div class="metric"><strong>Created:</strong> {log_data[12]}</div>
|
| 3297 |
+
<div class="metric"><strong>Client IP:</strong> {log_data[4]}</div>
|
| 3298 |
+
</div>
|
| 3299 |
+
|
| 3300 |
+
{f'''
|
| 3301 |
+
<div class="section request-info">
|
| 3302 |
+
<h2>π Request Information</h2>
|
| 3303 |
+
<p><strong>Product:</strong> {log_data[14]}</p>
|
| 3304 |
+
<p><strong>Document Type:</strong> {log_data[13]}</p>
|
| 3305 |
+
<p><strong>Supplier:</strong> {log_data[15]}</p>
|
| 3306 |
+
{f'<p><strong>File Info:</strong> {log_data[8]}</p>' if log_data[8] else ''}
|
| 3307 |
+
{f'<div><strong>User Message:</strong><pre>{log_data[16][:500]}{"..." if log_data[16] and len(log_data[16]) > 500 else ""}</pre></div>' if log_data[16] else ''}
|
| 3308 |
+
</div>
|
| 3309 |
+
''' if log_data[1] else ''}
|
| 3310 |
+
|
| 3311 |
+
{f'''
|
| 3312 |
+
<div class="section response-info">
|
| 3313 |
+
<h2>π€ Response Information</h2>
|
| 3314 |
+
{f'<div><strong>Response Data:</strong><pre>{log_data[7]}</pre></div>' if log_data[7] else '<p>No response data available</p>'}
|
| 3315 |
+
</div>
|
| 3316 |
+
''' if log_data[7] else ''}
|
| 3317 |
+
|
| 3318 |
+
{f'''
|
| 3319 |
+
<div class="section error-info">
|
| 3320 |
+
<h2>β Error Information</h2>
|
| 3321 |
+
<p><strong>Error Message:</strong></p>
|
| 3322 |
+
<pre>{log_data[11]}</pre>
|
| 3323 |
+
</div>
|
| 3324 |
+
''' if log_data[11] else ''}
|
| 3325 |
+
|
| 3326 |
+
<div class="section">
|
| 3327 |
+
<h2>π Technical Details</h2>
|
| 3328 |
+
<p><strong>User Agent:</strong> {log_data[5] or 'Not available'}</p>
|
| 3329 |
+
{f'<div><strong>Request Data:</strong><pre>{log_data[6]}</pre></div>' if log_data[6] else '<p>No request data captured</p>'}
|
| 3330 |
+
</div>
|
| 3331 |
+
</div>
|
| 3332 |
+
</body>
|
| 3333 |
+
</html>
|
| 3334 |
+
"""
|
| 3335 |
+
|
| 3336 |
+
return html
|
| 3337 |
+
|
| 3338 |
+
except Exception as e:
|
| 3339 |
+
return f"<h1>Error</h1><p>{str(e)}</p>", 500
|
| 3340 |
@app.route("/preview/<int:request_id>", methods=["GET"])
|
| 3341 |
def preview_page(request_id):
|
| 3342 |
"""preview with better formatting and metadata"""
|