hf-oauth-demo / api_endpoints.js
其天
Refactor to HF-only OAuth demo aligned with ms-oauth-studio structure
03be224
Raw
History Blame Contribute Delete
6.97 kB
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;