soiz1's picture
Update app.py
48be6fe verified
import json
import requests
from flask import Flask, render_template_string, request, jsonify, redirect, url_for
import secrets
app = Flask(__name__)
app.secret_key = secrets.token_hex(16)
# 簡易的なOAuth状態管理
oauth_state = {}
@app.route("/", methods=["GET", "POST"])
def index():
if request.method == "POST":
# OAuthコールバック処理
if "code" in request.args and "state" in request.args:
state = request.args["state"]
if state not in oauth_state:
return "無効な状態トークン", 400
code = request.args["code"]
# 実際にはここでHugging FaceのOAuthトークンエンドポイントにリクエストを送信
# デモ用に簡略化
token = f"oauth-token-{code}" # 実際には取得したトークンを使用
return render_index(token=token)
# スペース作成処理
token = request.form.get("token")
if not token:
return "トークンが提供されていません", 400
space_name = request.form["space_name"]
github_url = request.form["github_url"]
github_token = request.form.get("github_token")
private = request.form.get("private") == "on"
sdk = request.form["sdk"]
description = request.form["description"]
license_ = request.form["license"]
port = request.form["port"]
title = request.form["title"]
emoji = request.form["emoji"]
pinned = request.form.get("pinned") == "on"
if not github_url.startswith("https://"):
github_url = f"https://github.com/{github_url}"
headers = {"Authorization": f"Bearer {token}"}
user_info = requests.get("https://huggingface.co/api/whoami-v2", headers=headers).json()
username = user_info["name"]
api_url = f"https://huggingface.co/api/spaces/{username}/{space_name}"
payload = {
"sdk": sdk,
"private": private,
"title": title,
"emoji": emoji,
"pinned": pinned,
"license": license_,
"app_port": port,
"description": description,
"git": github_url
}
if github_token:
payload["secrets"] = {"GITHUB_TOKEN": github_token}
json_data = json.dumps(payload, ensure_ascii=False).encode("utf-8")
response = requests.put(
api_url,
headers={
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
},
data=json_data
)
try:
return jsonify(response.json())
except requests.exceptions.JSONDecodeError:
return f"エラー内容(JSON形式でない可能性): {response.text}", response.status_code
return render_index()
def render_index(token=None):
return render_template_string('''
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>HuggingFace Space 作成フォーム</title>
<style>
.tab {
overflow: hidden;
border: 1px solid #ccc;
background-color: #f1f1f1;
border-radius: 4px 4px 0 0;
}
.tab button {
background-color: inherit;
float: left;
border: none;
outline: none;
cursor: pointer;
padding: 10px 16px;
transition: 0.3s;
}
.tab button:hover {
background-color: #ddd;
}
.tab button.active {
background-color: #fff;
border-bottom: 2px solid #4CAF50;
}
.tabcontent {
display: none;
padding: 20px;
border: 1px solid #ccc;
border-top: none;
border-radius: 0 0 4px 4px;
}
.tabcontent.active {
display: block;
}
.form-group {
margin-bottom: 15px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
input, select {
width: 100%;
padding: 8px;
box-sizing: border-box;
border: 1px solid #ddd;
border-radius: 4px;
}
button[type="submit"] {
background-color: #4CAF50;
color: white;
padding: 10px 15px;
border: none;
border-radius: 4px;
cursor: pointer;
}
button[type="submit"]:hover {
background-color: #45a049;
}
</style>
</head>
<body>
<h1>Hugging Face Space 作成</h1>
<div class="tab">
<button class="tablinks active" onclick="openTab(event, 'tokenTab')">トークン入力</button>
<button class="tablinks" onclick="openTab(event, 'oauthTab')">Hugging Faceでログイン</button>
</div>
<form method="POST">
<div id="tokenTab" class="tabcontent active">
<div class="form-group">
<label for="token">Hugging Face 書き込みトークン:</label>
<input type="password" name="token" id="token" required>
</div>
</div>
<div id="oauthTab" class="tabcontent">
<div class="form-group">
<p>Hugging FaceのOAuthを使用してログインします。</p>
<button type="button" id="oauthLogin" onclick="startOAuth()">Hugging Faceでログイン</button>
</div>
</div>
<div class="form-group">
<label for="space_name">スペース名:</label>
<input type="text" name="space_name" id="space_name" required>
</div>
<div class="form-group">
<label for="github_url">GitHub リポジトリURL または ID:</label>
<input type="text" name="github_url" id="github_url" required>
</div>
<div class="form-group">
<label for="github_token">GitHub トークン (必要な場合):</label>
<input type="password" name="github_token" id="github_token">
</div>
<div class="form-group">
<label>
<input type="checkbox" name="private" id="private">
非公開にする
</label>
</div>
<div class="form-group">
<label for="sdk">SDK:</label>
<select name="sdk" id="sdk">
<option value="gradio">Gradio</option>
<option value="streamlit">Streamlit</option>
<option value="static">Static</option>
<option value="docker">Docker</option>
</select>
</div>
<div class="form-group">
<label for="description">説明:</label>
<input type="text" name="description" id="description">
</div>
<div class="form-group">
<label for="license">ライセンス:</label>
<input type="text" name="license" id="license" placeholder="e.g. apache-2.0">
</div>
<div class="form-group">
<label for="port">アプリのポート:</label>
<input type="text" name="port" id="port" placeholder="例: 7860">
</div>
<div class="form-group">
<label for="title">スペースの名前 (表示用):</label>
<input type="text" name="title" id="title">
</div>
<div class="form-group">
<label for="emoji">絵文字 (表示アイコン):</label>
<input type="text" name="emoji" id="emoji" placeholder="例: 🚀">
</div>
<div class="form-group">
<label>
<input type="checkbox" name="pinned" id="pinned">
固定 (ピン止め)
</label>
</div>
<button type="submit">スペースを作成</button>
</form>
<script>
function openTab(evt, tabName) {
const tabcontent = document.getElementsByClassName("tabcontent");
for (let i = 0; i < tabcontent.length; i++) {
tabcontent[i].classList.remove("active");
}
const tablinks = document.getElementsByClassName("tablinks");
for (let i = 0; i < tablinks.length; i++) {
tablinks[i].classList.remove("active");
}
document.getElementById(tabName).classList.add("active");
evt.currentTarget.classList.add("active");
}
function startOAuth() {
// 実際のアプリではHugging FaceのOAuthエンドポイントを使用
// デモ用に簡略化
const state = Math.random().toString(36).substring(2);
window.location.href = `https://huggingface.co/oauth/authorize?response_type=code&client_id=YOUR_CLIENT_ID&redirect_uri=${encodeURIComponent(window.location.origin)}&scope=read-repos,write-repos&state=${state}`;
}
document.addEventListener("DOMContentLoaded", () => {
const tokenInput = document.getElementById("token");
// URLからOAuthトークンを取得 (デモ用)
const urlParams = new URLSearchParams(window.location.search);
const oauthToken = urlParams.get('oauth_token');
if (oauthToken) {
tokenInput.value = oauthToken;
} else {
// 保存されたトークンを自動で読み込み
tokenInput.value = localStorage.getItem("hf_token") || "";
}
tokenInput.addEventListener("input", () => {
localStorage.setItem("hf_token", tokenInput.value);
});
});
</script>
</body>
</html>
''', token=token)
if __name__ == "__main__":
app.run(host="0.0.0.0", port=7860)