Spaces:
Sleeping
Sleeping
| const express = require('express'); | |
| const axios = require('axios'); | |
| const router = express.Router(); | |
| const HF_API_BASE = 'https://huggingface.co/api'; | |
| /** | |
| * 验证 Authorization 请求头中的 Bearer Token | |
| * 支持两种方式传递 token(兼容创空间 Header 限制): | |
| * 1. Authorization: Bearer <token> | |
| * 2. Query: ?access_token=<token> | |
| */ | |
| const validateAuthHeader = (req, res, next) => { | |
| const authHeader = req.headers.authorization; | |
| let token = ''; | |
| if (authHeader && authHeader.startsWith('Bearer ')) { | |
| token = authHeader.substring(7); | |
| } else if (req.query.access_token) { | |
| token = req.query.access_token; | |
| } | |
| if (!token) { | |
| return res.status(401).json({ | |
| error: '缺少 access_token,可通过 Authorization 头或 ?access_token= 参数传递' | |
| }); | |
| } | |
| req.accessToken = token; | |
| next(); | |
| }; | |
| // 1. 获取当前登录用户信息 | |
| router.get('/whoami', validateAuthHeader, async (req, res) => { | |
| try { | |
| const response = await axios.get(`${HF_API_BASE}/whoami-v2`, { | |
| headers: { | |
| 'Authorization': `Bearer ${req.accessToken}`, | |
| 'Content-Type': 'application/json' | |
| } | |
| }); | |
| res.json({ | |
| status: response.status, | |
| data: response.data | |
| }); | |
| } catch (error) { | |
| console.error('Error fetching whoami:', error.response?.data || error.message); | |
| res.status(error.response?.status || 500).json({ | |
| error: 'Failed to fetch user info', | |
| details: error.response?.data || error.message | |
| }); | |
| } | |
| }); | |
| // 2. 获取指定用户的模型列表 | |
| router.get('/models/:owner', validateAuthHeader, async (req, res) => { | |
| try { | |
| const { owner } = req.params; | |
| const pageSize = req.query.page_size || 50; | |
| const response = await axios.get(`${HF_API_BASE}/models?author=${owner}&limit=${pageSize}`, { | |
| headers: { | |
| 'Authorization': `Bearer ${req.accessToken}`, | |
| 'Content-Type': 'application/json' | |
| } | |
| }); | |
| const models = Array.isArray(response.data) ? response.data : []; | |
| const processedModels = models.map(model => ({ | |
| id: model.id, | |
| name: model.id, | |
| private: model.private || false, | |
| gated: model.gated || false, | |
| ...model | |
| })); | |
| res.json({ | |
| total: processedModels.length, | |
| page_size: pageSize, | |
| data: processedModels | |
| }); | |
| } catch (error) { | |
| console.error('Error fetching models:', error.response?.data || error.message); | |
| res.status(error.response?.status || 500).json({ | |
| error: 'Failed to fetch models', | |
| details: error.response?.data || error.message | |
| }); | |
| } | |
| }); | |
| // 3. 获取指定用户的数据集列表 | |
| router.get('/datasets/:owner', validateAuthHeader, async (req, res) => { | |
| try { | |
| const { owner } = req.params; | |
| const pageSize = req.query.page_size || 50; | |
| const response = await axios.get(`${HF_API_BASE}/datasets?author=${owner}&limit=${pageSize}`, { | |
| headers: { | |
| 'Authorization': `Bearer ${req.accessToken}`, | |
| 'Content-Type': 'application/json' | |
| } | |
| }); | |
| const datasets = Array.isArray(response.data) ? response.data : []; | |
| const processedDatasets = datasets.map(dataset => ({ | |
| id: dataset.id, | |
| name: dataset.id, | |
| private: dataset.private || false, | |
| gated: dataset.gated || false, | |
| ...dataset | |
| })); | |
| res.json({ | |
| total: processedDatasets.length, | |
| page_size: pageSize, | |
| data: processedDatasets | |
| }); | |
| } catch (error) { | |
| console.error('Error fetching datasets:', error.response?.data || error.message); | |
| res.status(error.response?.status || 500).json({ | |
| error: 'Failed to fetch datasets', | |
| details: error.response?.data || error.message | |
| }); | |
| } | |
| }); | |
| // 4. 获取指定用户的 Spaces 列表 | |
| router.get('/spaces/:owner', validateAuthHeader, async (req, res) => { | |
| try { | |
| const { owner } = req.params; | |
| const pageSize = req.query.page_size || 50; | |
| const response = await axios.get(`${HF_API_BASE}/spaces?author=${owner}&limit=${pageSize}`, { | |
| headers: { | |
| 'Authorization': `Bearer ${req.accessToken}`, | |
| 'Content-Type': 'application/json' | |
| } | |
| }); | |
| const spaces = Array.isArray(response.data) ? response.data : []; | |
| const processedSpaces = spaces.map(space => ({ | |
| id: space.id, | |
| name: space.id, | |
| sdk: space.sdk, | |
| ...space | |
| })); | |
| res.json({ | |
| total: processedSpaces.length, | |
| page_size: pageSize, | |
| data: processedSpaces | |
| }); | |
| } catch (error) { | |
| console.error('Error fetching spaces:', error.response?.data || error.message); | |
| res.status(error.response?.status || 500).json({ | |
| error: 'Failed to fetch spaces', | |
| details: error.response?.data || error.message | |
| }); | |
| } | |
| }); | |
| // 5. 获取特定模型详情 | |
| router.get('/models/:owner/:repo_name', validateAuthHeader, async (req, res) => { | |
| try { | |
| const { owner, repo_name } = req.params; | |
| const response = await axios.get(`${HF_API_BASE}/models/${owner}/${repo_name}`, { | |
| headers: { | |
| 'Authorization': `Bearer ${req.accessToken}`, | |
| 'Content-Type': 'application/json' | |
| } | |
| }); | |
| res.json({ | |
| status: response.status, | |
| data: response.data | |
| }); | |
| } catch (error) { | |
| console.error('Error fetching model details:', error.response?.data || error.message); | |
| res.status(error.response?.status || 500).json({ | |
| error: 'Failed to fetch model details', | |
| details: error.response?.data || error.message | |
| }); | |
| } | |
| }); | |
| // 6. 获取特定数据集详情 | |
| router.get('/datasets/:owner/:repo_name', validateAuthHeader, async (req, res) => { | |
| try { | |
| const { owner, repo_name } = req.params; | |
| const response = await axios.get(`${HF_API_BASE}/datasets/${owner}/${repo_name}`, { | |
| headers: { | |
| 'Authorization': `Bearer ${req.accessToken}`, | |
| 'Content-Type': 'application/json' | |
| } | |
| }); | |
| res.json({ | |
| status: response.status, | |
| data: response.data | |
| }); | |
| } catch (error) { | |
| console.error('Error fetching dataset details:', error.response?.data || error.message); | |
| res.status(error.response?.status || 500).json({ | |
| error: 'Failed to fetch dataset details', | |
| details: error.response?.data || error.message | |
| }); | |
| } | |
| }); | |
| // 7. 获取特定 Space 详情 | |
| router.get('/spaces/:owner/:repo_name', validateAuthHeader, async (req, res) => { | |
| try { | |
| const { owner, repo_name } = req.params; | |
| const response = await axios.get(`${HF_API_BASE}/spaces/${owner}/${repo_name}`, { | |
| headers: { | |
| 'Authorization': `Bearer ${req.accessToken}`, | |
| 'Content-Type': 'application/json' | |
| } | |
| }); | |
| res.json({ | |
| status: response.status, | |
| data: response.data | |
| }); | |
| } catch (error) { | |
| console.error('Error fetching space details:', error.response?.data || error.message); | |
| res.status(error.response?.status || 500).json({ | |
| error: 'Failed to fetch space details', | |
| details: error.response?.data || error.message | |
| }); | |
| } | |
| }); | |
| module.exports = router; | |