Spaces:
Sleeping
Sleeping
Commit ยท
c77c822
1
Parent(s): b02f039
ueifu
Browse files
app.py
CHANGED
|
@@ -549,6 +549,68 @@ def apply_changes_to_params(parameters, changes):
|
|
| 549 |
|
| 550 |
return parameters
|
| 551 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 552 |
def generate_json_template(doc_type, product_name, supplier_name, parameters):
|
| 553 |
"""
|
| 554 |
JSON template generation with intelligent parameter type handling.
|
|
@@ -2813,6 +2875,7 @@ def view_history():
|
|
| 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>
|
|
@@ -2941,9 +3004,12 @@ def view_logs():
|
|
| 2941 |
l.id, l.request_id, l.endpoint, l.method, l.client_ip,
|
| 2942 |
l.file_info, l.processing_time_ms, l.status_code,
|
| 2943 |
l.error_message, l.created_at,
|
| 2944 |
-
r.product_name, r.supplier_name, r.doc_type
|
|
|
|
|
|
|
| 2945 |
FROM api_logs l
|
| 2946 |
LEFT JOIN qc_requests r ON l.request_id = r.id
|
|
|
|
| 2947 |
WHERE 1=1
|
| 2948 |
"""
|
| 2949 |
params = []
|
|
@@ -2978,7 +3044,9 @@ def view_logs():
|
|
| 2978 |
"created_at": row[9],
|
| 2979 |
"product_name": row[10],
|
| 2980 |
"supplier_name": row[11],
|
| 2981 |
-
"doc_type": row[12]
|
|
|
|
|
|
|
| 2982 |
})
|
| 2983 |
|
| 2984 |
return jsonify({
|
|
@@ -3002,16 +3070,19 @@ def view_logs():
|
|
| 3002 |
|
| 3003 |
# Get logs with request details
|
| 3004 |
cur.execute("""
|
| 3005 |
-
|
| 3006 |
-
|
| 3007 |
-
|
| 3008 |
-
|
| 3009 |
-
|
| 3010 |
-
|
| 3011 |
-
|
| 3012 |
-
|
| 3013 |
-
|
| 3014 |
-
|
|
|
|
|
|
|
|
|
|
| 3015 |
|
| 3016 |
rows = cur.fetchall()
|
| 3017 |
|
|
@@ -3136,7 +3207,7 @@ def view_logs():
|
|
| 3136 |
<th>File Info</th>
|
| 3137 |
<th>Time (ms)</th>
|
| 3138 |
<th>Status</th>
|
| 3139 |
-
<th>
|
| 3140 |
<th>Error</th>
|
| 3141 |
<th>Created At</th>
|
| 3142 |
<th>Actions</th>
|
|
@@ -3144,7 +3215,7 @@ def view_logs():
|
|
| 3144 |
"""
|
| 3145 |
|
| 3146 |
for row in rows:
|
| 3147 |
-
log_id, request_id, endpoint, method, client_ip, file_info, processing_time, status_code, error_message, created_at, product_name, supplier_name, doc_type = row
|
| 3148 |
|
| 3149 |
# Style endpoint
|
| 3150 |
endpoint_class = endpoint.replace('/', '').lower()
|
|
@@ -3169,9 +3240,12 @@ def view_logs():
|
|
| 3169 |
# Format error message
|
| 3170 |
error_display = f'<span class="error-msg" title="{error_message or ""}">{(error_message or "")[:50]}{"..." if error_message and len(error_message) > 50 else ""}</span>'
|
| 3171 |
|
|
|
|
|
|
|
|
|
|
| 3172 |
html += f"""
|
| 3173 |
<tr class="log-row" data-endpoint="{endpoint}" data-status="{status_code}">
|
| 3174 |
-
<td>{log_id}</td>
|
| 3175 |
<td>{request_id or "N/A"}</td>
|
| 3176 |
<td>{endpoint_badge}</td>
|
| 3177 |
<td><strong>{product_name or "N/A"}</strong></td>
|
|
@@ -3179,11 +3253,12 @@ def view_logs():
|
|
| 3179 |
<td>{file_display}</td>
|
| 3180 |
<td>{time_text}</td>
|
| 3181 |
<td>{status_text}</td>
|
| 3182 |
-
<td>{
|
| 3183 |
<td>{error_display}</td>
|
| 3184 |
<td>{created_at}</td>
|
| 3185 |
<td>
|
| 3186 |
-
|
|
|
|
| 3187 |
</td>
|
| 3188 |
</tr>
|
| 3189 |
"""
|
|
@@ -3205,7 +3280,6 @@ def view_logs():
|
|
| 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"""
|
|
@@ -3251,10 +3325,11 @@ def view_detailed_log(log_id):
|
|
| 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 |
-
#
|
| 3258 |
html = f"""
|
| 3259 |
<html>
|
| 3260 |
<head>
|
|
@@ -3267,6 +3342,13 @@ def view_detailed_log(log_id):
|
|
| 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; }}
|
|
@@ -3275,6 +3357,8 @@ def view_detailed_log(log_id):
|
|
| 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>
|
|
@@ -3296,39 +3380,146 @@ def view_detailed_log(log_id):
|
|
| 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 |
-
|
|
|
|
|
|
|
|
|
|
| 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 |
-
|
| 3308 |
-
|
| 3309 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3310 |
|
| 3311 |
-
|
| 3312 |
-
|
| 3313 |
-
|
| 3314 |
-
|
| 3315 |
-
|
| 3316 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3317 |
|
| 3318 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
|
| 3325 |
-
|
|
|
|
|
|
|
| 3326 |
<div class="section">
|
| 3327 |
<h2>๐ Technical Details</h2>
|
| 3328 |
<p><strong>User Agent:</strong> {log_data[5] or 'Not available'}</p>
|
| 3329 |
-
|
| 3330 |
-
|
| 3331 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3332 |
</body>
|
| 3333 |
</html>
|
| 3334 |
"""
|
|
@@ -3337,6 +3528,8 @@ def view_detailed_log(log_id):
|
|
| 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"""
|
|
|
|
| 549 |
|
| 550 |
return parameters
|
| 551 |
|
| 552 |
+
def _analyze_llm_response(llm_response):
|
| 553 |
+
"""Analyze LLM response to extract key information"""
|
| 554 |
+
if not llm_response:
|
| 555 |
+
return ""
|
| 556 |
+
|
| 557 |
+
analysis_html = '<div class="json-analysis"><h4>๐ Response Analysis</h4>'
|
| 558 |
+
|
| 559 |
+
# Try to extract JSON array
|
| 560 |
+
import re
|
| 561 |
+
json_match = re.search(r'\[.*?\]', llm_response, re.DOTALL)
|
| 562 |
+
|
| 563 |
+
if json_match:
|
| 564 |
+
try:
|
| 565 |
+
import json
|
| 566 |
+
json_content = json_match.group(0)
|
| 567 |
+
parsed_json = json.loads(json_content)
|
| 568 |
+
|
| 569 |
+
if isinstance(parsed_json, list):
|
| 570 |
+
param_count = len(parsed_json)
|
| 571 |
+
analysis_html += f'<p><strong>Parameters Generated:</strong> <span class="parameter-count">{param_count}</span></p>'
|
| 572 |
+
|
| 573 |
+
# Analyze parameter types
|
| 574 |
+
param_types = {}
|
| 575 |
+
for param in parsed_json:
|
| 576 |
+
if isinstance(param, dict):
|
| 577 |
+
param_type = param.get('Type', 'Unknown')
|
| 578 |
+
param_types[param_type] = param_types.get(param_type, 0) + 1
|
| 579 |
+
|
| 580 |
+
if param_types:
|
| 581 |
+
analysis_html += '<p><strong>Parameter Types:</strong></p><ul>'
|
| 582 |
+
for ptype, count in param_types.items():
|
| 583 |
+
analysis_html += f'<li>{ptype}: {count}</li>'
|
| 584 |
+
analysis_html += '</ul>'
|
| 585 |
+
|
| 586 |
+
# Show first few parameter names
|
| 587 |
+
param_names = [p.get('Parameter', 'Unnamed') for p in parsed_json[:5] if isinstance(p, dict)]
|
| 588 |
+
if param_names:
|
| 589 |
+
analysis_html += f'<p><strong>Sample Parameters:</strong> {", ".join(param_names)}</p>'
|
| 590 |
+
if len(parsed_json) > 5:
|
| 591 |
+
analysis_html += f'<p><em>...and {len(parsed_json) - 5} more parameters</em></p>'
|
| 592 |
+
|
| 593 |
+
except json.JSONDecodeError:
|
| 594 |
+
analysis_html += '<p><span style="color: #ffc107;">โ ๏ธ JSON found but could not parse completely</span></p>'
|
| 595 |
+
else:
|
| 596 |
+
analysis_html += '<p><span style="color: #dc3545;">โ No JSON array found in response</span></p>'
|
| 597 |
+
|
| 598 |
+
# Check response length
|
| 599 |
+
response_length = len(llm_response)
|
| 600 |
+
if response_length > 10000:
|
| 601 |
+
analysis_html += f'<p><strong>Response Size:</strong> <span style="color: #ffc107;">{response_length:,} characters (Large response)</span></p>'
|
| 602 |
+
else:
|
| 603 |
+
analysis_html += f'<p><strong>Response Size:</strong> {response_length:,} characters</p>'
|
| 604 |
+
|
| 605 |
+
# Check for errors or issues
|
| 606 |
+
if 'error' in llm_response.lower() or 'failed' in llm_response.lower():
|
| 607 |
+
analysis_html += '<p><span style="color: #dc3545;">โ ๏ธ Response may contain error indicators</span></p>'
|
| 608 |
+
|
| 609 |
+
analysis_html += '</div>'
|
| 610 |
+
return analysis_html
|
| 611 |
+
|
| 612 |
+
|
| 613 |
+
|
| 614 |
def generate_json_template(doc_type, product_name, supplier_name, parameters):
|
| 615 |
"""
|
| 616 |
JSON template generation with intelligent parameter type handling.
|
|
|
|
| 2875 |
border: none; border-radius: 6px; margin: 0 10px; text-decoration: none; display: inline-block;
|
| 2876 |
font-weight: bold; transition: all 0.3s ease; }
|
| 2877 |
.nav-btn:hover { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(0, 123, 255, 0.3); color: white; }
|
| 2878 |
+
|
| 2879 |
</style>
|
| 2880 |
</head>
|
| 2881 |
<body>
|
|
|
|
| 3004 |
l.id, l.request_id, l.endpoint, l.method, l.client_ip,
|
| 3005 |
l.file_info, l.processing_time_ms, l.status_code,
|
| 3006 |
l.error_message, l.created_at,
|
| 3007 |
+
r.product_name, r.supplier_name, r.doc_type,
|
| 3008 |
+
lr.summary_text,
|
| 3009 |
+
CASE WHEN lr.llm_response IS NOT NULL THEN 'Yes' ELSE 'No' END as has_llm_response
|
| 3010 |
FROM api_logs l
|
| 3011 |
LEFT JOIN qc_requests r ON l.request_id = r.id
|
| 3012 |
+
LEFT JOIN llm_responses lr ON l.request_id = lr.request_id
|
| 3013 |
WHERE 1=1
|
| 3014 |
"""
|
| 3015 |
params = []
|
|
|
|
| 3044 |
"created_at": row[9],
|
| 3045 |
"product_name": row[10],
|
| 3046 |
"supplier_name": row[11],
|
| 3047 |
+
"doc_type": row[12],
|
| 3048 |
+
"llm_summary": row[13],
|
| 3049 |
+
"has_llm_response": row[14]
|
| 3050 |
})
|
| 3051 |
|
| 3052 |
return jsonify({
|
|
|
|
| 3070 |
|
| 3071 |
# Get logs with request details
|
| 3072 |
cur.execute("""
|
| 3073 |
+
SELECT
|
| 3074 |
+
l.id, l.request_id, l.endpoint, l.method, l.client_ip,
|
| 3075 |
+
l.file_info, l.processing_time_ms, l.status_code,
|
| 3076 |
+
l.error_message, l.created_at,
|
| 3077 |
+
r.product_name, r.supplier_name, r.doc_type,
|
| 3078 |
+
lr.summary_text,
|
| 3079 |
+
CASE WHEN lr.llm_response IS NOT NULL THEN 'Yes' ELSE 'No' END as has_llm_response
|
| 3080 |
+
FROM api_logs l
|
| 3081 |
+
LEFT JOIN qc_requests r ON l.request_id = r.id
|
| 3082 |
+
LEFT JOIN llm_responses lr ON l.request_id = lr.request_id
|
| 3083 |
+
ORDER BY l.created_at DESC
|
| 3084 |
+
LIMIT 100
|
| 3085 |
+
""")
|
| 3086 |
|
| 3087 |
rows = cur.fetchall()
|
| 3088 |
|
|
|
|
| 3207 |
<th>File Info</th>
|
| 3208 |
<th>Time (ms)</th>
|
| 3209 |
<th>Status</th>
|
| 3210 |
+
<th>LLM Used</th>
|
| 3211 |
<th>Error</th>
|
| 3212 |
<th>Created At</th>
|
| 3213 |
<th>Actions</th>
|
|
|
|
| 3215 |
"""
|
| 3216 |
|
| 3217 |
for row in rows:
|
| 3218 |
+
log_id, request_id, endpoint, method, client_ip, file_info, processing_time, status_code, error_message, created_at, product_name, supplier_name, doc_type, llm_summary, has_llm_response = row
|
| 3219 |
|
| 3220 |
# Style endpoint
|
| 3221 |
endpoint_class = endpoint.replace('/', '').lower()
|
|
|
|
| 3240 |
# Format error message
|
| 3241 |
error_display = f'<span class="error-msg" title="{error_message or ""}">{(error_message or "")[:50]}{"..." if error_message and len(error_message) > 50 else ""}</span>'
|
| 3242 |
|
| 3243 |
+
llm_indicator = "๐ค Yes" if has_llm_response == "Yes" else "โ No"
|
| 3244 |
+
llm_color = "#28a745" if has_llm_response == "Yes" else "#6c757d"
|
| 3245 |
+
|
| 3246 |
html += f"""
|
| 3247 |
<tr class="log-row" data-endpoint="{endpoint}" data-status="{status_code}">
|
| 3248 |
+
<td><a href="/logs/{log_id}" style="color: #007bff; font-weight: bold;">#{log_id}</a></td>
|
| 3249 |
<td>{request_id or "N/A"}</td>
|
| 3250 |
<td>{endpoint_badge}</td>
|
| 3251 |
<td><strong>{product_name or "N/A"}</strong></td>
|
|
|
|
| 3253 |
<td>{file_display}</td>
|
| 3254 |
<td>{time_text}</td>
|
| 3255 |
<td>{status_text}</td>
|
| 3256 |
+
<td><span style="color: {llm_color}; font-weight: bold;">{llm_indicator}</span></td>
|
| 3257 |
<td>{error_display}</td>
|
| 3258 |
<td>{created_at}</td>
|
| 3259 |
<td>
|
| 3260 |
+
<a href="/logs/{log_id}">Details</a>
|
| 3261 |
+
{f'<a href="/preview/{request_id}">Preview</a> <a href="/template/{request_id}">JSON</a>' if request_id else ''}
|
| 3262 |
</td>
|
| 3263 |
</tr>
|
| 3264 |
"""
|
|
|
|
| 3280 |
return f"<h1>Error</h1><p>{str(e)}</p>", 500
|
| 3281 |
|
| 3282 |
# ADD this new endpoint after the /logs endpoint
|
|
|
|
| 3283 |
@app.route("/logs/<int:log_id>", methods=["GET"])
|
| 3284 |
def view_detailed_log(log_id):
|
| 3285 |
"""View detailed information for a specific log entry"""
|
|
|
|
| 3325 |
"product_name": log_data[14],
|
| 3326 |
"supplier_name": log_data[15],
|
| 3327 |
"user_message": log_data[16],
|
| 3328 |
+
"llm_response": log_data[17],
|
| 3329 |
"llm_response_summary": log_data[18]
|
| 3330 |
})
|
| 3331 |
|
| 3332 |
+
# Start building HTML
|
| 3333 |
html = f"""
|
| 3334 |
<html>
|
| 3335 |
<head>
|
|
|
|
| 3342 |
.request-info {{ background: #f8f9fa; border-left: 4px solid #28a745; }}
|
| 3343 |
.response-info {{ background: #fff3cd; border-left: 4px solid #ffc107; }}
|
| 3344 |
.error-info {{ background: #f8d7da; border-left: 4px solid #dc3545; }}
|
| 3345 |
+
.llm-section {{ background: #f0f8ff; border-left: 4px solid #007bff; }}
|
| 3346 |
+
.json-analysis {{ background: #f8f9fa; border: 1px solid #dee2e6; border-radius: 5px; padding: 10px; margin: 10px 0; }}
|
| 3347 |
+
.json-preview {{ background: #2d3748; color: #e2e8f0; padding: 15px; border-radius: 5px; font-family: 'Courier New', monospace; font-size: 12px; }}
|
| 3348 |
+
.expandable {{ cursor: pointer; user-select: none; }}
|
| 3349 |
+
.expandable:hover {{ background: #e9ecef; }}
|
| 3350 |
+
.collapsed {{ display: none; }}
|
| 3351 |
+
.parameter-count {{ background: #28a745; color: white; padding: 2px 8px; border-radius: 12px; font-size: 11px; margin-left: 10px; }}
|
| 3352 |
h1, h2 {{ color: #333; }}
|
| 3353 |
h1 {{ text-align: center; }}
|
| 3354 |
pre {{ background: #f8f9fa; padding: 15px; border-radius: 5px; overflow: auto; max-height: 300px; }}
|
|
|
|
| 3357 |
.nav-btn {{ background: #007bff; color: white; padding: 10px 15px; text-decoration: none; border-radius: 5px; margin: 5px; display: inline-block; }}
|
| 3358 |
.nav-btn:hover {{ background: #0056b3; color: white; }}
|
| 3359 |
.metric {{ display: inline-block; margin: 10px 15px 10px 0; padding: 8px 12px; background: white; border-radius: 5px; border: 1px solid #ddd; }}
|
| 3360 |
+
.copy-btn {{ background: #17a2b8; color: white; border: none; padding: 5px 10px; border-radius: 3px; cursor: pointer; float: right; margin: 5px; }}
|
| 3361 |
+
.copy-btn:hover {{ background: #138496; }}
|
| 3362 |
</style>
|
| 3363 |
</head>
|
| 3364 |
<body>
|
|
|
|
| 3380 |
<div class="metric"><strong>Created:</strong> {log_data[12]}</div>
|
| 3381 |
<div class="metric"><strong>Client IP:</strong> {log_data[4]}</div>
|
| 3382 |
</div>
|
| 3383 |
+
"""
|
| 3384 |
+
|
| 3385 |
+
# Add request information section if we have request data
|
| 3386 |
+
if log_data[1]: # If we have a request_id
|
| 3387 |
+
html += f"""
|
| 3388 |
<div class="section request-info">
|
| 3389 |
<h2>๐ Request Information</h2>
|
| 3390 |
+
<p><strong>Product:</strong> {log_data[14] or 'N/A'}</p>
|
| 3391 |
+
<p><strong>Document Type:</strong> {log_data[13] or 'N/A'}</p>
|
| 3392 |
+
<p><strong>Supplier:</strong> {log_data[15] or 'N/A'}</p>
|
| 3393 |
+
{f'<p><strong>File Info:</strong> {log_data[8]}</p>' if log_data[8] else '<p><strong>File Info:</strong> No file uploaded</p>'}
|
| 3394 |
+
"""
|
| 3395 |
+
|
| 3396 |
+
if log_data[16]: # User message
|
| 3397 |
+
user_message_preview = log_data[16][:500]
|
| 3398 |
+
if len(log_data[16]) > 500:
|
| 3399 |
+
user_message_preview += "..."
|
| 3400 |
+
html += f"""
|
| 3401 |
+
<div><strong>User Message:</strong>
|
| 3402 |
+
<pre>{user_message_preview}</pre></div>
|
| 3403 |
+
"""
|
| 3404 |
+
|
| 3405 |
+
html += "</div>"
|
| 3406 |
+
|
| 3407 |
+
# Add LLM Processing section if we have LLM data
|
| 3408 |
+
if log_data[17] or log_data[7]:
|
| 3409 |
+
html += f"""
|
| 3410 |
+
<div class="section llm-section">
|
| 3411 |
+
<h2>๐ค LLM Processing Chain</h2>
|
| 3412 |
+
<p><strong>Summary:</strong> {log_data[18] or 'No summary available'}</p>
|
| 3413 |
+
"""
|
| 3414 |
+
|
| 3415 |
+
# Raw LLM Response section
|
| 3416 |
+
if log_data[17]:
|
| 3417 |
+
# Escape the LLM response for safe JavaScript usage
|
| 3418 |
+
llm_response_js_safe = str(log_data[17]).replace("\\", "\\\\").replace("'", "\\'").replace('"', '\\"').replace('\n', '\\n').replace('\r', '\\r')
|
| 3419 |
|
| 3420 |
+
html += f"""
|
| 3421 |
+
<div class="json-analysis">
|
| 3422 |
+
<h3 class="expandable" onclick="toggleSection('llm-response-section')">โผ Raw LLM Response</h3>
|
| 3423 |
+
<div id="llm-response-section">
|
| 3424 |
+
<button class="copy-btn" onclick="copyToClipboard('{llm_response_js_safe}')">๐ Copy</button>
|
| 3425 |
+
<pre id="llm-response-content" class="json-preview" style="max-height: 500px; overflow-y: auto;">{log_data[17]}</pre>
|
| 3426 |
+
</div>
|
| 3427 |
+
</div>
|
| 3428 |
+
"""
|
| 3429 |
+
|
| 3430 |
+
# Add LLM response analysis
|
| 3431 |
+
html += _analyze_llm_response(log_data[17])
|
| 3432 |
+
|
| 3433 |
+
# Final API Response section
|
| 3434 |
+
if log_data[7]:
|
| 3435 |
+
# Escape the final response for safe JavaScript usage
|
| 3436 |
+
final_response_js_safe = str(log_data[7]).replace("\\", "\\\\").replace("'", "\\'").replace('"', '\\"').replace('\n', '\\n').replace('\r', '\\r')
|
| 3437 |
|
| 3438 |
+
html += f"""
|
| 3439 |
+
<div class="json-analysis">
|
| 3440 |
+
<h3 class="expandable" onclick="toggleSection('final-response-section')">โผ Final API Response</h3>
|
| 3441 |
+
<div id="final-response-section">
|
| 3442 |
+
<button class="copy-btn" onclick="copyToClipboard('{final_response_js_safe}')">๐ Copy</button>
|
| 3443 |
+
<pre class="json-preview">{log_data[7]}</pre>
|
| 3444 |
+
</div>
|
| 3445 |
+
</div>
|
| 3446 |
+
"""
|
| 3447 |
+
|
| 3448 |
+
html += "</div>"
|
| 3449 |
+
|
| 3450 |
+
# Add error information if present
|
| 3451 |
+
if log_data[11]:
|
| 3452 |
+
html += f"""
|
| 3453 |
<div class="section error-info">
|
| 3454 |
<h2>โ Error Information</h2>
|
| 3455 |
<p><strong>Error Message:</strong></p>
|
| 3456 |
<pre>{log_data[11]}</pre>
|
| 3457 |
</div>
|
| 3458 |
+
"""
|
| 3459 |
+
|
| 3460 |
+
# Add technical details section
|
| 3461 |
+
html += f"""
|
| 3462 |
<div class="section">
|
| 3463 |
<h2>๐ Technical Details</h2>
|
| 3464 |
<p><strong>User Agent:</strong> {log_data[5] or 'Not available'}</p>
|
| 3465 |
+
"""
|
| 3466 |
+
|
| 3467 |
+
if log_data[6]:
|
| 3468 |
+
html += f"""
|
| 3469 |
+
<div><strong>Request Data:</strong>
|
| 3470 |
+
<pre>{log_data[6]}</pre></div>
|
| 3471 |
+
"""
|
| 3472 |
+
else:
|
| 3473 |
+
html += "<p>No request data captured</p>"
|
| 3474 |
+
|
| 3475 |
+
html += "</div></div>"
|
| 3476 |
+
|
| 3477 |
+
# Add JavaScript section safely
|
| 3478 |
+
html += """
|
| 3479 |
+
<script>
|
| 3480 |
+
function toggleSection(id) {
|
| 3481 |
+
const element = document.getElementById(id);
|
| 3482 |
+
const button = document.querySelector('[onclick*="' + id + '"]');
|
| 3483 |
+
|
| 3484 |
+
if (element && button) {
|
| 3485 |
+
if (element.classList.contains('collapsed')) {
|
| 3486 |
+
element.classList.remove('collapsed');
|
| 3487 |
+
button.textContent = button.textContent.replace('โถ', 'โผ');
|
| 3488 |
+
} else {
|
| 3489 |
+
element.classList.add('collapsed');
|
| 3490 |
+
button.textContent = button.textContent.replace('โผ', 'โถ');
|
| 3491 |
+
}
|
| 3492 |
+
}
|
| 3493 |
+
}
|
| 3494 |
+
|
| 3495 |
+
function copyToClipboard(text) {
|
| 3496 |
+
// Create a temporary textarea element
|
| 3497 |
+
const textArea = document.createElement('textarea');
|
| 3498 |
+
textArea.value = text;
|
| 3499 |
+
textArea.style.position = 'fixed';
|
| 3500 |
+
textArea.style.opacity = '0';
|
| 3501 |
+
document.body.appendChild(textArea);
|
| 3502 |
+
textArea.select();
|
| 3503 |
+
|
| 3504 |
+
try {
|
| 3505 |
+
document.execCommand('copy');
|
| 3506 |
+
alert('โ
Copied to clipboard!');
|
| 3507 |
+
} catch (err) {
|
| 3508 |
+
console.error('Failed to copy: ', err);
|
| 3509 |
+
alert('โ Failed to copy to clipboard');
|
| 3510 |
+
}
|
| 3511 |
+
|
| 3512 |
+
document.body.removeChild(textArea);
|
| 3513 |
+
}
|
| 3514 |
+
|
| 3515 |
+
// Auto-expand LLM response if it contains JSON
|
| 3516 |
+
document.addEventListener('DOMContentLoaded', function() {
|
| 3517 |
+
const llmResponse = document.getElementById('llm-response-content');
|
| 3518 |
+
if (llmResponse && llmResponse.textContent.includes('[')) {
|
| 3519 |
+
// Likely contains JSON, keep expanded by default
|
| 3520 |
+
}
|
| 3521 |
+
});
|
| 3522 |
+
</script>
|
| 3523 |
</body>
|
| 3524 |
</html>
|
| 3525 |
"""
|
|
|
|
| 3528 |
|
| 3529 |
except Exception as e:
|
| 3530 |
return f"<h1>Error</h1><p>{str(e)}</p>", 500
|
| 3531 |
+
|
| 3532 |
+
|
| 3533 |
@app.route("/preview/<int:request_id>", methods=["GET"])
|
| 3534 |
def preview_page(request_id):
|
| 3535 |
"""preview with better formatting and metadata"""
|