Spaces:
Running
Running
# app.py - ์ฌ๋ฐ๋ฅธ API ์ฒ๋ฆฌ๊ฐ ํฌํจ๋ ์ต์ข ๋ฒ์ | |
import gradio as gr | |
import sqlite3 | |
import json | |
import uuid | |
from datetime import datetime | |
import pandas as pd | |
import os | |
import threading | |
# ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ์ผ ๊ฒฝ๋ก | |
DB_FILE = "tracking_data.db" | |
# ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ด๊ธฐํ | |
def init_database(): | |
"""SQLite ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ด๊ธฐํ ๋ฐ ํ ์ด๋ธ ์์ฑ""" | |
conn = sqlite3.connect(DB_FILE) | |
cursor = conn.cursor() | |
# ๋ฐฉ๋ฌธ์ ํ ์ด๋ธ ์์ฑ | |
cursor.execute(""" | |
CREATE TABLE IF NOT EXISTS visitors ( | |
device_id TEXT PRIMARY KEY, | |
first_seen TIMESTAMP NOT NULL, | |
last_seen TIMESTAMP NOT NULL, | |
user_agent TEXT, | |
platform TEXT, | |
language TEXT, | |
screen_resolution TEXT, | |
cpu_cores INTEGER, | |
device_memory REAL, | |
gpu_info TEXT, | |
timezone TEXT | |
) | |
""") | |
# ์ด๋ฒคํธ ํ ์ด๋ธ ์์ฑ | |
cursor.execute(""" | |
CREATE TABLE IF NOT EXISTS events ( | |
id INTEGER PRIMARY KEY AUTOINCREMENT, | |
device_id TEXT NOT NULL, | |
site_id TEXT NOT NULL, | |
event_type TEXT NOT NULL, | |
event_data TEXT, | |
page_url TEXT, | |
page_title TEXT, | |
referrer TEXT, | |
client_timestamp TIMESTAMP, | |
server_timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP, | |
FOREIGN KEY (device_id) REFERENCES visitors(device_id) | |
) | |
""") | |
# ์ธ๋ฑ์ค ์์ฑ (์ฟผ๋ฆฌ ์ฑ๋ฅ ํฅ์) | |
cursor.execute("CREATE INDEX IF NOT EXISTS idx_device_id ON events(device_id)") | |
cursor.execute("CREATE INDEX IF NOT EXISTS idx_timestamp ON events(server_timestamp)") | |
cursor.execute("CREATE INDEX IF NOT EXISTS idx_event_type ON events(event_type)") | |
cursor.execute("CREATE INDEX IF NOT EXISTS idx_site_id ON events(site_id)") | |
conn.commit() | |
conn.close() | |
print(f"โ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ด๊ธฐํ ์๋ฃ: {DB_FILE}") | |
# ์ฑ ์์ ์ DB ์ด๊ธฐํ | |
init_database() | |
# ์ค๋ ๋ ์์ ์ฑ์ ์ํ ๋ฝ | |
db_lock = threading.Lock() | |
def process_tracking_data(data_json): | |
"""์ถ์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์ SQLite DB์ ์ ์ฅ""" | |
with db_lock: | |
conn = None | |
try: | |
# ๋ก๊น ์ถ๊ฐ | |
print(f"[API] Received data: {data_json[:200] if isinstance(data_json, str) else data_json}") | |
# JSON ํ์ฑ | |
data = json.loads(data_json) if isinstance(data_json, str) else data_json | |
# ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ | |
conn = sqlite3.connect(DB_FILE) | |
cursor = conn.cursor() | |
# ํ์ ํ๋ ํ์ธ | |
device_id = data.get('deviceId', 'unknown') | |
site_id = data.get('siteId', 'unknown') | |
# 1. ๋ฐฉ๋ฌธ์ ์ ๋ณด ์ ๋ฐ์ดํธ (UPSERT) | |
cursor.execute(""" | |
SELECT device_id FROM visitors WHERE device_id = ? | |
""", (device_id,)) | |
if cursor.fetchone() is None: | |
# ์ ๊ท ๋ฐฉ๋ฌธ์ ์ฝ์ | |
cursor.execute(""" | |
INSERT INTO visitors ( | |
device_id, first_seen, last_seen, user_agent, platform, | |
language, screen_resolution, cpu_cores, device_memory, | |
gpu_info, timezone | |
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) | |
""", ( | |
device_id, | |
datetime.now(), | |
datetime.now(), | |
data.get('userAgent', ''), | |
data.get('platform', ''), | |
data.get('language', ''), | |
data.get('screenResolution', ''), | |
data.get('cpuCores', 0), | |
data.get('deviceMemory', 0), | |
data.get('gpuInfo', ''), | |
data.get('timezone', '') | |
)) | |
print(f"๐ ์ ๊ท ๋ฐฉ๋ฌธ์ ๋ฑ๋ก: {device_id}") | |
else: | |
# ๊ธฐ์กด ๋ฐฉ๋ฌธ์ ์ ๋ฐ์ดํธ | |
cursor.execute(""" | |
UPDATE visitors | |
SET last_seen = ?, | |
user_agent = ?, | |
platform = ?, | |
language = ?, | |
screen_resolution = ?, | |
cpu_cores = ?, | |
device_memory = ?, | |
gpu_info = ?, | |
timezone = ? | |
WHERE device_id = ? | |
""", ( | |
datetime.now(), | |
data.get('userAgent', ''), | |
data.get('platform', ''), | |
data.get('language', ''), | |
data.get('screenResolution', ''), | |
data.get('cpuCores', 0), | |
data.get('deviceMemory', 0), | |
data.get('gpuInfo', ''), | |
data.get('timezone', ''), | |
device_id | |
)) | |
# 2. ์ด๋ฒคํธ ์ ์ฅ | |
event_data = data.get('eventData', {}) | |
cursor.execute(""" | |
INSERT INTO events ( | |
device_id, site_id, event_type, event_data, | |
page_url, page_title, referrer, client_timestamp | |
) VALUES (?, ?, ?, ?, ?, ?, ?, ?) | |
""", ( | |
device_id, | |
site_id, | |
data.get('eventType', 'pageview'), | |
json.dumps(event_data), | |
data.get('pageUrl', ''), | |
data.get('pageTitle', ''), | |
data.get('referrer', ''), | |
data.get('timestamp', datetime.now().isoformat()) | |
)) | |
tracking_id = cursor.lastrowid | |
conn.commit() | |
print(f"โ ์ด๋ฒคํธ ์ ์ฅ: ID={tracking_id}, Type={data.get('eventType')}, Device={device_id}") | |
return { | |
"status": "success", | |
"message": "Data tracked successfully", | |
"trackingId": tracking_id, | |
"deviceId": device_id | |
} | |
except Exception as e: | |
if conn: | |
conn.rollback() | |
print(f"โ ์ค๋ฅ ๋ฐ์: {str(e)}") | |
return {"status": "error", "message": str(e)} | |
finally: | |
if conn: | |
conn.close() | |
def get_statistics(): | |
"""DB์์ ํต๊ณ ๋ฐ์ดํฐ ์กฐํ""" | |
conn = sqlite3.connect(DB_FILE) | |
cursor = conn.cursor() | |
try: | |
# ์ด ๋ฐฉ๋ฌธ์ ์ | |
cursor.execute("SELECT COUNT(*) FROM visitors") | |
total_visitors = cursor.fetchone()[0] | |
# ์ค๋ ๋ฐฉ๋ฌธ์ ์ | |
cursor.execute(""" | |
SELECT COUNT(DISTINCT device_id) FROM events | |
WHERE DATE(server_timestamp) = DATE('now', 'localtime') | |
""") | |
today_visitors = cursor.fetchone()[0] | |
# ์ด ์ด๋ฒคํธ ์ | |
cursor.execute("SELECT COUNT(*) FROM events") | |
total_events = cursor.fetchone()[0] | |
# ์ด๋ฒคํธ ํ์ ๋ณ ํต๊ณ | |
cursor.execute(""" | |
SELECT event_type, COUNT(*) as count | |
FROM events | |
GROUP BY event_type | |
ORDER BY count DESC | |
""") | |
event_types = cursor.fetchall() | |
# ์ฌ์ดํธ๋ณ ํต๊ณ | |
cursor.execute(""" | |
SELECT site_id, COUNT(*) as count | |
FROM events | |
GROUP BY site_id | |
ORDER BY count DESC | |
LIMIT 5 | |
""") | |
site_stats = cursor.fetchall() | |
# ์ต๊ทผ ์ด๋ฒคํธ | |
cursor.execute(""" | |
SELECT | |
e.server_timestamp, | |
e.event_type, | |
e.device_id, | |
e.page_url, | |
e.site_id | |
FROM events e | |
ORDER BY e.id DESC | |
LIMIT 15 | |
""") | |
recent_events = cursor.fetchall() | |
# ์๊ฐ๋๋ณ ํต๊ณ | |
cursor.execute(""" | |
SELECT | |
strftime('%H', server_timestamp) as hour, | |
COUNT(*) as count | |
FROM events | |
WHERE DATE(server_timestamp) = DATE('now', 'localtime') | |
GROUP BY hour | |
ORDER BY hour | |
""") | |
hourly_stats = cursor.fetchall() | |
return { | |
'total_visitors': total_visitors, | |
'today_visitors': today_visitors, | |
'total_events': total_events, | |
'event_types': event_types, | |
'site_stats': site_stats, | |
'recent_events': recent_events, | |
'hourly_stats': hourly_stats | |
} | |
finally: | |
conn.close() | |
def view_statistics(): | |
"""ํต๊ณ ๋ฐ์ดํฐ ํฌ๋งทํ ํ์ฌ ํ์""" | |
stats = get_statistics() | |
summary = f""" | |
### ๐ ๋ฐฉ๋ฌธ์ ํต๊ณ | |
- **์ด ๋ฐฉ๋ฌธ์**: {stats['total_visitors']}๋ช | |
- **์ค๋ ๋ฐฉ๋ฌธ์**: {stats['today_visitors']}๋ช | |
- **์ด ์ด๋ฒคํธ**: {stats['total_events']}ํ | |
- **๋ง์ง๋ง ์ ๋ฐ์ดํธ**: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} | |
### ๐ ์ด๋ฒคํธ ํ์ ๋ณ ํต๊ณ | |
""" | |
for event_type, count in stats['event_types']: | |
summary += f"\n- **{event_type}**: {count:,}ํ" | |
if stats['site_stats']: | |
summary += "\n\n### ๐ ์ฌ์ดํธ๋ณ ํต๊ณ (์์ 5๊ฐ)" | |
for site_id, count in stats['site_stats']: | |
summary += f"\n- **{site_id}**: {count:,}ํ" | |
if stats['hourly_stats']: | |
summary += "\n\n### โฐ ์ค๋ ์๊ฐ๋๋ณ ํ๋" | |
for hour, count in stats['hourly_stats']: | |
summary += f"\n- **{hour}์**: {count}ํ" | |
summary += "\n\n### ๐ ์ต๊ทผ ์ด๋ฒคํธ (์ต๋ 15๊ฐ)" | |
for event in stats['recent_events']: | |
timestamp, event_type, device_id, page_url, site_id = event | |
summary += f"\n- {timestamp} | {event_type} | {device_id[:8]}... | {site_id} | {page_url[:40]}..." | |
return summary | |
def get_recent_data(): | |
"""์ต๊ทผ ๋ฐ์ดํฐ๋ฅผ DataFrame์ผ๋ก ๋ฐํ""" | |
conn = sqlite3.connect(DB_FILE) | |
try: | |
query = """ | |
SELECT | |
e.server_timestamp as 'Timestamp', | |
e.device_id as 'Device ID', | |
e.event_type as 'Event Type', | |
e.page_url as 'Page URL', | |
v.platform as 'Platform', | |
v.language as 'Language', | |
e.site_id as 'Site ID' | |
FROM events e | |
JOIN visitors v ON e.device_id = v.device_id | |
ORDER BY e.id DESC | |
LIMIT 200 | |
""" | |
df = pd.read_sql_query(query, conn) | |
return df | |
finally: | |
conn.close() | |
def export_data(start_date, end_date): | |
"""๋ฐ์ดํฐ๋ฅผ CSV๋ก ๋ด๋ณด๋ด๊ธฐ""" | |
conn = sqlite3.connect(DB_FILE) | |
try: | |
query = """ | |
SELECT | |
e.id, | |
e.server_timestamp, | |
e.client_timestamp, | |
e.device_id, | |
e.site_id, | |
e.event_type, | |
e.event_data, | |
e.page_url, | |
e.page_title, | |
e.referrer, | |
v.user_agent, | |
v.platform, | |
v.language, | |
v.screen_resolution, | |
v.cpu_cores, | |
v.device_memory, | |
v.gpu_info, | |
v.timezone, | |
v.first_seen, | |
v.last_seen | |
FROM events e | |
JOIN visitors v ON e.device_id = v.device_id | |
WHERE DATE(e.server_timestamp) BETWEEN ? AND ? | |
ORDER BY e.id DESC | |
""" | |
df = pd.read_sql_query(query, conn, params=(start_date, end_date)) | |
# CSV ํ์ผ๋ก ์ ์ฅ | |
filename = f"tracking_export_{start_date}_to_{end_date}.csv" | |
df.to_csv(filename, index=False) | |
return filename, f"โ ๋ฐ์ดํฐ๋ฅผ {filename} ํ์ผ๋ก ๋ด๋ณด๋์ต๋๋ค. ({len(df):,}๊ฐ ๋ ์ฝ๋)" | |
except Exception as e: | |
return None, f"โ ๋ด๋ณด๋ด๊ธฐ ์คํจ: {str(e)}" | |
finally: | |
conn.close() | |
def test_tracking(): | |
"""ํ ์คํธ ๋ฐ์ดํฐ ์์ฑ""" | |
test_data = { | |
"siteId": "test-site", | |
"deviceId": f"TEST_{str(uuid.uuid4())[:8]}", | |
"eventType": "test_event", | |
"eventData": {"test": True, "timestamp": datetime.now().isoformat()}, | |
"pageUrl": "https://test.example.com/page", | |
"pageTitle": "Test Page", | |
"referrer": "https://google.com", | |
"userAgent": "Test Browser/1.0", | |
"screenResolution": "1920x1080", | |
"platform": "Test Platform", | |
"language": "ko-KR", | |
"timezone": "Asia/Seoul", | |
"cpuCores": 8, | |
"deviceMemory": 16, | |
"gpuInfo": "Test GPU", | |
"timestamp": datetime.now().isoformat() | |
} | |
result = process_tracking_data(test_data) | |
return f"ํ ์คํธ ๊ฒฐ๊ณผ:\n{json.dumps(result, indent=2)}\n\nํ ์คํธ ๋ฐ์ดํฐ:\n{json.dumps(test_data, indent=2)}" | |
def get_db_info(): | |
"""๋ฐ์ดํฐ๋ฒ ์ด์ค ์ ๋ณด ์กฐํ""" | |
conn = sqlite3.connect(DB_FILE) | |
cursor = conn.cursor() | |
try: | |
# DB ํ์ผ ํฌ๊ธฐ | |
db_size = os.path.getsize(DB_FILE) / (1024 * 1024) # MB | |
# ํ ์ด๋ธ ์ ๋ณด | |
cursor.execute(""" | |
SELECT name, sql FROM sqlite_master | |
WHERE type='table' AND name NOT LIKE 'sqlite_%' | |
""") | |
tables = cursor.fetchall() | |
# ๋ ์ฝ๋ ์ | |
cursor.execute("SELECT COUNT(*) FROM visitors") | |
visitor_count = cursor.fetchone()[0] | |
cursor.execute("SELECT COUNT(*) FROM events") | |
event_count = cursor.fetchone()[0] | |
info = f""" | |
### ๐พ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ ๋ณด | |
- **DB ํ์ผ**: {DB_FILE} | |
- **ํ์ผ ํฌ๊ธฐ**: {db_size:.2f} MB | |
- **๋ฐฉ๋ฌธ์ ์**: {visitor_count:,}๊ฐ | |
- **์ด๋ฒคํธ ์**: {event_count:,}๊ฐ | |
### ๐ ํ ์ด๋ธ ๊ตฌ์กฐ | |
""" | |
for table_name, sql in tables: | |
info += f"\n**{table_name}**\n```sql\n{sql}\n```\n" | |
return info | |
finally: | |
conn.close() | |
# ์ถ์ ์คํฌ๋ฆฝํธ ์์ฑ ํจ์ | |
def generate_tracking_script(site_id, server_url): | |
"""์ธ๋ถ ์ฌ์ดํธ์ ์ฝ์ ํ ์ถ์ ์คํฌ๋ฆฝํธ ์์ฑ""" | |
script = f""" | |
<!-- Visitor Tracking Script --> | |
<script> | |
(function() {{ | |
// ์ถ์ ์๋ฒ URL | |
const TRACKING_SERVER = '{server_url}'; | |
const SITE_ID = '{site_id}'; | |
// ๋๋ฐ์ด์ค ID ์์ฑ/์กฐํ | |
function getDeviceId() {{ | |
let deviceId = localStorage.getItem('_tracker_device_id'); | |
if (!deviceId) {{ | |
deviceId = 'DEV_' + Date.now() + '_' + Math.random().toString(36).substring(2, 9); | |
localStorage.setItem('_tracker_device_id', deviceId); | |
}} | |
return deviceId; | |
}} | |
// ์ถ์ ๋ฐ์ดํฐ ์ ์ก | |
async function collectAndSend(eventType = 'pageview', eventData = {{}}) {{ | |
const data = {{ | |
siteId: SITE_ID, | |
deviceId: getDeviceId(), | |
eventType: eventType, | |
eventData: eventData, | |
pageUrl: window.location.href, | |
pageTitle: document.title, | |
referrer: document.referrer, | |
userAgent: navigator.userAgent, | |
screenResolution: screen.width + 'x' + screen.height, | |
platform: navigator.platform, | |
language: navigator.language, | |
timestamp: new Date().toISOString() | |
}}; | |
try {{ | |
const response = await fetch(TRACKING_SERVER + '/call/process_tracking', {{ | |
method: 'POST', | |
headers: {{ 'Content-Type': 'application/json' }}, | |
body: JSON.stringify({{ data: [JSON.stringify(data)] }}) | |
}}); | |
if (response.ok) {{ | |
const result = await response.json(); | |
if (result.event_id) {{ | |
console.log('[Tracker] โ Event tracked'); | |
}} | |
}} | |
}} catch(e) {{ | |
console.error('[Tracker] Error:', e); | |
}} | |
}} | |
// ์ ์ญ ์ถ์ ํจ์ | |
window._tracker = {{ | |
trackEvent: function(eventName, eventData) {{ | |
collectAndSend('custom', {{ name: eventName, data: eventData }}); | |
}} | |
}}; | |
// ํ์ด์ง ๋ก๋์ ์ถ์ | |
if (document.readyState === 'loading') {{ | |
document.addEventListener('DOMContentLoaded', () => collectAndSend()); | |
}} else {{ | |
collectAndSend(); | |
}} | |
}})(); | |
</script> | |
<!-- End Visitor Tracking Script --> | |
""" | |
return script.strip() | |
def create_site_id(server_url): | |
"""์๋ก์ด ์ถ์ ์ฌ์ดํธ ID ์์ฑ""" | |
if not server_url: | |
server_url = "https://your-space-name.hf.space" | |
site_id = str(uuid.uuid4())[:8] | |
return site_id, generate_tracking_script(site_id, server_url) | |
# CSS ์คํ์ผ | |
custom_css = """ | |
.gradio-container { | |
font-family: 'Arial', sans-serif; | |
} | |
.tracking-script { | |
background: #f5f5f5; | |
border: 1px solid #ddd; | |
border-radius: 5px; | |
padding: 10px; | |
font-family: monospace; | |
font-size: 12px; | |
} | |
.db-info { | |
background: #e3f2fd; | |
padding: 15px; | |
border-radius: 5px; | |
margin: 10px 0; | |
} | |
""" | |
# Gradio UI | |
with gr.Blocks(title="๋ฐฉ๋ฌธ์ ์ถ์ ๊ด๋ฆฌ ์์คํ ", css=custom_css, theme=gr.themes.Soft()) as demo: | |
gr.Markdown(""" | |
# ๐ ๋ฐฉ๋ฌธ์ ์ถ์ ๊ด๋ฆฌ ์์คํ | |
### ์ธ๋ถ ์น์ฌ์ดํธ์ ์ถ์ ์คํฌ๋ฆฝํธ๋ฅผ ์ฝ์ ํ์ฌ ๋ฐฉ๋ฌธ์๋ฅผ ๋ชจ๋ํฐ๋งํฉ๋๋ค. | |
> โ **SQLite ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ชจ๋ ๋ฐ์ดํฐ๊ฐ ์๊ตฌ ์ ์ฅ๋ฉ๋๋ค.** | |
""") | |
# ์จ๊ฒจ์ง API ์ฒ๋ฆฌ (์ฌ๋ฐ๋ฅธ ๋ฐฉ์) | |
with gr.Column(visible=False): | |
api_input = gr.Textbox(label="API Input") | |
api_output = gr.JSON(label="API Output") | |
api_button = gr.Button("Process Tracking Data") | |
# Button click์ api_name ์ง์ | |
api_button.click( | |
fn=process_tracking_data, | |
inputs=api_input, | |
outputs=api_output, | |
api_name="process_tracking" | |
) | |
with gr.Tab("๐ง ์ถ์ ์คํฌ๋ฆฝํธ ์์ฑ"): | |
gr.Markdown("### ์๋ก์ด ์ถ์ ์คํฌ๋ฆฝํธ ์์ฑ") | |
with gr.Row(): | |
with gr.Column(): | |
server_url_input = gr.Textbox( | |
label="์ถ์ ์๋ฒ URL", | |
placeholder="https://your-space-name.hf.space", | |
info="์ด Hugging Face Space์ URL์ ์ ๋ ฅํ์ธ์" | |
) | |
gr.Markdown(""" | |
โน๏ธ **์๋ฒ URL ์ฐพ๊ธฐ**: | |
1. ์ด Space์ URL์ ํ์ธํ์ธ์ | |
2. ํ์: `https://username-spacename.hf.space` | |
3. ์์: `https://seawolf2357-evcook.hf.space` | |
""") | |
create_btn = gr.Button("๐ง ์ ์ถ์ ์ฝ๋ ์์ฑ", variant="primary") | |
with gr.Row(): | |
site_id_output = gr.Textbox(label="์ฌ์ดํธ ID", interactive=False) | |
script_output = gr.Code( | |
label="HTML์ ์ฝ์ ํ ์ถ์ ์คํฌ๋ฆฝํธ", | |
language="html", | |
interactive=True, | |
elem_classes="tracking-script" | |
) | |
create_btn.click( | |
fn=create_site_id, | |
inputs=[server_url_input], | |
outputs=[site_id_output, script_output], | |
api_name="create_site_id" | |
) | |
with gr.Tab("๐ ํต๊ณ ๋์๋ณด๋"): | |
gr.Markdown("### ๐ ์ค์๊ฐ ๋ฐฉ๋ฌธ์ ํต๊ณ") | |
with gr.Row(): | |
refresh_btn = gr.Button("๐ ํต๊ณ ์๋ก๊ณ ์นจ", variant="secondary") | |
test_btn = gr.Button("๐งช ํ ์คํธ ๋ฐ์ดํฐ ์์ฑ", variant="secondary") | |
db_info_btn = gr.Button("๐พ DB ์ ๋ณด ๋ณด๊ธฐ", variant="secondary") | |
stats_output = gr.Markdown() | |
test_output = gr.Textbox(label="ํ ์คํธ ๊ฒฐ๊ณผ", visible=False) | |
db_info_output = gr.Markdown(visible=False, elem_classes="db-info") | |
# ํ์ด์ง ๋ก๋ ์ ํต๊ณ ํ์ | |
demo.load(fn=view_statistics, outputs=stats_output, api_name="view_statistics") | |
refresh_btn.click(fn=view_statistics, outputs=stats_output, api_name="view_statistics_1") | |
def test_and_refresh(): | |
test_result = test_tracking() | |
stats = view_statistics() | |
return stats, gr.update(visible=True, value=test_result) | |
test_btn.click( | |
fn=test_and_refresh, | |
outputs=[stats_output, test_output], | |
api_name="test_and_refresh" | |
) | |
def show_db_info(): | |
info = get_db_info() | |
return gr.update(visible=True, value=info) | |
db_info_btn.click( | |
fn=show_db_info, | |
outputs=db_info_output, | |
api_name="show_db_info" | |
) | |
with gr.Tab("๐ ๋ฐ์ดํฐ ๋ทฐ์ด"): | |
gr.Markdown("### ๐ ์ต๊ทผ ์ถ์ ๋ฐ์ดํฐ") | |
data_refresh_btn = gr.Button("๐ ๋ฐ์ดํฐ ์๋ก๊ณ ์นจ") | |
data_output = gr.Dataframe( | |
headers=["Timestamp", "Device ID", "Event Type", "Page URL", "Platform", "Language", "Site ID"], | |
label="์ต๊ทผ ์ด๋ฒคํธ (์ต๋ 200๊ฐ)" | |
) | |
demo.load(fn=get_recent_data, outputs=data_output, api_name="get_recent_data") | |
data_refresh_btn.click(fn=get_recent_data, outputs=data_output, api_name="get_recent_data_1") | |
gr.Markdown("### ๐ฅ ๋ฐ์ดํฐ ๋ด๋ณด๋ด๊ธฐ") | |
with gr.Row(): | |
start_date = gr.Textbox( | |
label="์์ ๋ ์ง", | |
placeholder="2025-01-01", | |
value=datetime.now().strftime('%Y-%m-%d') | |
) | |
end_date = gr.Textbox( | |
label="์ข ๋ฃ ๋ ์ง", | |
placeholder="2025-01-31", | |
value=datetime.now().strftime('%Y-%m-%d') | |
) | |
export_btn = gr.Button("๐พ CSV๋ก ๋ด๋ณด๋ด๊ธฐ", variant="primary") | |
export_output = gr.Textbox(label="๋ด๋ณด๋ด๊ธฐ ๊ฒฐ๊ณผ") | |
export_btn.click( | |
fn=export_data, | |
inputs=[start_date, end_date], | |
outputs=[gr.File(label="๋ค์ด๋ก๋ ํ์ผ"), export_output], | |
api_name="export_data" | |
) | |
with gr.Tab("โ ๋์๋ง"): | |
gr.Markdown(""" | |
### ๐ ๋น ๋ฅธ ์์ ๊ฐ์ด๋ | |
1. **์ด Space์ URL ํ์ธ** | |
- ๋ธ๋ผ์ฐ์ ์ฃผ์์ฐฝ์์ URL ๋ณต์ฌ | |
- ์: `https://username-spacename.hf.space` | |
2. **์ถ์ ์คํฌ๋ฆฝํธ ์์ฑ** | |
- "์ถ์ ์คํฌ๋ฆฝํธ ์์ฑ" ํญ์ผ๋ก ์ด๋ | |
- URL ์ ๋ ฅ ํ ์คํฌ๋ฆฝํธ ์์ฑ | |
3. **์น์ฌ์ดํธ์ ์ค์น** | |
```html | |
<!-- ์ฌ๊ธฐ์ ์์ฑ๋ ์คํฌ๋ฆฝํธ ๋ถ์ฌ๋ฃ๊ธฐ --> | |
</body> | |
</html> | |
``` | |
4. **์ถ์ ํ์ธ** | |
- "ํต๊ณ ๋์๋ณด๋" ํญ์์ ์ค์๊ฐ ๋ชจ๋ํฐ๋ง | |
### ๐พ ๋ฐ์ดํฐ ์ ์ฅ | |
- **SQLite DB ํ์ผ**: `tracking_data.db` | |
- **์๋ ์ ์ฅ**: ๋ชจ๋ ์ด๋ฒคํธ๊ฐ ์ค์๊ฐ์ผ๋ก DB์ ์ ์ฅ | |
- **์๊ตฌ ๋ณด๊ด**: ์๋ฒ ์ฌ์์ ํ์๋ ๋ฐ์ดํฐ ์ ์ง | |
### ๐ก API ์ฌ์ฉ๋ฒ | |
```javascript | |
// Gradio Client API ์ฌ์ฉ | |
fetch('https://your-space.hf.space/call/process_tracking', { | |
method: 'POST', | |
headers: {'Content-Type': 'application/json'}, | |
body: JSON.stringify({ | |
data: [JSON.stringify({ | |
siteId: 'your-site-id', | |
deviceId: 'device-id', | |
eventType: 'pageview', | |
// ... ๊ธฐํ ๋ฐ์ดํฐ | |
})] | |
}) | |
}); | |
``` | |
""") | |
# ์ฑ ์คํ | |
if __name__ == "__main__": | |
demo.queue().launch() | |
# requirements.txt ๋ด์ฉ: | |
""" | |
gradio==4.44.1 | |
pandas==2.2.3 | |
""" |