Spaces:
Running
Running
File size: 5,697 Bytes
a5914e7 5141a1d 236b21e 5141a1d a5914e7 5141a1d 236b21e 44590c9 5141a1d 3b7098a 5141a1d 236b21e 5141a1d 44590c9 5141a1d 44590c9 5141a1d 44590c9 5141a1d a5914e7 5141a1d 44590c9 5141a1d b4ae552 a5914e7 307e610 a5914e7 5141a1d 236b21e a5914e7 5141a1d a5914e7 5141a1d 44590c9 a5914e7 44590c9 5141a1d 44590c9 5141a1d b4ae552 44590c9 5141a1d 9170381 a2c46a4 9170381 c46a0a4 42aed2b 76bc2e4 e48aea9 c46a0a4 ee59cc5 9170381 5141a1d a5914e7 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
# --- START OF MODIFIED FILE app.py ---
import gradio as gr
from atproto import Client, models
import os
import io
from PIL import Image
# --- 配置您的 Bluesky 账户信息 ---
BSKY_HANDLE = os.environ.get("BSKY_HANDLE")
BSKY_APP_PASSWORD = os.environ.get("BSKY_APP_PASSWORD")
# --- 新增:配置缓存目录 ---
IMAGE_CACHE_DIR = "image_cache"
# 确保缓存目录存在
os.makedirs(IMAGE_CACHE_DIR, exist_ok=True)
client = Client()
# --- 全局登录 ---
try:
print("正在尝试登录 Bluesky...")
if BSKY_HANDLE and BSKY_APP_PASSWORD:
client.login(BSKY_HANDLE, BSKY_APP_PASSWORD)
print(f"Bluesky 登录成功!用户: {client.me.handle}")
else:
print("未找到 Bluesky 环境变量,跳过全局登录。")
except Exception as e:
print(f"Bluesky 全局登录失败: {e}")
pass
def fetch_bsky_gallery(max_posts=51):
if not client.me:
print("客户端未登录,正在尝试重新登录...")
if not BSKY_HANDLE or not BSKY_APP_PASSWORD:
raise gr.Error("Bluesky 登录失败:请在 Hugging Face Spaces 的 Repository secrets 中设置 BSKY_HANDLE 和 BSKY_APP_PASSWORD。")
try:
client.login(BSKY_HANDLE, BSKY_APP_PASSWORD)
print(f"Bluesky 重新登录成功!用户: {client.me.handle}")
except Exception as e:
raise gr.Error(f"Bluesky 登录失败,请检查 Handle 或应用密码并重启程序。错误: {e}")
print(f"正在为用户 {client.me.handle} 获取帖子...")
try:
actor_did = client.me.did
profile_feed = client.get_author_feed(actor=actor_did, limit=max_posts)
print(f"从 API 获取了 {len(profile_feed.feed)} 条帖子,正在开始检查...")
gallery_items = []
for i, feed_view in enumerate(profile_feed.feed):
post_record = feed_view.post.record
# 核心判断逻辑
if post_record.embed and isinstance(post_record.embed, models.AppBskyEmbedImages.Main):
print(f"成功匹配到图片帖子 #{i+1}!正在处理...")
images = post_record.embed.images
post_text = getattr(post_record, 'text', '')
for j, image_data in enumerate(images):
try:
image_cid = image_data.image.ref.link
# --- 缓存逻辑开始 ---
# 1. 定义缓存文件的路径
cached_image_path = os.path.join(IMAGE_CACHE_DIR, f"{image_cid}.jpg")
# 2. 检查缓存是否存在
if os.path.exists(cached_image_path):
print(f" > 缓存命中!直接使用本地图片: {cached_image_path}")
else:
# 3. 如果缓存不存在,则下载并保存
print(f" > 缓存未命中。正在下载 CID: {image_cid}...")
params = models.ComAtprotoSyncGetBlob.Params(did=actor_did, cid=image_cid)
image_bytes = client.com.atproto.sync.get_blob(params)
if image_bytes:
# 使用 PIL 打开图片并转换为 RGB
img = Image.open(io.BytesIO(image_bytes))
if img.mode == 'RGBA':
img = img.convert('RGB')
# 保存到缓存目录
img.save(cached_image_path, format='JPEG')
print(f" > 图片已成功下载并缓存至: {cached_image_path}")
else:
print(f" > 下载失败,未获取到图片数据。")
continue # 跳过这张图片
# --- 缓存逻辑结束 ---
# 将缓存路径(或已存在的本地路径)添加到画廊列表
caption = post_text if j == 0 else ""
gallery_items.append((cached_image_path, caption))
except Exception as img_e:
print(f"处理单张图片时发生错误: {img_e}")
continue
else:
print(f"帖子 #{i+1} 不包含图片,已跳过。")
print(f"\n检查完成。成功获取并处理了 {len(gallery_items)} 张图片。")
if not gallery_items:
placeholder_image = "https://i.imgur.com/nA8n922.png"
return [(placeholder_image, f"在最近的 {max_posts} 条帖子中没有找到符合条件的图片。")]
return gallery_items
except Exception as e:
print(f"获取帖子时发生错误: {e}")
raise gr.Error(f"获取 Bluesky 帖子时出错: {e}")
with gr.Blocks() as demo:
gr.Markdown("""
### 🎨 AiFeiFei 的 Bluesky 数字艺术画廊
""")
with gr.Row():
gallery = gr.Gallery(
label="作品集",
columns=3,
height=600,
show_download_button=True,
object_fit="contain",
show_label=False
)
with gr.Row():
refresh_button = gr.Button("🔄 刷新画廊")
demo.load(fn=fetch_bsky_gallery, inputs=None, outputs=gallery)
refresh_button.click(fn=fetch_bsky_gallery, inputs=None, outputs=gallery)
if __name__ == "__main__":
demo.launch(debug=True)
# --- END OF MODIFIED FILE app.py --- |