diff --git a/personal-blog/backend/routers/crawl.py b/personal-blog/backend/routers/crawl.py index 6fbe1c2..63214d4 100644 --- a/personal-blog/backend/routers/crawl.py +++ b/personal-blog/backend/routers/crawl.py @@ -675,7 +675,67 @@ def download_image(url: str, temp_dir: str) -> tuple: return filename, filepath, True except Exception as e: print(f"下载图片失败 {url}: {e}") - return None, None, False + + # CDN 子域名回退(如 eewimg.cn 的 66 子域名在部分网络无法解析) + if 'eewimg.cn' in url and url.startswith('http'): + fallback_result = _try_eewimg_cdn_fallback(url, temp_dir) + if fallback_result and fallback_result[2]: + return fallback_result + + return None, None, False + + +# eewimg.cn CDN 可解析的子域名(66 子域名在海外/部分网络 NXDOMAIN) +_EEWIMG_FALLBACK_SUBDOMAINS = ["8", "2", "10", "11", "12", "3", "1"] + + +def _try_eewimg_cdn_fallback(url: str, temp_dir: str) -> tuple: + """尝试用其他 eewimg.cn 子域名下载图片""" + # 去掉 imageView2 等图片处理参数,获取原始图片 + clean_url = re.sub(r'\?.*$', '', url) + + for sub in _EEWIMG_FALLBACK_SUBDOMAINS: + try: + # 替换子域名(数字开头的子域名) + fallback_url = re.sub(r'https?://\d+\.eewimg\.cn', f'https://{sub}.eewimg.cn', clean_url) + if fallback_url == clean_url: + continue # 没替换成功,跳过 + + headers = { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', + 'Accept': 'image/avif,image/webp,image/apng,image/*,*/*;q=0.8', + 'Referer': 'https://www.eeworld.com.cn/', + } + response = requests.get(fallback_url, headers=headers, timeout=15, stream=True) + response.raise_for_status() + + content_type = response.headers.get('content-type', '') + ext = '.jpg' + if 'png' in content_type: + ext = '.png' + elif 'gif' in content_type: + ext = '.gif' + elif 'webp' in content_type: + ext = '.webp' + else: + parsed = urlparse(url) + path_ext = os.path.splitext(parsed.path)[1] + if path_ext: + ext = path_ext + + filename = f"crawl_{datetime.now().strftime('%Y%m%d_%H%M%S')}_{uuid.uuid4().hex[:8]}{ext}" + filepath = os.path.join(temp_dir, filename) + + with open(filepath, 'wb') as f: + for chunk in response.iter_content(chunk_size=8192): + f.write(chunk) + + print(f"[CDN fallback] 成功通过 {sub}.eewimg.cn 下载: {url}") + return filename, filepath, True + except Exception as e: + continue + + return None, None, False def is_spa_site(html: str) -> bool: diff --git a/personal-blog/backend/routers/universal_crawl.py b/personal-blog/backend/routers/universal_crawl.py index 986289b..1c4900c 100644 --- a/personal-blog/backend/routers/universal_crawl.py +++ b/personal-blog/backend/routers/universal_crawl.py @@ -40,6 +40,20 @@ from .crawl import ( CrawlImage, ) + +class CrawlSaveRequest(BaseModel): + """通用采集保存请求""" + title: str + content: str + content_html: Optional[str] = "" + images: List[CrawlImage] = [] + summary: Optional[str] = "" + category_id: Optional[int] = None + is_draft: bool = True + is_published: bool = False + tags: Optional[List[str]] = [] + source_url: Optional[str] = None + # 复用图片处理 from .images import generate_thumbnail, get_image_dimensions @@ -71,6 +85,7 @@ def _needs_browser(url: str) -> bool: 'infoq.cn', 'infoq.com', '51cto.com', + 'eeworld.com.cn', # JS WAF 防护,必须用浏览器渲染 ] return any(d in domain for d in browser_domains) @@ -466,29 +481,19 @@ async def universal_fetch(request: UniversalCrawlRequest): @router.post("/save") -async def universal_save( - title: str, - content: str, - excerpt: Optional[str] = None, - category_id: Optional[int] = None, - source_url: Optional[str] = None, - images: Optional[str] = None, - db: Session = Depends(get_db) -): - """保存通用采集的文章(复用 crawl.py 的保存逻辑)""" +async def universal_save(request: CrawlSaveRequest, db: Session = Depends(get_db)): + """保存通用采集的文章,下载图片到本地并替换内容中的远程 URL""" try: - print(f"[Universal Crawl] Saving article: {title}") - - # 解析图片列表 - image_list = [] - if images: - try: - import json - image_data = json.loads(images) - for img in image_data: - image_list.append(CrawlImage(**img)) - except Exception as e: - print(f"[Universal Crawl] Parse images error: {e}") + title = request.title + content = request.content + excerpt = request.summary or "" + category_id = request.category_id + source_url = request.source_url + image_list = request.images + is_draft = request.is_draft + is_published = request.is_published + + print(f"[Universal Crawl] Saving article: {title}, images: {len(image_list)}") # 创建临时目录 temp_dir = tempfile.mkdtemp(dir=TEMP_DIR) @@ -499,12 +504,17 @@ async def universal_save( # 下载图片 downloaded_images = [] + images_saved = 0 + images_failed = 0 for img in image_list: try: - filename, filepath, success = download_image(str(img.url), temp_dir) + img_url = str(img.original_url) + if not img_url: + continue + filename, filepath, success = download_image(img_url, temp_dir) if success and filepath: # 移动最终文件 - final_filename = f"crawl_{datetime.now().strftime('%Y%m%d_%H%M%S')}_{uuid.uuid4().hex[:8]}{os.path.splitext(filename)[1]}" + final_filename = f"crawl_{datetime.now().strftime('%Y%m%d_%H%M%S')}_{uuid.uuid4().hex[:8]}{os.path.splitext(filename or 'img.jpg')[1] or '.jpg'}" final_path = final_dir / final_filename os.rename(filepath, str(final_path)) @@ -521,7 +531,7 @@ async def universal_save( # 保存到数据库 db_image = Image( filename=final_filename, - original_filename=img.alt or final_filename, + original_filename=final_filename, file_path=f"/uploads/images/{final_filename}", file_size=os.path.getsize(str(final_path)), mime_type=f"image/{os.path.splitext(final_filename)[1].lstrip('.') or 'jpeg'}", @@ -533,9 +543,9 @@ async def universal_save( db.flush() # 替换内容中的图片 URL - original_url = str(img.url) new_url = f"/uploads/images/{final_filename}" - content = content.replace(original_url, new_url) + content = content.replace(img_url, new_url) + images_saved += 1 downloaded_images.append({ "id": db_image.id, @@ -543,25 +553,19 @@ async def universal_save( "thumb": thumb_path_db, }) except Exception as e: + images_failed += 1 print(f"[Universal Crawl] Download image error: {e}") continue - # 清理 excerpt - if excerpt: - excerpt = re.sub(r'<[^>]+>', '', excerpt) - excerpt = excerpt.replace('\n', ' ').strip()[:200] - else: - excerpt = content.replace('\n', ' ').strip()[:200] + # 生成摘要 + summary = excerpt if excerpt else content[:300] if len(content) > 300 else content + summary = re.sub(r'[#*`\[\]\(\)!]', '', summary).strip()[:300] # 创建文章 now = datetime.now() slug = re.sub(r'[^\w\u4e00-\u9fff-]', '-', title)[:50].strip('-') slug = f"{slug}-{now.strftime('%Y%m%d%H%M%S')}-{uuid.uuid4().hex[:4]}" - # 生成摘要 - summary = content[:300] if len(content) > 300 else content - summary = re.sub(r'[#*`\[\]\(\)!]', '', summary) - # 查找或创建分类 final_category_id = category_id if not final_category_id: @@ -576,28 +580,42 @@ async def universal_save( title=title, slug=slug, content=content, - excerpt=excerpt, + content_type="markdown", summary=summary, category_id=final_category_id, - author_id=1, - status="draft", + is_published=is_published, + is_draft=is_draft, view_count=0, - is_original=False, - source_url=source_url, created_at=now, updated_at=now, - published_at=None, ) db.add(post) db.flush() + # 处理标签 + if request.tags: + for tag_name in request.tags: + tag_name = tag_name.strip() + if not tag_name: + continue + tag = db.query(Tag).filter(Tag.name == tag_name).first() + if not tag: + tag_slug = re.sub(r'[^\w\u4e00-\u9fff-]', '-', tag_name).strip('-') + tag = Tag(name=tag_name, slug=tag_slug) + db.add(tag) + db.flush() + post_tag = PostTag(post_id=post.id, tag_id=tag.id) + db.add(post_tag) + db.commit() return { - "status": "success", + "success": True, "post_id": post.id, + "slug": slug, "message": "文章保存成功", - "images": downloaded_images, + "images_saved": images_saved, + "images_failed": images_failed, } except Exception as e: diff --git a/personal-blog/backend/uploads/crawl_20260708_03a57e69.png b/personal-blog/backend/uploads/crawl_20260708_03a57e69.png new file mode 100644 index 0000000..07566c1 Binary files /dev/null and b/personal-blog/backend/uploads/crawl_20260708_03a57e69.png differ diff --git a/personal-blog/backend/uploads/crawl_20260708_099bc2d1.png b/personal-blog/backend/uploads/crawl_20260708_099bc2d1.png new file mode 100644 index 0000000..e924c77 Binary files /dev/null and b/personal-blog/backend/uploads/crawl_20260708_099bc2d1.png differ diff --git a/personal-blog/backend/uploads/crawl_20260708_272abde3.png b/personal-blog/backend/uploads/crawl_20260708_272abde3.png new file mode 100644 index 0000000..47f4b3c Binary files /dev/null and b/personal-blog/backend/uploads/crawl_20260708_272abde3.png differ diff --git a/personal-blog/backend/uploads/crawl_20260708_3315deae.png b/personal-blog/backend/uploads/crawl_20260708_3315deae.png new file mode 100644 index 0000000..e2abc4d Binary files /dev/null and b/personal-blog/backend/uploads/crawl_20260708_3315deae.png differ diff --git a/personal-blog/backend/uploads/crawl_20260708_377f89ce.png b/personal-blog/backend/uploads/crawl_20260708_377f89ce.png new file mode 100644 index 0000000..e2abc4d Binary files /dev/null and b/personal-blog/backend/uploads/crawl_20260708_377f89ce.png differ diff --git a/personal-blog/backend/uploads/crawl_20260708_38dcdded.png b/personal-blog/backend/uploads/crawl_20260708_38dcdded.png new file mode 100644 index 0000000..18da99d Binary files /dev/null and b/personal-blog/backend/uploads/crawl_20260708_38dcdded.png differ diff --git a/personal-blog/backend/uploads/crawl_20260708_4bcea782.png b/personal-blog/backend/uploads/crawl_20260708_4bcea782.png new file mode 100644 index 0000000..a785b86 Binary files /dev/null and b/personal-blog/backend/uploads/crawl_20260708_4bcea782.png differ diff --git a/personal-blog/backend/uploads/crawl_20260708_5db6f5cb.png b/personal-blog/backend/uploads/crawl_20260708_5db6f5cb.png new file mode 100644 index 0000000..1767e4f Binary files /dev/null and b/personal-blog/backend/uploads/crawl_20260708_5db6f5cb.png differ diff --git a/personal-blog/backend/uploads/crawl_20260708_61876aab.png b/personal-blog/backend/uploads/crawl_20260708_61876aab.png new file mode 100644 index 0000000..47f4b3c Binary files /dev/null and b/personal-blog/backend/uploads/crawl_20260708_61876aab.png differ diff --git a/personal-blog/backend/uploads/crawl_20260708_63fc3c8f.png b/personal-blog/backend/uploads/crawl_20260708_63fc3c8f.png new file mode 100644 index 0000000..81594ef Binary files /dev/null and b/personal-blog/backend/uploads/crawl_20260708_63fc3c8f.png differ diff --git a/personal-blog/backend/uploads/crawl_20260708_65227ee5.png b/personal-blog/backend/uploads/crawl_20260708_65227ee5.png new file mode 100644 index 0000000..81594ef Binary files /dev/null and b/personal-blog/backend/uploads/crawl_20260708_65227ee5.png differ diff --git a/personal-blog/backend/uploads/crawl_20260708_66cbd09c.png b/personal-blog/backend/uploads/crawl_20260708_66cbd09c.png new file mode 100644 index 0000000..f3c240a Binary files /dev/null and b/personal-blog/backend/uploads/crawl_20260708_66cbd09c.png differ diff --git a/personal-blog/backend/uploads/crawl_20260708_72fd8a88.png b/personal-blog/backend/uploads/crawl_20260708_72fd8a88.png new file mode 100644 index 0000000..1edee63 Binary files /dev/null and b/personal-blog/backend/uploads/crawl_20260708_72fd8a88.png differ diff --git a/personal-blog/backend/uploads/crawl_20260708_76d05e01.png b/personal-blog/backend/uploads/crawl_20260708_76d05e01.png new file mode 100644 index 0000000..a785b86 Binary files /dev/null and b/personal-blog/backend/uploads/crawl_20260708_76d05e01.png differ diff --git a/personal-blog/backend/uploads/crawl_20260708_798cbcd7.png b/personal-blog/backend/uploads/crawl_20260708_798cbcd7.png new file mode 100644 index 0000000..f8033aa Binary files /dev/null and b/personal-blog/backend/uploads/crawl_20260708_798cbcd7.png differ diff --git a/personal-blog/backend/uploads/crawl_20260708_7a73a8b5.png b/personal-blog/backend/uploads/crawl_20260708_7a73a8b5.png new file mode 100644 index 0000000..7112a14 Binary files /dev/null and b/personal-blog/backend/uploads/crawl_20260708_7a73a8b5.png differ diff --git a/personal-blog/backend/uploads/crawl_20260708_7c367283.png b/personal-blog/backend/uploads/crawl_20260708_7c367283.png new file mode 100644 index 0000000..c2ee77f Binary files /dev/null and b/personal-blog/backend/uploads/crawl_20260708_7c367283.png differ diff --git a/personal-blog/backend/uploads/crawl_20260708_7cce5e50.png b/personal-blog/backend/uploads/crawl_20260708_7cce5e50.png new file mode 100644 index 0000000..1edee63 Binary files /dev/null and b/personal-blog/backend/uploads/crawl_20260708_7cce5e50.png differ diff --git a/personal-blog/backend/uploads/crawl_20260708_819a28bf.png b/personal-blog/backend/uploads/crawl_20260708_819a28bf.png new file mode 100644 index 0000000..6349ca9 Binary files /dev/null and b/personal-blog/backend/uploads/crawl_20260708_819a28bf.png differ diff --git a/personal-blog/backend/uploads/crawl_20260708_89fcc986.png b/personal-blog/backend/uploads/crawl_20260708_89fcc986.png new file mode 100644 index 0000000..6349ca9 Binary files /dev/null and b/personal-blog/backend/uploads/crawl_20260708_89fcc986.png differ diff --git a/personal-blog/backend/uploads/crawl_20260708_8ec1ab4a.png b/personal-blog/backend/uploads/crawl_20260708_8ec1ab4a.png new file mode 100644 index 0000000..f8033aa Binary files /dev/null and b/personal-blog/backend/uploads/crawl_20260708_8ec1ab4a.png differ diff --git a/personal-blog/backend/uploads/crawl_20260708_9b5c57d0.png b/personal-blog/backend/uploads/crawl_20260708_9b5c57d0.png new file mode 100644 index 0000000..07566c1 Binary files /dev/null and b/personal-blog/backend/uploads/crawl_20260708_9b5c57d0.png differ diff --git a/personal-blog/backend/uploads/crawl_20260708_a3a2404d.png b/personal-blog/backend/uploads/crawl_20260708_a3a2404d.png new file mode 100644 index 0000000..ebe607e Binary files /dev/null and b/personal-blog/backend/uploads/crawl_20260708_a3a2404d.png differ diff --git a/personal-blog/backend/uploads/crawl_20260708_a58eb806.png b/personal-blog/backend/uploads/crawl_20260708_a58eb806.png new file mode 100644 index 0000000..7e782ab Binary files /dev/null and b/personal-blog/backend/uploads/crawl_20260708_a58eb806.png differ diff --git a/personal-blog/backend/uploads/crawl_20260708_a5a5e66f.png b/personal-blog/backend/uploads/crawl_20260708_a5a5e66f.png new file mode 100644 index 0000000..5da7573 Binary files /dev/null and b/personal-blog/backend/uploads/crawl_20260708_a5a5e66f.png differ diff --git a/personal-blog/backend/uploads/crawl_20260708_a7bc2db1.png b/personal-blog/backend/uploads/crawl_20260708_a7bc2db1.png new file mode 100644 index 0000000..ebe607e Binary files /dev/null and b/personal-blog/backend/uploads/crawl_20260708_a7bc2db1.png differ diff --git a/personal-blog/backend/uploads/crawl_20260708_aaac6741.png b/personal-blog/backend/uploads/crawl_20260708_aaac6741.png new file mode 100644 index 0000000..18da99d Binary files /dev/null and b/personal-blog/backend/uploads/crawl_20260708_aaac6741.png differ diff --git a/personal-blog/backend/uploads/crawl_20260708_adc6b6d6.png b/personal-blog/backend/uploads/crawl_20260708_adc6b6d6.png new file mode 100644 index 0000000..1767e4f Binary files /dev/null and b/personal-blog/backend/uploads/crawl_20260708_adc6b6d6.png differ diff --git a/personal-blog/backend/uploads/crawl_20260708_b75dde04.png b/personal-blog/backend/uploads/crawl_20260708_b75dde04.png new file mode 100644 index 0000000..c2ee77f Binary files /dev/null and b/personal-blog/backend/uploads/crawl_20260708_b75dde04.png differ diff --git a/personal-blog/backend/uploads/crawl_20260708_b768246d.png b/personal-blog/backend/uploads/crawl_20260708_b768246d.png new file mode 100644 index 0000000..7e782ab Binary files /dev/null and b/personal-blog/backend/uploads/crawl_20260708_b768246d.png differ diff --git a/personal-blog/backend/uploads/crawl_20260708_c3ea46c4.png b/personal-blog/backend/uploads/crawl_20260708_c3ea46c4.png new file mode 100644 index 0000000..e924c77 Binary files /dev/null and b/personal-blog/backend/uploads/crawl_20260708_c3ea46c4.png differ diff --git a/personal-blog/backend/uploads/crawl_20260708_ee0147ee.png b/personal-blog/backend/uploads/crawl_20260708_ee0147ee.png new file mode 100644 index 0000000..5da7573 Binary files /dev/null and b/personal-blog/backend/uploads/crawl_20260708_ee0147ee.png differ diff --git a/personal-blog/backend/uploads/crawl_20260708_eebfcce7.png b/personal-blog/backend/uploads/crawl_20260708_eebfcce7.png new file mode 100644 index 0000000..7112a14 Binary files /dev/null and b/personal-blog/backend/uploads/crawl_20260708_eebfcce7.png differ diff --git a/personal-blog/backend/uploads/crawl_20260708_f84daa73.png b/personal-blog/backend/uploads/crawl_20260708_f84daa73.png new file mode 100644 index 0000000..f3c240a Binary files /dev/null and b/personal-blog/backend/uploads/crawl_20260708_f84daa73.png differ diff --git a/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_03a57e69.png b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_03a57e69.png new file mode 100644 index 0000000..5029a84 Binary files /dev/null and b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_03a57e69.png differ diff --git a/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_099bc2d1.png b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_099bc2d1.png new file mode 100644 index 0000000..9b137d8 Binary files /dev/null and b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_099bc2d1.png differ diff --git a/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_272abde3.png b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_272abde3.png new file mode 100644 index 0000000..e683eab Binary files /dev/null and b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_272abde3.png differ diff --git a/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_3315deae.png b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_3315deae.png new file mode 100644 index 0000000..f05a97b Binary files /dev/null and b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_3315deae.png differ diff --git a/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_377f89ce.png b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_377f89ce.png new file mode 100644 index 0000000..f05a97b Binary files /dev/null and b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_377f89ce.png differ diff --git a/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_38dcdded.png b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_38dcdded.png new file mode 100644 index 0000000..d1cc761 Binary files /dev/null and b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_38dcdded.png differ diff --git a/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_4bcea782.png b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_4bcea782.png new file mode 100644 index 0000000..661ec57 Binary files /dev/null and b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_4bcea782.png differ diff --git a/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_5db6f5cb.png b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_5db6f5cb.png new file mode 100644 index 0000000..a503b61 Binary files /dev/null and b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_5db6f5cb.png differ diff --git a/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_61876aab.png b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_61876aab.png new file mode 100644 index 0000000..e683eab Binary files /dev/null and b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_61876aab.png differ diff --git a/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_63fc3c8f.png b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_63fc3c8f.png new file mode 100644 index 0000000..6c36ebf Binary files /dev/null and b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_63fc3c8f.png differ diff --git a/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_65227ee5.png b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_65227ee5.png new file mode 100644 index 0000000..6c36ebf Binary files /dev/null and b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_65227ee5.png differ diff --git a/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_66cbd09c.png b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_66cbd09c.png new file mode 100644 index 0000000..9159126 Binary files /dev/null and b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_66cbd09c.png differ diff --git a/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_72fd8a88.png b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_72fd8a88.png new file mode 100644 index 0000000..225790e Binary files /dev/null and b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_72fd8a88.png differ diff --git a/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_76d05e01.png b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_76d05e01.png new file mode 100644 index 0000000..661ec57 Binary files /dev/null and b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_76d05e01.png differ diff --git a/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_798cbcd7.png b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_798cbcd7.png new file mode 100644 index 0000000..5423333 Binary files /dev/null and b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_798cbcd7.png differ diff --git a/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_7a73a8b5.png b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_7a73a8b5.png new file mode 100644 index 0000000..f3f5f19 Binary files /dev/null and b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_7a73a8b5.png differ diff --git a/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_7c367283.png b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_7c367283.png new file mode 100644 index 0000000..c13bfb3 Binary files /dev/null and b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_7c367283.png differ diff --git a/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_7cce5e50.png b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_7cce5e50.png new file mode 100644 index 0000000..225790e Binary files /dev/null and b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_7cce5e50.png differ diff --git a/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_819a28bf.png b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_819a28bf.png new file mode 100644 index 0000000..f4c7027 Binary files /dev/null and b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_819a28bf.png differ diff --git a/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_89fcc986.png b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_89fcc986.png new file mode 100644 index 0000000..f4c7027 Binary files /dev/null and b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_89fcc986.png differ diff --git a/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_8ec1ab4a.png b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_8ec1ab4a.png new file mode 100644 index 0000000..5423333 Binary files /dev/null and b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_8ec1ab4a.png differ diff --git a/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_9b5c57d0.png b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_9b5c57d0.png new file mode 100644 index 0000000..5029a84 Binary files /dev/null and b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_9b5c57d0.png differ diff --git a/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_a3a2404d.png b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_a3a2404d.png new file mode 100644 index 0000000..b21eab2 Binary files /dev/null and b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_a3a2404d.png differ diff --git a/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_a58eb806.png b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_a58eb806.png new file mode 100644 index 0000000..3a33281 Binary files /dev/null and b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_a58eb806.png differ diff --git a/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_a5a5e66f.png b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_a5a5e66f.png new file mode 100644 index 0000000..9e5ffb1 Binary files /dev/null and b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_a5a5e66f.png differ diff --git a/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_a7bc2db1.png b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_a7bc2db1.png new file mode 100644 index 0000000..b21eab2 Binary files /dev/null and b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_a7bc2db1.png differ diff --git a/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_aaac6741.png b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_aaac6741.png new file mode 100644 index 0000000..d1cc761 Binary files /dev/null and b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_aaac6741.png differ diff --git a/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_adc6b6d6.png b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_adc6b6d6.png new file mode 100644 index 0000000..a503b61 Binary files /dev/null and b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_adc6b6d6.png differ diff --git a/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_b75dde04.png b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_b75dde04.png new file mode 100644 index 0000000..c13bfb3 Binary files /dev/null and b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_b75dde04.png differ diff --git a/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_b768246d.png b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_b768246d.png new file mode 100644 index 0000000..3a33281 Binary files /dev/null and b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_b768246d.png differ diff --git a/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_c3ea46c4.png b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_c3ea46c4.png new file mode 100644 index 0000000..9b137d8 Binary files /dev/null and b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_c3ea46c4.png differ diff --git a/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_ee0147ee.png b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_ee0147ee.png new file mode 100644 index 0000000..9e5ffb1 Binary files /dev/null and b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_ee0147ee.png differ diff --git a/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_eebfcce7.png b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_eebfcce7.png new file mode 100644 index 0000000..f3f5f19 Binary files /dev/null and b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_eebfcce7.png differ diff --git a/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_f84daa73.png b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_f84daa73.png new file mode 100644 index 0000000..9159126 Binary files /dev/null and b/personal-blog/backend/uploads/thumbnails/thumb_crawl_20260708_f84daa73.png differ diff --git a/personal-blog/frontend/src/pages/UniversalCrawlEdit.jsx b/personal-blog/frontend/src/pages/UniversalCrawlEdit.jsx index 74f9c2e..ccf0150 100644 --- a/personal-blog/frontend/src/pages/UniversalCrawlEdit.jsx +++ b/personal-blog/frontend/src/pages/UniversalCrawlEdit.jsx @@ -6,7 +6,6 @@ import { authApi } from '../api/auth' import { Card, CardHeader, CardTitle, CardDescription, CardBody, CardFooter } from '../components-preline/Card' import { Button } from '../components-preline/Button' import { Input, Textarea, Label, FormError } from '../components-preline/Input' -import { postsApi } from '../api/posts' import { categoriesApi } from '../api/categories' import { tagsApi } from '../api/tags' import { API_BASE_URL } from '../api/config' @@ -200,25 +199,55 @@ export function UniversalCrawlEdit() { // 保存文章 const handleSubmit = async (e, isDraft = false) => { e.preventDefault() - + if (!form.title.trim() || !form.content.trim()) { alert('请填写标题和内容') return } - + setSaving(true) try { - const data = { - ...form, - category_id: form.category_id || null, - is_draft: isDraft, - is_published: !isDraft + const token = localStorage.getItem('token') + // 将 tag_ids 转换为 tag 名称数组 + const tagNames = form.tag_ids.map(tid => { + const tag = tags.find(t => t.id === Number(tid)) + return tag ? tag.name : '' + }).filter(Boolean) + + const response = await fetch(`${API_BASE_URL}/universal-crawl/save`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + ...(token ? { 'Authorization': `Bearer ${token}` } : {}) + }, + body: JSON.stringify({ + title: form.title, + content: form.content, + content_html: '', + images: crawledImages, + summary: form.summary, + category_id: form.category_id || null, + is_draft: isDraft, + is_published: !isDraft, + tags: tagNames, + source_url: crawlUrl + }), + credentials: 'include' + }) + + const data = await response.json() + if (!data.success) { + throw new Error(data.detail || data.message || '保存失败') } - - await postsApi.createPost(data) + + // 提示图片下载情况 + if (data.images_failed > 0) { + alert(`文章已保存成功!\n图片:${data.images_saved} 张下载成功,${data.images_failed} 张下载失败(保留原始链接)。`) + } + navigate('/admin/posts') } catch (error) { - alert('保存失败: ' + (error.response?.data?.detail || '未知错误')) + alert('保存失败: ' + (error.message || error.response?.data?.detail || '未知错误')) } finally { setSaving(false) } diff --git a/skills/baoyu-imagine/prompts/gao-shanwen-cover-system.md b/skills/baoyu-imagine/prompts/gao-shanwen-cover-system.md new file mode 100644 index 0000000..0383a41 --- /dev/null +++ b/skills/baoyu-imagine/prompts/gao-shanwen-cover-system.md @@ -0,0 +1,9 @@ +你是一位专业的信息图设计师。请根据用户提供的内容生成一张人物主题信息图。 + +设计原则: +- 整体色调:深蓝、藏青、金色渐变,体现庄重、专业、肃穆的氛围 +- 主体:一位经济学家形象的剪影/侧影,与数据图表、趋势线等宏观分析元素融合 +- 文字:可包含标题"高善文"以及关键词如"宏观研究""资产重估""因果推断" +- 风格:严肃、专业、有纪念意义 +- 布局:人物肖像位于左侧或中央,右侧/周围环绕经济数据图表元素 +- 避免过于具体的数字和统计数据,使用抽象概念表达 diff --git a/skills/baoyu-post-to-wechat/SKILL.md b/skills/baoyu-post-to-wechat/SKILL.md index ee82ee2..3e66bad 100644 --- a/skills/baoyu-post-to-wechat/SKILL.md +++ b/skills/baoyu-post-to-wechat/SKILL.md @@ -273,6 +273,7 @@ python3 baoyu_with_image_gen.py markdown /home/ubuntu/test_ai_images.md --genera 5. **凭证安全**:API凭证已加密存储 6. **AI图片生成**:使用豆包Seedream API,需要网络连接,生成时间约30-60秒/张 7. **Frontmatter格式**:使用标准YAML格式,注意缩进 +8. **API 48001 限制**:微信API仅支持创建草稿,不支持自动发布。所有公众号文章需在微信后台手动发布。博客同步不受此限制。 ---