mirror of
https://github.com/MemeMeow-Studio/MemeMeow.git
synced 2026-10-16 20:31:33 +08:00
187 lines
6.2 KiB
Python
187 lines
6.2 KiB
Python
from fastapi import FastAPI, HTTPException, BackgroundTasks
|
||
from pydantic import BaseModel
|
||
from typing import List, Optional
|
||
import yaml
|
||
import os
|
||
from services.image_search import IMAGE_SEARCH_SERVICE
|
||
|
||
from config.settings import Config
|
||
from config.api_settings import load_config
|
||
from services.community_service import CommunityService
|
||
|
||
import uvicorn
|
||
|
||
from middleware.protected_mode import ProtectedModeMiddleware
|
||
from middleware.rate_limiter import RateLimitMiddleware
|
||
import re
|
||
import json
|
||
|
||
# 初始化核心组件
|
||
config = Config()
|
||
search_engine = IMAGE_SEARCH_SERVICE
|
||
api_config = load_config()
|
||
app = FastAPI(title="VVQuest API")
|
||
|
||
# 注册保护模式中间件
|
||
if api_config.protected_mode:
|
||
app.add_middleware(ProtectedModeMiddleware, config=api_config)
|
||
|
||
if api_config.rate_limit.enabled:
|
||
app.add_middleware(RateLimitMiddleware, config=api_config)
|
||
|
||
# 数据模型定义
|
||
class SearchRequest(BaseModel):
|
||
query: str
|
||
n_results: int = 5
|
||
|
||
class SearchRequestEnhanced(SearchRequest):
|
||
resource_pack_uuids: List[str] = [] # 添加默认空列表
|
||
ai_search: bool = False
|
||
|
||
class ConfigUpdate(BaseModel):
|
||
api_key: Optional[str] = None
|
||
base_url: Optional[str] = None
|
||
|
||
class ModelDownloadRequest(BaseModel):
|
||
model_id: str
|
||
|
||
def search_result_postprocess(results:List[str]):
|
||
ret = []
|
||
for v in results:
|
||
if api_config.urls.return_type == "abs_path":
|
||
pass
|
||
elif api_config.urls.return_type == "rel_path":
|
||
v = os.path.relpath(v, Config().base_dir)
|
||
elif api_config.urls.return_type == "sha256":
|
||
v = v[1] + os.path.splitext(os.path.basename(v[0]))[1] # 假设v是一个元组,v[1]是sha256,v[0]是文件名
|
||
reg_pattern = api_config.urls.path_replace_regex
|
||
if reg_pattern:
|
||
v = re.sub(reg_pattern, "", v)
|
||
|
||
if api_config.urls.url_prefix:
|
||
v = f'{api_config.urls.url_prefix}/{v}'
|
||
if api_config.urls.url_postfix:
|
||
if not v.endswith(api_config.urls.url_postfix):
|
||
v = f'{v}/{api_config.urls.url_prefix}'
|
||
|
||
ret.append(v)
|
||
return ret
|
||
|
||
# API 端点
|
||
# @app.post("/search")
|
||
# async def search_images(request: SearchRequest):
|
||
# """执行图片搜索"""
|
||
# try:
|
||
# results = search_engine.search(
|
||
# request.query,
|
||
# request.n_results,
|
||
# api_key = config.api.embedding_models.api_key
|
||
# )
|
||
# return {"results": search_result_postprocess(results)}
|
||
# except Exception as e:
|
||
# raise HTTPException(status_code=500, detail=str(e))
|
||
|
||
@app.post("/search")
|
||
async def search_images(request: SearchRequestEnhanced):
|
||
"""执行图片搜索"""
|
||
try:
|
||
results = search_engine.search(
|
||
request.query,
|
||
request.n_results,
|
||
request.resource_pack_uuids,
|
||
api_key = config.api.embedding_models.api_key,
|
||
use_llm = request.ai_search,
|
||
return_type = "hash" if api_config.urls.return_type == "sha256" else "default"
|
||
)
|
||
|
||
return {"results": search_result_postprocess(results)}
|
||
except Exception as e:
|
||
raise HTTPException(status_code=500, detail=str(e))
|
||
|
||
@app.get("/")
|
||
async def root():
|
||
"""API根目录"""
|
||
return {"message": "Welcome to the VVQuest API"}
|
||
|
||
@app.get("/libs_manifest")
|
||
async def get_libs_manifest():
|
||
|
||
manifest_path = os.path.join(Config().temp_dir, "all_manifest.json")
|
||
if not os.path.exists(manifest_path):
|
||
CommunityService().reload_community_info()
|
||
|
||
try:
|
||
with open(manifest_path, 'r', encoding='utf-8') as f:
|
||
manifest_data = json.load(f)
|
||
return manifest_data
|
||
except FileNotFoundError:
|
||
raise HTTPException(status_code=404, detail="Manifest file not found")
|
||
except json.JSONDecodeError:
|
||
raise HTTPException(status_code=500, detail="Invalid JSON format in manifest file")
|
||
except Exception as e:
|
||
raise HTTPException(status_code=500, detail=str(e))
|
||
|
||
@app.post("/generate-cache")
|
||
async def generate_cache(background_tasks: BackgroundTasks):
|
||
"""触发缓存生成(后台任务)"""
|
||
if not search_engine.has_cache():
|
||
background_tasks.add_task(search_engine.generate_cache)
|
||
return {"message": "Cache generation started"}
|
||
return {"message": "Cache already exists"}
|
||
|
||
@app.get("/config")
|
||
async def get_config():
|
||
"""获取当前配置"""
|
||
return {
|
||
# "mode": search_engine.get_mode(),
|
||
"model": search_engine.get_model_name(),
|
||
"api_key": search_engine.embedding_service.api_key,
|
||
"base_url": search_engine.embedding_service.base_url
|
||
}
|
||
|
||
@app.put("/api-config")
|
||
async def update_config(update: ConfigUpdate):
|
||
"""更新API配置"""
|
||
try:
|
||
if update.api_key:
|
||
search_engine.embedding_service.api_key = update.api_key
|
||
if update.base_url:
|
||
search_engine.embedding_service.base_url = update.base_url
|
||
config.save()
|
||
return {"message": "Config updated successfully"}
|
||
except Exception as e:
|
||
raise HTTPException(status_code=500, detail=str(e))
|
||
|
||
# @app.post("/download-model")
|
||
# async def download_model(req: ModelDownloadRequest):
|
||
# """下载指定模型"""
|
||
# try:
|
||
# if search_engine.embedding_service.is_model_downloaded(req.model_id):
|
||
# return {"message": "Model already exists"}
|
||
#
|
||
# search_engine.download_model(req.model_id)
|
||
# return {"message": "Model download completed"}
|
||
# except Exception as e:
|
||
# raise HTTPException(status_code=500, detail=str(e))
|
||
|
||
# @app.get("/models")
|
||
# async def list_models():
|
||
# """获取可用模型列表"""
|
||
# models = []
|
||
# for model_id, info in Config().models.embedding_models.items():
|
||
# models.append({
|
||
# "id": model_id,
|
||
# "performance": info.performance,
|
||
# "downloaded": search_engine.embedding_service.is_model_downloaded(model_id)
|
||
# })
|
||
# return {"models": models}
|
||
|
||
|
||
if __name__ == "__main__":
|
||
search_engine.embedding_service.api_key = api_config.api_mode_config.default_api_key
|
||
search_engine.embedding_service.base_url = api_config.api_mode_config.default_base_url
|
||
# search_engine.set_mode('api')
|
||
if api_config.generate_cache:
|
||
search_engine.generate_cache()
|
||
print("Starting API server...")
|
||
uvicorn.run(app, host="0.0.0.0", port=8000) |