mirror of
https://github.com/bnair123/MusicAnalyser.git
synced 2026-02-25 19:56:06 +00:00
Implement Phase 2 Frontend with Ant Design and verify Data Ingestion
- Created `frontend/` React+Vite app using Ant Design (Dark Theme). - Implemented `App.jsx` to display listening history and calculated "Vibes". - Updated `backend/app/ingest.py` to fix ReccoBeats ID parsing. - Updated `backend/app/schemas.py` to expose audio features to the API. - Updated `README.md` with detailed Docker hosting instructions. - Added `TODO.md` for Phase 3 roadmap. - Cleaned up test scripts.
This commit is contained in:
117
frontend/src/App.jsx
Normal file
117
frontend/src/App.jsx
Normal file
@@ -0,0 +1,117 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Table, Layout, Typography, Tag, Card, Statistic, Row, Col, Space } from 'antd';
|
||||
import { ClockCircleOutlined, SoundOutlined, UserOutlined } from '@ant-design/icons';
|
||||
import axios from 'axios';
|
||||
import { format } from 'date-fns';
|
||||
|
||||
const { Header, Content, Footer } = Layout;
|
||||
const { Title, Text } = Typography;
|
||||
|
||||
const App = () => {
|
||||
const [history, setHistory] = useState([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
// Fetch History
|
||||
useEffect(() => {
|
||||
const fetchHistory = async () => {
|
||||
try {
|
||||
const response = await axios.get('/api/history?limit=100');
|
||||
setHistory(response.data);
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch history", error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
fetchHistory();
|
||||
}, []);
|
||||
|
||||
// Columns for Ant Design Table
|
||||
const columns = [
|
||||
{
|
||||
title: 'Track',
|
||||
dataIndex: ['track', 'name'],
|
||||
key: 'track',
|
||||
render: (text, record) => (
|
||||
<Space direction="vertical" size={0}>
|
||||
<Text strong>{text}</Text>
|
||||
<Text type="secondary" style={{ fontSize: '12px' }}>{record.track.album}</Text>
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Artist',
|
||||
dataIndex: ['track', 'artist'],
|
||||
key: 'artist',
|
||||
render: (text) => <Tag icon={<UserOutlined />} color="blue">{text}</Tag>,
|
||||
},
|
||||
{
|
||||
title: 'Played At',
|
||||
dataIndex: 'played_at',
|
||||
key: 'played_at',
|
||||
render: (date) => (
|
||||
<Space>
|
||||
<ClockCircleOutlined />
|
||||
{format(new Date(date), 'MMM d, h:mm a')}
|
||||
</Space>
|
||||
),
|
||||
sorter: (a, b) => new Date(a.played_at) - new Date(b.played_at),
|
||||
defaultSortOrder: 'descend',
|
||||
},
|
||||
{
|
||||
title: 'Vibe',
|
||||
key: 'vibe',
|
||||
render: (_, record) => {
|
||||
const energy = record.track.energy;
|
||||
const valence = record.track.valence;
|
||||
if (energy === undefined || valence === undefined) return <Tag>Unknown</Tag>;
|
||||
|
||||
let color = 'default';
|
||||
let label = 'Neutral';
|
||||
|
||||
if (energy > 0.7 && valence > 0.5) { color = 'orange'; label = 'High Energy / Happy'; }
|
||||
else if (energy > 0.7 && valence <= 0.5) { color = 'red'; label = 'High Energy / Dark'; }
|
||||
else if (energy <= 0.4 && valence > 0.5) { color = 'green'; label = 'Chill / Peaceful'; }
|
||||
else if (energy <= 0.4 && valence <= 0.5) { color = 'purple'; label = 'Sad / Melancholic'; }
|
||||
|
||||
return <Tag color={color}>{label}</Tag>;
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<Layout style={{ minHeight: '100vh' }}>
|
||||
<Header style={{ display: 'flex', alignItems: 'center' }}>
|
||||
<Title level={3} style={{ color: 'white', margin: 0 }}>
|
||||
<SoundOutlined style={{ marginRight: 10 }}/> Music Analyser
|
||||
</Title>
|
||||
</Header>
|
||||
<Content style={{ padding: '0 50px', marginTop: 30 }}>
|
||||
<div style={{ background: '#141414', padding: 24, borderRadius: 8, minHeight: 280 }}>
|
||||
|
||||
<Row gutter={16} style={{ marginBottom: 24 }}>
|
||||
<Col span={8}>
|
||||
<Card>
|
||||
<Statistic title="Total Plays (Stored)" value={history.length} prefix={<SoundOutlined />} />
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Title level={4} style={{ color: 'white' }}>Recent Listening History</Title>
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={history}
|
||||
rowKey="id"
|
||||
loading={loading}
|
||||
pagination={{ pageSize: 10 }}
|
||||
/>
|
||||
</div>
|
||||
</Content>
|
||||
<Footer style={{ textAlign: 'center' }}>
|
||||
Music Analyser ©{new Date().getFullYear()} Created with Ant Design
|
||||
</Footer>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
Reference in New Issue
Block a user